Skip to content

Commit fd07032

Browse files
committed
1 parent a75ec86 commit fd07032

File tree

6 files changed

+119
-55
lines changed

6 files changed

+119
-55
lines changed

backend/cmm_helpers.ml

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,35 +2441,34 @@ let cache_public_method meths tag cache dbg =
24412441
Cvar tagged ) ) ) ) )
24422442

24432443
let has_local_allocs e =
2444-
let rec loop = function
2445-
| Cregion e ->
2446-
(* Local allocations within a nested region do not affect this region,
2447-
except inside a Ctail block *)
2448-
loop_until_tail e
2449-
| Cop (Calloc Alloc_local, _, _) | Cop ((Cextcall _ | Capply _), _, _) ->
2444+
let rec loop ~depth = function
2445+
| Cregion e -> loop ~depth:(depth + 1) e
2446+
| Ctail e -> if depth = 0 then () else loop ~depth:(depth - 1) e
2447+
| Cop ((Calloc Alloc_local | Cextcall _ | Capply _), _, _) when depth = 0 ->
24502448
raise Exit
2451-
| e -> iter_shallow loop e
2452-
and loop_until_tail = function
2453-
| Ctail e -> loop e
2454-
| Cregion _ -> ()
2455-
| e -> ignore (iter_shallow_tail loop_until_tail e)
2449+
| e -> iter_shallow (loop ~depth) e
24562450
in
2457-
match loop e with () -> false | exception Exit -> true
2451+
match loop e ~depth:0 with () -> false | exception Exit -> true
24582452

24592453
let remove_region_tail e =
2460-
let rec has_tail = function
2461-
| Ctail _ | Cop (Capply (_, Rc_close_at_apply), _, _) -> raise Exit
2462-
| Cregion _ -> ()
2463-
| e -> ignore (iter_shallow_tail has_tail e)
2454+
let rec has_tail ~depth = function
2455+
| (Ctail _ | Cop (Capply (_, Rc_close_at_apply), _, _)) when depth = 0 ->
2456+
raise Exit
2457+
| Ctail e -> has_tail ~depth:(depth - 1) e
2458+
| Cregion e -> has_tail ~depth:(depth + 1) e
2459+
| e -> ignore (iter_shallow_tail (has_tail ~depth) e : bool)
24642460
in
2465-
let rec remove_tail = function
2466-
| Ctail e -> e
2467-
| Cop (Capply (mach, Rc_close_at_apply), args, dbg) ->
2461+
let rec remove_tail ~depth = function
2462+
| Ctail e ->
2463+
if depth = 0 then e else Ctail (remove_tail ~depth:(depth - 1) e)
2464+
| Cop (Capply (mach, Rc_close_at_apply), args, dbg) when depth = 0 ->
24682465
Cop (Capply (mach, Rc_normal), args, dbg)
2469-
| Cregion _ as e -> e
2470-
| e -> map_shallow_tail remove_tail e
2466+
| Cregion e -> Cregion (remove_tail ~depth:(depth + 1) e)
2467+
| e -> map_shallow_tail (remove_tail ~depth) e
24712468
in
2472-
match has_tail e with () -> e | exception Exit -> remove_tail e
2469+
match has_tail e ~depth:0 with
2470+
| () -> e
2471+
| exception Exit -> remove_tail e ~depth:0
24732472

24742473
let region e =
24752474
(* [Cregion e] is equivalent to [e] if [e] contains no local allocs *)

middle_end/flambda/flambda_iterators.ml

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ let map_snd_sharing f ((a, b) as cpl) =
7676
else
7777
(a, new_b)
7878

