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 /// Get the next position that a forwards traversal will move to, but do not 303 /// move this cursor. 304 fn next_position(&self) -> CursorPosition { 305 self.next_inst_position() 306 .unwrap_or_else(|| self.next_block_position()) 307 } 308 309 /// Get the next position that a backwards traversal will move to, but do 310 /// not move this cursor. 311 fn prev_position(&self) -> CursorPosition { 312 self.prev_inst_position() 313 .unwrap_or_else(|| self.prev_block_position()) 314 } 315 316 /// Get the position that a `cursor.next_block()` call would move this 317 /// cursor to, but do not update this cursor's position. 318 fn next_block_position(&self) -> CursorPosition { 319 let next = if let Some(block) = self.current_block() { 320 self.layout().next_block(block) 321 } else { 322 self.layout().entry_block() 323 }; 324 match next { 325 Some(block) => CursorPosition::Before(block), 326 None => CursorPosition::Nowhere, 327 } 328 } 329 330 /// Go to the top of the next block in layout order and return it. 331 /// 332 /// - If the cursor wasn't pointing at anything, go to the top of the first block in the 333 /// function. 334 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 335 /// 336 /// # Examples 337 /// 338 /// The `next_block()` method is intended for iterating over the blocks in layout order: 339 /// 340 /// ``` 341 /// # use cranelift_codegen::ir::{Function, Block}; 342 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 343 /// fn edit_func(func: &mut Function) { 344 /// let mut cursor = FuncCursor::new(func); 345 /// while let Some(block) = cursor.next_block() { 346 /// // Edit block. 347 /// } 348 /// } 349 /// ``` 350 fn next_block(&mut self) -> Option<ir::Block> { 351 let pos = self.next_block_position(); 352 self.set_position(pos); 353 self.current_block() 354 } 355 356 /// Get the position that a `cursor.prev_block()` call would move this 357 /// cursor to, but do not update this cursor's position. 358 fn prev_block_position(&self) -> CursorPosition { 359 let prev = if let Some(block) = self.current_block() { 360 self.layout().prev_block(block) 361 } else { 362 self.layout().last_block() 363 }; 364 match prev { 365 Some(block) => CursorPosition::After(block), 366 None => CursorPosition::Nowhere, 367 } 368 } 369 370 /// Go to the bottom of the previous block in layout order and return it. 371 /// 372 /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the 373 /// function. 374 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 375 /// 376 /// # Examples 377 /// 378 /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order: 379 /// 380 /// ``` 381 /// # use cranelift_codegen::ir::{Function, Block}; 382 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 383 /// fn edit_func(func: &mut Function) { 384 /// let mut cursor = FuncCursor::new(func); 385 /// while let Some(block) = cursor.prev_block() { 386 /// // Edit block. 387 /// } 388 /// } 389 /// ``` 390 fn prev_block(&mut self) -> Option<ir::Block> { 391 let pos = self.prev_block_position(); 392 self.set_position(pos); 393 self.current_block() 394 } 395 396 /// Get the position that a `cursor.next_inst()` call would move this cursor 397 /// to, but do not update this cursor's position. 398 fn next_inst_position(&self) -> Option<CursorPosition> { 399 use self::CursorPosition::*; 400 match self.position() { 401 Nowhere | After(..) => None, 402 At(inst) => { 403 if let Some(next) = self.layout().next_inst(inst) { 404 Some(At(next)) 405 } else { 406 Some(After( 407 self.layout() 408 .inst_block(inst) 409 .expect("current instruction removed?"), 410 )) 411 } 412 } 413 Before(block) => { 414 if let Some(next) = self.layout().first_inst(block) { 415 Some(At(next)) 416 } else { 417 Some(After(block)) 418 } 419 } 420 } 421 } 422 423 /// Move to the next instruction in the same block and return it. 424 /// 425 /// - If the cursor was positioned before a block, go to the first instruction in that block. 426 /// - If there are no more instructions in the block, go to the `After(block)` position and return 427 /// `None`. 428 /// - If the cursor wasn't pointing anywhere, keep doing that. 429 /// 430 /// This method will never move the cursor to a different block. 431 /// 432 /// # Examples 433 /// 434 /// The `next_inst()` method is intended for iterating over the instructions in a block like 435 /// this: 436 /// 437 /// ``` 438 /// # use cranelift_codegen::ir::{Function, Block}; 439 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 440 /// fn edit_block(func: &mut Function, block: Block) { 441 /// let mut cursor = FuncCursor::new(func).at_top(block); 442 /// while let Some(inst) = cursor.next_inst() { 443 /// // Edit instructions... 444 /// } 445 /// } 446 /// ``` 447 /// The loop body can insert and remove instructions via the cursor. 448 /// 449 /// Iterating over all the instructions in a function looks like this: 450 /// 451 /// ``` 452 /// # use cranelift_codegen::ir::{Function, Block}; 453 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 454 /// fn edit_func(func: &mut Function) { 455 /// let mut cursor = FuncCursor::new(func); 456 /// while let Some(block) = cursor.next_block() { 457 /// while let Some(inst) = cursor.next_inst() { 458 /// // Edit instructions... 459 /// } 460 /// } 461 /// } 462 /// ``` 463 fn next_inst(&mut self) -> Option<ir::Inst> { 464 let pos = self.next_inst_position()?; 465 self.set_position(pos); 466 self.current_inst() 467 } 468 469 /// Get the position that a `cursor.prev_inst()` call would move this cursor 470 /// to, but do not update this cursor's position. 471 fn prev_inst_position(&self) -> Option<CursorPosition> { 472 use self::CursorPosition::*; 473 match self.position() { 474 Nowhere | Before(..) => None, 475 At(inst) => { 476 if let Some(prev) = self.layout().prev_inst(inst) { 477 Some(At(prev)) 478 } else { 479 Some(Before( 480 self.layout() 481 .inst_block(inst) 482 .expect("current instruction removed?"), 483 )) 484 } 485 } 486 After(block) => { 487 if let Some(prev) = self.layout().last_inst(block) { 488 Some(At(prev)) 489 } else { 490 Some(Before(block)) 491 } 492 } 493 } 494 } 495 496 /// Move to the previous instruction in the same block and return it. 497 /// 498 /// - If the cursor was positioned after a block, go to the last instruction in that block. 499 /// - If there are no more instructions in the block, go to the `Before(block)` position and return 500 /// `None`. 501 /// - If the cursor wasn't pointing anywhere, keep doing that. 502 /// 503 /// This method will never move the cursor to a different block. 504 /// 505 /// # Examples 506 /// 507 /// The `prev_inst()` method is intended for iterating backwards over the instructions in an 508 /// block like this: 509 /// 510 /// ``` 511 /// # use cranelift_codegen::ir::{Function, Block}; 512 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 513 /// fn edit_block(func: &mut Function, block: Block) { 514 /// let mut cursor = FuncCursor::new(func).at_bottom(block); 515 /// while let Some(inst) = cursor.prev_inst() { 516 /// // Edit instructions... 517 /// } 518 /// } 519 /// ``` 520 fn prev_inst(&mut self) -> Option<ir::Inst> { 521 let pos = self.prev_inst_position()?; 522 self.set_position(pos); 523 self.current_inst() 524 } 525 526 /// Insert an instruction at the current position. 527 /// 528 /// - If pointing at an instruction, the new instruction is inserted before the current 529 /// instruction. 530 /// - If pointing at the bottom of a block, the new instruction is appended to the block. 531 /// - Otherwise panic. 532 /// 533 /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes 534 /// instructions to appear in insertion order in the block. 535 fn insert_inst(&mut self, inst: ir::Inst) { 536 use self::CursorPosition::*; 537 match self.position() { 538 Nowhere | Before(..) => panic!("Invalid insert_inst position"), 539 At(cur) => self.layout_mut().insert_inst(inst, cur), 540 After(block) => self.layout_mut().append_inst(inst, block), 541 } 542 } 543 544 /// Remove the instruction under the cursor. 545 /// 546 /// The cursor is left pointing at the position following the current instruction. 547 /// 548 /// Return the instruction that was removed. 549 fn remove_inst(&mut self) -> ir::Inst { 550 let inst = self.current_inst().expect("No instruction to remove"); 551 self.next_inst(); 552 self.layout_mut().remove_inst(inst); 553 inst 554 } 555 556 /// Remove the instruction under the cursor. 557 /// 558 /// The cursor is left pointing at the position preceding the current instruction. 559 /// 560 /// Return the instruction that was removed. 561 fn remove_inst_and_step_back(&mut self) -> ir::Inst { 562 let inst = self.current_inst().expect("No instruction to remove"); 563 self.prev_inst(); 564 self.layout_mut().remove_inst(inst); 565 inst 566 } 567 568 /// Replace the instruction under the cursor with `new_inst`. 569 /// 570 /// The cursor is left pointing at the new instruction. 571 /// 572 /// The old instruction that was replaced is returned. 573 fn replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst { 574 let prev_inst = self.remove_inst(); 575 self.insert_inst(new_inst); 576 prev_inst 577 } 578 579 /// Insert a block at the current position and switch to it. 580 /// 581 /// As far as possible, this method behaves as if the block header were an instruction inserted 582 /// at the current position. 583 /// 584 /// - If the cursor is pointing at an existing instruction, *the current block is split in two* 585 /// and the current instruction becomes the first instruction in the inserted block. 586 /// - If the cursor points at the bottom of a block, the new block is inserted after the current 587 /// one, and moved to the bottom of the new block where instructions can be appended. 588 /// - If the cursor points to the top of a block, the new block is inserted above the current one. 589 /// - If the cursor is not pointing at anything, the new block is placed last in the layout. 590 /// 591 /// This means that it is always valid to call this method, and it always leaves the cursor in 592 /// a state that will insert instructions into the new block. 593 fn insert_block(&mut self, new_block: ir::Block) { 594 use self::CursorPosition::*; 595 match self.position() { 596 At(inst) => { 597 self.layout_mut().split_block(new_block, inst); 598 // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`. 599 return; 600 } 601 Nowhere => self.layout_mut().append_block(new_block), 602 Before(block) => self.layout_mut().insert_block(new_block, block), 603 After(block) => self.layout_mut().insert_block_after(new_block, block), 604 } 605 // For everything but `At(inst)` we end up appending to the new block. 606 self.set_position(After(new_block)); 607 } 608 } 609 610 /// Function cursor. 611 /// 612 /// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position 613 /// too. The function can be re-borrowed by accessing the public `cur.func` member. 614 /// 615 /// This cursor is for use before legalization. The inserted instructions are not given an 616 /// encoding. 617 pub struct FuncCursor<'f> { 618 pos: CursorPosition, 619 srcloc: ir::SourceLoc, 620 621 /// The referenced function. 622 pub func: &'f mut ir::Function, 623 } 624 625 impl<'f> FuncCursor<'f> { 626 /// Create a new `FuncCursor` pointing nowhere. 627 pub fn new(func: &'f mut ir::Function) -> Self { 628 Self { 629 pos: CursorPosition::Nowhere, 630 srcloc: Default::default(), 631 func, 632 } 633 } 634 635 /// Use the source location of `inst` for future instructions. 636 pub fn use_srcloc(&mut self, inst: ir::Inst) { 637 self.srcloc = self.func.srcloc(inst); 638 } 639 640 /// Create an instruction builder that inserts an instruction at the current position. 641 pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> { 642 ir::InsertBuilder::new(self) 643 } 644 } 645 646 impl<'f> Cursor for FuncCursor<'f> { 647 fn position(&self) -> CursorPosition { 648 self.pos 649 } 650 651 fn set_position(&mut self, pos: CursorPosition) { 652 self.pos = pos 653 } 654 655 fn srcloc(&self) -> ir::SourceLoc { 656 self.srcloc 657 } 658 659 fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { 660 self.func.params.ensure_base_srcloc(srcloc); 661 self.srcloc = srcloc; 662 } 663 664 fn layout(&self) -> &ir::Layout { 665 &self.func.layout 666 } 667 668 fn layout_mut(&mut self) -> &mut ir::Layout { 669 &mut self.func.layout 670 } 671 } 672 673 impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> { 674 fn data_flow_graph(&self) -> &ir::DataFlowGraph { 675 &self.func.dfg 676 } 677 678 fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { 679 &mut self.func.dfg 680 } 681 682 fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph { 683 self.insert_inst(inst); 684 if !self.srcloc.is_default() { 685 self.func.set_srcloc(inst, self.srcloc); 686 } 687 &mut self.func.dfg 688 } 689 } 690