Skip to content

Commit dc1c1ce

Browse files
authored
flambda-backend: Layouts for parameters in lambda & remove most layout_top (#1084)
1 parent 49fea78 commit dc1c1ce

13 files changed

+246
-197
lines changed

lambda/lambda.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ val layout_lazy : layout
496496
val layout_lazy_contents : layout
497497
(* A layout that is Pgenval because we are missing layout polymorphism *)
498498
val layout_any_value : layout
499+
(* A layout that is Pgenval because it is bound by a letrec *)
499500
val layout_letrec : layout
500501

501502
val layout_top : layout

lambda/matching.ml

Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ end
926926

927927
type 'row pattern_matching = {
928928
mutable cases : 'row list;
929-
args : (lambda * let_kind) list;
929+
args : (lambda * let_kind * layout) list;
930930
(** args are not just Ident.t in at least the following cases:
931931
- when matching the arguments of a constructor,
932932
direct field projections are used (make_field_args)
@@ -1433,7 +1433,7 @@ and precompile_var args cls def k =
14331433
If the rest doesn't generate any split, abort and do_not_precompile. *)
14341434
match args with
14351435
| [] -> assert false
1436-
| _ :: ((Lvar v, _) as arg) :: rargs -> (
1436+
| _ :: ((Lvar v, _, _) as arg) :: rargs -> (
14371437
(* We will use the name of the head column of the submatrix
14381438
we compile, and this is the *second* column of our argument. *)
14391439
match cls with
@@ -1451,7 +1451,7 @@ and precompile_var args cls def k =
14511451
(* we learned by pattern-matching on [args]
14521452
that [p::ps] has at least two arguments,
14531453
so [ps] must be non-empty *)
1454-
half_simplify_clause ~arg:(fst arg) (ps, act))
1454+
half_simplify_clause ~arg:(Lvar v) (ps, act))
14551455
cls
14561456
and var_def = Default_environment.pop_column def in
14571457
let { me = first; matrix }, nexts =
@@ -1664,7 +1664,7 @@ let make_line_matching get_expr_args head def = function
16641664
}
16651665

16661666
type 'a division = {
1667-
args : (lambda * let_kind) list;
1667+
args : (lambda * let_kind * layout) list;
16681668
cells : ('a * cell) list
16691669
}
16701670

@@ -1754,7 +1754,7 @@ let get_pat_args_constr p rem =
17541754
| { pat_desc = Tpat_construct (_, _, args, _) } -> args @ rem
17551755
| _ -> assert false
17561756

1757-
let get_expr_args_constr ~scopes head (arg, _mut) rem =
1757+
let get_expr_args_constr ~scopes head (arg, _mut, layout) rem =
17581758
let cstr =
17591759
match head.pat_desc with
17601760
| Patterns.Head.Construct cstr -> cstr
@@ -1766,19 +1766,19 @@ let get_expr_args_constr ~scopes head (arg, _mut) rem =
17661766
if pos > last_pos then
17671767
argl
17681768
else
1769-
(Lprim (Pfield (pos, Reads_agree), [ arg ], loc), binding_kind)
1769+
(Lprim (Pfield (pos, Reads_agree), [ arg ], loc), binding_kind, layout_field)
17701770
:: make_args (pos + 1)
17711771
in
17721772
make_args first_pos
17731773
in
17741774
if cstr.cstr_inlined <> None then
1775-
(arg, Alias) :: rem
1775+
(arg, Alias, layout) :: rem
17761776
else
17771777
match cstr.cstr_tag with
17781778
| Cstr_constant _
17791779
| Cstr_block _ ->
17801780
make_field_accesses Alias 0 (cstr.cstr_arity - 1) rem
1781-
| Cstr_unboxed -> (arg, Alias) :: rem
1781+
| Cstr_unboxed -> (arg, Alias, layout) :: rem
17821782
| Cstr_extension _ -> make_field_accesses Alias 1 cstr.cstr_arity rem
17831783

17841784
let divide_constructor ~scopes ctx pm =
@@ -1796,10 +1796,10 @@ let get_expr_args_variant_constant = drop_expr_arg
17961796
let nonconstant_variant_field index =
17971797
Lambda.Pfield(index, Reads_agree)
17981798

1799-
let get_expr_args_variant_nonconst ~scopes head (arg, _mut) rem =
1799+
let get_expr_args_variant_nonconst ~scopes head (arg, _mut, _layout) rem =
18001800
let loc = head_loc ~scopes head in
18011801
let field_prim = nonconstant_variant_field 1 in
1802-
(Lprim (field_prim, [ arg ], loc), Alias) :: rem
1802+
(Lprim (field_prim, [ arg ], loc), Alias, layout_field) :: rem
18031803

18041804
let divide_variant ~scopes row ctx { cases = cl; args; default = def } =
18051805
let rec divide = function
@@ -2006,9 +2006,9 @@ let inline_lazy_force arg pos loc =
20062006
tables (~ 250 elts); conditionals are better *)
20072007
inline_lazy_force_cond arg pos loc
20082008

