@@ -219,7 +219,8 @@ let is_pure_prim p =
219
219
| Arbitrary_effects , _ -> false
220
220
221
221
(* Check if a clambda term is ``pure'',
222
- that is without side-effects *and* not containing function definitions *)
222
+ that is without side-effects *and* not containing function definitions
223
+ (Pure terms may still read mutable state) *)
223
224
224
225
let rec is_pure = function
225
226
Uvar _ -> true
@@ -729,17 +730,19 @@ type env = {
729
730
*)
730
731
731
732
(* Approximates "no effects and no coeffects" *)
732
- let is_substituable ~mutable_vars = function
733
+ let rec is_substituable ~mutable_vars = function
733
734
| Uvar v -> not (V.Set. mem v mutable_vars)
734
735
| Uconst _ -> true
736
+ | Uoffset (arg , _ ) -> is_substituable ~mutable_vars arg
735
737
| _ -> false
736
738
737
739
(* Approximates "only generative effects" *)
738
740
let is_erasable = function
739
741
| Uclosure _ -> true
740
742
| u -> is_pure u
741
743
742
- let bind_params { backend; mutable_vars; _ } loc fpc params args body =
744
+ let bind_params { backend; mutable_vars; _ } loc fdesc params args funct body =
745
+ let fpc = fdesc.fun_float_const_prop in
743
746
let rec aux subst pl al body =
744
747
match (pl, al) with
745
748
([] , [] ) -> substitute (Debuginfo. from_location loc) (backend, fpc)
@@ -772,7 +775,16 @@ let bind_params { backend; mutable_vars; _ } loc fpc params args body =
772
775
in
773
776
(* Reverse parameters and arguments to preserve right-to-left
774
777
evaluation order (PR#2910). *)
775
- aux V.Map. empty (List. rev params) (List. rev args) body
778
+ let params, args = List. rev params, List. rev args in
779
+ let params, args, body =
780
+ (* Ensure funct is evaluated after args *)
781
+ match params with
782
+ | my_closure :: params when not fdesc.fun_closed ->
783
+ (params @ [my_closure]), (args @ [funct]), body
784
+ | _ ->
785
+ params, args, (if is_pure funct then body else Usequence (funct, body))
786
+ in
787
+ aux V.Map. empty params args body
776
788
777
789
let warning_if_forced_inline ~loc ~attribute warning =
778
790
if attribute = Always_inline then
@@ -782,27 +794,39 @@ let warning_if_forced_inline ~loc ~attribute warning =
782
794
(* Generate a direct application *)
783
795
784
796
let direct_apply env fundesc ufunct uargs ~loc ~attribute =
785
- let app_args =
786
- if fundesc.fun_closed then uargs else uargs @ [ufunct] in
787
- let app =
788
- match fundesc.fun_inline, attribute with
789
- | _ , Never_inline | None , _ ->
790
- let dbg = Debuginfo. from_location loc in
791
- warning_if_forced_inline ~loc ~attribute
792
- " Function information unavailable" ;
793
- Udirect_apply (fundesc.fun_label, app_args, dbg)
794
- | Some (params , body ), _ ->
795
- bind_params env loc fundesc.fun_float_const_prop params app_args
796
- body
797
- in
798
- (* If ufunct can contain side-effects or function definitions,
799
- we must make sure that it is evaluated exactly once.
800
- If the function is not closed, we evaluate ufunct as part of the
801
- arguments.
802
- If the function is closed, we force the evaluation of ufunct first. *)
803
- if not fundesc.fun_closed || is_pure ufunct
804
- then app
805
- else Usequence (ufunct, app)
797
+ match fundesc.fun_inline, attribute with
798
+ | _, Never_inline
799
+ | None , _ ->
800
+ let dbg = Debuginfo. from_location loc in
801
+ warning_if_forced_inline ~loc ~attribute
802
+ " Function information unavailable" ;
803
+ if fundesc.fun_closed && is_pure ufunct then
804
+ Udirect_apply (fundesc.fun_label, uargs, dbg)
805
+ else if not fundesc.fun_closed &&
806
+ is_substituable ~mutable_vars: env.mutable_vars ufunct then
807
+ Udirect_apply (fundesc.fun_label, uargs @ [ufunct], dbg)
808
+ else begin
809
+ let args = List. map (fun arg ->
810
+ if is_substituable ~mutable_vars: env.mutable_vars arg then
811
+ None , arg
812
+ else
813
+ let id = V. create_local " arg" in
814
+ Some (VP. create id, arg), Uvar id) uargs in
815
+ let app_args = List. map snd args in
816
+ List. fold_left (fun app (binding ,_ ) ->
817
+ match binding with
818
+ | None -> app
819
+ | Some (v , e ) -> Ulet (Immutable , Pgenval , v, e, app))
820
+ (if fundesc.fun_closed then
821
+ Usequence (ufunct, Udirect_apply (fundesc.fun_label, app_args, dbg))
822
+ else
823
+ let clos = V. create_local " clos" in
824
+ Ulet (Immutable , Pgenval , VP. create clos, ufunct,
825
+ Udirect_apply (fundesc.fun_label, app_args @ [Uvar clos], dbg)))
826
+ args
827
+ end
828
+ | Some (params , body ), _ ->
829
+ bind_params env loc fundesc params uargs ufunct body
806
830
807
831
(* Add [Value_integer] info to the approximation of an application *)
808
832
0 commit comments