Skip to content

Commit a42782f

Browse files
authored
Make IRC coalescing respect registers with multiple names (#2573)
1 parent e704441 commit a42782f

File tree

9 files changed

+93
-33
lines changed

9 files changed

+93
-33
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,24 +71,28 @@ jobs:
7171
config: --enable-middle-end=flambda2
7272
os: ubuntu-latest
7373
build_ocamlparam: '_,w=-46,regalloc=irc,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=IRC_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1'
74+
ocamlparam: '_,w=-46,regalloc=irc,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=IRC_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1'
7475
check_arch: true
7576

7677
- name: irc_frame_pointers
7778
config: --enable-middle-end=flambda2 --enable-frame-pointers
7879
os: ubuntu-latest
7980
build_ocamlparam: '_,w=-46,regalloc=irc,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=IRC_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1'
81+
ocamlparam: '_,w=-46,regalloc=irc,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=IRC_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1'
8082
check_arch: true
8183

8284
- name: ls
8385
config: --enable-middle-end=flambda2
8486
os: ubuntu-latest
8587
build_ocamlparam: '_,w=-46,regalloc=ls,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=LS_ORDER:layout,regalloc-validate=1'
88+
ocamlparam: '_,w=-46,regalloc=ls,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=LS_ORDER:layout,regalloc-validate=1'
8689
check_arch: true
8790

8891
- name: gi
8992
config: --enable-middle-end=flambda2
9093
os: ubuntu-latest
9194
build_ocamlparam: '_,w=-46,regalloc=gi,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=GI_PRIORITY_HEURISTICS:interval-length,regalloc-param=GI_SELECTION_HEURISTICS:first-available,regalloc-param=GI_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1,cfg-cse-optimize=1'
95+
ocamlparam: '_,w=-46,regalloc=gi,regalloc-param=SPLIT_LIVE_RANGES:on,regalloc-param=GI_PRIORITY_HEURISTICS:interval-length,regalloc-param=GI_SELECTION_HEURISTICS:first-available,regalloc-param=GI_SPILLING_HEURISTICS:flat-uses,regalloc-validate=1,cfg-cse-optimize=1'
9296
check_arch: true
9397

9498
env:

backend/amd64/emit.mlp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -799,24 +799,23 @@ let emit_global_label s =
799799
emit_global_label_for_symbol lbl
800800

801801
let move (src : Reg.t) (dst : Reg.t) =
802-
if src.loc <> dst.loc then
803-
begin match src.typ, src.loc, dst.typ, dst.loc with
804-
| Float, Reg _, Float, Reg _
805-
| Float32, Reg _, Float32, Reg _
806-
| Vec128, _, Vec128, _ (* Vec128 stack slots are always aligned. *) ->
807-
I.movapd (reg src) (reg dst)
808-
| Float, _, Float, _ ->
809-
I.movsd (reg src) (reg dst)
810-
| Float32, _, Float32, _ ->
811-
I.movss (reg src) (reg dst)
812-
| (Int | Val | Addr), _, (Int | Val | Addr), _ ->
813-
I.mov (reg src) (reg dst)
814-
| (Float | Float32 | Vec128 | Int | Val | Addr), _, _, _ ->
815-
Misc.fatal_errorf
816-
"Illegal move between registers of differing types (%s:%a to %s:%a)\n"
817-
(Reg.name src) Printcmm.machtype_component src.typ
818-
(Reg.name dst) Printcmm.machtype_component dst.typ
819-
end
802+
let distinct = src.loc <> dst.loc in
803+
begin match src.typ, src.loc, dst.typ, dst.loc with
804+
| Float, Reg _, Float, Reg _
805+
| Float32, Reg _, Float32, Reg _
806+
| Vec128, _, Vec128, _ (* Vec128 stack slots are always aligned. *) ->
807+
if distinct then I.movapd (reg src) (reg dst)
808+
| Float, _, Float, _ ->
809+
if distinct then I.movsd (reg src) (reg dst)
810+
| Float32, _, Float32, _ ->
811+
if distinct then I.movss (reg src) (reg dst)
812+
| (Int | Val | Addr), _, (Int | Val | Addr), _ ->
813+
if distinct then I.mov (reg src) (reg dst)
814+
| (Float | Float32 | Vec128 | Int | Val | Addr), _, _, _ ->
815+
Misc.fatal_errorf
816+
"Illegal move between registers of differing types (%a to %a)\n"
817+
Printmach.reg src Printmach.reg dst
818+
end
820819

821820
let stack_to_stack_move (src : Reg.t) (dst : Reg.t) =
822821
assert (src.typ = dst.typ);

backend/interf.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616
(* Construction of the interference graph.
1717
Annotate pseudoregs with interference lists and preference lists. *)
1818

19+
let check_collisions = false
20+
21+
let assert_no_collisions set =
22+
if check_collisions && (Reg.set_has_collisions set) then
23+
Misc.fatal_error "live set has physical register collisions"
24+
25+
let assert_compatible src dst =
26+
if not (Reg.types_are_compatible src dst) then
27+
Misc.fatal_errorf "found move between registers of incompatible types (%a to %a)"
28+
Printmach.reg src Printmach.reg dst
29+
1930
module IntPairSet =
2031
Hashtbl.Make(struct
2132
type t = int * int
@@ -79,11 +90,13 @@ let build_graph fundecl =
7990
do not add an interference between them if the source is still live
8091
afterwards. *)
8192
let add_interf_move src dst s =
93+
assert_compatible src dst;
8294
Reg.Set.iter (fun r -> if r.stamp <> src.stamp then add_interf dst r) s in
8395

8496
(* Compute interferences *)
8597

8698
let rec interf i =
99+
assert_no_collisions i.live;
87100
let destroyed = Proc.destroyed_at_oper i.desc in
88101
if Array.length destroyed > 0 then add_interf_set destroyed i.live;
89102
match i.desc with
@@ -126,6 +139,7 @@ let build_graph fundecl =
126139
float arguments in integer registers, PR#6227.) *)
127140

128141
let add_pref weight r1 r2 =
142+
assert_compatible r1 r2;
129143
let i = r1.stamp and j = r2.stamp in
130144
if i <> j
131145
&& r1.loc = Unknown

backend/printmach.ml

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,15 @@ let loc ?(wrap_out = fun ppf f -> f ppf) ~unknown ppf loc typ =
3939
wrap_out ppf (fun ppf -> fprintf ppf "ds[%i]" s)
4040
4141
let reg ppf r =
42-
if not (Reg.anonymous r) then
43-
fprintf ppf "%s" (Reg.name r)
44-
else
45-
fprintf ppf "%s"
46-
(match (r.typ : machtype_component) with
47-
| Val -> "V"
48-
| Addr -> "A"
49-
| Int -> "I"
50-
| Float -> "F"
51-
| Vec128 -> "X"
52-
| Float32 -> "S");
42+
if not (Reg.anonymous r) then fprintf ppf "%s:" (Reg.name r);
43+
fprintf ppf "%s"
44+
(match (r.typ : machtype_component) with
45+
| Val -> "V"
46+
| Addr -> "A"
47+
| Int -> "I"
48+
| Float -> "F"
49+
| Vec128 -> "X"
50+
| Float32 -> "S");
5351
fprintf ppf "/%i" r.stamp;
5452
loc
5553
~wrap_out:(fun ppf f -> fprintf ppf "[%t]" f)

backend/reg.ml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,15 @@ let set_of_array v =
299299
if i >= n then Set.empty else Set.add v.(i) (add_all(i+1))
300300
in add_all 0
301301

302+
let set_has_collisions s =
303+
let phys_regs = Hashtbl.create (Int.min (Set.cardinal s) 32) in
304+
Set.fold (fun r acc ->
305+
match r.loc with
306+
| Reg id ->
307+
if Hashtbl.mem phys_regs id then true
308+
else (Hashtbl.add phys_regs id (); acc)
309+
| Unknown | Stack _ -> acc) s false
310+
302311
let equal_stack_location left right =
303312
match left, right with
304313
| Local left, Local right -> Int.equal left right
@@ -321,6 +330,11 @@ let equal_location left right =
321330
| Stack _, (Unknown | Reg _) ->
322331
false
323332

333+
let same_phys_reg left right =
334+
match left.loc, right.loc with
335+
| Reg l, Reg r -> Int.equal l r
336+
| (Reg _ | Unknown | Stack _), _ -> false
337+
324338
let same_loc left right =
325339
(* CR-soon azewierzejew: This should also compare [reg_class] for [Stack
326340
(Local _)]. That's complicated because [reg_class] is definied in [Proc]
@@ -329,3 +343,15 @@ let same_loc left right =
329343

330344
let same left right =
331345
Int.equal left.stamp right.stamp
346+
347+
(* Two registers have compatible types if we allow moves between them.
348+
Note that we never allow moves between different register classes, so this
349+
condition must be at least as strict as [class left = class right]. *)
350+
let types_are_compatible left right =
351+
match left.typ, right.typ with
352+
| (Int | Val | Addr), (Int | Val | Addr)
353+
| Float, Float
354+
| Float32, Float32
355+
| Vec128, Vec128 ->
356+
true
357+
| (Int | Val | Addr | Float | Float32 | Vec128), _ -> false

backend/reg.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ val diff_set_array: Set.t -> t array -> Set.t
113113
val inter_set_array: Set.t -> t array -> Set.t
114114
val disjoint_set_array: Set.t -> t array -> bool
115115
val set_of_array: t array -> Set.t
116+
val set_has_collisions : Set.t -> bool
116117

117118
val reset: unit -> unit
118119
val all_registers: unit -> t list
@@ -123,5 +124,7 @@ val mark_visited : t -> unit
123124
val is_visited : t -> bool
124125
val clear_visited_marks : unit -> unit
125126

127+
val types_are_compatible : t -> t -> bool
128+
val same_phys_reg : t -> t -> bool
126129
val same_loc : t -> t -> bool
127130
val same : t -> t -> bool

backend/regalloc/regalloc_irc.ml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ let build : State.t -> Cfg_with_infos.t -> unit =
4343
~(move_src : Reg.t) ~(destroyed : Reg.t array) : unit =
4444
let destroyed = filter_fp destroyed in
4545
let live = Cfg_dataflow.Instr.Tbl.find liveness id in
46+
if irc_debug && Reg.set_has_collisions live.across
47+
then fatal "live set has physical register collisions";
4648
if Array.length def > 0
4749
then
4850
Reg.Set.iter
@@ -199,7 +201,13 @@ let coalesce : State.t -> unit =
199201
if irc_debug then log ~indent:2 "case #1/4";
200202
State.add_coalesced_moves state m;
201203
add_work_list state u)
202-
else if State.is_precolored state v || State.mem_adj_set state u v
204+
else if State.is_precolored state v
205+
|| (* We must not alias v->u if u uses the same register as a neighbor
206+
of v. Simply checking whether u and v are adjacent is not
207+
sufficient because the interference graph treats machine
208+
registers aliased at multiple types (e.g. xmm0 at float32,
209+
float, and vec128) as disjoint. *)
210+
State.interferes_with_adj state v u
203211
then (
204212
if irc_debug then log ~indent:2 "case #2/4";
205213
State.add_constrained_moves state m;

backend/regalloc/regalloc_irc_state.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ let[@inline] mem_adj_set state reg1 reg2 =
336336

337337
let[@inline] adj_list _state reg = reg.Reg.interf
338338

339+
let[@inline] interferes_with_adj state reg1 reg2 =
340+
mem_adj_set state reg1 reg2
341+
|| List.exists reg1.Reg.interf ~f:(Reg.same_phys_reg reg2)
342+
339343
let[@inline] add_edge state u v =
340344
let is_interesting_reg reg =
341345
match reg.Reg.loc with
@@ -466,11 +470,13 @@ let[@inline] rec find_alias state reg =
466470
else reg
467471

468472
let[@inline] add_alias _state v u =
469-
if not (same_reg_class v u)
473+
(* We should never generate moves between registers of different types.
474+
Bit-casting operations have specific instructions. *)
475+
if not (Reg.types_are_compatible v u)
470476
then
471477
fatal
472-
"trying to create an alias between %a and %a but they are in different \
473-
classes"
478+
"trying to create an alias between %a and %a but they have incompatible \
479+
types"
474480
Printmach.reg v Printmach.reg u;
475481
v.Reg.irc_alias <- Some u
476482

backend/regalloc/regalloc_irc_state.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ val mem_adj_set : t -> Reg.t -> Reg.t -> bool
9696

9797
val adj_list : t -> Reg.t -> Reg.t list
9898

99+
val interferes_with_adj : t -> Reg.t -> Reg.t -> bool
100+
99101
val adj_set : t -> RegisterStamp.PairSet.t
100102

101103
val add_edge : t -> Reg.t -> Reg.t -> unit

0 commit comments

Comments
 (0)