2009-
let get_expr_args_lazy ~scopes head (arg, _mut) rem =
2009+
let get_expr_args_lazy ~scopes head (arg, _mut, _layout) rem =
20102010
let loc = head_loc ~scopes head in
2011-
(inline_lazy_force arg Rc_normal loc, Strict) :: rem
2011+
(inline_lazy_force arg Rc_normal loc, Strict, layout_lazy_contents) :: rem
20122012

20132013
let divide_lazy ~scopes head ctx pm =
20142014
divide_line (Context.specialize head)
@@ -2024,14 +2024,14 @@ let get_pat_args_tuple arity p rem =
20242024
| { pat_desc = Tpat_tuple args } -> args @ rem
20252025
| _ -> assert false
20262026

2027-
let get_expr_args_tuple ~scopes head (arg, _mut) rem =
2027+
let get_expr_args_tuple ~scopes head (arg, _mut, _layout) rem =
20282028
let loc = head_loc ~scopes head in
20292029
let arity = Patterns.Head.arity head in
20302030
let rec make_args pos =
20312031
if pos >= arity then
20322032
rem
20332033
else
2034-
(Lprim (Pfield (pos, Reads_agree), [ arg ], loc), Alias)
2034+
(Lprim (Pfield (pos, Reads_agree), [ arg ], loc), Alias, layout_field)
20352035
:: make_args (pos + 1)
20362036
in
20372037
make_args 0
@@ -2057,7 +2057,7 @@ let get_pat_args_record num_fields p rem =
20572057
record_matching_line num_fields lbl_pat_list @ rem
20582058
| _ -> assert false
20592059

2060-
let get_expr_args_record ~scopes head (arg, _mut) rem =
2060+
let get_expr_args_record ~scopes head (arg, _mut, layout) rem =
20612061
let loc = head_loc ~scopes head in
20622062
let all_labels =
20632063
let open Patterns.Head in
@@ -2077,24 +2077,25 @@ let get_expr_args_record ~scopes head (arg, _mut) rem =
20772077
| Immutable -> Reads_agree
20782078
| Mutable -> Reads_vary
20792079
in
2080-
let access =
2080+
let access, layout =
20812081
match lbl.lbl_repres with
20822082
| Record_regular
20832083
| Record_inlined _ ->
2084-
Lprim (Pfield (lbl.lbl_pos, sem), [ arg ], loc)
2085-
| Record_unboxed _ -> arg
2084+
Lprim (Pfield (lbl.lbl_pos, sem), [ arg ], loc), layout_field
2085+
| Record_unboxed _ -> arg, layout
20862086
| Record_float ->
20872087
(* TODO: could optimise to Alloc_local sometimes *)
2088-
Lprim (Pfloatfield (lbl.lbl_pos, sem, alloc_heap), [ arg ], loc)
2088+
Lprim (Pfloatfield (lbl.lbl_pos, sem, alloc_heap), [ arg ], loc),
2089+
layout_float
20892090
| Record_extension _ ->
2090-
Lprim (Pfield (lbl.lbl_pos + 1, sem), [ arg ], loc)
2091+
Lprim (Pfield (lbl.lbl_pos + 1, sem), [ arg ], loc), layout_field
20912092
in
20922093
let str =
20932094
match lbl.lbl_mut with
20942095
| Immutable -> Alias
20952096
| Mutable -> StrictOpt
20962097
in
2097-
(access, str) :: make_args (pos + 1)
2098+
(access, str, layout) :: make_args (pos + 1)
20982099
in
20992100
make_args 0
21002101

