Skip to content

Commit ce98e04

Browse files
azewierzejewmshinwell
authored andcommitted
CFG: Add validator for register allocation. (#786)
(without structural checks)
1 parent 9beb63a commit ce98e04

18 files changed

+2310
-127
lines changed

backend/asmgen.ml

+26-18
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ let recompute_liveness_on_cfg (cfg_with_layout : Cfg_with_layout.t) : Cfg_with_l
243243
let cfg = Cfg_with_layout.cfg cfg_with_layout in
244244
let init = { Cfg_liveness.before = Reg.Set.empty; across = Reg.Set.empty; } in
245245
begin match Cfg_liveness.Liveness.run cfg ~init ~map:Cfg_liveness.Liveness.Instr () with
246-
| Result.Ok (liveness : Cfg_liveness.Liveness.domain Cfg_dataflow.Instr.Tbl.t) ->
246+
| Ok (liveness : Cfg_liveness.Liveness.domain Cfg_dataflow.Instr.Tbl.t) ->
247247
let with_liveness (instr : _ Cfg.instruction) =
248248
match Cfg_dataflow.Instr.Tbl.find_opt liveness instr.id with
249249
| None ->
@@ -257,7 +257,8 @@ let recompute_liveness_on_cfg (cfg_with_layout : Cfg_with_layout.t) : Cfg_with_l
257257
block.body <- ListLabels.map block.body ~f:with_liveness;
258258
block.terminator <- with_liveness block.terminator;
259259
);
260-
| Result.Error _ ->
260+
| Aborted _ -> .
261+
| Max_iterations_reached ->
261262
Misc.fatal_errorf "Unable to compute liveness from CFG for function %s@."
262263
cfg.Cfg.fun_name;
263264
end;
@@ -357,27 +358,34 @@ let compile_fundecl ?dwarf ~ppf_dump fd_cmm =
357358
++ Profile.record ~accumulate:true "selection" Selection.fundecl
358359
++ Compiler_hooks.execute_and_pipe Compiler_hooks.Mach_sel
359360
++ pass_dump_if ppf_dump dump_selection "After instruction selection"
360-
++ save_mach_as_cfg Compiler_pass.Selection
361+
++ Profile.record ~accumulate:true "save_mach_as_cfg" (save_mach_as_cfg Compiler_pass.Selection)
361362
++ Profile.record ~accumulate:true "comballoc" Comballoc.fundecl
362363
++ Compiler_hooks.execute_and_pipe Compiler_hooks.Mach_combine
363364
++ pass_dump_if ppf_dump dump_combine "After allocation combining"
364365
++ Profile.record ~accumulate:true "cse" CSE.fundecl
365366
++ Compiler_hooks.execute_and_pipe Compiler_hooks.Mach_cse
366367
++ pass_dump_if ppf_dump dump_cse "After CSE"
367-
++ Checkmach.fundecl ppf_dump
368-
++ (fun (fd : Mach.fundecl) ->
368+
++ Profile.record ~accumulate:true "checkmach" (Checkmach.fundecl ppf_dump)
369+
++ Profile.record ~accumulate:true "regalloc" (fun (fd : Mach.fundecl) ->
369370
let force_linscan = should_use_linscan fd in
370-
match force_linscan, register_allocator with
371-
| false, IRC ->
372-
let res =
371+
match force_linscan, register_allocator with
372+
| false, IRC ->
373+
fd
374+
++ Profile.record ~accumulate:true "irc" (fun fd ->
375+
let cfg =
373376
fd
374377
++ Profile.record ~accumulate:true "cfgize" cfgize
375378
++ Profile.record ~accumulate:true "cfg_deadcode" Cfg_deadcode.run
376-
++ Profile.record ~accumulate:true "cfg_irc" Cfg_irc.run
377379
in
378-
(Cfg_regalloc_utils.simplify_cfg res)
379-
++ Profile.record ~accumulate:true "cfg_to_linear" Cfg_to_linear.run
380-
| true, _ | false, Upstream ->
380+
let cfg_description = Profile.record ~accumulate:true "cfg_create_description" Cfg_regalloc_validate.Description.create cfg in
381+
cfg
382+
++ Profile.record ~accumulate:true "cfg_irc" Cfg_irc.run
383+
++ Profile.record ~accumulate:true "cfg_validate_description" (Cfg_regalloc_validate.run cfg_description)
384+
++ Profile.record ~accumulate:true "cfg_simplify" Cfg_regalloc_utils.simplify_cfg
385+
++ Profile.record ~accumulate:true "cfg_to_linear" Cfg_to_linear.run)
386+
| true, _ | false, Upstream ->
387+
fd
388+
++ Profile.record ~accumulate:true "default" (fun fd ->
381389
let res =
382390
fd
383391
++ Profile.record ~accumulate:true "liveness" liveness
@@ -402,25 +410,25 @@ let compile_fundecl ?dwarf ~ppf_dump fd_cmm =
402410
test_cfgize f res;
403411
end;
404412
res)
405-
++ pass_dump_linear_if ppf_dump dump_linear "Linearized code")
413+
++ pass_dump_linear_if ppf_dump dump_linear "Linearized code"))
406414
++ Compiler_hooks.execute_and_pipe Compiler_hooks.Linear
407-
++ (fun (fd : Linear.fundecl) ->
415+
++ Profile.record ~accumulate:true "reorder_blocks" (fun (fd : Linear.fundecl) ->
408416
if !Flambda_backend_flags.use_ocamlcfg then begin
409417
fd
410418
++ Profile.record ~accumulate:true "linear_to_cfg"
411419
(Linear_to_cfg.run ~preserve_orig_labels:true)
412420
++ Compiler_hooks.execute_and_pipe Compiler_hooks.Cfg
413421
++ pass_dump_cfg_if ppf_dump Flambda_backend_flags.dump_cfg "After linear_to_cfg"
414-
++ save_cfg
415-
++ reorder_blocks_random ppf_dump
422+
++ Profile.record ~accumulate:true "save_cfg" save_cfg
423+
++ Profile.record ~accumulate:true "cfg_reorder_blocks" (reorder_blocks_random ppf_dump)
416424
++ Profile.record ~accumulate:true "cfg_to_linear" Cfg_to_linear.run
417425
++ pass_dump_linear_if ppf_dump dump_linear "After cfg_to_linear"
418426
end else
419427
fd)
420428
++ Profile.record ~accumulate:true "scheduling" Scheduling.fundecl
421429
++ pass_dump_linear_if ppf_dump dump_scheduling "After instruction scheduling"
422-
++ save_linear
423-
++ emit_fundecl ~dwarf
430+
++ Profile.record ~accumulate:true "save_linear" save_linear
431+
++ Profile.record ~accumulate:true "emit_fundecl" (emit_fundecl ~dwarf)
424432

425433
let compile_data dl =
426434
dl

backend/cfg/cfg_dataflow.ml

+106-74
Original file line numberDiff line numberDiff line change
@@ -139,55 +139,76 @@ module type Backward_domain = sig
139139

140140
val bot : t
141141

142-
val compare : t -> t -> int
143-
144142
val join : t -> t -> t
145143

146144
val less_equal : t -> t -> bool
147145

146+
val compare : t -> t -> int
147+
148148
val to_string : t -> string
149149
end
150150

151151
module type Backward_transfer = sig
152152
type domain
153153

154-
val basic : domain -> exn:domain -> Cfg.basic Cfg.instruction -> domain
154+
type error
155+
156+
val basic :
157+
domain -> exn:domain -> Cfg.basic Cfg.instruction -> (domain, error) result
155158

156159
val terminator :
157-
domain -> exn:domain -> Cfg.terminator Cfg.instruction -> domain
160+
domain ->
161+
exn:domain ->
162+
Cfg.terminator Cfg.instruction ->
163+
(domain, error) result
158164

159-
val exception_ : domain -> domain
165+
val exception_ : domain -> (domain, error) result
160166
end
161167

162168
module Instr = Numbers.Int
163169

170+
module Dataflow_result = struct
171+
type ('a, 'e) t =
172+
| Ok of 'a
173+
| Aborted of 'a * 'e
174+
| Max_iterations_reached
175+
end
176+
164177
module type Backward_S = sig
165178
type domain
166179

180+
type error
181+
167182
type _ map =
168183
| Block : domain Label.Tbl.t map
169184
| Instr : domain Instr.Tbl.t map
185+
| Both : (domain Instr.Tbl.t * domain Label.Tbl.t) map
170186

171187
val run :
172188
Cfg.t ->
173189
?max_iteration:int ->
174190
init:domain ->
175191
map:'a map ->
176192
unit ->
177-
('a, 'a) Result.t
193+
('a, error) Dataflow_result.t
178194
end
179195

180196
module Backward
181197
(D : Backward_domain)
182198
(T : Backward_transfer with type domain = D.t) :
183-
Backward_S with type domain = D.t = struct
199+
Backward_S with type domain = D.t and type error = T.error = struct
184200
(* CR xclerc for xclerc: see what can be shared with `Forward`. *)
185201

186202
type domain = D.t
187203

204+
type error = T.error
205+
206+
exception Dataflow_aborted of error
207+
188208
type _ map =
189209
| Block : domain Label.Tbl.t map
190210
| Instr : domain Instr.Tbl.t map
211+
| Both : (domain Instr.Tbl.t * domain Label.Tbl.t) map
191212

192213
module WorkSetElement = struct
193214
type t =
@@ -204,6 +225,11 @@ module Backward
204225

205226
module WorkSet = Set.Make (WorkSetElement)
206227

228+
let unwrap_transfer_result value =
229+
match value with
230+
| Ok value -> value
231+
| Error error -> raise (Dataflow_aborted error)
232+
207233
let transfer_block :
208234
domain Instr.Tbl.t option ->
209235
domain ->
@@ -212,6 +238,7 @@ module Backward
212238
domain =
213239
fun tbl value ~exn block ->
214240
let replace (instr : _ Cfg.instruction) value =
241+
let value = unwrap_transfer_result value in
215242
match tbl with
216243
| None -> value
217244
| Some tbl ->
@@ -256,7 +283,7 @@ module Backward
256283
init:domain ->
257284
map:a map ->
258285
unit ->
259-
(a, a) Result.t =
286+
(a, error) Dataflow_result.t =
260287
fun cfg ?(max_iteration = max_int) ~init ~map () ->
261288
let res_block, res_instr, work_set = create cfg ~init in
262289
let iteration = ref 0 in
@@ -265,80 +292,85 @@ module Backward
265292
Label.Tbl.create (Label.Tbl.length cfg.Cfg.blocks)
266293
in
267294
let instr_map : D.t Instr.Tbl.t option =
268-
match map with Block -> None | Instr -> Some res_instr
295+
match map with Block -> None | Both | Instr -> Some res_instr
269296
in
270-
while (not (WorkSet.is_empty !work_set)) && !iteration < max_iteration do
271-
incr iteration;
272-
let element, block = remove_and_return cfg work_set in
273-
let exn : domain =
274-
Option.map
275-
(fun exceptional_successor ->
276-
Label.Tbl.find_opt handler_map exceptional_successor)
277-
block.exn
278-
|> Option.join
279-
|> Option.value ~default:D.bot
280-
in
281-
let value = transfer_block instr_map element.value ~exn block in
282-
if block.is_trap_handler
283-
then (
284-
let old_value =
285-
Option.value
286-
(Label.Tbl.find_opt handler_map block.start)
287-
~default:D.bot
297+
let result : a =
298+
match map with
299+
| Block -> res_block
300+
| Instr -> res_instr
301+
| Both -> res_instr, res_block
302+
in
303+
try
304+
while (not (WorkSet.is_empty !work_set)) && !iteration < max_iteration do
305+
incr iteration;
306+
let element, block = remove_and_return cfg work_set in
307+
let exn : domain =
308+
Option.map
309+
(fun exceptional_successor ->
310+
Label.Tbl.find_opt handler_map exceptional_successor)
311+
block.exn
312+
|> Option.join
313+
|> Option.value ~default:D.bot
288314
in
289-
let new_value = T.exception_ value in
290-
if not (D.less_equal new_value old_value)
315+
let value = transfer_block instr_map element.value ~exn block in
316+
if block.is_trap_handler
291317
then (
292-
Label.Tbl.replace handler_map block.start new_value;
318+
let old_value =
319+
Option.value
320+
(Label.Tbl.find_opt handler_map block.start)
321+
~default:D.bot
322+
in
323+
let new_value = T.exception_ value |> unwrap_transfer_result in
324+
if not (D.less_equal new_value old_value)
325+
then (
326+
Label.Tbl.replace handler_map block.start new_value;
327+
List.iter
328+
(fun predecessor_label ->
329+
let current_value =
330+
Option.value
331+
(Label.Tbl.find_opt res_block predecessor_label)
332+
~default:D.bot
333+
in
334+
work_set
335+
:= WorkSet.add
336+
{ WorkSetElement.label = predecessor_label;
337+
value = current_value
338+
}
339+
!work_set)
340+
(Cfg.predecessor_labels block)))
341+
else
293342
List.iter
294343
(fun predecessor_label ->
295-
let current_value =
344+
let old_value =
296345
Option.value
297346
(Label.Tbl.find_opt res_block predecessor_label)
298347
~default:D.bot
299348
in
300-
work_set
301-
:= WorkSet.add
302-
{ WorkSetElement.label = predecessor_label;
303-
value = current_value
304-
}
305-
!work_set)
306-
(Cfg.predecessor_labels block)))
307-
else
308-
List.iter
309-
(fun predecessor_label ->
310-
let old_value =
311-
Option.value
312-
(Label.Tbl.find_opt res_block predecessor_label)
313-
~default:D.bot
314-
in
315-
let new_value = D.join old_value value in
316-
if not (D.less_equal new_value old_value)
317-
then (
318-
Label.Tbl.replace res_block predecessor_label new_value;
319-
let already_in_workset = ref false in
320-
work_set
321-
:= WorkSet.filter
322-
(fun { WorkSetElement.label; value } ->
323-
if Label.equal label predecessor_label
324-
then (
325-
if D.less_equal new_value value
326-
then already_in_workset := true;
327-
not (D.less_equal value new_value))
328-
else true)
329-
!work_set;
330-
if not !already_in_workset
331-
then
349+
let new_value = D.join old_value value in
350+
if not (D.less_equal new_value old_value)
351+
then (
352+
Label.Tbl.replace res_block predecessor_label new_value;
353+
let already_in_workset = ref false in
332354
work_set
333-
:= WorkSet.add
334-
{ WorkSetElement.label = predecessor_label;
335-
value = new_value
336-
}
337-
!work_set))
338-
(Cfg.predecessor_labels block)
339-
done;
340-
let return x =
341-
if WorkSet.is_empty !work_set then Result.Ok x else Result.Error x
342-
in
343-
match map with Block -> return res_block | Instr -> return res_instr
355+
:= WorkSet.filter
356+
(fun { WorkSetElement.label; value } ->
357+
if Label.equal label predecessor_label
358+
then (
359+
if D.less_equal new_value value
360+
then already_in_workset := true;
361+
not (D.less_equal value new_value))
362+
else true)
363+
!work_set;
364+
if not !already_in_workset
365+
then
366+
work_set
367+
:= WorkSet.add
368+
{ WorkSetElement.label = predecessor_label;
369+
value = new_value
370+
}
371+
!work_set))
372+
(Cfg.predecessor_labels block)
373+
done;
374+
if WorkSet.is_empty !work_set then Ok result else Max_iterations_reached
375+
with Dataflow_aborted error -> Aborted (result, error)
344376
end

0 commit comments

Comments
 (0)