Skip to content

Commit d53bd35

Browse files
authored
CFG/IRC: dedicated type for list of instructions (#793)
Explicit type for list of instructions / bodies.
1 parent 2963d59 commit d53bd35

23 files changed

+389
-396
lines changed

backend/asmgen.ml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,26 +241,26 @@ let recompute_liveness_on_cfg (cfg_with_layout : Cfg_with_layout.t) : Cfg_with_l
241241
let init = { Cfg_liveness.before = Reg.Set.empty; across = Reg.Set.empty; } in
242242
begin match Cfg_liveness.Liveness.run cfg ~init ~map:Cfg_liveness.Liveness.Instr () with
243243
| Ok (liveness : Cfg_liveness.Liveness.domain Cfg_dataflow.Instr.Tbl.t) ->
244-
let with_liveness (instr : _ Cfg.instruction) =
244+
let set_liveness (instr : _ Cfg.instruction) =
245245
match Cfg_dataflow.Instr.Tbl.find_opt liveness instr.id with
246246
| None ->
247247
Misc.fatal_errorf "Missing liveness information for instruction %d in function %s@."
248248
instr.id
249249
cfg.Cfg.fun_name
250250
| Some { Cfg_liveness.before = _; across } ->
251-
Cfg.set_live instr across
251+
instr.live <- across
252252
in
253253
Cfg.iter_blocks cfg ~f:(fun _label block ->
254-
block.body <- ListLabels.map block.body ~f:with_liveness;
255-
block.terminator <- with_liveness block.terminator;
254+
Cfg.BasicInstructionList.iter block.body ~f:set_liveness;
255+
set_liveness block.terminator;
256256
);
257257
| Aborted _ -> .
258258
| Max_iterations_reached ->
259259
Misc.fatal_errorf "Unable to compute liveness from CFG for function %s@."
260260
cfg.Cfg.fun_name;
261261
end;
262262
Cfg.iter_blocks cfg ~f:(fun _label block ->
263-
block.body <- ListLabels.filter block.body ~f:(fun instr ->
263+
Cfg.BasicInstructionList.filter_left block.body ~f:(fun instr ->
264264
not (Cfg.is_noop_move instr)));
265265
let layout : Label.t list =
266266
ListLabels.filter (Cfg_with_layout.layout cfg_with_layout) ~f:(fun label ->

backend/cfg/cfg.ml

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,70 @@ let verbose = ref false
2929

3030
include Cfg_intf.S
3131

32+
module BasicInstructionList = struct
33+
type instr = basic instruction
34+
35+
type cell =
36+
{ instr : instr;
37+
mutable before_rev : instr list;
38+
mutable after : instr list
39+
}
40+
41+
let insert_before cell instr = cell.before_rev <- instr :: cell.before_rev
42+
43+
let insert_after cell instr = cell.after <- instr :: cell.after
44+
45+
let instr cell = cell.instr
46+
47+
type t = instr list ref
48+
49+
let make_empty () = ref []
50+
51+
let make_single instr = ref [instr]
52+
53+
let of_list l = ref l
54+
55+
let hd t = match !t with [] -> None | hd :: _ -> Some hd
56+
57+
let add_begin t instr = t := instr :: !t
58+
59+
let add_end t instr = t := !t @ [instr]
60+
61+
let is_empty t = match !t with [] -> true | _ :: _ -> false
62+
63+
let length t = ListLabels.length !t
64+
65+
let filter_left t ~f = t := ListLabels.filter ~f !t
66+
67+
let filter_right t ~f =
68+
t
69+
:= ListLabels.fold_right
70+
~f:(fun elem acc -> if f elem then elem :: acc else acc)
71+
!t ~init:[]
72+
73+
let iter t ~f = ListLabels.iter ~f !t
74+
75+
let iter_cell t ~f =
76+
t
77+
:= ListLabels.concat_map !t ~f:(fun instr ->
78+
let cell = { instr; before_rev = []; after = [] } in
79+
f cell;
80+
List.rev cell.before_rev @ [instr] @ cell.after)
81+
82+
let iter2 t t' ~f = ListLabels.iter2 ~f !t !t'
83+
84+
let fold_left t ~f ~init = ListLabels.fold_left ~f ~init !t
85+
86+
let fold_right t ~f ~init = ListLabels.fold_right ~f !t ~init
87+
88+
let transfer ~to_:t ~from:t' () =
89+
t := !t @ !t';
90+
t' := []
91+
end
92+
3293
type basic_block =
3394
{ start : Label.t;
34-
mutable body : basic instruction list;
95+
body : BasicInstructionList.t;
3596
mutable terminator : terminator instruction;
3697
mutable predecessors : Label.Set.t;
3798
mutable stack_offset : int;
@@ -153,6 +214,11 @@ let get_block_exn t label =
153214

154215
let can_raise_interproc block = block.can_raise && Option.is_none block.exn
155216

217+
let first_instruction_id (block : basic_block) : int =
218+
match BasicInstructionList.hd block.body with
219+
| None -> block.terminator.id
220+
| Some first_instr -> first_instr.id
221+
156222
let fun_name t = t.fun_name
157223

158224
let entry_label t = t.entry_label
@@ -485,12 +551,7 @@ let set_stack_offset (instr : _ instruction) stack_offset =
485551
then
486552
Misc.fatal_errorf "Cfg.set_stack_offset: expected non-negative got %d"
487553
stack_offset;
488-
if instr.stack_offset = stack_offset
489-
then instr
490-
else { instr with stack_offset }
491-
492-
let set_live (instr : _ instruction) live =
493-
if Reg.Set.equal instr.live live then instr else { instr with live }
554+
instr.stack_offset <- stack_offset
494555
495556
let string_of_irc_work_list = function
496557
| Unknown_list -> "unknown_list"

backend/cfg/cfg.mli

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,56 @@ include module type of struct
3131
include Cfg_intf.S
3232
end
3333

34+
module BasicInstructionList : sig
35+
type instr = basic instruction
36+
37+
type cell
38+
39+
val insert_before : cell -> instr -> unit
40+
41+
val insert_after : cell -> instr -> unit
42+
43+
val instr : cell -> instr
44+
45+
type t
46+
47+
val make_empty : unit -> t
48+
49+
val make_single : instr -> t
50+
51+
val of_list : instr list -> t
52+
53+
val hd : t -> instr option
54+
55+
val add_begin : t -> instr -> unit
56+
57+
val add_end : t -> instr -> unit
58+
59+
val is_empty : t -> bool
60+
61+
val length : t -> int
62+
63+
val filter_left : t -> f:(instr -> bool) -> unit
64+
65+
val filter_right : t -> f:(instr -> bool) -> unit
66+
67+
val iter : t -> f:(instr -> unit) -> unit
68+
69+
val iter_cell : t -> f:(cell -> unit) -> unit
70+
71+
val iter2 : t -> t -> f:(instr -> instr -> unit) -> unit
72+
73+
val fold_left : t -> f:('a -> instr -> 'a) -> init:'a -> 'a
74+
75+
val fold_right : t -> f:(instr -> 'a -> 'a) -> init:'a -> 'a
76+
77+
(* Adds all of the elements of `from` to `to_`, and clears `from`. *)
78+
val transfer : to_:t -> from:t -> unit -> unit
79+
end
80+
3481
type basic_block =
3582
{ start : Label.t;
36-
mutable body : basic instruction list;
83+
body : BasicInstructionList.t;
3784
mutable terminator : terminator instruction;
3885
mutable predecessors : Label.Set.t;
3986
(** All predecessors, both normal and exceptional paths. *)
@@ -109,6 +156,8 @@ val replace_successor_labels :
109156
vice versa. *)
110157
val can_raise_interproc : basic_block -> bool
111158

159+
val first_instruction_id : basic_block -> int
160+
112161
val mem_block : t -> Label.t -> bool
113162

114163
val remove_block_exn : t -> Label.t -> unit
@@ -168,9 +217,7 @@ val is_pure_basic : basic -> bool
168217

169218
val is_noop_move : basic instruction -> bool
170219

171-
val set_stack_offset : 'a instruction -> int -> 'a instruction
172-
173-
val set_live : 'a instruction -> Reg.Set.t -> 'a instruction
220+
val set_stack_offset : 'a instruction -> int -> unit
174221

175222
val string_of_irc_work_list : irc_work_list -> string
176223

backend/cfg/cfg_dataflow.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ module Forward (D : Domain_S) (T : Forward_transfer with type domain = D.t) :
340340
in
341341
let normal, exceptional =
342342
transfer T.terminator
343-
(ListLabels.fold_left block.body ~init:(value, value)
343+
(Cfg.BasicInstructionList.fold_left block.body ~init:(value, value)
344344
~f:(transfer T.basic))
345345
block.terminator
346346
in
@@ -479,8 +479,8 @@ module Backward (D : Domain_S) (T : Backward_transfer with type domain = D.t) :
479479
transfer block.terminator (T.terminator normal ~exn block.terminator)
480480
in
481481
let value =
482-
ListLabels.fold_right block.body ~init:value ~f:(fun instr value ->
483-
transfer instr (T.basic value ~exn instr))
482+
Cfg.BasicInstructionList.fold_right block.body ~init:value
483+
~f:(fun instr value -> transfer instr (T.basic value ~exn instr))
484484
in
485485
let value =
486486
if block.is_trap_handler

backend/cfg/cfg_deadcode.ml

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,30 @@ let live_before : type a. a Cfg.instruction -> liveness -> Reg.Set.t =
88
| None -> fatal "no liveness information for instruction %d" instr.id
99
| Some { Cfg_liveness.before; across = _ } -> before
1010

11-
let remove_deadcode (body : Instruction.t list) liveness used_after :
12-
Instruction.t list * bool =
13-
let body, _, changed =
14-
List.fold_right body ~init:([], used_after, false)
15-
~f:(fun (instr : Instruction.t) (acc, used_after, changed) ->
16-
let before = live_before instr liveness in
17-
let is_deadcode =
18-
match instr.desc with
19-
| Op _ as op ->
20-
Cfg.is_pure_basic op
21-
&& Reg.disjoint_set_array used_after instr.res
22-
&& (not (Proc.regs_are_volatile instr.arg))
23-
&& not (Proc.regs_are_volatile instr.res)
24-
| Call _ | Reloadretaddr | Pushtrap _ | Poptrap | Prologue -> false
25-
in
26-
let acc = if is_deadcode then acc else instr :: acc in
27-
acc, before, changed || is_deadcode)
28-
in
29-
body, changed
11+
let remove_deadcode (body : Cfg.BasicInstructionList.t) changed liveness
12+
used_after : unit =
13+
let used_after = ref used_after in
14+
Cfg.BasicInstructionList.filter_right body ~f:(fun (instr : Instruction.t) ->
15+
let before = live_before instr liveness in
16+
let is_deadcode =
17+
match instr.desc with
18+
| Op _ as op ->
19+
Cfg.is_pure_basic op
20+
&& Reg.disjoint_set_array !used_after instr.res
21+
&& (not (Proc.regs_are_volatile instr.arg))
22+
&& not (Proc.regs_are_volatile instr.res)
23+
| Call _ | Reloadretaddr | Pushtrap _ | Poptrap | Prologue -> false
24+
in
25+
used_after := before;
26+
changed := !changed || is_deadcode;
27+
not is_deadcode)
3028

3129
let run cfg_with_liveness =
3230
let liveness = Cfg_with_liveness.liveness cfg_with_liveness in
33-
let invalidate =
34-
Cfg.fold_blocks (Cfg_with_liveness.cfg cfg_with_liveness) ~init:false
35-
~f:(fun _label block changed ->
36-
let new_body, body_changed =
37-
remove_deadcode block.body liveness
38-
(live_before block.terminator liveness)
39-
in
40-
block.body <- new_body;
41-
changed || body_changed)
42-
in
43-
if invalidate then Cfg_with_liveness.invalidate_liveness cfg_with_liveness;
31+
let changed = ref false in
32+
Cfg.iter_blocks (Cfg_with_liveness.cfg cfg_with_liveness)
33+
~f:(fun _label block ->
34+
remove_deadcode block.body changed liveness
35+
(live_before block.terminator liveness));
36+
if !changed then Cfg_with_liveness.invalidate_liveness cfg_with_liveness;
4437
cfg_with_liveness

backend/cfg/cfg_equivalence.ml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -408,23 +408,24 @@ let check_basic_instruction :
408408
check_instruction ~check_live ~check_dbg ~check_arg:true idx location expected
409409
result
410410

411-
let rec check_basic_instruction_list :
411+
let check_basic_instruction_list :
412412
State.t ->
413413
location ->
414-
int ->
415-
Cfg.basic Cfg.instruction list ->
416-
Cfg.basic Cfg.instruction list ->
414+
Cfg.BasicInstructionList.t ->
415+
Cfg.BasicInstructionList.t ->
417416
unit =
418-
fun state location idx expected result ->
419-
match expected, result with
420-
| [], [] -> ()
421-
| _ :: _, [] ->
422-
different location "bodies with different sizes (expected is longer)"
423-
| [], _ :: _ ->
424-
different location "bodies with different sizes (result is longer)"
425-
| expected_hd :: expected_tl, result_hd :: result_tl ->
426-
check_basic_instruction state location idx expected_hd result_hd;
427-
check_basic_instruction_list state location (succ idx) expected_tl result_tl
417+
fun state location expected result ->
418+
let expected_len = Cfg.BasicInstructionList.length expected in
419+
let result_len = Cfg.BasicInstructionList.length result in
420+
if expected_len = result_len
421+
then
422+
let i = ref 0 in
423+
Cfg.BasicInstructionList.iter2 expected result ~f:(fun expected result ->
424+
check_basic_instruction state location !i expected result;
425+
incr i)
426+
else if expected_len > result_len
427+
then different location "bodies with different sizes (expected is longer)"
428+
else different location "bodies with different sizes (result is longer)"
428429

429430
let check_terminator_instruction :
430431
State.t ->
@@ -512,7 +513,7 @@ let check_basic_block : State.t -> Cfg.basic_block -> Cfg.basic_block -> unit =
512513
(Label.to_string expected.start)
513514
(Label.to_string result.start)
514515
in
515-
check_basic_instruction_list state location 0 expected.body result.body;
516+
check_basic_instruction_list state location expected.body result.body;
516517
check_terminator_instruction state location expected.terminator
517518
result.terminator;
518519
(* State.add_label_sets_to_check state (location ^ " (predecessors)")

backend/cfg/cfg_intf.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,10 @@ module S = struct
138138
{ desc : 'a;
139139
mutable arg : Reg.t array;
140140
mutable res : Reg.t array;
141-
dbg : Debuginfo.t;
142-
fdo : Fdo_info.t;
143-
live : Reg.Set.t;
144-
stack_offset : int;
141+
mutable dbg : Debuginfo.t;
142+
mutable fdo : Fdo_info.t;
143+
mutable live : Reg.Set.t;
144+
mutable stack_offset : int;
145145
id : int;
146146
mutable irc_work_list : irc_work_list
147147
}

0 commit comments

Comments
 (0)