diff --git a/Cargo.toml b/Cargo.toml index 5410cf1..ab66451 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,11 @@ slice-group-by = "0.3.0" # Keep this in sync with libfuzzer_sys's crate version: arbitrary = { version = "^0.4.6", optional = true } +# When testing regalloc2 by itself, enable debug assertions and overflow checks [profile.release] debug = true +debug-assertions = true +overflow-checks = true [features] default = [] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 199eb9d..af37b2e 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -49,3 +49,9 @@ name = "ion_checker" path = "fuzz_targets/ion_checker.rs" test = false doc = false + +# Enable debug assertions and overflow checks when fuzzing +[profile.release] +debug = true +debug-assertions = true +overflow-checks = true \ No newline at end of file diff --git a/src/checker.rs b/src/checker.rs index 9e81e27..081a64c 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -550,7 +550,7 @@ impl<'a, F: Function> Checker<'a, F> { for inst_or_edit in out.block_insts_and_edits(self.f, block) { match inst_or_edit { InstOrEdit::Inst(inst) => { - assert!(last_inst.is_none() || inst > last_inst.unwrap()); + debug_assert!(last_inst.is_none() || inst > last_inst.unwrap()); last_inst = Some(inst); self.handle_inst(block, inst, &mut safepoint_slots, out); } diff --git a/src/domtree.rs b/src/domtree.rs index 4300e04..1bf4139 100644 --- a/src/domtree.rs +++ b/src/domtree.rs @@ -33,7 +33,7 @@ fn merge_sets( node2 = idom[node2.index()]; } } - assert!(node1 == node2); + debug_assert!(node1 == node2); node1 } diff --git a/src/fuzzing/func.rs b/src/fuzzing/func.rs index cbc9717..89445b4 100644 --- a/src/fuzzing/func.rs +++ b/src/fuzzing/func.rs @@ -79,7 +79,7 @@ impl Function for Func { } fn entry_block(&self) -> Block { - assert!(self.blocks.len() > 0); + debug_assert!(self.blocks.len() > 0); Block::new(0) } @@ -237,7 +237,7 @@ fn choose_dominating_block( allow_self: bool, u: &mut Unstructured, ) -> ArbitraryResult { - assert!(block.is_valid()); + debug_assert!(block.is_valid()); let orig_block = block; loop { if (allow_self || block != orig_block) && bool::arbitrary(u)? { @@ -445,7 +445,7 @@ impl Func { if operands.len() > 1 && opts.reused_inputs && bool::arbitrary(u)? { // Make the def a reused input. let op = operands[0]; - assert_eq!(op.kind(), OperandKind::Def); + debug_assert_eq!(op.kind(), OperandKind::Def); let reused = u.int_in_range(1..=(operands.len() - 1))?; operands[0] = Operand::new( op.vreg(), diff --git a/src/index.rs b/src/index.rs index 21dd976..4c376fa 100644 --- a/src/index.rs +++ b/src/index.rs @@ -10,7 +10,7 @@ macro_rules! define_index { } #[inline(always)] pub fn index(self) -> usize { - assert!(self.is_valid()); + debug_assert!(self.is_valid()); self.0 as usize } #[inline(always)] @@ -27,12 +27,12 @@ macro_rules! define_index { } #[inline(always)] pub fn next(self) -> $ix { - assert!(self.is_valid()); + debug_assert!(self.is_valid()); Self(self.0 + 1) } #[inline(always)] pub fn prev(self) -> $ix { - assert!(self.is_valid()); + debug_assert!(self.is_valid()); Self(self.0 - 1) } @@ -62,19 +62,19 @@ pub struct InstRange(Inst, Inst, bool); impl InstRange { #[inline(always)] pub fn forward(from: Inst, to: Inst) -> Self { - assert!(from.index() <= to.index()); + debug_assert!(from.index() <= to.index()); InstRange(from, to, true) } #[inline(always)] pub fn backward(from: Inst, to: Inst) -> Self { - assert!(from.index() >= to.index()); + debug_assert!(from.index() >= to.index()); InstRange(to, from, false) } #[inline(always)] pub fn first(self) -> Inst { - assert!(self.len() > 0); + debug_assert!(self.len() > 0); if self.is_forward() { self.0 } else { @@ -84,7 +84,7 @@ impl InstRange { #[inline(always)] pub fn last(self) -> Inst { - assert!(self.len() > 0); + debug_assert!(self.len() > 0); if self.is_forward() { self.1.prev() } else { @@ -94,7 +94,7 @@ impl InstRange { #[inline(always)] pub fn rest(self) -> InstRange { - assert!(self.len() > 0); + debug_assert!(self.len() > 0); if self.is_forward() { InstRange::forward(self.0.next(), self.1) } else { @@ -147,13 +147,13 @@ mod test { #[test] fn test_inst_range() { let range = InstRange::forward(Inst::new(0), Inst::new(0)); - assert_eq!(range.len(), 0); + debug_assert_eq!(range.len(), 0); let range = InstRange::forward(Inst::new(0), Inst::new(5)); - assert_eq!(range.first().index(), 0); - assert_eq!(range.last().index(), 4); - assert_eq!(range.len(), 5); - assert_eq!( + debug_assert_eq!(range.first().index(), 0); + debug_assert_eq!(range.last().index(), 4); + debug_assert_eq!(range.len(), 5); + debug_assert_eq!( range.iter().collect::>(), vec![ Inst::new(0), @@ -164,10 +164,10 @@ mod test { ] ); let range = range.rev(); - assert_eq!(range.first().index(), 4); - assert_eq!(range.last().index(), 0); - assert_eq!(range.len(), 5); - assert_eq!( + debug_assert_eq!(range.first().index(), 4); + debug_assert_eq!(range.last().index(), 0); + debug_assert_eq!(range.len(), 5); + debug_assert_eq!( range.iter().collect::>(), vec![ Inst::new(4), diff --git a/src/indexset.rs b/src/indexset.rs index 35d90dd..a5c263a 100644 --- a/src/indexset.rs +++ b/src/indexset.rs @@ -93,7 +93,7 @@ impl AdaptiveMap { }; if needs_expand { - assert!(small_mode_idx.is_none()); + debug_assert!(small_mode_idx.is_none()); self.expand(); } @@ -111,7 +111,7 @@ impl AdaptiveMap { } // Otherwise, the key must not be present; add a new // entry. - assert!(*len < SMALL_ELEMS as u32); + debug_assert!(*len < SMALL_ELEMS as u32); let idx = *len; *len += 1; keys[idx as usize] = key; @@ -344,11 +344,11 @@ mod test { let mut checksum = 0; for bit in vec.iter() { - assert!(bit % 17 == 0); + debug_assert!(bit % 17 == 0); checksum += bit; } - assert_eq!(sum, checksum); + debug_assert_eq!(sum, checksum); } #[test] @@ -362,6 +362,6 @@ mod test { // should still be in small mode. vec.set(64 * 5, false); vec.set(64 * 100, true); - assert!(vec.is_small()); + debug_assert!(vec.is_small()); } } diff --git a/src/ion/liveranges.rs b/src/ion/liveranges.rs index 404b438..2f7e2e6 100644 --- a/src/ion/liveranges.rs +++ b/src/ion/liveranges.rs @@ -199,7 +199,7 @@ impl<'a, F: Function> Env<'a, F> { // array, then reverse them at the end of // `compute_liveness()`. - assert!( + debug_assert!( self.vregs[vreg.index()].ranges.is_empty() || range.to <= self.ranges[self.vregs[vreg.index()] @@ -235,7 +235,7 @@ impl<'a, F: Function> Env<'a, F> { // Is contiguous with previously-added range; just extend // its range and return it. let lr = self.vregs[vreg.index()].ranges.last().unwrap().index; - assert!(range.to == self.ranges[lr.index()].range.from); + debug_assert!(range.to == self.ranges[lr.index()].range.from); self.ranges[lr.index()].range.from = range.from; lr } @@ -504,11 +504,11 @@ impl<'a, F: Function> Env<'a, F> { if src.vreg() != dst.vreg() { log::trace!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst); - assert_eq!(src.class(), dst.class()); - assert_eq!(src.kind(), OperandKind::Use); - assert_eq!(src.pos(), OperandPos::Early); - assert_eq!(dst.kind(), OperandKind::Def); - assert_eq!(dst.pos(), OperandPos::Late); + debug_assert_eq!(src.class(), dst.class()); + debug_assert_eq!(src.kind(), OperandKind::Use); + debug_assert_eq!(src.pos(), OperandPos::Early); + debug_assert_eq!(dst.kind(), OperandKind::Def); + debug_assert_eq!(dst.pos(), OperandPos::Late); // If both src and dest are pinned, emit the // move right here, right now. @@ -1012,7 +1012,7 @@ impl<'a, F: Function> Env<'a, F> { ); vreg_ranges[operand.vreg().vreg()] = lr; } - assert!(lr.is_valid()); + debug_assert!(lr.is_valid()); log::trace!("Use of {:?} at {:?} -> {:?}", operand, pos, lr,); @@ -1082,7 +1082,7 @@ impl<'a, F: Function> Env<'a, F> { // need to update with the final range here. entry.range = self.ranges[entry.index.index()].range; // Assert in-order and non-overlapping. - assert!(last.is_none() || last.unwrap() <= entry.range.from); + debug_assert!(last.is_none() || last.unwrap() <= entry.range.from); last = Some(entry.range.to); } } diff --git a/src/ion/merge.rs b/src/ion/merge.rs index a8e1fe5..01bad4a 100644 --- a/src/ion/merge.rs +++ b/src/ion/merge.rs @@ -52,11 +52,11 @@ impl<'a, F: Function> Env<'a, F> { // Sanity check: both bundles should contain only ranges with appropriate VReg classes. for entry in &self.bundles[from.index()].ranges { let vreg = self.ranges[entry.index.index()].vreg; - assert_eq!(from_rc, self.vreg_regs[vreg.index()].class()); + debug_assert_eq!(from_rc, self.vreg_regs[vreg.index()].class()); } for entry in &self.bundles[to.index()].ranges { let vreg = self.ranges[entry.index.index()].vreg; - assert_eq!(to_rc, self.vreg_regs[vreg.index()].class()); + debug_assert_eq!(to_rc, self.vreg_regs[vreg.index()].class()); } } @@ -175,7 +175,7 @@ impl<'a, F: Function> Env<'a, F> { for i in 0..self.bundles[to.index()].ranges.len() { let entry = self.bundles[to.index()].ranges[i]; if last_range.is_some() { - assert!(last_range.unwrap() < entry.range); + debug_assert!(last_range.unwrap() < entry.range); } last_range = Some(entry.range); @@ -321,10 +321,10 @@ impl<'a, F: Function> Env<'a, F> { ); let src_bundle = self.ranges[self.vregs[src_vreg.vreg()].ranges[0].index.index()].bundle; - assert!(src_bundle.is_valid()); + debug_assert!(src_bundle.is_valid()); let dest_bundle = self.ranges[self.vregs[dst_vreg.vreg()].ranges[0].index.index()].bundle; - assert!(dest_bundle.is_valid()); + debug_assert!(dest_bundle.is_valid()); self.merge_bundles(/* from */ dest_bundle, /* to */ src_bundle); } } @@ -339,10 +339,10 @@ impl<'a, F: Function> Env<'a, F> { from_vreg.index() ); let to_bundle = self.ranges[self.vregs[to_vreg.index()].ranges[0].index.index()].bundle; - assert!(to_bundle.is_valid()); + debug_assert!(to_bundle.is_valid()); let from_bundle = self.ranges[self.vregs[from_vreg.index()].ranges[0].index.index()].bundle; - assert!(from_bundle.is_valid()); + debug_assert!(from_bundle.is_valid()); log::trace!( " -> from bundle{} to bundle{}", from_bundle.index(), @@ -384,9 +384,9 @@ impl<'a, F: Function> Env<'a, F> { } let src_bundle = self.ranges[src.index()].bundle; - assert!(src_bundle.is_valid()); + debug_assert!(src_bundle.is_valid()); let dest_bundle = self.ranges[dst.index()].bundle; - assert!(dest_bundle.is_valid()); + debug_assert!(dest_bundle.is_valid()); self.stats.prog_move_merge_attempt += 1; if self.merge_bundles(/* from */ dest_bundle, /* to */ src_bundle) { self.stats.prog_move_merge_success += 1; diff --git a/src/ion/moves.rs b/src/ion/moves.rs index 9f913c4..c86fd1a 100644 --- a/src/ion/moves.rs +++ b/src/ion/moves.rs @@ -62,7 +62,7 @@ impl<'a, F: Function> Env<'a, F> { ); match (from_alloc.as_reg(), to_alloc.as_reg()) { (Some(from), Some(to)) => { - assert_eq!(from.class(), to.class()); + debug_assert_eq!(from.class(), to.class()); } _ => {} } @@ -148,9 +148,9 @@ impl<'a, F: Function> Env<'a, F> { to_vreg: VRegIndex, kind: HalfMoveKind, ) -> u64 { - assert!(from_block.index() < 1 << 21); - assert!(to_block.index() < 1 << 21); - assert!(to_vreg.index() < 1 << 21); + debug_assert!(from_block.index() < 1 << 21); + debug_assert!(to_block.index() < 1 << 21); + debug_assert!(to_vreg.index() < 1 << 21); ((from_block.index() as u64) << 43) | ((to_block.index() as u64) << 22) | ((to_vreg.index() as u64) << 1) @@ -277,7 +277,7 @@ impl<'a, F: Function> Env<'a, F> { alloc, vreg.index() ); - assert_eq!(range.from.pos(), InstPosition::Before); + debug_assert_eq!(range.from.pos(), InstPosition::Before); self.insert_move( range.from, InsertMovePrio::Regular, @@ -816,7 +816,7 @@ impl<'a, F: Function> Env<'a, F> { .sort_unstable_by_key(|((_, inst), _)| inst.prev()); let prog_move_srcs = std::mem::replace(&mut self.prog_move_srcs, vec![]); let prog_move_dsts = std::mem::replace(&mut self.prog_move_dsts, vec![]); - assert_eq!(prog_move_srcs.len(), prog_move_dsts.len()); + debug_assert_eq!(prog_move_srcs.len(), prog_move_dsts.len()); for (&((_, from_inst), from_alloc), &((to_vreg, to_inst), to_alloc)) in prog_move_srcs.iter().zip(prog_move_dsts.iter()) { @@ -827,9 +827,9 @@ impl<'a, F: Function> Env<'a, F> { to_alloc, to_vreg.index(), ); - assert!(from_alloc.is_some()); - assert!(to_alloc.is_some()); - assert_eq!(from_inst, to_inst.prev()); + debug_assert!(from_alloc.is_some()); + debug_assert!(to_alloc.is_some()); + debug_assert_eq!(from_inst, to_inst.prev()); // N.B.: these moves happen with the *same* priority as // LR-to-LR moves, because they work just like them: they // connect a use at one progpoint (move-After) with a def @@ -933,7 +933,7 @@ impl<'a, F: Function> Env<'a, F> { for m in moves { if m.from_alloc.is_reg() && m.to_alloc.is_reg() { - 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.to_vreg.is_some() { @@ -1020,7 +1020,7 @@ impl<'a, F: Function> Env<'a, F> { }, ); } else { - assert!(extra_slot.is_some()); + debug_assert!(extra_slot.is_some()); self.add_edit( pos, prio, @@ -1093,7 +1093,7 @@ impl<'a, F: Function> Env<'a, F> { m.to_vreg ); let action = redundant_moves.process_move(m.from_alloc, m.to_alloc, m.to_vreg); - assert!(action.elide); + debug_assert!(action.elide); if let Some((alloc, vreg)) = action.def_alloc { log::trace!(" -> DefAlloc: alloc {} vreg {}", alloc, vreg); self.add_edit(pos, prio, Edit::DefAlloc { alloc, vreg }); @@ -1122,8 +1122,8 @@ impl<'a, F: Function> Env<'a, F> { .iter() .map(|(_, _, _, alloc)| *alloc) .collect::>(); - assert_eq!(vregs.len(), self.func.block_params(block).len()); - assert_eq!(allocs.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()); for (vreg, alloc) in vregs.into_iter().zip(allocs.into_iter()) { self.add_edit( self.cfginfo.block_entry[block.index()], @@ -1164,7 +1164,7 @@ impl<'a, F: Function> Env<'a, F> { match &edit { &Edit::Move { from, to, to_vreg } if from == to && to_vreg.is_none() => return, &Edit::Move { from, to, .. } if from.is_reg() && to.is_reg() => { - 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()); } _ => {} } diff --git a/src/ion/process.rs b/src/ion/process.rs index c45bc5b..753990b 100644 --- a/src/ion/process.rs +++ b/src/ion/process.rs @@ -150,7 +150,7 @@ impl<'a, F: Function> Env<'a, F> { // Otherwise, there is a conflict. let preg_key = *preg_range_iter.peek().unwrap().0; - assert_eq!(preg_key, key); // Assert that this range overlaps. + debug_assert_eq!(preg_key, key); // Assert that this range overlaps. let preg_range = preg_range_iter.next().unwrap().1; log::trace!(" -> btree contains range {:?} that overlaps", preg_range); @@ -410,7 +410,7 @@ impl<'a, F: Function> Env<'a, F> { let spillset = self.bundles[bundle.index()].spillset; - assert!(!self.bundles[bundle.index()].ranges.is_empty()); + debug_assert!(!self.bundles[bundle.index()].ranges.is_empty()); // Split point *at* start is OK; this means we peel off // exactly one use to create a minimal bundle. let bundle_start = self.bundles[bundle.index()] @@ -419,9 +419,9 @@ impl<'a, F: Function> Env<'a, F> { .unwrap() .range .from; - assert!(split_at >= bundle_start); + debug_assert!(split_at >= bundle_start); let bundle_end = self.bundles[bundle.index()].ranges.last().unwrap().range.to; - assert!(split_at < bundle_end); + debug_assert!(split_at < bundle_end); // Is the split point *at* the start? If so, peel off the // first use: set the split point just after it, or just @@ -471,7 +471,7 @@ impl<'a, F: Function> Env<'a, F> { } } - assert!(split_at > bundle_start && split_at < bundle_end); + debug_assert!(split_at > bundle_start && split_at < bundle_end); // We need to find which LRs fall on each side of the split, // which LR we need to split down the middle, then update the @@ -516,7 +516,7 @@ impl<'a, F: Function> Env<'a, F> { // down the middle, replace it with a new LR and chop off the // end of the same LR in the original list. if split_at > new_lr_list[0].range.from { - assert_eq!(last_lr_in_old_bundle_idx, first_lr_in_new_bundle_idx); + debug_assert_eq!(last_lr_in_old_bundle_idx, first_lr_in_new_bundle_idx); let orig_lr = new_lr_list[0].index; let new_lr = self.create_liverange(CodeRange { from: split_at, @@ -749,7 +749,7 @@ impl<'a, F: Function> Env<'a, F> { // We have to split right away. We'll find a point to // split that would allow at least the first half of the // split to be conflict-free. - assert!( + debug_assert!( !self.minimal_bundle(bundle), "Minimal bundle with conflict!" ); @@ -932,7 +932,7 @@ impl<'a, F: Function> Env<'a, F> { ); // If we reach here, we *must* have an option either to split or evict. - assert!( + debug_assert!( lowest_cost_split_conflict_cost.is_some() || lowest_cost_evict_conflict_cost.is_some() ); diff --git a/src/lib.rs b/src/lib.rs index 9639b0f..f1a5d70 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,7 +234,7 @@ impl SpillSlot { /// Create a new SpillSlot of a given class. #[inline(always)] pub fn new(slot: usize, class: RegClass) -> Self { - assert!(slot < (1 << 24)); + debug_assert!(slot < (1 << 24)); SpillSlot { bits: (slot as u32) | (class as u8 as u32) << 24, } @@ -412,11 +412,11 @@ impl Operand { OperandConstraint::Reg => 1, OperandConstraint::Stack => 2, OperandConstraint::FixedReg(preg) => { - assert_eq!(preg.class(), vreg.class()); + debug_assert_eq!(preg.class(), vreg.class()); 0b1000000 | preg.hw_enc() as u32 } OperandConstraint::Reuse(which) => { - assert!(which <= 31); + debug_assert!(which <= 31); 0b0100000 | which as u32 } }; @@ -696,7 +696,7 @@ impl Allocation { /// Construct a new Allocation. #[inline(always)] pub(crate) fn new(kind: AllocationKind, index: usize) -> Self { - assert!(index < (1 << 28)); + debug_assert!(index < (1 << 28)); Self { bits: ((kind as u8 as u32) << 29) | (index as u32), } diff --git a/src/moves.rs b/src/moves.rs index 0bb388e..e961654 100644 --- a/src/moves.rs +++ b/src/moves.rs @@ -183,7 +183,7 @@ impl ParallelMoves { scratch_src = Some(src); src = self.scratch; } else { - assert_eq!(last_dst.unwrap(), src); + debug_assert_eq!(last_dst.unwrap(), src); } ret.push((src, dst, dst_t));