79-
let map_subexpressions f f_named (tree:Flambda.t) : Flambda.t =
79+
let map_subexpressions_with_tail f f_named (tree:Flambda.t) : Flambda.t =
80+
let f_tail v = f v ~tail:true in
81+
let f_nontail v = f v ~tail:false in
8082
match tree with
8183
| Var _ | Apply _ | Assign _ | Send _ | Proved_unreachable
8284
| Static_raise _ -> tree
8385
| Let { var; defining_expr; body; _ } ->
8486
let new_named = f_named var defining_expr in
85-
let new_body = f body in
87+
let new_body = f_tail body in
8688
if new_named == defining_expr && new_body == body then
8789
tree
8890
else
@@ -91,22 +93,23 @@ let map_subexpressions f f_named (tree:Flambda.t) : Flambda.t =
9193
let new_defs =
9294
list_map_sharing (map_snd_sharing f_named) defs
9395
in
94-
let new_body = f body in
96+
let new_body = f_tail body in
9597
if new_defs == defs && new_body == body then
9698
tree
9799
else
98100
Let_rec (new_defs, new_body)
99101
| Let_mutable mutable_let ->
100-
let new_body = f mutable_let.body in
102+
let new_body = f_tail mutable_let.body in
101103
if new_body == mutable_let.body then
102104
tree
103105
else
104106
Let_mutable { mutable_let with body = new_body }
105107
| Switch (arg, sw) ->
106-
let aux = map_snd_sharing (fun _ v -> f v) in
108+
let aux = map_snd_sharing (fun _ v -> f_tail v) in
107109
let new_consts = list_map_sharing aux sw.consts in
108110
let new_blocks = list_map_sharing aux sw.blocks in
109-
let new_failaction = may_map_sharing f sw.failaction in
111+
let new_failaction = may_map_sharing f_tail sw.failaction
112+
in
110113
if sw.failaction == new_failaction &&
111114
new_consts == sw.consts &&
112115
new_blocks == sw.blocks then
@@ -121,59 +124,66 @@ let map_subexpressions f f_named (tree:Flambda.t) : Flambda.t =
121124
in
122125
Switch (arg, sw)
123126
| String_switch (arg, sw, def, kind) ->
124-
let new_sw = list_map_sharing (map_snd_sharing (fun _ v -> f v)) sw in
125-
let new_def = may_map_sharing f def in
127+
let new_sw = list_map_sharing (map_snd_sharing (fun _ v -> f_tail v)) sw in
128+
let new_def = may_map_sharing f_tail def in
126129
if sw == new_sw && def == new_def then
127130
tree
128131
else
129132
String_switch(arg, new_sw, new_def, kind)
130133
| Static_catch (i, vars, body, handler, kind) ->
131-
let new_body = f body in
132-
let new_handler = f handler in
134+
let new_body = f_tail body in
135+
let new_handler = f_tail handler in
133136
if new_body == body && new_handler == handler then
134137
tree
135138
else
136139
Static_catch (i, vars, new_body, new_handler, kind)
137140
| Try_with(body, id, handler, kind) ->
138-
let new_body = f body in
139-
let new_handler = f handler in
141+
let new_body = f_tail body in
142+
let new_handler = f_tail handler in
140143
if body == new_body && handler == new_handler then
141144
tree
142145
else
143146
Try_with(new_body, id, new_handler, kind)
144147
| If_then_else(arg, ifso, ifnot, kind) ->
145-
let new_ifso = f ifso in
146-
let new_ifnot = f ifnot in
148+
let new_ifso = f_tail ifso in
149+
let new_ifnot = f_tail ifnot in
147150
if new_ifso == ifso && new_ifnot == ifnot then
148151
tree
149152
else
150153
If_then_else(arg, new_ifso, new_ifnot, kind)
151154
| While(cond, body) ->
152-
let new_cond = f cond in
153-
let new_body = f body in
155+
let new_cond = f_nontail cond in
156+
let new_body = f_nontail body in
154157
if new_cond == cond && new_body == body then
155158
tree
156159
else
157160
While(new_cond, new_body)
158161
| For { bound_var; from_value; to_value; direction; body; } ->
159-
let new_body = f body in
162+
let new_body = f_nontail body in
160163
if new_body == body then
161164
tree
162165
else
163166
For { bound_var; from_value; to_value; direction; body = new_body; }
164167
| Region body ->
165-
let new_body = f body in
168+
let new_body = f_tail body in
166169
if new_body == body then
167170
tree
168171
else
169172
Region new_body
170173
| Exclave body ->
171-
let new_body = f body in
174+
let new_body = f_tail body in
172175
if new_body == body then
173176
tree
174177
else
175178
Exclave new_body
176179

