moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
35
cranelift/filetests/filetests/regalloc/aliases.clif
Normal file
35
cranelift/filetests/filetests/regalloc/aliases.clif
Normal file
@@ -0,0 +1,35 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
function %value_aliases(i32, f32, i64 vmctx) baldrdash {
|
||||
gv0 = vmctx
|
||||
heap0 = static gv0, min 0x0001_0000, bound 0x0001_0000_0000, offset_guard 0x8000_0000
|
||||
|
||||
ebb0(v0: i32, v1: f32, v2: i64):
|
||||
v3 = iconst.i32 0
|
||||
jump ebb3(v3)
|
||||
|
||||
ebb3(v4: i32):
|
||||
v5 = heap_addr.i64 heap0, v4, 1
|
||||
v6 = load.f32 v5
|
||||
v7 -> v1
|
||||
v8 = fdiv v6, v7
|
||||
v9 = heap_addr.i64 heap0, v4, 1
|
||||
store v8, v9
|
||||
v10 = iconst.i32 4
|
||||
v11 = iadd v4, v10
|
||||
v12 -> v0
|
||||
v13 = icmp ult v11, v12
|
||||
v14 = bint.i32 v13
|
||||
brnz v14, ebb3(v11)
|
||||
jump ebb4
|
||||
|
||||
ebb4:
|
||||
jump ebb2
|
||||
|
||||
ebb2:
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
return
|
||||
}
|
||||
80
cranelift/filetests/filetests/regalloc/basic.clif
Normal file
80
cranelift/filetests/filetests/regalloc/basic.clif
Normal file
@@ -0,0 +1,80 @@
|
||||
test regalloc
|
||||
|
||||
; We can add more ISAs once they have defined encodings.
|
||||
target riscv32
|
||||
|
||||
; regex: RX=%x\d+
|
||||
|
||||
function %add(i32, i32) {
|
||||
ebb0(v1: i32, v2: i32):
|
||||
v3 = iadd v1, v2
|
||||
; check: [R#0c,%x5]
|
||||
; sameln: iadd
|
||||
return
|
||||
}
|
||||
|
||||
; Function with a dead argument.
|
||||
function %dead_arg(i32, i32) -> i32{
|
||||
ebb0(v1: i32, v2: i32):
|
||||
; not: regmove
|
||||
; check: return v1
|
||||
return v1
|
||||
}
|
||||
|
||||
; Return a value from a different register.
|
||||
function %move1(i32, i32) -> i32 {
|
||||
ebb0(v1: i32, v2: i32):
|
||||
; not: regmove
|
||||
; check: regmove v2, %x11 -> %x10
|
||||
; nextln: return v2
|
||||
return v2
|
||||
}
|
||||
|
||||
; Swap two registers.
|
||||
function %swap(i32, i32) -> i32, i32 {
|
||||
ebb0(v1: i32, v2: i32):
|
||||
; not: regmove
|
||||
; check: regmove v2, %x11 -> $(tmp=$RX)
|
||||
; nextln: regmove v1, %x10 -> %x11
|
||||
; nextln: regmove v2, $tmp -> %x10
|
||||
; nextln: return v2, v1
|
||||
return v2, v1
|
||||
}
|
||||
|
||||
; Return an EBB argument.
|
||||
function %retebb(i32, i32) -> i32 {
|
||||
ebb0(v1: i32, v2: i32):
|
||||
brnz v1, ebb1(v1)
|
||||
jump ebb1(v2)
|
||||
|
||||
ebb1(v10: i32):
|
||||
return v10
|
||||
}
|
||||
|
||||
; Pass an EBB argument as a function argument.
|
||||
function %callebb(i32, i32) -> i32 {
|
||||
fn0 = %foo(i32) -> i32
|
||||
|
||||
ebb0(v1: i32, v2: i32):
|
||||
brnz v1, ebb1(v1)
|
||||
jump ebb1(v2)
|
||||
|
||||
ebb1(v10: i32):
|
||||
v11 = call fn0(v10)
|
||||
return v11
|
||||
}
|
||||
|
||||
; Pass an EBB argument as a jump argument.
|
||||
function %jumpebb(i32, i32) -> i32 {
|
||||
fn0 = %foo(i32) -> i32
|
||||
|
||||
ebb0(v1: i32, v2: i32):
|
||||
brnz v1, ebb1(v1, v2)
|
||||
jump ebb1(v2, v1)
|
||||
|
||||
ebb1(v10: i32, v11: i32):
|
||||
jump ebb2(v10, v11)
|
||||
|
||||
ebb2(v20: i32, v21: i32):
|
||||
return v21
|
||||
}
|
||||
122
cranelift/filetests/filetests/regalloc/coalesce.clif
Normal file
122
cranelift/filetests/filetests/regalloc/coalesce.clif
Normal file
@@ -0,0 +1,122 @@
|
||||
test regalloc
|
||||
target riscv32
|
||||
|
||||
; 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)
|
||||
; 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($cp1, v0)
|
||||
brnz v0, ebb1(v0, v0)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
v5 = iconst.i32 1
|
||||
brnz v3, ebb2(v2, v5)
|
||||
return
|
||||
}
|
||||
1263
cranelift/filetests/filetests/regalloc/coalescing-207.clif
Normal file
1263
cranelift/filetests/filetests/regalloc/coalescing-207.clif
Normal file
File diff suppressed because it is too large
Load Diff
72
cranelift/filetests/filetests/regalloc/coalescing-216.clif
Normal file
72
cranelift/filetests/filetests/regalloc/coalescing-216.clif
Normal file
@@ -0,0 +1,72 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
; Reported as https://github.com/CraneStation/cranelift/issues/216 from the Binaryen fuzzer.
|
||||
;
|
||||
; The (old) coalescer creates a virtual register with two identical values.
|
||||
function %pr216(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] system_v {
|
||||
ebb0(v0: i32, v1: i64):
|
||||
v3 = iconst.i64 0
|
||||
v5 = iconst.i32 0
|
||||
brz v5, ebb3(v3)
|
||||
jump ebb4(v3, v3)
|
||||
|
||||
ebb4(v11: i64, v29: i64):
|
||||
v6 = iconst.i32 0
|
||||
brz v6, ebb14
|
||||
v9 = iconst.i32 -17
|
||||
v12 = iconst.i32 0xffff_ffff_ffff_8000
|
||||
jump ebb9(v12)
|
||||
|
||||
ebb9(v10: i32):
|
||||
brnz v10, ebb8(v9, v11, v11)
|
||||
brz.i32 v9, ebb13
|
||||
v13 = iconst.i32 0
|
||||
brnz v13, ebb6(v11, v11)
|
||||
v14 = iconst.i32 0
|
||||
brz v14, ebb12
|
||||
jump ebb11
|
||||
|
||||
ebb12:
|
||||
jump ebb4(v11, v11)
|
||||
|
||||
ebb11:
|
||||
jump ebb10(v11)
|
||||
|
||||
ebb13:
|
||||
v15 = iconst.i64 1
|
||||
jump ebb10(v15)
|
||||
|
||||
ebb10(v21: i64):
|
||||
v16 = iconst.i32 0
|
||||
brnz v16, ebb6(v21, v11)
|
||||
v17 = iconst.i32 0xffff_ffff_ffff_9f35
|
||||
jump ebb8(v17, v21, v11)
|
||||
|
||||
ebb8(v8: i32, v23: i64, v28: i64):
|
||||
jump ebb7(v8, v23, v28)
|
||||
|
||||
ebb14:
|
||||
v18 = iconst.i32 0
|
||||
jump ebb7(v18, v11, v29)
|
||||
|
||||
ebb7(v7: i32, v22: i64, v27: i64):
|
||||
jump ebb6(v22, v27)
|
||||
|
||||
ebb6(v20: i64, v25: i64):
|
||||
v19 = iconst.i32 0xffc7
|
||||
brnz v19, ebb4(v20, v25)
|
||||
jump ebb5
|
||||
|
||||
ebb5:
|
||||
jump ebb3(v25)
|
||||
|
||||
ebb3(v24: i64):
|
||||
jump ebb2(v24)
|
||||
|
||||
ebb2(v4: i64):
|
||||
jump ebb1(v4)
|
||||
|
||||
ebb1(v2: i64):
|
||||
return v2
|
||||
}
|
||||
100
cranelift/filetests/filetests/regalloc/coloring-227.clif
Normal file
100
cranelift/filetests/filetests/regalloc/coloring-227.clif
Normal file
@@ -0,0 +1,100 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
function %pr227(i32 [%rdi], i32 [%rsi], i32 [%rdx], i32 [%rcx], i64 vmctx [%r8]) system_v {
|
||||
gv0 = vmctx
|
||||
heap0 = static gv0, min 0, bound 0x0001_0000_0000, offset_guard 0x8000_0000
|
||||
|
||||
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i64):
|
||||
[RexOp1pu_id#b8] v5 = iconst.i32 0
|
||||
[RexOp1pu_id#b8] v6 = iconst.i32 0
|
||||
[RexOp1tjccb#74] brz v6, ebb10
|
||||
[RexOp1jmpb#eb] jump ebb3(v5, v5, v5, v5, v5, v5, v0, v1, v2, v3)
|
||||
|
||||
ebb3(v15: i32, v17: i32, v25: i32, v31: i32, v40: i32, v47: i32, v54: i32, v61: i32, v68: i32, v75: i32):
|
||||
[RexOp1jmpb#eb] jump ebb6
|
||||
|
||||
ebb6:
|
||||
[RexOp1pu_id#b8] v8 = iconst.i32 0
|
||||
[RexOp1tjccb#75] brnz v8, ebb5
|
||||
[RexOp1pu_id#b8] v9 = iconst.i32 0
|
||||
[RexOp1pu_id#b8] v11 = iconst.i32 0
|
||||
[RexOp1icscc#39] v12 = icmp.i32 eq v15, v11
|
||||
[RexOp2urm_noflags#4b6] v13 = bint.i32 v12
|
||||
[RexOp1rr#21] v14 = band v9, v13
|
||||
[RexOp1tjccb#75] brnz v14, ebb6
|
||||
[RexOp1jmpb#eb] jump ebb7
|
||||
|
||||
ebb7:
|
||||
[RexOp1tjccb#74] brz.i32 v17, ebb8
|
||||
[RexOp1pu_id#b8] v18 = iconst.i32 0
|
||||
[RexOp1tjccb#74] brz v18, ebb9
|
||||
[RexOp1pu_id#b8] v21 = iconst.i32 0
|
||||
[RexOp1umr#89] v79 = uextend.i64 v5
|
||||
[RexOp1r_ib#8083] v80 = iadd_imm.i64 v4, 0
|
||||
[RexOp1ld#808b] v81 = load.i64 v80
|
||||
[RexOp1rr#8001] v22 = iadd v81, v79
|
||||
[RexMp1st#189] istore16 v21, v22
|
||||
[RexOp1jmpb#eb] jump ebb9
|
||||
|
||||
ebb9:
|
||||
[RexOp1jmpb#eb] jump ebb8
|
||||
|
||||
ebb8:
|
||||
[RexOp1pu_id#b8] v27 = iconst.i32 3
|
||||
[RexOp1pu_id#b8] v28 = iconst.i32 4
|
||||
[RexOp1rr#09] v35 = bor.i32 v31, v13
|
||||
[RexOp1tjccb#75] brnz v35, ebb15(v27)
|
||||
[RexOp1jmpb#eb] jump ebb15(v28)
|
||||
|
||||
ebb15(v36: i32):
|
||||
[RexOp1jmpb#eb] jump ebb3(v25, v36, v25, v31, v40, v47, v54, v61, v68, v75)
|
||||
|
||||
ebb5:
|
||||
[RexOp1jmpb#eb] jump ebb4
|
||||
|
||||
ebb4:
|
||||
[RexOp1jmpb#eb] jump ebb2(v40, v47, v54, v61, v68, v75)
|
||||
|
||||
ebb10:
|
||||
[RexOp1pu_id#b8] v43 = iconst.i32 0
|
||||
[RexOp1jmpb#eb] jump ebb2(v43, v5, v0, v1, v2, v3)
|
||||
|
||||
ebb2(v7: i32, v45: i32, v52: i32, v59: i32, v66: i32, v73: i32):
|
||||
[RexOp1pu_id#b8] v44 = iconst.i32 0
|
||||
[RexOp1tjccb#74] brz v44, ebb12
|
||||
[RexOp1pu_id#b8] v50 = iconst.i32 11
|
||||
[RexOp1tjccb#74] brz v50, ebb14
|
||||
[RexOp1umr#89] v82 = uextend.i64 v52
|
||||
[RexOp1r_ib#8083] v83 = iadd_imm.i64 v4, 0
|
||||
[RexOp1ld#808b] v84 = load.i64 v83
|
||||
[RexOp1rr#8001] v57 = iadd v84, v82
|
||||
[RexOp1ld#8b] v58 = load.i32 v57
|
||||
[RexOp1umr#89] v85 = uextend.i64 v58
|
||||
[RexOp1r_ib#8083] v86 = iadd_imm.i64 v4, 0
|
||||
[RexOp1ld#808b] v87 = load.i64 v86
|
||||
[RexOp1rr#8001] v64 = iadd v87, v85
|
||||
[RexOp1st#88] istore8 v59, v64
|
||||
[RexOp1pu_id#b8] v65 = iconst.i32 0
|
||||
[RexOp1jmpb#eb] jump ebb13(v65)
|
||||
|
||||
ebb14:
|
||||
[RexOp1jmpb#eb] jump ebb13(v66)
|
||||
|
||||
ebb13(v51: i32):
|
||||
[RexOp1umr#89] v88 = uextend.i64 v45
|
||||
[RexOp1r_ib#8083] v89 = iadd_imm.i64 v4, 0
|
||||
[RexOp1ld#808b] v90 = load.i64 v89
|
||||
[RexOp1rr#8001] v71 = iadd v90, v88
|
||||
[RexOp1st#89] store v51, v71
|
||||
[RexOp1jmpb#eb] jump ebb12
|
||||
|
||||
ebb12:
|
||||
[RexOp1jmpb#eb] jump ebb11
|
||||
|
||||
ebb11:
|
||||
[RexOp1jmpb#eb] jump ebb1
|
||||
|
||||
ebb1:
|
||||
[Op1ret#c3] return
|
||||
}
|
||||
82
cranelift/filetests/filetests/regalloc/constraints.clif
Normal file
82
cranelift/filetests/filetests/regalloc/constraints.clif
Normal file
@@ -0,0 +1,82 @@
|
||||
test regalloc
|
||||
target i686
|
||||
|
||||
; regex: V=v\d+
|
||||
; regex: REG=%r([abcd]x|[sd]i)
|
||||
|
||||
; Tied operands, both are killed at instruction.
|
||||
function %tied_easy() -> i32 {
|
||||
ebb0:
|
||||
v0 = iconst.i32 12
|
||||
v1 = iconst.i32 13
|
||||
; not: copy
|
||||
; check: isub
|
||||
v2 = isub v0, v1
|
||||
return v2
|
||||
}
|
||||
|
||||
; Tied operand is live after instruction.
|
||||
function %tied_alive() -> i32 {
|
||||
ebb0:
|
||||
v0 = iconst.i32 12
|
||||
v1 = iconst.i32 13
|
||||
; check: $(v0c=$V) = copy v0
|
||||
; check: v2 = isub $v0c, v1
|
||||
v2 = isub v0, v1
|
||||
; check: v3 = iadd v2, v0
|
||||
v3 = iadd v2, v0
|
||||
return v3
|
||||
}
|
||||
|
||||
; Fixed register constraint.
|
||||
function %fixed_op() -> i32 {
|
||||
ebb0:
|
||||
; check: ,%rax]
|
||||
; sameln: v0 = iconst.i32 12
|
||||
v0 = iconst.i32 12
|
||||
v1 = iconst.i32 13
|
||||
; The dynamic shift amount must be in %rcx
|
||||
; check: regmove v0, %rax -> %rcx
|
||||
v2 = ishl v1, v0
|
||||
return v2
|
||||
}
|
||||
|
||||
; Fixed register constraint twice.
|
||||
function %fixed_op_twice() -> i32 {
|
||||
ebb0:
|
||||
; check: ,%rax]
|
||||
; sameln: v0 = iconst.i32 12
|
||||
v0 = iconst.i32 12
|
||||
v1 = iconst.i32 13
|
||||
; The dynamic shift amount must be in %rcx
|
||||
; check: regmove v0, %rax -> %rcx
|
||||
v2 = ishl v1, v0
|
||||
; check: regmove v0, %rcx -> $REG
|
||||
; check: regmove v2, $REG -> %rcx
|
||||
v3 = ishl v0, v2
|
||||
|
||||
return v3
|
||||
}
|
||||
|
||||
; Tied use of a diverted register.
|
||||
function %fixed_op_twice() -> i32 {
|
||||
ebb0:
|
||||
; check: ,%rax]
|
||||
; sameln: v0 = iconst.i32 12
|
||||
v0 = iconst.i32 12
|
||||
v1 = iconst.i32 13
|
||||
; The dynamic shift amount must be in %rcx
|
||||
; check: regmove v0, %rax -> %rcx
|
||||
; check: v2 = ishl v1, v0
|
||||
v2 = ishl v1, v0
|
||||
|
||||
; Now v0 is globally allocated to %rax, but diverted to %rcx.
|
||||
; Check that the tied def gets the diverted register.
|
||||
v3 = isub v0, v2
|
||||
; not: regmove
|
||||
; check: ,%rcx]
|
||||
; sameln: isub
|
||||
; Move it into place for the return value.
|
||||
; check: regmove v3, %rcx -> %rax
|
||||
return v3
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
test regalloc
|
||||
target x86_64
|
||||
|
||||
; Test that fallthrough returns are visited by reload and coloring.
|
||||
|
||||
function %foo() -> f64 {
|
||||
fn0 = %bar()
|
||||
|
||||
ebb0:
|
||||
v0 = f64const 0.0
|
||||
call fn0()
|
||||
fallthrough_return v0
|
||||
}
|
||||
; check: fill v0
|
||||
|
||||
function %foo() -> f64 {
|
||||
fn0 = %bar() -> f64, f64
|
||||
|
||||
ebb0:
|
||||
v0, v1 = call fn0()
|
||||
fallthrough_return v1
|
||||
}
|
||||
; check: regmove v1, %xmm1 -> %xmm0
|
||||
42
cranelift/filetests/filetests/regalloc/ghost-param.clif
Normal file
42
cranelift/filetests/filetests/regalloc/ghost-param.clif
Normal file
@@ -0,0 +1,42 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
; This test case would create an EBB parameter that was a ghost value.
|
||||
; The coalescer would insert a copy of the ghost value, leading to verifier errors.
|
||||
;
|
||||
; We don't allow EBB parameters to be ghost values any longer.
|
||||
;
|
||||
; Test case by binaryen fuzzer!
|
||||
|
||||
function %pr215(i64 vmctx [%rdi]) system_v {
|
||||
ebb0(v0: i64):
|
||||
v10 = iconst.i64 0
|
||||
v1 = bitcast.f64 v10
|
||||
jump ebb5(v1)
|
||||
|
||||
ebb5(v9: f64):
|
||||
v11 = iconst.i64 0xffff_ffff_ff9a_421a
|
||||
v4 = bitcast.f64 v11
|
||||
v6 = iconst.i32 0
|
||||
v7 = iconst.i32 1
|
||||
brnz v7, ebb4(v6)
|
||||
v8 = iconst.i32 0
|
||||
jump ebb7(v8)
|
||||
|
||||
ebb7(v5: i32):
|
||||
brnz v5, ebb3(v4)
|
||||
jump ebb5(v4)
|
||||
|
||||
ebb4(v3: i32):
|
||||
brnz v3, ebb2
|
||||
jump ebb3(v9)
|
||||
|
||||
ebb3(v2: f64):
|
||||
jump ebb2
|
||||
|
||||
ebb2:
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
test regalloc
|
||||
target i686
|
||||
|
||||
; This test covers the troubles when values with global live ranges are defined
|
||||
; by instructions with constrained register classes.
|
||||
;
|
||||
; The icmp_imm instrutions write their b1 result to the ABCD register class on
|
||||
; 32-bit x86. So if we define 5 live values, they can't all fit.
|
||||
function %global_constraints(i32) {
|
||||
ebb0(v0: i32):
|
||||
v1 = icmp_imm eq v0, 1
|
||||
v2 = icmp_imm ugt v0, 2
|
||||
v3 = icmp_imm sle v0, 3
|
||||
v4 = icmp_imm ne v0, 4
|
||||
v5 = icmp_imm sge v0, 5
|
||||
brnz v5, ebb1
|
||||
return
|
||||
|
||||
ebb1:
|
||||
; Make sure v1-v5 are live in.
|
||||
v10 = band v1, v2
|
||||
v11 = bor v3, v4
|
||||
v12 = bor v10, v11
|
||||
v13 = bor v12, v5
|
||||
trapnz v13, user0
|
||||
return
|
||||
}
|
||||
16
cranelift/filetests/filetests/regalloc/global-fixed.clif
Normal file
16
cranelift/filetests/filetests/regalloc/global-fixed.clif
Normal file
@@ -0,0 +1,16 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
function %foo() system_v {
|
||||
ebb4:
|
||||
v3 = iconst.i32 0
|
||||
jump ebb3
|
||||
|
||||
ebb3:
|
||||
v9 = udiv v3, v3
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
v19 = iadd.i32 v9, v9
|
||||
jump ebb3
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
test regalloc
|
||||
target x86_64
|
||||
|
||||
function u0:587() fast {
|
||||
ebb0:
|
||||
v97 = iconst.i32 0
|
||||
v169 = iconst.i32 0
|
||||
v1729 = iconst.i32 0
|
||||
jump ebb100(v97, v97, v97, v97, v97)
|
||||
|
||||
ebb100(v1758: i32, v1784: i32, v1845: i32, v1856: i32, v1870: i32):
|
||||
v1762 = iconst.i32 0
|
||||
v1769 = iconst.i32 0
|
||||
v1774 = iconst.i32 0
|
||||
v1864 = iconst.i32 0
|
||||
v1897 = iconst.i32 0
|
||||
jump ebb102(v1774, v1784, v1845, v1856, v1870, v1758, v1762, v169, v1729, v97, v169, v169, v169, v169)
|
||||
|
||||
ebb102(v1785: i32, v1789: i32, v1843: i32, v1854: i32, v1868: i32, v1882: i32, v1890: i32, v1901: i32, v1921: i32, v1933: i32, v2058: i32, v2124: i32, v2236: i32, v2366: i32):
|
||||
v1929 = iconst.i32 0
|
||||
v1943 = iconst.i32 0
|
||||
v1949 = iconst.i32 0
|
||||
jump ebb123(v1897, v1769)
|
||||
|
||||
ebb123(v1950: i32, v1979: i32):
|
||||
v1955 = iconst.i32 0
|
||||
brz v1955, ebb125
|
||||
jump ebb122(v1929, v1843, v1864, v2058, v1882, v1897, v1943, v1868, v2124, v1901)
|
||||
|
||||
ebb125:
|
||||
v1961 = iadd_imm.i32 v1949, 0
|
||||
v1952 = iconst.i32 0
|
||||
v1962 = iconst.i64 0
|
||||
v1963 = load.i32 v1962
|
||||
brz v1963, ebb123(v1952, v1961)
|
||||
jump ebb127
|
||||
|
||||
ebb127:
|
||||
v1966 = iconst.i32 0
|
||||
jump ebb122(v1963, v1966, v1966, v1966, v1966, v1966, v1966, v1966, v1966, v1966)
|
||||
|
||||
ebb122(v1967: i32, v1971: i32, v1972: i32, v1978: i32, v2032: i32, v2041: i32, v2053: i32, v2076: i32, v2085: i32, v2096: i32):
|
||||
trap user0
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
test regalloc
|
||||
target riscv32
|
||||
|
||||
; Here, the coalescer initially builds vreg0 = [v1, v2, v3]
|
||||
;
|
||||
; There's interference between v1 and v2 at the brz instruction. Isolating v2 is not going to
|
||||
; resolve that conflict since v1 will just interfere with the inserted copy too.
|
||||
|
||||
;function %c1(i32) -> i32 {
|
||||
;ebb0(v0: i32):
|
||||
; v1 = iadd_imm v0, 1
|
||||
; v2 = iconst.i32 1
|
||||
; brz v1, ebb1(v2)
|
||||
; jump ebb2
|
||||
;
|
||||
;ebb1(v3: i32):
|
||||
; return v3
|
||||
;
|
||||
;ebb2:
|
||||
; jump ebb1(v1)
|
||||
;}
|
||||
|
||||
; Same thing with v1 and v2 swapped to reverse the order of definitions.
|
||||
|
||||
function %c2(i32) -> i32 {
|
||||
ebb0(v0: i32):
|
||||
v1 = iadd_imm v0, 1
|
||||
v2 = iconst.i32 1
|
||||
brz v2, ebb1(v1)
|
||||
jump ebb2
|
||||
|
||||
ebb1(v3: i32):
|
||||
return v3
|
||||
|
||||
ebb2:
|
||||
jump ebb1(v2)
|
||||
}
|
||||
140
cranelift/filetests/filetests/regalloc/iterate.clif
Normal file
140
cranelift/filetests/filetests/regalloc/iterate.clif
Normal file
@@ -0,0 +1,140 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
function u0:9(i64 [%rdi], f32 [%xmm0], f64 [%xmm1], i32 [%rsi], i32 [%rdx], i64 vmctx [%r14]) -> i64 [%rax] baldrdash {
|
||||
ebb0(v0: i64, v1: f32, v2: f64, v3: i32, v4: i32, v5: i64):
|
||||
v32 = iconst.i32 0
|
||||
v6 = bitcast.f32 v32
|
||||
v7 = iconst.i64 0
|
||||
v33 = iconst.i64 0
|
||||
v8 = bitcast.f64 v33
|
||||
v34 = iconst.i32 0xbe99_999a
|
||||
v9 = bitcast.f32 v34
|
||||
v10 = iconst.i32 40
|
||||
v11 = iconst.i32 -7
|
||||
v35 = iconst.i32 0x40b0_0000
|
||||
v12 = bitcast.f32 v35
|
||||
v13 = iconst.i64 6
|
||||
v36 = iconst.i64 0x4020_0000_0000_0000
|
||||
v14 = bitcast.f64 v36
|
||||
v44 = iconst.i64 0
|
||||
v37 = icmp slt v0, v44
|
||||
brnz v37, ebb2
|
||||
v38 = fcvt_from_sint.f64 v0
|
||||
jump ebb3(v38)
|
||||
|
||||
ebb2:
|
||||
v45 = iconst.i32 1
|
||||
v39 = ushr.i64 v0, v45
|
||||
v40 = band_imm.i64 v0, 1
|
||||
v41 = bor v39, v40
|
||||
v42 = fcvt_from_sint.f64 v41
|
||||
v43 = fadd v42, v42
|
||||
jump ebb3(v43)
|
||||
|
||||
ebb3(v15: f64):
|
||||
v16 = fpromote.f64 v9
|
||||
v46 = uextend.i64 v10
|
||||
v17 = fcvt_from_sint.f64 v46
|
||||
v18 = fcvt_from_sint.f64 v11
|
||||
v19 = fpromote.f64 v12
|
||||
v54 = iconst.i64 0
|
||||
v47 = icmp.i64 slt v13, v54
|
||||
brnz v47, ebb4
|
||||
v48 = fcvt_from_sint.f64 v13
|
||||
jump ebb5(v48)
|
||||
|
||||
ebb4:
|
||||
v55 = iconst.i32 1
|
||||
v49 = ushr.i64 v13, v55
|
||||
v50 = band_imm.i64 v13, 1
|
||||
v51 = bor v49, v50
|
||||
v52 = fcvt_from_sint.f64 v51
|
||||
v53 = fadd v52, v52
|
||||
jump ebb5(v53)
|
||||
|
||||
ebb5(v20: f64):
|
||||
v63 = iconst.i64 0
|
||||
v56 = icmp.i64 slt v7, v63
|
||||
brnz v56, ebb6
|
||||
v57 = fcvt_from_sint.f64 v7
|
||||
jump ebb7(v57)
|
||||
|
||||
ebb6:
|
||||
v64 = iconst.i32 1
|
||||
v58 = ushr.i64 v7, v64
|
||||
v59 = band_imm.i64 v7, 1
|
||||
v60 = bor v58, v59
|
||||
v61 = fcvt_from_sint.f64 v60
|
||||
v62 = fadd v61, v61
|
||||
jump ebb7(v62)
|
||||
|
||||
ebb7(v21: f64):
|
||||
v22 = fadd v21, v14
|
||||
v23 = fadd.f64 v20, v22
|
||||
v24 = fadd.f64 v19, v23
|
||||
v25 = fadd.f64 v18, v24
|
||||
v26 = fadd.f64 v17, v25
|
||||
v27 = fadd.f64 v2, v26
|
||||
v28 = fadd.f64 v16, v27
|
||||
v29 = fadd.f64 v15, v28
|
||||
v30 = x86_cvtt2si.i64 v29
|
||||
v69 = iconst.i64 0x8000_0000_0000_0000
|
||||
v65 = icmp ne v30, v69
|
||||
brnz v65, ebb8
|
||||
v66 = fcmp uno v29, v29
|
||||
brz v66, ebb9
|
||||
trap bad_toint
|
||||
|
||||
ebb9:
|
||||
v70 = iconst.i64 0xc3e0_0000_0000_0000
|
||||
v67 = bitcast.f64 v70
|
||||
v68 = fcmp gt v67, v29
|
||||
brz v68, ebb10
|
||||
trap int_ovf
|
||||
|
||||
ebb10:
|
||||
jump ebb8
|
||||
|
||||
ebb8:
|
||||
jump ebb1(v30)
|
||||
|
||||
ebb1(v31: i64):
|
||||
return v31
|
||||
}
|
||||
|
||||
function u0:26(i64 vmctx [%r14]) -> i64 [%rax] baldrdash {
|
||||
gv1 = vmctx
|
||||
gv0 = iadd_imm.i64 gv1, 48
|
||||
sig0 = (i32 [%rdi], i64 [%rsi], i64 vmctx [%r14], i64 sigid [%rbx]) -> i64 [%rax] baldrdash
|
||||
|
||||
ebb0(v0: i64):
|
||||
v1 = iconst.i32 32
|
||||
v2 = iconst.i64 64
|
||||
v3 = iconst.i32 9
|
||||
v4 = iconst.i64 1063
|
||||
v5 = iadd_imm v0, 48
|
||||
v6 = load.i32 v5
|
||||
v7 = icmp uge v3, v6
|
||||
; If we're unlucky, there are no ABCD registers available for v7 at this branch.
|
||||
brz v7, ebb2
|
||||
trap oob
|
||||
|
||||
ebb2:
|
||||
v8 = load.i64 v5+8
|
||||
v9 = uextend.i64 v3
|
||||
v16 = iconst.i64 16
|
||||
v10 = imul v9, v16
|
||||
v11 = iadd v8, v10
|
||||
v12 = load.i64 v11
|
||||
brnz v12, ebb3
|
||||
trap icall_null
|
||||
|
||||
ebb3:
|
||||
v13 = load.i64 v11+8
|
||||
v14 = call_indirect.i64 sig0, v12(v1, v2, v13, v4)
|
||||
jump ebb1(v14)
|
||||
|
||||
ebb1(v15: i64):
|
||||
return v15
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
; Test combinations of constraints.
|
||||
;
|
||||
; The x86 ushr instruction requires its second operand to be passed in %rcx and its output is
|
||||
; tied to the first input operand.
|
||||
;
|
||||
; If we pass the same value to both operands, both constraints must be satisfied.
|
||||
|
||||
; Found by the Binaryen fuzzer in PR221.
|
||||
;
|
||||
; Conditions triggering the problem:
|
||||
;
|
||||
; - The same value used for a tied operand and a fixed operand.
|
||||
; - The common value is already in %rcx.
|
||||
; - The tied output value is live outside the EBB.
|
||||
;
|
||||
; Under these conditions, Solver::add_tied_input() would create a variable for the tied input
|
||||
; without considering the fixed constraint.
|
||||
function %pr221(i64 [%rdi], i64 [%rsi], i64 [%rdx], i64 [%rcx]) -> i64 [%rax] {
|
||||
ebb0(v0: i64, v1: i64, v2: i64, v3: i64):
|
||||
v4 = ushr v3, v3
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
return v4
|
||||
}
|
||||
|
||||
; Found by the Binaryen fuzzer in PR218.
|
||||
;
|
||||
; This is a similar situation involving combined constraints on the ushr instruction:
|
||||
;
|
||||
; - The %rcx register is already in use by a globally live value.
|
||||
; - The ushr x, x result is also a globally live value.
|
||||
;
|
||||
; Since the ushr x, x result is forced to be placed in %rcx, we must set the replace_global_defines
|
||||
; flag so it can be reassigned to a different global register.
|
||||
function %pr218(i64 [%rdi], i64 [%rsi], i64 [%rdx], i64 [%rcx]) -> i64 [%rax] {
|
||||
ebb0(v0: i64, v1: i64, v2: i64, v3: i64):
|
||||
; check: regmove v3, %rcx ->
|
||||
v4 = ushr v0, v0
|
||||
; check: v4 = copy
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
; v3 is globally live in %rcx.
|
||||
; v4 is also globally live. Needs to be assigned something else for the trip across the CFG edge.
|
||||
v5 = iadd v3, v4
|
||||
return v5
|
||||
}
|
||||
23
cranelift/filetests/filetests/regalloc/multiple-returns.clif
Normal file
23
cranelift/filetests/filetests/regalloc/multiple-returns.clif
Normal file
@@ -0,0 +1,23 @@
|
||||
test regalloc
|
||||
target x86_64
|
||||
|
||||
; Return the same value twice. This needs a copy so that each value can be
|
||||
; allocated its own register.
|
||||
function %multiple_returns() -> i64, i64 {
|
||||
ebb0:
|
||||
v2 = iconst.i64 0
|
||||
return v2, v2
|
||||
}
|
||||
; check: v2 = iconst.i64 0
|
||||
; check: v3 = copy v2
|
||||
; check: return v2, v3
|
||||
|
||||
; Same thing, now with a fallthrough_return.
|
||||
function %multiple_returns() -> i64, i64 {
|
||||
ebb0:
|
||||
v2 = iconst.i64 0
|
||||
fallthrough_return v2, v2
|
||||
}
|
||||
; check: v2 = iconst.i64 0
|
||||
; check: v3 = copy v2
|
||||
; check: fallthrough_return v2, v3
|
||||
@@ -0,0 +1,14 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
function %test(i64) -> i64 system_v {
|
||||
ebb0(v0: i64):
|
||||
v2 = iconst.i64 12
|
||||
; This division clobbers two of its fixed input registers on x86.
|
||||
; These are FixedTied constraints that the spiller needs to resolve.
|
||||
v5 = udiv v0, v2
|
||||
v6 = iconst.i64 13
|
||||
v9 = udiv v0, v6
|
||||
v10 = iadd v5, v9
|
||||
return v10
|
||||
}
|
||||
94
cranelift/filetests/filetests/regalloc/reload-208.clif
Normal file
94
cranelift/filetests/filetests/regalloc/reload-208.clif
Normal file
@@ -0,0 +1,94 @@
|
||||
test regalloc
|
||||
target x86_64 haswell
|
||||
|
||||
; regex: V=v\d+
|
||||
|
||||
; Filed as https://github.com/CraneStation/cranelift/issues/208
|
||||
;
|
||||
; The verifier complains about a branch argument that is not in the same virtual register as the
|
||||
; corresponding EBB argument.
|
||||
;
|
||||
; The problem was the reload pass rewriting EBB arguments on "brnz v9, ebb3(v9)"
|
||||
|
||||
function %pr208(i64 vmctx [%rdi]) system_v {
|
||||
gv1 = vmctx
|
||||
gv0 = iadd_imm.i64 gv1, -8
|
||||
heap0 = static gv0, min 0, bound 0x5000, offset_guard 0x0040_0000
|
||||
sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] system_v
|
||||
sig1 = (i64 vmctx [%rdi], i32 [%rsi]) system_v
|
||||
fn0 = u0:1 sig0
|
||||
fn1 = u0:3 sig1
|
||||
|
||||
ebb0(v0: i64):
|
||||
v1 = iconst.i32 0
|
||||
v2 = call fn0(v0)
|
||||
v20 = iconst.i32 0x4ffe
|
||||
v16 = icmp uge v2, v20
|
||||
brz v16, ebb5
|
||||
trap heap_oob
|
||||
|
||||
ebb5:
|
||||
v17 = uextend.i64 v2
|
||||
v18 = iadd_imm.i64 v0, -8
|
||||
v19 = load.i64 v18
|
||||
v3 = iadd v19, v17
|
||||
v4 = load.i32 v3
|
||||
v21 = iconst.i32 0
|
||||
v5 = icmp eq v4, v21
|
||||
v6 = bint.i32 v5
|
||||
brnz v6, ebb2
|
||||
jump ebb3(v4)
|
||||
|
||||
ebb3(v7: i32):
|
||||
call fn1(v0, v7)
|
||||
v26 = iconst.i32 0x4ffe
|
||||
v22 = icmp uge v7, v26
|
||||
brz v22, ebb6
|
||||
trap heap_oob
|
||||
|
||||
ebb6:
|
||||
v23 = uextend.i64 v7
|
||||
v24 = iadd_imm.i64 v0, -8
|
||||
v25 = load.i64 v24
|
||||
v8 = iadd v25, v23
|
||||
v9 = load.i32 v8+56
|
||||
; check: v9 = spill
|
||||
; check: brnz $V, ebb3(v9)
|
||||
brnz v9, ebb3(v9)
|
||||
jump ebb4
|
||||
|
||||
ebb4:
|
||||
jump ebb2
|
||||
|
||||
ebb2:
|
||||
v10 = iconst.i32 0
|
||||
v31 = iconst.i32 0x4ffe
|
||||
v27 = icmp uge v10, v31
|
||||
brz v27, ebb7
|
||||
trap heap_oob
|
||||
|
||||
ebb7:
|
||||
v28 = uextend.i64 v10
|
||||
v29 = iadd_imm.i64 v0, -8
|
||||
v30 = load.i64 v29
|
||||
v11 = iadd v30, v28
|
||||
v12 = load.i32 v11+12
|
||||
call fn1(v0, v12)
|
||||
v13 = iconst.i32 0
|
||||
v36 = iconst.i32 0x4ffe
|
||||
v32 = icmp uge v13, v36
|
||||
brz v32, ebb8
|
||||
trap heap_oob
|
||||
|
||||
ebb8:
|
||||
v33 = uextend.i64 v13
|
||||
v34 = iadd_imm.i64 v0, -8
|
||||
v35 = load.i64 v34
|
||||
v14 = iadd v35, v33
|
||||
v15 = load.i32 v14+12
|
||||
call fn1(v0, v15)
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
return
|
||||
}
|
||||
46
cranelift/filetests/filetests/regalloc/reload.clif
Normal file
46
cranelift/filetests/filetests/regalloc/reload.clif
Normal file
@@ -0,0 +1,46 @@
|
||||
test regalloc
|
||||
target riscv32 enable_e
|
||||
|
||||
; regex: V=v\d+
|
||||
|
||||
; Check that we can handle a function return value that got spilled.
|
||||
function %spill_return() -> i32 {
|
||||
fn0 = %foo() -> i32 system_v
|
||||
|
||||
ebb0:
|
||||
v0 = call fn0()
|
||||
; check: $(reg=$V) = call fn0
|
||||
; check: v0 = spill $reg
|
||||
v2 = call fn0()
|
||||
; check: v2 = call fn0
|
||||
return v0
|
||||
; check: $(reload=$V) = fill v0
|
||||
; check: return $reload
|
||||
}
|
||||
|
||||
; Check that copies where the arg has been spilled are replaced with fills.
|
||||
;
|
||||
; RV32E has 6 registers for function arguments so the 7th, v6, will be placed
|
||||
; on the stack.
|
||||
function %spilled_copy_arg(i32, i32, i32, i32, i32, i32, i32) -> i32 {
|
||||
|
||||
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
|
||||
; not: copy
|
||||
; check: v10 = fill v6
|
||||
v10 = copy v6
|
||||
return v10
|
||||
}
|
||||
|
||||
; Check that copies where the result has been spilled are replaced with spills.
|
||||
;
|
||||
; v1 is live across a call so it will be spilled.
|
||||
function %spilled_copy_result(i32) -> i32 {
|
||||
fn0 = %foo(i32)
|
||||
|
||||
ebb0(v0: i32):
|
||||
; not: copy
|
||||
; check: v1 = spill v0
|
||||
v1 = copy v0
|
||||
call fn0(v1)
|
||||
return v1
|
||||
}
|
||||
39
cranelift/filetests/filetests/regalloc/schedule-moves.clif
Normal file
39
cranelift/filetests/filetests/regalloc/schedule-moves.clif
Normal file
@@ -0,0 +1,39 @@
|
||||
test regalloc
|
||||
target i686 haswell
|
||||
|
||||
function %pr165() system_v {
|
||||
ebb0:
|
||||
v0 = iconst.i32 0x0102_0304
|
||||
v1 = iconst.i32 0x1102_0304
|
||||
v2 = iconst.i32 0x2102_0304
|
||||
v20 = ishl v1, v0
|
||||
v21 = ishl v2, v0
|
||||
v22 = sshr v1, v0
|
||||
v23 = sshr v2, v0
|
||||
v24 = ushr v1, v0
|
||||
v25 = ushr v2, v0
|
||||
istore8 v0, v1+0x2710
|
||||
istore8 v1, v0+0x2710
|
||||
return
|
||||
}
|
||||
|
||||
; Same as above, but use so many registers that spilling is required.
|
||||
; Note: This is also a candidate for using xchg instructions.
|
||||
function %emergency_spill() system_v {
|
||||
ebb0:
|
||||
v0 = iconst.i32 0x0102_0304
|
||||
v1 = iconst.i32 0x1102_0304
|
||||
v2 = iconst.i32 0x2102_0304
|
||||
v3 = iconst.i32 0x3102_0304
|
||||
v4 = iconst.i32 0x4102_0304
|
||||
v20 = ishl v1, v0
|
||||
v21 = ishl v2, v3
|
||||
v22 = sshr v1, v0
|
||||
v23 = sshr v2, v0
|
||||
v24 = ushr v1, v0
|
||||
v25 = ushr v2, v0
|
||||
istore8 v0, v1+0x2710
|
||||
istore8 v1, v0+0x2710
|
||||
istore8 v3, v4+0x2710
|
||||
return
|
||||
}
|
||||
175
cranelift/filetests/filetests/regalloc/spill-noregs.clif
Normal file
175
cranelift/filetests/filetests/regalloc/spill-noregs.clif
Normal file
@@ -0,0 +1,175 @@
|
||||
test regalloc
|
||||
target x86_64
|
||||
|
||||
; Test case found by the Binaryen fuzzer.
|
||||
;
|
||||
; The spiller panics with a
|
||||
; 'Ran out of GPR registers when inserting copy before v68 = icmp.i32 eq v66, v67',
|
||||
; cranelift-codegen/src/regalloc/spilling.rs:425:28 message.
|
||||
;
|
||||
; The process_reg_uses() function is trying to insert a copy before the icmp instruction in ebb4
|
||||
; and runs out of registers to spill. Note that ebb7 has a lot of dead parameter values.
|
||||
;
|
||||
; The spiller was not releasing register pressure for dead EBB parameters.
|
||||
|
||||
function %pr223(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] system_v {
|
||||
ebb0(v0: i32, v1: i64):
|
||||
v2 = iconst.i32 0
|
||||
v3 = iconst.i64 0
|
||||
v4 = iconst.i32 0xffff_ffff_bb3f_4a2c
|
||||
brz v4, ebb5
|
||||
jump ebb1
|
||||
|
||||
ebb1:
|
||||
v5 = iconst.i32 0
|
||||
v6 = copy.i64 v3
|
||||
v7 = copy.i64 v3
|
||||
v8 = copy.i64 v3
|
||||
v9 = copy.i64 v3
|
||||
v10 = copy.i64 v3
|
||||
v11 = copy.i64 v3
|
||||
v12 = copy.i64 v3
|
||||
v13 = copy.i64 v3
|
||||
v14 = copy.i64 v3
|
||||
v15 = copy.i64 v3
|
||||
v16 = copy.i64 v3
|
||||
brnz v5, ebb4(v2, v3, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
|
||||
jump ebb2
|
||||
|
||||
ebb2:
|
||||
v17 = iconst.i32 0
|
||||
v18 = copy.i64 v3
|
||||
v19 = copy.i64 v3
|
||||
v20 = copy.i64 v3
|
||||
v21 = copy.i64 v3
|
||||
v22 = copy.i64 v3
|
||||
v23 = copy.i64 v3
|
||||
v24 = copy.i64 v3
|
||||
v25 = copy.i64 v3
|
||||
v26 = copy.i64 v3
|
||||
v27 = copy.i64 v3
|
||||
v28 = copy.i64 v3
|
||||
brnz v17, ebb4(v2, v3, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
|
||||
jump ebb3
|
||||
|
||||
ebb3:
|
||||
jump ebb1
|
||||
|
||||
ebb4(v29: i32, v30: i64, v31: i64, v32: i64, v33: i64, v34: i64, v35: i64, v36: i64, v37: i64, v38: i64, v39: i64, v40: i64, v41: i64):
|
||||
jump ebb7(v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
|
||||
|
||||
ebb5:
|
||||
jump ebb6
|
||||
|
||||
ebb6:
|
||||
v42 = copy.i64 v3
|
||||
v43 = copy.i64 v3
|
||||
v44 = copy.i64 v3
|
||||
v45 = copy.i64 v3
|
||||
v46 = copy.i64 v3
|
||||
v47 = copy.i64 v3
|
||||
v48 = copy.i64 v3
|
||||
v49 = copy.i64 v3
|
||||
v50 = copy.i64 v3
|
||||
v51 = copy.i64 v3
|
||||
v52 = copy.i64 v3
|
||||
jump ebb7(v2, v3, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
|
||||
|
||||
ebb7(v53: i32, v54: i64, v55: i64, v56: i64, v57: i64, v58: i64, v59: i64, v60: i64, v61: i64, v62: i64, v63: i64, v64: i64, v65: i64):
|
||||
v66 = iconst.i32 0
|
||||
v67 = iconst.i32 0
|
||||
v68 = icmp eq v66, v67
|
||||
v69 = bint.i32 v68
|
||||
jump ebb8
|
||||
|
||||
ebb8:
|
||||
jump ebb9
|
||||
|
||||
ebb9:
|
||||
v70 = iconst.i32 0xffff_ffff_ffff_912f
|
||||
brz v70, ebb10
|
||||
jump ebb35
|
||||
|
||||
ebb10:
|
||||
v71 = iconst.i32 0
|
||||
brz v71, ebb11
|
||||
jump ebb27
|
||||
|
||||
ebb11:
|
||||
jump ebb12
|
||||
|
||||
ebb12:
|
||||
jump ebb13
|
||||
|
||||
ebb13:
|
||||
jump ebb14
|
||||
|
||||
ebb14:
|
||||
jump ebb15
|
||||
|
||||
ebb15:
|
||||
jump ebb16
|
||||
|
||||
ebb16:
|
||||
jump ebb17
|
||||
|
||||
ebb17:
|
||||
jump ebb18
|
||||
|
||||
ebb18:
|
||||
jump ebb19
|
||||
|
||||
ebb19:
|
||||
jump ebb20
|
||||
|
||||
ebb20:
|
||||
jump ebb21
|
||||
|
||||
ebb21:
|
||||
jump ebb22
|
||||
|
||||
ebb22:
|
||||
jump ebb23
|
||||
|
||||
ebb23:
|
||||
jump ebb24
|
||||
|
||||
ebb24:
|
||||
jump ebb25
|
||||
|
||||
ebb25:
|
||||
jump ebb26
|
||||
|
||||
ebb26:
|
||||
jump ebb27
|
||||
|
||||
ebb27:
|
||||
jump ebb28
|
||||
|
||||
ebb28:
|
||||
jump ebb29
|
||||
|
||||
ebb29:
|
||||
jump ebb30
|
||||
|
||||
ebb30:
|
||||
jump ebb31
|
||||
|
||||
ebb31:
|
||||
jump ebb32
|
||||
|
||||
ebb32:
|
||||
jump ebb33
|
||||
|
||||
ebb33:
|
||||
jump ebb34
|
||||
|
||||
ebb34:
|
||||
jump ebb35
|
||||
|
||||
ebb35:
|
||||
jump ebb36
|
||||
|
||||
ebb36:
|
||||
trap user0
|
||||
}
|
||||
220
cranelift/filetests/filetests/regalloc/spill.clif
Normal file
220
cranelift/filetests/filetests/regalloc/spill.clif
Normal file
@@ -0,0 +1,220 @@
|
||||
test regalloc
|
||||
|
||||
; Test the spiler on an ISA with few registers.
|
||||
; RV32E has 16 registers, where:
|
||||
; - %x0 is hardwired to zero.
|
||||
; - %x1 is the return address.
|
||||
; - %x2 is the stack pointer.
|
||||
; - %x3 is the global pointer.
|
||||
; - %x4 is the thread pointer.
|
||||
; - %x10-%x15 are function arguments.
|
||||
;
|
||||
; regex: V=v\d+
|
||||
; regex: WS=\s+
|
||||
|
||||
target riscv32 enable_e
|
||||
|
||||
; In straight-line code, the first value defined is spilled.
|
||||
; That is in order:
|
||||
; 1. The argument v1.
|
||||
; 2. The link register.
|
||||
; 3. The first computed value, v2
|
||||
function %pyramid(i32) -> i32 {
|
||||
; check: ss0 = spill_slot 4
|
||||
; check: ss1 = spill_slot 4
|
||||
; check: ss2 = spill_slot 4
|
||||
; not: spill_slot
|
||||
ebb0(v1: i32):
|
||||
; check: ebb0($(rv1=$V): i32 [%x10], $(rlink=$V): i32 [%x1])
|
||||
; check: ,ss0]$WS v1 = spill $rv1
|
||||
; nextln: ,ss1]$WS $(link=$V) = spill $rlink
|
||||
; not: spill
|
||||
v2 = iadd_imm v1, 12
|
||||
; check: $(r1v2=$V) = iadd_imm
|
||||
; nextln: ,ss2]$WS v2 = spill $r1v2
|
||||
; not: spill
|
||||
v3 = iadd_imm v2, 12
|
||||
v4 = iadd_imm v3, 12
|
||||
v5 = iadd_imm v4, 12
|
||||
v6 = iadd_imm v5, 12
|
||||
v7 = iadd_imm v6, 12
|
||||
v8 = iadd_imm v7, 12
|
||||
v9 = iadd_imm v8, 12
|
||||
v10 = iadd_imm v9, 12
|
||||
v11 = iadd_imm v10, 12
|
||||
v12 = iadd_imm v11, 12
|
||||
v13 = iadd_imm v12, 12
|
||||
v14 = iadd_imm v13, 12
|
||||
v33 = iadd v13, v14
|
||||
; check: iadd v13
|
||||
v32 = iadd v33, v12
|
||||
v31 = iadd v32, v11
|
||||
v30 = iadd v31, v10
|
||||
v29 = iadd v30, v9
|
||||
v28 = iadd v29, v8
|
||||
v27 = iadd v28, v7
|
||||
v26 = iadd v27, v6
|
||||
v25 = iadd v26, v5
|
||||
v24 = iadd v25, v4
|
||||
v23 = iadd v24, v3
|
||||
v22 = iadd v23, v2
|
||||
; check: $(r2v2=$V) = fill v2
|
||||
; check: v22 = iadd v23, $r2v2
|
||||
v21 = iadd v22, v1
|
||||
; check: $(r2v1=$V) = fill v1
|
||||
; check: v21 = iadd v22, $r2v1
|
||||
; check: $(rlink2=$V) = fill $link
|
||||
return v21
|
||||
; check: return v21, $rlink2
|
||||
}
|
||||
|
||||
; All values live across a call must be spilled
|
||||
function %across_call(i32) {
|
||||
fn0 = %foo(i32)
|
||||
ebb0(v1: i32):
|
||||
; check: v1 = spill
|
||||
call fn0(v1)
|
||||
; check: call fn0
|
||||
call fn0(v1)
|
||||
; check: fill v1
|
||||
; check: call fn0
|
||||
return
|
||||
}
|
||||
|
||||
; The same value used for two function arguments.
|
||||
function %doubleuse(i32) {
|
||||
fn0 = %xx(i32, i32)
|
||||
ebb0(v0: i32):
|
||||
; check: $(c=$V) = copy v0
|
||||
call fn0(v0, v0)
|
||||
; check: call fn0(v0, $c)
|
||||
return
|
||||
}
|
||||
|
||||
; The same value used as indirect callee and argument.
|
||||
function %doubleuse_icall1(i32) {
|
||||
sig0 = (i32) system_v
|
||||
ebb0(v0: i32):
|
||||
; not:copy
|
||||
call_indirect sig0, v0(v0)
|
||||
return
|
||||
}
|
||||
|
||||
; The same value used as indirect callee and two arguments.
|
||||
function %doubleuse_icall2(i32) {
|
||||
sig0 = (i32, i32) system_v
|
||||
ebb0(v0: i32):
|
||||
; check: $(c=$V) = copy v0
|
||||
call_indirect sig0, v0(v0, v0)
|
||||
; check: call_indirect sig0, v0(v0, $c)
|
||||
return
|
||||
}
|
||||
|
||||
; Two arguments on the stack.
|
||||
function %stackargs(i32, i32, i32, i32, i32, i32, i32, i32) -> i32 {
|
||||
; check: ss0 = incoming_arg 4
|
||||
; check: ss1 = incoming_arg 4, offset 4
|
||||
; not: incoming_arg
|
||||
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32):
|
||||
; unordered: fill v6
|
||||
; unordered: fill v7
|
||||
v10 = iadd v6, v7
|
||||
return v10
|
||||
}
|
||||
|
||||
; More EBB arguments than registers.
|
||||
function %ebbargs(i32) -> i32 {
|
||||
ebb0(v1: i32):
|
||||
; check: v1 = spill
|
||||
v2 = iconst.i32 1
|
||||
jump ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2)
|
||||
|
||||
ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32):
|
||||
v22 = iadd v10, v11
|
||||
v23 = iadd v22, v12
|
||||
v24 = iadd v23, v13
|
||||
v25 = iadd v24, v14
|
||||
v26 = iadd v25, v15
|
||||
v27 = iadd v26, v16
|
||||
v28 = iadd v27, v17
|
||||
v29 = iadd v28, v18
|
||||
v30 = iadd v29, v19
|
||||
v31 = iadd v30, v20
|
||||
v32 = iadd v31, v21
|
||||
v33 = iadd v32, v1
|
||||
return v33
|
||||
}
|
||||
|
||||
; Spilling an EBB argument to make room for a branch operand.
|
||||
function %brargs(i32) -> i32 {
|
||||
ebb0(v1: i32):
|
||||
; check: v1 = spill
|
||||
v2 = iconst.i32 1
|
||||
brnz v1, ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2)
|
||||
return v1
|
||||
|
||||
ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32):
|
||||
v22 = iadd v10, v11
|
||||
v23 = iadd v22, v12
|
||||
v24 = iadd v23, v13
|
||||
v25 = iadd v24, v14
|
||||
v26 = iadd v25, v15
|
||||
v27 = iadd v26, v16
|
||||
v28 = iadd v27, v17
|
||||
v29 = iadd v28, v18
|
||||
v30 = iadd v29, v19
|
||||
v31 = iadd v30, v20
|
||||
v32 = iadd v31, v21
|
||||
v33 = iadd v32, v1
|
||||
return v33
|
||||
}
|
||||
|
||||
; In straight-line code, the first value defined is spilled.
|
||||
; That is in order:
|
||||
; 1. The argument v1.
|
||||
; 2. The link register.
|
||||
; 3. The first computed value, v2
|
||||
function %use_spilled_value(i32) -> i32 {
|
||||
; check: ss0 = spill_slot 4
|
||||
; check: ss1 = spill_slot 4
|
||||
; check: ss2 = spill_slot 4
|
||||
ebb0(v1: i32):
|
||||
; check: ebb0($(rv1=$V): i32 [%x10], $(rlink=$V): i32 [%x1])
|
||||
; check: ,ss0]$WS v1 = spill $rv1
|
||||
; nextln: ,ss1]$WS $(link=$V) = spill $rlink
|
||||
; not: spill
|
||||
v2 = iadd_imm v1, 12
|
||||
; check: $(r1v2=$V) = iadd_imm
|
||||
; nextln: ,ss2]$WS v2 = spill $r1v2
|
||||
v3 = iadd_imm v2, 12
|
||||
v4 = iadd_imm v3, 12
|
||||
v5 = iadd_imm v4, 12
|
||||
v6 = iadd_imm v5, 12
|
||||
v7 = iadd_imm v6, 12
|
||||
v8 = iadd_imm v7, 12
|
||||
v9 = iadd_imm v8, 12
|
||||
v10 = iadd_imm v9, 12
|
||||
v11 = iadd_imm v10, 12
|
||||
v12 = iadd_imm v11, 12
|
||||
v13 = iadd_imm v12, 12
|
||||
v14 = iadd_imm v13, 12
|
||||
|
||||
; Here we have maximum register pressure, and v2 has been spilled.
|
||||
; What happens if we use it?
|
||||
v33 = iadd v2, v14
|
||||
v32 = iadd v33, v12
|
||||
v31 = iadd v32, v11
|
||||
v30 = iadd v31, v10
|
||||
v29 = iadd v30, v9
|
||||
v28 = iadd v29, v8
|
||||
v27 = iadd v28, v7
|
||||
v26 = iadd v27, v6
|
||||
v25 = iadd v26, v5
|
||||
v24 = iadd v25, v4
|
||||
v23 = iadd v24, v3
|
||||
v22 = iadd v23, v2
|
||||
v21 = iadd v22, v1
|
||||
v20 = iadd v21, v13
|
||||
v19 = iadd v20, v2
|
||||
return v21
|
||||
}
|
||||
47
cranelift/filetests/filetests/regalloc/unreachable_code.clif
Normal file
47
cranelift/filetests/filetests/regalloc/unreachable_code.clif
Normal file
@@ -0,0 +1,47 @@
|
||||
; Use "test compile" here otherwise the dead blocks won't be eliminated.
|
||||
test compile
|
||||
|
||||
set probestack_enabled=0
|
||||
target x86_64 haswell
|
||||
|
||||
; This function contains unreachable blocks which trip up the register
|
||||
; allocator if they don't get cleared out.
|
||||
function %unreachable_blocks(i64 vmctx) -> i32 baldrdash {
|
||||
ebb0(v0: i64):
|
||||
v1 = iconst.i32 0
|
||||
v2 = iconst.i32 0
|
||||
jump ebb2
|
||||
|
||||
ebb2:
|
||||
jump ebb4
|
||||
|
||||
ebb4:
|
||||
jump ebb2
|
||||
|
||||
; Everything below this point is unreachable.
|
||||
|
||||
ebb3(v3: i32):
|
||||
v5 = iadd.i32 v2, v3
|
||||
jump ebb6
|
||||
|
||||
ebb6:
|
||||
jump ebb6
|
||||
|
||||
ebb7(v6: i32):
|
||||
v7 = iadd.i32 v5, v6
|
||||
jump ebb8
|
||||
|
||||
ebb8:
|
||||
jump ebb10
|
||||
|
||||
ebb10:
|
||||
jump ebb8
|
||||
|
||||
ebb9(v8: i32):
|
||||
v10 = iadd.i32 v7, v8
|
||||
jump ebb1(v10)
|
||||
|
||||
ebb1(v11: i32):
|
||||
return v11
|
||||
}
|
||||
|
||||
46
cranelift/filetests/filetests/regalloc/x86-regres.clif
Normal file
46
cranelift/filetests/filetests/regalloc/x86-regres.clif
Normal file
@@ -0,0 +1,46 @@
|
||||
test regalloc
|
||||
|
||||
target i686
|
||||
|
||||
; regex: V=v\d+
|
||||
|
||||
; The value v9 appears both as the branch control and one of the EBB arguments
|
||||
; in the brnz instruction in ebb2. It also happens that v7 and v9 are assigned
|
||||
; to the same register, so v9 doesn't need to be moved before the brnz.
|
||||
;
|
||||
; This ended up confusong the constraint solver which had not made a record of
|
||||
; the fixed register assignment for v9 since it was already in the correct
|
||||
; register.
|
||||
function %pr147(i32) -> i32 system_v {
|
||||
ebb0(v0: i32):
|
||||
v1 = iconst.i32 0
|
||||
v2 = iconst.i32 1
|
||||
v3 = iconst.i32 0
|
||||
jump ebb2(v3, v2, v0)
|
||||
|
||||
ebb2(v4: i32, v5: i32, v7: i32):
|
||||
; check: ebb2
|
||||
v6 = iadd v4, v5
|
||||
v8 = iconst.i32 -1
|
||||
; v7 is killed here and v9 gets the same register.
|
||||
v9 = iadd v7, v8
|
||||
; check: v9 = iadd v7, v8
|
||||
; Here v9 the brnz control appears to interfere with v9 the EBB argument,
|
||||
; so divert_fixed_input_conflicts() calls add_var(v9), which is ok. The
|
||||
; add_var sanity checks got confused when no fixed assignment could be
|
||||
; found for v9.
|
||||
;
|
||||
; We should be able to handle this situation without making copies of v9.
|
||||
brnz v9, ebb2(v5, v6, v9)
|
||||
; check: brnz v9, ebb2($V, $V, v9)
|
||||
jump ebb3
|
||||
|
||||
ebb3:
|
||||
return v5
|
||||
}
|
||||
|
||||
function %select_i64(i64, i64, i32) -> i64 {
|
||||
ebb0(v0: i64, v1: i64, v2: i32):
|
||||
v3 = select v2, v0, v1
|
||||
return v3
|
||||
}
|
||||
Reference in New Issue
Block a user