Only emit DefAlloc edits when the "checker" feature is enabled.

This reduces instruction counts by ~2% when disabled.
This commit is contained in:
Amanieu d'Antras
2022-01-11 11:32:16 +00:00
parent d95a9d9399
commit 693fb6a975
5 changed files with 121 additions and 113 deletions

View File

@@ -25,4 +25,6 @@ overflow-checks = true
[features] [features]
default = [] default = []
fuzzing = ["arbitrary"] checker = []
fuzzing = ["arbitrary", "checker"]

View File

@@ -599,17 +599,11 @@ impl<'a, F: Function> Checker<'a, F> {
fn handle_edit(&mut self, block: Block, edit: &Edit) { fn handle_edit(&mut self, block: Block, edit: &Edit) {
log::trace!("checker: adding edit {:?}", edit); log::trace!("checker: adding edit {:?}", edit);
match edit { match edit {
&Edit::Move { from, to, to_vreg } => { &Edit::Move { from, to } => {
self.bb_insts self.bb_insts
.get_mut(&block) .get_mut(&block)
.unwrap() .unwrap()
.push(CheckerInst::Move { into: to, from }); .push(CheckerInst::Move { into: to, from });
if let Some(vreg) = to_vreg {
self.bb_insts
.get_mut(&block)
.unwrap()
.push(CheckerInst::DefAlloc { alloc: to, vreg });
}
} }
&Edit::DefAlloc { alloc, vreg } => { &Edit::DefAlloc { alloc, vreg } => {
self.bb_insts self.bb_insts

View File

@@ -472,12 +472,15 @@ impl<'a, F: Function> Env<'a, F> {
block = block.next(); block = block.next();
} }
#[cfg(feature = "checker")]
{
// If this is a blockparam vreg and the start of block // If this is a blockparam vreg and the start of block
// is in this range, add to blockparam_allocs. // is in this range, add to blockparam_allocs.
let (blockparam_block, blockparam_idx) = let (blockparam_block, blockparam_idx) =
self.cfginfo.vreg_def_blockparam[vreg.index()]; self.cfginfo.vreg_def_blockparam[vreg.index()];
if blockparam_block.is_valid() if blockparam_block.is_valid()
&& range.contains_point(self.cfginfo.block_entry[blockparam_block.index()]) && range
.contains_point(self.cfginfo.block_entry[blockparam_block.index()])
{ {
self.blockparam_allocs.push(( self.blockparam_allocs.push((
blockparam_block, blockparam_block,
@@ -487,6 +490,7 @@ impl<'a, F: Function> Env<'a, F> {
)); ));
} }
} }
}
// Scan over def/uses and apply allocations. // Scan over def/uses and apply allocations.
for use_idx in 0..self.ranges[entry.index.index()].uses.len() { for use_idx in 0..self.ranges[entry.index.index()].uses.len() {
@@ -930,6 +934,7 @@ impl<'a, F: Function> Env<'a, F> {
// regs, but this seems simpler.) // regs, but this seems simpler.)
let mut int_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; let mut int_moves: SmallVec<[InsertedMove; 8]> = smallvec![];
let mut float_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; let mut float_moves: SmallVec<[InsertedMove; 8]> = smallvec![];
#[cfg(feature = "checker")]
let mut self_moves: SmallVec<[InsertedMove; 8]> = smallvec![]; let mut self_moves: SmallVec<[InsertedMove; 8]> = smallvec![];
for m in moves { for m in moves {
@@ -937,6 +942,7 @@ impl<'a, F: Function> Env<'a, F> {
debug_assert_eq!(m.from_alloc.class(), m.to_alloc.class()); debug_assert_eq!(m.from_alloc.class(), m.to_alloc.class());
} }
if m.from_alloc == m.to_alloc { if m.from_alloc == m.to_alloc {
#[cfg(feature = "checker")]
if m.to_vreg.is_some() { if m.to_vreg.is_some() {
self_moves.push(m.clone()); self_moves.push(m.clone());
} }
@@ -1002,88 +1008,71 @@ impl<'a, F: Function> Env<'a, F> {
} }
if self.allocation_is_stack(src) && self.allocation_is_stack(dst) { if self.allocation_is_stack(src) && self.allocation_is_stack(dst) {
if !scratch_used_yet { if !scratch_used_yet {
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { src,
from: src, Allocation::reg(scratch),
to: Allocation::reg(scratch),
to_vreg, to_vreg,
},
); );
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { Allocation::reg(scratch),
from: Allocation::reg(scratch), dst,
to: dst,
to_vreg, to_vreg,
},
); );
} else { } else {
debug_assert!(extra_slot.is_some()); debug_assert!(extra_slot.is_some());
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { Allocation::reg(scratch),
from: Allocation::reg(scratch), extra_slot.unwrap(),
to: extra_slot.unwrap(), None,
to_vreg: None,
},
); );
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { src,
from: src, Allocation::reg(scratch),
to: Allocation::reg(scratch),
to_vreg, to_vreg,
},
); );
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { Allocation::reg(scratch),
from: Allocation::reg(scratch), dst,
to: dst,
to_vreg, to_vreg,
},
); );
self.add_edit( self.add_move_edit(
pos, pos,
prio, prio,
Edit::Move { extra_slot.unwrap(),
from: extra_slot.unwrap(), Allocation::reg(scratch),
to: Allocation::reg(scratch), None,
to_vreg: None,
},
); );
} }
} else { } else {
self.add_edit( self.add_move_edit(pos, prio, src, dst, to_vreg);
pos,
prio,
Edit::Move {
from: src,
to: dst,
to_vreg,
},
);
} }
} else { } else {
log::trace!(" -> redundant move elided"); log::trace!(" -> redundant move elided");
} }
#[cfg(feature = "checker")]
if let Some((alloc, vreg)) = action.def_alloc { if let Some((alloc, vreg)) = action.def_alloc {
log::trace!( log::trace!(
" -> converted to DefAlloc: alloc {} vreg {}", " -> converted to DefAlloc: alloc {} vreg {}",
alloc, alloc,
vreg vreg
); );
self.add_edit(pos, prio, Edit::DefAlloc { alloc, vreg }); self.edits
.push((pos.to_index(), prio, Edit::DefAlloc { alloc, vreg }));
} }
} }
} }
#[cfg(feature = "checker")]
for m in &self_moves { for m in &self_moves {
log::trace!( log::trace!(
"self move at pos {:?} prio {:?}: {} -> {} to_vreg {:?}", "self move at pos {:?} prio {:?}: {} -> {} to_vreg {:?}",
@@ -1097,11 +1086,14 @@ impl<'a, F: Function> Env<'a, F> {
debug_assert!(action.elide); debug_assert!(action.elide);
if let Some((alloc, vreg)) = action.def_alloc { if let Some((alloc, vreg)) = action.def_alloc {
log::trace!(" -> DefAlloc: alloc {} vreg {}", alloc, vreg); log::trace!(" -> DefAlloc: alloc {} vreg {}", alloc, vreg);
self.add_edit(pos, prio, Edit::DefAlloc { alloc, vreg }); self.edits
.push((pos.to_index(), prio, Edit::DefAlloc { alloc, vreg }));
} }
} }
} }
#[cfg(feature = "checker")]
{
// Add edits to describe blockparam locations too. This is // Add edits to describe blockparam locations too. This is
// required by the checker. This comes after any edge-moves. // required by the checker. This comes after any edge-moves.
self.blockparam_allocs self.blockparam_allocs
@@ -1126,11 +1118,12 @@ impl<'a, F: Function> Env<'a, F> {
debug_assert_eq!(vregs.len(), self.func.block_params(block).len()); debug_assert_eq!(vregs.len(), self.func.block_params(block).len());
debug_assert_eq!(allocs.len(), self.func.block_params(block).len()); debug_assert_eq!(allocs.len(), self.func.block_params(block).len());
for (vreg, alloc) in vregs.into_iter().zip(allocs.into_iter()) { for (vreg, alloc) in vregs.into_iter().zip(allocs.into_iter()) {
self.add_edit( self.edits.push((
self.cfginfo.block_entry[block.index()], self.cfginfo.block_entry[block.index()].to_index(),
InsertMovePrio::BlockParam, InsertMovePrio::BlockParam,
Edit::DefAlloc { alloc, vreg }, Edit::DefAlloc { alloc, vreg },
); ));
}
} }
} }
@@ -1147,10 +1140,10 @@ impl<'a, F: Function> Env<'a, F> {
for i in 0..self.edits.len() { for i in 0..self.edits.len() {
let &(pos, _, ref edit) = &self.edits[i]; let &(pos, _, ref edit) = &self.edits[i];
match edit { match edit {
&Edit::Move { from, to, to_vreg } => { &Edit::Move { from, to } => {
self.annotate( self.annotate(
ProgPoint::from_index(pos), ProgPoint::from_index(pos),
format!("move {} -> {} ({:?})", from, to, to_vreg), format!("move {} -> {})", from, to),
); );
} }
&Edit::DefAlloc { alloc, vreg } => { &Edit::DefAlloc { alloc, vreg } => {
@@ -1162,15 +1155,32 @@ impl<'a, F: Function> Env<'a, F> {
} }
} }
pub fn add_edit(&mut self, pos: ProgPoint, prio: InsertMovePrio, edit: Edit) { pub fn add_move_edit(
match &edit { &mut self,
&Edit::Move { from, to, to_vreg } if from == to && to_vreg.is_none() => return, pos: ProgPoint,
&Edit::Move { from, to, .. } if from.is_reg() && to.is_reg() => { prio: InsertMovePrio,
from: Allocation,
to: Allocation,
_to_vreg: Option<VReg>,
) {
if from != to {
if from.is_reg() && to.is_reg() {
debug_assert_eq!(from.as_reg().unwrap().class(), to.as_reg().unwrap().class()); debug_assert_eq!(from.as_reg().unwrap().class(), to.as_reg().unwrap().class());
} }
_ => {} self.edits
.push((pos.to_index(), prio, Edit::Move { from, to }));
} }
self.edits.push((pos.to_index(), prio, edit)); #[cfg(feature = "checker")]
if let Some(to_vreg) = _to_vreg {
self.edits.push((
pos.to_index(),
prio,
Edit::DefAlloc {
alloc: to,
vreg: to_vreg,
},
));
}
} }
} }

View File

@@ -18,6 +18,7 @@ pub struct RedundantMoveEliminator {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct RedundantMoveAction { pub struct RedundantMoveAction {
pub elide: bool, pub elide: bool,
#[cfg(feature = "checker")]
pub def_alloc: Option<(Allocation, VReg)>, pub def_alloc: Option<(Allocation, VReg)>,
} }
@@ -58,6 +59,7 @@ impl RedundantMoveEliminator {
.insert(to, RedundantMoveState::Orig(to_vreg.unwrap())); .insert(to, RedundantMoveState::Orig(to_vreg.unwrap()));
return RedundantMoveAction { return RedundantMoveAction {
elide: true, elide: true,
#[cfg(feature = "checker")]
def_alloc: Some((to, to_vreg.unwrap())), def_alloc: Some((to, to_vreg.unwrap())),
}; };
} }
@@ -111,7 +113,11 @@ impl RedundantMoveEliminator {
.push(to); .push(to);
} }
RedundantMoveAction { elide, def_alloc } RedundantMoveAction {
elide,
#[cfg(feature = "checker")]
def_alloc,
}
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {

View File

@@ -1105,20 +1105,16 @@ pub enum Edit {
/// register or a stack slot (spillslot). However, stack-to-stack /// register or a stack slot (spillslot). However, stack-to-stack
/// moves will never be generated. /// moves will never be generated.
/// ///
/// `to_vreg`, if defined, is useful as metadata: it indicates
/// that the moved value is a def of a new vreg.
///
/// `Move` edits will be generated even if src and dst allocation /// `Move` edits will be generated even if src and dst allocation
/// are the same if the vreg changes; this allows proper metadata /// are the same if the vreg changes; this allows proper metadata
/// tracking even when moves are elided. /// tracking even when moves are elided.
Move { Move { from: Allocation, to: Allocation },
from: Allocation,
to: Allocation,
to_vreg: Option<VReg>,
},
/// Define a particular Allocation to contain a particular VReg. Useful /// Define a particular Allocation to contain a particular VReg. Useful
/// for the checker. /// for the checker.
///
/// `DefAlloc` edits are only emitted when the `"checker"` Cargo feature is
/// enabled.
DefAlloc { alloc: Allocation, vreg: VReg }, DefAlloc { alloc: Allocation, vreg: VReg },
} }