When using basic block instructions cannot be added in-between jump instructions which are ending basic blocks. These changes create extra basic blocks such that extra space is available for the spilling and moving registers where they are expected.
145 lines
3.1 KiB
Plaintext
145 lines
3.1 KiB
Plaintext
test regalloc
|
|
target riscv32
|
|
feature !"basic-blocks"
|
|
|
|
; Test the coalescer.
|
|
; regex: V=v\d+
|
|
; regex: WS=\s+
|
|
; regex: LOC=%\w+
|
|
|
|
; 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)
|
|
jump ebb2
|
|
|
|
ebb2:
|
|
; 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)
|
|
jump ebb2
|
|
|
|
ebb2:
|
|
; 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($cp1, v0)
|
|
brnz v0, ebb1(v0, v0)
|
|
jump ebb2
|
|
|
|
ebb2:
|
|
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):
|
|
; check: $(cp0=$V) = copy v0
|
|
; not: copy
|
|
; check: brnz v0, ebb1($cp0)
|
|
brnz v0, ebb1(v0)
|
|
jump ebb2
|
|
|
|
ebb2:
|
|
v1 = iadd_imm v0, 7
|
|
; v1 and v0 interfere here:
|
|
v2 = iadd_imm v0, 8
|
|
; not: copy
|
|
; check: jump ebb1(v1)
|
|
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):
|
|
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 [$LOC], $(nv11a=$V): i32 [$LOC])
|
|
; check: v11 = copy $nv11a
|
|
v12 = iadd v10, v11
|
|
v13 = icmp ult v12, v0
|
|
; check: $(nv11b=$V) = copy v11
|
|
; not: copy
|
|
; check: brnz v13, ebb1($nv11b, v12)
|
|
brnz v13, ebb1(v11, v12)
|
|
jump ebb2
|
|
|
|
ebb2:
|
|
return v12
|
|
}
|
|
|
|
; Function arguments passed on the stack aren't allowed to be part of a virtual
|
|
; register, at least for now. This is because the other values in the virtual
|
|
; register would need to be spilled to the incoming_arg stack slot which we treat
|
|
; as belonging to the caller.
|
|
function %stackarg(i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32 {
|
|
; check: ss0 = incoming_arg 4
|
|
; not: incoming_arg
|
|
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32, v8: i32):
|
|
; check: fill v8
|
|
; not: v8
|
|
jump ebb1(v8)
|
|
|
|
ebb1(v10: i32):
|
|
v11 = iadd_imm v10, 1
|
|
return v11
|
|
}
|
|
|
|
function %gvn_unremovable_phi(i32) system_v {
|
|
ebb0(v0: i32):
|
|
v2 = iconst.i32 0
|
|
jump ebb2(v2, v0)
|
|
|
|
ebb2(v3: i32, v4: i32):
|
|
brnz v3, ebb2(v3, v4)
|
|
jump ebb3
|
|
|
|
ebb3:
|
|
v5 = iconst.i32 1
|
|
brnz v3, ebb2(v2, v5)
|
|
jump ebb4
|
|
|
|
ebb4:
|
|
return
|
|
}
|