Move the CursorBase trait into the cursor module.
Also move the CursorPosition type into the cursor module. Move layout::cursor into the tests module as LayoutCursor and remove its ability to insert instructions via the dfg.ins() method. This cursor type is only used in the layout unit tests now. The FuncCursor and EncCursor types are the commonly used cursors now.
This commit is contained in:
@@ -5,10 +5,557 @@
|
||||
use ir;
|
||||
use isa::TargetIsa;
|
||||
|
||||
// Re-export these types, anticipating their being moved here.
|
||||
pub use ir::layout::CursorBase as Cursor;
|
||||
pub use ir::layout::CursorPosition;
|
||||
pub use ir::layout::Cursor as LayoutCursor;
|
||||
/// The possible positions of a cursor.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CursorPosition {
|
||||
/// Cursor is not pointing anywhere. No instructions can be inserted.
|
||||
Nowhere,
|
||||
/// 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 EBB. No instructions can be inserted. Calling
|
||||
/// `next_inst()` will move to the first instruction in the EBB.
|
||||
Before(ir::Ebb),
|
||||
/// Cursor is pointing after the end of an EBB.
|
||||
/// New instructions will be appended to the EBB.
|
||||
After(ir::Ebb),
|
||||
}
|
||||
|
||||
/// All cursor types implement the `Cursor` which provides common navigation operations.
|
||||
pub trait Cursor {
|
||||
/// Get the current cursor position.
|
||||
fn position(&self) -> CursorPosition;
|
||||
|
||||
/// Set the current position.
|
||||
fn set_position(&mut self, pos: CursorPosition);
|
||||
|
||||
/// Get the source location that should be assigned to new instructions.
|
||||
fn srcloc(&self) -> ir::SourceLoc;
|
||||
|
||||
/// Set the source location that should be assigned to new instructions.
|
||||
fn set_srcloc(&mut self, srcloc: ir::SourceLoc);
|
||||
|
||||
/// Borrow a reference to the function layout that this cursor is navigating.
|
||||
fn layout(&self) -> &ir::Layout;
|
||||
|
||||
/// Borrow a mutable reference to the function layout that this cursor is navigating.
|
||||
fn layout_mut(&mut self) -> &mut ir::Layout;
|
||||
|
||||
/// Exchange this cursor for one with a set source location.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, SourceLoc};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, srcloc: SourceLoc) {
|
||||
/// let mut pos = FuncCursor::new(func).with_srcloc(srcloc);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_srcloc(srcloc);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at `pos`.
|
||||
fn at_position(mut self, pos: CursorPosition) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_position(pos);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at `inst`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, inst: Inst) {
|
||||
/// let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_inst(mut self, inst: ir::Inst) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_inst(inst);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the first insertion point for `ebb`.
|
||||
/// This differs from `at_first_inst` in that it doesn't assume that any
|
||||
/// instructions have been inserted into `ebb` yet.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_first_insertion_point(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_first_insertion_point(mut self, ebb: ir::Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_first_insertion_point(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the first instruction in `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_first_inst(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_first_inst(mut self, ebb: ir::Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_first_inst(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the last instruction in `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_last_inst(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_last_inst(mut self, ebb: ir::Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_last_inst(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned after `inst`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, inst: Inst) {
|
||||
/// let mut pos = FuncCursor::new(func).after_inst(inst);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn after_inst(mut self, inst: ir::Inst) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_after_inst(inst);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the top of `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_top(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_top(mut self, ebb: ir::Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_top(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the bottom of `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_bottom(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_bottom(mut self, ebb: ir::Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_bottom(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the EBB corresponding to the current position.
|
||||
fn current_ebb(&self) -> Option<ir::Ebb> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere => None,
|
||||
At(inst) => self.layout().inst_ebb(inst),
|
||||
Before(ebb) | After(ebb) => Some(ebb),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the instruction corresponding to the current position, if any.
|
||||
fn current_inst(&self) -> Option<ir::Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
At(inst) => Some(inst),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to the position after a specific instruction, which must be inserted
|
||||
/// in the layout. New instructions will be inserted after `inst`.
|
||||
fn goto_after_inst(&mut self, inst: ir::Inst) {
|
||||
debug_assert!(self.layout().inst_ebb(inst).is_some());
|
||||
let new_pos = if let Some(next) = self.layout().next_inst(inst) {
|
||||
CursorPosition::At(next)
|
||||
} else {
|
||||
CursorPosition::After(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
))
|
||||
};
|
||||
self.set_position(new_pos);
|
||||
}
|
||||
|
||||
/// Go to a specific instruction which must be inserted in the layout.
|
||||
/// New instructions will be inserted before `inst`.
|
||||
fn goto_inst(&mut self, inst: ir::Inst) {
|
||||
assert!(self.layout().inst_ebb(inst).is_some());
|
||||
self.set_position(CursorPosition::At(inst));
|
||||
}
|
||||
|
||||
/// Go to the position for inserting instructions at the beginning of `ebb`,
|
||||
/// which unlike `goto_first_inst` doesn't assume that any instructions have
|
||||
/// been inserted into `ebb` yet.
|
||||
fn goto_first_insertion_point(&mut self, ebb: ir::Ebb) {
|
||||
if let Some(inst) = self.layout().first_inst(ebb) {
|
||||
self.goto_inst(inst);
|
||||
} else {
|
||||
self.goto_bottom(ebb);
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to the first instruction in `ebb`.
|
||||
fn goto_first_inst(&mut self, ebb: ir::Ebb) {
|
||||
let inst = self.layout().first_inst(ebb).expect("Empty EBB");
|
||||
self.goto_inst(inst);
|
||||
}
|
||||
|
||||
/// Go to the last instruction in `ebb`.
|
||||
fn goto_last_inst(&mut self, ebb: ir::Ebb) {
|
||||
let inst = self.layout().last_inst(ebb).expect("Empty EBB");
|
||||
self.goto_inst(inst);
|
||||
}
|
||||
|
||||
/// Go to the top of `ebb` which must be inserted into the layout.
|
||||
/// At this position, instructions cannot be inserted, but `next_inst()` will move to the first
|
||||
/// instruction in `ebb`.
|
||||
fn goto_top(&mut self, ebb: ir::Ebb) {
|
||||
assert!(self.layout().is_ebb_inserted(ebb));
|
||||
self.set_position(CursorPosition::Before(ebb));
|
||||
}
|
||||
|
||||
/// Go to the bottom of `ebb` which must be inserted into the layout.
|
||||
/// At this position, inserted instructions will be appended to `ebb`.
|
||||
fn goto_bottom(&mut self, ebb: ir::Ebb) {
|
||||
assert!(self.layout().is_ebb_inserted(ebb));
|
||||
self.set_position(CursorPosition::After(ebb));
|
||||
}
|
||||
|
||||
/// Go to the top of the next EBB in layout order and return it.
|
||||
///
|
||||
/// - If the cursor wasn't pointing at anything, go to the top of the first EBB in the
|
||||
/// function.
|
||||
/// - If there are no more EBBs, leave the cursor pointing at nothing and return `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `next_ebb()` method is intended for iterating over the EBBs in layout order:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.next_ebb() {
|
||||
/// // Edit ebb.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn next_ebb(&mut self) -> Option<ir::Ebb> {
|
||||
let next = if let Some(ebb) = self.current_ebb() {
|
||||
self.layout().next_ebb(ebb)
|
||||
} else {
|
||||
self.layout().entry_block()
|
||||
};
|
||||
self.set_position(match next {
|
||||
Some(ebb) => CursorPosition::Before(ebb),
|
||||
None => CursorPosition::Nowhere,
|
||||
});
|
||||
next
|
||||
}
|
||||
|
||||
/// Go to the bottom of the previous EBB in layout order and return it.
|
||||
///
|
||||
/// - If the cursor wasn't pointing at anything, go to the bottom of the last EBB in the
|
||||
/// function.
|
||||
/// - If there are no more EBBs, leave the cursor pointing at nothing and return `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `prev_ebb()` method is intended for iterating over the EBBs in backwards layout order:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.prev_ebb() {
|
||||
/// // Edit ebb.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn prev_ebb(&mut self) -> Option<ir::Ebb> {
|
||||
let prev = if let Some(ebb) = self.current_ebb() {
|
||||
self.layout().prev_ebb(ebb)
|
||||
} else {
|
||||
self.layout().last_ebb()
|
||||
};
|
||||
self.set_position(match prev {
|
||||
Some(ebb) => CursorPosition::After(ebb),
|
||||
None => CursorPosition::Nowhere,
|
||||
});
|
||||
prev
|
||||
}
|
||||
|
||||
/// Move to the next instruction in the same EBB and return it.
|
||||
///
|
||||
/// - If the cursor was positioned before an EBB, go to the first instruction in that EBB.
|
||||
/// - If there are no more instructions in the EBB, go to the `After(ebb)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
///
|
||||
/// This method will never move the cursor to a different EBB.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `next_inst()` method is intended for iterating over the instructions in an EBB like
|
||||
/// this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut cursor = FuncCursor::new(func).at_top(ebb);
|
||||
/// while let Some(inst) = cursor.next_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// The loop body can insert and remove instructions via the cursor.
|
||||
///
|
||||
/// Iterating over all the instructions in a function looks like this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.next_ebb() {
|
||||
/// while let Some(inst) = cursor.next_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn next_inst(&mut self) -> Option<ir::Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | After(..) => None,
|
||||
At(inst) => {
|
||||
if let Some(next) = self.layout().next_inst(inst) {
|
||||
self.set_position(At(next));
|
||||
Some(next)
|
||||
} else {
|
||||
let pos = After(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
));
|
||||
self.set_position(pos);
|
||||
None
|
||||
}
|
||||
}
|
||||
Before(ebb) => {
|
||||
if let Some(next) = self.layout().first_inst(ebb) {
|
||||
self.set_position(At(next));
|
||||
Some(next)
|
||||
} else {
|
||||
self.set_position(After(ebb));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move to the previous instruction in the same EBB and return it.
|
||||
///
|
||||
/// - If the cursor was positioned after an EBB, go to the last instruction in that EBB.
|
||||
/// - If there are no more instructions in the EBB, go to the `Before(ebb)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
///
|
||||
/// This method will never move the cursor to a different EBB.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `prev_inst()` method is intended for iterating backwards over the instructions in an
|
||||
/// EBB like this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut cursor = FuncCursor::new(func).at_bottom(ebb);
|
||||
/// while let Some(inst) = cursor.prev_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn prev_inst(&mut self) -> Option<ir::Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | Before(..) => None,
|
||||
At(inst) => {
|
||||
if let Some(prev) = self.layout().prev_inst(inst) {
|
||||
self.set_position(At(prev));
|
||||
Some(prev)
|
||||
} else {
|
||||
let pos = Before(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
));
|
||||
self.set_position(pos);
|
||||
None
|
||||
}
|
||||
}
|
||||
After(ebb) => {
|
||||
if let Some(prev) = self.layout().last_inst(ebb) {
|
||||
self.set_position(At(prev));
|
||||
Some(prev)
|
||||
} else {
|
||||
self.set_position(Before(ebb));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert an instruction at the current position.
|
||||
///
|
||||
/// - If pointing at an instruction, the new instruction is inserted before the current
|
||||
/// instruction.
|
||||
/// - If pointing at the bottom of an EBB, the new instruction is appended to the EBB.
|
||||
/// - Otherwise panic.
|
||||
///
|
||||
/// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
|
||||
/// instructions to appear in insertion order in the EBB.
|
||||
fn insert_inst(&mut self, inst: ir::Inst) {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | Before(..) => panic!("Invalid insert_inst position"),
|
||||
At(cur) => self.layout_mut().insert_inst(inst, cur),
|
||||
After(ebb) => self.layout_mut().append_inst(inst, ebb),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the instruction under the cursor.
|
||||
///
|
||||
/// The cursor is left pointing at the position following the current instruction.
|
||||
///
|
||||
/// Return the instruction that was removed.
|
||||
fn remove_inst(&mut self) -> ir::Inst {
|
||||
let inst = self.current_inst().expect("No instruction to remove");
|
||||
self.next_inst();
|
||||
self.layout_mut().remove_inst(inst);
|
||||
inst
|
||||
}
|
||||
|
||||
/// Remove the instruction under the cursor.
|
||||
///
|
||||
/// The cursor is left pointing at the position preceding the current instruction.
|
||||
///
|
||||
/// Return the instruction that was removed.
|
||||
fn remove_inst_and_step_back(&mut self) -> ir::Inst {
|
||||
let inst = self.current_inst().expect("No instruction to remove");
|
||||
self.prev_inst();
|
||||
self.layout_mut().remove_inst(inst);
|
||||
inst
|
||||
}
|
||||
|
||||
/// Insert an EBB at the current position and switch to it.
|
||||
///
|
||||
/// As far as possible, this method behaves as if the EBB header were an instruction inserted
|
||||
/// at the current position.
|
||||
///
|
||||
/// - If the cursor is pointing at an existing instruction, *the current EBB is split in two*
|
||||
/// and the current instruction becomes the first instruction in the inserted EBB.
|
||||
/// - If the cursor points at the bottom of an EBB, the new EBB is inserted after the current
|
||||
/// one, and moved to the bottom of the new EBB where instructions can be appended.
|
||||
/// - If the cursor points to the top of an EBB, the new EBB is inserted above the current one.
|
||||
/// - If the cursor is not pointing at anything, the new EBB is placed last in the layout.
|
||||
///
|
||||
/// This means that it is always valid to call this method, and it always leaves the cursor in
|
||||
/// a state that will insert instructions into the new EBB.
|
||||
fn insert_ebb(&mut self, new_ebb: ir::Ebb) {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
At(inst) => {
|
||||
self.layout_mut().split_ebb(new_ebb, inst);
|
||||
// All other cases move to `After(ebb)`, but in this case we'll stay `At(inst)`.
|
||||
return;
|
||||
}
|
||||
Nowhere => self.layout_mut().append_ebb(new_ebb),
|
||||
Before(ebb) => self.layout_mut().insert_ebb(new_ebb, ebb),
|
||||
After(ebb) => self.layout_mut().insert_ebb_after(new_ebb, ebb),
|
||||
}
|
||||
// For everything but `At(inst)` we end up appending to the new EBB.
|
||||
self.set_position(After(new_ebb));
|
||||
}
|
||||
}
|
||||
|
||||
/// Function cursor.
|
||||
///
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
use entity::{PrimaryMap, EntityMap};
|
||||
use isa::TargetIsa;
|
||||
use ir::builder::{InsertBuilder, ReplaceBuilder};
|
||||
use ir::builder::ReplaceBuilder;
|
||||
use ir::extfunc::ExtFuncData;
|
||||
use ir::instructions::{InstructionData, CallInfo, BranchInfo};
|
||||
use ir::layout::{Cursor, LayoutCursorInserter};
|
||||
use ir::types;
|
||||
use ir::{Ebb, Inst, Value, Type, SigRef, Signature, FuncRef, ValueList, ValueListPool};
|
||||
use write::write_operands;
|
||||
@@ -479,14 +478,6 @@ impl DataFlowGraph {
|
||||
total_results
|
||||
}
|
||||
|
||||
/// Create an `InsertBuilder` that will insert an instruction at the cursor's current position.
|
||||
pub fn ins<'c, 'fc: 'c, 'fd>(
|
||||
&'fd mut self,
|
||||
at: &'c mut Cursor<'fc>,
|
||||
) -> InsertBuilder<'fd, LayoutCursorInserter<'c, 'fc, 'fd>> {
|
||||
InsertBuilder::new(LayoutCursorInserter::new(at, self))
|
||||
}
|
||||
|
||||
/// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place.
|
||||
pub fn replace(&mut self, inst: Inst) -> ReplaceBuilder {
|
||||
ReplaceBuilder::new(self, inst)
|
||||
@@ -508,7 +499,6 @@ impl DataFlowGraph {
|
||||
self.results[inst].clear(&mut self.value_lists)
|
||||
}
|
||||
|
||||
|
||||
/// Attach an existing value to the result value list for `inst`.
|
||||
///
|
||||
/// The `res` value is appended to the end of the result list.
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
//! The order of extended basic blocks in a function and the order of instructions in an EBB is
|
||||
//! determined by the `Layout` data structure defined in this module.
|
||||
|
||||
use entity::EntityMap;
|
||||
use ir::{Ebb, Inst};
|
||||
use ir::progpoint::{ProgramOrder, ExpandedProgramPoint};
|
||||
use packed_option::PackedOption;
|
||||
use std::cmp;
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
use entity::EntityMap;
|
||||
use packed_option::PackedOption;
|
||||
use ir::{Ebb, Inst, Type, DataFlowGraph, SourceLoc, SourceLocs};
|
||||
use ir::builder::InstInserterBase;
|
||||
use ir::progpoint::{ProgramOrder, ExpandedProgramPoint};
|
||||
|
||||
/// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not
|
||||
/// contain definitions of instructions or EBBs, but depends on `Inst` and `Ebb` entity references
|
||||
@@ -405,6 +404,11 @@ impl Layout {
|
||||
self.last_ebb
|
||||
}
|
||||
|
||||
/// Get the block preceding `ebb` in the layout order.
|
||||
pub fn prev_ebb(&self, ebb: Ebb) -> Option<Ebb> {
|
||||
self.ebbs[ebb].prev.expand()
|
||||
}
|
||||
|
||||
/// Get the block following `ebb` in the layout order.
|
||||
pub fn next_ebb(&self, ebb: Ebb) -> Option<Ebb> {
|
||||
self.ebbs[ebb].next.expand()
|
||||
@@ -432,7 +436,7 @@ impl<'f> Iterator for Ebbs<'f> {
|
||||
fn next(&mut self) -> Option<Ebb> {
|
||||
match self.next {
|
||||
Some(ebb) => {
|
||||
self.next = self.layout.ebbs[ebb].next.expand();
|
||||
self.next = self.layout.next_ebb(ebb);
|
||||
Some(ebb)
|
||||
}
|
||||
None => None,
|
||||
@@ -690,673 +694,57 @@ impl<'f> DoubleEndedIterator for Insts<'f> {
|
||||
}
|
||||
|
||||
|
||||
/// Layout Cursor.
|
||||
///
|
||||
/// A `Cursor` represents a position in a function layout where instructions can be inserted and
|
||||
/// removed. It can be used to iterate through the instructions of a function while editing them at
|
||||
/// the same time. A normal instruction iterator can't do this since it holds an immutable
|
||||
/// reference to the Layout.
|
||||
///
|
||||
/// When new instructions are added, the cursor can either append them to an EBB or insert them
|
||||
/// before the current instruction.
|
||||
pub struct Cursor<'f> {
|
||||
/// Borrowed function layout. Public so it can be re-borrowed from this cursor.
|
||||
pub layout: &'f mut Layout,
|
||||
/// Borrowed source locations.
|
||||
pub srclocs: Option<&'f mut SourceLocs>,
|
||||
pos: CursorPosition,
|
||||
srcloc: SourceLoc,
|
||||
}
|
||||
|
||||
/// The possible positions of a cursor.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum CursorPosition {
|
||||
/// Cursor is not pointing anywhere. No instructions can be inserted.
|
||||
Nowhere,
|
||||
/// Cursor is pointing at an existing instruction.
|
||||
/// New instructions will be inserted *before* the current instruction.
|
||||
At(Inst),
|
||||
/// Cursor is before the beginning of an EBB. No instructions can be inserted. Calling
|
||||
/// `next_inst()` will move to the first instruction in the EBB.
|
||||
Before(Ebb),
|
||||
/// Cursor is pointing after the end of an EBB.
|
||||
/// New instructions will be appended to the EBB.
|
||||
After(Ebb),
|
||||
}
|
||||
|
||||
/// All cursor types implement the `CursorBase` which provides common navigation operations.
|
||||
pub trait CursorBase {
|
||||
/// Get the current cursor position.
|
||||
fn position(&self) -> CursorPosition;
|
||||
|
||||
/// Set the current position.
|
||||
fn set_position(&mut self, pos: CursorPosition);
|
||||
|
||||
/// Get the source location that should be assigned to new instructions.
|
||||
fn srcloc(&self) -> SourceLoc;
|
||||
|
||||
/// Set the source location that should be assigned to new instructions.
|
||||
fn set_srcloc(&mut self, srcloc: SourceLoc);
|
||||
|
||||
/// Borrow a reference to the function layout that this cursor is navigating.
|
||||
fn layout(&self) -> &Layout;
|
||||
|
||||
/// Borrow a mutable reference to the function layout that this cursor is navigating.
|
||||
fn layout_mut(&mut self) -> &mut Layout;
|
||||
|
||||
/// Exchange this cursor for one with a set source location.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, SourceLoc};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, srcloc: SourceLoc) {
|
||||
/// let mut pos = FuncCursor::new(func).with_srcloc(srcloc);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn with_srcloc(mut self, srcloc: SourceLoc) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_srcloc(srcloc);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at `pos`.
|
||||
fn at_position(mut self, pos: CursorPosition) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_position(pos);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at `inst`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, inst: Inst) {
|
||||
/// let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_inst(mut self, inst: Inst) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_inst(inst);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the first insertion point for `ebb`.
|
||||
/// This differs from `at_first_inst` in that it doesn't assume that any
|
||||
/// instructions have been inserted into `ebb` yet.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_first_insertion_point(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_first_insertion_point(mut self, ebb: Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_first_insertion_point(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the first instruction in `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_first_inst(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_first_inst(mut self, ebb: Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_first_inst(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the last instruction in `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_last_inst(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_last_inst(mut self, ebb: Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_last_inst(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned after `inst`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, inst: Inst) {
|
||||
/// let mut pos = FuncCursor::new(func).after_inst(inst);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn after_inst(mut self, inst: Inst) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_after_inst(inst);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the top of `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_top(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_top(mut self, ebb: Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_top(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Rebuild this cursor positioned at the bottom of `ebb`.
|
||||
///
|
||||
/// This is intended to be used as a builder method:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb, Inst};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut pos = FuncCursor::new(func).at_bottom(ebb);
|
||||
///
|
||||
/// // Use `pos`...
|
||||
/// }
|
||||
/// ```
|
||||
fn at_bottom(mut self, ebb: Ebb) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.goto_bottom(ebb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the EBB corresponding to the current position.
|
||||
fn current_ebb(&self) -> Option<Ebb> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere => None,
|
||||
At(inst) => self.layout().inst_ebb(inst),
|
||||
Before(ebb) | After(ebb) => Some(ebb),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the instruction corresponding to the current position, if any.
|
||||
fn current_inst(&self) -> Option<Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
At(inst) => Some(inst),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to the position after a specific instruction, which must be inserted
|
||||
/// in the layout. New instructions will be inserted after `inst`.
|
||||
fn goto_after_inst(&mut self, inst: Inst) {
|
||||
debug_assert!(self.layout().inst_ebb(inst).is_some());
|
||||
let new_pos = if let Some(next) = self.layout().insts[inst].next.expand() {
|
||||
CursorPosition::At(next)
|
||||
} else {
|
||||
CursorPosition::After(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
))
|
||||
};
|
||||
self.set_position(new_pos);
|
||||
}
|
||||
|
||||
/// Go to a specific instruction which must be inserted in the layout.
|
||||
/// New instructions will be inserted before `inst`.
|
||||
fn goto_inst(&mut self, inst: Inst) {
|
||||
assert!(self.layout().inst_ebb(inst).is_some());
|
||||
self.set_position(CursorPosition::At(inst));
|
||||
}
|
||||
|
||||
/// Go to the position for inserting instructions at the beginning of `ebb`,
|
||||
/// which unlike `goto_first_inst` doesn't assume that any instructions have
|
||||
/// been inserted into `ebb` yet.
|
||||
fn goto_first_insertion_point(&mut self, ebb: Ebb) {
|
||||
if let Some(inst) = self.layout().ebbs[ebb].first_inst.expand() {
|
||||
self.goto_inst(inst);
|
||||
} else {
|
||||
self.goto_bottom(ebb);
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to the first instruction in `ebb`.
|
||||
fn goto_first_inst(&mut self, ebb: Ebb) {
|
||||
let inst = self.layout().ebbs[ebb].first_inst.expect("Empty EBB");
|
||||
self.goto_inst(inst);
|
||||
}
|
||||
|
||||
/// Go to the last instruction in `ebb`.
|
||||
fn goto_last_inst(&mut self, ebb: Ebb) {
|
||||
let inst = self.layout().ebbs[ebb].last_inst.expect("Empty EBB");
|
||||
self.goto_inst(inst);
|
||||
}
|
||||
|
||||
/// Go to the top of `ebb` which must be inserted into the layout.
|
||||
/// At this position, instructions cannot be inserted, but `next_inst()` will move to the first
|
||||
/// instruction in `ebb`.
|
||||
fn goto_top(&mut self, ebb: Ebb) {
|
||||
assert!(self.layout().is_ebb_inserted(ebb));
|
||||
self.set_position(CursorPosition::Before(ebb));
|
||||
}
|
||||
|
||||
/// Go to the bottom of `ebb` which must be inserted into the layout.
|
||||
/// At this position, inserted instructions will be appended to `ebb`.
|
||||
fn goto_bottom(&mut self, ebb: Ebb) {
|
||||
assert!(self.layout().is_ebb_inserted(ebb));
|
||||
self.set_position(CursorPosition::After(ebb));
|
||||
}
|
||||
|
||||
/// Go to the top of the next EBB in layout order and return it.
|
||||
///
|
||||
/// - If the cursor wasn't pointing at anything, go to the top of the first EBB in the
|
||||
/// function.
|
||||
/// - If there are no more EBBs, leave the cursor pointing at nothing and return `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `next_ebb()` method is intended for iterating over the EBBs in layout order:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.next_ebb() {
|
||||
/// // Edit ebb.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn next_ebb(&mut self) -> Option<Ebb> {
|
||||
let next = if let Some(ebb) = self.current_ebb() {
|
||||
self.layout().ebbs[ebb].next.expand()
|
||||
} else {
|
||||
self.layout().first_ebb
|
||||
};
|
||||
self.set_position(match next {
|
||||
Some(ebb) => CursorPosition::Before(ebb),
|
||||
None => CursorPosition::Nowhere,
|
||||
});
|
||||
next
|
||||
}
|
||||
|
||||
/// Go to the bottom of the previous EBB in layout order and return it.
|
||||
///
|
||||
/// - If the cursor wasn't pointing at anything, go to the bottom of the last EBB in the
|
||||
/// function.
|
||||
/// - If there are no more EBBs, leave the cursor pointing at nothing and return `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `prev_ebb()` method is intended for iterating over the EBBs in backwards layout order:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.prev_ebb() {
|
||||
/// // Edit ebb.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn prev_ebb(&mut self) -> Option<Ebb> {
|
||||
let prev = if let Some(ebb) = self.current_ebb() {
|
||||
self.layout().ebbs[ebb].prev.expand()
|
||||
} else {
|
||||
self.layout().last_ebb
|
||||
};
|
||||
self.set_position(match prev {
|
||||
Some(ebb) => CursorPosition::After(ebb),
|
||||
None => CursorPosition::Nowhere,
|
||||
});
|
||||
prev
|
||||
}
|
||||
|
||||
/// Move to the next instruction in the same EBB and return it.
|
||||
///
|
||||
/// - If the cursor was positioned before an EBB, go to the first instruction in that EBB.
|
||||
/// - If there are no more instructions in the EBB, go to the `After(ebb)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
///
|
||||
/// This method will never move the cursor to a different EBB.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `next_inst()` method is intended for iterating over the instructions in an EBB like
|
||||
/// this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut cursor = FuncCursor::new(func).at_top(ebb);
|
||||
/// while let Some(inst) = cursor.next_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// The loop body can insert and remove instructions via the cursor.
|
||||
///
|
||||
/// Iterating over all the instructions in a function looks like this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_func(func: &mut Function) {
|
||||
/// let mut cursor = FuncCursor::new(func);
|
||||
/// while let Some(ebb) = cursor.next_ebb() {
|
||||
/// while let Some(inst) = cursor.next_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn next_inst(&mut self) -> Option<Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | After(..) => None,
|
||||
At(inst) => {
|
||||
if let Some(next) = self.layout().insts[inst].next.expand() {
|
||||
self.set_position(At(next));
|
||||
Some(next)
|
||||
} else {
|
||||
let pos = After(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
));
|
||||
self.set_position(pos);
|
||||
None
|
||||
}
|
||||
}
|
||||
Before(ebb) => {
|
||||
if let Some(next) = self.layout().ebbs[ebb].first_inst.expand() {
|
||||
self.set_position(At(next));
|
||||
Some(next)
|
||||
} else {
|
||||
self.set_position(After(ebb));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move to the previous instruction in the same EBB and return it.
|
||||
///
|
||||
/// - If the cursor was positioned after an EBB, go to the last instruction in that EBB.
|
||||
/// - If there are no more instructions in the EBB, go to the `Before(ebb)` position and return
|
||||
/// `None`.
|
||||
/// - If the cursor wasn't pointing anywhere, keep doing that.
|
||||
///
|
||||
/// This method will never move the cursor to a different EBB.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The `prev_inst()` method is intended for iterating backwards over the instructions in an
|
||||
/// EBB like this:
|
||||
///
|
||||
/// ```
|
||||
/// # use cretonne::ir::{Function, Ebb};
|
||||
/// # use cretonne::cursor::{Cursor, FuncCursor};
|
||||
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
|
||||
/// let mut cursor = FuncCursor::new(func).at_bottom(ebb);
|
||||
/// while let Some(inst) = cursor.prev_inst() {
|
||||
/// // Edit instructions...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn prev_inst(&mut self) -> Option<Inst> {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | Before(..) => None,
|
||||
At(inst) => {
|
||||
if let Some(prev) = self.layout().insts[inst].prev.expand() {
|
||||
self.set_position(At(prev));
|
||||
Some(prev)
|
||||
} else {
|
||||
let pos = Before(self.layout().inst_ebb(inst).expect(
|
||||
"current instruction removed?",
|
||||
));
|
||||
self.set_position(pos);
|
||||
None
|
||||
}
|
||||
}
|
||||
After(ebb) => {
|
||||
if let Some(prev) = self.layout().ebbs[ebb].last_inst.expand() {
|
||||
self.set_position(At(prev));
|
||||
Some(prev)
|
||||
} else {
|
||||
self.set_position(Before(ebb));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert an instruction at the current position.
|
||||
///
|
||||
/// - If pointing at an instruction, the new instruction is inserted before the current
|
||||
/// instruction.
|
||||
/// - If pointing at the bottom of an EBB, the new instruction is appended to the EBB.
|
||||
/// - Otherwise panic.
|
||||
///
|
||||
/// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
|
||||
/// instructions to appear in insertion order in the EBB.
|
||||
fn insert_inst(&mut self, inst: Inst) {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
Nowhere | Before(..) => panic!("Invalid insert_inst position"),
|
||||
At(cur) => self.layout_mut().insert_inst(inst, cur),
|
||||
After(ebb) => self.layout_mut().append_inst(inst, ebb),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the instruction under the cursor.
|
||||
///
|
||||
/// The cursor is left pointing at the position following the current instruction.
|
||||
///
|
||||
/// Return the instruction that was removed.
|
||||
fn remove_inst(&mut self) -> Inst {
|
||||
let inst = self.current_inst().expect("No instruction to remove");
|
||||
self.next_inst();
|
||||
self.layout_mut().remove_inst(inst);
|
||||
inst
|
||||
}
|
||||
|
||||
/// Remove the instruction under the cursor.
|
||||
///
|
||||
/// The cursor is left pointing at the position preceding the current instruction.
|
||||
///
|
||||
/// Return the instruction that was removed.
|
||||
fn remove_inst_and_step_back(&mut self) -> Inst {
|
||||
let inst = self.current_inst().expect("No instruction to remove");
|
||||
self.prev_inst();
|
||||
self.layout_mut().remove_inst(inst);
|
||||
inst
|
||||
}
|
||||
|
||||
/// Insert an EBB at the current position and switch to it.
|
||||
///
|
||||
/// As far as possible, this method behaves as if the EBB header were an instruction inserted
|
||||
/// at the current position.
|
||||
///
|
||||
/// - If the cursor is pointing at an existing instruction, *the current EBB is split in two*
|
||||
/// and the current instruction becomes the first instruction in the inserted EBB.
|
||||
/// - If the cursor points at the bottom of an EBB, the new EBB is inserted after the current
|
||||
/// one, and moved to the bottom of the new EBB where instructions can be appended.
|
||||
/// - If the cursor points to the top of an EBB, the new EBB is inserted above the current one.
|
||||
/// - If the cursor is not pointing at anything, the new EBB is placed last in the layout.
|
||||
///
|
||||
/// This means that it is always valid to call this method, and it always leaves the cursor in
|
||||
/// a state that will insert instructions into the new EBB.
|
||||
fn insert_ebb(&mut self, new_ebb: Ebb) {
|
||||
use self::CursorPosition::*;
|
||||
match self.position() {
|
||||
At(inst) => {
|
||||
self.layout_mut().split_ebb(new_ebb, inst);
|
||||
// All other cases move to `After(ebb)`, but in this case we'll stay `At(inst)`.
|
||||
return;
|
||||
}
|
||||
Nowhere => self.layout_mut().append_ebb(new_ebb),
|
||||
Before(ebb) => self.layout_mut().insert_ebb(new_ebb, ebb),
|
||||
After(ebb) => self.layout_mut().insert_ebb_after(new_ebb, ebb),
|
||||
}
|
||||
// For everything but `At(inst)` we end up appending to the new EBB.
|
||||
self.set_position(After(new_ebb));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f> CursorBase for Cursor<'f> {
|
||||
fn position(&self) -> CursorPosition {
|
||||
self.pos
|
||||
}
|
||||
|
||||
fn set_position(&mut self, pos: CursorPosition) {
|
||||
self.pos = pos;
|
||||
}
|
||||
|
||||
fn srcloc(&self) -> SourceLoc {
|
||||
self.srcloc
|
||||
}
|
||||
|
||||
fn set_srcloc(&mut self, srcloc: SourceLoc) {
|
||||
self.srcloc = srcloc
|
||||
}
|
||||
|
||||
fn layout(&self) -> &Layout {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn layout_mut(&mut self) -> &mut Layout {
|
||||
self.layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f> Cursor<'f> {
|
||||
/// Create a new `Cursor` for `layout`.
|
||||
/// The cursor holds a mutable reference to `layout` for its entire lifetime.
|
||||
pub fn new<SL: Into<Option<&'f mut SourceLocs>>>(
|
||||
layout: &'f mut Layout,
|
||||
srclocs: SL,
|
||||
) -> Cursor<'f> {
|
||||
Cursor {
|
||||
layout,
|
||||
srclocs: srclocs.into(),
|
||||
pos: CursorPosition::Nowhere,
|
||||
srcloc: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the source location of `inst` for future instructions.
|
||||
pub fn use_srcloc(&mut self, inst: Inst) {
|
||||
if let Some(ref mut ss) = self.srclocs {
|
||||
self.srcloc = ss[inst];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An instruction inserter which can be used to build and insert instructions at a cursor
|
||||
/// position.
|
||||
///
|
||||
/// This is used by `dfg.ins()`.
|
||||
pub struct LayoutCursorInserter<'c, 'fc: 'c, 'fd> {
|
||||
pos: &'c mut Cursor<'fc>,
|
||||
dfg: &'fd mut DataFlowGraph,
|
||||
}
|
||||
|
||||
impl<'c, 'fc: 'c, 'fd> LayoutCursorInserter<'c, 'fc, 'fd> {
|
||||
/// Create a new inserter. Don't use this, use `dfg.ins(pos)`.
|
||||
pub fn new(
|
||||
pos: &'c mut Cursor<'fc>,
|
||||
dfg: &'fd mut DataFlowGraph,
|
||||
) -> LayoutCursorInserter<'c, 'fc, 'fd> {
|
||||
LayoutCursorInserter { pos, dfg }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'fc: 'c, 'fd> InstInserterBase<'fd> for LayoutCursorInserter<'c, 'fc, 'fd> {
|
||||
fn data_flow_graph(&self) -> &DataFlowGraph {
|
||||
self.dfg
|
||||
}
|
||||
|
||||
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
|
||||
self.dfg
|
||||
}
|
||||
|
||||
fn insert_built_inst(self, inst: Inst, _ctrl_typevar: Type) -> &'fd mut DataFlowGraph {
|
||||
self.pos.insert_inst(inst);
|
||||
if !self.pos.srcloc.is_default() {
|
||||
if let Some(ref mut ss) = self.pos.srclocs {
|
||||
ss[inst] = self.pos.srcloc;
|
||||
} else {
|
||||
panic!("layout::Cursor missing a SourceLocs reference");
|
||||
}
|
||||
}
|
||||
self.dfg
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Layout, Cursor, CursorBase, CursorPosition};
|
||||
use cursor::{Cursor, CursorPosition};
|
||||
use super::Layout;
|
||||
use entity::EntityRef;
|
||||
use ir::{Ebb, Inst, ProgramOrder};
|
||||
use ir::{Ebb, Inst, ProgramOrder, SourceLoc};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
struct LayoutCursor<'f> {
|
||||
/// Borrowed function layout. Public so it can be re-borrowed from this cursor.
|
||||
pub layout: &'f mut Layout,
|
||||
pos: CursorPosition,
|
||||
}
|
||||
|
||||
impl<'f> Cursor for LayoutCursor<'f> {
|
||||
fn position(&self) -> CursorPosition {
|
||||
self.pos
|
||||
}
|
||||
|
||||
fn set_position(&mut self, pos: CursorPosition) {
|
||||
self.pos = pos;
|
||||
}
|
||||
|
||||
fn srcloc(&self) -> SourceLoc {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_srcloc(&mut self, _srcloc: SourceLoc) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn layout(&self) -> &Layout {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn layout_mut(&mut self) -> &mut Layout {
|
||||
self.layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f> LayoutCursor<'f> {
|
||||
/// Create a new `LayoutCursor` for `layout`.
|
||||
/// The cursor holds a mutable reference to `layout` for its entire lifetime.
|
||||
pub fn new(layout: &'f mut Layout) -> LayoutCursor<'f> {
|
||||
LayoutCursor {
|
||||
layout,
|
||||
pos: CursorPosition::Nowhere,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(layout: &mut Layout, ebbs: &[(Ebb, &[Inst])]) {
|
||||
// Check that EBBs are inserted and instructions belong the right places.
|
||||
// Check forward linkage with iterators.
|
||||
@@ -1383,7 +771,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Check backwards linkage with a cursor.
|
||||
let mut cur = Cursor::new(layout, None);
|
||||
let mut cur = LayoutCursor::new(layout);
|
||||
for &(ebb, insts) in ebbs.into_iter().rev() {
|
||||
assert_eq!(cur.prev_ebb(), Some(ebb));
|
||||
for &inst in insts.into_iter().rev() {
|
||||
@@ -1439,7 +827,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Test cursor positioning.
|
||||
let mut cur = Cursor::new(&mut layout, None);
|
||||
let mut cur = LayoutCursor::new(&mut layout);
|
||||
assert_eq!(cur.position(), CursorPosition::Nowhere);
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.position(), CursorPosition::Nowhere);
|
||||
@@ -1557,7 +945,7 @@ mod tests {
|
||||
verify(&mut layout, &[(e1, &[i1, i2, i0])]);
|
||||
|
||||
// Test cursor positioning.
|
||||
let mut cur = Cursor::new(&mut layout, None).at_top(e1);
|
||||
let mut cur = LayoutCursor::new(&mut layout).at_top(e1);
|
||||
assert_eq!(cur.position(), CursorPosition::Before(e1));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.position(), CursorPosition::Before(e1));
|
||||
@@ -1677,7 +1065,7 @@ mod tests {
|
||||
assert_eq!(layout.inst_ebb(i0), Some(e1));
|
||||
|
||||
{
|
||||
let mut cur = Cursor::new(&mut layout, None);
|
||||
let mut cur = LayoutCursor::new(&mut layout);
|
||||
assert_eq!(cur.next_ebb(), Some(e0));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), Some(e1));
|
||||
@@ -1705,7 +1093,7 @@ mod tests {
|
||||
assert_eq!(layout.inst_ebb(i3), Some(e2));
|
||||
|
||||
{
|
||||
let mut cur = Cursor::new(&mut layout, None);
|
||||
let mut cur = LayoutCursor::new(&mut layout);
|
||||
assert_eq!(cur.next_ebb(), Some(e0));
|
||||
assert_eq!(cur.next_inst(), Some(i1));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
|
||||
@@ -32,7 +32,7 @@ pub use ir::globalvar::GlobalVarData;
|
||||
pub use ir::heap::{HeapData, HeapStyle, HeapBase};
|
||||
pub use ir::instructions::{Opcode, InstructionData, VariableArgs, ValueList, ValueListPool};
|
||||
pub use ir::jumptable::JumpTableData;
|
||||
pub use ir::layout::{Layout, CursorBase, Cursor};
|
||||
pub use ir::layout::Layout;
|
||||
pub use ir::memflags::MemFlags;
|
||||
pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint};
|
||||
pub use ir::sourceloc::SourceLoc;
|
||||
|
||||
Reference in New Issue
Block a user