Move most Cursor methods into a CursorBase trait.

The Cursor navigation methods all just depend on the cursor's position
and layout reference. Make a CursorBase trait that provides access to
this information with methods and implement the navigation methods on
top of that.

This makes it possible to have multiple types implement the cursor
interface.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-03 16:43:47 -07:00
parent f175882030
commit dba0df787c
20 changed files with 136 additions and 110 deletions

View File

@@ -355,7 +355,7 @@ def gen_xform_group(xgrp, fmt, type_sets):
'cfg: &mut ::flowgraph::ControlFlowGraph, '
'pos: &mut ir::Cursor) -> '
'bool {{'.format(xgrp.name), '}'):
fmt.line('use ir::InstBuilder;')
fmt.line('use ir::{InstBuilder, CursorBase};')
# Gen the instruction to be legalized. The cursor we're passed must be
# pointing at an instruction.

View File

@@ -28,7 +28,7 @@
//! ```
use binemit::CodeOffset;
use ir::{Function, DataFlowGraph, Cursor, InstructionData, Opcode, InstEncodings};
use ir::{Function, DataFlowGraph, Cursor, CursorBase, InstructionData, Opcode, InstEncodings};
use isa::{TargetIsa, EncInfo};
use iterators::IteratorExtras;
use result::CtonError;

View File