@@ -2121,7 +2122,7 @@ let get_pat_args_array p rem =
21212122
| { pat_desc = Tpat_array (_, patl) } -> patl @ rem
21222123
| _ -> assert false
21232124

2124-
let get_expr_args_array ~scopes kind head (arg, _mut) rem =
2125+
let get_expr_args_array ~scopes kind head (arg, _mut, _layout) rem =
21252126
let am, len =
21262127
let open Patterns.Head in
21272128
match head.pat_desc with
@@ -2133,11 +2134,13 @@ let get_expr_args_array ~scopes kind head (arg, _mut) rem =
21332134
if pos >= len then
21342135
rem
21352136
else
2137+
(* CR ncourant: could do better than layout_field using kind *)
21362138
( Lprim
21372139
(Parrayrefu kind, [ arg; Lconst (Const_base (Const_int pos)) ], loc),
2138-
match am with
2140+
(match am with
21392141
| Mutable -> StrictOpt
2140-
| Immutable -> Alias )
2142+
| Immutable -> Alias),
2143+
layout_field)
21412144
:: make_args (pos + 1)
21422145
in
21432146
make_args 0
@@ -3276,25 +3279,25 @@ and compile_match_nonempty ~scopes value_kind repr partial ctx
32763279
(m : Typedtree.pattern Non_empty_row.t clause pattern_matching)=
32773280
match m with
32783281
| { cases = []; args = [] } -> comp_exit ctx m
3279-
| { args = (arg, str) :: argl } ->
3282+
| { args = (arg, str, layout) :: argl } ->
32803283
let v, newarg = arg_to_var arg m.cases in
3281-
let args = (newarg, Alias) :: argl in
3284+
let args = (newarg, Alias, layout) :: argl in
32823285
let cases = List.map (half_simplify_nonempty ~arg:newarg) m.cases in
32833286
let m = { m with args; cases } in
32843287
let first_match, rem =
32853288
split_and_precompile_half_simplified ~arg:newarg m in
3286-
combine_handlers ~scopes value_kind repr partial ctx (v, str, Lambda.layout_top, arg) first_match rem
3289+
combine_handlers ~scopes value_kind repr partial ctx (v, str, layout, arg) first_match rem
32873290
| _ -> assert false
32883291

32893292
and compile_match_simplified ~scopes value_kind repr partial ctx
32903293
(m : Simple.clause pattern_matching) =
32913294
match m with
32923295
| { cases = []; args = [] } -> comp_exit ctx m
3293-
| { args = ((Lvar v as arg), str) :: argl } ->
3294-
let args = (arg, Alias) :: argl in
3296+
| { args = ((Lvar v as arg), str, layout) :: argl } ->
3297+
let args = (arg, Alias, layout) :: argl in
32953298
let m = { m with args } in
32963299
let first_match, rem = split_and_precompile_simplified m in
3297-
combine_handlers value_kind ~scopes repr partial ctx (v, str, Lambda.layout_top, arg)
3300+
combine_handlers value_kind ~scopes repr partial ctx (v, str, layout, arg)
32983301
first_match rem
32993302
| _ -> assert false
33003303

