Rename 'an block' to 'a block'
Missed this in the automatic rename of 'Ebb' to 'Block'.
This commit is contained in:
@@ -74,7 +74,7 @@ impl<'a> MemoryCodeSink<'a> {
|
||||
|
||||
/// A trait for receiving relocations for code that is emitted directly into memory.
|
||||
pub trait RelocSink {
|
||||
/// Add a relocation referencing an block at the current offset.
|
||||
/// Add a relocation referencing a block at the current offset.
|
||||
fn reloc_block(&mut self, _: CodeOffset, _: Reloc, _: CodeOffset);
|
||||
|
||||
/// Add a relocation referencing an external symbol at the current offset.
|
||||
|
||||
@@ -136,7 +136,7 @@ pub trait CodeSink {
|
||||
/// Add 8 bytes to the code section.
|
||||
fn put8(&mut self, _: u64);
|
||||
|
||||
/// Add a relocation referencing an block at the current offset.
|
||||
/// Add a relocation referencing a block at the current offset.
|
||||
fn reloc_block(&mut self, _: Reloc, _: CodeOffset);
|
||||
|
||||
/// Add a relocation referencing an external symbol plus the addend at the current offset.
|
||||
|
||||
@@ -163,7 +163,7 @@ fn try_fold_redundant_jump(
|
||||
}
|
||||
};
|
||||
|
||||
// For the moment, only attempt to fold a branch to an block that is parameterless.
|
||||
// For the moment, only attempt to fold a branch to a block that is parameterless.
|
||||
// These blocks are mainly produced by critical edge splitting.
|
||||
//
|
||||
// TODO: Allow folding blocks that define SSA values and function as phi nodes.
|
||||
|
||||
@@ -13,10 +13,10 @@ pub enum CursorPosition {
|
||||
/// Cursor is pointing at an existing instruction.
|
||||
/// New instructions will be inserted *before* the current instruction.
|
||||
At(ir::Inst),
|
||||
/// Cursor is before the beginning of an block. No instructions can be inserted. Calling
|
||||
/// Cursor is before the beginning of a block. No instructions can be inserted. Calling
|
||||
/// `next_inst()` will move to the first instruction in the block.
|
||||
Before(ir::Block),
|
||||
/// Cursor is pointing after the end of an block.
|
||||
/// Cursor is pointing after the end of a block.
|
||||
/// New instructions will be appended to the block.
|
||||
After(ir::Block),
|
||||
}
|
||||
@@ -368,7 +368,7 @@ pub trait Cursor {
|
||||
|
||||
/// Move to the next instruction in the same block and return it.
|
||||
///
|
||||
/// - If the cursor was positioned before an block, go to the first instruction in that block.
|
||||
/// - If the cursor was positioned before a block, go to the first instruction in that block.
|
||||
/// - If there are no more instructions in the block, go to the `After(block)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
@@ -377,7 +377,7 @@ pub trait Cursor {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `next_inst()` method is intended for iterating over the instructions in an block like
|
||||
/// The `next_inst()` method is intended for iterating over the instructions in a block like
|
||||
/// this:
|
||||
///
|
||||
/// ```
|
||||
@@ -438,7 +438,7 @@ pub trait Cursor {
|
||||
|
||||
/// Move to the previous instruction in the same block and return it.
|
||||
///
|
||||
/// - If the cursor was positioned after an block, go to the last instruction in that block.
|
||||
/// - If the cursor was positioned after a block, go to the last instruction in that block.
|
||||
/// - If there are no more instructions in the block, go to the `Before(block)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
@@ -494,7 +494,7 @@ pub trait Cursor {
|
||||
///
|
||||
/// - If pointing at an instruction, the new instruction is inserted before the current
|
||||
/// instruction.
|
||||
/// - If pointing at the bottom of an block, the new instruction is appended to the block.
|
||||
/// - If pointing at the bottom of a block, the new instruction is appended to the block.
|
||||
/// - Otherwise panic.
|
||||
///
|
||||
/// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
|
||||
@@ -532,16 +532,16 @@ pub trait Cursor {
|
||||
inst
|
||||
}
|
||||
|
||||
/// Insert an block at the current position and switch to it.
|
||||
/// Insert a block at the current position and switch to it.
|
||||
///
|
||||
/// As far as possible, this method behaves as if the block header were an instruction inserted
|
||||
/// at the current position.
|
||||
///
|
||||
/// - If the cursor is pointing at an existing instruction, *the current block is split in two*
|
||||
/// and the current instruction becomes the first instruction in the inserted block.
|
||||
/// - If the cursor points at the bottom of an block, the new block is inserted after the current
|
||||
/// - If the cursor points at the bottom of a block, the new block is inserted after the current
|
||||
/// one, and moved to the bottom of the new block where instructions can be appended.
|
||||
/// - If the cursor points to the top of an block, the new block is inserted above the current one.
|
||||
/// - If the cursor points to the top of a block, the new block is inserted above the current one.
|
||||
/// - If the cursor is not pointing at anything, the new block is placed last in the layout.
|
||||
///
|
||||
/// This means that it is always valid to call this method, and it always leaves the cursor in
|
||||
|
||||
@@ -284,9 +284,9 @@ impl DominatorTree {
|
||||
//
|
||||
// 1. Each block is a node, with outgoing edges for all the branches in the block.
|
||||
// 2. Each basic block is a node, with outgoing edges for the single branch at the end of
|
||||
// the BB. (An block is a linear sequence of basic blocks).
|
||||
// the BB. (A block is a linear sequence of basic blocks).
|
||||
//
|
||||
// The first graph is a contraction of the second one. We want to compute an block post-order
|
||||
// The first graph is a contraction of the second one. We want to compute a block post-order
|
||||
// that is compatible both graph interpretations. That is, if you compute a BB post-order
|
||||
// and then remove those BBs that do not correspond to block headers, you get a post-order of
|
||||
// the block graph.
|
||||
@@ -302,15 +302,15 @@ impl DominatorTree {
|
||||
//
|
||||
// Edge pruning:
|
||||
//
|
||||
// In the BB graph, we keep an edge to an block the first time we visit the *source* side
|
||||
// In the BB graph, we keep an edge to a block the first time we visit the *source* side
|
||||
// of the edge. Any subsequent edges to the same block are pruned.
|
||||
//
|
||||
// The equivalent tree is reached in the block graph by keeping the first edge to an block
|
||||
// The equivalent tree is reached in the block graph by keeping the first edge to a block
|
||||
// in a top-down traversal of the successors. (And then visiting edges in a bottom-up
|
||||
// order).
|
||||
//
|
||||
// This pruning method makes it possible to compute the DFT without storing lots of
|
||||
// information about the progress through an block.
|
||||
// information about the progress through a block.
|
||||
|
||||
// During this algorithm only, use `rpo_number` to hold the following state:
|
||||
//
|
||||
@@ -348,7 +348,7 @@ impl DominatorTree {
|
||||
/// Push `block` successors onto `self.stack`, filtering out those that have already been seen.
|
||||
///
|
||||
/// The successors are pushed in program order which is important to get a split-invariant
|
||||
/// post-order. Split-invariant means that if an block is split in two, we get the same
|
||||
/// post-order. Split-invariant means that if a block is split in two, we get the same
|
||||
/// post-order except for the insertion of the new block header at the split point.
|
||||
fn push_successors(&mut self, func: &Function, block: Block) {
|
||||
for inst in func.layout.block_insts(block) {
|
||||
@@ -543,7 +543,7 @@ impl DominatorTreePreorder {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that enumerates the direct children of an block in the dominator tree.
|
||||
/// An iterator that enumerates the direct children of a block in the dominator tree.
|
||||
pub struct ChildIter<'a> {
|
||||
dtpo: &'a DominatorTreePreorder,
|
||||
next: PackedOption<Block>,
|
||||
@@ -580,7 +580,7 @@ impl DominatorTreePreorder {
|
||||
/// time. This is less general than the `DominatorTree` method because it only works with block
|
||||
/// program points.
|
||||
///
|
||||
/// An block is considered to dominate itself.
|
||||
/// A block is considered to dominate itself.
|
||||
pub fn dominates(&self, a: Block, b: Block) -> bool {
|
||||
let na = &self.nodes[a];
|
||||
let nb = &self.nodes[b];
|
||||
|
||||
@@ -376,7 +376,7 @@ 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 block.
|
||||
/// Value is the n'th parameter to a block.
|
||||
Param(Block, usize),
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ impl ValueDef {
|
||||
pub fn unwrap_block(&self) -> Block {
|
||||
match *self {
|
||||
Self::Param(block, _) => block,
|
||||
_ => panic!("Value is not an block parameter"),
|
||||
_ => panic!("Value is not a block parameter"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ enum ValueData {
|
||||
/// Value is defined by an instruction.
|
||||
Inst { ty: Type, num: u16, inst: Inst },
|
||||
|
||||
/// Value is an block parameter.
|
||||
/// Value is a block parameter.
|
||||
Param { ty: Type, num: u16, block: Block },
|
||||
|
||||
/// Value is an alias of another value.
|
||||
@@ -804,12 +804,12 @@ impl DataFlowGraph {
|
||||
/// 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 block parameter.
|
||||
/// Panics if `val` is not a 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 block parameter", val);
|
||||
panic!("{} must be a block parameter", val);
|
||||
};
|
||||
self.blocks[block]
|
||||
.params
|
||||
@@ -826,7 +826,7 @@ impl DataFlowGraph {
|
||||
{
|
||||
*old_num = num;
|
||||
} else {
|
||||
panic!("{} should be an Block parameter", last_arg_val);
|
||||
panic!("{} should be a Block parameter", last_arg_val);
|
||||
}
|
||||
}
|
||||
num as usize
|
||||
@@ -838,7 +838,7 @@ impl DataFlowGraph {
|
||||
let (block, num) = if let ValueData::Param { num, block, .. } = self.values[val] {
|
||||
(block, num)
|
||||
} else {
|
||||
panic!("{} must be an block parameter", val);
|
||||
panic!("{} must be a block parameter", val);
|
||||
};
|
||||
self.blocks[block]
|
||||
.params
|
||||
@@ -853,7 +853,7 @@ impl DataFlowGraph {
|
||||
*num -= 1;
|
||||
}
|
||||
_ => panic!(
|
||||
"{} must be an block parameter",
|
||||
"{} must be a block parameter",
|
||||
self.blocks[block]
|
||||
.params
|
||||
.get(index as usize, &self.value_lists)
|
||||
@@ -880,7 +880,7 @@ impl DataFlowGraph {
|
||||
};
|
||||
}
|
||||
|
||||
/// Replace an block parameter with a new value of type `ty`.
|
||||
/// Replace a block parameter with a new value of type `ty`.
|
||||
///
|
||||
/// 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
|
||||
@@ -894,7 +894,7 @@ impl DataFlowGraph {
|
||||
let (block, num) = if let ValueData::Param { num, block, .. } = self.values[old_value] {
|
||||
(block, num)
|
||||
} else {
|
||||
panic!("{} must be an block parameter", old_value);
|
||||
panic!("{} must be a block parameter", old_value);
|
||||
};
|
||||
let new_arg = self.make_value(ValueData::Param {
|
||||
ty: new_type,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Function layout.
|
||||
//!
|
||||
//! The order of basic blocks in a function and the order of instructions in an block is
|
||||
//! The order of basic blocks in a function and the order of instructions in a block is
|
||||
//! determined by the `Layout` data structure defined in this module.
|
||||
|
||||
use crate::entity::SecondaryMap;
|
||||
@@ -21,7 +21,7 @@ use log::debug;
|
||||
///
|
||||
/// - The order of blocks in the function.
|
||||
/// - Which block contains a given instruction.
|
||||
/// - The order of instructions with an block.
|
||||
/// - The order of instructions with a block.
|
||||
///
|
||||
/// While data dependencies are not recorded, instruction ordering does affect control
|
||||
/// dependencies, so part of the semantics of the program are determined by the layout.
|
||||
@@ -75,7 +75,7 @@ impl Layout {
|
||||
/// like line numbers in BASIC: 10, 20, 30, ...
|
||||
///
|
||||
/// The block sequence numbers are strictly increasing, and so are the instruction sequence numbers
|
||||
/// within an block. The instruction sequence numbers are all between the sequence number of their
|
||||
/// within a block. The instruction sequence numbers are all between the sequence number of their
|
||||
/// containing block and the following block.
|
||||
///
|
||||
/// The result is that sequence numbers work like BASIC line numbers for the textual form of the IR.
|
||||
@@ -335,7 +335,7 @@ impl Layout {
|
||||
/// Methods for laying out blocks.
|
||||
///
|
||||
/// An unknown block starts out as *not inserted* in the block layout. The layout is a linear order of
|
||||
/// inserted blocks. Once an block has been inserted in the layout, instructions can be added. An block
|
||||
/// inserted blocks. Once a block has been inserted in the layout, instructions can be added. A block
|
||||
/// can only be removed from the layout when it is empty.
|
||||
///
|
||||
/// Since every block must end with a terminator instruction which cannot fall through, the layout of
|
||||
@@ -514,7 +514,7 @@ impl<'f> IntoIterator for &'f Layout {
|
||||
/// Methods for arranging instructions.
|
||||
///
|
||||
/// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into
|
||||
/// an block at a given position.
|
||||
/// a block at a given position.
|
||||
impl Layout {
|
||||
/// Get the block containing `inst`, or `None` if `inst` is not inserted in the layout.
|
||||
pub fn inst_block(&self, inst: Inst) -> Option<Block> {
|
||||
@@ -559,12 +559,12 @@ impl Layout {
|
||||
self.assign_inst_seq(inst);
|
||||
}
|
||||
|
||||
/// Fetch an block's first instruction.
|
||||
/// Fetch a block's first instruction.
|
||||
pub fn first_inst(&self, block: Block) -> Option<Inst> {
|
||||
self.blocks[block].first_inst.into()
|
||||
}
|
||||
|
||||
/// Fetch an block's last instruction.
|
||||
/// Fetch a block's last instruction.
|
||||
pub fn last_inst(&self, block: Block) -> Option<Inst> {
|
||||
self.blocks[block].last_inst.into()
|
||||
}
|
||||
@@ -579,7 +579,7 @@ impl Layout {
|
||||
self.insts[inst].prev.expand()
|
||||
}
|
||||
|
||||
/// Fetch the first instruction in an block's terminal branch group.
|
||||
/// Fetch the first instruction in a block's terminal branch group.
|
||||
pub fn canonical_branch_inst(&self, dfg: &DataFlowGraph, block: Block) -> Option<Inst> {
|
||||
// Basic blocks permit at most two terminal branch instructions.
|
||||
// If two, the former is conditional and the latter is unconditional.
|
||||
@@ -724,7 +724,7 @@ struct InstNode {
|
||||
seq: SequenceNumber,
|
||||
}
|
||||
|
||||
/// Iterate over instructions in an block in layout order. See `Layout::block_insts()`.
|
||||
/// Iterate over instructions in a block in layout order. See `Layout::block_insts()`.
|
||||
pub struct Insts<'f> {
|
||||
layout: &'f Layout,
|
||||
head: Option<Inst>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use core::u32;
|
||||
/// begin or end. It can be either:
|
||||
///
|
||||
/// 1. An instruction or
|
||||
/// 2. An block header.
|
||||
/// 2. A block header.
|
||||
///
|
||||
/// This corresponds more or less to the lines in the textual form of Cranelift IR.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
@@ -47,7 +47,7 @@ impl From<ValueDef> for ProgramPoint {
|
||||
pub enum ExpandedProgramPoint {
|
||||
/// An instruction in the function.
|
||||
Inst(Inst),
|
||||
/// An block header.
|
||||
/// A block header.
|
||||
Block(Block),
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ fn static_addr(
|
||||
pos.func.dfg.replace(inst).iconst(addr_ty, 0);
|
||||
|
||||
// Split Block, as the trap is a terminator instruction.
|
||||
let curr_block = pos.current_block().expect("Cursor is not in an block");
|
||||
let curr_block = pos.current_block().expect("Cursor is not in a block");
|
||||
let new_block = pos.func.dfg.make_block();
|
||||
pos.insert_block(new_block);
|
||||
cfg.recompute_block(pos.func, curr_block);
|
||||
|
||||
@@ -95,7 +95,7 @@ pub fn vsplit(
|
||||
split_any(func, cfg, pos, srcloc, value, Opcode::Vconcat)
|
||||
}
|
||||
|
||||
/// After splitting an block argument, we need to go back and fix up all of the predecessor
|
||||
/// After splitting a block argument, we need to go back and fix up all of the predecessor
|
||||
/// instructions. This is potentially a recursive operation, but we don't implement it recursively
|
||||
/// since that could use up too muck stack.
|
||||
///
|
||||
@@ -260,7 +260,7 @@ fn split_value(
|
||||
}
|
||||
}
|
||||
ValueDef::Param(block, num) => {
|
||||
// This is an block parameter.
|
||||
// This is a block parameter.
|
||||
// We can split the parameter value unless this is the entry block.
|
||||
if pos.func.layout.entry_block() != Some(block) {
|
||||
reuse = Some(split_block_param(pos, block, num, value, concat, repairs));
|
||||
|
||||
@@ -71,7 +71,7 @@ impl LoopAnalysis {
|
||||
self.loops[lp].parent.expand()
|
||||
}
|
||||
|
||||
/// Determine if an Block belongs to a loop by running a finger along the loop tree.
|
||||
/// Determine if a Block belongs to a loop by running a finger along the loop tree.
|
||||
///
|
||||
/// Returns `true` if `block` is in loop `lp`.
|
||||
pub fn is_in_loop(&self, block: Block, lp: Loop) -> bool {
|
||||
|
||||
@@ -122,7 +122,7 @@ use cranelift_entity::{PrimaryMap, SecondaryMap};
|
||||
// =============================================================================================
|
||||
// Data structures used for discovery of trees
|
||||
|
||||
// `ZeroOneOrMany` is used to record the number of predecessors an Block block has. The `Zero` case
|
||||
// `ZeroOneOrMany` is used to record the number of predecessors a Block block has. The `Zero` case
|
||||
// is included so as to cleanly handle the case where the incoming graph has unreachable Blocks.
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
@@ -184,7 +184,7 @@ struct AvailEnv {
|
||||
}
|
||||
|
||||
// `ProcessingStackElem` combines AvailEnv with contextual information needed to "navigate" within
|
||||
// an Block.
|
||||
// a Block.
|
||||
//
|
||||
// A ProcessingStackElem conceptually has the lifetime of exactly one Block: once the current Block is
|
||||
// completed, the ProcessingStackElem will be abandoned. In practice the top level state,
|
||||
@@ -192,7 +192,7 @@ struct AvailEnv {
|
||||
//
|
||||
// Note that ProcessingStackElem must contain a CursorPosition. The CursorPosition, which
|
||||
// indicates where we are in the current Block, cannot be implicitly maintained by looping over all
|
||||
// the instructions in an Block in turn, because we may choose to suspend processing the current Block
|
||||
// the instructions in a Block in turn, because we may choose to suspend processing the current Block
|
||||
// at a side exit, continue by processing the subtree reached via the side exit, and only later
|
||||
// resume the current Block.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Conventional SSA (CSSA) form is a subset of SSA form where any (transitively) phi-related
|
||||
//! values do not interfere. We construct CSSA by building virtual registers that are as large as
|
||||
//! possible and inserting copies where necessary such that all argument values passed to an block
|
||||
//! possible and inserting copies where necessary such that all argument values passed to a block
|
||||
//! parameter will belong to the same virtual register as the block parameter value itself.
|
||||
|
||||
use crate::cursor::{Cursor, EncCursor};
|
||||
@@ -233,7 +233,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
// Check for basic interference: If `arg` overlaps a value defined at the entry to
|
||||
// `block`, it can never be used as an block argument.
|
||||
// `block`, it can never be used as a block argument.
|
||||
let interference = {
|
||||
let lr = &self.liveness[arg];
|
||||
|
||||
@@ -874,7 +874,7 @@ struct VirtualCopies {
|
||||
|
||||
// Filter for the currently active node iterator.
|
||||
//
|
||||
// An block => (set_id, num) entry means that branches to `block` are active in `set_id` with
|
||||
// A block => (set_id, num) entry means that branches to `block` are active in `set_id` with
|
||||
// branch argument number `num`.
|
||||
filter: FxHashMap<Block, (u8, usize)>,
|
||||
}
|
||||
@@ -953,7 +953,7 @@ impl VirtualCopies {
|
||||
debug_assert_eq!(popped, Some(param));
|
||||
|
||||
// The domtree pre-order in `self.params` guarantees that all parameters defined at the
|
||||
// same block will be adjacent. This means we can see when all parameters at an block have been
|
||||
// same block will be adjacent. This means we can see when all parameters at a block have been
|
||||
// merged.
|
||||
//
|
||||
// We don't care about the last parameter - when that is merged we are done.
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
//! a register.
|
||||
//!
|
||||
//! 5. The code must be in Conventional SSA form. Among other things, this means that values passed
|
||||
//! as arguments when branching to an block must belong to the same virtual register as the
|
||||
//! as arguments when branching to a block must belong to the same virtual register as the
|
||||
//! corresponding block argument value.
|
||||
//!
|
||||
//! # Iteration order
|
||||
@@ -35,7 +35,7 @@
|
||||
//! defined by the instruction and only consider the colors of other values that are live at the
|
||||
//! instruction.
|
||||
//!
|
||||
//! The first time we see a branch to an block, the block's argument values are colored to match the
|
||||
//! The first time we see a branch to a block, the block's argument values are colored to match the
|
||||
//! registers currently holding branch argument values passed to the predecessor branch. By
|
||||
//! visiting blocks in a CFG topological order, we guarantee that at least one predecessor branch has
|
||||
//! been visited before the destination block. Therefore, the block's arguments are already colored.
|
||||
@@ -224,7 +224,7 @@ impl<'a> Context<'a> {
|
||||
SingleDest(block, _) => block,
|
||||
};
|
||||
|
||||
// We have a single branch with a single target, and an block with a single
|
||||
// We have a single branch with a single target, and a block with a single
|
||||
// predecessor. Thus we can forward the diversion set to the next block.
|
||||
if self.cfg.pred_iter(target).count() == 1 {
|
||||
// Transfer the diversion to the next block.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! Sometimes, it is necessary to move register values to a different register in order to satisfy
|
||||
//! instruction constraints.
|
||||
//!
|
||||
//! These register diversions are local to an block. No values can be diverted when entering a new
|
||||
//! These register diversions are local to a block. No values can be diverted when entering a new
|
||||
//! block.
|
||||
|
||||
use crate::fx::FxHashMap;
|
||||
@@ -38,7 +38,7 @@ impl Diversion {
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep track of diversions in an block.
|
||||
/// Keep track of diversions in a block.
|
||||
#[derive(Clone)]
|
||||
pub struct RegDiversions {
|
||||
current: FxHashMap<Value, Diversion>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Track which values are live in an block with instruction granularity.
|
||||
//! Track which values are live in a block with instruction granularity.
|
||||
//!
|
||||
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in an block.
|
||||
//! The `LiveValueTracker` keeps track of the set of live SSA values at each instruction in a block.
|
||||
//! The sets of live values are computed on the fly as the tracker is moved from instruction to
|
||||
//! instruction, starting at the block header.
|
||||
|
||||
@@ -16,13 +16,13 @@ use alloc::vec::Vec;
|
||||
|
||||
type ValueList = EntityList<Value>;
|
||||
|
||||
/// Compute and track live values throughout an block.
|
||||
/// Compute and track live values throughout a block.
|
||||
pub struct LiveValueTracker {
|
||||
/// The set of values that are live at the current program point.
|
||||
live: LiveValueVec,
|
||||
|
||||
/// Saved set of live values for every jump and branch that can potentially be an immediate
|
||||
/// dominator of an block.
|
||||
/// dominator of a block.
|
||||
///
|
||||
/// This is the set of values that are live *before* the branch.
|
||||
idom_sets: FxHashMap<Inst, ValueList>,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//!
|
||||
//! The set of `LiveRange` instances can answer these questions through their `def_local_end` and
|
||||
//! `livein_local_end` queries. The coloring algorithm visits blocks in a topological order of the
|
||||
//! dominator tree, so it can compute the set of live values at the beginning of an block by starting
|
||||
//! dominator tree, so it can compute the set of live values at the beginning of a block by starting
|
||||
//! from the set of live values at the dominating branch instruction and filtering it with
|
||||
//! `livein_local_end`. These sets do not need to be stored in the liveness analysis.
|
||||
//!
|
||||
|
||||
@@ -131,7 +131,7 @@ use smallvec::SmallVec;
|
||||
/// 2. The *live-in intervals* are the local intervals in the remaining blocks.
|
||||
///
|
||||
/// A live-in interval always begins at the block header, while the def interval can begin at the
|
||||
/// defining instruction, or at the block header for an block argument value.
|
||||
/// defining instruction, or at the block header for a block argument value.
|
||||
///
|
||||
/// All values have a def interval, but a large proportion of values don't have any live-in
|
||||
/// intervals. These are called *local live ranges*.
|
||||
@@ -139,7 +139,7 @@ use smallvec::SmallVec;
|
||||
/// # Program order requirements
|
||||
///
|
||||
/// The internal representation of a `LiveRange` depends on a consistent `ProgramOrder` both for
|
||||
/// ordering instructions inside an block *and* for ordering blocks. The methods that depend on the
|
||||
/// ordering instructions inside a block *and* for ordering blocks. The methods that depend on the
|
||||
/// ordering take an explicit `ProgramOrder` object, and it is the caller's responsibility to
|
||||
/// ensure that the provided ordering is consistent between calls.
|
||||
///
|
||||
@@ -363,7 +363,7 @@ impl<PO: ProgramOrder> GenericLiveRange<PO> {
|
||||
|
||||
/// Get the program point where this live range is defined.
|
||||
///
|
||||
/// This will be an block header when the value is an block argument, otherwise it is the defining
|
||||
/// This will be a block header when the value is a block argument, otherwise it is the defining
|
||||
/// instruction.
|
||||
pub fn def(&self) -> ProgramPoint {
|
||||
self.def_begin
|
||||
@@ -385,7 +385,7 @@ impl<PO: ProgramOrder> GenericLiveRange<PO> {
|
||||
self.def_end
|
||||
}
|
||||
|
||||
/// Get the local end-point of this live range in an block where it is live-in.
|
||||
/// Get the local end-point of this live range in a block where it is live-in.
|
||||
///
|
||||
/// If this live range is not live-in to `block`, return `None`. Otherwise, return the end-point
|
||||
/// of this live range's local interval in `block`.
|
||||
@@ -409,7 +409,7 @@ impl<PO: ProgramOrder> GenericLiveRange<PO> {
|
||||
|
||||
/// Is this value live-in to `block`?
|
||||
///
|
||||
/// An block argument is not considered to be live in.
|
||||
/// A block argument is not considered to be live in.
|
||||
pub fn is_livein(&self, block: Block, order: &PO) -> bool {
|
||||
self.livein_local_end(block, order).is_some()
|
||||
}
|
||||
@@ -594,7 +594,7 @@ mod tests {
|
||||
assert!(lr.is_local());
|
||||
assert_eq!(lr.def(), e2.into());
|
||||
assert_eq!(lr.def_local_end(), e2.into());
|
||||
// The def interval of an block argument does not count as live-in.
|
||||
// The def interval of a block argument does not count as live-in.
|
||||
assert_eq!(lr.livein_local_end(e2, PO), None);
|
||||
PO.validate(&lr);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ impl<'a> Context<'a> {
|
||||
self.pressure.reset();
|
||||
self.take_live_regs(liveins);
|
||||
|
||||
// An block can have an arbitrary (up to 2^16...) number of parameters, so they are not
|
||||
// A block can have an arbitrary (up to 2^16...) number of parameters, so they are not
|
||||
// guaranteed to fit in registers.
|
||||
for lv in params {
|
||||
if let Affinity::Reg(rci) = lv.affinity {
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
//! output.
|
||||
//!
|
||||
//! A virtual register is typically built by merging together SSA values that are "phi-related" -
|
||||
//! that is, one value is passed as an block argument to a branch and the other is the block parameter
|
||||
//! that is, one value is passed as a block argument to a branch and the other is the block parameter
|
||||
//! value itself.
|
||||
//!
|
||||
//! If any values in a virtual register are spilled, they will use the same stack slot. This avoids
|
||||
//! memory-to-memory copies when a spilled value is passed as an block argument.
|
||||
//! memory-to-memory copies when a spilled value is passed as a block argument.
|
||||
|
||||
use crate::dbg::DisplayList;
|
||||
use crate::dominator_tree::DominatorTreePreorder;
|
||||
|
||||
@@ -810,7 +810,7 @@ enum BranchOrderKind {
|
||||
|
||||
/// Reorder branches to encourage fallthroughs.
|
||||
///
|
||||
/// When an block ends with a conditional branch followed by an unconditional
|
||||
/// When a block ends with a conditional branch followed by an unconditional
|
||||
/// branch, this will reorder them if one of them is branching to the next Block
|
||||
/// layout-wise. The unconditional jump can then become a fallthrough.
|
||||
fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, block: Block, inst: Inst) {
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::verifier::{VerifierErrors, VerifierStepResult};
|
||||
///
|
||||
/// Conventional SSA form is represented in Cranelift with the help of virtual registers:
|
||||
///
|
||||
/// - Two values are said to be *PHI-related* if one is an block argument and the other is passed as
|
||||
/// - Two values are said to be *PHI-related* if one is a block argument and the other is passed as
|
||||
/// a branch argument in a location that matches the first value.
|
||||
/// - PHI-related values must belong to the same virtual register.
|
||||
/// - Two values in the same virtual register must not have overlapping live ranges.
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::verifier::{VerifierErrors, VerifierStepResult};
|
||||
/// - All values in the program must have a live range.
|
||||
/// - The live range def point must match where the value is defined.
|
||||
/// - The live range must reach all uses.
|
||||
/// - When a live range is live-in to an block, it must be live at all the predecessors.
|
||||
/// - When a live range is live-in to a block, it must be live at all the predecessors.
|
||||
/// - The live range affinity must be compatible with encoding constraints.
|
||||
///
|
||||
/// We don't verify that live ranges are minimal. This would require recomputing live ranges for
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::verifier::{VerifierErrors, VerifierStepResult};
|
||||
/// instruction encoding recipes.
|
||||
///
|
||||
/// Values can be temporarily diverted to a different location by using the `regmove`, `regspill`,
|
||||
/// and `regfill` instructions, but only inside an block.
|
||||
/// and `regfill` instructions, but only inside a block.
|
||||
///
|
||||
/// If a liveness analysis is provided, it is used to verify that there are no active register
|
||||
/// diversions across control flow edges.
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
//! SSA form
|
||||
//!
|
||||
//! - Values must be defined by an instruction that exists and that is inserted in
|
||||
//! an block, or be an argument of an existing block.
|
||||
//! a 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 block.
|
||||
//! - All branches to an block must be present in the CFG.
|
||||
//! - All branches to a block must be present in the CFG.
|
||||
//! - A recomputed dominator tree is identical to the existing one.
|
||||
//!
|
||||
//! Type checking
|
||||
@@ -961,7 +961,7 @@ impl<'a> Verifier<'a> {
|
||||
format!("{} is defined by invalid instruction {}", v, def_inst),
|
||||
));
|
||||
}
|
||||
// Defining instruction is inserted in an block.
|
||||
// Defining instruction is inserted in a block.
|
||||
if self.func.layout.inst_block(def_inst) == None {
|
||||
return errors.fatal((
|
||||
loc_inst,
|
||||
|
||||
@@ -40,11 +40,11 @@ pub struct FunctionBuilder<'a> {
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct BlockData {
|
||||
/// An Block is "pristine" iff no instructions have been added since the last
|
||||
/// A Block is "pristine" iff no instructions have been added since the last
|
||||
/// call to `switch_to_block()`.
|
||||
pristine: bool,
|
||||
|
||||
/// An Block is "filled" iff a terminator instruction has been inserted since
|
||||
/// A Block is "filled" iff a terminator instruction has been inserted since
|
||||
/// the last call to `switch_to_block()`.
|
||||
///
|
||||
/// A filled block cannot be pristine.
|
||||
@@ -832,7 +832,7 @@ impl<'a> FunctionBuilder<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
/// An Block is 'filled' when a terminator instruction is present.
|
||||
/// A Block is 'filled' when a terminator instruction is present.
|
||||
fn fill_current_block(&mut self) {
|
||||
self.func_ctx.blocks[self.position.block.unwrap()].filled = true;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ impl SSABuilder {
|
||||
// Part 1: With a mutable borrow of self, update the DataFlowGraph if necessary.
|
||||
let case = match self.ssa_blocks[ssa_block] {
|
||||
SSABlockData::BlockHeader(ref mut data) => {
|
||||
// The block has multiple predecessors so we append an Block parameter that
|
||||
// The block has multiple predecessors so we append a Block parameter that
|
||||
// will serve as a value.
|
||||
if data.sealed {
|
||||
if data.predecessors.len() == 1 {
|
||||
@@ -408,7 +408,7 @@ impl SSABuilder {
|
||||
self.block_headers[block] = ssa_block.into();
|
||||
ssa_block
|
||||
}
|
||||
/// Gets the header block corresponding to an Block, panics if the Block or the header block
|
||||
/// Gets the header block corresponding to a Block, panics if the Block or the header block
|
||||
/// isn't declared.
|
||||
pub fn header_block(&self, block: Block) -> SSABlock {
|
||||
self.block_headers
|
||||
@@ -491,7 +491,7 @@ impl SSABuilder {
|
||||
}
|
||||
};
|
||||
|
||||
// For each undef var we look up values in the predecessors and create an block parameter
|
||||
// For each undef var we look up values in the predecessors and create a block parameter
|
||||
// only if necessary.
|
||||
for (var, val) in undef_vars {
|
||||
let ty = func.dfg.value_type(val);
|
||||
@@ -516,13 +516,13 @@ impl SSABuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the local SSA Value of a Variable in an Block, perform a recursive lookup on
|
||||
/// Given the local SSA Value of a Variable in a Block, perform a recursive lookup on
|
||||
/// predecessors to determine if it is redundant with another Value earlier in the CFG.
|
||||
///
|
||||
/// If such a Value exists and is redundant, the local Value is replaced by the
|
||||
/// corresponding non-local Value. If the original Value was an Block parameter,
|
||||
/// corresponding non-local Value. If the original Value was a Block parameter,
|
||||
/// the parameter may be removed if redundant. Parameters are placed eagerly by callers
|
||||
/// to avoid infinite loops when looking up a Value for an Block that is in a CFG loop.
|
||||
/// to avoid infinite loops when looking up a Value for a Block that is in a CFG loop.
|
||||
///
|
||||
/// Doing this lookup for each Value in each Block preserves SSA form during construction.
|
||||
///
|
||||
@@ -623,7 +623,7 @@ impl SSABuilder {
|
||||
}
|
||||
ZeroOneOrMore::One(pred_val) => {
|
||||
// Here all the predecessors use a single value to represent our variable
|
||||
// so we don't need to have it as an block argument.
|
||||
// so we don't need to have it as a block argument.
|
||||
// We need to replace all the occurrences of val with pred_val but since
|
||||
// we can't afford a re-writing pass right now we just declare an alias.
|
||||
// Resolve aliases eagerly so that we can check for cyclic aliasing,
|
||||
@@ -692,7 +692,7 @@ impl SSABuilder {
|
||||
) -> Option<(Block, SSABlock, Inst)> {
|
||||
match func.dfg.analyze_branch(jump_inst) {
|
||||
BranchInfo::NotABranch => {
|
||||
panic!("you have declared a non-branch instruction as a predecessor to an block");
|
||||
panic!("you have declared a non-branch instruction as a predecessor to a block");
|
||||
}
|
||||
// For a single destination appending a jump argument to the instruction
|
||||
// is sufficient.
|
||||
|
||||
@@ -558,7 +558,7 @@ impl<'a> Parser<'a> {
|
||||
err!(self.loc, "expected jump table number: jt«n»")
|
||||
}
|
||||
|
||||
// Match and consume an block reference.
|
||||
// Match and consume a block reference.
|
||||
fn match_block(&mut self, err_msg: &str) -> ParseResult<Block> {
|
||||
if let Some(Token::Block(block)) = self.token() {
|
||||
self.consume();
|
||||
|
||||
@@ -44,7 +44,7 @@ pub struct Details<'a> {
|
||||
|
||||
/// A comment in a parsed function.
|
||||
///
|
||||
/// The comment belongs to the immediately preceding entity, whether that is an block header, and
|
||||
/// The comment belongs to the immediately preceding entity, whether that is a block header, and
|
||||
/// instruction, or one of the preamble declarations.
|
||||
///
|
||||
/// Comments appearing inside the function but before the preamble, as well as comments appearing
|
||||
|
||||
@@ -274,7 +274,7 @@ impl Mutator for ReplaceInstWithTrap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to remove an block.
|
||||
/// Try to remove a block.
|
||||
struct RemoveBlock {
|
||||
block: Block,
|
||||
}
|
||||
|
||||
@@ -185,10 +185,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||
let (destination, else_data) = if params == results {
|
||||
// It is possible there is no `else` block, so we will only
|
||||
// allocate an block for it if/when we find the `else`. For now,
|
||||
// allocate a block for it if/when we find the `else`. For now,
|
||||
// we if the condition isn't true, then we jump directly to the
|
||||
// destination block following the whole `if...end`. If we do end
|
||||
// up discovering an `else`, then we will allocate an block for it
|
||||
// up discovering an `else`, then we will allocate a block for it
|
||||
// and go back and patch the jump.
|
||||
let destination = block_with_params(builder, results, environ)?;
|
||||
let branch_inst = builder
|
||||
@@ -212,7 +212,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
builder.seal_block(next_block); // Only predecessor is the current block.
|
||||
builder.switch_to_block(next_block);
|
||||
|
||||
// Here we append an argument to an Block targeted by an argumentless jump instruction
|
||||
// Here we append an argument to a Block targeted by an argumentless jump instruction
|
||||
// But in fact there are two cases:
|
||||
// - either the If does not have a Else clause, in that case ty = EmptyBlock
|
||||
// and we add nothing;
|
||||
@@ -241,7 +241,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// We have a branch from the head of the `if` to the `else`.
|
||||
state.reachable = true;
|
||||
|
||||
// Ensure we have an block for the `else` block (it may have
|
||||
// Ensure we have a block for the `else` block (it may have
|
||||
// already been pre-allocated, see `ElseData` for details).
|
||||
let else_block = match *else_data {
|
||||
ElseData::NoElse { branch_inst } => {
|
||||
|
||||
Reference in New Issue
Block a user