diff --git a/src/ion/merge.rs b/src/ion/merge.rs index a5c4fe2..f3eb808 100644 --- a/src/ion/merge.rs +++ b/src/ion/merge.rs @@ -41,8 +41,8 @@ impl<'a, F: Function> Env<'a, F> { } // If either bundle is already assigned (due to a pinned vreg), don't merge. - if !self.bundles[from.index()].allocation.is_none() - || !self.bundles[to.index()].allocation.is_none() + if self.bundles[from.index()].allocation.is_some() + || self.bundles[to.index()].allocation.is_some() { log::trace!("one of the bundles is already assigned (pinned)"); return false; diff --git a/src/ion/moves.rs b/src/ion/moves.rs index 190292c..56336c4 100644 --- a/src/ion/moves.rs +++ b/src/ion/moves.rs @@ -817,8 +817,8 @@ impl<'a, F: Function> Env<'a, F> { to_alloc, to_vreg.index(), ); - assert!(!from_alloc.is_none()); - assert!(!to_alloc.is_none()); + assert!(from_alloc.is_some()); + assert!(to_alloc.is_some()); 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 diff --git a/src/lib.rs b/src/lib.rs index dda8575..1980908 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,9 @@ impl std::fmt::Display for SpillSlot { /// physical register". The allocator's result will always satisfy all /// given constraints; however, if the input has a combination of /// constraints that are impossible to satisfy, then allocation may -/// fail. +/// fail or the allocator may panic (providing impossible constraints +/// is usually a programming error in the client, rather than a +/// function of bad input). #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum OperandConstraint { /// Any location is fine (register or stack slot). @@ -487,6 +489,13 @@ impl Operand { /// to be written by the instruction, and will not conflict with /// any input or output, but should not be used after the /// instruction completes. + /// + /// Note that within a single instruction, the dedicated scratch + /// register (as specified in the `MachineEnv`) is also always + /// available for use. The register allocator may use the register + /// *between* instructions in order to implement certain sequences + /// of moves, but will never hold a value live in the scratch + /// register across an instruction. #[inline(always)] pub fn reg_temp(vreg: VReg) -> Self { // For now a temp is equivalent to a def-at-start operand, @@ -724,6 +733,12 @@ impl Allocation { self.kind() == AllocationKind::None } + /// Is the allocation not "none"? + #[inline(always)] + pub fn is_some(self) -> bool { + self.kind() != AllocationKind::None + } + /// Is the allocation a register? #[inline(always)] pub fn is_reg(self) -> bool {