@@ -3332,7 +3335,7 @@ and do_compile_matching ~scopes value_kind repr partial ctx pmh =
33323335
| Pm pm -> (
33333336
let arg =
33343337
match pm.args with
3335-
| (first_arg, _) :: _ -> first_arg
3338+
| (first_arg, _, _) :: _ -> first_arg
33363339
| _ ->
33373340
(* We arrive in do_compile_matching from:
33383341
- compile_matching
@@ -3556,9 +3559,9 @@ let toplevel_handler ~scopes value_kind loc ~failer partial args cases compile_f
35563559
check_total ~scopes value_kind loc ~failer total lam raise_num
35573560
end
35583561

3559-
let compile_matching ~scopes value_kind loc ~failer repr arg pat_act_list partial =
3562+
let compile_matching ~scopes value_kind loc ~failer repr (arg, arg_layout) pat_act_list partial =
35603563
let partial = check_partial pat_act_list partial in
3561-
let args = [ (arg, Strict) ] in
3564+
let args = [ (arg, Strict, arg_layout) ] in
35623565
let rows = map_on_rows (fun pat -> (pat, [])) pat_act_list in
35633566
toplevel_handler ~scopes value_kind loc ~failer partial args rows (fun partial pm ->
35643567
compile_match_nonempty ~scopes value_kind repr partial (Context.start 1) pm)
@@ -3577,11 +3580,11 @@ let for_trywith ~scopes value_kind loc param pat_act_list =
35773580
the reraise (hence the [_noloc]) to avoid seeing this
35783581
silent reraise in exception backtraces. *)
35793582
compile_matching ~scopes value_kind loc ~failer:(Reraise_noloc param)
3580-
None param pat_act_list Partial
3583+
None (param, layout_block) pat_act_list Partial
35813584

35823585
let simple_for_let ~scopes value_kind loc param pat body =
35833586
compile_matching ~scopes value_kind loc ~failer:Raise_match_failure
3584-
None param [ (pat, body) ] Partial
3587+
None (param, Typeopt.layout pat.pat_env pat.pat_type) [ (pat, body) ] Partial
35853588

35863589
(* Optimize binding of immediate tuples
35873590
@@ -3748,7 +3751,8 @@ let for_let ~scopes loc param pat body_kind body =
37483751
(* Easy case since variables are available *)
37493752
let for_tupled_function ~scopes loc kind paraml pats_act_list partial =
37503753
let partial = check_partial_list pats_act_list partial in
3751-
let args = List.map (fun id -> (Lvar id, Strict)) paraml in
3754+
(* The arguments of a tupled function are always values since they must be fields *)
3755+
let args = List.map (fun id -> (Lvar id, Strict, layout_field)) paraml in
37523756
let handler =
37533757
toplevel_handler ~scopes kind loc ~failer:Raise_match_failure
37543758
partial args pats_act_list in
@@ -3839,23 +3843,25 @@ let do_for_multiple_match ~scopes value_kind loc paraml mode pat_act_list partia
38393843
let repr = None in
38403844
let arg =
38413845
let sloc = Scoped_location.of_location ~scopes loc in
3842-
Lprim (Pmakeblock (0, Immutable, None, mode), paraml, sloc) in
3846+
(* CR ncourant: this can build a mixed block, but it should never actually be
3847+
created except if the pattern-matching binds it, in which case it should be
3848+
rejected by the typing. Do we really trust this case will not happen? *)
3849+
Lprim (Pmakeblock (0, Immutable, None, mode), List.map fst paraml, sloc) in
38433850
let handler =
38443851
let partial = check_partial pat_act_list partial in
38453852
let rows = map_on_rows (fun p -> (p, [])) pat_act_list in
38463853
toplevel_handler ~scopes value_kind loc ~failer:Raise_match_failure
3847-
partial [ (arg, Strict) ] rows in
3854+
partial [ (arg, Strict, layout_block) ] rows in
38483855
handler (fun partial pm1 ->
38493856
let pm1_half =
38503857
{ pm1 with cases = List.map (half_simplify_nonempty ~arg) pm1.cases }
38513858
in
38523859
let next, nexts = split_and_precompile_half_simplified ~arg pm1_half in
38533860
let size = List.length paraml
3854-
and idl = List.map (function
3855-
| Lvar id -> id
3856-
| _ -> Ident.create_local "*match*") paraml in
3857-
let idl_with_layouts = List.map (fun id -> (id, Lambda.layout_top)) idl in
3858-
let args = List.map (fun id -> (Lvar id, Alias)) idl in
3861+
and idl_with_layouts = List.map (function
3862+
| Lvar id, layout -> id, layout
3863+
| _, layout -> Ident.create_local "*match*", layout) paraml in
3864+
let args = List.map (fun (id, layout) -> (Lvar id, Alias, layout)) idl_with_layouts in
38593865
let flat_next = flatten_precompiled size args next
38603866
and flat_nexts =
38613867
List.map (fun (e, pm) -> (e, flatten_precompiled size args pm)) nexts
@@ -3864,24 +3870,24 @@ let do_for_multiple_match ~scopes value_kind loc paraml mode pat_act_list partia
38643870
comp_match_handlers value_kind (compile_flattened ~scopes value_kind repr) partial
38653871
(Context.start size) flat_next flat_nexts
38663872
in
3867-
List.fold_right2 (bind_with_layout Strict) idl_with_layouts paraml lam, total
3873+
List.fold_right2 (bind_with_layout Strict) idl_with_layouts (List.map fst paraml) lam, total
38683874
)
38693875

38703876
(* PR#4828: Believe it or not, the 'paraml' argument below
38713877
may not be side effect free. *)
38723878

3873-
let param_to_var param =
3879+
let param_to_var (param, layout) =
38743880
match param with
3875-
| Lvar v -> (v, None)
3876-
| _ -> (Ident.create_local "*match*", Some param)
3881+
| Lvar v -> (v, layout, None)
3882+
| _ -> (Ident.create_local "*match*", layout, Some param)
38773883

3878-
let bind_opt (v, eo) k =
3884+
let bind_opt (v, layout, eo) k =
38793885
match eo with
38803886
| None -> k
3881-
| Some e -> Lambda.bind_with_layout Strict (v, Lambda.layout_top) e k
3887+
| Some e -> Lambda.bind_with_layout Strict (v, layout) e k
38823888

38833889
let for_multiple_match ~scopes value_kind loc paraml mode pat_act_list partial =
38843890
let v_paraml = List.map param_to_var paraml in
3885-
let paraml = List.map (fun (v, _) -> Lvar v) v_paraml in
3891+
let paraml = List.map (fun (v, layout, _) -> (Lvar v, layout)) v_paraml in
38863892
List.fold_right bind_opt v_paraml
38873893
(do_for_multiple_match ~scopes value_kind loc paraml mode pat_act_list partial)

lambda/matching.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ open Debuginfo.Scoped_location
2222
(* Entry points to match compiler *)
2323
val for_function:
2424
scopes:scopes -> layout -> Location.t ->
25-
int ref option -> lambda -> (pattern * lambda) list -> partial ->
25+
int ref option -> (lambda * layout) -> (pattern * lambda) list -> partial ->
2626
lambda
2727
val for_trywith:
2828
scopes:scopes -> layout -> Location.t ->
@@ -34,7 +34,7 @@ val for_let:
3434
lambda
3535
val for_multiple_match:
3636
scopes:scopes -> layout -> Location.t ->
37-
lambda list -> alloc_mode -> (pattern * lambda) list -> partial ->
37+
(lambda * layout) list -> alloc_mode -> (pattern * lambda) list -> partial ->
3838
lambda
3939

4040
val for_tupled_function:

lambda/simplif.ml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -777,8 +777,14 @@ let split_default_wrapper ~id:fun_id ~kind ~params ~return ~body
777777
List.iter (fun (id, _) -> if Ident.Set.mem id fv then raise Exit) map;
778778

779779
let inner_id = Ident.create_local (Ident.name fun_id ^ "_inner") in
780-
let map_param p = try List.assoc p map with Not_found -> p in
781-
let args = List.map (fun (p, _) -> Lvar (map_param p)) params in
780+
let map_param p layout =
781+
try
782+
(* If the param is optional, then it must be a value *)
783+
List.assoc p map, Lambda.layout_field
784+
with
785+
Not_found -> p, layout
786+
in
787+
let args = List.map (fun (p, layout) -> Lvar (fst (map_param p layout))) params in
782788
let wrapper_body =
783789
Lapply {
784790
ap_func = Lvar inner_id;
@@ -793,18 +799,18 @@ let split_default_wrapper ~id:fun_id ~kind ~params ~return ~body
793799
ap_probe=None;
794800
}
795801
in
796-
let inner_params = List.map map_param (List.map fst params) in
797-
let new_ids = List.map Ident.rename inner_params in
802+
let inner_params = List.map (fun (param, layout) -> map_param param layout) params in
803+
let new_ids = List.map (fun (param, layout) -> (Ident.rename param, layout)) inner_params in
798804
let subst =
799-
List.fold_left2 (fun s id new_id ->
805+
List.fold_left2 (fun s (id, _) (new_id, _) ->
800806
Ident.Map.add id new_id s
801807
) Ident.Map.empty inner_params new_ids
802808
in
803809
let body = Lambda.rename subst body in
804810
let body = if add_region then Lregion (body, return) else body in
805811
let inner_fun =
806812
lfunction ~kind:(Curried {nlocal=0})
807-
~params:(List.map (fun id -> id, Lambda.layout_top) new_ids)
813+
~params:new_ids
808814
~return ~body ~attr ~loc ~mode ~region:true
809815
in
810816
(wrapper_body, (inner_id, inner_fun))

0 commit comments

Comments
 (0)