180+
let map_subexpressions f f_named tree =
181+
map_subexpressions_with_tail (fun v ~tail:_ -> f v) f_named tree
182+
183+
let map_tail_subexpressions f tree =
184+
let f v ~tail = if tail then f v else v in
185+
map_subexpressions_with_tail f (fun _ named -> named) tree
186+
177187
let iter_general = Flambda.iter_general
178188

179189
let iter f f_named t = iter_general ~toplevel:false f f_named (Is_expr t)

middle_end/flambda/flambda_iterators.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ val map_subexpressions
3535
-> Flambda.t
3636
-> Flambda.t
3737

38+
val map_tail_subexpressions : (Flambda.t -> Flambda.t) -> Flambda.t -> Flambda.t
39+
3840
(* CR-soon lwhite: add comment to clarify that these recurse unlike the
3941
ones above *)
4042
val iter

middle_end/flambda/inline_and_simplify.ml

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,29 @@ let simplify_move_within_set_of_closures env r
394394
let approx = A.value_closure value_set_of_closures move_to in
395395
Move_within_set_of_closures move_within, ret r approx)
396396

397+
let remove_exclaves (lam : Flambda.t) =
398+
let rec remove lam ~depth : Flambda.t =
399+
match (lam : Flambda.t) with
400+
| Region body ->
401+
let new_body = remove ~depth:(depth + 1) body in
402+
if new_body == body then lam else Region new_body
403+
| Exclave body ->
404+
if depth = 0 then body
405+
else
406+
let new_body = remove ~depth:(depth - 1) body in
407+
if new_body == body then lam else Exclave new_body
408+
| Apply ({ reg_close = Rc_close_at_apply; _ } as apply) when depth = 0 ->
409+
(* Can still be compiled as a tail call, so use [Rc_normal] rather than
410+
[Rc_nontail] *)
411+
Apply { apply with reg_close = Rc_normal }
412+
| Send ({ reg_close = Rc_close_at_apply; _ } as send) when depth = 0 ->
413+
(* Similar to [Apply] *)
414+
Send { send with reg_close = Rc_normal }
415+
| _ ->
416+
Flambda_iterators.map_tail_subexpressions (remove ~depth) lam
417+
in
418+
remove lam ~depth:0
419+
397420
(* Transform an expression denoting an access to a variable bound in
398421
a closure. Variables in the closure ([project_var.closure]) may
399422
have been freshened since [expr] was constructed; as such, we
@@ -675,10 +698,18 @@ and simplify_set_of_closures original_env r
675698
set_of_closures, r, value_set_of_closures.freshening
676699

677700
and mark_region_used_for_apply ~(reg_close : Lambda.region_close) ~(mode : Lambda.alloc_mode) r =
678-
match reg_close, mode with
679-
| (Rc_normal | Rc_nontail), Alloc_heap -> r
680-
| Rc_close_at_apply, _
681-
| _, Alloc_local -> R.set_region_used r
701+
let r =
702+
(* A close-at-apply tail call is effectively a small exclave *)
703+
match reg_close with
704+
| Rc_close_at_apply -> R.set_region_has_exclave r
705+
| Rc_normal | Rc_nontail -> r
706+
in
707+
let r =
708+
match mode with
709+
| Alloc_local -> R.set_region_used r
710+
| Alloc_heap -> r
711+
in
712+
r
682713

683714
and simplify_apply env r ~(apply : Flambda.apply) : Flambda.t * R.t =
684715
let {
@@ -1460,11 +1491,11 @@ and simplify env r (tree : Flambda.t) : Flambda.t * R.t =
14601491
let r = R.enter_region r in
14611492
let body, r = simplify env r body in
14621493
let use_inner_region = R.may_use_region r in
1494+
let has_exclave = R.region_has_exclave r in
14631495
let r = R.leave_region r in
14641496
if use_inner_region then Region body, r
1465-
else body, r
1497+
else if has_exclave then remove_exclaves body, r else body, r
14661498
| Exclave body ->
1467-
let r = R.set_region_used r in
14681499
let exclave, r = R.enter_exclave r in
14691500
let body, r = simplify env r body in
14701501
let r = R.leave_exclave r exclave in

middle_end/flambda/inline_and_simplify_aux.ml

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ let initial_inlining_toplevel_threshold ~round : Inlining_cost.Threshold.t =
437437
(unscaled * Inlining_cost.scale_inline_threshold_by)
438438

439439
module Result = struct
440-
type region = { may_be_used : bool; }
440+
type region = { may_be_used : bool; has_exclave : bool }
441441

442442
type t =
443443
{ approx : Simple_value_approx.t;
@@ -448,7 +448,7 @@ module Result = struct
448448
regions : region list;
449449
}
450450

451-
let create_region () = { may_be_used = false; }
451+
let create_region () = { may_be_used = false; has_exclave = false }
452452

453453
let create () =
454454
{ approx = Simple_value_approx.value_unknown Other;
@@ -490,17 +490,28 @@ module Result = struct
490490

491491
let set_region_used t =
492492
match t.regions with
493-
| _ :: regions ->
494-
{ t with regions = { may_be_used = true } :: regions }
495-
| [] -> t
493+
| region :: regions ->
494+
{ t with regions = { region with may_be_used = true } :: regions }
495+
| [] ->
496+
(* By rights this should be a fatal error, but currently
497+
[Semantics_of_primitives.may_locally_allocate] has too many false
498+
positives (including ccalls). *)
499+
t
500+
501+
let set_region_has_exclave t =
502+
match t.regions with
503+
| region :: regions ->
504+
{ t with regions = { region with has_exclave = true } :: regions }
505+
| [] -> no_current_region ()
496506

497507
type exclave = { from_region : region }
498508

499509
let enter_exclave t =
500510
match t.regions with
501511
| region :: regions ->
502-
let exclave = { from_region = region } in
503-
exclave, { t with regions = regions }
512+
let region = { region with has_exclave = true } in
513+
let exclave = { from_region = region } in
514+
exclave, { t with regions = regions }
504515
| [] -> no_current_region ()
505516

506517
let leave_exclave t { from_region } =
@@ -511,7 +522,11 @@ module Result = struct
511522
| region :: _ -> region
512523
| [] -> no_current_region ()
513524

514-
let may_use_region t = (current_region t).may_be_used
525+
let may_use_region t =
526+
(current_region t).may_be_used
527+
528+
let region_has_exclave t =
529+
(current_region t).has_exclave
515530

516531
let exit_scope_catch t i =
517532
{ t with

middle_end/flambda/inline_and_simplify_aux.mli

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@ module Result : sig
321321
(** Whether [set_region_used _] has been called *)
322322
val may_use_region : t -> bool
323323

324+
(** Mark that the nearest enclosing region has an exclave (either an actual
325+
[exclave] expression or a close-on-apply tail call). *)
326+
val set_region_has_exclave : t -> t
327+
328+
(** Whether [enter_exclave _] or [set_region_has_exclave] has been called. *)
329+
val region_has_exclave : t -> bool
330+
324331
(** Mark that we are moving up out of the scope of a static-catch block
325332
that catches the given static exception identifier. This has the effect
326333
of removing the identifier from the [used_staticfail] set. *)

0 commit comments

Comments
 (0)