Refactor collect_branches_and_targets to not need a smallvec (#5803)

* Refactor collect_branches_and_targets to not need a smallvec

Basic blocks are terminated by at most one branch instruction now, so we
can use that assumption in `collect_branches_and_targets` to return the
last instruction we saw instead.

* Review comments
This commit is contained in:
Trevor Elliott
2023-02-16 13:30:17 -08:00
committed by GitHub
parent c7e2571866
commit d711872d63

View File

@@ -10,8 +10,8 @@ use crate::fx::{FxHashMap, FxHashSet};
use crate::inst_predicates::{has_lowering_side_effect, is_constant_64bit}; use crate::inst_predicates::{has_lowering_side_effect, is_constant_64bit};
use crate::ir::{ use crate::ir::{
ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, ExternalName, Function, ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, ExternalName, Function,
GlobalValue, GlobalValueData, Immediate, Inst, InstructionData, MemFlags, Opcode, RelSourceLoc, GlobalValue, GlobalValueData, Immediate, Inst, InstructionData, MemFlags, RelSourceLoc, Type,
Type, Value, ValueDef, ValueLabelAssignments, ValueLabelStart, Value, ValueDef, ValueLabelAssignments, ValueLabelStart,
}; };
use crate::machinst::{ use crate::machinst::{
writable_value_regs, BlockIndex, BlockLoweringOrder, Callee, LoweredBlock, MachLabel, Reg, writable_value_regs, BlockIndex, BlockLoweringOrder, Callee, LoweredBlock, MachLabel, Reg,
@@ -898,39 +898,29 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
bindex: BlockIndex, bindex: BlockIndex,
// Original CLIF block: // Original CLIF block:
block: Block, block: Block,
branches: &SmallVec<[Inst; 2]>, branch: Inst,
targets: &SmallVec<[MachLabel; 2]>, targets: &[MachLabel],
) -> CodegenResult<()> { ) -> CodegenResult<()> {
trace!( trace!(
"lower_clif_branches: block {} branches {:?} targets {:?}", "lower_clif_branches: block {} branch {:?} targets {:?}",
block, block,
branches, branch,
targets, targets,
); );
// A block should end with at most two branches. The first may be a
// conditional branch; a conditional branch can be followed only by an
// unconditional branch or fallthrough. Otherwise, if only one branch,
// it may be an unconditional branch, a fallthrough, a return, or a
// trap. These conditions are verified by `is_block_basic()` during the
// verifier pass.
assert!(branches.len() <= 2);
if branches.len() == 2 {
assert!(self.data(branches[1]).opcode() == Opcode::Jump);
}
// When considering code-motion opportunities, consider the current // When considering code-motion opportunities, consider the current
// program point to be the first branch. // program point to be this branch.
self.cur_inst = Some(branches[0]); self.cur_inst = Some(branch);
// Lower the first branch in ISLE. This will automatically handle
// the second branch (if any) by emitting a two-way conditional branch. // Lower the branch in ISLE.
backend backend
.lower_branch(self, branches[0], targets) .lower_branch(self, branch, targets)
.unwrap_or_else(|| { .unwrap_or_else(|| {
panic!( panic!(
"should be implemented in ISLE: branch = `{}`", "should be implemented in ISLE: branch = `{}`",
self.f.dfg.display_inst(branches[0]), self.f.dfg.display_inst(branch),
) )
}); });
let loc = self.srcloc(branches[0]); let loc = self.srcloc(branch);
self.finish_ir_inst(loc); self.finish_ir_inst(loc);
// Add block param outputs for current block. // Add block param outputs for current block.
self.lower_branch_blockparam_args(bindex); self.lower_branch_blockparam_args(bindex);
@@ -967,26 +957,20 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
&self, &self,
bindex: BlockIndex, bindex: BlockIndex,
_bb: Block, _bb: Block,
branches: &mut SmallVec<[Inst; 2]>,
targets: &mut SmallVec<[MachLabel; 2]>, targets: &mut SmallVec<[MachLabel; 2]>,
) { ) -> Option<Inst> {
branches.clear();
targets.clear(); targets.clear();
let mut last_inst = None; let mut last_inst = None;
for &(inst, succ) in self.vcode.block_order().succ_indices(bindex) { for &(inst, succ) in self.vcode.block_order().succ_indices(bindex) {
// Avoid duplicates: this ensures a br_table is only inserted once. // Basic blocks may end in a single branch instruction, but those instructions may have
if last_inst != Some(inst) { // multiple destinations. As such, all `inst` values in `succ_indices` must be the
branches.push(inst); // same, or this basic block would have multiple branch instructions present.
} else { debug_assert!(last_inst.map_or(true, |prev| prev == inst));
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); last_inst = Some(inst);
targets.push(MachLabel::from_block(succ)); targets.push(MachLabel::from_block(succ));
} }
last_inst
} }
/// Lower the function. /// Lower the function.
@@ -1010,7 +994,6 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
self.vcode.set_entry(BlockIndex::new(0)); self.vcode.set_entry(BlockIndex::new(0));
// Reused vectors for branch lowering. // Reused vectors for branch lowering.
let mut branches: SmallVec<[Inst; 2]> = SmallVec::new();
let mut targets: SmallVec<[MachLabel; 2]> = SmallVec::new(); let mut targets: SmallVec<[MachLabel; 2]> = SmallVec::new();
// get a copy of the lowered order; we hold this separately because we // get a copy of the lowered order; we hold this separately because we
@@ -1032,10 +1015,9 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
// End branches. // End branches.
if let Some(bb) = lb.orig_block() { if let Some(bb) = lb.orig_block() {
self.collect_branches_and_targets(bindex, bb, &mut branches, &mut targets); if let Some(branch) = self.collect_branches_and_targets(bindex, bb, &mut targets) {
if branches.len() > 0 { self.lower_clif_branches(backend, bindex, bb, branch, &targets)?;
self.lower_clif_branches(backend, bindex, bb, &branches, &targets)?; self.finish_ir_inst(self.srcloc(branch));
self.finish_ir_inst(self.srcloc(branches[0]));
} }
} else { } else {
// If no orig block, this must be a pure edge block; // If no orig block, this must be a pure edge block;