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