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:
@@ -1,4 +1,4 @@
|
||||
use crate::ir::{Value, ValueList};
|
||||
use crate::ir::{BlockCall, Value, ValueList};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use smallvec::SmallVec;
|
||||
@@ -22,6 +22,7 @@ pub type Unit = ();
|
||||
pub type ValueSlice = (ValueList, usize);
|
||||
pub type ValueArray2 = [Value; 2];
|
||||
pub type ValueArray3 = [Value; 3];
|
||||
pub type BlockArray2 = [BlockCall; 2];
|
||||
pub type WritableReg = Writable<Reg>;
|
||||
pub type VecRetPair = Vec<RetPair>;
|
||||
pub type VecMask = Vec<u8>;
|
||||
|
||||
@@ -9,9 +9,9 @@ use crate::entity::SecondaryMap;
|
||||
use crate::fx::{FxHashMap, FxHashSet};
|
||||
use crate::inst_predicates::{has_lowering_side_effect, is_constant_64bit};
|
||||
use crate::ir::{
|
||||
ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, ExternalName, Function,
|
||||
GlobalValue, GlobalValueData, Immediate, Inst, InstructionData, MemFlags, Opcode, RelSourceLoc,
|
||||
Type, Value, ValueDef, ValueLabelAssignments, ValueLabelStart,
|
||||
instructions, ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, ExternalName,
|
||||
Function, GlobalValue, GlobalValueData, Immediate, Inst, InstructionData, MemFlags, Opcode,
|
||||
RelSourceLoc, Type, Value, ValueDef, ValueLabelAssignments, ValueLabelStart,
|
||||
};
|
||||
use crate::machinst::{
|
||||
writable_value_regs, BlockIndex, BlockLoweringOrder, Callee, LoweredBlock, MachLabel, Reg,
|
||||
@@ -941,12 +941,28 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
||||
for succ_idx in 0..self.vcode.block_order().succ_indices(block).len() {
|
||||
// Avoid immutable borrow by explicitly indexing.
|
||||
let (inst, succ) = self.vcode.block_order().succ_indices(block)[succ_idx];
|
||||
// Get branch args and convert to Regs.
|
||||
let branch_args = self.f.dfg.insts[inst]
|
||||
.branch_destination()
|
||||
.into_iter()
|
||||
.flat_map(|block| block.args_slice(&self.f.dfg.value_lists));
|
||||
|
||||
// Get branch args and convert to Regs.
|
||||
let branch_args = match self.f.dfg.analyze_branch(inst) {
|
||||
instructions::BranchInfo::NotABranch => unreachable!(),
|
||||
instructions::BranchInfo::SingleDest(block) => {
|
||||
block.args_slice(&self.f.dfg.value_lists)
|
||||
}
|
||||
instructions::BranchInfo::Conditional(then_block, else_block) => {
|
||||
// NOTE: `succ_idx == 0` implying that we're traversing the `then_block` is
|
||||
// enforced by the traversal order defined in `visit_block_succs`. Eventually
|
||||
// we should traverse the `branch_destination` slice instead of the result of
|
||||
// analyze_branch there, which would simplify computing the branch args
|
||||
// significantly.
|
||||
if succ_idx == 0 {
|
||||
then_block.args_slice(&self.f.dfg.value_lists)
|
||||
} else {
|
||||
assert!(succ_idx == 1);
|
||||
else_block.args_slice(&self.f.dfg.value_lists)
|
||||
}
|
||||
}
|
||||
instructions::BranchInfo::Table(_, _) => &[],
|
||||
};
|
||||
let mut branch_arg_vregs: SmallVec<[Reg; 16]> = smallvec![];
|
||||
for &arg in branch_args {
|
||||
let arg = self.f.dfg.resolve_aliases(arg);
|
||||
@@ -976,7 +992,10 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
||||
if last_inst != Some(inst) {
|
||||
branches.push(inst);
|
||||
} else {
|
||||
debug_assert!(self.f.dfg.insts[inst].opcode() == Opcode::BrTable);
|
||||
debug_assert!(
|
||||
self.f.dfg.insts[inst].opcode() == Opcode::BrTable
|
||||
|| self.f.dfg.insts[inst].opcode() == Opcode::Brif
|
||||
);
|
||||
debug_assert!(branches.len() == 1);
|
||||
}
|
||||
last_inst = Some(inst);
|
||||
|
||||
Reference in New Issue
Block a user