@@ -388,7 +388,7 @@ impl DominatorTree {
#[cfg(test)]
mod test {
use flowgraph::ControlFlowGraph;
use ir::{Function, InstBuilder, Cursor, types};
use ir::{Function, InstBuilder, Cursor, CursorBase, types};
use super::*;
use ir::types::*;
use verifier::verify_context;

View File

@@ -136,7 +136,7 @@ impl ControlFlowGraph {
#[cfg(test)]
mod tests {
use super::*;
use ir::{Function, InstBuilder, Cursor, types};
use ir::{Function, InstBuilder, Cursor, CursorBase, types};
#[test]
fn empty() {

View File

@@ -4,7 +4,7 @@
//! function. Many of its methods are generated from the meta language instruction definitions.
use ir::types;
use ir::{InstructionData, DataFlowGraph, Cursor};
use ir::{InstructionData, DataFlowGraph, Cursor, CursorBase};
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot, ValueList,
MemFlags};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
@@ -185,7 +185,7 @@ impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
#[cfg(test)]
mod tests {
use ir::{Function, Cursor, InstBuilder, ValueDef};
use ir::{Function, Cursor, CursorBase, InstBuilder, ValueDef};
use ir::types::*;
use ir::condcodes::*;

View File

@@ -865,7 +865,7 @@ impl<'a> fmt::Display for DisplayInst<'a> {
mod tests {
use super::*;
use ir::types;
use ir::{Function, Cursor, Opcode, InstructionData};
use ir::{Function, Cursor, CursorBase, Opcode, InstructionData};
#[test]
fn make_inst() {

View File

@@ -658,40 +658,34 @@ pub enum CursorPosition {
After(Ebb),
}
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(layout: &'f mut Layout) -> Cursor {
Cursor {
layout,
pos: CursorPosition::Nowhere,
}
}
/// All cursor types implement the `CursorBase` which provides common navigation operations.
pub trait CursorBase {
/// Get the current cursor position.
fn position(&self) -> CursorPosition;
/// Get the current position.
pub fn position(&self) -> CursorPosition {
self.pos
}
/// Set the current position.
fn set_position(&mut self, pos: CursorPosition);
/// Move the cursor to a new position.
pub fn set_position(&mut self, pos: CursorPosition) {
self.pos = pos;
}
/// 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;
/// Get the EBB corresponding to the current position.
pub fn current_ebb(&self) -> Option<Ebb> {
fn current_ebb(&self) -> Option<Ebb> {
use self::CursorPosition::*;
match self.pos {
match self.position() {
Nowhere => None,
At(inst) => self.layout.inst_ebb(inst),
At(inst) => self.layout().inst_ebb(inst),
Before(ebb) | After(ebb) => Some(ebb),
}
}
/// Get the instruction corresponding to the current position, if any.
pub fn current_inst(&self) -> Option<Inst> {
fn current_inst(&self) -> Option<Inst> {
use self::CursorPosition::*;
match self.pos {
match self.position() {
At(inst) => Some(inst),
_ => None,
}
@@ -699,24 +693,24 @@ impl<'f> Cursor<'f> {
/// Go to a specific instruction which must be inserted in the layout.
/// New instructions will be inserted before `inst`.
pub fn goto_inst(&mut self, inst: Inst) {
assert!(self.layout.inst_ebb(inst).is_some());
self.pos = CursorPosition::At(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 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`.
pub fn goto_top(&mut self, ebb: Ebb) {
assert!(self.layout.is_ebb_inserted(ebb));
self.pos = CursorPosition::Before(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`.
pub fn goto_bottom(&mut self, ebb: Ebb) {
assert!(self.layout.is_ebb_inserted(ebb));
self.pos = CursorPosition::After(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.
@@ -731,7 +725,7 @@ impl<'f> Cursor<'f> {
///
/// ```
/// # use cretonne::ir::{Function, Ebb};
/// # use cretonne::ir::layout::Cursor;
/// # use cretonne::ir::layout::{Cursor, CursorBase};
/// fn edit_func(func: &mut Function) {
/// let mut cursor = Cursor::new(&mut func.layout);
/// while let Some(ebb) = cursor.next_ebb() {
@@ -739,16 +733,16 @@ impl<'f> Cursor<'f> {
/// }
/// }
/// ```
pub fn next_ebb(&mut self) -> Option<Ebb> {
fn next_ebb(&mut self) -> Option<Ebb> {
let next = if let Some(ebb) = self.current_ebb() {
self.layout.ebbs[ebb].next.expand()
self.layout().ebbs[ebb].next.expand()
} else {
self.layout.first_ebb
};
self.pos = match next {
Some(ebb) => CursorPosition::Before(ebb),
None => CursorPosition::Nowhere,
self.layout().first_ebb
};
self.set_position(match next {
Some(ebb) => CursorPosition::Before(ebb),
None => CursorPosition::Nowhere,
});
next
}
@@ -764,7 +758,7 @@ impl<'f> Cursor<'f> {
///
/// ```
/// # use cretonne::ir::{Function, Ebb};
/// # use cretonne::ir::layout::Cursor;
/// # use cretonne::ir::layout::{Cursor, CursorBase};
/// fn edit_func(func: &mut Function) {
/// let mut cursor = Cursor::new(&mut func.layout);
/// while let Some(ebb) = cursor.prev_ebb() {
@@ -772,16 +766,16 @@ impl<'f> Cursor<'f> {
/// }
/// }
/// ```
pub fn prev_ebb(&mut self) -> Option<Ebb> {
fn prev_ebb(&mut self) -> Option<Ebb> {
let prev = if let Some(ebb) = self.current_ebb() {
self.layout.ebbs[ebb].prev.expand()
self.layout().ebbs[ebb].prev.expand()
} else {
self.layout.last_ebb
};
self.pos = match prev {
Some(ebb) => CursorPosition::After(ebb),
None => CursorPosition::Nowhere,
self.layout().last_ebb
};
self.set_position(match prev {
Some(ebb) => CursorPosition::After(ebb),
None => CursorPosition::Nowhere,
});
prev
}
@@ -801,7 +795,7 @@ impl<'f> Cursor<'f> {
///
/// ```
/// # use cretonne::ir::{Function, Ebb};
/// # use cretonne::ir::layout::Cursor;
/// # use cretonne::ir::layout::{Cursor, CursorBase};
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
/// let mut cursor = Cursor::new(&mut func.layout);
/// cursor.goto_top(ebb);
@@ -816,7 +810,7 @@ impl<'f> Cursor<'f> {
///
/// ```
/// # use cretonne::ir::{Function, Ebb};
/// # use cretonne::ir::layout::Cursor;
/// # use cretonne::ir::layout::{Cursor, CursorBase};
/// fn edit_func(func: &mut Function) {
/// let mut cursor = Cursor::new(&mut func.layout);
/// while let Some(ebb) = cursor.next_ebb() {
@@ -826,27 +820,28 @@ impl<'f> Cursor<'f> {
/// }
/// }
/// ```
pub fn next_inst(&mut self) -> Option<Inst> {
fn next_inst(&mut self) -> Option<Inst> {
use self::CursorPosition::*;
match self.pos {
match self.position() {
Nowhere | After(..) => None,
At(inst) => {
if let Some(next) = self.layout.insts[inst].next.expand() {
self.pos = At(next);
if let Some(next) = self.layout().insts[inst].next.expand() {
self.set_position(At(next));
Some(next)
} else {
self.pos = After(self.layout
.inst_ebb(inst)
.expect("current instruction removed?"));
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.pos = At(next);
if let Some(next) = self.layout().ebbs[ebb].first_inst.expand() {
self.set_position(At(next));
Some(next)
} else {
self.pos = After(ebb);
self.set_position(After(ebb));
None
}
}
@@ -869,7 +864,7 @@ impl<'f> Cursor<'f> {
///
/// ```
/// # use cretonne::ir::{Function, Ebb};
/// # use cretonne::ir::layout::Cursor;
/// # use cretonne::ir::layout::{Cursor, CursorBase};
/// fn edit_ebb(func: &mut Function, ebb: Ebb) {
/// let mut cursor = Cursor::new(&mut func.layout);
/// cursor.goto_bottom(ebb);
@@ -878,27 +873,28 @@ impl<'f> Cursor<'f> {
/// }
/// }
/// ```
pub fn prev_inst(&mut self) -> Option<Inst> {
fn prev_inst(&mut self) -> Option<Inst> {
use self::CursorPosition::*;
match self.pos {
match self.position() {
Nowhere | Before(..) => None,
At(inst) => {
if let Some(prev) = self.layout.insts[inst].prev.expand() {
self.pos = At(prev);
if let Some(prev) = self.layout().insts[inst].prev.expand() {
self.set_position(At(prev));
Some(prev)
} else {
self.pos = Before(self.layout
.inst_ebb(inst)
.expect("current instruction removed?"));
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.pos = At(prev);
if let Some(prev) = self.layout().ebbs[ebb].last_inst.expand() {
self.set_position(At(prev));
Some(prev)
} else {
self.pos = Before(ebb);
self.set_position(Before(ebb));
None
}
}
@@ -914,12 +910,12 @@ impl<'f> Cursor<'f> {
///
/// 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.
pub fn insert_inst(&mut self, inst: Inst) {
fn insert_inst(&mut self, inst: Inst) {
use self::CursorPosition::*;
match self.pos {
match self.position() {
Nowhere | Before(..) => panic!("Invalid insert_inst position"),
At(cur) => self.layout.insert_inst(inst, cur),
After(ebb) => self.layout.append_inst(inst, ebb),
At(cur) => self.layout_mut().insert_inst(inst, cur),
After(ebb) => self.layout_mut().append_inst(inst, ebb),
}
}
@@ -928,10 +924,10 @@ impl<'f> Cursor<'f> {
/// The cursor is left pointing at the position following the current instruction.
///
/// Return the instruction that was removed.
pub fn remove_inst(&mut self) -> Inst {
fn remove_inst(&mut self) -> Inst {
let inst = self.current_inst().expect("No instruction to remove");
self.next_inst();
self.layout.remove_inst(inst);
self.layout_mut().remove_inst(inst);
inst
}
@@ -940,10 +936,10 @@ impl<'f> Cursor<'f> {
/// The cursor is left pointing at the position preceding the current instruction.
///
/// Return the instruction that was removed.
pub fn remove_inst_and_step_back(&mut self) -> Inst {
fn remove_inst_and_step_back(&mut self) -> Inst {
let inst = self.current_inst().expect("No instruction to remove");
self.prev_inst();
self.layout.remove_inst(inst);
self.layout_mut().remove_inst(inst);
inst
}
@@ -961,27 +957,56 @@ impl<'f> Cursor<'f> {
///
/// This means that is is always valid to call this method, and it always leaves the cursor in
/// a state that will insert instructions into the new EBB.
pub fn insert_ebb(&mut self, new_ebb: Ebb) {
fn insert_ebb(&mut self, new_ebb: Ebb) {
use self::CursorPosition::*;
match self.pos {
match self.position() {
At(inst) => {
self.layout.split_ebb(new_ebb, inst);
self.layout_mut().split_ebb(new_ebb, inst);
// All other cases move to `After(ebb)`, but in this case we we'll stay `At(inst)`.
return;
}
Nowhere => self.layout.append_ebb(new_ebb),
Before(ebb) => self.layout.insert_ebb(new_ebb, ebb),
After(ebb) => self.layout.insert_ebb_after(new_ebb, ebb),
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.pos = After(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 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(layout: &'f mut Layout) -> Cursor {
Cursor {
layout,
pos: CursorPosition::Nowhere,
}
}
}
#[cfg(test)]
mod tests {
use super::{Layout, Cursor, CursorPosition};
use super::{Layout, Cursor, CursorBase, CursorPosition};
use entity_ref::EntityRef;
use ir::{Ebb, Inst, ProgramOrder};
use std::cmp::Ordering;

View File

@@ -27,7 +27,7 @@ pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData};
pub use ir::jumptable::JumpTableData;
pub use ir::valueloc::{ValueLoc, ArgumentLoc};
pub use ir::dfg::{DataFlowGraph, ValueDef};
pub use ir::layout::{Layout, Cursor};
pub use ir::layout::{Layout, CursorBase, Cursor};
pub use ir::function::Function;
pub use ir::builder::InstBuilder;
pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint};

View File

@@ -19,9 +19,9 @@
use abi::{legalize_abi_value, ValueConversion};
use flowgraph::ControlFlowGraph;
use ir::{Function, Cursor, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value, Signature, SigRef,
ArgumentType, ArgumentPurpose, ArgumentLoc, ValueLoc, ValueLocations, StackSlots,
StackSlotKind};
use ir::{Function, Cursor, CursorBase, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value,
Signature, SigRef, ArgumentType, ArgumentPurpose, ArgumentLoc, ValueLoc, ValueLocations,
StackSlots, StackSlotKind};
use ir::instructions::CallInfo;
use isa::TargetIsa;
use legalizer::split::{isplit, vsplit};

View File

@@ -15,7 +15,7 @@
use dominator_tree::DominatorTree;
use flowgraph::ControlFlowGraph;
use ir::{self, Function, Cursor};
use ir::{self, Function, Cursor, CursorBase};
use ir::condcodes::IntCC;
use isa::TargetIsa;
use bitset::BitSet;

View File

@@ -65,8 +65,8 @@
//! instructions. These loops will remain in the program.
use flowgraph::ControlFlowGraph;
use ir::{DataFlowGraph, Ebb, Inst, Cursor, Value, Type, Opcode, ValueDef, InstructionData,
InstBuilder};
use ir::{DataFlowGraph, Ebb, Inst, Cursor, CursorBase, Value, Type, Opcode, ValueDef,
InstructionData, InstBuilder};
use std::iter;
/// Split `value` into two values using the `isplit` semantics. Do this by reusing existing values

View File

@@ -1,6 +1,6 @@
//! A Loop Invariant Code Motion optimization pass
use ir::{Function, Ebb, Inst, Value, Cursor, Type, InstBuilder, Layout};
use ir::{Function, Ebb, Inst, Value, Cursor, CursorBase, Type, InstBuilder, Layout};
use flowgraph::ControlFlowGraph;
use std::collections::HashSet;
use dominator_tree::DominatorTree;

View File

@@ -199,7 +199,7 @@ impl LoopAnalysis {
#[cfg(test)]
mod test {
use ir::{Function, InstBuilder, Cursor, types};
use ir::{Function, InstBuilder, Cursor, CursorBase, types};
use loop_analysis::{Loop, LoopAnalysis};
use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree;

View File

@@ -8,7 +8,7 @@
use dbg::DisplayList;
use dominator_tree::DominatorTree;
use flowgraph::{ControlFlowGraph, BasicBlock};
use ir::{DataFlowGraph, Layout, Cursor, InstBuilder, ValueDef};
use ir::{DataFlowGraph, Layout, Cursor, CursorBase, InstBuilder, ValueDef};
use ir::{Function, Ebb, Inst, Value, ExpandedProgramPoint};
use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;

View File

@@ -43,7 +43,7 @@
//! The exception is the entry block whose arguments are colored from the ABI requirements.
use dominator_tree::DominatorTree;
use ir::{Ebb, Inst, Value, Function, Cursor, ValueLoc, DataFlowGraph, Layout};
use ir::{Ebb, Inst, Value, Function, Cursor, CursorBase, ValueLoc, DataFlowGraph, Layout};
use ir::{InstEncodings, ValueLocations};
use ir::{InstBuilder, Signature, ArgumentType, ArgumentLoc};
use isa::{RegUnit, RegClass, RegInfo, regs_overlap};

View File

@@ -11,7 +11,7 @@
use dominator_tree::DominatorTree;
use ir::{Ebb, Inst, Value, Function, Signature, DataFlowGraph, InstEncodings};
use ir::layout::{Cursor, CursorPosition};
use ir::layout::{Cursor, CursorBase, CursorPosition};
use ir::{InstBuilder, Opcode, ArgumentType, ArgumentLoc};
use isa::RegClass;
use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind};

View File

@@ -16,7 +16,7 @@
//! operands.
use dominator_tree::DominatorTree;
use ir::{DataFlowGraph, Layout, Cursor, InstBuilder};
use ir::{DataFlowGraph, Layout, Cursor, CursorBase, InstBuilder};
use ir::{Function, Ebb, Inst, Value, ValueLoc, SigRef};
use ir::{InstEncodings, StackSlots, ValueLocations};
use isa::registers::{RegClassMask, RegClassIndex};

View File

@@ -2,7 +2,7 @@
use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree;
use ir::{Cursor, InstructionData, Function, Inst, Opcode};
use ir::{Cursor, CursorBase, InstructionData, Function, Inst, Opcode};
use std::collections::HashMap;
/// Test whether the given opcode is unsafe to even consider for GVN.

View File

@@ -81,7 +81,7 @@ impl TopoOrder {
mod test {
use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree;
use ir::{Function, InstBuilder, Cursor};
use ir::{Function, InstBuilder, Cursor, CursorBase};
use std::iter;
use super::*;

View File

@@ -5,7 +5,8 @@
//! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013.
//! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg
use cretonne::ir::{Ebb, Value, Inst, Type, DataFlowGraph, JumpTables, Layout, Cursor, InstBuilder};
use cretonne::ir::{Ebb, Value, Inst, Type, DataFlowGraph, JumpTables, Layout, Cursor, CursorBase,
InstBuilder};
use cretonne::ir::instructions::BranchInfo;
use std::hash::Hash;
use cretonne::entity_map::{EntityMap, PrimaryEntityData};
@@ -607,7 +608,7 @@ impl<Variable> SSABuilder<Variable>
#[cfg(test)]
mod tests {
use cretonne::entity_ref::EntityRef;
use cretonne::ir::{Function, InstBuilder, Cursor, Inst, JumpTableData};
use cretonne::ir::{Function, InstBuilder, Cursor, CursorBase, Inst, JumpTableData};
use cretonne::ir::types::*;
use cretonne::verify_function;
use cretonne::ir::instructions::BranchInfo;