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