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:
@@ -223,10 +223,10 @@ mod tests {
|
||||
#[test]
|
||||
fn types() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let arg0 = func.dfg.append_ebb_param(ebb0, I32);
|
||||
let block0 = func.dfg.make_block();
|
||||
let arg0 = func.dfg.append_block_param(block0, I32);
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_ebb(ebb0);
|
||||
pos.insert_block(block0);
|
||||
|
||||
// Explicit types.
|
||||
let v0 = pos.ins().iconst(I32, 3);
|
||||
@@ -244,10 +244,10 @@ mod tests {
|
||||
#[test]
|
||||
fn reuse_results() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let arg0 = func.dfg.append_ebb_param(ebb0, I32);
|
||||
let block0 = func.dfg.make_block();
|
||||
let arg0 = func.dfg.append_block_param(block0, I32);
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_ebb(ebb0);
|
||||
pos.insert_block(block0);
|
||||
|
||||
let v0 = pos.ins().iadd_imm(arg0, 17);
|
||||
assert_eq!(pos.func.dfg.value_type(v0), I32);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Data flow graph tracking Instructions, Values, and EBBs.
|
||||
//! Data flow graph tracking Instructions, Values, and blocks.
|
||||
|
||||
use crate::entity::{self, PrimaryMap, SecondaryMap};
|
||||
use crate::ir;
|
||||
@@ -7,7 +7,7 @@ use crate::ir::extfunc::ExtFuncData;
|
||||
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData};
|
||||
use crate::ir::{types, ConstantData, ConstantPool, Immediate};
|
||||
use crate::ir::{
|
||||
Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments, ValueList,
|
||||
Block, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments, ValueList,
|
||||
ValueListPool,
|
||||
};
|
||||
use crate::isa::TargetIsa;
|
||||
@@ -21,18 +21,18 @@ use core::mem;
|
||||
use core::ops::{Index, IndexMut};
|
||||
use core::u16;
|
||||
|
||||
/// A data flow graph defines all instructions and extended basic blocks in a function as well as
|
||||
/// A data flow graph defines all instructions and basic blocks in a function as well as
|
||||
/// the data flow dependencies between them. The DFG also tracks values which can be either
|
||||
/// instruction results or EBB parameters.
|
||||
/// instruction results or block parameters.
|
||||
///
|
||||
/// The layout of EBBs in the function and of instructions in each EBB is recorded by the
|
||||
/// The layout of blocks in the function and of instructions in each block is recorded by the
|
||||
/// `Layout` data structure which forms the other half of the function representation.
|
||||
///
|
||||
#[derive(Clone)]
|
||||
pub struct DataFlowGraph {
|
||||
/// Data about all of the instructions in the function, including opcodes and operands.
|
||||
/// The instructions in this map are not in program order. That is tracked by `Layout`, along
|
||||
/// with the EBB containing each instruction.
|
||||
/// with the block containing each instruction.
|
||||
insts: PrimaryMap<Inst, InstructionData>,
|
||||
|
||||
/// List of result values for each instruction.
|
||||
@@ -41,11 +41,11 @@ pub struct DataFlowGraph {
|
||||
/// primary `insts` map.
|
||||
results: SecondaryMap<Inst, ValueList>,
|
||||
|
||||
/// Extended basic blocks in the function and their parameters.
|
||||
/// basic blocks in the function and their parameters.
|
||||
///
|
||||
/// This map is not in program order. That is handled by `Layout`, and so is the sequence of
|
||||
/// instructions contained in each EBB.
|
||||
ebbs: PrimaryMap<Ebb, EbbData>,
|
||||
/// instructions contained in each block.
|
||||
blocks: PrimaryMap<Block, BlockData>,
|
||||
|
||||
/// Memory pool of value lists.
|
||||
///
|
||||
@@ -53,7 +53,7 @@ pub struct DataFlowGraph {
|
||||
///
|
||||
/// - Instructions in `insts` that don't have room for their entire argument list inline.
|
||||
/// - Instruction result values in `results`.
|
||||
/// - EBB parameters in `ebbs`.
|
||||
/// - block parameters in `blocks`.
|
||||
pub value_lists: ValueListPool,
|
||||
|
||||
/// Primary value table with entries for all values.
|
||||
@@ -85,7 +85,7 @@ impl DataFlowGraph {
|
||||
Self {
|
||||
insts: PrimaryMap::new(),
|
||||
results: SecondaryMap::new(),
|
||||
ebbs: PrimaryMap::new(),
|
||||
blocks: PrimaryMap::new(),
|
||||
value_lists: ValueListPool::new(),
|
||||
values: PrimaryMap::new(),
|
||||
signatures: PrimaryMap::new(),
|
||||
@@ -101,7 +101,7 @@ impl DataFlowGraph {
|
||||
pub fn clear(&mut self) {
|
||||
self.insts.clear();
|
||||
self.results.clear();
|
||||
self.ebbs.clear();
|
||||
self.blocks.clear();
|
||||
self.value_lists.clear();
|
||||
self.values.clear();
|
||||
self.signatures.clear();
|
||||
@@ -125,17 +125,17 @@ impl DataFlowGraph {
|
||||
self.insts.is_valid(inst)
|
||||
}
|
||||
|
||||
/// Get the total number of extended basic blocks created in this function, whether they are
|
||||
/// Get the total number of basic blocks created in this function, whether they are
|
||||
/// currently inserted in the layout or not.
|
||||
///
|
||||
/// This is intended for use with `SecondaryMap::with_capacity`.
|
||||
pub fn num_ebbs(&self) -> usize {
|
||||
self.ebbs.len()
|
||||
pub fn num_blocks(&self) -> usize {
|
||||
self.blocks.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the given ebb reference is valid.
|
||||
pub fn ebb_is_valid(&self, ebb: Ebb) -> bool {
|
||||
self.ebbs.is_valid(ebb)
|
||||
/// Returns `true` if the given block reference is valid.
|
||||
pub fn block_is_valid(&self, block: Block) -> bool {
|
||||
self.blocks.is_valid(block)
|
||||
}
|
||||
|
||||
/// Get the total number of values.
|
||||
@@ -213,7 +213,7 @@ impl<'a> Iterator for Values<'a> {
|
||||
|
||||
/// Handling values.
|
||||
///
|
||||
/// Values are either EBB parameters or instruction results.
|
||||
/// Values are either block parameters or instruction results.
|
||||
impl DataFlowGraph {
|
||||
/// Allocate an extended value entry.
|
||||
fn make_value(&mut self, data: ValueData) -> Value {
|
||||
@@ -243,12 +243,12 @@ impl DataFlowGraph {
|
||||
|
||||
/// Get the definition of a value.
|
||||
///
|
||||
/// This is either the instruction that defined it or the Ebb that has the value as an
|
||||
/// This is either the instruction that defined it or the Block that has the value as an
|
||||
/// parameter.
|
||||
pub fn value_def(&self, v: Value) -> ValueDef {
|
||||
match self.values[v] {
|
||||
ValueData::Inst { inst, num, .. } => ValueDef::Result(inst, num as usize),
|
||||
ValueData::Param { ebb, num, .. } => ValueDef::Param(ebb, num as usize),
|
||||
ValueData::Param { block, num, .. } => ValueDef::Param(block, num as usize),
|
||||
ValueData::Alias { original, .. } => {
|
||||
// Make sure we only recurse one level. `resolve_aliases` has safeguards to
|
||||
// detect alias loops without overrunning the stack.
|
||||
@@ -257,7 +257,7 @@ impl DataFlowGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if `v` is an attached instruction result / EBB parameter.
|
||||
/// Determine if `v` is an attached instruction result / block parameter.
|
||||
///
|
||||
/// An attached value can't be attached to something else without first being detached.
|
||||
///
|
||||
@@ -267,7 +267,7 @@ impl DataFlowGraph {
|
||||
use self::ValueData::*;
|
||||
match self.values[v] {
|
||||
Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize),
|
||||
Param { ebb, num, .. } => Some(&v) == self.ebb_params(ebb).get(num as usize),
|
||||
Param { block, num, .. } => Some(&v) == self.block_params(block).get(num as usize),
|
||||
Alias { .. } => false,
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ impl DataFlowGraph {
|
||||
/// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest`
|
||||
/// will behave as if they used that value `src`.
|
||||
///
|
||||
/// The `dest` value can't be attached to an instruction or EBB.
|
||||
/// The `dest` value can't be attached to an instruction or block.
|
||||
pub fn change_to_alias(&mut self, dest: Value, src: Value) {
|
||||
debug_assert!(!self.value_is_attached(dest));
|
||||
// Try to create short alias chains by finding the original source value.
|
||||
@@ -376,8 +376,8 @@ impl DataFlowGraph {
|
||||
pub enum ValueDef {
|
||||
/// Value is the n'th result of an instruction.
|
||||
Result(Inst, usize),
|
||||
/// Value is the n'th parameter to an EBB.
|
||||
Param(Ebb, usize),
|
||||
/// Value is the n'th parameter to an block.
|
||||
Param(Block, usize),
|
||||
}
|
||||
|
||||
impl ValueDef {
|
||||
@@ -389,11 +389,11 @@ impl ValueDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwrap the EBB there the parameter is defined, or panic.
|
||||
pub fn unwrap_ebb(&self) -> Ebb {
|
||||
/// Unwrap the block there the parameter is defined, or panic.
|
||||
pub fn unwrap_block(&self) -> Block {
|
||||
match *self {
|
||||
Self::Param(ebb, _) => ebb,
|
||||
_ => panic!("Value is not an EBB parameter"),
|
||||
Self::Param(block, _) => block,
|
||||
_ => panic!("Value is not an block parameter"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,12 +419,12 @@ enum ValueData {
|
||||
/// Value is defined by an instruction.
|
||||
Inst { ty: Type, num: u16, inst: Inst },
|
||||
|
||||
/// Value is an EBB parameter.
|
||||
Param { ty: Type, num: u16, ebb: Ebb },
|
||||
/// Value is an block parameter.
|
||||
Param { ty: Type, num: u16, block: Block },
|
||||
|
||||
/// Value is an alias of another value.
|
||||
/// An alias value can't be linked as an instruction result or EBB parameter. It is used as a
|
||||
/// placeholder when the original instruction or EBB has been rewritten or modified.
|
||||
/// An alias value can't be linked as an instruction result or block parameter. It is used as a
|
||||
/// placeholder when the original instruction or block has been rewritten or modified.
|
||||
Alias { ty: Type, original: Value },
|
||||
}
|
||||
|
||||
@@ -760,61 +760,64 @@ impl IndexMut<Inst> for DataFlowGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extended basic blocks.
|
||||
/// basic blocks.
|
||||
impl DataFlowGraph {
|
||||
/// Create a new basic block.
|
||||
pub fn make_ebb(&mut self) -> Ebb {
|
||||
self.ebbs.push(EbbData::new())
|
||||
pub fn make_block(&mut self) -> Block {
|
||||
self.blocks.push(BlockData::new())
|
||||
}
|
||||
|
||||
/// Get the number of parameters on `ebb`.
|
||||
pub fn num_ebb_params(&self, ebb: Ebb) -> usize {
|
||||
self.ebbs[ebb].params.len(&self.value_lists)
|
||||
/// Get the number of parameters on `block`.
|
||||
pub fn num_block_params(&self, block: Block) -> usize {
|
||||
self.blocks[block].params.len(&self.value_lists)
|
||||
}
|
||||
|
||||
/// Get the parameters on `ebb`.
|
||||
pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
|
||||
self.ebbs[ebb].params.as_slice(&self.value_lists)
|
||||
/// Get the parameters on `block`.
|
||||
pub fn block_params(&self, block: Block) -> &[Value] {
|
||||
self.blocks[block].params.as_slice(&self.value_lists)
|
||||
}
|
||||
|
||||
/// Get the types of the parameters on `ebb`.
|
||||
pub fn ebb_param_types(&self, ebb: Ebb) -> Vec<Type> {
|
||||
self.ebb_params(ebb)
|
||||
/// Get the types of the parameters on `block`.
|
||||
pub fn block_param_types(&self, block: Block) -> Vec<Type> {
|
||||
self.block_params(block)
|
||||
.iter()
|
||||
.map(|&v| self.value_type(v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Append a parameter with type `ty` to `ebb`.
|
||||
pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
|
||||
/// Append a parameter with type `ty` to `block`.
|
||||
pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value {
|
||||
let param = self.values.next_key();
|
||||
let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
|
||||
debug_assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
|
||||
let num = self.blocks[block].params.push(param, &mut self.value_lists);
|
||||
debug_assert!(num <= u16::MAX as usize, "Too many parameters on block");
|
||||
self.make_value(ValueData::Param {
|
||||
ty,
|
||||
num: num as u16,
|
||||
ebb,
|
||||
block,
|
||||
})
|
||||
}
|
||||
|
||||
/// Removes `val` from `ebb`'s parameters by swapping it with the last parameter on `ebb`.
|
||||
/// Removes `val` from `block`'s parameters by swapping it with the last parameter on `block`.
|
||||
/// Returns the position of `val` before removal.
|
||||
///
|
||||
/// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the
|
||||
/// last `ebb` parameter. This can disrupt all the branch instructions jumping to this
|
||||
/// `ebb` for which you have to change the branch argument order if necessary.
|
||||
/// last `block` parameter. This can disrupt all the branch instructions jumping to this
|
||||
/// `block` for which you have to change the branch argument order if necessary.
|
||||
///
|
||||
/// Panics if `val` is not an EBB parameter.
|
||||
pub fn swap_remove_ebb_param(&mut self, val: Value) -> usize {
|
||||
let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
|
||||
(ebb, num)
|
||||
/// Panics if `val` is not an block parameter.
|
||||
pub fn swap_remove_block_param(&mut self, val: Value) -> usize {
|
||||
let (block, num) = if let ValueData::Param { num, block, .. } = self.values[val] {
|
||||
(block, num)
|
||||
} else {
|
||||
panic!("{} must be an EBB parameter", val);
|
||||
panic!("{} must be an block parameter", val);
|
||||
};
|
||||
self.ebbs[ebb]
|
||||
self.blocks[block]
|
||||
.params
|
||||
.swap_remove(num as usize, &mut self.value_lists);
|
||||
if let Some(last_arg_val) = self.ebbs[ebb].params.get(num as usize, &self.value_lists) {
|
||||
if let Some(last_arg_val) = self.blocks[block]
|
||||
.params
|
||||
.get(num as usize, &self.value_lists)
|
||||
{
|
||||
// We update the position of the old last arg.
|
||||
if let ValueData::Param {
|
||||
num: ref mut old_num,
|
||||
@@ -823,25 +826,25 @@ impl DataFlowGraph {
|
||||
{
|
||||
*old_num = num;
|
||||
} else {
|
||||
panic!("{} should be an Ebb parameter", last_arg_val);
|
||||
panic!("{} should be an Block parameter", last_arg_val);
|
||||
}
|
||||
}
|
||||
num as usize
|
||||
}
|
||||
|
||||
/// Removes `val` from `ebb`'s parameters by a standard linear time list removal which
|
||||
/// Removes `val` from `block`'s parameters by a standard linear time list removal which
|
||||
/// preserves ordering. Also updates the values' data.
|
||||
pub fn remove_ebb_param(&mut self, val: Value) {
|
||||
let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
|
||||
(ebb, num)
|
||||
pub fn remove_block_param(&mut self, val: Value) {
|
||||
let (block, num) = if let ValueData::Param { num, block, .. } = self.values[val] {
|
||||
(block, num)
|
||||
} else {
|
||||
panic!("{} must be an EBB parameter", val);
|
||||
panic!("{} must be an block parameter", val);
|
||||
};
|
||||
self.ebbs[ebb]
|
||||
self.blocks[block]
|
||||
.params
|
||||
.remove(num as usize, &mut self.value_lists);
|
||||
for index in num..(self.num_ebb_params(ebb) as u16) {
|
||||
match self.values[self.ebbs[ebb]
|
||||
for index in num..(self.num_block_params(block) as u16) {
|
||||
match self.values[self.blocks[block]
|
||||
.params
|
||||
.get(index as usize, &self.value_lists)
|
||||
.unwrap()]
|
||||
@@ -850,8 +853,8 @@ impl DataFlowGraph {
|
||||
*num -= 1;
|
||||
}
|
||||
_ => panic!(
|
||||
"{} must be an EBB parameter",
|
||||
self.ebbs[ebb]
|
||||
"{} must be an block parameter",
|
||||
self.blocks[block]
|
||||
.params
|
||||
.get(index as usize, &self.value_lists)
|
||||
.unwrap()
|
||||
@@ -860,71 +863,73 @@ impl DataFlowGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// Append an existing value to `ebb`'s parameters.
|
||||
/// Append an existing value to `block`'s parameters.
|
||||
///
|
||||
/// The appended value can't already be attached to something else.
|
||||
///
|
||||
/// In almost all cases, you should be using `append_ebb_param()` instead of this method.
|
||||
pub fn attach_ebb_param(&mut self, ebb: Ebb, param: Value) {
|
||||
/// In almost all cases, you should be using `append_block_param()` instead of this method.
|
||||
pub fn attach_block_param(&mut self, block: Block, param: Value) {
|
||||
debug_assert!(!self.value_is_attached(param));
|
||||
let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
|
||||
debug_assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
|
||||
let num = self.blocks[block].params.push(param, &mut self.value_lists);
|
||||
debug_assert!(num <= u16::MAX as usize, "Too many parameters on block");
|
||||
let ty = self.value_type(param);
|
||||
self.values[param] = ValueData::Param {
|
||||
ty,
|
||||
num: num as u16,
|
||||
ebb,
|
||||
block,
|
||||
};
|
||||
}
|
||||
|
||||
/// Replace an EBB parameter with a new value of type `ty`.
|
||||
/// Replace an block parameter with a new value of type `ty`.
|
||||
///
|
||||
/// The `old_value` must be an attached EBB parameter. It is removed from its place in the list
|
||||
/// The `old_value` must be an attached block parameter. It is removed from its place in the list
|
||||
/// of parameters and replaced by a new value of type `new_type`. The new value gets the same
|
||||
/// position in the list, and other parameters are not disturbed.
|
||||
///
|
||||
/// The old value is left detached, so it should probably be changed into something else.
|
||||
///
|
||||
/// Returns the new value.
|
||||
pub fn replace_ebb_param(&mut self, old_value: Value, new_type: Type) -> Value {
|
||||
pub fn replace_block_param(&mut self, old_value: Value, new_type: Type) -> Value {
|
||||
// Create new value identical to the old one except for the type.
|
||||
let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[old_value] {
|
||||
(ebb, num)
|
||||
let (block, num) = if let ValueData::Param { num, block, .. } = self.values[old_value] {
|
||||
(block, num)
|
||||
} else {
|
||||
panic!("{} must be an EBB parameter", old_value);
|
||||
panic!("{} must be an block parameter", old_value);
|
||||
};
|
||||
let new_arg = self.make_value(ValueData::Param {
|
||||
ty: new_type,
|
||||
num,
|
||||
ebb,
|
||||
block,
|
||||
});
|
||||
|
||||
self.ebbs[ebb].params.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg;
|
||||
self.blocks[block]
|
||||
.params
|
||||
.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg;
|
||||
new_arg
|
||||
}
|
||||
|
||||
/// Detach all the parameters from `ebb` and return them as a `ValueList`.
|
||||
/// Detach all the parameters from `block` and return them as a `ValueList`.
|
||||
///
|
||||
/// This is a quite low-level operation. Sensible things to do with the detached EBB parameters
|
||||
/// is to put them back on the same EBB with `attach_ebb_param()` or change them into aliases
|
||||
/// This is a quite low-level operation. Sensible things to do with the detached block parameters
|
||||
/// is to put them back on the same block with `attach_block_param()` or change them into aliases
|
||||
/// with `change_to_alias()`.
|
||||
pub fn detach_ebb_params(&mut self, ebb: Ebb) -> ValueList {
|
||||
self.ebbs[ebb].params.take()
|
||||
pub fn detach_block_params(&mut self, block: Block) -> ValueList {
|
||||
self.blocks[block].params.take()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contents of an extended basic block.
|
||||
/// Contents of a basic block.
|
||||
///
|
||||
/// Parameters on an extended basic block are values that dominate everything in the EBB. All
|
||||
/// branches to this EBB must provide matching arguments, and the arguments to the entry EBB must
|
||||
/// Parameters on a basic block are values that dominate everything in the block. All
|
||||
/// branches to this block must provide matching arguments, and the arguments to the entry block must
|
||||
/// match the function arguments.
|
||||
#[derive(Clone)]
|
||||
struct EbbData {
|
||||
/// List of parameters to this EBB.
|
||||
struct BlockData {
|
||||
/// List of parameters to this block.
|
||||
params: ValueList,
|
||||
}
|
||||
|
||||
impl EbbData {
|
||||
impl BlockData {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
params: ValueList::new(),
|
||||
@@ -1012,17 +1017,17 @@ impl DataFlowGraph {
|
||||
self.make_inst_results_reusing(inst, ctrl_typevar, reuse.iter().map(|x| Some(*x)))
|
||||
}
|
||||
|
||||
/// Similar to `append_ebb_param`, append a parameter with type `ty` to
|
||||
/// `ebb`, but using value `val`. This is only for use by the parser to
|
||||
/// Similar to `append_block_param`, append a parameter with type `ty` to
|
||||
/// `block`, but using value `val`. This is only for use by the parser to
|
||||
/// create parameters with specific values.
|
||||
#[cold]
|
||||
pub fn append_ebb_param_for_parser(&mut self, ebb: Ebb, ty: Type, val: Value) {
|
||||
let num = self.ebbs[ebb].params.push(val, &mut self.value_lists);
|
||||
assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
|
||||
pub fn append_block_param_for_parser(&mut self, block: Block, ty: Type, val: Value) {
|
||||
let num = self.blocks[block].params.push(val, &mut self.value_lists);
|
||||
assert!(num <= u16::MAX as usize, "Too many parameters on block");
|
||||
self.values[val] = ValueData::Param {
|
||||
ty,
|
||||
num: num as u16,
|
||||
ebb,
|
||||
block,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1165,95 +1170,95 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ebb() {
|
||||
fn block() {
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
|
||||
let ebb = dfg.make_ebb();
|
||||
assert_eq!(ebb.to_string(), "ebb0");
|
||||
assert_eq!(dfg.num_ebb_params(ebb), 0);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[]);
|
||||
assert!(dfg.detach_ebb_params(ebb).is_empty());
|
||||
assert_eq!(dfg.num_ebb_params(ebb), 0);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[]);
|
||||
let block = dfg.make_block();
|
||||
assert_eq!(block.to_string(), "block0");
|
||||
assert_eq!(dfg.num_block_params(block), 0);
|
||||
assert_eq!(dfg.block_params(block), &[]);
|
||||
assert!(dfg.detach_block_params(block).is_empty());
|
||||
assert_eq!(dfg.num_block_params(block), 0);
|
||||
assert_eq!(dfg.block_params(block), &[]);
|
||||
|
||||
let arg1 = dfg.append_ebb_param(ebb, types::F32);
|
||||
let arg1 = dfg.append_block_param(block, types::F32);
|
||||
assert_eq!(arg1.to_string(), "v0");
|
||||
assert_eq!(dfg.num_ebb_params(ebb), 1);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg1]);
|
||||
assert_eq!(dfg.num_block_params(block), 1);
|
||||
assert_eq!(dfg.block_params(block), &[arg1]);
|
||||
|
||||
let arg2 = dfg.append_ebb_param(ebb, types::I16);
|
||||
let arg2 = dfg.append_block_param(block, types::I16);
|
||||
assert_eq!(arg2.to_string(), "v1");
|
||||
assert_eq!(dfg.num_ebb_params(ebb), 2);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2]);
|
||||
assert_eq!(dfg.num_block_params(block), 2);
|
||||
assert_eq!(dfg.block_params(block), &[arg1, arg2]);
|
||||
|
||||
assert_eq!(dfg.value_def(arg1), ValueDef::Param(ebb, 0));
|
||||
assert_eq!(dfg.value_def(arg2), ValueDef::Param(ebb, 1));
|
||||
assert_eq!(dfg.value_def(arg1), ValueDef::Param(block, 0));
|
||||
assert_eq!(dfg.value_def(arg2), ValueDef::Param(block, 1));
|
||||
assert_eq!(dfg.value_type(arg1), types::F32);
|
||||
assert_eq!(dfg.value_type(arg2), types::I16);
|
||||
|
||||
// Swap the two EBB parameters.
|
||||
let vlist = dfg.detach_ebb_params(ebb);
|
||||
assert_eq!(dfg.num_ebb_params(ebb), 0);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[]);
|
||||
// Swap the two block parameters.
|
||||
let vlist = dfg.detach_block_params(block);
|
||||
assert_eq!(dfg.num_block_params(block), 0);
|
||||
assert_eq!(dfg.block_params(block), &[]);
|
||||
assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]);
|
||||
dfg.attach_ebb_param(ebb, arg2);
|
||||
let arg3 = dfg.append_ebb_param(ebb, types::I32);
|
||||
dfg.attach_ebb_param(ebb, arg1);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg2, arg3, arg1]);
|
||||
dfg.attach_block_param(block, arg2);
|
||||
let arg3 = dfg.append_block_param(block, types::I32);
|
||||
dfg.attach_block_param(block, arg1);
|
||||
assert_eq!(dfg.block_params(block), &[arg2, arg3, arg1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_ebb_params() {
|
||||
fn replace_block_params() {
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
|
||||
let ebb = dfg.make_ebb();
|
||||
let arg1 = dfg.append_ebb_param(ebb, types::F32);
|
||||
let block = dfg.make_block();
|
||||
let arg1 = dfg.append_block_param(block, types::F32);
|
||||
|
||||
let new1 = dfg.replace_ebb_param(arg1, types::I64);
|
||||
let new1 = dfg.replace_block_param(arg1, types::I64);
|
||||
assert_eq!(dfg.value_type(arg1), types::F32);
|
||||
assert_eq!(dfg.value_type(new1), types::I64);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[new1]);
|
||||
assert_eq!(dfg.block_params(block), &[new1]);
|
||||
|
||||
dfg.attach_ebb_param(ebb, arg1);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[new1, arg1]);
|
||||
dfg.attach_block_param(block, arg1);
|
||||
assert_eq!(dfg.block_params(block), &[new1, arg1]);
|
||||
|
||||
let new2 = dfg.replace_ebb_param(arg1, types::I8);
|
||||
let new2 = dfg.replace_block_param(arg1, types::I8);
|
||||
assert_eq!(dfg.value_type(arg1), types::F32);
|
||||
assert_eq!(dfg.value_type(new2), types::I8);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[new1, new2]);
|
||||
assert_eq!(dfg.block_params(block), &[new1, new2]);
|
||||
|
||||
dfg.attach_ebb_param(ebb, arg1);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[new1, new2, arg1]);
|
||||
dfg.attach_block_param(block, arg1);
|
||||
assert_eq!(dfg.block_params(block), &[new1, new2, arg1]);
|
||||
|
||||
let new3 = dfg.replace_ebb_param(new2, types::I16);
|
||||
let new3 = dfg.replace_block_param(new2, types::I16);
|
||||
assert_eq!(dfg.value_type(new1), types::I64);
|
||||
assert_eq!(dfg.value_type(new2), types::I8);
|
||||
assert_eq!(dfg.value_type(new3), types::I16);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[new1, new3, arg1]);
|
||||
assert_eq!(dfg.block_params(block), &[new1, new3, arg1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_remove_ebb_params() {
|
||||
fn swap_remove_block_params() {
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
|
||||
let ebb = dfg.make_ebb();
|
||||
let arg1 = dfg.append_ebb_param(ebb, types::F32);
|
||||
let arg2 = dfg.append_ebb_param(ebb, types::F32);
|
||||
let arg3 = dfg.append_ebb_param(ebb, types::F32);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2, arg3]);
|
||||
let block = dfg.make_block();
|
||||
let arg1 = dfg.append_block_param(block, types::F32);
|
||||
let arg2 = dfg.append_block_param(block, types::F32);
|
||||
let arg3 = dfg.append_block_param(block, types::F32);
|
||||
assert_eq!(dfg.block_params(block), &[arg1, arg2, arg3]);
|
||||
|
||||
dfg.swap_remove_ebb_param(arg1);
|
||||
dfg.swap_remove_block_param(arg1);
|
||||
assert_eq!(dfg.value_is_attached(arg1), false);
|
||||
assert_eq!(dfg.value_is_attached(arg2), true);
|
||||
assert_eq!(dfg.value_is_attached(arg3), true);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg3, arg2]);
|
||||
dfg.swap_remove_ebb_param(arg2);
|
||||
assert_eq!(dfg.block_params(block), &[arg3, arg2]);
|
||||
dfg.swap_remove_block_param(arg2);
|
||||
assert_eq!(dfg.value_is_attached(arg2), false);
|
||||
assert_eq!(dfg.value_is_attached(arg3), true);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[arg3]);
|
||||
dfg.swap_remove_ebb_param(arg3);
|
||||
assert_eq!(dfg.block_params(block), &[arg3]);
|
||||
dfg.swap_remove_block_param(arg3);
|
||||
assert_eq!(dfg.value_is_attached(arg3), false);
|
||||
assert_eq!(dfg.ebb_params(ebb), &[]);
|
||||
assert_eq!(dfg.block_params(block), &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1261,9 +1266,9 @@ mod tests {
|
||||
use crate::ir::InstBuilder;
|
||||
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let block0 = func.dfg.make_block();
|
||||
let mut pos = FuncCursor::new(&mut func);
|
||||
pos.insert_ebb(ebb0);
|
||||
pos.insert_block(block0);
|
||||
|
||||
// Build a little test program.
|
||||
let v1 = pos.ins().iconst(types::I32, 42);
|
||||
@@ -1271,7 +1276,7 @@ mod tests {
|
||||
// Make sure we can resolve value aliases even when values is empty.
|
||||
assert_eq!(pos.func.dfg.resolve_aliases(v1), v1);
|
||||
|
||||
let arg0 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
|
||||
let arg0 = pos.func.dfg.append_block_param(block0, types::I32);
|
||||
let (s, c) = pos.ins().iadd_ifcout(v1, arg0);
|
||||
let iadd = match pos.func.dfg.value_def(s) {
|
||||
ValueDef::Result(i, 0) => i,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Cranelift IR entity references.
|
||||
//!
|
||||
//! Instructions in Cranelift IR need to reference other entities in the function. This can be other
|
||||
//! parts of the function like extended basic blocks or stack slots, or it can be external entities
|
||||
//! parts of the function like basic blocks or stack slots, or it can be external entities
|
||||
//! that are declared in the function preamble in the text format.
|
||||
//!
|
||||
//! These entity references in instruction operands are not implemented as Rust references both
|
||||
@@ -25,20 +25,19 @@ use core::u32;
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An opaque reference to an [extended basic
|
||||
/// block](https://en.wikipedia.org/wiki/Extended_basic_block) in a
|
||||
/// An opaque reference to a [basic block](https://en.wikipedia.org/wiki/Basic_block) in a
|
||||
/// [`Function`](super::function::Function).
|
||||
///
|
||||
/// You can get an `Ebb` using
|
||||
/// [`FunctionBuilder::create_ebb`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_ebb)
|
||||
/// You can get a `Block` using
|
||||
/// [`FunctionBuilder::create_block`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_block)
|
||||
///
|
||||
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Ebb(u32);
|
||||
entity_impl!(Ebb, "ebb");
|
||||
pub struct Block(u32);
|
||||
entity_impl!(Block, "block");
|
||||
|
||||
impl Ebb {
|
||||
/// Create a new EBB reference from its number. This corresponds to the `ebbNN` representation.
|
||||
impl Block {
|
||||
/// Create a new block reference from its number. This corresponds to the `blockNN` representation.
|
||||
///
|
||||
/// This method is for use by the parser.
|
||||
pub fn with_number(n: u32) -> Option<Self> {
|
||||
@@ -371,8 +370,8 @@ impl Table {
|
||||
pub enum AnyEntity {
|
||||
/// The whole function.
|
||||
Function,
|
||||
/// An extended basic block.
|
||||
Ebb(Ebb),
|
||||
/// a basic block.
|
||||
Block(Block),
|
||||
/// An instruction.
|
||||
Inst(Inst),
|
||||
/// An SSA value.
|
||||
@@ -397,7 +396,7 @@ impl fmt::Display for AnyEntity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Self::Function => write!(f, "function"),
|
||||
Self::Ebb(r) => r.fmt(f),
|
||||
Self::Block(r) => r.fmt(f),
|
||||
Self::Inst(r) => r.fmt(f),
|
||||
Self::Value(r) => r.fmt(f),
|
||||
Self::StackSlot(r) => r.fmt(f),
|
||||
@@ -417,9 +416,9 @@ impl fmt::Debug for AnyEntity {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ebb> for AnyEntity {
|
||||
fn from(r: Ebb) -> Self {
|
||||
Self::Ebb(r)
|
||||
impl From<Block> for AnyEntity {
|
||||
fn from(r: Block) -> Self {
|
||||
Self::Block(r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ pub enum ExternalName {
|
||||
/// Arbitrary.
|
||||
index: u32,
|
||||
},
|
||||
/// A test case function name of up to 10 ascii characters. This is
|
||||
/// not intended to be used outside test cases.
|
||||
/// A test case function name of up to a hardcoded amount of ascii
|
||||
/// characters. This is not intended to be used outside test cases.
|
||||
TestCase {
|
||||
/// How many of the bytes in `ascii` are valid?
|
||||
length: u8,
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//! Intermediate representation of a function.
|
||||
//!
|
||||
//! The `Function` struct defined in this module owns all of its extended basic blocks and
|
||||
//! The `Function` struct defined in this module owns all of its basic blocks and
|
||||
//! instructions.
|
||||
|
||||
use crate::binemit::CodeOffset;
|
||||
use crate::entity::{PrimaryMap, SecondaryMap};
|
||||
use crate::ir;
|
||||
use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature};
|
||||
use crate::ir::{
|
||||
Ebb, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable,
|
||||
Block, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable,
|
||||
JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData,
|
||||
};
|
||||
use crate::ir::{EbbOffsets, FrameLayout, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
||||
use crate::ir::{BlockOffsets, FrameLayout, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
||||
use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature};
|
||||
use crate::ir::{JumpTableOffsets, JumpTables};
|
||||
use crate::isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa};
|
||||
use crate::regalloc::{EntryRegDiversions, RegDiversions};
|
||||
@@ -50,10 +50,10 @@ pub struct Function {
|
||||
/// Jump tables used in this function.
|
||||
pub jump_tables: JumpTables,
|
||||
|
||||
/// Data flow graph containing the primary definition of all instructions, EBBs and values.
|
||||
/// Data flow graph containing the primary definition of all instructions, blocks and values.
|
||||
pub dfg: DataFlowGraph,
|
||||
|
||||
/// Layout of EBBs and instructions in the function body.
|
||||
/// Layout of blocks and instructions in the function body.
|
||||
pub layout: Layout,
|
||||
|
||||
/// Encoding recipe and bits for the legal instructions.
|
||||
@@ -69,12 +69,12 @@ pub struct Function {
|
||||
/// ValueLocation. This field records these register-to-register moves as Diversions.
|
||||
pub entry_diversions: EntryRegDiversions,
|
||||
|
||||
/// Code offsets of the EBB headers.
|
||||
/// Code offsets of the block headers.
|
||||
///
|
||||
/// This information is only transiently available after the `binemit::relax_branches` function
|
||||
/// computes it, and it can easily be recomputed by calling that function. It is not included
|
||||
/// in the textual IR format.
|
||||
pub offsets: EbbOffsets,
|
||||
pub offsets: BlockOffsets,
|
||||
|
||||
/// Code offsets of Jump Table headers.
|
||||
pub jt_offsets: JumpTableOffsets,
|
||||
@@ -207,10 +207,10 @@ impl Function {
|
||||
let entry = self.layout.entry_block().expect("Function is empty");
|
||||
self.signature
|
||||
.special_param_index(purpose)
|
||||
.map(|i| self.dfg.ebb_params(entry)[i])
|
||||
.map(|i| self.dfg.block_params(entry)[i])
|
||||
}
|
||||
|
||||
/// Get an iterator over the instructions in `ebb`, including offsets and encoded instruction
|
||||
/// Get an iterator over the instructions in `block`, including offsets and encoded instruction
|
||||
/// sizes.
|
||||
///
|
||||
/// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes
|
||||
@@ -219,20 +219,20 @@ impl Function {
|
||||
///
|
||||
/// This function can only be used after the code layout has been computed by the
|
||||
/// `binemit::relax_branches()` function.
|
||||
pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
|
||||
pub fn inst_offsets<'a>(&'a self, block: Block, encinfo: &EncInfo) -> InstOffsetIter<'a> {
|
||||
assert!(
|
||||
!self.offsets.is_empty(),
|
||||
"Code layout must be computed first"
|
||||
);
|
||||
let mut divert = RegDiversions::new();
|
||||
divert.at_ebb(&self.entry_diversions, ebb);
|
||||
divert.at_block(&self.entry_diversions, block);
|
||||
InstOffsetIter {
|
||||
encinfo: encinfo.clone(),
|
||||
func: self,
|
||||
divert,
|
||||
encodings: &self.encodings,
|
||||
offset: self.offsets[ebb],
|
||||
iter: self.layout.ebb_insts(ebb),
|
||||
offset: self.offsets[block],
|
||||
iter: self.layout.block_insts(block),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,19 +260,19 @@ impl Function {
|
||||
|
||||
/// Changes the destination of a jump or branch instruction.
|
||||
/// Does nothing if called with a non-jump or non-branch instruction.
|
||||
pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Ebb) {
|
||||
pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) {
|
||||
match self.dfg[inst].branch_destination_mut() {
|
||||
None => (),
|
||||
Some(inst_dest) => *inst_dest = new_dest,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the specified EBB can be encoded as a basic block.
|
||||
/// Checks that the specified block can be encoded as a basic block.
|
||||
///
|
||||
/// On error, returns the first invalid instruction and an error message.
|
||||
pub fn is_ebb_basic(&self, ebb: Ebb) -> Result<(), (Inst, &'static str)> {
|
||||
pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> {
|
||||
let dfg = &self.dfg;
|
||||
let inst_iter = self.layout.ebb_insts(ebb);
|
||||
let inst_iter = self.layout.block_insts(block);
|
||||
|
||||
// Ignore all instructions prior to the first branch.
|
||||
let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch());
|
||||
|
||||
@@ -13,7 +13,7 @@ use core::str::FromStr;
|
||||
|
||||
use crate::ir;
|
||||
use crate::ir::types;
|
||||
use crate::ir::{Ebb, FuncRef, JumpTable, SigRef, Type, Value};
|
||||
use crate::ir::{Block, FuncRef, JumpTable, SigRef, Type, Value};
|
||||
use crate::isa;
|
||||
|
||||
use crate::bitset::BitSet;
|
||||
@@ -164,7 +164,7 @@ impl Default for VariableArgs {
|
||||
impl InstructionData {
|
||||
/// Return information about the destination of a branch or jump instruction.
|
||||
///
|
||||
/// Any instruction that can transfer control to another EBB reveals its possible destinations
|
||||
/// Any instruction that can transfer control to another block reveals its possible destinations
|
||||
/// here.
|
||||
pub fn analyze_branch<'a>(&'a self, pool: &'a ValueListPool) -> BranchInfo<'a> {
|
||||
match *self {
|
||||
@@ -208,7 +208,7 @@ impl InstructionData {
|
||||
/// branch or jump.
|
||||
///
|
||||
/// Multi-destination branches like `br_table` return `None`.
|
||||
pub fn branch_destination(&self) -> Option<Ebb> {
|
||||
pub fn branch_destination(&self) -> Option<Block> {
|
||||
match *self {
|
||||
Self::Jump { destination, .. }
|
||||
| Self::Branch { destination, .. }
|
||||
@@ -227,7 +227,7 @@ impl InstructionData {
|
||||
/// single destination branch or jump.
|
||||
///
|
||||
/// Multi-destination branches like `br_table` return `None`.
|
||||
pub fn branch_destination_mut(&mut self) -> Option<&mut Ebb> {
|
||||
pub fn branch_destination_mut(&mut self) -> Option<&mut Block> {
|
||||
match *self {
|
||||
Self::Jump {
|
||||
ref mut destination,
|
||||
@@ -279,15 +279,15 @@ impl InstructionData {
|
||||
/// Information about branch and jump instructions.
|
||||
pub enum BranchInfo<'a> {
|
||||
/// This is not a branch or jump instruction.
|
||||
/// This instruction will not transfer control to another EBB in the function, but it may still
|
||||
/// This instruction will not transfer control to another block in the function, but it may still
|
||||
/// affect control flow by returning or trapping.
|
||||
NotABranch,
|
||||
|
||||
/// This is a branch or jump to a single destination EBB, possibly taking value arguments.
|
||||
SingleDest(Ebb, &'a [Value]),
|
||||
/// This is a branch or jump to a single destination block, possibly taking value arguments.
|
||||
SingleDest(Block, &'a [Value]),
|
||||
|
||||
/// This is a jump table branch which can have many destination EBBs and maybe one default EBB.
|
||||
Table(JumpTable, Option<Ebb>),
|
||||
/// This is a jump table branch which can have many destination blocks and maybe one default block.
|
||||
Table(JumpTable, Option<Block>),
|
||||
}
|
||||
|
||||
/// Information about call instructions.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
|
||||
//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
|
||||
|
||||
use crate::ir::entities::Ebb;
|
||||
use crate::ir::entities::Block;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Display, Formatter};
|
||||
use core::slice::{Iter, IterMut};
|
||||
@@ -14,7 +14,7 @@ use core::slice::{Iter, IterMut};
|
||||
#[derive(Clone)]
|
||||
pub struct JumpTableData {
|
||||
// Table entries.
|
||||
table: Vec<Ebb>,
|
||||
table: Vec<Block>,
|
||||
}
|
||||
|
||||
impl JumpTableData {
|
||||
@@ -36,32 +36,32 @@ impl JumpTableData {
|
||||
}
|
||||
|
||||
/// Append a table entry.
|
||||
pub fn push_entry(&mut self, dest: Ebb) {
|
||||
pub fn push_entry(&mut self, dest: Block) {
|
||||
self.table.push(dest)
|
||||
}
|
||||
|
||||
/// Checks if any of the entries branch to `ebb`.
|
||||
pub fn branches_to(&self, ebb: Ebb) -> bool {
|
||||
self.table.iter().any(|target_ebb| *target_ebb == ebb)
|
||||
/// Checks if any of the entries branch to `block`.
|
||||
pub fn branches_to(&self, block: Block) -> bool {
|
||||
self.table.iter().any(|target_block| *target_block == block)
|
||||
}
|
||||
|
||||
/// Access the whole table as a slice.
|
||||
pub fn as_slice(&self) -> &[Ebb] {
|
||||
pub fn as_slice(&self) -> &[Block] {
|
||||
self.table.as_slice()
|
||||
}
|
||||
|
||||
/// Access the whole table as a mutable slice.
|
||||
pub fn as_mut_slice(&mut self) -> &mut [Ebb] {
|
||||
pub fn as_mut_slice(&mut self) -> &mut [Block] {
|
||||
self.table.as_mut_slice()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the table.
|
||||
pub fn iter(&self) -> Iter<Ebb> {
|
||||
pub fn iter(&self) -> Iter<Block> {
|
||||
self.table.iter()
|
||||
}
|
||||
|
||||
/// Returns an iterator that allows modifying each value.
|
||||
pub fn iter_mut(&mut self) -> IterMut<Ebb> {
|
||||
pub fn iter_mut(&mut self) -> IterMut<Block> {
|
||||
self.table.iter_mut()
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,8 @@ impl Display for JumpTableData {
|
||||
None => (),
|
||||
Some(first) => write!(fmt, "{}", first)?,
|
||||
}
|
||||
for ebb in self.table.iter().skip(1) {
|
||||
write!(fmt, ", {}", ebb)?;
|
||||
for block in self.table.iter().skip(1) {
|
||||
write!(fmt, ", {}", block)?;
|
||||
}
|
||||
write!(fmt, "]")
|
||||
}
|
||||
@@ -84,7 +84,7 @@ impl Display for JumpTableData {
|
||||
mod tests {
|
||||
use super::JumpTableData;
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir::Ebb;
|
||||
use crate::ir::Block;
|
||||
use alloc::string::ToString;
|
||||
|
||||
#[test]
|
||||
@@ -102,8 +102,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn insert() {
|
||||
let e1 = Ebb::new(1);
|
||||
let e2 = Ebb::new(2);
|
||||
let e1 = Block::new(1);
|
||||
let e2 = Block::new(2);
|
||||
|
||||
let mut jt = JumpTableData::new();
|
||||
|
||||
@@ -111,7 +111,7 @@ mod tests {
|
||||
jt.push_entry(e2);
|
||||
jt.push_entry(e1);
|
||||
|
||||
assert_eq!(jt.to_string(), "jump_table [ebb1, ebb2, ebb1]");
|
||||
assert_eq!(jt.to_string(), "jump_table [block1, block2, block1]");
|
||||
|
||||
let v = jt.as_slice();
|
||||
assert_eq!(v, [e1, e2, e1]);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@ pub use crate::ir::builder::{
|
||||
pub use crate::ir::constant::{ConstantData, ConstantOffset, ConstantPool};
|
||||
pub use crate::ir::dfg::{DataFlowGraph, ValueDef};
|
||||
pub use crate::ir::entities::{
|
||||
Constant, Ebb, FuncRef, GlobalValue, Heap, Immediate, Inst, JumpTable, SigRef, StackSlot,
|
||||
Block, Constant, FuncRef, GlobalValue, Heap, Immediate, Inst, JumpTable, SigRef, StackSlot,
|
||||
Table, Value,
|
||||
};
|
||||
pub use crate::ir::extfunc::{
|
||||
@@ -73,8 +73,8 @@ pub type JumpTables = PrimaryMap<JumpTable, JumpTableData>;
|
||||
/// Map of instruction encodings.
|
||||
pub type InstEncodings = SecondaryMap<Inst, isa::Encoding>;
|
||||
|
||||
/// Code offsets for EBBs.
|
||||
pub type EbbOffsets = SecondaryMap<Ebb, binemit::CodeOffset>;
|
||||
/// Code offsets for blocks.
|
||||
pub type BlockOffsets = SecondaryMap<Block, binemit::CodeOffset>;
|
||||
|
||||
/// Code offsets for Jump Tables.
|
||||
pub type JumpTableOffsets = SecondaryMap<JumpTable, binemit::CodeOffset>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Program points.
|
||||
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir::{Ebb, Inst, ValueDef};
|
||||
use crate::ir::{Block, Inst, ValueDef};
|
||||
use core::cmp;
|
||||
use core::fmt;
|
||||
use core::u32;
|
||||
@@ -10,7 +10,7 @@ use core::u32;
|
||||
/// begin or end. It can be either:
|
||||
///
|
||||
/// 1. An instruction or
|
||||
/// 2. An EBB header.
|
||||
/// 2. An block header.
|
||||
///
|
||||
/// This corresponds more or less to the lines in the textual form of Cranelift IR.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
@@ -24,9 +24,9 @@ impl From<Inst> for ProgramPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ebb> for ProgramPoint {
|
||||
fn from(ebb: Ebb) -> Self {
|
||||
let idx = ebb.index();
|
||||
impl From<Block> for ProgramPoint {
|
||||
fn from(block: Block) -> Self {
|
||||
let idx = block.index();
|
||||
debug_assert!(idx < (u32::MAX / 2) as usize);
|
||||
Self((idx * 2 + 1) as u32)
|
||||
}
|
||||
@@ -36,7 +36,7 @@ impl From<ValueDef> for ProgramPoint {
|
||||
fn from(def: ValueDef) -> Self {
|
||||
match def {
|
||||
ValueDef::Result(inst, _) => inst.into(),
|
||||
ValueDef::Param(ebb, _) => ebb.into(),
|
||||
ValueDef::Param(block, _) => block.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,8 +47,8 @@ impl From<ValueDef> for ProgramPoint {
|
||||
pub enum ExpandedProgramPoint {
|
||||
/// An instruction in the function.
|
||||
Inst(Inst),
|
||||
/// An EBB header.
|
||||
Ebb(Ebb),
|
||||
/// An block header.
|
||||
Block(Block),
|
||||
}
|
||||
|
||||
impl ExpandedProgramPoint {
|
||||
@@ -56,7 +56,7 @@ impl ExpandedProgramPoint {
|
||||
pub fn unwrap_inst(self) -> Inst {
|
||||
match self {
|
||||
Self::Inst(x) => x,
|
||||
Self::Ebb(x) => panic!("expected inst: {}", x),
|
||||
Self::Block(x) => panic!("expected inst: {}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,9 +67,9 @@ impl From<Inst> for ExpandedProgramPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ebb> for ExpandedProgramPoint {
|
||||
fn from(ebb: Ebb) -> Self {
|
||||
Self::Ebb(ebb)
|
||||
impl From<Block> for ExpandedProgramPoint {
|
||||
fn from(block: Block) -> Self {
|
||||
Self::Block(block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl From<ValueDef> for ExpandedProgramPoint {
|
||||
fn from(def: ValueDef) -> Self {
|
||||
match def {
|
||||
ValueDef::Result(inst, _) => inst.into(),
|
||||
ValueDef::Param(ebb, _) => ebb.into(),
|
||||
ValueDef::Param(block, _) => block.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ impl From<ProgramPoint> for ExpandedProgramPoint {
|
||||
if pp.0 & 1 == 0 {
|
||||
Self::Inst(Inst::from_u32(pp.0 / 2))
|
||||
} else {
|
||||
Self::Ebb(Ebb::from_u32(pp.0 / 2))
|
||||
Self::Block(Block::from_u32(pp.0 / 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ impl fmt::Display for ExpandedProgramPoint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Self::Inst(x) => write!(f, "{}", x),
|
||||
Self::Ebb(x) => write!(f, "{}", x),
|
||||
Self::Block(x) => write!(f, "{}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ pub trait ProgramOrder {
|
||||
///
|
||||
/// Return `Less` if `a` appears in the program before `b`.
|
||||
///
|
||||
/// This is declared as a generic such that it can be called with `Inst` and `Ebb` arguments
|
||||
/// This is declared as a generic such that it can be called with `Inst` and `Block` arguments
|
||||
/// directly. Depending on the implementation, there is a good chance performance will be
|
||||
/// improved for those cases where the type of either argument is known statically.
|
||||
fn cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
|
||||
@@ -137,28 +137,28 @@ pub trait ProgramOrder {
|
||||
A: Into<ExpandedProgramPoint>,
|
||||
B: Into<ExpandedProgramPoint>;
|
||||
|
||||
/// Is the range from `inst` to `ebb` just the gap between consecutive EBBs?
|
||||
/// Is the range from `inst` to `block` just the gap between consecutive blocks?
|
||||
///
|
||||
/// This returns true if `inst` is the terminator in the EBB immediately before `ebb`.
|
||||
fn is_ebb_gap(&self, inst: Inst, ebb: Ebb) -> bool;
|
||||
/// This returns true if `inst` is the terminator in the block immediately before `block`.
|
||||
fn is_block_gap(&self, inst: Inst, block: Block) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::entity::EntityRef;
|
||||
use crate::ir::{Ebb, Inst};
|
||||
use crate::ir::{Block, Inst};
|
||||
use alloc::string::ToString;
|
||||
|
||||
#[test]
|
||||
fn convert() {
|
||||
let i5 = Inst::new(5);
|
||||
let b3 = Ebb::new(3);
|
||||
let b3 = Block::new(3);
|
||||
|
||||
let pp1: ProgramPoint = i5.into();
|
||||
let pp2: ProgramPoint = b3.into();
|
||||
|
||||
assert_eq!(pp1.to_string(), "inst5");
|
||||
assert_eq!(pp2.to_string(), "ebb3");
|
||||
assert_eq!(pp2.to_string(), "block3");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user