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

@@ -6,8 +6,8 @@ use cranelift_codegen::cursor::{Cursor, FuncCursor};
use cranelift_codegen::flowgraph::ControlFlowGraph;
use cranelift_codegen::ir::types::{F32, F64};
use cranelift_codegen::ir::{
self, Ebb, FuncRef, Function, GlobalValueData, Inst, InstBuilder, InstructionData, StackSlots,
TrapCode,
self, Block, FuncRef, Function, GlobalValueData, Inst, InstBuilder, InstructionData,
StackSlots, TrapCode,
};
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::Context;
@@ -46,17 +46,17 @@ pub fn run(
std::env::set_var("RUST_BACKTRACE", "0"); // Disable backtraces to reduce verbosity
for (func, _) in test_file.functions {
let (orig_ebb_count, orig_inst_count) = (ebb_count(&func), inst_count(&func));
let (orig_block_count, orig_inst_count) = (block_count(&func), inst_count(&func));
match reduce(isa, func, verbose) {
Ok((func, crash_msg)) => {
println!("Crash message: {}", crash_msg);
println!("\n{}", func);
println!(
"{} ebbs {} insts -> {} ebbs {} insts",
orig_ebb_count,
"{} blocks {} insts -> {} blocks {} insts",
orig_block_count,
orig_inst_count,
ebb_count(&func),
block_count(&func),
inst_count(&func)
);
}
@@ -68,7 +68,7 @@ pub fn run(
}
enum ProgressStatus {
/// The mutation raised or reduced the amount of instructions or ebbs.
/// The mutation raised or reduced the amount of instructions or blocks.
ExpandedOrShrinked,
/// The mutation only changed an instruction. Performing another round of mutations may only
@@ -92,16 +92,16 @@ trait Mutator {
/// Try to remove instructions.
struct RemoveInst {
ebb: Ebb,
block: Block,
inst: Inst,
}
impl RemoveInst {
fn new(func: &Function) -> Self {
let first_ebb = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_ebb).unwrap();
let first_block = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_block).unwrap();
Self {
ebb: first_ebb,
block: first_block,
inst: first_inst,
}
}
@@ -117,12 +117,12 @@ impl Mutator for RemoveInst {
}
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(prev_ebb, prev_inst)| {
next_inst_ret_prev(&func, &mut self.block, &mut self.inst).map(|(prev_block, prev_inst)| {
func.layout.remove_inst(prev_inst);
let msg = if func.layout.ebb_insts(prev_ebb).next().is_none() {
// Make sure empty ebbs are removed, as `next_inst_ret_prev` depends on non empty ebbs
func.layout.remove_ebb(prev_ebb);
format!("Remove inst {} and empty ebb {}", prev_inst, prev_ebb)
let msg = if func.layout.block_insts(prev_block).next().is_none() {
// Make sure empty blocks are removed, as `next_inst_ret_prev` depends on non empty blocks
func.layout.remove_block(prev_block);
format!("Remove inst {} and empty block {}", prev_inst, prev_block)
} else {
format!("Remove inst {}", prev_inst)
};
@@ -133,16 +133,16 @@ impl Mutator for RemoveInst {
/// Try to replace instructions with `iconst` or `fconst`.
struct ReplaceInstWithConst {
ebb: Ebb,
block: Block,
inst: Inst,
}
impl ReplaceInstWithConst {
fn new(func: &Function) -> Self {
let first_ebb = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_ebb).unwrap();
let first_block = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_block).unwrap();
Self {
ebb: first_ebb,
block: first_block,
inst: first_inst,
}
}
@@ -174,71 +174,73 @@ impl Mutator for ReplaceInstWithConst {
}
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(_prev_ebb, prev_inst)| {
let num_results = func.dfg.inst_results(prev_inst).len();
next_inst_ret_prev(&func, &mut self.block, &mut self.inst).map(
|(_prev_block, prev_inst)| {
let num_results = func.dfg.inst_results(prev_inst).len();
let opcode = func.dfg[prev_inst].opcode();
if num_results == 0
|| opcode == ir::Opcode::Iconst
|| opcode == ir::Opcode::F32const
|| opcode == ir::Opcode::F64const
{
return (func, format!(""), ProgressStatus::Skip);
}
let opcode = func.dfg[prev_inst].opcode();
if num_results == 0
|| opcode == ir::Opcode::Iconst
|| opcode == ir::Opcode::F32const
|| opcode == ir::Opcode::F64const
{
return (func, format!(""), ProgressStatus::Skip);
}
if num_results == 1 {
let ty = func.dfg.value_type(func.dfg.first_result(prev_inst));
let new_inst_name = Self::const_for_type(func.dfg.replace(prev_inst), ty);
return (
if num_results == 1 {
let ty = func.dfg.value_type(func.dfg.first_result(prev_inst));
let new_inst_name = Self::const_for_type(func.dfg.replace(prev_inst), ty);
return (
func,
format!("Replace inst {} with {}.", prev_inst, new_inst_name),
ProgressStatus::Changed,
);
}
// At least 2 results. Replace each instruction with as many const instructions as
// there are results.
let mut pos = FuncCursor::new(&mut func).at_inst(prev_inst);
// Copy result SSA names into our own vector; otherwise we couldn't mutably borrow pos
// in the loop below.
let results = pos.func.dfg.inst_results(prev_inst).to_vec();
// Detach results from the previous instruction, since we're going to reuse them.
pos.func.dfg.clear_results(prev_inst);
let mut inst_names = Vec::new();
for r in results {
let ty = pos.func.dfg.value_type(r);
let builder = pos.ins().with_results([Some(r)]);
let new_inst_name = Self::const_for_type(builder, ty);
inst_names.push(new_inst_name);
}
// Remove the instruction.
assert_eq!(pos.remove_inst(), prev_inst);
(
func,
format!("Replace inst {} with {}.", prev_inst, new_inst_name),
ProgressStatus::Changed,
);
}
// At least 2 results. Replace each instruction with as many const instructions as
// there are results.
let mut pos = FuncCursor::new(&mut func).at_inst(prev_inst);
// Copy result SSA names into our own vector; otherwise we couldn't mutably borrow pos
// in the loop below.
let results = pos.func.dfg.inst_results(prev_inst).to_vec();
// Detach results from the previous instruction, since we're going to reuse them.
pos.func.dfg.clear_results(prev_inst);
let mut inst_names = Vec::new();
for r in results {
let ty = pos.func.dfg.value_type(r);
let builder = pos.ins().with_results([Some(r)]);
let new_inst_name = Self::const_for_type(builder, ty);
inst_names.push(new_inst_name);
}
// Remove the instruction.
assert_eq!(pos.remove_inst(), prev_inst);
(
func,
format!("Replace inst {} with {}", prev_inst, inst_names.join(" / ")),
ProgressStatus::ExpandedOrShrinked,
)
})
format!("Replace inst {} with {}", prev_inst, inst_names.join(" / ")),
ProgressStatus::ExpandedOrShrinked,
)
},
)
}
}
/// Try to replace instructions with `trap`.
struct ReplaceInstWithTrap {
ebb: Ebb,
block: Block,
inst: Inst,
}
impl ReplaceInstWithTrap {
fn new(func: &Function) -> Self {
let first_ebb = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_ebb).unwrap();
let first_block = func.layout.entry_block().unwrap();
let first_inst = func.layout.first_inst(first_block).unwrap();
Self {
ebb: first_ebb,
block: first_block,
inst: first_inst,
}
}
@@ -254,54 +256,56 @@ impl Mutator for ReplaceInstWithTrap {
}
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(_prev_ebb, prev_inst)| {
let status = if func.dfg[prev_inst].opcode() == ir::Opcode::Trap {
ProgressStatus::Skip
} else {
func.dfg.replace(prev_inst).trap(TrapCode::User(0));
ProgressStatus::Changed
};
(
func,
format!("Replace inst {} with trap", prev_inst),
status,
)
})
next_inst_ret_prev(&func, &mut self.block, &mut self.inst).map(
|(_prev_block, prev_inst)| {
let status = if func.dfg[prev_inst].opcode() == ir::Opcode::Trap {
ProgressStatus::Skip
} else {
func.dfg.replace(prev_inst).trap(TrapCode::User(0));
ProgressStatus::Changed
};
(
func,
format!("Replace inst {} with trap", prev_inst),
status,
)
},
)
}
}
/// Try to remove an ebb.
struct RemoveEbb {
ebb: Ebb,
/// Try to remove an block.
struct RemoveBlock {
block: Block,
}
impl RemoveEbb {
impl RemoveBlock {
fn new(func: &Function) -> Self {
Self {
ebb: func.layout.entry_block().unwrap(),
block: func.layout.entry_block().unwrap(),
}
}
}
impl Mutator for RemoveEbb {
impl Mutator for RemoveBlock {
fn name(&self) -> &'static str {
"remove ebb"
"remove block"
}
fn mutation_count(&self, func: &Function) -> usize {
ebb_count(func)
block_count(func)
}
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
func.layout.next_ebb(self.ebb).map(|next_ebb| {
self.ebb = next_ebb;
while let Some(inst) = func.layout.last_inst(self.ebb) {
func.layout.next_block(self.block).map(|next_block| {
self.block = next_block;
while let Some(inst) = func.layout.last_inst(self.block) {
func.layout.remove_inst(inst);
}
func.layout.remove_ebb(self.ebb);
func.layout.remove_block(self.block);
(
func,
format!("Remove ebb {}", next_ebb),
format!("Remove block {}", next_block),
ProgressStatus::ExpandedOrShrinked,
)
})
@@ -333,8 +337,8 @@ impl Mutator for RemoveUnusedEntities {
let name = match self.kind {
0 => {
let mut ext_func_usage_map = HashMap::new();
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
match func.dfg[inst] {
// Add new cases when there are new instruction formats taking a `FuncRef`.
InstructionData::Call { func_ref, .. }
@@ -383,8 +387,8 @@ impl Mutator for RemoveUnusedEntities {
}
let mut signatures_usage_map = HashMap::new();
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
// Add new cases when there are new instruction formats taking a `SigRef`.
if let InstructionData::CallIndirect { sig_ref, .. } = func.dfg[inst] {
signatures_usage_map
@@ -431,8 +435,8 @@ impl Mutator for RemoveUnusedEntities {
}
2 => {
let mut stack_slot_usage_map = HashMap::new();
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
match func.dfg[inst] {
// Add new cases when there are new instruction formats taking a `StackSlot`.
InstructionData::StackLoad { stack_slot, .. }
@@ -490,8 +494,8 @@ impl Mutator for RemoveUnusedEntities {
}
3 => {
let mut global_value_usage_map = HashMap::new();
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
// Add new cases when there are new instruction formats taking a `GlobalValue`.
if let InstructionData::UnaryGlobalValue { global_value, .. } =
func.dfg[inst]
@@ -545,15 +549,15 @@ impl Mutator for RemoveUnusedEntities {
}
struct MergeBlocks {
ebb: Ebb,
prev_ebb: Option<Ebb>,
block: Block,
prev_block: Option<Block>,
}
impl MergeBlocks {
fn new(func: &Function) -> Self {
Self {
ebb: func.layout.entry_block().unwrap(),
prev_ebb: None,
block: func.layout.entry_block().unwrap(),
prev_block: None,
}
}
}
@@ -564,30 +568,30 @@ impl Mutator for MergeBlocks {
}
fn mutation_count(&self, func: &Function) -> usize {
// N ebbs may result in at most N-1 merges.
ebb_count(func) - 1
// N blocks may result in at most N-1 merges.
block_count(func) - 1
}
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
let ebb = match func.layout.next_ebb(self.ebb) {
Some(ebb) => ebb,
let block = match func.layout.next_block(self.block) {
Some(block) => block,
None => return None,
};
self.ebb = ebb;
self.block = block;
let mut cfg = ControlFlowGraph::new();
cfg.compute(&func);
if cfg.pred_iter(ebb).count() != 1 {
if cfg.pred_iter(block).count() != 1 {
return Some((
func,
format!("did nothing for {}", ebb),
format!("did nothing for {}", block),
ProgressStatus::Skip,
));
}
let pred = cfg.pred_iter(ebb).next().unwrap();
let pred = cfg.pred_iter(block).next().unwrap();
// If the branch instruction that lead us to this block is preceded by another branch
// instruction, then we have a conditional jump sequence that we should not break by
@@ -596,86 +600,90 @@ impl Mutator for MergeBlocks {
if func.dfg[pred_pred_inst].opcode().is_branch() {
return Some((
func,
format!("did nothing for {}", ebb),
format!("did nothing for {}", block),
ProgressStatus::Skip,
));
}
}
assert!(func.dfg.ebb_params(ebb).len() == func.dfg.inst_variable_args(pred.inst).len());
assert!(func.dfg.block_params(block).len() == func.dfg.inst_variable_args(pred.inst).len());
// If there were any EBB parameters in ebb, then the last instruction in pred will
// fill these parameters. Make the EBB params aliases of the terminator arguments.
for (ebb_param, arg) in func
// If there were any block parameters in block, then the last instruction in pred will
// fill these parameters. Make the block params aliases of the terminator arguments.
for (block_param, arg) in func
.dfg
.detach_ebb_params(ebb)
.detach_block_params(block)
.as_slice(&func.dfg.value_lists)
.iter()
.cloned()
.zip(func.dfg.inst_variable_args(pred.inst).iter().cloned())
.collect::<Vec<_>>()
{
if ebb_param != arg {
func.dfg.change_to_alias(ebb_param, arg);
if block_param != arg {
func.dfg.change_to_alias(block_param, arg);
}
}
// Remove the terminator branch to the current EBB.
// Remove the terminator branch to the current block.
func.layout.remove_inst(pred.inst);
// Move all the instructions to the predecessor.
while let Some(inst) = func.layout.first_inst(ebb) {
while let Some(inst) = func.layout.first_inst(block) {
func.layout.remove_inst(inst);
func.layout.append_inst(inst, pred.ebb);
func.layout.append_inst(inst, pred.block);
}
// Remove the predecessor EBB.
func.layout.remove_ebb(ebb);
// Remove the predecessor block.
func.layout.remove_block(block);
// Record the previous EBB: if we caused a crash (as signaled by a call to did_crash), then
// we'll start back to this EBB.
self.prev_ebb = Some(pred.ebb);
// Record the previous block: if we caused a crash (as signaled by a call to did_crash), then
// we'll start back to this block.
self.prev_block = Some(pred.block);
Some((
func,
format!("merged {} and {}", pred.ebb, ebb),
format!("merged {} and {}", pred.block, block),
ProgressStatus::ExpandedOrShrinked,
))
}
fn did_crash(&mut self) {
self.ebb = self.prev_ebb.unwrap();
self.block = self.prev_block.unwrap();
}
}
fn next_inst_ret_prev(func: &Function, ebb: &mut Ebb, inst: &mut Inst) -> Option<(Ebb, Inst)> {
let prev = (*ebb, *inst);
fn next_inst_ret_prev(
func: &Function,
block: &mut Block,
inst: &mut Inst,
) -> Option<(Block, Inst)> {
let prev = (*block, *inst);
if let Some(next_inst) = func.layout.next_inst(*inst) {
*inst = next_inst;
return Some(prev);
}
if let Some(next_ebb) = func.layout.next_ebb(*ebb) {
*ebb = next_ebb;
*inst = func.layout.first_inst(*ebb).expect("no inst");
if let Some(next_block) = func.layout.next_block(*block) {
*block = next_block;
*inst = func.layout.first_inst(*block).expect("no inst");
return Some(prev);
}
None
}
fn ebb_count(func: &Function) -> usize {
func.layout.ebbs().count()
fn block_count(func: &Function) -> usize {
func.layout.blocks().count()
}
fn inst_count(func: &Function) -> usize {
func.layout
.ebbs()
.map(|ebb| func.layout.ebb_insts(ebb).count())
.blocks()
.map(|block| func.layout.block_insts(block).count())
.sum()
}
fn resolve_aliases(func: &mut Function) {
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
func.dfg.resolve_aliases_in_arguments(inst);
}
}
@@ -713,7 +721,7 @@ fn reduce(
0 => Box::new(RemoveInst::new(&func)),
1 => Box::new(ReplaceInstWithConst::new(&func)),
2 => Box::new(ReplaceInstWithTrap::new(&func)),
3 => Box::new(RemoveEbb::new(&func)),
3 => Box::new(RemoveBlock::new(&func)),
4 => Box::new(RemoveUnusedEntities::new()),
5 => Box::new(MergeBlocks::new(&func)),
_ => break,
@@ -775,10 +783,10 @@ fn reduce(
}
progress_bar.println(format!(
"After pass {}, remaining insts/ebbs: {}/{} ({})",
"After pass {}, remaining insts/blocks: {}/{} ({})",
pass_idx,
inst_count(&func),
ebb_count(&func),
block_count(&func),
if should_keep_reducing {
"will keep reducing"
} else {
@@ -861,7 +869,7 @@ impl<'a> CrashCheckContext<'a> {
Ok(None) => {}
// The verifier panicked. Compiling it will probably give the same panic.
// We treat it as succeeding to make it possible to reduce for the actual error.
// FIXME prevent verifier panic on removing ebb0.
// FIXME prevent verifier panic on removing block0.
Err(_) => return CheckResult::Succeed,
}
@@ -869,11 +877,13 @@ impl<'a> CrashCheckContext<'a> {
{
// For testing purposes we emulate a panic caused by the existence of
// a `call` instruction.
let contains_call = func.layout.ebbs().any(|ebb| {
func.layout.ebb_insts(ebb).any(|inst| match func.dfg[inst] {
InstructionData::Call { .. } => true,
_ => false,
})
let contains_call = func.layout.blocks().any(|block| {
func.layout
.block_insts(block)
.any(|inst| match func.dfg[inst] {
InstructionData::Call { .. } => true,
_ => false,
})
});
if contains_call {
return CheckResult::Crash("test crash".to_string());
@@ -934,9 +944,9 @@ mod tests {
assert_eq!(crash_msg, "test crash");
assert_eq!(
ebb_count(&func_reduced_twice),
ebb_count(&reduced_func),
"reduction wasn't maximal for ebbs"
block_count(&func_reduced_twice),
block_count(&reduced_func),
"reduction wasn't maximal for blocks"
);
assert_eq!(
inst_count(&func_reduced_twice),

View File

@@ -18,14 +18,19 @@ impl PrintRelocs {
}
impl binemit::RelocSink for PrintRelocs {
fn reloc_ebb(
fn reloc_block(
&mut self,
where_: binemit::CodeOffset,
r: binemit::Reloc,
offset: binemit::CodeOffset,
) {
if self.flag_print {
writeln!(&mut self.text, "reloc_ebb: {} {} at {}", r, offset, where_).unwrap();
writeln!(
&mut self.text,
"reloc_block: {} {} at {}",
r, offset, where_
)
.unwrap();
}
}

View File

@@ -119,7 +119,7 @@ mod test {
let code = String::from(
"
function %test() -> b8 {
ebb0:
block0:
nop
v1 = bconst.b8 true
return v1