Add a coalescing pass to the register allocator.

Coalescing means creating virtual registers and transforming the code
into conventional SSA form. This means that every value used as a branch
argument will belong to the same virtual register as the corresponding
EBB argument value.

Conventional SSA form makes it easy to avoid memory-memory copies when
spilling values, and the virtual registers can be used as hints when
picking registers too. This reduces the number of register moves needed
for EBB arguments.
This commit is contained in:
Jakob Stoklund Olesen
2017-06-21 09:24:12 -07:00
parent d5055275c4
commit 85b624d13b
5 changed files with 661 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
test regalloc
isa riscv
; Test the coalescer.
; regex: V=v\d+
; regex: WS=\s+
; This function is already CSSA, so no copies should be inserted.
function %cssa(i32) -> i32 {
ebb0(v0: i32):
; not: copy
; v0 is used by the branch and passed as an arg - that's no conflict.
brnz v0, ebb1(v0)
; v0 is live across the branch above. That's no conflict.
v1 = iadd_imm v0, 7
jump ebb1(v1)
ebb1(v10: i32):
v11 = iadd_imm v10, 7
return v11
}
function %trivial(i32) -> i32 {
ebb0(v0: i32):
; check: $(cp1=$V) = copy $v0
; nextln: brnz $v0, $ebb1($cp1)
brnz v0, ebb1(v0)
; not: copy
v1 = iadd_imm v0, 7
jump ebb1(v1)
ebb1(v10: i32):
; Use v0 in the destination EBB causes a conflict.
v11 = iadd v10, v0
return v11
}
; A value is used as an SSA argument twice in the same branch.
function %dualuse(i32) -> i32 {
ebb0(v0: i32):
; check: $(cp1=$V) = copy $v0
; nextln: brnz $v0, $ebb1($v0, $cp1)
brnz v0, ebb1(v0, v0)
; not: copy
v1 = iadd_imm v0, 7
v2 = iadd_imm v1, 56
jump ebb1(v1, v2)
ebb1(v10: i32, v11: i32):
v12 = iadd v10, v11
return v12
}
; Interference away from the branch
; The interference can be broken with a copy at either branch.
function %interference(i32) -> i32 {
ebb0(v0: i32):
; not: copy
brnz v0, ebb1(v0)
v1 = iadd_imm v0, 7
; v1 and v0 interfere here:
trapnz v0
; check: $(cp1=$V) = copy $v1
; nextln: jump $ebb1($cp1)
jump ebb1(v1)
ebb1(v10: i32):
; not: copy
v11 = iadd_imm v10, 7
return v11
}
; A loop where one induction variable is used as a backedge argument.
function %fibonacci(i32) -> i32 {
ebb0(v0: i32):
; not: copy
v1 = iconst.i32 1
v2 = iconst.i32 2
jump ebb1(v1, v2)
ebb1(v10: i32, v11: i32):
; v11 needs to be isolated because it interferes with v10.
; check: $ebb1($v10: i32, $(nv11a=$V): i32)
; check: $v11 = copy $nv11a
v12 = iadd v10, v11
v13 = icmp ult v12, v0
; check: $(nv11b=$V) = copy $v11
; nextln: brnz $v13, $ebb1($nv11b, $v12)
brnz v13, ebb1(v11, v12)
return v12
}