summaryrefslogtreecommitdiff
path: root/src/PureMicroPasses.ml
diff options
context:
space:
mode:
authorSon Ho2022-02-04 13:33:45 +0100
committerSon Ho2022-02-04 13:33:45 +0100
commit3ead957cf13ddd3b48ee85c008c6d56e44726eb4 (patch)
tree51e694665a3623cea8250bb0c3e4523c321fada1 /src/PureMicroPasses.ml
parent25200ad9664980d3276dd7462b4845a1a21c3e64 (diff)
Work on decomposition of monadic let-bindings for F*
Diffstat (limited to 'src/PureMicroPasses.ml')
-rw-r--r--src/PureMicroPasses.ml87
1 files changed, 86 insertions, 1 deletions
diff --git a/src/PureMicroPasses.ml b/src/PureMicroPasses.ml
index d8bfe4cd..ceee71dd 100644
--- a/src/PureMicroPasses.ml
+++ b/src/PureMicroPasses.ml
@@ -8,14 +8,38 @@ open TranslateCore
let log = L.pure_micro_passes_log
type config = {
+ decompose_monadic_let_bindings : bool;
+ (** Some provers like F* don't support the decomposition of return values
+ in monadic let-bindings:
+ ```
+ // NOT supported in F*
+ let (x, y) <-- f ();
+ ...
+ ```
+
+ In such situations, we might want to introduce an intermediate
+ assignment:
+ ```
+ let tmp <-- f ();
+ let (x, y) = tmp in
+ ...
+ ```
+ *)
unfold_monadic_let_bindings : bool;
(** Controls the unfolding of monadic let-bindings to explicit matches:
+
`y <-- f x; ...`
+
becomes:
+
`match f x with | Failure -> Failure | Return y -> ...`
-
+
+
This is useful when extracting to F*: the support for monadic
definitions is not super powerful.
+ Note that when [undolf_monadic_let_bindings] is true, setting
+ [decompose_monadic_let_bindings] to true and only makes the code
+ more verbose.
*)
filter_unused_monadic_calls : bool;
(** Controls whether we try to filter the calls to monadic functions
@@ -714,6 +738,51 @@ let eliminate_box_functions (_ctx : trans_ctx) (def : fun_def) : fun_def =
let body = obj#visit_texpression () def.body in
{ def with body }
+(** Decompose the monadic let-bindings.
+
+ See the explanations in [config].
+ *)
+let decompose_monadic_let_bindings (_ctx : trans_ctx) (def : fun_def) : fun_def
+ =
+ (* Set up the var id generator *)
+ let cnt = get_expression_min_var_counter def.body.e in
+ let _, fresh_id = VarId.mk_stateful_generator cnt in
+ (* It is a very simple map *)
+ let obj =
+ object (self)
+ inherit [_] map_expression as super
+
+ method! visit_Let env monadic lv re next_e =
+ if not monadic then super#visit_Let env monadic lv re next_e
+ else
+ (* If monadic, we need to check if the left-value is a variable:
+ * - if yes, don't decompose
+ * - if not, make the decomposition in two steps
+ *)
+ match lv.value with
+ | LvVar _ ->
+ (* Variable: nothing to do *)
+ super#visit_Let env monadic lv re next_e
+ | _ ->
+ (* Not a variable: decompose *)
+ (* Introduce a temporary variable to receive the value of the
+ * monadic binding *)
+ let vid = fresh_id () in
+ let tmp : var = { id = vid; basename = None; ty = lv.ty } in
+ let ltmp = mk_typed_lvalue_from_var tmp None in
+ let rtmp = mk_typed_rvalue_from_var tmp in
+ let rtmp = mk_value_expression rtmp None in
+ (* Visit the next expression *)
+ let next_e = self#visit_texpression env next_e in
+ (* Create the let-bindings *)
+ (mk_let true ltmp re (mk_let false lv rtmp next_e)).e
+ end
+ in
+ (* Update the body *)
+ let body = obj#visit_texpression () def.body in
+ (* Return *)
+ { def with body }
+
(** Unfold the monadic let-bindings to explicit matches. *)
let unfold_monadic_let_bindings (_ctx : trans_ctx) (def : fun_def) : fun_def =
(* It is a very simple map *)
@@ -813,6 +882,22 @@ let apply_passes_to_def (config : config) (ctx : trans_ctx) (def : fun_def) :
log#ldebug
(lazy ("filter_unused:\n\n" ^ fun_def_to_string ctx def ^ "\n"));
+ (* Decompose the monadic let-bindings *)
+ let def =
+ if config.decompose_monadic_let_bindings then (
+ let def = decompose_monadic_let_bindings ctx def in
+ log#ldebug
+ (lazy
+ ("decompose_monadic_let_bindings:\n\n" ^ fun_def_to_string ctx def
+ ^ "\n"));
+ def)
+ else (
+ log#ldebug
+ (lazy
+ "ignoring decompose_monadic_let_bindings due to the configuration\n");
+ def)
+ in
+
(* Unfold the monadic let-bindings *)
let def =
if config.unfold_monadic_let_bindings then (