Only emit DefAlloc edits when the "checker" feature is enabled.
This reduces instruction counts by ~2% when disabled.
This commit is contained in:
@@ -25,4 +25,6 @@ overflow-checks = true
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
fuzzing = ["arbitrary"]
|
checker = []
|
||||||
|
fuzzing = ["arbitrary", "checker"]
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
202
src/ion/moves.rs
202
src/ion/moves.rs
@@ -472,19 +472,23 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a blockparam vreg and the start of block
|
#[cfg(feature = "checker")]
|
||||||
// is in this range, add to blockparam_allocs.
|
|
||||||
let (blockparam_block, blockparam_idx) =
|
|
||||||
self.cfginfo.vreg_def_blockparam[vreg.index()];
|
|
||||||
if blockparam_block.is_valid()
|
|
||||||
&& range.contains_point(self.cfginfo.block_entry[blockparam_block.index()])
|
|
||||||
{
|
{
|
||||||
self.blockparam_allocs.push((
|
// If this is a blockparam vreg and the start of block
|
||||||
blockparam_block,
|
// is in this range, add to blockparam_allocs.
|
||||||
blockparam_idx,
|
let (blockparam_block, blockparam_idx) =
|
||||||
vreg,
|
self.cfginfo.vreg_def_blockparam[vreg.index()];
|
||||||
alloc,
|
if blockparam_block.is_valid()
|
||||||
));
|
&& range
|
||||||
|
.contains_point(self.cfginfo.block_entry[blockparam_block.index()])
|
||||||
|
{
|
||||||
|
self.blockparam_allocs.push((
|
||||||
|
blockparam_block,
|
||||||
|
blockparam_idx,
|
||||||
|
vreg,
|
||||||
|
alloc,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,40 +1086,44 @@ 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 }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add edits to describe blockparam locations too. This is
|
#[cfg(feature = "checker")]
|
||||||
// required by the checker. This comes after any edge-moves.
|
{
|
||||||
self.blockparam_allocs
|
// Add edits to describe blockparam locations too. This is
|
||||||
.sort_unstable_by_key(|&(block, idx, _, _)| u64_key(block.raw_u32(), idx));
|
// required by the checker. This comes after any edge-moves.
|
||||||
self.stats.blockparam_allocs_count = self.blockparam_allocs.len();
|
self.blockparam_allocs
|
||||||
let mut i = 0;
|
.sort_unstable_by_key(|&(block, idx, _, _)| u64_key(block.raw_u32(), idx));
|
||||||
while i < self.blockparam_allocs.len() {
|
self.stats.blockparam_allocs_count = self.blockparam_allocs.len();
|
||||||
let start = i;
|
let mut i = 0;
|
||||||
let block = self.blockparam_allocs[i].0;
|
while i < self.blockparam_allocs.len() {
|
||||||
while i < self.blockparam_allocs.len() && self.blockparam_allocs[i].0 == block {
|
let start = i;
|
||||||
i += 1;
|
let block = self.blockparam_allocs[i].0;
|
||||||
}
|
while i < self.blockparam_allocs.len() && self.blockparam_allocs[i].0 == block {
|
||||||
let params = &self.blockparam_allocs[start..i];
|
i += 1;
|
||||||
let vregs = params
|
}
|
||||||
.iter()
|
let params = &self.blockparam_allocs[start..i];
|
||||||
.map(|(_, _, vreg_idx, _)| self.vreg_regs[vreg_idx.index()])
|
let vregs = params
|
||||||
.collect::<Vec<_>>();
|
.iter()
|
||||||
let allocs = params
|
.map(|(_, _, vreg_idx, _)| self.vreg_regs[vreg_idx.index()])
|
||||||
.iter()
|
.collect::<Vec<_>>();
|
||||||
.map(|(_, _, _, alloc)| *alloc)
|
let allocs = params
|
||||||
.collect::<Vec<_>>();
|
.iter()
|
||||||
debug_assert_eq!(vregs.len(), self.func.block_params(block).len());
|
.map(|(_, _, _, alloc)| *alloc)
|
||||||
debug_assert_eq!(allocs.len(), self.func.block_params(block).len());
|
.collect::<Vec<_>>();
|
||||||
for (vreg, alloc) in vregs.into_iter().zip(allocs.into_iter()) {
|
debug_assert_eq!(vregs.len(), self.func.block_params(block).len());
|
||||||
self.add_edit(
|
debug_assert_eq!(allocs.len(), self.func.block_params(block).len());
|
||||||
self.cfginfo.block_entry[block.index()],
|
for (vreg, alloc) in vregs.into_iter().zip(allocs.into_iter()) {
|
||||||
InsertMovePrio::BlockParam,
|
self.edits.push((
|
||||||
Edit::DefAlloc { alloc, vreg },
|
self.cfginfo.block_entry[block.index()].to_index(),
|
||||||
);
|
InsertMovePrio::BlockParam,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -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 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user