1747ad3c4Slazypassion //! Cursor library. 2747ad3c4Slazypassion //! 3747ad3c4Slazypassion //! This module defines cursor data types that can be used for inserting instructions. 4747ad3c4Slazypassion 5747ad3c4Slazypassion use crate::ir; 6747ad3c4Slazypassion 7747ad3c4Slazypassion /// The possible positions of a cursor. 8747ad3c4Slazypassion #[derive(Clone, Copy, PartialEq, Eq, Debug)] 9747ad3c4Slazypassion pub enum CursorPosition { 10747ad3c4Slazypassion /// Cursor is not pointing anywhere. No instructions can be inserted. 11747ad3c4Slazypassion Nowhere, 12747ad3c4Slazypassion /// Cursor is pointing at an existing instruction. 13747ad3c4Slazypassion /// New instructions will be inserted *before* the current instruction. 14747ad3c4Slazypassion At(ir::Inst), 1507f335dcSRyan Hunt /// Cursor is before the beginning of a block. No instructions can be inserted. Calling 16832666c4SRyan Hunt /// `next_inst()` will move to the first instruction in the block. 17832666c4SRyan Hunt Before(ir::Block), 1807f335dcSRyan Hunt /// Cursor is pointing after the end of a block. 19832666c4SRyan Hunt /// New instructions will be appended to the block. 20832666c4SRyan Hunt After(ir::Block), 21747ad3c4Slazypassion } 22747ad3c4Slazypassion 23747ad3c4Slazypassion /// All cursor types implement the `Cursor` which provides common navigation operations. 24747ad3c4Slazypassion pub trait Cursor { 25747ad3c4Slazypassion /// Get the current cursor position. position(&self) -> CursorPosition26747ad3c4Slazypassion fn position(&self) -> CursorPosition; 27747ad3c4Slazypassion 28747ad3c4Slazypassion /// Set the current position. set_position(&mut self, pos: CursorPosition)29747ad3c4Slazypassion fn set_position(&mut self, pos: CursorPosition); 30747ad3c4Slazypassion 31747ad3c4Slazypassion /// Get the source location that should be assigned to new instructions. srcloc(&self) -> ir::SourceLoc32747ad3c4Slazypassion fn srcloc(&self) -> ir::SourceLoc; 33747ad3c4Slazypassion 34747ad3c4Slazypassion /// Set the source location that should be assigned to new instructions. set_srcloc(&mut self, srcloc: ir::SourceLoc)35747ad3c4Slazypassion fn set_srcloc(&mut self, srcloc: ir::SourceLoc); 36747ad3c4Slazypassion 37747ad3c4Slazypassion /// Borrow a reference to the function layout that this cursor is navigating. layout(&self) -> &ir::Layout38747ad3c4Slazypassion fn layout(&self) -> &ir::Layout; 39747ad3c4Slazypassion 40747ad3c4Slazypassion /// Borrow a mutable reference to the function layout that this cursor is navigating. layout_mut(&mut self) -> &mut ir::Layout41747ad3c4Slazypassion fn layout_mut(&mut self) -> &mut ir::Layout; 42747ad3c4Slazypassion 43747ad3c4Slazypassion /// Exchange this cursor for one with a set source location. 44747ad3c4Slazypassion /// 45747ad3c4Slazypassion /// This is intended to be used as a builder method: 46747ad3c4Slazypassion /// 47747ad3c4Slazypassion /// ``` 48832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, SourceLoc}; 49747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 50747ad3c4Slazypassion /// fn edit_func(func: &mut Function, srcloc: SourceLoc) { 51747ad3c4Slazypassion /// let mut pos = FuncCursor::new(func).with_srcloc(srcloc); 52747ad3c4Slazypassion /// 53747ad3c4Slazypassion /// // Use `pos`... 54747ad3c4Slazypassion /// } 55747ad3c4Slazypassion /// ``` with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self where Self: Sized,56747ad3c4Slazypassion fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self 57747ad3c4Slazypassion where 58747ad3c4Slazypassion Self: Sized, 59747ad3c4Slazypassion { 60747ad3c4Slazypassion self.set_srcloc(srcloc); 61747ad3c4Slazypassion self 62747ad3c4Slazypassion } 63747ad3c4Slazypassion 64747ad3c4Slazypassion /// Rebuild this cursor positioned at `pos`. at_position(mut self, pos: CursorPosition) -> Self where Self: Sized,65747ad3c4Slazypassion fn at_position(mut self, pos: CursorPosition) -> Self 66747ad3c4Slazypassion where 67747ad3c4Slazypassion Self: Sized, 68747ad3c4Slazypassion { 69747ad3c4Slazypassion self.set_position(pos); 70747ad3c4Slazypassion self 71747ad3c4Slazypassion } 72747ad3c4Slazypassion 73747ad3c4Slazypassion /// Rebuild this cursor positioned at `inst`. 74747ad3c4Slazypassion /// 75747ad3c4Slazypassion /// This is intended to be used as a builder method: 76747ad3c4Slazypassion /// 77747ad3c4Slazypassion /// ``` 78832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 79747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 80747ad3c4Slazypassion /// fn edit_func(func: &mut Function, inst: Inst) { 81747ad3c4Slazypassion /// let mut pos = FuncCursor::new(func).at_inst(inst); 82747ad3c4Slazypassion /// 83747ad3c4Slazypassion /// // Use `pos`... 84747ad3c4Slazypassion /// } 85747ad3c4Slazypassion /// ``` at_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,86747ad3c4Slazypassion fn at_inst(mut self, inst: ir::Inst) -> Self 87747ad3c4Slazypassion where 88747ad3c4Slazypassion Self: Sized, 89747ad3c4Slazypassion { 90747ad3c4Slazypassion self.goto_inst(inst); 91747ad3c4Slazypassion self 92747ad3c4Slazypassion } 93747ad3c4Slazypassion 94832666c4SRyan Hunt /// Rebuild this cursor positioned at the first insertion point for `block`. 95747ad3c4Slazypassion /// This differs from `at_first_inst` in that it doesn't assume that any 96832666c4SRyan Hunt /// instructions have been inserted into `block` yet. 97747ad3c4Slazypassion /// 98747ad3c4Slazypassion /// This is intended to be used as a builder method: 99747ad3c4Slazypassion /// 100747ad3c4Slazypassion /// ``` 101832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 102747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 103832666c4SRyan Hunt /// fn edit_func(func: &mut Function, block: Block) { 104832666c4SRyan Hunt /// let mut pos = FuncCursor::new(func).at_first_insertion_point(block); 105747ad3c4Slazypassion /// 106747ad3c4Slazypassion /// // Use `pos`... 107747ad3c4Slazypassion /// } 108747ad3c4Slazypassion /// ``` at_first_insertion_point(mut self, block: ir::Block) -> Self where Self: Sized,109832666c4SRyan Hunt fn at_first_insertion_point(mut self, block: ir::Block) -> Self 110747ad3c4Slazypassion where 111747ad3c4Slazypassion Self: Sized, 112747ad3c4Slazypassion { 113832666c4SRyan Hunt self.goto_first_insertion_point(block); 114747ad3c4Slazypassion self 115747ad3c4Slazypassion } 116747ad3c4Slazypassion 117832666c4SRyan Hunt /// Rebuild this cursor positioned at the first instruction in `block`. 118747ad3c4Slazypassion /// 119747ad3c4Slazypassion /// This is intended to be used as a builder method: 120747ad3c4Slazypassion /// 121747ad3c4Slazypassion /// ``` 122832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 123747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 124832666c4SRyan Hunt /// fn edit_func(func: &mut Function, block: Block) { 125832666c4SRyan Hunt /// let mut pos = FuncCursor::new(func).at_first_inst(block); 126747ad3c4Slazypassion /// 127747ad3c4Slazypassion /// // Use `pos`... 128747ad3c4Slazypassion /// } 129747ad3c4Slazypassion /// ``` at_first_inst(mut self, block: ir::Block) -> Self where Self: Sized,130832666c4SRyan Hunt fn at_first_inst(mut self, block: ir::Block) -> Self 131747ad3c4Slazypassion where 132747ad3c4Slazypassion Self: Sized, 133747ad3c4Slazypassion { 134832666c4SRyan Hunt self.goto_first_inst(block); 135747ad3c4Slazypassion self 136747ad3c4Slazypassion } 137747ad3c4Slazypassion 138832666c4SRyan Hunt /// Rebuild this cursor positioned at the last instruction in `block`. 139747ad3c4Slazypassion /// 140747ad3c4Slazypassion /// This is intended to be used as a builder method: 141747ad3c4Slazypassion /// 142747ad3c4Slazypassion /// ``` 143832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 144747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 145832666c4SRyan Hunt /// fn edit_func(func: &mut Function, block: Block) { 146832666c4SRyan Hunt /// let mut pos = FuncCursor::new(func).at_last_inst(block); 147747ad3c4Slazypassion /// 148747ad3c4Slazypassion /// // Use `pos`... 149747ad3c4Slazypassion /// } 150747ad3c4Slazypassion /// ``` at_last_inst(mut self, block: ir::Block) -> Self where Self: Sized,151832666c4SRyan Hunt fn at_last_inst(mut self, block: ir::Block) -> Self 152747ad3c4Slazypassion where 153747ad3c4Slazypassion Self: Sized, 154747ad3c4Slazypassion { 155832666c4SRyan Hunt self.goto_last_inst(block); 156747ad3c4Slazypassion self 157747ad3c4Slazypassion } 158747ad3c4Slazypassion 159747ad3c4Slazypassion /// Rebuild this cursor positioned after `inst`. 160747ad3c4Slazypassion /// 161747ad3c4Slazypassion /// This is intended to be used as a builder method: 162747ad3c4Slazypassion /// 163747ad3c4Slazypassion /// ``` 164832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 165747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 166747ad3c4Slazypassion /// fn edit_func(func: &mut Function, inst: Inst) { 167747ad3c4Slazypassion /// let mut pos = FuncCursor::new(func).after_inst(inst); 168747ad3c4Slazypassion /// 169747ad3c4Slazypassion /// // Use `pos`... 170747ad3c4Slazypassion /// } 171747ad3c4Slazypassion /// ``` after_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,172747ad3c4Slazypassion fn after_inst(mut self, inst: ir::Inst) -> Self 173747ad3c4Slazypassion where 174747ad3c4Slazypassion Self: Sized, 175747ad3c4Slazypassion { 176747ad3c4Slazypassion self.goto_after_inst(inst); 177747ad3c4Slazypassion self 178747ad3c4Slazypassion } 179747ad3c4Slazypassion 180832666c4SRyan Hunt /// Rebuild this cursor positioned at the top of `block`. 181747ad3c4Slazypassion /// 182747ad3c4Slazypassion /// This is intended to be used as a builder method: 183747ad3c4Slazypassion /// 184747ad3c4Slazypassion /// ``` 185832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 186747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 187832666c4SRyan Hunt /// fn edit_func(func: &mut Function, block: Block) { 188832666c4SRyan Hunt /// let mut pos = FuncCursor::new(func).at_top(block); 189747ad3c4Slazypassion /// 190747ad3c4Slazypassion /// // Use `pos`... 191747ad3c4Slazypassion /// } 192747ad3c4Slazypassion /// ``` at_top(mut self, block: ir::Block) -> Self where Self: Sized,193832666c4SRyan Hunt fn at_top(mut self, block: ir::Block) -> Self 194747ad3c4Slazypassion where 195747ad3c4Slazypassion Self: Sized, 196747ad3c4Slazypassion { 197832666c4SRyan Hunt self.goto_top(block); 198747ad3c4Slazypassion self 199747ad3c4Slazypassion } 200747ad3c4Slazypassion 201832666c4SRyan Hunt /// Rebuild this cursor positioned at the bottom of `block`. 202747ad3c4Slazypassion /// 203747ad3c4Slazypassion /// This is intended to be used as a builder method: 204747ad3c4Slazypassion /// 205747ad3c4Slazypassion /// ``` 206832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block, Inst}; 207747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 208832666c4SRyan Hunt /// fn edit_func(func: &mut Function, block: Block) { 209832666c4SRyan Hunt /// let mut pos = FuncCursor::new(func).at_bottom(block); 210747ad3c4Slazypassion /// 211747ad3c4Slazypassion /// // Use `pos`... 212747ad3c4Slazypassion /// } 213747ad3c4Slazypassion /// ``` at_bottom(mut self, block: ir::Block) -> Self where Self: Sized,214832666c4SRyan Hunt fn at_bottom(mut self, block: ir::Block) -> Self 215747ad3c4Slazypassion where 216747ad3c4Slazypassion Self: Sized, 217747ad3c4Slazypassion { 218832666c4SRyan Hunt self.goto_bottom(block); 219747ad3c4Slazypassion self 220747ad3c4Slazypassion } 221747ad3c4Slazypassion 222832666c4SRyan Hunt /// Get the block corresponding to the current position. current_block(&self) -> Option<ir::Block>223832666c4SRyan Hunt fn current_block(&self) -> Option<ir::Block> { 224747ad3c4Slazypassion use self::CursorPosition::*; 225747ad3c4Slazypassion match self.position() { 226747ad3c4Slazypassion Nowhere => None, 227832666c4SRyan Hunt At(inst) => self.layout().inst_block(inst), 228832666c4SRyan Hunt Before(block) | After(block) => Some(block), 229747ad3c4Slazypassion } 230747ad3c4Slazypassion } 231747ad3c4Slazypassion 232747ad3c4Slazypassion /// Get the instruction corresponding to the current position, if any. current_inst(&self) -> Option<ir::Inst>233747ad3c4Slazypassion fn current_inst(&self) -> Option<ir::Inst> { 234747ad3c4Slazypassion use self::CursorPosition::*; 235747ad3c4Slazypassion match self.position() { 236747ad3c4Slazypassion At(inst) => Some(inst), 237747ad3c4Slazypassion _ => None, 238747ad3c4Slazypassion } 239747ad3c4Slazypassion } 240747ad3c4Slazypassion 241747ad3c4Slazypassion /// Go to the position after a specific instruction, which must be inserted 242747ad3c4Slazypassion /// in the layout. New instructions will be inserted after `inst`. goto_after_inst(&mut self, inst: ir::Inst)243747ad3c4Slazypassion fn goto_after_inst(&mut self, inst: ir::Inst) { 244832666c4SRyan Hunt debug_assert!(self.layout().inst_block(inst).is_some()); 245747ad3c4Slazypassion let new_pos = if let Some(next) = self.layout().next_inst(inst) { 246747ad3c4Slazypassion CursorPosition::At(next) 247747ad3c4Slazypassion } else { 248747ad3c4Slazypassion CursorPosition::After( 249747ad3c4Slazypassion self.layout() 250832666c4SRyan Hunt .inst_block(inst) 251747ad3c4Slazypassion .expect("current instruction removed?"), 252747ad3c4Slazypassion ) 253747ad3c4Slazypassion }; 254747ad3c4Slazypassion self.set_position(new_pos); 255747ad3c4Slazypassion } 256747ad3c4Slazypassion 257747ad3c4Slazypassion /// Go to a specific instruction which must be inserted in the layout. 258747ad3c4Slazypassion /// New instructions will be inserted before `inst`. goto_inst(&mut self, inst: ir::Inst)259747ad3c4Slazypassion fn goto_inst(&mut self, inst: ir::Inst) { 260832666c4SRyan Hunt debug_assert!(self.layout().inst_block(inst).is_some()); 261747ad3c4Slazypassion self.set_position(CursorPosition::At(inst)); 262747ad3c4Slazypassion } 263747ad3c4Slazypassion 264832666c4SRyan Hunt /// Go to the position for inserting instructions at the beginning of `block`, 265747ad3c4Slazypassion /// which unlike `goto_first_inst` doesn't assume that any instructions have 266832666c4SRyan Hunt /// been inserted into `block` yet. goto_first_insertion_point(&mut self, block: ir::Block)267832666c4SRyan Hunt fn goto_first_insertion_point(&mut self, block: ir::Block) { 268832666c4SRyan Hunt if let Some(inst) = self.layout().first_inst(block) { 269747ad3c4Slazypassion self.goto_inst(inst); 270747ad3c4Slazypassion } else { 271832666c4SRyan Hunt self.goto_bottom(block); 272747ad3c4Slazypassion } 273747ad3c4Slazypassion } 274747ad3c4Slazypassion 275832666c4SRyan Hunt /// Go to the first instruction in `block`. goto_first_inst(&mut self, block: ir::Block)276832666c4SRyan Hunt fn goto_first_inst(&mut self, block: ir::Block) { 277832666c4SRyan Hunt let inst = self.layout().first_inst(block).expect("Empty block"); 278747ad3c4Slazypassion self.goto_inst(inst); 279747ad3c4Slazypassion } 280747ad3c4Slazypassion 281832666c4SRyan Hunt /// Go to the last instruction in `block`. goto_last_inst(&mut self, block: ir::Block)282832666c4SRyan Hunt fn goto_last_inst(&mut self, block: ir::Block) { 283832666c4SRyan Hunt let inst = self.layout().last_inst(block).expect("Empty block"); 284747ad3c4Slazypassion self.goto_inst(inst); 285747ad3c4Slazypassion } 286747ad3c4Slazypassion 287832666c4SRyan Hunt /// Go to the top of `block` which must be inserted into the layout. 288747ad3c4Slazypassion /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first 289832666c4SRyan Hunt /// instruction in `block`. goto_top(&mut self, block: ir::Block)290832666c4SRyan Hunt fn goto_top(&mut self, block: ir::Block) { 291832666c4SRyan Hunt debug_assert!(self.layout().is_block_inserted(block)); 292832666c4SRyan Hunt self.set_position(CursorPosition::Before(block)); 293747ad3c4Slazypassion } 294747ad3c4Slazypassion 295832666c4SRyan Hunt /// Go to the bottom of `block` which must be inserted into the layout. 296832666c4SRyan Hunt /// At this position, inserted instructions will be appended to `block`. goto_bottom(&mut self, block: ir::Block)297832666c4SRyan Hunt fn goto_bottom(&mut self, block: ir::Block) { 298832666c4SRyan Hunt debug_assert!(self.layout().is_block_inserted(block)); 299832666c4SRyan Hunt self.set_position(CursorPosition::After(block)); 300747ad3c4Slazypassion } 301747ad3c4Slazypassion 302*3d4bd054SNick Fitzgerald /// Get the next position that a forwards traversal will move to, but do not 303*3d4bd054SNick Fitzgerald /// move this cursor. next_position(&self) -> CursorPosition304*3d4bd054SNick Fitzgerald fn next_position(&self) -> CursorPosition { 305*3d4bd054SNick Fitzgerald self.next_inst_position() 306*3d4bd054SNick Fitzgerald .unwrap_or_else(|| self.next_block_position()) 307*3d4bd054SNick Fitzgerald } 308*3d4bd054SNick Fitzgerald 309*3d4bd054SNick Fitzgerald /// Get the next position that a backwards traversal will move to, but do 310*3d4bd054SNick Fitzgerald /// not move this cursor. prev_position(&self) -> CursorPosition311*3d4bd054SNick Fitzgerald fn prev_position(&self) -> CursorPosition { 312*3d4bd054SNick Fitzgerald self.prev_inst_position() 313*3d4bd054SNick Fitzgerald .unwrap_or_else(|| self.prev_block_position()) 314*3d4bd054SNick Fitzgerald } 315*3d4bd054SNick Fitzgerald 316*3d4bd054SNick Fitzgerald /// Get the position that a `cursor.next_block()` call would move this 317*3d4bd054SNick Fitzgerald /// cursor to, but do not update this cursor's position. next_block_position(&self) -> CursorPosition318*3d4bd054SNick Fitzgerald fn next_block_position(&self) -> CursorPosition { 319*3d4bd054SNick Fitzgerald let next = if let Some(block) = self.current_block() { 320*3d4bd054SNick Fitzgerald self.layout().next_block(block) 321*3d4bd054SNick Fitzgerald } else { 322*3d4bd054SNick Fitzgerald self.layout().entry_block() 323*3d4bd054SNick Fitzgerald }; 324*3d4bd054SNick Fitzgerald match next { 325*3d4bd054SNick Fitzgerald Some(block) => CursorPosition::Before(block), 326*3d4bd054SNick Fitzgerald None => CursorPosition::Nowhere, 327*3d4bd054SNick Fitzgerald } 328*3d4bd054SNick Fitzgerald } 329*3d4bd054SNick Fitzgerald 330832666c4SRyan Hunt /// Go to the top of the next block in layout order and return it. 331747ad3c4Slazypassion /// 332832666c4SRyan Hunt /// - If the cursor wasn't pointing at anything, go to the top of the first block in the 333747ad3c4Slazypassion /// function. 334832666c4SRyan Hunt /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 335747ad3c4Slazypassion /// 336747ad3c4Slazypassion /// # Examples 337747ad3c4Slazypassion /// 338832666c4SRyan Hunt /// The `next_block()` method is intended for iterating over the blocks in layout order: 339747ad3c4Slazypassion /// 340747ad3c4Slazypassion /// ``` 341832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block}; 342747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 343747ad3c4Slazypassion /// fn edit_func(func: &mut Function) { 344747ad3c4Slazypassion /// let mut cursor = FuncCursor::new(func); 345832666c4SRyan Hunt /// while let Some(block) = cursor.next_block() { 346832666c4SRyan Hunt /// // Edit block. 347747ad3c4Slazypassion /// } 348747ad3c4Slazypassion /// } 349747ad3c4Slazypassion /// ``` next_block(&mut self) -> Option<ir::Block>350832666c4SRyan Hunt fn next_block(&mut self) -> Option<ir::Block> { 351*3d4bd054SNick Fitzgerald let pos = self.next_block_position(); 352*3d4bd054SNick Fitzgerald self.set_position(pos); 353*3d4bd054SNick Fitzgerald self.current_block() 354*3d4bd054SNick Fitzgerald } 355*3d4bd054SNick Fitzgerald 356*3d4bd054SNick Fitzgerald /// Get the position that a `cursor.prev_block()` call would move this 357*3d4bd054SNick Fitzgerald /// cursor to, but do not update this cursor's position. prev_block_position(&self) -> CursorPosition358*3d4bd054SNick Fitzgerald fn prev_block_position(&self) -> CursorPosition { 359*3d4bd054SNick Fitzgerald let prev = if let Some(block) = self.current_block() { 360*3d4bd054SNick Fitzgerald self.layout().prev_block(block) 361747ad3c4Slazypassion } else { 362*3d4bd054SNick Fitzgerald self.layout().last_block() 363747ad3c4Slazypassion }; 364*3d4bd054SNick Fitzgerald match prev { 365*3d4bd054SNick Fitzgerald Some(block) => CursorPosition::After(block), 366747ad3c4Slazypassion None => CursorPosition::Nowhere, 367*3d4bd054SNick Fitzgerald } 368747ad3c4Slazypassion } 369747ad3c4Slazypassion 370832666c4SRyan Hunt /// Go to the bottom of the previous block in layout order and return it. 371747ad3c4Slazypassion /// 372832666c4SRyan Hunt /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the 373747ad3c4Slazypassion /// function. 374832666c4SRyan Hunt /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 375747ad3c4Slazypassion /// 376747ad3c4Slazypassion /// # Examples 377747ad3c4Slazypassion /// 378832666c4SRyan Hunt /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order: 379747ad3c4Slazypassion /// 380747ad3c4Slazypassion /// ``` 381832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block}; 382747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 383747ad3c4Slazypassion /// fn edit_func(func: &mut Function) { 384747ad3c4Slazypassion /// let mut cursor = FuncCursor::new(func); 385832666c4SRyan Hunt /// while let Some(block) = cursor.prev_block() { 386832666c4SRyan Hunt /// // Edit block. 387747ad3c4Slazypassion /// } 388747ad3c4Slazypassion /// } 389747ad3c4Slazypassion /// ``` prev_block(&mut self) -> Option<ir::Block>390832666c4SRyan Hunt fn prev_block(&mut self) -> Option<ir::Block> { 391*3d4bd054SNick Fitzgerald let pos = self.prev_block_position(); 392*3d4bd054SNick Fitzgerald self.set_position(pos); 393*3d4bd054SNick Fitzgerald self.current_block() 394*3d4bd054SNick Fitzgerald } 395*3d4bd054SNick Fitzgerald 396*3d4bd054SNick Fitzgerald /// Get the position that a `cursor.next_inst()` call would move this cursor 397*3d4bd054SNick Fitzgerald /// to, but do not update this cursor's position. next_inst_position(&self) -> Option<CursorPosition>398*3d4bd054SNick Fitzgerald fn next_inst_position(&self) -> Option<CursorPosition> { 399*3d4bd054SNick Fitzgerald use self::CursorPosition::*; 400*3d4bd054SNick Fitzgerald match self.position() { 401*3d4bd054SNick Fitzgerald Nowhere | After(..) => None, 402*3d4bd054SNick Fitzgerald At(inst) => { 403*3d4bd054SNick Fitzgerald if let Some(next) = self.layout().next_inst(inst) { 404*3d4bd054SNick Fitzgerald Some(At(next)) 405747ad3c4Slazypassion } else { 406*3d4bd054SNick Fitzgerald Some(After( 407*3d4bd054SNick Fitzgerald self.layout() 408*3d4bd054SNick Fitzgerald .inst_block(inst) 409*3d4bd054SNick Fitzgerald .expect("current instruction removed?"), 410*3d4bd054SNick Fitzgerald )) 411*3d4bd054SNick Fitzgerald } 412*3d4bd054SNick Fitzgerald } 413*3d4bd054SNick Fitzgerald Before(block) => { 414*3d4bd054SNick Fitzgerald if let Some(next) = self.layout().first_inst(block) { 415*3d4bd054SNick Fitzgerald Some(At(next)) 416*3d4bd054SNick Fitzgerald } else { 417*3d4bd054SNick Fitzgerald Some(After(block)) 418*3d4bd054SNick Fitzgerald } 419*3d4bd054SNick Fitzgerald } 420*3d4bd054SNick Fitzgerald } 421747ad3c4Slazypassion } 422747ad3c4Slazypassion 423832666c4SRyan Hunt /// Move to the next instruction in the same block and return it. 424747ad3c4Slazypassion /// 42507f335dcSRyan Hunt /// - If the cursor was positioned before a block, go to the first instruction in that block. 426832666c4SRyan Hunt /// - If there are no more instructions in the block, go to the `After(block)` position and return 427747ad3c4Slazypassion /// `None`. 428747ad3c4Slazypassion /// - If the cursor wasn't pointing anywhere, keep doing that. 429747ad3c4Slazypassion /// 430832666c4SRyan Hunt /// This method will never move the cursor to a different block. 431747ad3c4Slazypassion /// 432747ad3c4Slazypassion /// # Examples 433747ad3c4Slazypassion /// 43407f335dcSRyan Hunt /// The `next_inst()` method is intended for iterating over the instructions in a block like 435747ad3c4Slazypassion /// this: 436747ad3c4Slazypassion /// 437747ad3c4Slazypassion /// ``` 438832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block}; 439747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 440832666c4SRyan Hunt /// fn edit_block(func: &mut Function, block: Block) { 441832666c4SRyan Hunt /// let mut cursor = FuncCursor::new(func).at_top(block); 442747ad3c4Slazypassion /// while let Some(inst) = cursor.next_inst() { 443747ad3c4Slazypassion /// // Edit instructions... 444747ad3c4Slazypassion /// } 445747ad3c4Slazypassion /// } 446747ad3c4Slazypassion /// ``` 447747ad3c4Slazypassion /// The loop body can insert and remove instructions via the cursor. 448747ad3c4Slazypassion /// 449747ad3c4Slazypassion /// Iterating over all the instructions in a function looks like this: 450747ad3c4Slazypassion /// 451747ad3c4Slazypassion /// ``` 452832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block}; 453747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 454747ad3c4Slazypassion /// fn edit_func(func: &mut Function) { 455747ad3c4Slazypassion /// let mut cursor = FuncCursor::new(func); 456832666c4SRyan Hunt /// while let Some(block) = cursor.next_block() { 457747ad3c4Slazypassion /// while let Some(inst) = cursor.next_inst() { 458747ad3c4Slazypassion /// // Edit instructions... 459747ad3c4Slazypassion /// } 460747ad3c4Slazypassion /// } 461747ad3c4Slazypassion /// } 462747ad3c4Slazypassion /// ``` next_inst(&mut self) -> Option<ir::Inst>463747ad3c4Slazypassion fn next_inst(&mut self) -> Option<ir::Inst> { 464*3d4bd054SNick Fitzgerald let pos = self.next_inst_position()?; 465*3d4bd054SNick Fitzgerald self.set_position(pos); 466*3d4bd054SNick Fitzgerald self.current_inst() 467*3d4bd054SNick Fitzgerald } 468*3d4bd054SNick Fitzgerald 469*3d4bd054SNick Fitzgerald /// Get the position that a `cursor.prev_inst()` call would move this cursor 470*3d4bd054SNick Fitzgerald /// to, but do not update this cursor's position. prev_inst_position(&self) -> Option<CursorPosition>471*3d4bd054SNick Fitzgerald fn prev_inst_position(&self) -> Option<CursorPosition> { 472747ad3c4Slazypassion use self::CursorPosition::*; 473747ad3c4Slazypassion match self.position() { 474*3d4bd054SNick Fitzgerald Nowhere | Before(..) => None, 475747ad3c4Slazypassion At(inst) => { 476*3d4bd054SNick Fitzgerald if let Some(prev) = self.layout().prev_inst(inst) { 477*3d4bd054SNick Fitzgerald Some(At(prev)) 478747ad3c4Slazypassion } else { 479*3d4bd054SNick Fitzgerald Some(Before( 480747ad3c4Slazypassion self.layout() 481832666c4SRyan Hunt .inst_block(inst) 482747ad3c4Slazypassion .expect("current instruction removed?"), 483*3d4bd054SNick Fitzgerald )) 484747ad3c4Slazypassion } 485747ad3c4Slazypassion } 486*3d4bd054SNick Fitzgerald After(block) => { 487*3d4bd054SNick Fitzgerald if let Some(prev) = self.layout().last_inst(block) { 488*3d4bd054SNick Fitzgerald Some(At(prev)) 489747ad3c4Slazypassion } else { 490*3d4bd054SNick Fitzgerald Some(Before(block)) 491747ad3c4Slazypassion } 492747ad3c4Slazypassion } 493747ad3c4Slazypassion } 494747ad3c4Slazypassion } 495747ad3c4Slazypassion 496832666c4SRyan Hunt /// Move to the previous instruction in the same block and return it. 497747ad3c4Slazypassion /// 49807f335dcSRyan Hunt /// - If the cursor was positioned after a block, go to the last instruction in that block. 499832666c4SRyan Hunt /// - If there are no more instructions in the block, go to the `Before(block)` position and return 500747ad3c4Slazypassion /// `None`. 501747ad3c4Slazypassion /// - If the cursor wasn't pointing anywhere, keep doing that. 502747ad3c4Slazypassion /// 503832666c4SRyan Hunt /// This method will never move the cursor to a different block. 504747ad3c4Slazypassion /// 505747ad3c4Slazypassion /// # Examples 506747ad3c4Slazypassion /// 507747ad3c4Slazypassion /// The `prev_inst()` method is intended for iterating backwards over the instructions in an 508832666c4SRyan Hunt /// block like this: 509747ad3c4Slazypassion /// 510747ad3c4Slazypassion /// ``` 511832666c4SRyan Hunt /// # use cranelift_codegen::ir::{Function, Block}; 512747ad3c4Slazypassion /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 513832666c4SRyan Hunt /// fn edit_block(func: &mut Function, block: Block) { 514832666c4SRyan Hunt /// let mut cursor = FuncCursor::new(func).at_bottom(block); 515747ad3c4Slazypassion /// while let Some(inst) = cursor.prev_inst() { 516747ad3c4Slazypassion /// // Edit instructions... 517747ad3c4Slazypassion /// } 518747ad3c4Slazypassion /// } 519747ad3c4Slazypassion /// ``` prev_inst(&mut self) -> Option<ir::Inst>520747ad3c4Slazypassion fn prev_inst(&mut self) -> Option<ir::Inst> { 521*3d4bd054SNick Fitzgerald let pos = self.prev_inst_position()?; 522747ad3c4Slazypassion self.set_position(pos); 523*3d4bd054SNick Fitzgerald self.current_inst() 524747ad3c4Slazypassion } 525747ad3c4Slazypassion 526747ad3c4Slazypassion /// Insert an instruction at the current position. 527747ad3c4Slazypassion /// 528747ad3c4Slazypassion /// - If pointing at an instruction, the new instruction is inserted before the current 529747ad3c4Slazypassion /// instruction. 53007f335dcSRyan Hunt /// - If pointing at the bottom of a block, the new instruction is appended to the block. 531747ad3c4Slazypassion /// - Otherwise panic. 532747ad3c4Slazypassion /// 533747ad3c4Slazypassion /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes 534832666c4SRyan Hunt /// instructions to appear in insertion order in the block. insert_inst(&mut self, inst: ir::Inst)535747ad3c4Slazypassion fn insert_inst(&mut self, inst: ir::Inst) { 536747ad3c4Slazypassion use self::CursorPosition::*; 537747ad3c4Slazypassion match self.position() { 538747ad3c4Slazypassion Nowhere | Before(..) => panic!("Invalid insert_inst position"), 539747ad3c4Slazypassion At(cur) => self.layout_mut().insert_inst(inst, cur), 540832666c4SRyan Hunt After(block) => self.layout_mut().append_inst(inst, block), 541747ad3c4Slazypassion } 542747ad3c4Slazypassion } 543747ad3c4Slazypassion 544747ad3c4Slazypassion /// Remove the instruction under the cursor. 545747ad3c4Slazypassion /// 546747ad3c4Slazypassion /// The cursor is left pointing at the position following the current instruction. 547747ad3c4Slazypassion /// 548747ad3c4Slazypassion /// Return the instruction that was removed. remove_inst(&mut self) -> ir::Inst549747ad3c4Slazypassion fn remove_inst(&mut self) -> ir::Inst { 550747ad3c4Slazypassion let inst = self.current_inst().expect("No instruction to remove"); 551747ad3c4Slazypassion self.next_inst(); 552747ad3c4Slazypassion self.layout_mut().remove_inst(inst); 553747ad3c4Slazypassion inst 554747ad3c4Slazypassion } 555747ad3c4Slazypassion 556747ad3c4Slazypassion /// Remove the instruction under the cursor. 557747ad3c4Slazypassion /// 558747ad3c4Slazypassion /// The cursor is left pointing at the position preceding the current instruction. 559747ad3c4Slazypassion /// 560747ad3c4Slazypassion /// Return the instruction that was removed. remove_inst_and_step_back(&mut self) -> ir::Inst561747ad3c4Slazypassion fn remove_inst_and_step_back(&mut self) -> ir::Inst { 562747ad3c4Slazypassion let inst = self.current_inst().expect("No instruction to remove"); 563747ad3c4Slazypassion self.prev_inst(); 564747ad3c4Slazypassion self.layout_mut().remove_inst(inst); 565747ad3c4Slazypassion inst 566747ad3c4Slazypassion } 567747ad3c4Slazypassion 5687bf31723SNick Fitzgerald /// Replace the instruction under the cursor with `new_inst`. 5697bf31723SNick Fitzgerald /// 5707bf31723SNick Fitzgerald /// The cursor is left pointing at the new instruction. 5717bf31723SNick Fitzgerald /// 5727bf31723SNick Fitzgerald /// The old instruction that was replaced is returned. replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst5737bf31723SNick Fitzgerald fn replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst { 5747bf31723SNick Fitzgerald let prev_inst = self.remove_inst(); 5757bf31723SNick Fitzgerald self.insert_inst(new_inst); 5767bf31723SNick Fitzgerald prev_inst 5777bf31723SNick Fitzgerald } 5787bf31723SNick Fitzgerald 57907f335dcSRyan Hunt /// Insert a block at the current position and switch to it. 580747ad3c4Slazypassion /// 581832666c4SRyan Hunt /// As far as possible, this method behaves as if the block header were an instruction inserted 582747ad3c4Slazypassion /// at the current position. 583747ad3c4Slazypassion /// 584832666c4SRyan Hunt /// - If the cursor is pointing at an existing instruction, *the current block is split in two* 585832666c4SRyan Hunt /// and the current instruction becomes the first instruction in the inserted block. 58607f335dcSRyan Hunt /// - If the cursor points at the bottom of a block, the new block is inserted after the current 587832666c4SRyan Hunt /// one, and moved to the bottom of the new block where instructions can be appended. 58807f335dcSRyan Hunt /// - If the cursor points to the top of a block, the new block is inserted above the current one. 589832666c4SRyan Hunt /// - If the cursor is not pointing at anything, the new block is placed last in the layout. 590747ad3c4Slazypassion /// 591747ad3c4Slazypassion /// This means that it is always valid to call this method, and it always leaves the cursor in 592832666c4SRyan Hunt /// a state that will insert instructions into the new block. insert_block(&mut self, new_block: ir::Block)593832666c4SRyan Hunt fn insert_block(&mut self, new_block: ir::Block) { 594747ad3c4Slazypassion use self::CursorPosition::*; 595747ad3c4Slazypassion match self.position() { 596747ad3c4Slazypassion At(inst) => { 597832666c4SRyan Hunt self.layout_mut().split_block(new_block, inst); 598832666c4SRyan Hunt // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`. 599747ad3c4Slazypassion return; 600747ad3c4Slazypassion } 601832666c4SRyan Hunt Nowhere => self.layout_mut().append_block(new_block), 602832666c4SRyan Hunt Before(block) => self.layout_mut().insert_block(new_block, block), 603832666c4SRyan Hunt After(block) => self.layout_mut().insert_block_after(new_block, block), 604747ad3c4Slazypassion } 605832666c4SRyan Hunt // For everything but `At(inst)` we end up appending to the new block. 606832666c4SRyan Hunt self.set_position(After(new_block)); 607747ad3c4Slazypassion } 608747ad3c4Slazypassion } 609747ad3c4Slazypassion 610747ad3c4Slazypassion /// Function cursor. 611747ad3c4Slazypassion /// 612747ad3c4Slazypassion /// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position 613747ad3c4Slazypassion /// too. The function can be re-borrowed by accessing the public `cur.func` member. 614747ad3c4Slazypassion /// 615747ad3c4Slazypassion /// This cursor is for use before legalization. The inserted instructions are not given an 616747ad3c4Slazypassion /// encoding. 617747ad3c4Slazypassion pub struct FuncCursor<'f> { 618747ad3c4Slazypassion pos: CursorPosition, 619747ad3c4Slazypassion srcloc: ir::SourceLoc, 620747ad3c4Slazypassion 621747ad3c4Slazypassion /// The referenced function. 622747ad3c4Slazypassion pub func: &'f mut ir::Function, 623747ad3c4Slazypassion } 624747ad3c4Slazypassion 625747ad3c4Slazypassion impl<'f> FuncCursor<'f> { 626747ad3c4Slazypassion /// Create a new `FuncCursor` pointing nowhere. new(func: &'f mut ir::Function) -> Self627747ad3c4Slazypassion pub fn new(func: &'f mut ir::Function) -> Self { 628747ad3c4Slazypassion Self { 629747ad3c4Slazypassion pos: CursorPosition::Nowhere, 630747ad3c4Slazypassion srcloc: Default::default(), 631747ad3c4Slazypassion func, 632747ad3c4Slazypassion } 633747ad3c4Slazypassion } 634747ad3c4Slazypassion 635747ad3c4Slazypassion /// Use the source location of `inst` for future instructions. use_srcloc(&mut self, inst: ir::Inst)636747ad3c4Slazypassion pub fn use_srcloc(&mut self, inst: ir::Inst) { 6378a9b1a90SBenjamin Bouvier self.srcloc = self.func.srcloc(inst); 638747ad3c4Slazypassion } 639747ad3c4Slazypassion 640747ad3c4Slazypassion /// Create an instruction builder that inserts an instruction at the current position. ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>>641868f0c38SNick Fitzgerald pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> { 642747ad3c4Slazypassion ir::InsertBuilder::new(self) 643747ad3c4Slazypassion } 644747ad3c4Slazypassion } 645747ad3c4Slazypassion 646747ad3c4Slazypassion impl<'f> Cursor for FuncCursor<'f> { position(&self) -> CursorPosition647747ad3c4Slazypassion fn position(&self) -> CursorPosition { 648747ad3c4Slazypassion self.pos 649747ad3c4Slazypassion } 650747ad3c4Slazypassion set_position(&mut self, pos: CursorPosition)651747ad3c4Slazypassion fn set_position(&mut self, pos: CursorPosition) { 652747ad3c4Slazypassion self.pos = pos 653747ad3c4Slazypassion } 654747ad3c4Slazypassion srcloc(&self) -> ir::SourceLoc655747ad3c4Slazypassion fn srcloc(&self) -> ir::SourceLoc { 656747ad3c4Slazypassion self.srcloc 657747ad3c4Slazypassion } 658747ad3c4Slazypassion set_srcloc(&mut self, srcloc: ir::SourceLoc)659747ad3c4Slazypassion fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { 6608a9b1a90SBenjamin Bouvier self.func.params.ensure_base_srcloc(srcloc); 661747ad3c4Slazypassion self.srcloc = srcloc; 662747ad3c4Slazypassion } 663747ad3c4Slazypassion layout(&self) -> &ir::Layout664747ad3c4Slazypassion fn layout(&self) -> &ir::Layout { 665747ad3c4Slazypassion &self.func.layout 666747ad3c4Slazypassion } 667747ad3c4Slazypassion layout_mut(&mut self) -> &mut ir::Layout668747ad3c4Slazypassion fn layout_mut(&mut self) -> &mut ir::Layout { 669747ad3c4Slazypassion &mut self.func.layout 670747ad3c4Slazypassion } 671747ad3c4Slazypassion } 672747ad3c4Slazypassion 673747ad3c4Slazypassion impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> { data_flow_graph(&self) -> &ir::DataFlowGraph674747ad3c4Slazypassion fn data_flow_graph(&self) -> &ir::DataFlowGraph { 675747ad3c4Slazypassion &self.func.dfg 676747ad3c4Slazypassion } 677747ad3c4Slazypassion data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph678747ad3c4Slazypassion fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { 679747ad3c4Slazypassion &mut self.func.dfg 680747ad3c4Slazypassion } 681747ad3c4Slazypassion insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph682bae4ec64SBenjamin Bouvier fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph { 683747ad3c4Slazypassion self.insert_inst(inst); 684747ad3c4Slazypassion if !self.srcloc.is_default() { 6858a9b1a90SBenjamin Bouvier self.func.set_srcloc(inst, self.srcloc); 686747ad3c4Slazypassion } 687747ad3c4Slazypassion &mut self.func.dfg 688747ad3c4Slazypassion } 689747ad3c4Slazypassion } 690