cranelift: Add a conditional branch instruction with two targets (#5446)

Add a conditional branch instruction with two targets: brif. This instruction will eventually replace brz and brnz, as it encompasses the behavior of both.

This PR also changes the InstructionData layout for instruction formats that hold BlockCall values, taking the same approach we use for Value arguments. This allows branch_destination to return a slice to the BlockCall values held in the instruction, rather than requiring that we pattern match on InstructionData to fetch the then/else blocks.

Function generation for fuzzing has been updated to generate uses of brif, and I've run the cranelift-fuzzgen target locally for hours without triggering any new failures.
This commit is contained in:
Trevor Elliott
2023-01-24 14:37:16 -08:00
committed by GitHub
parent ec6922ff24
commit b58a197d33
35 changed files with 943 additions and 159 deletions

View File

@@ -0,0 +1,195 @@
test interpret
test run
target aarch64
target s390x
target x86_64
target riscv64
function %brif_value(i8) -> i64 {
block0(v0: i8):
brif v0, block1, block2
block1:
v1 = uextend.i64 v0
return v1
block2:
v2 = iconst.i64 42
return v2
}
; run: %brif_value(0) == 42
; run: %brif_value(42) == 42
; run: %brif_value(97) == 97
function %brif_ne_zero(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 0
v2 = icmp ne v0, v1
brif v2, block1, block2
block1:
v3 = uextend.i64 v0
return v3
block2:
v4 = iconst.i64 42
return v4
}
; run: %brif_ne_zero(0) == 42
; run: %brif_ne_zero(42) == 42
; run: %brif_ne_zero(97) == 97
function %brif_ne_one(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 1
v2 = icmp ne v0, v1
brif v2, block1, block2
block1:
v3 = uextend.i64 v0
return v3
block2:
v4 = iconst.i64 42
return v4
}
; run: %brif_ne_one(1) == 42
; run: %brif_ne_one(0) == 0
; run: %brif_ne_one(42) == 42
; run: %brif_ne_one(97) == 97
function %brif_uextend_ne_one(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 1
v2 = icmp ne v0, v1
v3 = uextend.i64 v2
brif v3, block1, block2
block1:
v4 = uextend.i64 v0
return v4
block2:
v5 = iconst.i64 42
return v5
}
; run: %brif_uextend_ne_one(1) == 42
; run: %brif_uextend_ne_one(0) == 0
; run: %brif_uextend_ne_one(42) == 42
; run: %brif_uextend_ne_one(97) == 97
function %brif_i64(i64) -> i8 {
block0(v0: i64):
brif v0, block1, block2
block1:
v1 = iconst.i8 1
return v1
block2:
v2 = iconst.i8 0
return v2
}
; run: %brif_i64(0) == 0
; run: %brif_i64(1) == 1
; run: %brif_i64(-1) == 1
function %brif_i32(i32) -> i8 {
block0(v0: i32):
brif v0, block1, block2
block1:
v1 = iconst.i8 1
return v1
block2:
v2 = iconst.i8 0
return v2
}
; run: %brif_i32(0) == 0
; run: %brif_i32(1) == 1
; run: %brif_i32(-1) == 1
function %brif_i16(i16) -> i8 {
block0(v0: i16):
brif v0, block1, block2
block1:
v1 = iconst.i8 1
return v1
block2:
v2 = iconst.i8 0
return v2
}
; run: %brif_i16(0) == 0
; run: %brif_i16(1) == 1
; run: %brif_i16(-1) == 1
function %brif_i8(i8) -> i8 {
block0(v0: i8):
brif v0, block1, block2
block1:
v1 = iconst.i8 1
return v1
block2:
v2 = iconst.i8 0
return v2
}
; run: %brif_i8(0) == 0
; run: %brif_i8(1) == 1
; run: %brif_i8(-1) == 1
; run: %brif_i8(97) == 1
function %brif_different_args(i8) -> i8 {
block0(v0: i8):
brif v0, block1(v0, v0), block2(v0)
block1(v1: i8, v2: i8):
v3 = iadd v1, v2
return v3
block2(v4: i8):
return v4
}
; run: %brif_different_args(0) == 0
; run: %brif_different_args(1) == 2
; run: %brif_different_args(8) == 16
; run: %brif_different_args(128) == 0
function %fuzzgen_1() -> i8 system_v {
block0:
v1 = iconst.i8 35
brif v1, block1(v1), block1(v1) ; v1 = 35
block1(v0: i8):
return v0
}
; run: %fuzzgen_1() == 35
function %fuzzgen_2(i16) -> i16, i16 system_v {
block0(v0: i16):
brnz v0, block1(v0, v0)
jump block2(v0, v0)
block1(v1: i16, v2: i16):
brif v1, block2(v2, v2), block2(v2, v2)
block2(v3: i16, v4: i16):
return v3, v4
}
; run: %fuzzgen_2(0) == [0, 0]
function %fuzzgen_3(i8 sext) -> i8 system_v {
block0(v0: i8):
v1 = iconst.i8 -9
brif v0, block1(v1), block1(v0)
block1(v2: i8):
return v2
}
; run: %fuzzgen_3(-65) == -9
; run: %fuzzgen_3(0) == 0