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:
lazypassion
2019-01-28 18:56:54 -05:00
committed by Dan Gohman
parent 54959cf5bb
commit 747ad3c4c5
508 changed files with 94 additions and 92 deletions

View 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
}

View 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
}

View 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
}

File diff suppressed because it is too large Load Diff

View 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
}

View 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
}

View 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
}

View File

@@ -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

View 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
}

View File

@@ -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
}

View 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
}

View File

@@ -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
}

View File

@@ -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)
}

View 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
}

View File

@@ -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
}

View 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

View File

@@ -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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}