diff options
author | Tom Kelly <ctk21@cl.cam.ac.uk> | 2021-12-20 15:43:01 +0000 |
---|---|---|
committer | Tom Kelly <ctk21@cl.cam.ac.uk> | 2021-12-20 15:43:01 +0000 |
commit | 6ded93883ad0e5b2fc42da0d6d1c5066cc16eec2 (patch) | |
tree | 96af54d4d81a1a52a9127d3295a6284467413de7 /middle_end | |
parent | 76a1913e349a818614e0966c5016731ce772a07f (diff) | |
parent | 2bcef4bc172f476217f253d24cb3311eaca504bf (diff) | |
download | ocaml-6ded93883ad0e5b2fc42da0d6d1c5066cc16eec2.tar.gz |
Merge commit '2bcef4bc172f476217f253d24cb3311eaca504bf' into 5.00_rebase_to_pr
Diffstat (limited to 'middle_end')
-rw-r--r-- | middle_end/closure/closure.ml | 74 |
1 files changed, 49 insertions, 25 deletions
diff --git a/middle_end/closure/closure.ml b/middle_end/closure/closure.ml index e2353d6e8d..21bf345ab1 100644 --- a/middle_end/closure/closure.ml +++ b/middle_end/closure/closure.ml @@ -225,7 +225,8 @@ let is_pure_prim p = | Arbitrary_effects, _ -> false (* Check if a clambda term is ``pure'', - that is without side-effects *and* not containing function definitions *) + that is without side-effects *and* not containing function definitions + (Pure terms may still read mutable state) *) let rec is_pure = function Uvar _ -> true @@ -736,9 +737,10 @@ type env = { *) (* Approximates "no effects and no coeffects" *) -let is_substituable ~mutable_vars = function +let rec is_substituable ~mutable_vars = function | Uvar v -> not (V.Set.mem v mutable_vars) | Uconst _ -> true + | Uoffset(arg, _) -> is_substituable ~mutable_vars arg | _ -> false (* Approximates "only generative effects" *) @@ -746,7 +748,8 @@ let is_erasable = function | Uclosure _ -> true | u -> is_pure u -let bind_params { backend; mutable_vars; _ } loc fpc params args body = +let bind_params { backend; mutable_vars; _ } loc fdesc params args funct body = + let fpc = fdesc.fun_float_const_prop in let rec aux subst pl al body = match (pl, al) with ([], []) -> substitute (Debuginfo.from_location loc) (backend, fpc) @@ -779,7 +782,16 @@ let bind_params { backend; mutable_vars; _ } loc fpc params args body = in (* Reverse parameters and arguments to preserve right-to-left evaluation order (PR#2910). *) - aux V.Map.empty (List.rev params) (List.rev args) body + let params, args = List.rev params, List.rev args in + let params, args, body = + (* Ensure funct is evaluated after args *) + match params with + | my_closure :: params when not fdesc.fun_closed -> + (params @ [my_closure]), (args @ [funct]), body + | _ -> + params, args, (if is_pure funct then body else Usequence (funct, body)) + in + aux V.Map.empty params args body let warning_if_forced_inline ~loc ~attribute warning = if attribute = Always_inline then @@ -789,27 +801,39 @@ let warning_if_forced_inline ~loc ~attribute warning = (* Generate a direct application *) let direct_apply env fundesc ufunct uargs ~loc ~attribute = - let app_args = - if fundesc.fun_closed then uargs else uargs @ [ufunct] in - let app = - match fundesc.fun_inline, attribute with - | _, Never_inline | None, _ -> - let dbg = Debuginfo.from_location loc in - warning_if_forced_inline ~loc ~attribute - "Function information unavailable"; - Udirect_apply(fundesc.fun_label, app_args, dbg) - | Some(params, body), _ -> - bind_params env loc fundesc.fun_float_const_prop params app_args - body - in - (* If ufunct can contain side-effects or function definitions, - we must make sure that it is evaluated exactly once. - If the function is not closed, we evaluate ufunct as part of the - arguments. - If the function is closed, we force the evaluation of ufunct first. *) - if not fundesc.fun_closed || is_pure ufunct - then app - else Usequence(ufunct, app) + match fundesc.fun_inline, attribute with + | _, Never_inline + | None, _ -> + let dbg = Debuginfo.from_location loc in + warning_if_forced_inline ~loc ~attribute + "Function information unavailable"; + if fundesc.fun_closed && is_pure ufunct then + Udirect_apply(fundesc.fun_label, uargs, dbg) + else if not fundesc.fun_closed && + is_substituable ~mutable_vars:env.mutable_vars ufunct then + Udirect_apply(fundesc.fun_label, uargs @ [ufunct], dbg) + else begin + let args = List.map (fun arg -> + if is_substituable ~mutable_vars:env.mutable_vars arg then + None, arg + else + let id = V.create_local "arg" in + Some (VP.create id, arg), Uvar id) uargs in + let app_args = List.map snd args in + List.fold_left (fun app (binding,_) -> + match binding with + | None -> app + | Some (v, e) -> Ulet(Immutable, Pgenval, v, e, app)) + (if fundesc.fun_closed then + Usequence (ufunct, Udirect_apply (fundesc.fun_label, app_args, dbg)) + else + let clos = V.create_local "clos" in + Ulet(Immutable, Pgenval, VP.create clos, ufunct, + Udirect_apply(fundesc.fun_label, app_args @ [Uvar clos], dbg))) + args + end + | Some(params, body), _ -> + bind_params env loc fundesc params uargs ufunct body (* Add [Value_integer] info to the approximation of an application *) |