diff --git a/lib/cretonne/src/binemit/relaxation.rs b/lib/cretonne/src/binemit/relaxation.rs index 94835b736e..c6ea41f451 100644 --- a/lib/cretonne/src/binemit/relaxation.rs +++ b/lib/cretonne/src/binemit/relaxation.rs @@ -152,13 +152,23 @@ fn relax_branch( if let Some(enc) = isa.legal_encodings(dfg, &dfg[inst], ctrl_type).find( |&enc| { let range = encinfo.branch_range(enc).expect("Branch with no range"); - let in_range = range.contains(offset, dest_offset); - dbg!( - " trying [{}]: {}", - encinfo.display(enc), - if in_range { "OK" } else { "out of range" } - ); - in_range + if !range.contains(offset, dest_offset) { + dbg!(" trying [{}]: out of range", encinfo.display(enc)); + false + } else if encinfo.operand_constraints(enc) != + encinfo.operand_constraints(cur.func.encodings[inst]) + { + // Conservatively give up if the encoding has different constraints + // than the original, so that we don't risk picking a new encoding + // which the existing operands don't satisfy. We can't check for + // validity directly because we don't have a RegDiversions active so + // we don't know which registers are actually in use. + dbg!(" trying [{}]: constraints differ", encinfo.display(enc)); + false + } else { + dbg!(" trying [{}]: OK", encinfo.display(enc)); + true + } }, ) { diff --git a/lib/cretonne/src/context.rs b/lib/cretonne/src/context.rs index 5b8db2414c..0eb7ff5c05 100644 --- a/lib/cretonne/src/context.rs +++ b/lib/cretonne/src/context.rs @@ -131,6 +131,20 @@ impl Context { } } + /// Run the locations verifier on the function. + pub fn verify_locations<'a>(&self, isa: &TargetIsa) -> verifier::Result { + verifier::verify_locations(isa, &self.func, None) + } + + /// Run the locations verifier only if the `enable_verifier` setting is true. + pub fn verify_locations_if<'a>(&self, isa: &TargetIsa) -> CtonResult { + if isa.flags().enable_verifier() { + self.verify_locations(isa).map_err(Into::into) + } else { + Ok(()) + } + } + /// Perform pre-legalization rewrites on the function. pub fn preopt(&mut self, isa: &TargetIsa) -> CtonResult { do_preopt(&mut self.func); @@ -212,13 +226,16 @@ impl Context { /// Insert prologue and epilogues after computing the stack frame layout. pub fn prologue_epilogue(&mut self, isa: &TargetIsa) -> CtonResult { isa.prologue_epilogue(&mut self.func)?; - self.verify_if(isa) + self.verify_if(isa)?; + self.verify_locations_if(isa)?; + Ok(()) } /// Run the branch relaxation pass and return the final code size. pub fn relax_branches(&mut self, isa: &TargetIsa) -> Result { let code_size = relax_branches(&mut self.func, isa)?; self.verify_if(isa)?; + self.verify_locations_if(isa)?; Ok(code_size) } diff --git a/lib/cretonne/src/isa/constraints.rs b/lib/cretonne/src/isa/constraints.rs index eb6b33c3cb..f831c0e187 100644 --- a/lib/cretonne/src/isa/constraints.rs +++ b/lib/cretonne/src/isa/constraints.rs @@ -13,6 +13,7 @@ use ir::{Function, ValueLoc, Inst}; use regalloc::RegDiversions; /// Register constraint for a single value operand or instruction result. +#[derive(PartialEq, Debug)] pub struct OperandConstraint { /// The kind of constraint. pub kind: ConstraintKind, @@ -53,7 +54,7 @@ impl OperandConstraint { } /// The different kinds of operand constraints. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum ConstraintKind { /// This operand or result must be a register from the given register class. Reg, @@ -89,7 +90,7 @@ pub enum ConstraintKind { } /// Value operand constraints for an encoding recipe. -#[derive(Clone)] +#[derive(PartialEq, Clone)] pub struct RecipeConstraints { /// Constraints for the instruction's fixed value operands. /// @@ -160,7 +161,7 @@ impl RecipeConstraints { /// - Intel uses the address of the instruction following the branch, `origin = 2` for a 2-byte /// branch instruction. /// - ARM's A32 encoding uses the address of the branch instruction + 8 bytes, `origin = 8`. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct BranchRange { /// Offset in bytes from the address of the branch instruction to the origin used for computing /// the branch displacement. This is the destination of a branch that encodes a 0 displacement.