diff --git a/lib/cretonne/src/cursor.rs b/lib/cretonne/src/cursor.rs index 5e3ea866f5..56ad657043 100644 --- a/lib/cretonne/src/cursor.rs +++ b/lib/cretonne/src/cursor.rs @@ -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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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. /// diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index b3d13c261d..d663130280 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -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. diff --git a/lib/cretonne/src/ir/layout.rs b/lib/cretonne/src/ir/layout.rs index 1664a3ba4d..8bb61cb11f 100644 --- a/lib/cretonne/src/ir/layout.rs +++ b/lib/cretonne/src/ir/layout.rs @@ -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 { + self.ebbs[ebb].prev.expand() + } + /// Get the block following `ebb` in the layout order. pub fn next_ebb(&self, ebb: Ebb) -> Option { self.ebbs[ebb].next.expand() @@ -432,7 +436,7 @@ impl<'f> Iterator for Ebbs<'f> { fn next(&mut self) -> Option { 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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>>( - 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); diff --git a/lib/cretonne/src/ir/mod.rs b/lib/cretonne/src/ir/mod.rs index 9fafd99b9a..2165937cee 100644 --- a/lib/cretonne/src/ir/mod.rs +++ b/lib/cretonne/src/ir/mod.rs @@ -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;