Mass rename Ebb and relatives to Block (#1365)

* Manually rename BasicBlock to BlockPredecessor

BasicBlock is a pair of (Ebb, Inst) that is used to represent the
basic block subcomponent of an Ebb that is a predecessor to an Ebb.

Eventually we will be able to remove this struct, but for now it
makes sense to give it a non-conflicting name so that we can start
to transition Ebb to represent a basic block.

I have not updated any comments that refer to BasicBlock, as
eventually we will remove BlockPredecessor and replace with Block,
which is a basic block, so the comments will become correct.

* Manually rename SSABuilder block types to avoid conflict

SSABuilder has its own Block and BlockData types. These along with
associated identifier will cause conflicts in a later commit, so
they are renamed to be more verbose here.

* Automatically rename 'Ebb' to 'Block' in *.rs

* Automatically rename 'EBB' to 'block' in *.rs

* Automatically rename 'ebb' to 'block' in *.rs

* Automatically rename 'extended basic block' to 'basic block' in *.rs

* Automatically rename 'an basic block' to 'a basic block' in *.rs

* Manually update comment for `Block`

`Block`'s wikipedia article required an update.

* Automatically rename 'an `Block`' to 'a `Block`' in *.rs

* Automatically rename 'extended_basic_block' to 'basic_block' in *.rs

* Automatically rename 'ebb' to 'block' in *.clif

* Manually rename clif constant that contains 'ebb' as substring to avoid conflict

* Automatically rename filecheck uses of 'EBB' to 'BB'

'regex: EBB' -> 'regex: BB'
'$EBB' -> '$BB'

* Automatically rename 'EBB' 'Ebb' to 'block' in *.clif

* Automatically rename 'an block' to 'a block' in *.clif

* Fix broken testcase when function name length increases

Test function names are limited to 16 characters. This causes
the new longer name to be truncated and fail a filecheck test. An
outdated comment was also fixed.
This commit is contained in:
Ryan Hunt
2020-02-07 10:46:47 -06:00
committed by GitHub
parent a136d1cb00
commit 832666c45e
370 changed files with 8090 additions and 7988 deletions

View File

@@ -1,40 +1,40 @@
//! A verifier for ensuring that functions are well formed.
//! It verifies:
//!
//! EBB integrity
//! block integrity
//!
//! - All instructions reached from the `ebb_insts` iterator must belong to
//! the EBB as reported by `inst_ebb()`.
//! - Every EBB must end in a terminator instruction, and no other instruction
//! - All instructions reached from the `block_insts` iterator must belong to
//! the block as reported by `inst_block()`.
//! - Every block must end in a terminator instruction, and no other instruction
//! can be a terminator.
//! - Every value in the `ebb_params` iterator belongs to the EBB as reported by `value_ebb`.
//! - Every value in the `block_params` iterator belongs to the block as reported by `value_block`.
//!
//! Instruction integrity
//!
//! - The instruction format must match the opcode.
//! - All result values must be created for multi-valued instructions.
//! - All referenced entities must exist. (Values, EBBs, stack slots, ...)
//! - All referenced entities must exist. (Values, blocks, stack slots, ...)
//! - Instructions must not reference (eg. branch to) the entry block.
//!
//! SSA form
//!
//! - Values must be defined by an instruction that exists and that is inserted in
//! an EBB, or be an argument of an existing EBB.
//! an block, or be an argument of an existing block.
//! - Values used by an instruction must dominate the instruction.
//!
//! Control flow graph and dominator tree integrity:
//!
//! - All predecessors in the CFG must be branches to the EBB.
//! - All branches to an EBB must be present in the CFG.
//! - All predecessors in the CFG must be branches to the block.
//! - All branches to an block must be present in the CFG.
//! - A recomputed dominator tree is identical to the existing one.
//!
//! Type checking
//!
//! - Compare input and output values against the opcode's type constraints.
//! For polymorphic opcodes, determine the controlling type variable first.
//! - Branches and jumps must pass arguments to destination EBBs that match the
//! - Branches and jumps must pass arguments to destination blocks that match the
//! expected types exactly. The number of arguments must match.
//! - All EBBs in a jump table must take no arguments.
//! - All blocks in a jump table must take no arguments.
//! - Function calls are type checked against their signature.
//! - The entry block must take arguments that match the signature of the current
//! function.
@@ -60,12 +60,12 @@ use self::flags::verify_flags;
use crate::dbg::DisplayList;
use crate::dominator_tree::DominatorTree;
use crate::entity::SparseSet;
use crate::flowgraph::{BasicBlock, ControlFlowGraph};
use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
use crate::ir;
use crate::ir::entities::AnyEntity;
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
use crate::ir::{
types, ArgumentLoc, Ebb, FuncRef, Function, GlobalValue, Inst, InstructionData, JumpTable,
types, ArgumentLoc, Block, FuncRef, Function, GlobalValue, Inst, InstructionData, JumpTable,
Opcode, SigRef, StackSlot, StackSlotKind, Type, Value, ValueDef, ValueList, ValueLoc,
};
use crate::isa::TargetIsa;
@@ -495,30 +495,30 @@ impl<'a> Verifier<'a> {
fn verify_jump_tables(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
for (jt, jt_data) in &self.func.jump_tables {
for &ebb in jt_data.iter() {
self.verify_ebb(jt, ebb, errors)?;
for &block in jt_data.iter() {
self.verify_block(jt, block, errors)?;
}
}
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<()> {
match self.func.is_ebb_basic(ebb) {
/// Check that the given block can be encoded as a BB, by checking that only
/// branching instructions are ending the block.
fn encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
match self.func.is_block_basic(block) {
Ok(()) => Ok(()),
Err((inst, message)) => errors.fatal((inst, self.context(inst), message)),
}
}
fn ebb_integrity(
fn block_integrity(
&self,
ebb: Ebb,
block: Block,
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let is_terminator = self.func.dfg[inst].opcode().is_terminator();
let is_last_inst = self.func.layout.last_inst(ebb) == Some(inst);
let is_last_inst = self.func.layout.last_inst(block) == Some(inst);
if is_terminator && !is_last_inst {
// Terminating instructions only occur at the end of blocks.
@@ -527,30 +527,30 @@ impl<'a> Verifier<'a> {
self.context(inst),
format!(
"a terminator instruction was encountered before the end of {}",
ebb
block
),
));
}
if is_last_inst && !is_terminator {
return errors.fatal((ebb, "block does not end in a terminator instruction"));
return errors.fatal((block, "block does not end in a terminator instruction"));
}
// Instructions belong to the correct ebb.
let inst_ebb = self.func.layout.inst_ebb(inst);
if inst_ebb != Some(ebb) {
// Instructions belong to the correct block.
let inst_block = self.func.layout.inst_block(inst);
if inst_block != Some(block) {
return errors.fatal((
inst,
self.context(inst),
format!("should belong to {} not {:?}", ebb, inst_ebb),
format!("should belong to {} not {:?}", block, inst_block),
));
}
// Parameters belong to the correct ebb.
for &arg in self.func.dfg.ebb_params(ebb) {
// Parameters belong to the correct block.
for &arg in self.func.dfg.block_params(block) {
match self.func.dfg.value_def(arg) {
ValueDef::Param(arg_ebb, _) => {
if ebb != arg_ebb {
return errors.fatal((arg, format!("does not belong to {}", ebb)));
ValueDef::Param(arg_block, _) => {
if block != arg_block {
return errors.fatal((arg, format!("does not belong to {}", block)));
}
}
_ => {
@@ -656,13 +656,13 @@ impl<'a> Verifier<'a> {
ref args,
..
} => {
self.verify_ebb(inst, destination, errors)?;
self.verify_block(inst, destination, errors)?;
self.verify_value_list(inst, args, errors)?;
}
BranchTable {
table, destination, ..
} => {
self.verify_ebb(inst, destination, errors)?;
self.verify_block(inst, destination, errors)?;
self.verify_jump_table(inst, table, errors)?;
}
BranchTableBase { table, .. }
@@ -775,18 +775,18 @@ impl<'a> Verifier<'a> {
Ok(())
}
fn verify_ebb(
fn verify_block(
&self,
loc: impl Into<AnyEntity>,
e: Ebb,
e: Block,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
if !self.func.dfg.ebb_is_valid(e) || !self.func.layout.is_ebb_inserted(e) {
return errors.fatal((loc, format!("invalid ebb reference {}", e)));
if !self.func.dfg.block_is_valid(e) || !self.func.layout.is_block_inserted(e) {
return errors.fatal((loc, format!("invalid block reference {}", e)));
}
if let Some(entry_block) = self.func.layout.entry_block() {
if e == entry_block {
return errors.fatal((loc, format!("invalid reference to entry ebb {}", e)));
return errors.fatal((loc, format!("invalid reference to entry block {}", e)));
}
}
Ok(())
@@ -947,8 +947,8 @@ impl<'a> Verifier<'a> {
self.verify_value(loc_inst, v, errors)?;
let dfg = &self.func.dfg;
let loc_ebb = self.func.layout.pp_ebb(loc_inst);
let is_reachable = self.expected_domtree.is_reachable(loc_ebb);
let loc_block = self.func.layout.pp_block(loc_inst);
let is_reachable = self.expected_domtree.is_reachable(loc_block);
// SSA form
match dfg.value_def(v) {
@@ -961,12 +961,12 @@ impl<'a> Verifier<'a> {
format!("{} is defined by invalid instruction {}", v, def_inst),
));
}
// Defining instruction is inserted in an EBB.
if self.func.layout.inst_ebb(def_inst) == None {
// Defining instruction is inserted in an block.
if self.func.layout.inst_block(def_inst) == None {
return errors.fatal((
loc_inst,
self.context(loc_inst),
format!("{} is defined by {} which has no EBB", v, def_inst),
format!("{} is defined by {} which has no block", v, def_inst),
));
}
// Defining instruction dominates the instruction that uses the value.
@@ -990,33 +990,33 @@ impl<'a> Verifier<'a> {
}
}
}
ValueDef::Param(ebb, _) => {
// Value is defined by an existing EBB.
if !dfg.ebb_is_valid(ebb) {
ValueDef::Param(block, _) => {
// Value is defined by an existing block.
if !dfg.block_is_valid(block) {
return errors.fatal((
loc_inst,
self.context(loc_inst),
format!("{} is defined by invalid EBB {}", v, ebb),
format!("{} is defined by invalid block {}", v, block),
));
}
// Defining EBB is inserted in the layout
if !self.func.layout.is_ebb_inserted(ebb) {
// Defining block is inserted in the layout
if !self.func.layout.is_block_inserted(block) {
return errors.fatal((
loc_inst,
self.context(loc_inst),
format!("{} is defined by {} which is not in the layout", v, ebb),
format!("{} is defined by {} which is not in the layout", v, block),
));
}
// The defining EBB dominates the instruction using this value.
// The defining block dominates the instruction using this value.
if is_reachable
&& !self
.expected_domtree
.dominates(ebb, loc_inst, &self.func.layout)
.dominates(block, loc_inst, &self.func.layout)
{
return errors.fatal((
loc_inst,
self.context(loc_inst),
format!("uses value arg from non-dominating {}", ebb),
format!("uses value arg from non-dominating {}", block),
));
}
}
@@ -1081,17 +1081,17 @@ impl<'a> Verifier<'a> {
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
// We consider two `DominatorTree`s to be equal if they return the same immediate
// dominator for each EBB. Therefore the current domtree is valid if it matches the freshly
// dominator for each block. Therefore the current domtree is valid if it matches the freshly
// computed one.
for ebb in self.func.layout.ebbs() {
let expected = self.expected_domtree.idom(ebb);
let got = domtree.idom(ebb);
for block in self.func.layout.blocks() {
let expected = self.expected_domtree.idom(block);
let got = domtree.idom(block);
if got != expected {
return errors.fatal((
ebb,
block,
format!(
"invalid domtree, expected idom({}) = {:?}, got {:?}",
ebb, expected, got
block, expected, got
),
));
}
@@ -1100,37 +1100,37 @@ impl<'a> Verifier<'a> {
if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() {
return errors.fatal((
AnyEntity::Function,
"incorrect number of Ebbs in postorder traversal",
"incorrect number of Blocks in postorder traversal",
));
}
for (index, (&test_ebb, &true_ebb)) in domtree
for (index, (&test_block, &true_block)) in domtree
.cfg_postorder()
.iter()
.zip(self.expected_domtree.cfg_postorder().iter())
.enumerate()
{
if test_ebb != true_ebb {
if test_block != true_block {
return errors.fatal((
test_ebb,
test_block,
format!(
"invalid domtree, postorder ebb number {} should be {}, got {}",
index, true_ebb, test_ebb
"invalid domtree, postorder block number {} should be {}, got {}",
index, true_block, test_block
),
));
}
}
// We verify rpo_cmp on pairs of adjacent ebbs in the postorder
for (&prev_ebb, &next_ebb) in domtree.cfg_postorder().iter().adjacent_pairs() {
// We verify rpo_cmp on pairs of adjacent blocks in the postorder
for (&prev_block, &next_block) in domtree.cfg_postorder().iter().adjacent_pairs() {
if self
.expected_domtree
.rpo_cmp(prev_ebb, next_ebb, &self.func.layout)
.rpo_cmp(prev_block, next_block, &self.func.layout)
!= Ordering::Greater
{
return errors.fatal((
next_ebb,
next_block,
format!(
"invalid domtree, rpo_cmp does not says {} is greater than {}",
prev_ebb, next_ebb
prev_block, next_block
),
));
}
@@ -1139,26 +1139,26 @@ impl<'a> Verifier<'a> {
}
fn typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
if let Some(ebb) = self.func.layout.entry_block() {
if let Some(block) = self.func.layout.entry_block() {
let expected_types = &self.func.signature.params;
let ebb_param_count = self.func.dfg.num_ebb_params(ebb);
let block_param_count = self.func.dfg.num_block_params(block);
if ebb_param_count != expected_types.len() {
if block_param_count != expected_types.len() {
return errors.fatal((
ebb,
block,
format!(
"entry block parameters ({}) must match function signature ({})",
ebb_param_count,
block_param_count,
expected_types.len()
),
));
}
for (i, &arg) in self.func.dfg.ebb_params(ebb).iter().enumerate() {
for (i, &arg) in self.func.dfg.block_params(block).iter().enumerate() {
let arg_type = self.func.dfg.value_type(arg);
if arg_type != expected_types[i].value_type {
errors.report((
ebb,
block,
format!(
"entry block parameter {} expected to have type {}, got {}",
i, expected_types[i], arg_type
@@ -1295,38 +1295,38 @@ impl<'a> Verifier<'a> {
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
match self.func.dfg.analyze_branch(inst) {
BranchInfo::SingleDest(ebb, _) => {
BranchInfo::SingleDest(block, _) => {
let iter = self
.func
.dfg
.ebb_params(ebb)
.block_params(block)
.iter()
.map(|&v| self.func.dfg.value_type(v));
self.typecheck_variable_args_iterator(inst, iter, errors)?;
}
BranchInfo::Table(table, ebb) => {
if let Some(ebb) = ebb {
let arg_count = self.func.dfg.num_ebb_params(ebb);
BranchInfo::Table(table, block) => {
if let Some(block) = block {
let arg_count = self.func.dfg.num_block_params(block);
if arg_count != 0 {
return errors.nonfatal((
inst,
self.context(inst),
format!(
"takes no arguments, but had target {} with {} arguments",
ebb, arg_count,
block, arg_count,
),
));
}
}
for ebb in self.func.jump_tables[table].iter() {
let arg_count = self.func.dfg.num_ebb_params(*ebb);
for block in self.func.jump_tables[table].iter() {
let arg_count = self.func.dfg.num_block_params(*block);
if arg_count != 0 {
return errors.nonfatal((
inst,
self.context(inst),
format!(
"takes no arguments, but had target {} with {} arguments",
ebb, arg_count,
block, arg_count,
),
));
}
@@ -1658,28 +1658,29 @@ impl<'a> Verifier<'a> {
cfg: &ControlFlowGraph,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let mut expected_succs = BTreeSet::<Ebb>::new();
let mut got_succs = BTreeSet::<Ebb>::new();
let mut expected_succs = BTreeSet::<Block>::new();
let mut got_succs = BTreeSet::<Block>::new();
let mut expected_preds = BTreeSet::<Inst>::new();
let mut got_preds = BTreeSet::<Inst>::new();
for ebb in self.func.layout.ebbs() {
expected_succs.extend(self.expected_cfg.succ_iter(ebb));
got_succs.extend(cfg.succ_iter(ebb));
for block in self.func.layout.blocks() {
expected_succs.extend(self.expected_cfg.succ_iter(block));
got_succs.extend(cfg.succ_iter(block));
let missing_succs: Vec<Ebb> = expected_succs.difference(&got_succs).cloned().collect();
let missing_succs: Vec<Block> =
expected_succs.difference(&got_succs).cloned().collect();
if !missing_succs.is_empty() {
errors.report((
ebb,
block,
format!("cfg lacked the following successor(s) {:?}", missing_succs),
));
continue;
}
let excess_succs: Vec<Ebb> = got_succs.difference(&expected_succs).cloned().collect();
let excess_succs: Vec<Block> = got_succs.difference(&expected_succs).cloned().collect();
if !excess_succs.is_empty() {
errors.report((
ebb,
block,
format!("cfg had unexpected successor(s) {:?}", excess_succs),
));
continue;
@@ -1687,15 +1688,18 @@ impl<'a> Verifier<'a> {
expected_preds.extend(
self.expected_cfg
.pred_iter(ebb)
.map(|BasicBlock { inst, .. }| inst),
.pred_iter(block)
.map(|BlockPredecessor { inst, .. }| inst),
);
got_preds.extend(
cfg.pred_iter(block)
.map(|BlockPredecessor { inst, .. }| inst),
);
got_preds.extend(cfg.pred_iter(ebb).map(|BasicBlock { inst, .. }| inst));
let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
if !missing_preds.is_empty() {
errors.report((
ebb,
block,
format!(
"cfg lacked the following predecessor(s) {:?}",
missing_preds
@@ -1707,7 +1711,7 @@ impl<'a> Verifier<'a> {
let excess_preds: Vec<Inst> = got_preds.difference(&expected_preds).cloned().collect();
if !excess_preds.is_empty() {
errors.report((
ebb,
block,
format!("cfg had unexpected predecessor(s) {:?}", excess_preds),
));
continue;
@@ -1969,12 +1973,12 @@ impl<'a> Verifier<'a> {
self.typecheck_entry_block_params(errors)?;
self.typecheck_function_signature(errors)?;
for ebb in self.func.layout.ebbs() {
if self.func.layout.first_inst(ebb).is_none() {
return errors.fatal((ebb, format!("{} cannot be empty", ebb)));
for block in self.func.layout.blocks() {
if self.func.layout.first_inst(block).is_none() {
return errors.fatal((block, format!("{} cannot be empty", block)));
}
for inst in self.func.layout.ebb_insts(ebb) {
self.ebb_integrity(ebb, inst, errors)?;
for inst in self.func.layout.block_insts(block) {
self.block_integrity(block, inst, errors)?;
self.instruction_integrity(inst, errors)?;
self.verify_safepoint_unused(inst, errors)?;
self.typecheck(inst, errors)?;
@@ -1982,7 +1986,7 @@ impl<'a> Verifier<'a> {
self.immediate_constraints(inst, errors)?;
}
self.encodable_as_bb(ebb, errors)?;
self.encodable_as_bb(block, errors)?;
}
verify_flags(self.func, &self.expected_cfg, self.isa, errors)?;
@@ -2039,20 +2043,20 @@ mod tests {
#[test]
fn bad_instruction_format() {
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
func.layout.append_ebb(ebb0);
let block0 = func.dfg.make_block();
func.layout.append_block(block0);
let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm {
opcode: Opcode::F32const,
imm: 0.into(),
});
func.layout.append_inst(nullary_with_bad_opcode, ebb0);
func.layout.append_inst(nullary_with_bad_opcode, block0);
func.layout.append_inst(
func.dfg.make_inst(InstructionData::Jump {
opcode: Opcode::Jump,
destination: ebb0,
destination: block0,
args: EntityList::default(),
}),
ebb0,
block0,
);
let flags = &settings::Flags::new(settings::builder());
let verifier = Verifier::new(&func, flags.into());
@@ -2093,8 +2097,8 @@ mod tests {
fn test_printing_contextual_errors() {
// Build function.
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
func.layout.append_ebb(ebb0);
let block0 = func.dfg.make_block();
func.layout.append_block(block0);
// Build instruction: v0, v1 = iconst 42
let inst = func.dfg.make_inst(InstructionData::UnaryImm {
@@ -2103,7 +2107,7 @@ mod tests {
});
func.dfg.append_result(inst, types::I32);
func.dfg.append_result(inst, types::I32);
func.layout.append_inst(inst, ebb0);
func.layout.append_inst(inst, block0);
// Setup verifier.
let mut errors = VerifierErrors::default();
@@ -2120,16 +2124,16 @@ mod tests {
}
#[test]
fn test_empty_ebb() {
fn test_empty_block() {
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
func.layout.append_ebb(ebb0);
let block0 = func.dfg.make_block();
func.layout.append_block(block0);
let flags = &settings::Flags::new(settings::builder());
let verifier = Verifier::new(&func, flags.into());
let mut errors = VerifierErrors::default();
let _ = verifier.run(&mut errors);
assert_err_with_msg!(errors, "ebb0 cannot be empty");
assert_err_with_msg!(errors, "block0 cannot be empty");
}
}