diff --git a/cranelift/codegen/src/verifier/mod.rs b/cranelift/codegen/src/verifier/mod.rs index 7e8d7909cf..694e5e46de 100644 --- a/cranelift/codegen/src/verifier/mod.rs +++ b/cranelift/codegen/src/verifier/mod.rs @@ -267,6 +267,8 @@ struct Verifier<'a> { expected_cfg: ControlFlowGraph, expected_domtree: DominatorTree, isa: Option<&'a dyn TargetIsa>, + // To be removed when #796 is completed. + verify_encodable_as_bb: bool, } impl<'a> Verifier<'a> { @@ -278,6 +280,7 @@ impl<'a> Verifier<'a> { expected_cfg, expected_domtree, isa: fisa.isa, + verify_encodable_as_bb: std::env::var("CRANELIFT_BB").is_ok(), } } @@ -468,6 +471,53 @@ impl<'a> Verifier<'a> { Ok(()) } + /// Check that the given EBB can be encoded as a BB, by checking that only + /// branching instructions are ending the EBB. + fn encodable_as_bb(&self, ebb: Ebb, errors: &mut VerifierErrors) -> VerifierStepResult<()> { + // Skip this verification if the environment variable is not set. + if !self.verify_encodable_as_bb { + return Ok(()); + }; + + let dfg = &self.func.dfg; + let inst_iter = self.func.layout.ebb_insts(ebb); + // Skip non-branching instructions. + let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch()); + + let branch = match inst_iter.next() { + // There is no branch in the current EBB. + None => return Ok(()), + Some(br) => br, + }; + + let after_branch = match inst_iter.next() { + // The branch is also the terminator. + None => return Ok(()), + Some(inst) => inst, + }; + + let after_branch_opcode = dfg[after_branch].opcode(); + if !after_branch_opcode.is_terminator() { + return fatal!( + errors, + branch, + "branch followed by a non-terminator instruction." + ); + }; + + // Allow only one conditional branch and a fallthrough implemented with + // a jump or fallthrough instruction. Any other, which returns or check + // a different condition would have to be moved to a different EBB. + match after_branch_opcode { + Opcode::Fallthrough | Opcode::Jump => Ok(()), + _ => fatal!( + errors, + after_branch, + "terminator instruction not fallthrough or jump" + ), + } + } + fn ebb_integrity( &self, ebb: Ebb, @@ -1744,6 +1794,7 @@ impl<'a> Verifier<'a> { self.verify_encoding(inst, errors)?; self.immediate_constraints(inst, errors)?; } + self.encodable_as_bb(ebb, errors)?; } verify_flags(self.func, &self.expected_cfg, self.isa, errors)?;