Skip to content

Commit b12c3c6

Browse files
authored
Enable Stdlib.Effect + add Flambda 2 support (#2205)
1 parent 944f991 commit b12c3c6

34 files changed

+760
-289
lines changed

backend/cmm_helpers.ml

+42
Original file line numberDiff line numberDiff line change
@@ -4108,3 +4108,45 @@ let allocate_unboxed_nativeint_array =
41084108
let block_header x y = block_header x y
41094109

41104110
let dls_get ~dbg = Cop (Cdls_get, [], dbg)
4111+
4112+
let perform ~dbg eff =
4113+
let cont =
4114+
make_alloc dbg Runtimetags.cont_tag
4115+
[int_const dbg 0]
4116+
~mode:Lambda.alloc_heap
4117+
in
4118+
(* Rc_normal means "allow tailcalls". Preventing them here by using Rc_nontail
4119+
improves backtraces of paused fibers. *)
4120+
Cop
4121+
( Capply (typ_val, Rc_nontail),
4122+
[Cconst_symbol (Cmm.global_symbol "caml_perform", dbg); eff; cont],
4123+
dbg )
4124+
4125+
let run_stack ~dbg ~stack ~f ~arg =
4126+
(* Rc_normal would be fine here, but this is unlikely to ever be a tail call
4127+
(usages of this primitive shouldn't be generated in tail position), so we
4128+
use Rc_nontail for clarity. *)
4129+
Cop
4130+
( Capply (typ_val, Rc_nontail),
4131+
[Cconst_symbol (Cmm.global_symbol "caml_runstack", dbg); stack; f; arg],
4132+
dbg )
4133+
4134+
let resume ~dbg ~stack ~f ~arg =
4135+
(* Rc_normal is required here, because there are some uses of effects with
4136+
repeated resumes, and these should consume O(1) stack space by tail-calling
4137+
caml_resume. *)
4138+
Cop
4139+
( Capply (typ_val, Rc_normal),
4140+
[Cconst_symbol (Cmm.global_symbol "caml_resume", dbg); stack; f; arg],
4141+
dbg )
4142+
4143+
let reperform ~dbg ~eff ~cont ~last_fiber =
4144+
(* Rc_normal is required here, this is used in tail position and should tail
4145+
call. *)
4146+
Cop
4147+
( Capply (typ_val, Rc_normal),
4148+
[ Cconst_symbol (Cmm.global_symbol "caml_reperform", dbg);
4149+
eff;
4150+
cont;
4151+
last_fiber ],
4152+
dbg )

backend/cmm_helpers.mli

+23
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,29 @@ val atomic_compare_and_set :
964964

965965
val emit_gc_roots_table : symbols:symbol list -> phrase list -> phrase list
966966

967+
val perform : dbg:Debuginfo.t -> expression -> expression
968+
969+
val run_stack :
970+
dbg:Debuginfo.t ->
971+
stack:expression ->
972+
f:expression ->
973+
arg:expression ->
974+
expression
975+
976+
val resume :
977+
dbg:Debuginfo.t ->
978+
stack:expression ->
979+
f:expression ->
980+
arg:expression ->
981+
expression
982+
983+
val reperform :
984+
dbg:Debuginfo.t ->
985+
eff:expression ->
986+
cont:expression ->
987+
last_fiber:expression ->
988+
expression
989+
967990
(** Allocate a block to hold an unboxed float32 array for the given number of
968991
elements. *)
969992
val allocate_unboxed_float32_array :

middle_end/flambda2/from_lambda/closure_conversion.ml

+92-7
Original file line numberDiff line numberDiff line change
@@ -404,10 +404,11 @@ module Inlining = struct
404404
let callee = Apply.callee apply in
405405
let region_inlined_into =
406406
match Apply.call_kind apply with
407-
| Function { alloc_mode; _ } | Method { alloc_mode; _ } -> alloc_mode
408-
| C_call _ ->
407+
| Function { alloc_mode; _ } -> alloc_mode
408+
| Method _ | C_call _ | Effect _ ->
409409
Misc.fatal_error
410-
"Trying to call [Closure_conversion.Inlining.inline] on a C call."
410+
"Trying to call [Closure_conversion.Inlining.inline] on a non-OCaml \
411+
function call."
411412
in
412413
let args = Apply.args apply in
413414
let apply_return_continuation = Apply.continuation apply in
@@ -508,10 +509,7 @@ let close_c_call acc env ~loc ~let_bound_ids_with_kinds
508509
in
509510
let cost_metrics_of_body, free_names_of_body, acc, body =
510511
Acc.measure_cost_metrics acc ~f:(fun acc ->
511-
k acc
512-
(List.map
513-
(fun var -> Named.create_simple (Simple.var var))
514-
let_bound_vars))
512+
k acc (List.map Named.create_var let_bound_vars))
515513
in
516514
let alloc_mode =
517515
match Lambda.alloc_mode_of_primitive_description prim_desc with
@@ -752,6 +750,82 @@ let close_raise acc env ~raise_kind ~arg ~dbg exn_continuation =
752750
let acc, arg = find_simple acc env arg in
753751
close_raise0 acc env ~raise_kind ~arg ~dbg exn_continuation
754752

753+
let close_effect_primitive acc env ~dbg exn_continuation
754+
(prim : Lambda.primitive) ~args ~let_bound_ids_with_kinds
755+
(k : Acc.t -> Named.t list -> Expr_with_acc.t) : Expr_with_acc.t =
756+
if not Config.runtime5
757+
then Misc.fatal_error "Effect primitives are only supported on runtime5";
758+
(* CR mshinwell: share with close_c_call, above *)
759+
let _env, let_bound_vars =
760+
List.fold_left_map
761+
(fun env (id, kind) -> Env.add_var_like env id Not_user_visible kind)
762+
env let_bound_ids_with_kinds
763+
in
764+
let let_bound_var =
765+
match let_bound_vars with
766+
| [let_bound_var] -> let_bound_var
767+
| [] | _ :: _ :: _ ->
768+
Misc.fatal_errorf
769+
"close_effect_primitive: expected singleton return for primitive %a, \
770+
but got: [%a]"
771+
Printlambda.primitive prim
772+
(Format.pp_print_list ~pp_sep:Format.pp_print_space Variable.print)
773+
let_bound_vars
774+
in
775+
let continuation = Continuation.create () in
776+
let return_kind = Flambda_kind.With_subkind.any_value in
777+
let params =
778+
[BP.create let_bound_var return_kind] |> Bound_parameters.create
779+
in
780+
let close call_kind =
781+
let apply acc =
782+
Apply_expr.create ~callee:None ~continuation:(Return continuation)
783+
exn_continuation ~args:[] ~args_arity:Flambda_arity.nullary
784+
~return_arity:
785+
(Flambda_arity.create_singletons
786+
[Flambda_kind.With_subkind.any_value])
787+
~call_kind dbg ~inlined:Never_inlined
788+
~inlining_state:(Inlining_state.default ~round:0)
789+
~probe:None ~position:Normal
790+
~relative_history:Inlining_history.Relative.empty
791+
|> Expr_with_acc.create_apply acc
792+
in
793+
Let_cont_with_acc.build_non_recursive acc continuation
794+
~handler_params:params
795+
~handler:(fun acc ->
796+
let cost_metrics_of_body, free_names_of_body, acc, code_after_call =
797+
Acc.measure_cost_metrics acc ~f:(fun acc ->
798+
k acc (List.map Named.create_var let_bound_vars))
799+
in
800+
let acc =
801+
Acc.with_cost_metrics
802+
(Cost_metrics.( + ) (Acc.cost_metrics acc) cost_metrics_of_body)
803+
(Acc.with_free_names free_names_of_body acc)
804+
in
805+
acc, code_after_call)
806+
~body:apply ~is_exn_handler:false ~is_cold:false
807+
in
808+
let module C = Call_kind in
809+
let module E = C.Effect in
810+
match[@ocaml.warning "-fragile-match"] prim, args with
811+
| Pperform, [[eff]] ->
812+
let call_kind = C.effect (E.perform ~eff) in
813+
close call_kind
814+
| Prunstack, [[stack]; [f]; [arg]] ->
815+
let call_kind = C.effect (E.run_stack ~stack ~f ~arg) in
816+
close call_kind
817+
| Presume, [[stack]; [f]; [arg]] ->
818+
let call_kind = C.effect (E.resume ~stack ~f ~arg) in
819+
close call_kind
820+
| Preperform, [[eff]; [cont]; [last_fiber]] ->
821+
let call_kind = C.effect (E.reperform ~eff ~cont ~last_fiber) in
822+
close call_kind
823+
| _ ->
824+
Misc.fatal_errorf
825+
"close_effect_primitive: Wrong primitive and/or number of arguments: %a \
826+
(%d args)"
827+
Printlambda.primitive prim (List.length args)
828+
755829
let close_primitive acc env ~let_bound_ids_with_kinds named
756830
(prim : Lambda.primitive) ~args loc
757831
(exn_continuation : IR.exn_continuation option) ~current_region
@@ -879,6 +953,17 @@ let close_primitive acc env ~let_bound_ids_with_kinds named
879953
assert false
880954
in
881955
k acc [Named.create_simple (Simple.symbol sym)]
956+
| (Pperform | Prunstack | Presume | Preperform), args ->
957+
let exn_continuation =
958+
match exn_continuation with
959+
| None ->
960+
Misc.fatal_errorf
961+
"Effect primitive is missing exception continuation: %a"
962+
IR.print_named named
963+
| Some exn_continuation -> exn_continuation
964+
in
965+
close_effect_primitive acc env ~dbg exn_continuation prim ~args
966+
~let_bound_ids_with_kinds k
882967
| prim, args ->
883968
Lambda_to_flambda_primitives.convert_and_bind acc exn_continuation
884969
~big_endian:(Env.big_endian env) ~register_const0 prim ~args dbg

middle_end/flambda2/from_lambda/closure_conversion_aux.ml

+1-2
Original file line numberDiff line numberDiff line change
@@ -957,8 +957,7 @@ module Expr_with_acc = struct
957957
{ function_call = Indirect_unknown_arity | Indirect_known_arity; _ }
958958
->
959959
false
960-
| Method _ -> false
961-
| C_call _ -> false)
960+
| Method _ | C_call _ | Effect _ -> false)
962961
in
963962
let acc =
964963
match Apply.callee apply with

