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:
@@ -19,6 +19,14 @@ pub(crate) struct EntityRefs {
|
||||
/// This is primarily used in control flow instructions.
|
||||
pub(crate) label: OperandKind,
|
||||
|
||||
/// A reference to a basic block in the same function, with its arguments provided.
|
||||
/// This is primarily used in control flow instructions.
|
||||
pub(crate) block_then: OperandKind,
|
||||
|
||||
/// A reference to a basic block in the same function, with its arguments provided.
|
||||
/// This is primarily used in control flow instructions.
|
||||
pub(crate) block_else: OperandKind,
|
||||
|
||||
/// A reference to a stack slot declared in the function preamble.
|
||||
pub(crate) stack_slot: OperandKind,
|
||||
|
||||
@@ -61,6 +69,18 @@ impl EntityRefs {
|
||||
"a basic block in the same function.",
|
||||
),
|
||||
|
||||
block_then: new(
|
||||
"block_then",
|
||||
"ir::BlockCall",
|
||||
"a basic block in the same function, with its arguments provided.",
|
||||
),
|
||||
|
||||
block_else: new(
|
||||
"block_else",
|
||||
"ir::BlockCall",
|
||||
"a basic block in the same function, with its arguments provided.",
|
||||
),
|
||||
|
||||
stack_slot: new("stack_slot", "ir::StackSlot", "A stack slot"),
|
||||
|
||||
dynamic_stack_slot: new(
|
||||
|
||||
@@ -8,6 +8,7 @@ pub(crate) struct Formats {
|
||||
pub(crate) binary: Rc<InstructionFormat>,
|
||||
pub(crate) binary_imm8: Rc<InstructionFormat>,
|
||||
pub(crate) binary_imm64: Rc<InstructionFormat>,
|
||||
pub(crate) brif: Rc<InstructionFormat>,
|
||||
pub(crate) branch: Rc<InstructionFormat>,
|
||||
pub(crate) branch_table: Rc<InstructionFormat>,
|
||||
pub(crate) call: Rc<InstructionFormat>,
|
||||
@@ -111,12 +112,11 @@ impl Formats {
|
||||
.value()
|
||||
.build(),
|
||||
|
||||
jump: Builder::new("Jump").imm(&entities.block_call).build(),
|
||||
jump: Builder::new("Jump").block().build(),
|
||||
|
||||
branch: Builder::new("Branch")
|
||||
.value()
|
||||
.imm(&entities.block_call)
|
||||
.build(),
|
||||
branch: Builder::new("Branch").value().block().build(),
|
||||
|
||||
brif: Builder::new("Brif").value().block().block().build(),
|
||||
|
||||
branch_table: Builder::new("BranchTable")
|
||||
.value()
|
||||
|
||||
@@ -44,6 +44,27 @@ fn define_control_flow(
|
||||
TypeSetBuilder::new().ints(Interval::All).build(),
|
||||
);
|
||||
|
||||
{
|
||||
let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
|
||||
let block_then = &Operand::new("block_then", &entities.block_then).with_doc("Then block");
|
||||
let block_else = &Operand::new("block_else", &entities.block_else).with_doc("Else block");
|
||||
|
||||
ig.push(
|
||||
Inst::new(
|
||||
"brif",
|
||||
r#"
|
||||
Conditional branch when cond is non-zero.
|
||||
|
||||
Take the ``then`` branch when ``c != 0``, and the ``else`` branch otherwise.
|
||||
"#,
|
||||
&formats.brif,
|
||||
)
|
||||
.operands_in(vec![c, block_then, block_else])
|
||||
.is_terminator(true)
|
||||
.is_branch(true),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user