summaryrefslogtreecommitdiff
path: root/middle_end
diff options
context:
space:
mode:
authorTom Kelly <ctk21@cl.cam.ac.uk>2021-12-20 15:43:01 +0000
committerTom Kelly <ctk21@cl.cam.ac.uk>2021-12-20 15:43:01 +0000
commit6ded93883ad0e5b2fc42da0d6d1c5066cc16eec2 (patch)
tree96af54d4d81a1a52a9127d3295a6284467413de7 /middle_end
parent76a1913e349a818614e0966c5016731ce772a07f (diff)
parent2bcef4bc172f476217f253d24cb3311eaca504bf (diff)
downloadocaml-6ded93883ad0e5b2fc42da0d6d1c5066cc16eec2.tar.gz
Merge commit '2bcef4bc172f476217f253d24cb3311eaca504bf' into 5.00_rebase_to_pr
Diffstat (limited to 'middle_end')
-rw-r--r--middle_end/closure/closure.ml74
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 *)