1 //! Cursor library. 2 //! 3 //! This module defines cursor data types that can be used for inserting instructions. 4 5 use crate::ir; 6 use crate::isa::TargetIsa; 7 8 /// The possible positions of a cursor. 9 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 10 pub enum CursorPosition { 11 /// Cursor is not pointing anywhere. No instructions can be inserted. 12 Nowhere, 13 /// Cursor is pointing at an existing instruction. 14 /// New instructions will be inserted *before* the current instruction. 15 At(ir::Inst), 16 /// Cursor is before the beginning of a block. No instructions can be inserted. Calling 17 /// `next_inst()` will move to the first instruction in the block. 18 Before(ir::Block), 19 /// Cursor is pointing after the end of a block. 20 /// New instructions will be appended to the block. 21 After(ir::Block), 22 } 23 24 /// All cursor types implement the `Cursor` which provides common navigation operations. 25 pub trait Cursor { 26 /// Get the current cursor position. position(&self) -> CursorPosition27 fn position(&self) -> CursorPosition; 28 29 /// Set the current position. set_position(&mut self, pos: CursorPosition)30 fn set_position(&mut self, pos: CursorPosition); 31 32 /// Get the source location that should be assigned to new instructions. srcloc(&self) -> ir::SourceLoc33 fn srcloc(&self) -> ir::SourceLoc; 34 35 /// Set the source location that should be assigned to new instructions. set_srcloc(&mut self, srcloc: ir::SourceLoc)36 fn set_srcloc(&mut self, srcloc: ir::SourceLoc); 37 38 /// Borrow a reference to the function layout that this cursor is navigating. layout(&self) -> &ir::Layout39 fn layout(&self) -> &ir::Layout; 40 41 /// Borrow a mutable reference to the function layout that this cursor is navigating. layout_mut(&mut self) -> &mut ir::Layout42 fn layout_mut(&mut self) -> &mut ir::Layout; 43 44 /// Exchange this cursor for one with a set source location. 45 /// 46 /// This is intended to be used as a builder method: 47 /// 48 /// ``` 49 /// # use cranelift_codegen::ir::{Function, Block, SourceLoc}; 50 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 51 /// fn edit_func(func: &mut Function, srcloc: SourceLoc) { 52 /// let mut pos = FuncCursor::new(func).with_srcloc(srcloc); 53 /// 54 /// // Use `pos`... 55 /// } 56 /// ``` with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self where Self: Sized,57 fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self 58 where 59 Self: Sized, 60 { 61 self.set_srcloc(srcloc); 62 self 63 } 64 65 /// Rebuild this cursor positioned at `pos`. at_position(mut self, pos: CursorPosition) -> Self where Self: Sized,66 fn at_position(mut self, pos: CursorPosition) -> Self 67 where 68 Self: Sized, 69 { 70 self.set_position(pos); 71 self 72 } 73 74 /// Rebuild this cursor positioned at `inst`. 75 /// 76 /// This is intended to be used as a builder method: 77 /// 78 /// ``` 79 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 80 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 81 /// fn edit_func(func: &mut Function, inst: Inst) { 82 /// let mut pos = FuncCursor::new(func).at_inst(inst); 83 /// 84 /// // Use `pos`... 85 /// } 86 /// ``` at_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,87 fn at_inst(mut self, inst: ir::Inst) -> Self 88 where 89 Self: Sized, 90 { 91 self.goto_inst(inst); 92 self 93 } 94 95 /// Rebuild this cursor positioned at the first insertion point for `block`. 96 /// This differs from `at_first_inst` in that it doesn't assume that any 97 /// instructions have been inserted into `block` yet. 98 /// 99 /// This is intended to be used as a builder method: 100 /// 101 /// ``` 102 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 103 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 104 /// fn edit_func(func: &mut Function, block: Block) { 105 /// let mut pos = FuncCursor::new(func).at_first_insertion_point(block); 106 /// 107 /// // Use `pos`... 108 /// } 109 /// ``` at_first_insertion_point(mut self, block: ir::Block) -> Self where Self: Sized,110 fn at_first_insertion_point(mut self, block: ir::Block) -> Self 111 where 112 Self: Sized, 113 { 114 self.goto_first_insertion_point(block); 115 self 116 } 117 118 /// Rebuild this cursor positioned at the first instruction in `block`. 119 /// 120 /// This is intended to be used as a builder method: 121 /// 122 /// ``` 123 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 124 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 125 /// fn edit_func(func: &mut Function, block: Block) { 126 /// let mut pos = FuncCursor::new(func).at_first_inst(block); 127 /// 128 /// // Use `pos`... 129 /// } 130 /// ``` at_first_inst(mut self, block: ir::Block) -> Self where Self: Sized,131 fn at_first_inst(mut self, block: ir::Block) -> Self 132 where 133 Self: Sized, 134 { 135 self.goto_first_inst(block); 136 self 137 } 138 139 /// Rebuild this cursor positioned at the last instruction in `block`. 140 /// 141 /// This is intended to be used as a builder method: 142 /// 143 /// ``` 144 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 145 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 146 /// fn edit_func(func: &mut Function, block: Block) { 147 /// let mut pos = FuncCursor::new(func).at_last_inst(block); 148 /// 149 /// // Use `pos`... 150 /// } 151 /// ``` at_last_inst(mut self, block: ir::Block) -> Self where Self: Sized,152 fn at_last_inst(mut self, block: ir::Block) -> Self 153 where 154 Self: Sized, 155 { 156 self.goto_last_inst(block); 157 self 158 } 159 160 /// Rebuild this cursor positioned after `inst`. 161 /// 162 /// This is intended to be used as a builder method: 163 /// 164 /// ``` 165 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 166 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 167 /// fn edit_func(func: &mut Function, inst: Inst) { 168 /// let mut pos = FuncCursor::new(func).after_inst(inst); 169 /// 170 /// // Use `pos`... 171 /// } 172 /// ``` after_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,173 fn after_inst(mut self, inst: ir::Inst) -> Self 174 where 175 Self: Sized, 176 { 177 self.goto_after_inst(inst); 178 self 179 } 180 181 /// Rebuild this cursor positioned at the top of `block`. 182 /// 183 /// This is intended to be used as a builder method: 184 /// 185 /// ``` 186 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 187 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 188 /// fn edit_func(func: &mut Function, block: Block) { 189 /// let mut pos = FuncCursor::new(func).at_top(block); 190 /// 191 /// // Use `pos`... 192 /// } 193 /// ``` at_top(mut self, block: ir::Block) -> Self where Self: Sized,194 fn at_top(mut self, block: ir::Block) -> Self 195 where 196 Self: Sized, 197 { 198 self.goto_top(block); 199 self 200 } 201 202 /// Rebuild this cursor positioned at the bottom of `block`. 203 /// 204 /// This is intended to be used as a builder method: 205 /// 206 /// ``` 207 /// # use cranelift_codegen::ir::{Function, Block, Inst}; 208 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 209 /// fn edit_func(func: &mut Function, block: Block) { 210 /// let mut pos = FuncCursor::new(func).at_bottom(block); 211 /// 212 /// // Use `pos`... 213 /// } 214 /// ``` at_bottom(mut self, block: ir::Block) -> Self where Self: Sized,215 fn at_bottom(mut self, block: ir::Block) -> Self 216 where 217 Self: Sized, 218 { 219 self.goto_bottom(block); 220 self 221 } 222 223 /// Get the block corresponding to the current position. current_block(&self) -> Option<ir::Block>224 fn current_block(&self) -> Option<ir::Block> { 225 use self::CursorPosition::*; 226 match self.position() { 227 Nowhere => None, 228 At(inst) => self.layout().inst_block(inst), 229 Before(block) | After(block) => Some(block), 230 } 231 } 232 233 /// Get the instruction corresponding to the current position, if any. current_inst(&self) -> Option<ir::Inst>234 fn current_inst(&self) -> Option<ir::Inst> { 235 use self::CursorPosition::*; 236 match self.position() { 237 At(inst) => Some(inst), 238 _ => None, 239 } 240 } 241 242 /// Go to the position after a specific instruction, which must be inserted 243 /// in the layout. New instructions will be inserted after `inst`. goto_after_inst(&mut self, inst: ir::Inst)244 fn goto_after_inst(&mut self, inst: ir::Inst) { 245 debug_assert!(self.layout().inst_block(inst).is_some()); 246 let new_pos = if let Some(next) = self.layout().next_inst(inst) { 247 CursorPosition::At(next) 248 } else { 249 CursorPosition::After( 250 self.layout() 251 .inst_block(inst) 252 .expect("current instruction removed?"), 253 ) 254 }; 255 self.set_position(new_pos); 256 } 257 258 /// Go to a specific instruction which must be inserted in the layout. 259 /// New instructions will be inserted before `inst`. goto_inst(&mut self, inst: ir::Inst)260 fn goto_inst(&mut self, inst: ir::Inst) { 261 debug_assert!(self.layout().inst_block(inst).is_some()); 262 self.set_position(CursorPosition::At(inst)); 263 } 264 265 /// Go to the position for inserting instructions at the beginning of `block`, 266 /// which unlike `goto_first_inst` doesn't assume that any instructions have 267 /// been inserted into `block` yet. goto_first_insertion_point(&mut self, block: ir::Block)268 fn goto_first_insertion_point(&mut self, block: ir::Block) { 269 if let Some(inst) = self.layout().first_inst(block) { 270 self.goto_inst(inst); 271 } else { 272 self.goto_bottom(block); 273 } 274 } 275 276 /// Go to the first instruction in `block`. goto_first_inst(&mut self, block: ir::Block)277 fn goto_first_inst(&mut self, block: ir::Block) { 278 let inst = self.layout().first_inst(block).expect("Empty block"); 279 self.goto_inst(inst); 280 } 281 282 /// Go to the last instruction in `block`. goto_last_inst(&mut self, block: ir::Block)283 fn goto_last_inst(&mut self, block: ir::Block) { 284 let inst = self.layout().last_inst(block).expect("Empty block"); 285 self.goto_inst(inst); 286 } 287 288 /// Go to the top of `block` which must be inserted into the layout. 289 /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first 290 /// instruction in `block`. goto_top(&mut self, block: ir::Block)291 fn goto_top(&mut self, block: ir::Block) { 292 debug_assert!(self.layout().is_block_inserted(block)); 293 self.set_position(CursorPosition::Before(block)); 294 } 295 296 /// Go to the bottom of `block` which must be inserted into the layout. 297 /// At this position, inserted instructions will be appended to `block`. goto_bottom(&mut self, block: ir::Block)298 fn goto_bottom(&mut self, block: ir::Block) { 299 debug_assert!(self.layout().is_block_inserted(block)); 300 self.set_position(CursorPosition::After(block)); 301 } 302 303 /// Go to the top of the next block in layout order and return it. 304 /// 305 /// - If the cursor wasn't pointing at anything, go to the top of the first block in the 306 /// function. 307 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 308 /// 309 /// # Examples 310 /// 311 /// The `next_block()` method is intended for iterating over the blocks in layout order: 312 /// 313 /// ``` 314 /// # use cranelift_codegen::ir::{Function, Block}; 315 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 316 /// fn edit_func(func: &mut Function) { 317 /// let mut cursor = FuncCursor::new(func); 318 /// while let Some(block) = cursor.next_block() { 319 /// // Edit block. 320 /// } 321 /// } 322 /// ``` next_block(&mut self) -> Option<ir::Block>323 fn next_block(&mut self) -> Option<ir::Block> { 324 let next = if let Some(block) = self.current_block() { 325 self.layout().next_block(block) 326 } else { 327 self.layout().entry_block() 328 }; 329 self.set_position(match next { 330 Some(block) => CursorPosition::Before(block), 331 None => CursorPosition::Nowhere, 332 }); 333 next 334 } 335 336 /// Go to the bottom of the previous block in layout order and return it. 337 /// 338 /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the 339 /// function. 340 /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`. 341 /// 342 /// # Examples 343 /// 344 /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order: 345 /// 346 /// ``` 347 /// # use cranelift_codegen::ir::{Function, Block}; 348 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 349 /// fn edit_func(func: &mut Function) { 350 /// let mut cursor = FuncCursor::new(func); 351 /// while let Some(block) = cursor.prev_block() { 352 /// // Edit block. 353 /// } 354 /// } 355 /// ``` prev_block(&mut self) -> Option<ir::Block>356 fn prev_block(&mut self) -> Option<ir::Block> { 357 let prev = if let Some(block) = self.current_block() { 358 self.layout().prev_block(block) 359 } else { 360 self.layout().last_block() 361 }; 362 self.set_position(match prev { 363 Some(block) => CursorPosition::After(block), 364 None => CursorPosition::Nowhere, 365 }); 366 prev 367 } 368 369 /// Move to the next instruction in the same block and return it. 370 /// 371 /// - If the cursor was positioned before a block, go to the first instruction in that block. 372 /// - If there are no more instructions in the block, go to the `After(block)` position and return 373 /// `None`. 374 /// - If the cursor wasn't pointing anywhere, keep doing that. 375 /// 376 /// This method will never move the cursor to a different block. 377 /// 378 /// # Examples 379 /// 380 /// The `next_inst()` method is intended for iterating over the instructions in a block like 381 /// this: 382 /// 383 /// ``` 384 /// # use cranelift_codegen::ir::{Function, Block}; 385 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 386 /// fn edit_block(func: &mut Function, block: Block) { 387 /// let mut cursor = FuncCursor::new(func).at_top(block); 388 /// while let Some(inst) = cursor.next_inst() { 389 /// // Edit instructions... 390 /// } 391 /// } 392 /// ``` 393 /// The loop body can insert and remove instructions via the cursor. 394 /// 395 /// Iterating over all the instructions in a function looks like this: 396 /// 397 /// ``` 398 /// # use cranelift_codegen::ir::{Function, Block}; 399 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 400 /// fn edit_func(func: &mut Function) { 401 /// let mut cursor = FuncCursor::new(func); 402 /// while let Some(block) = cursor.next_block() { 403 /// while let Some(inst) = cursor.next_inst() { 404 /// // Edit instructions... 405 /// } 406 /// } 407 /// } 408 /// ``` next_inst(&mut self) -> Option<ir::Inst>409 fn next_inst(&mut self) -> Option<ir::Inst> { 410 use self::CursorPosition::*; 411 match self.position() { 412 Nowhere | After(..) => None, 413 At(inst) => { 414 if let Some(next) = self.layout().next_inst(inst) { 415 self.set_position(At(next)); 416 Some(next) 417 } else { 418 let pos = After( 419 self.layout() 420 .inst_block(inst) 421 .expect("current instruction removed?"), 422 ); 423 self.set_position(pos); 424 None 425 } 426 } 427 Before(block) => { 428 if let Some(next) = self.layout().first_inst(block) { 429 self.set_position(At(next)); 430 Some(next) 431 } else { 432 self.set_position(After(block)); 433 None 434 } 435 } 436 } 437 } 438 439 /// Move to the previous instruction in the same block and return it. 440 /// 441 /// - If the cursor was positioned after a block, go to the last instruction in that block. 442 /// - If there are no more instructions in the block, go to the `Before(block)` position and return 443 /// `None`. 444 /// - If the cursor wasn't pointing anywhere, keep doing that. 445 /// 446 /// This method will never move the cursor to a different block. 447 /// 448 /// # Examples 449 /// 450 /// The `prev_inst()` method is intended for iterating backwards over the instructions in an 451 /// block like this: 452 /// 453 /// ``` 454 /// # use cranelift_codegen::ir::{Function, Block}; 455 /// # use cranelift_codegen::cursor::{Cursor, FuncCursor}; 456 /// fn edit_block(func: &mut Function, block: Block) { 457 /// let mut cursor = FuncCursor::new(func).at_bottom(block); 458 /// while let Some(inst) = cursor.prev_inst() { 459 /// // Edit instructions... 460 /// } 461 /// } 462 /// ``` prev_inst(&mut self) -> Option<ir::Inst>463 fn prev_inst(&mut self) -> Option<ir::Inst> { 464 use self::CursorPosition::*; 465 match self.position() { 466 Nowhere | Before(..) => None, 467 At(inst) => { 468 if let Some(prev) = self.layout().prev_inst(inst) { 469 self.set_position(At(prev)); 470 Some(prev) 471 } else { 472 let pos = Before( 473 self.layout() 474 .inst_block(inst) 475 .expect("current instruction removed?"), 476 ); 477 self.set_position(pos); 478 None 479 } 480 } 481 After(block) => { 482 if let Some(prev) = self.layout().last_inst(block) { 483 self.set_position(At(prev)); 484 Some(prev) 485 } else { 486 self.set_position(Before(block)); 487 None 488 } 489 } 490 } 491 } 492 493 /// Insert an instruction at the current position. 494 /// 495 /// - If pointing at an instruction, the new instruction is inserted before the current 496 /// instruction. 497 /// - If pointing at the bottom of a block, the new instruction is appended to the block. 498 /// - Otherwise panic. 499 /// 500 /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes 501 /// instructions to appear in insertion order in the block. insert_inst(&mut self, inst: ir::Inst)502 fn insert_inst(&mut self, inst: ir::Inst) { 503 use self::CursorPosition::*; 504 match self.position() { 505 Nowhere | Before(..) => panic!("Invalid insert_inst position"), 506 At(cur) => self.layout_mut().insert_inst(inst, cur), 507 After(block) => self.layout_mut().append_inst(inst, block), 508 } 509 } 510 511 /// Remove the instruction under the cursor. 512 /// 513 /// The cursor is left pointing at the position following the current instruction. 514 /// 515 /// Return the instruction that was removed. remove_inst(&mut self) -> ir::Inst516 fn remove_inst(&mut self) -> ir::Inst { 517 let inst = self.current_inst().expect("No instruction to remove"); 518 self.next_inst(); 519 self.layout_mut().remove_inst(inst); 520 inst 521 } 522 523 /// Remove the instruction under the cursor. 524 /// 525 /// The cursor is left pointing at the position preceding the current instruction. 526 /// 527 /// Return the instruction that was removed. remove_inst_and_step_back(&mut self) -> ir::Inst528 fn remove_inst_and_step_back(&mut self) -> ir::Inst { 529 let inst = self.current_inst().expect("No instruction to remove"); 530 self.prev_inst(); 531 self.layout_mut().remove_inst(inst); 532 inst 533 } 534 535 /// Insert a block at the current position and switch to it. 536 /// 537 /// As far as possible, this method behaves as if the block header were an instruction inserted 538 /// at the current position. 539 /// 540 /// - If the cursor is pointing at an existing instruction, *the current block is split in two* 541 /// and the current instruction becomes the first instruction in the inserted block. 542 /// - If the cursor points at the bottom of a block, the new block is inserted after the current 543 /// one, and moved to the bottom of the new block where instructions can be appended. 544 /// - If the cursor points to the top of a block, the new block is inserted above the current one. 545 /// - If the cursor is not pointing at anything, the new block is placed last in the layout. 546 /// 547 /// This means that it is always valid to call this method, and it always leaves the cursor in 548 /// a state that will insert instructions into the new block. insert_block(&mut self, new_block: ir::Block)549 fn insert_block(&mut self, new_block: ir::Block) { 550 use self::CursorPosition::*; 551 match self.position() { 552 At(inst) => { 553 self.layout_mut().split_block(new_block, inst); 554 // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`. 555 return; 556 } 557 Nowhere => self.layout_mut().append_block(new_block), 558 Before(block) => self.layout_mut().insert_block(new_block, block), 559 After(block) => self.layout_mut().insert_block_after(new_block, block), 560 } 561 // For everything but `At(inst)` we end up appending to the new block. 562 self.set_position(After(new_block)); 563 } 564 } 565 566 /// Function cursor. 567 /// 568 /// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position 569 /// too. The function can be re-borrowed by accessing the public `cur.func` member. 570 /// 571 /// This cursor is for use before legalization. The inserted instructions are not given an 572 /// encoding. 573 pub struct FuncCursor<'f> { 574 pos: CursorPosition, 575 srcloc: ir::SourceLoc, 576 577 /// The referenced function. 578 pub func: &'f mut ir::Function, 579 } 580 581 impl<'f> FuncCursor<'f> { 582 /// Create a new `FuncCursor` pointing nowhere. new(func: &'f mut ir::Function) -> Self583 pub fn new(func: &'f mut ir::Function) -> Self { 584 Self { 585 pos: CursorPosition::Nowhere, 586 srcloc: Default::default(), 587 func, 588 } 589 } 590 591 /// Use the source location of `inst` for future instructions. use_srcloc(&mut self, inst: ir::Inst)592 pub fn use_srcloc(&mut self, inst: ir::Inst) { 593 self.srcloc = self.func.srclocs[inst]; 594 } 595 596 /// Create an instruction builder that inserts an instruction at the current position. ins(&mut self) -> ir::InsertBuilder<&mut FuncCursor<'f>>597 pub fn ins(&mut self) -> ir::InsertBuilder<&mut FuncCursor<'f>> { 598 ir::InsertBuilder::new(self) 599 } 600 } 601 602 impl<'f> Cursor for FuncCursor<'f> { position(&self) -> CursorPosition603 fn position(&self) -> CursorPosition { 604 self.pos 605 } 606 set_position(&mut self, pos: CursorPosition)607 fn set_position(&mut self, pos: CursorPosition) { 608 self.pos = pos 609 } 610 srcloc(&self) -> ir::SourceLoc611 fn srcloc(&self) -> ir::SourceLoc { 612 self.srcloc 613 } 614 set_srcloc(&mut self, srcloc: ir::SourceLoc)615 fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { 616 self.srcloc = srcloc; 617 } 618 layout(&self) -> &ir::Layout619 fn layout(&self) -> &ir::Layout { 620 &self.func.layout 621 } 622 layout_mut(&mut self) -> &mut ir::Layout623 fn layout_mut(&mut self) -> &mut ir::Layout { 624 &mut self.func.layout 625 } 626 } 627 628 impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> { data_flow_graph(&self) -> &ir::DataFlowGraph629 fn data_flow_graph(&self) -> &ir::DataFlowGraph { 630 &self.func.dfg 631 } 632 data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph633 fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { 634 &mut self.func.dfg 635 } 636 insert_built_inst(self, inst: ir::Inst, _: ir::Type) -> &'c mut ir::DataFlowGraph637 fn insert_built_inst(self, inst: ir::Inst, _: ir::Type) -> &'c mut ir::DataFlowGraph { 638 // TODO: Remove this assertion once #796 is fixed. 639 #[cfg(debug_assertions)] 640 { 641 if let CursorPosition::At(_) = self.position() { 642 if let Some(curr) = self.current_inst() { 643 if let Some(prev) = self.layout().prev_inst(curr) { 644 let prev_op = self.data_flow_graph()[prev].opcode(); 645 let inst_op = self.data_flow_graph()[inst].opcode(); 646 let curr_op = self.data_flow_graph()[curr].opcode(); 647 if prev_op.is_branch() 648 && !prev_op.is_terminator() 649 && !inst_op.is_terminator() 650 { 651 panic!( 652 "Inserting instruction {} after {}, and before {}", 653 inst_op, prev_op, curr_op 654 ) 655 } 656 }; 657 }; 658 }; 659 } 660 self.insert_inst(inst); 661 if !self.srcloc.is_default() { 662 self.func.srclocs[inst] = self.srcloc; 663 } 664 &mut self.func.dfg 665 } 666 } 667 668 /// Encoding cursor. 669 /// 670 /// An `EncCursor` can be used to insert instructions that are immediately assigned an encoding. 671 /// The cursor holds a mutable reference to the whole function which can be re-borrowed from the 672 /// public `pos.func` member. 673 pub struct EncCursor<'f> { 674 pos: CursorPosition, 675 srcloc: ir::SourceLoc, 676 built_inst: Option<ir::Inst>, 677 678 /// The referenced function. 679 pub func: &'f mut ir::Function, 680 681 /// The target ISA that will be used to encode instructions. 682 pub isa: &'f dyn TargetIsa, 683 } 684 685 impl<'f> EncCursor<'f> { 686 /// Create a new `EncCursor` pointing nowhere. new(func: &'f mut ir::Function, isa: &'f dyn TargetIsa) -> Self687 pub fn new(func: &'f mut ir::Function, isa: &'f dyn TargetIsa) -> Self { 688 Self { 689 pos: CursorPosition::Nowhere, 690 srcloc: Default::default(), 691 built_inst: None, 692 func, 693 isa, 694 } 695 } 696 697 /// Use the source location of `inst` for future instructions. use_srcloc(&mut self, inst: ir::Inst)698 pub fn use_srcloc(&mut self, inst: ir::Inst) { 699 self.srcloc = self.func.srclocs[inst]; 700 } 701 702 /// Create an instruction builder that will insert an encoded instruction at the current 703 /// position. 704 /// 705 /// The builder will panic if it is used to insert an instruction that can't be encoded for 706 /// `self.isa`. ins(&mut self) -> ir::InsertBuilder<&mut EncCursor<'f>>707 pub fn ins(&mut self) -> ir::InsertBuilder<&mut EncCursor<'f>> { 708 ir::InsertBuilder::new(self) 709 } 710 711 /// Get the last built instruction. 712 /// 713 /// This returns the last instruction that was built using the `ins()` method on this cursor. 714 /// Panics if no instruction was built. built_inst(&self) -> ir::Inst715 pub fn built_inst(&self) -> ir::Inst { 716 self.built_inst.expect("No instruction was inserted") 717 } 718 719 /// Return an object that can display `inst`. 720 /// 721 /// This is a convenience wrapper for the DFG equivalent. display_inst(&self, inst: ir::Inst) -> ir::dfg::DisplayInst722 pub fn display_inst(&self, inst: ir::Inst) -> ir::dfg::DisplayInst { 723 self.func.dfg.display_inst(inst, self.isa) 724 } 725 } 726 727 impl<'f> Cursor for EncCursor<'f> { position(&self) -> CursorPosition728 fn position(&self) -> CursorPosition { 729 self.pos 730 } 731 set_position(&mut self, pos: CursorPosition)732 fn set_position(&mut self, pos: CursorPosition) { 733 self.pos = pos 734 } 735 srcloc(&self) -> ir::SourceLoc736 fn srcloc(&self) -> ir::SourceLoc { 737 self.srcloc 738 } 739 set_srcloc(&mut self, srcloc: ir::SourceLoc)740 fn set_srcloc(&mut self, srcloc: ir::SourceLoc) { 741 self.srcloc = srcloc; 742 } 743 layout(&self) -> &ir::Layout744 fn layout(&self) -> &ir::Layout { 745 &self.func.layout 746 } 747 layout_mut(&mut self) -> &mut ir::Layout748 fn layout_mut(&mut self) -> &mut ir::Layout { 749 &mut self.func.layout 750 } 751 } 752 753 impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut EncCursor<'f> { data_flow_graph(&self) -> &ir::DataFlowGraph754 fn data_flow_graph(&self) -> &ir::DataFlowGraph { 755 &self.func.dfg 756 } 757 data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph758 fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph { 759 &mut self.func.dfg 760 } 761 insert_built_inst( self, inst: ir::Inst, ctrl_typevar: ir::Type, ) -> &'c mut ir::DataFlowGraph762 fn insert_built_inst( 763 self, 764 inst: ir::Inst, 765 ctrl_typevar: ir::Type, 766 ) -> &'c mut ir::DataFlowGraph { 767 // TODO: Remove this assertion once #796 is fixed. 768 #[cfg(debug_assertions)] 769 { 770 if let CursorPosition::At(_) = self.position() { 771 if let Some(curr) = self.current_inst() { 772 if let Some(prev) = self.layout().prev_inst(curr) { 773 let prev_op = self.data_flow_graph()[prev].opcode(); 774 let inst_op = self.data_flow_graph()[inst].opcode(); 775 if prev_op.is_branch() 776 && !prev_op.is_terminator() 777 && !inst_op.is_terminator() 778 { 779 panic!( 780 "Inserting instruction {} after {} and before {}", 781 self.display_inst(inst), 782 self.display_inst(prev), 783 self.display_inst(curr) 784 ) 785 } 786 }; 787 }; 788 }; 789 } 790 // Insert the instruction and remember the reference. 791 self.insert_inst(inst); 792 self.built_inst = Some(inst); 793 794 if !self.srcloc.is_default() { 795 self.func.srclocs[inst] = self.srcloc; 796 } 797 798 // Skip the encoding update if we're using a new (MachInst) backend; encodings come later, 799 // during lowering. 800 if self.isa.get_mach_backend().is_none() { 801 // Assign an encoding. 802 // XXX Is there a way to describe this error to the user? 803 #[cfg_attr(feature = "cargo-clippy", allow(clippy::match_wild_err_arm))] 804 match self 805 .isa 806 .encode(&self.func, &self.func.dfg[inst], ctrl_typevar) 807 { 808 Ok(e) => self.func.encodings[inst] = e, 809 Err(_) => panic!("can't encode {}", self.display_inst(inst)), 810 } 811 } 812 813 &mut self.func.dfg 814 } 815 } 816