1 //! Cursor library. 2 //! 3 //! This module defines cursor data types that can be used for inserting instructions. 4 5 use crate::ir; 6 7 /// The possible positions of a cursor. 8 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 9 pub enum CursorPosition { 10 /// Cursor is not pointing anywhere. No instructions can be inserted. 11 Nowhere, 12 /// Cursor is pointing at an existing instruction. 13 /// New instructions will be inserted *before* the current instruction. 14 At(ir::Inst), 15 /// Cursor is before the beginning of a block. No instructions can be inserted. Calling 16 /// `next_inst()` will move to the first instruction in the block. 17 Before(ir::Block), 18 /// Cursor is pointing after the end of a block. 19 /// New instructions will be appended to the block. 20 After(ir::Block), 21 } 22 23 /// All cursor types implement the `Cursor` which provides common navigation operations. 24 pub trait Cursor { 25 /// Get the current cursor position. 26 fn position(&self) -> CursorPosition; 27 28 /// Set the current position. 29 fn set_position(&mut self, pos: CursorPosition); 30 31 /// Get the source location that should be assigned to new instructions. 32 fn srcloc(&self) -> ir::SourceLoc; 33 34 /// Set the source location that should be assigned to new instructions. 35 fn set_srcloc(&mut self, srcloc: ir::SourceLoc); 36 37 /// Borrow a reference to the function layout that this cursor is navigating. 38 fn layout(&self) -> &ir::Layout; 39 40 /// Borrow a mutable reference to the function layout that this cursor is navigating. 41 fn layout_mut(&mut self) -> &mut ir::Layout; 42 43 /// Exchange this cursor for one with a set source location. 44 /// 45 /// This is intended to be used as a builder method: 46 /// 47 /// ``` 48 /// # use cranelift_codegen::ir::{Function, Block, SourceLoc}; 49 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 50 /// fn edit_func(func: &mut Function, srcloc: SourceLoc) { 51 /// let mut pos = FuncCursor::new(func).with_srcloc(srcloc); 52 /// 53 /// // Use `pos`... 54 /// } 55 /// ``` 56 fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self 57 where 58 Self: Sized, 59 { 60 self.set_srcloc(srcloc); 61 self 62 } 63 64 /// Rebuild this cursor positioned at `pos`. 65 fn at_position(mut self, pos: CursorPosition) -> Self 66 where 67 Self: Sized, 68 { 69 self.set_position(pos); 70 self 71 } 72 73 /// Rebuild this cursor positioned at `inst`. 74 /// 75 /// This is intended to be used as a builder method: 76 /// 77 /// ``` 78 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 79 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 80 /// fn edit_func(func: &mut Function, inst: Inst) { 81 /// let mut pos = FuncCursor::new(func).at_inst(inst); 82 /// 83 /// // Use `pos`... 84 /// } 85 /// ``` 86 fn at_inst(mut self, inst: ir::Inst) -> Self 87 where 88 Self: Sized, 89 { 90 self.goto_inst(inst); 91 self 92 } 93 94 /// Rebuild this cursor positioned at the first insertion point for `block`. 95 /// This differs from `at_first_inst` in that it doesn't assume that any 96 /// instructions have been inserted into `block` yet. 97 /// 98 /// This is intended to be used as a builder method: 99 /// 100 /// ``` 101 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 102 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 103 /// fn edit_func(func: &mut Function, block: Block) { 104 /// let mut pos = FuncCursor::new(func).at_first_insertion_point(block); 105 /// 106 /// // Use `pos`... 107 /// } 108 /// ``` 109 fn at_first_insertion_point(mut self, block: ir::Block) -> Self 110 where 111 Self: Sized, 112 { 113 self.goto_first_insertion_point(block); 114 self 115 } 116 117 /// Rebuild this cursor positioned at the first instruction in `block`. 118 /// 119 /// This is intended to be used as a builder method: 120 /// 121 /// ``` 122 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 123 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 124 /// fn edit_func(func: &mut Function, block: Block) { 125 /// let mut pos = FuncCursor::new(func).at_first_inst(block); 126 /// 127 /// // Use `pos`... 128 /// } 129 /// ``` 130 fn at_first_inst(mut self, block: ir::Block) -> Self 131 where 132 Self: Sized, 133 { 134 self.goto_first_inst(block); 135 self 136 } 137 138 /// Rebuild this cursor positioned at the last instruction in `block`. 139 /// 140 /// This is intended to be used as a builder method: 141 /// 142 /// ``` 143 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 144 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 145 /// fn edit_func(func: &mut Function, block: Block) { 146 /// let mut pos = FuncCursor::new(func).at_last_inst(block); 147 /// 148 /// // Use `pos`... 149 /// } 150 /// ``` 151 fn at_last_inst(mut self, block: ir::Block) -> Self 152 where 153 Self: Sized, 154 { 155 self.goto_last_inst(block); 156 self 157 } 158 159 /// Rebuild this cursor positioned after `inst`. 160 /// 161 /// This is intended to be used as a builder method: 162 /// 163 /// ``` 164 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 165 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 166 /// fn edit_func(func: &mut Function, inst: Inst) { 167 /// let mut pos = FuncCursor::new(func).after_inst(inst); 168 /// 169 /// // Use `pos`... 170 /// } 171 /// ``` 172 fn after_inst(mut self, inst: ir::Inst) -> Self 173 where 174 Self: Sized, 175 { 176 self.goto_after_inst(inst); 177 self 178 } 179 180 /// Rebuild this cursor positioned at the top of `block`. 181 /// 182 /// This is intended to be used as a builder method: 183 /// 184 /// ``` 185 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 186 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 187 /// fn edit_func(func: &mut Function, block: Block) { 188 /// let mut pos = FuncCursor::new(func).at_top(block); 189 /// 190 /// // Use `pos`... 191 /// } 192 /// ``` 193 fn at_top(mut self, block: ir::Block) -> Self 194 where 195 Self: Sized, 196 { 197 self.goto_top(block); 198 self 199 } 200 201 /// Rebuild this cursor positioned at the bottom of `block`. 202 /// 203 /// This is intended to be used as a builder method: 204 /// 205 /// ``` 206 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 207 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 208 /// fn edit_func(func: &mut Function, block: Block) { 209 /// let mut pos = FuncCursor::new(func).at_bottom(block); 210 /// 211 /// // Use `pos`... 212 /// } 213 /// ``` 214 fn at_bottom(mut self, block: ir::Block) -> Self 215 where 216 Self: Sized, 217 { 218 self.goto_bottom(block); 219 self 220 } 221 222 /// Get the block corresponding to the current position. 223 fn current_block(&self) -> Option<ir::Block> { 224 use self::CursorPosition::*; 225 match self.position() { 226 Nowhere => None, 227 At(inst) => self.layout().inst_block(inst), 228 Before(block) | After(block) => Some(block), 229 } 230 } 231 232 /// Get the instruction corresponding to the current position, if any. 233 fn current_inst(&self) -> Option<ir::Inst> { 234 use self::CursorPosition::*; 235 match self.position() { 236 At(inst) => Some(inst), 237 _ => None, 238 } 239 } 240 241 /// Go to the position after a specific instruction, which must be inserted 242 /// in the layout. New instructions will be inserted after `inst`. 243 fn goto_after_inst(&mut self, inst: ir::Inst) { 244 debug_assert!(self.layout().inst_block(inst).is_some()); 245 let new_pos = if let Some(next) = self.layout().next_inst(inst) { 246 CursorPosition::At(next) 247 } else { 248 CursorPosition::After( 249 self.layout() 250 .inst_block(inst) 251 .expect("current instruction removed?"), 252 ) 253 }; 254 self.set_position(new_pos); 255 } 256 257 /// Go to a specific instruction which must be inserted in the layout. 258 /// New instructions will be inserted before `inst`. 259 fn goto_inst(&mut self, inst: ir::Inst) { 260 debug_assert!(self.layout().inst_block(inst).is_some()); 261 self.set_position(CursorPosition::At(inst)); 262 } 263 264 /// Go to the position for inserting instructions at the beginning of `block`, 265 /// which unlike `goto_first_inst` doesn't assume that any instructions have 266 /// been inserted into `block` yet. 267 fn goto_first_insertion_point(&mut self, block: ir::Block) { 268 if let Some(inst) = self.layout().first_inst(block) { 269 self.goto_inst(inst); 270 } else { 271 self.goto_bottom(block); 272 } 273 } 274 275 /// Go to the first instruction in `block`. 276 fn goto_first_inst(&mut self, block: ir::Block) { 277 let inst = self.layout().first_inst(block).expect("Empty block"); 278 self.goto_inst(inst); 279 } 280 281 /// Go to the last instruction in `block`. 282 fn goto_last_inst(&mut self, block: ir::Block) { 283 let inst = self.layout().last_inst(block).expect("Empty block"); 284 self.goto_inst(inst); 285 } 286 287 /// Go to the top of `block` which must be inserted into the layout. 288 /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first 289 /// instruction in `block`. 290 fn goto_top(&mut self, block: ir::Block) { 291 debug_assert!(self.layout().is_block_inserted(block)); 292 self.set_position(CursorPosition::Before(block)); 293 } 294 295 /// Go to the bottom of `block` which must be inserted into the layout. 296 /// At this position, inserted instructions will be appended to `block`. 297 fn goto_bottom(&mut self, block: ir::Block) { 298 debug_assert!(self.layout().is_block_inserted(block)); 299 self.set_position(CursorPosition::After(block)); 300 } 301 302 /// Go to the top of the next block in layout order and return it. 303 /// 304 /// - If the cursor wasn't pointing at anything, go to the top of the first block in the 305 /// function. 306 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 307 /// 308 /// # Examples 309 /// 310 /// The `next_block()` method is intended for iterating over the blocks in layout order: 311 /// 312 /// ``` 313 /// # use cranelift_codegen::ir::{Function, Block}; 314 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 315 /// fn edit_func(func: &mut Function) { 316 /// let mut cursor = FuncCursor::new(func); 317 /// while let Some(block) = cursor.next_block() { 318 /// // Edit block. 319 /// } 320 /// } 321 /// ``` 322 fn next_block(&mut self) -> Option<ir::Block> { 323 let next = if let Some(block) = self.current_block() { 324 self.layout().next_block(block) 325 } else { 326 self.layout().entry_block() 327 }; 328 self.set_position(match next { 329 Some(block) => CursorPosition::Before(block), 330 None => CursorPosition::Nowhere, 331 }); 332 next 333 } 334 335 /// Go to the bottom of the previous block in layout order and return it. 336 /// 337 /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the 338 /// function. 339 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 340 /// 341 /// # Examples 342 /// 343 /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order: 344 /// 345 /// ``` 346 /// # use cranelift_codegen::ir::{Function, Block}; 347 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 348 /// fn edit_func(func: &mut Function) { 349 /// let mut cursor = FuncCursor::new(func); 350 /// while let Some(block) = cursor.prev_block() { 351 /// // Edit block. 352 /// } 353 /// } 354 /// ``` 355 fn prev_block(&mut self) -> Option<ir::Block> { 356 let prev = if let Some(block) = self.current_block() { 357 self.layout().prev_block(block) 358 } else { 359 self.layout().last_block() 360 }; 361 self.set_position(match prev { 362 Some(block) => CursorPosition::After(block), 363 None => CursorPosition::Nowhere, 364 }); 365 prev 366 } 367 368 /// Move to the next instruction in the same block and return it. 369 /// 370 /// - If the cursor was positioned before a block, go to the first instruction in that block. 371 /// - If there are no more instructions in the block, go to the `After(block)` position and return 372 /// `None`. 373 /// - If the cursor wasn't pointing anywhere, keep doing that. 374 /// 375 /// This method will never move the cursor to a different block. 376 /// 377 /// # Examples 378 /// 379 /// The `next_inst()` method is intended for iterating over the instructions in a block like 380 /// this: 381 /// 382 /// ``` 383 /// # use cranelift_codegen::ir::{Function, Block}; 384 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 385 /// fn edit_block(func: &mut Function, block: Block) { 386 /// let mut cursor = FuncCursor::new(func).at_top(block); 387 /// while let Some(inst) = cursor.next_inst() { 388 /// // Edit instructions... 389 /// } 390 /// } 391 /// ``` 392 /// The loop body can insert and remove instructions via the cursor. 393 /// 394 /// Iterating over all the instructions in a function looks like this: 395 /// 396 /// ``` 397 /// # use cranelift_codegen::ir::{Function, Block}; 398 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 399 /// fn edit_func(func: &mut Function) { 400 /// let mut cursor = FuncCursor::new(func); 401 /// while let Some(block) = cursor.next_block() { 402 /// while let Some(inst) = cursor.next_inst() { 403 /// // Edit instructions... 404 /// } 405 /// } 406 /// } 407 /// ``` 408 fn next_inst(&mut self) -> Option<ir::Inst> { 409 use self::CursorPosition::*; 410 match self.position() { 411 Nowhere | After(..) => None, 412 At(inst) => { 413 if let Some(next) = self.layout().next_inst(inst) { 414 self.set_position(At(next)); 415 Some(next) 416 } else { 417 let pos = After( 418 self.layout() 419 .inst_block(inst) 420 .expect("current instruction removed?"), 421 ); 422 self.set_position(pos); 423 None 424 } 425 } 426 Before(block) => { 427 if let Some(next) = self.layout().first_inst(block) { 428 self.set_position(At(next)); 429 Some(next) 430 } else { 431 self.set_position(After(block)); 432 None 433 } 434 } 435 } 436 } 437 438 /// Move to the previous instruction in the same block and return it. 439 /// 440 /// - If the cursor was positioned after a block, go to the last instruction in that block. 441 /// - If there are no more instructions in the block, go to the `Before(block)` position and return 442 /// `None`. 443 /// - If the cursor wasn't pointing anywhere, keep doing that. 444 /// 445 /// This method will never move the cursor to a different block. 446 /// 447 /// # Examples 448 /// 449 /// The `prev_inst()` method is intended for iterating backwards over the instructions in an 450 /// block like this: 451 /// 452 /// ``` 453 /// # use cranelift_codegen::ir::{Function, Block}; 454 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 455 /// fn edit_block(func: &mut Function, block: Block) { 456 /// let mut cursor = FuncCursor::new(func).at_bottom(block); 457 /// while let Some(inst) = cursor.prev_inst() { 458 /// // Edit instructions... 459 /// } 460 /// } 461 /// ``` 462 fn prev_inst(&mut self) -> Option<ir::Inst> { 463 use self::CursorPosition::*; 464 match self.position() { 465 Nowhere | Before(..) => None, 466 At(inst) => { 467 if let Some(prev) = self.layout().prev_inst(inst) { 468 self.set_position(At(prev)); 469 Some(prev) 470 } else { 471 let pos = Before( 472 self.layout() 473 .inst_block(inst) 474 .expect("current instruction removed?"), 475 ); 476 self.set_position(pos); 477 None 478 } 479 } 480 After(block) => { 481 if let Some(prev) = self.layout().last_inst(block) { 482 self.set_position(At(prev)); 483 Some(prev) 484 } else { 485 self.set_position(Before(block)); 486 None 487 } 488 } 489 } 490 } 491 492 /// Insert an instruction at the current position. 493 /// 494 /// - If pointing at an instruction, the new instruction is inserted before the current 495 /// instruction. 496 /// - If pointing at the bottom of a block, the new instruction is appended to the block. 497 /// - Otherwise panic. 498 /// 499 /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes 500 /// instructions to appear in insertion order in the block. 501 fn insert_inst(&mut self, inst: ir::Inst) { 502 use self::CursorPosition::*; 503 match self.position() { 504 Nowhere | Before(..) => panic!("Invalid insert_inst position"), 505 At(cur) => self.layout_mut().insert_inst(inst, cur), 506 After(block) => self.layout_mut().append_inst(inst, block), 507 } 508 } 509 510 /// Remove the instruction under the cursor. 511 /// 512 /// The cursor is left pointing at the position following the current instruction. 513 /// 514 /// Return the instruction that was removed. 515 fn remove_inst(&mut self) -> ir::Inst { 516 let inst = self.current_inst().expect("No instruction to remove"); 517 self.next_inst(); 518 self.layout_mut().remove_inst(inst); 519 inst 520 } 521 522 /// Remove the instruction under the cursor. 523 /// 524 /// The cursor is left pointing at the position preceding the current instruction. 525 /// 526 /// Return the instruction that was removed. 527 fn remove_inst_and_step_back(&mut self) -> ir::Inst { 528 let inst = self.current_inst().expect("No instruction to remove"); 529 self.prev_inst(); 530 self.layout_mut().remove_inst(inst); 531 inst 532 } 533 534 /// Replace the instruction under the cursor with `new_inst`. 535 /// 536 /// The cursor is left pointing at the new instruction. 537 /// 538 /// The old instruction that was replaced is returned. 539 fn replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst { 540 let prev_inst = self.remove_inst(); 541 self.insert_inst(new_inst); 542 prev_inst 543 } 544 545 /// Insert a block at the current position and switch to it. 546 /// 547 /// As far as possible, this method behaves as if the block header were an instruction inserted 548 /// at the current position. 549 /// 550 /// - If the cursor is pointing at an existing instruction, *the current block is split in two* 551 /// and the current instruction becomes the first instruction in the inserted block. 552 /// - If the cursor points at the bottom of a block, the new block is inserted after the current 553 /// one, and moved to the bottom of the new block where instructions can be appended. 554 /// - If the cursor points to the top of a block, the new block is inserted above the current one. 555 /// - If the cursor is not pointing at anything, the new block is placed last in the layout. 556 /// 557 /// This means that it is always valid to call this method, and it always leaves the cursor in 558 /// a state that will insert instructions into the new block. 559 fn insert_block(&mut self, new_block: ir::Block) { 560 use self::CursorPosition::*; 561 match self.position() { 562 At(inst) => { 563 self.layout_mut().split_block(new_block, inst); 564 // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`. 565 return; 566 } 567 Nowhere => self.layout_mut().append_block(new_block), 568 Before(block) => self.layout_mut().insert_block(new_block, block), 569 After(block) => self.layout_mut().insert_block_after(new_block, block), 570 } 571 // For everything but `At(inst)` we end up appending to the new block. 572 self.set_position(After(new_block)); 573 } 574 } 575 576 /// Function cursor. 577 /// 578 /// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position 579 /// too. The function can be re-borrowed by accessing the public `cur.func` member. 580 /// 581 /// This cursor is for use before legalization. The inserted instructions are not given an 582 /// encoding. 583 pub struct FuncCursor<'f> { 584 pos: CursorPosition, 585 srcloc: ir::SourceLoc, 586 587 /// The referenced function. 588 pub func: &'f mut ir::Function, 589 } 590 591 impl<'f> FuncCursor<'f> { 592 /// Create a new `FuncCursor` pointing nowhere. 593 pub fn new(func: &'f mut ir::Function) -> Self { 594 Self { 595 pos: CursorPosition::Nowhere, 596 srcloc: Default::default(), 597 func, 598 } 599 } 600 601 /// Use the source location of `inst` for future instructions. 602 pub fn use_srcloc(&mut self, inst: ir::Inst) { 603 self.srcloc = self.func.srcloc(inst); 604 } 605 606 /// Create an instruction builder that inserts an instruction at the current position. 607 pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> { 608 ir::InsertBuilder::new(self) 609 } 610 } 611 612 impl<'f> Cursor for FuncCursor<'f> { 613 fn position(&self) -> CursorPosition { 614 self.pos 615 } 616 617 fn set_position(&mut self, pos: CursorPosition) { 618 self.pos = pos 619 } 620 621 fn srcloc(&self) -> ir::SourceLoc { 622 self.srcloc 623 } 624 625 fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { 626 self.func.params.ensure_base_srcloc(srcloc); 627 self.srcloc = srcloc; 628 } 629 630 fn layout(&self) -> &ir::Layout { 631 &self.func.layout 632 } 633 634 fn layout_mut(&mut self) -> &mut ir::Layout { 635 &mut self.func.layout 636 } 637 } 638 639 impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> { 640 fn data_flow_graph(&self) -> &ir::DataFlowGraph { 641 &self.func.dfg 642 } 643 644 fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { 645 &mut self.func.dfg 646 } 647 648 fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph { 649 self.insert_inst(inst); 650 if !self.srcloc.is_default() { 651 self.func.set_srcloc(inst, self.srcloc); 652 } 653 &mut self.func.dfg 654 } 655 } 656