middle_end/flambda2/from_lambda/lambda_to_flambda.ml

+1-3
Original file line numberDiff line numberDiff line change
@@ -716,9 +716,7 @@ let primitive_can_raise (prim : Lambda.primitive) =
716716
| Punboxed_product_field _ | Pget_header _ ->
717717
false
718718
| Patomic_exchange | Patomic_cas | Patomic_fetch_add | Patomic_load _ -> false
719-
| Prunstack | Pperform | Presume | Preperform ->
720-
Misc.fatal_errorf "Primitive %a is not yet supported by Flambda 2"
721-
Printlambda.primitive prim
719+
| Prunstack | Pperform | Presume | Preperform -> true (* XXX! *)
722720
| Pdls_get -> false
723721

724722
type non_tail_continuation =

middle_end/flambda2/from_lambda/lambda_to_flambda_primitives.ml

+2-4
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,8 @@ let convert_lprim ~big_endian (prim : L.primitive) (args : Simple.t list list)
19931993
%a (%a)"
19941994
Printlambda.primitive prim H.print_list_of_lists_of_simple_or_prim args
19951995
| ( ( Pignore | Psequand | Psequor | Pbytes_of_string | Pbytes_to_string
1996-
| Parray_of_iarray | Parray_to_iarray ),
1996+
| Parray_of_iarray | Parray_to_iarray | Prunstack | Pperform | Presume
1997+
| Preperform ),
19971998
_ ) ->
19981999
Misc.fatal_errorf
19992000
"[%a] should have been removed by [Lambda_to_flambda.transform_primitive]"
@@ -2002,9 +2003,6 @@ let convert_lprim ~big_endian (prim : L.primitive) (args : Simple.t list list)
20022003
Misc.fatal_errorf
20032004
"[%a] should have been handled by [Closure_conversion.close_primitive]"
20042005
Printlambda.primitive prim
2005-
| (Prunstack | Pperform | Presume | Preperform), _ ->
2006-
Misc.fatal_errorf "Primitive %a is not yet supported by Flambda 2"
2007-
Printlambda.primitive prim
20082006

20092007
module Acc = Closure_conversion_aux.Acc
20102008
module Expr_with_acc = Closure_conversion_aux.Expr_with_acc

middle_end/flambda2/kinds/flambda_arity.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ val create : 'uc Component_for_creation.t list -> 'uc t
5555
val create_singletons : Flambda_kind.With_subkind.t list -> [> ] t
5656

5757
(** "No parameters". (Not e.g. "one parameter of type void".) *)
58-
val nullary : [> `Unarized] t
58+
val nullary : [> ] t
5959

6060
(** How many parameters, potentially of unboxed product layout, the given
6161
arity describes. *)

middle_end/flambda2/parser/flambda_to_fexpr.ml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ and apply_expr env (app : Apply_expr.t) : Fexpr.expr =
10401040
Function (Indirect alloc)
10411041
| C_call { needs_caml_c_call; _ } -> C_call { alloc = needs_caml_c_call }
10421042
| Method _ -> Misc.fatal_error "TODO: Method call kind"
1043+
| Effect _ -> Misc.fatal_error "TODO: Effect call kind"
10431044
in
10441045
let param_arity = Apply_expr.args_arity app in
10451046
let return_arity = Apply_expr.return_arity app in
@@ -1063,9 +1064,9 @@ and apply_expr env (app : Apply_expr.t) : Fexpr.expr =
10631064
let params_arity = Some (complex_arity param_arity) in
10641065
let ret_arity = arity return_arity in
10651066
Some { params_arity; ret_arity }
1066-
| Function { function_call = Indirect_unknown_arity; alloc_mode = _ }
1067-
| Method _ ->
1067+
| Function { function_call = Indirect_unknown_arity; alloc_mode = _ } ->
10681068
None
1069+
| Method _ | Effect _ -> assert false
10691070
in
10701071
let inlined : Fexpr.inlined_attribute option =
10711072
if Flambda2_terms.Inlined_attribute.is_default (Apply_expr.inlined app)

middle_end/flambda2/simplify/inlining/inlining_transforms.ml

+4-3
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@ let inline dacc ~apply ~unroll_to ~was_inline_always function_decl =
9595
let callee = Apply.callee apply in
9696
let region_inlined_into =
9797
match Apply.call_kind apply with
98-
| Function { alloc_mode; _ } | Method { alloc_mode; _ } -> alloc_mode
99-
| C_call _ ->
98+
| Function { alloc_mode; _ } -> alloc_mode
99+
| Method _ | C_call _ | Effect _ ->
100100
Misc.fatal_error
101-
"Trying to call [Inlining_transforms.inline] on a C call."
101+
"Trying to call [Inlining_transforms.inline] on something other than \
102+
an OCaml function call."
102103
in
103104
let args = Apply.args apply in
104105
let apply_return_continuation = Apply.continuation apply in

0 commit comments

Comments
 (0)