1 //! Function layout. 2 //! 3 //! The order of basic blocks in a function and the order of instructions in a block is 4 //! determined by the `Layout` data structure defined in this module. 5 6 use crate::entity::SecondaryMap; 7 use crate::ir::progpoint::ProgramPoint; 8 use crate::ir::{Block, Inst}; 9 use crate::packed_option::PackedOption; 10 use crate::{timing, trace}; 11 use core::cmp; 12 13 /// The `Layout` struct determines the layout of blocks and instructions in a function. It does not 14 /// contain definitions of instructions or blocks, but depends on `Inst` and `Block` entity references 15 /// being defined elsewhere. 16 /// 17 /// This data structure determines: 18 /// 19 /// - The order of blocks in the function. 20 /// - Which block contains a given instruction. 21 /// - The order of instructions with a block. 22 /// 23 /// While data dependencies are not recorded, instruction ordering does affect control 24 /// dependencies, so part of the semantics of the program are determined by the layout. 25 /// 26 #[derive(Debug, Clone, PartialEq, Hash)] 27 pub struct Layout { 28 /// Linked list nodes for the layout order of blocks Forms a doubly linked list, terminated in 29 /// both ends by `None`. 30 blocks: SecondaryMap<Block, BlockNode>, 31 32 /// Linked list nodes for the layout order of instructions. Forms a double linked list per block, 33 /// terminated in both ends by `None`. 34 insts: SecondaryMap<Inst, InstNode>, 35 36 /// First block in the layout order, or `None` when no blocks have been laid out. 37 first_block: Option<Block>, 38 39 /// Last block in the layout order, or `None` when no blocks have been laid out. 40 last_block: Option<Block>, 41 } 42 43 impl Layout { 44 /// Create a new empty `Layout`. 45 pub fn new() -> Self { 46 Self { 47 blocks: SecondaryMap::new(), 48 insts: SecondaryMap::new(), 49 first_block: None, 50 last_block: None, 51 } 52 } 53 54 /// Clear the layout. 55 pub fn clear(&mut self) { 56 self.blocks.clear(); 57 self.insts.clear(); 58 self.first_block = None; 59 self.last_block = None; 60 } 61 62 /// Returns the capacity of the `BlockData` map. 63 pub fn block_capacity(&self) -> usize { 64 self.blocks.capacity() 65 } 66 } 67 68 /// Sequence numbers. 69 /// 70 /// All instructions are given a sequence number that can be used to quickly determine 71 /// their relative position in a block. The sequence numbers are not contiguous, but are assigned 72 /// like line numbers in BASIC: 10, 20, 30, ... 73 /// 74 /// Sequence numbers are strictly increasing within a block, but are reset between blocks. 75 /// 76 /// The result is that sequence numbers work like BASIC line numbers for the textual form of the IR. 77 type SequenceNumber = u32; 78 79 /// Initial stride assigned to new sequence numbers. 80 const MAJOR_STRIDE: SequenceNumber = 10; 81 82 /// Secondary stride used when renumbering locally. 83 const MINOR_STRIDE: SequenceNumber = 2; 84 85 /// Limit on the sequence number range we'll renumber locally. If this limit is exceeded, we'll 86 /// switch to a full block renumbering. 87 const LOCAL_LIMIT: SequenceNumber = 100 * MINOR_STRIDE; 88 89 /// Compute the midpoint between `a` and `b`. 90 /// Return `None` if the midpoint would be equal to either. 91 fn midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber> { 92 debug_assert!(a < b); 93 // Avoid integer overflow. 94 let m = a + (b - a) / 2; 95 if m > a { Some(m) } else { None } 96 } 97 98 impl Layout { 99 /// Compare the program points `a` and `b` in the same block relative to this program order. 100 /// 101 /// Return `Less` if `a` appears in the program before `b`. 102 /// 103 /// This is declared as a generic such that it can be called with `Inst` and `Block` arguments 104 /// directly. Depending on the implementation, there is a good chance performance will be 105 /// improved for those cases where the type of either argument is known statically. 106 pub fn pp_cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering 107 where 108 A: Into<ProgramPoint>, 109 B: Into<ProgramPoint>, 110 { 111 let a = a.into(); 112 let b = b.into(); 113 debug_assert_eq!(self.pp_block(a), self.pp_block(b)); 114 let a_seq = match a { 115 ProgramPoint::Block(_block) => 0, 116 ProgramPoint::Inst(inst) => self.insts[inst].seq, 117 }; 118 let b_seq = match b { 119 ProgramPoint::Block(_block) => 0, 120 ProgramPoint::Inst(inst) => self.insts[inst].seq, 121 }; 122 a_seq.cmp(&b_seq) 123 } 124 } 125 126 // Private methods for dealing with sequence numbers. 127 impl Layout { 128 /// Assign a valid sequence number to `inst` such that the numbers are still monotonic. This may 129 /// require renumbering. 130 fn assign_inst_seq(&mut self, inst: Inst) { 131 // Get the sequence number immediately before `inst`. 132 let prev_seq = match self.insts[inst].prev.expand() { 133 Some(prev_inst) => self.insts[prev_inst].seq, 134 None => 0, 135 }; 136 137 // Get the sequence number immediately following `inst`. 138 let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() { 139 self.insts[next_inst].seq 140 } else { 141 // There is nothing after `inst`. We can just use a major stride. 142 self.insts[inst].seq = prev_seq + MAJOR_STRIDE; 143 return; 144 }; 145 146 // Check if there is room between these sequence numbers. 147 if let Some(seq) = midpoint(prev_seq, next_seq) { 148 self.insts[inst].seq = seq; 149 } else { 150 // No available integers between `prev_seq` and `next_seq`. We have to renumber. 151 self.renumber_insts(inst, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT); 152 } 153 } 154 155 /// Renumber instructions starting from `inst` until the end of the block or until numbers catch 156 /// up. 157 /// 158 /// If sequence numbers exceed `limit`, switch to a full block renumbering. 159 fn renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber) { 160 let mut inst = inst; 161 let mut seq = seq; 162 163 loop { 164 self.insts[inst].seq = seq; 165 166 // Next instruction. 167 inst = match self.insts[inst].next.expand() { 168 None => return, 169 Some(next) => next, 170 }; 171 172 if seq < self.insts[inst].seq { 173 // Sequence caught up. 174 return; 175 } 176 177 if seq > limit { 178 // We're pushing too many instructions in front of us. 179 // Switch to a full block renumbering to make some space. 180 self.full_block_renumber( 181 self.inst_block(inst) 182 .expect("inst must be inserted before assigning an seq"), 183 ); 184 return; 185 } 186 187 seq += MINOR_STRIDE; 188 } 189 } 190 191 /// Renumber all instructions in a block. 192 /// 193 /// This doesn't affect the position of anything, but it gives more room in the internal 194 /// sequence numbers for inserting instructions later. 195 fn full_block_renumber(&mut self, block: Block) { 196 let _tt = timing::layout_renumber(); 197 // Avoid 0 as this is reserved for the program point indicating the block itself 198 let mut seq = MAJOR_STRIDE; 199 let mut next_inst = self.blocks[block].first_inst.expand(); 200 while let Some(inst) = next_inst { 201 self.insts[inst].seq = seq; 202 seq += MAJOR_STRIDE; 203 next_inst = self.insts[inst].next.expand(); 204 } 205 206 trace!("Renumbered {} program points", seq / MAJOR_STRIDE); 207 } 208 } 209 210 /// Methods for laying out blocks. 211 /// 212 /// An unknown block starts out as *not inserted* in the block layout. The layout is a linear order of 213 /// inserted blocks. Once a block has been inserted in the layout, instructions can be added. A block 214 /// can only be removed from the layout when it is empty. 215 /// 216 /// Since every block must end with a terminator instruction which cannot fall through, the layout of 217 /// blocks do not affect the semantics of the program. 218 /// 219 impl Layout { 220 /// Is `block` currently part of the layout? 221 pub fn is_block_inserted(&self, block: Block) -> bool { 222 Some(block) == self.first_block || self.blocks[block].prev.is_some() 223 } 224 225 /// Insert `block` as the last block in the layout. 226 pub fn append_block(&mut self, block: Block) { 227 debug_assert!( 228 !self.is_block_inserted(block), 229 "Cannot append block that is already in the layout" 230 ); 231 { 232 let node = &mut self.blocks[block]; 233 debug_assert!(node.first_inst.is_none() && node.last_inst.is_none()); 234 node.prev = self.last_block.into(); 235 node.next = None.into(); 236 } 237 if let Some(last) = self.last_block { 238 self.blocks[last].next = block.into(); 239 } else { 240 self.first_block = Some(block); 241 } 242 self.last_block = Some(block); 243 } 244 245 /// Insert `block` in the layout before the existing block `before`. 246 pub fn insert_block(&mut self, block: Block, before: Block) { 247 debug_assert!( 248 !self.is_block_inserted(block), 249 "Cannot insert block that is already in the layout" 250 ); 251 debug_assert!( 252 self.is_block_inserted(before), 253 "block Insertion point not in the layout" 254 ); 255 let after = self.blocks[before].prev; 256 { 257 let node = &mut self.blocks[block]; 258 node.next = before.into(); 259 node.prev = after; 260 } 261 self.blocks[before].prev = block.into(); 262 match after.expand() { 263 None => self.first_block = Some(block), 264 Some(a) => self.blocks[a].next = block.into(), 265 } 266 } 267 268 /// Insert `block` in the layout *after* the existing block `after`. 269 pub fn insert_block_after(&mut self, block: Block, after: Block) { 270 debug_assert!( 271 !self.is_block_inserted(block), 272 "Cannot insert block that is already in the layout" 273 ); 274 debug_assert!( 275 self.is_block_inserted(after), 276 "block Insertion point not in the layout" 277 ); 278 let before = self.blocks[after].next; 279 { 280 let node = &mut self.blocks[block]; 281 node.next = before; 282 node.prev = after.into(); 283 } 284 self.blocks[after].next = block.into(); 285 match before.expand() { 286 None => self.last_block = Some(block), 287 Some(b) => self.blocks[b].prev = block.into(), 288 } 289 } 290 291 /// Remove `block` from the layout. 292 pub fn remove_block(&mut self, block: Block) { 293 debug_assert!(self.is_block_inserted(block), "block not in the layout"); 294 debug_assert!(self.first_inst(block).is_none(), "block must be empty."); 295 296 // Clear the `block` node and extract links. 297 let prev; 298 let next; 299 { 300 let n = &mut self.blocks[block]; 301 prev = n.prev; 302 next = n.next; 303 n.prev = None.into(); 304 n.next = None.into(); 305 } 306 // Fix up links to `block`. 307 match prev.expand() { 308 None => self.first_block = next.expand(), 309 Some(p) => self.blocks[p].next = next, 310 } 311 match next.expand() { 312 None => self.last_block = prev.expand(), 313 Some(n) => self.blocks[n].prev = prev, 314 } 315 } 316 317 /// Return an iterator over all blocks in layout order. 318 pub fn blocks(&self) -> Blocks<'_> { 319 Blocks { 320 layout: self, 321 next: self.first_block, 322 } 323 } 324 325 /// Get the function's entry block. 326 /// This is simply the first block in the layout order. 327 pub fn entry_block(&self) -> Option<Block> { 328 self.first_block 329 } 330 331 /// Get the last block in the layout. 332 pub fn last_block(&self) -> Option<Block> { 333 self.last_block 334 } 335 336 /// Get the block preceding `block` in the layout order. 337 pub fn prev_block(&self, block: Block) -> Option<Block> { 338 self.blocks[block].prev.expand() 339 } 340 341 /// Get the block following `block` in the layout order. 342 pub fn next_block(&self, block: Block) -> Option<Block> { 343 self.blocks[block].next.expand() 344 } 345 346 /// Mark a block as "cold". 347 /// 348 /// This will try to move it out of the ordinary path of execution 349 /// when lowered to machine code. 350 pub fn set_cold(&mut self, block: Block) { 351 self.blocks[block].cold = true; 352 } 353 354 /// Is the given block cold? 355 pub fn is_cold(&self, block: Block) -> bool { 356 self.blocks[block].cold 357 } 358 } 359 360 /// A single node in the linked-list of blocks. 361 // **Note:** Whenever you add new fields here, don't forget to update the custom serializer for `Layout` too. 362 #[derive(Clone, Debug, Default, PartialEq, Hash)] 363 struct BlockNode { 364 prev: PackedOption<Block>, 365 next: PackedOption<Block>, 366 first_inst: PackedOption<Inst>, 367 last_inst: PackedOption<Inst>, 368 cold: bool, 369 } 370 371 /// Iterate over blocks in layout order. See [crate::ir::layout::Layout::blocks]. 372 pub struct Blocks<'f> { 373 layout: &'f Layout, 374 next: Option<Block>, 375 } 376 377 impl<'f> Iterator for Blocks<'f> { 378 type Item = Block; 379 380 fn next(&mut self) -> Option<Block> { 381 match self.next { 382 Some(block) => { 383 self.next = self.layout.next_block(block); 384 Some(block) 385 } 386 None => None, 387 } 388 } 389 } 390 391 /// Use a layout reference in a for loop. 392 impl<'f> IntoIterator for &'f Layout { 393 type Item = Block; 394 type IntoIter = Blocks<'f>; 395 396 fn into_iter(self) -> Blocks<'f> { 397 self.blocks() 398 } 399 } 400 401 /// Methods for arranging instructions. 402 /// 403 /// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into 404 /// a block at a given position. 405 impl Layout { 406 /// Get the block containing `inst`, or `None` if `inst` is not inserted in the layout. 407 pub fn inst_block(&self, inst: Inst) -> Option<Block> { 408 self.insts[inst].block.into() 409 } 410 411 /// Get the block containing the program point `pp`. Panic if `pp` is not in the layout. 412 pub fn pp_block(&self, pp: ProgramPoint) -> Block { 413 match pp { 414 ProgramPoint::Block(block) => block, 415 ProgramPoint::Inst(inst) => self.inst_block(inst).expect("Program point not in layout"), 416 } 417 } 418 419 /// Append `inst` to the end of `block`. 420 pub fn append_inst(&mut self, inst: Inst, block: Block) { 421 debug_assert_eq!(self.inst_block(inst), None); 422 debug_assert!( 423 self.is_block_inserted(block), 424 "Cannot append instructions to block not in layout" 425 ); 426 { 427 let block_node = &mut self.blocks[block]; 428 { 429 let inst_node = &mut self.insts[inst]; 430 inst_node.block = block.into(); 431 inst_node.prev = block_node.last_inst; 432 debug_assert!(inst_node.next.is_none()); 433 } 434 if block_node.first_inst.is_none() { 435 block_node.first_inst = inst.into(); 436 } else { 437 self.insts[block_node.last_inst.unwrap()].next = inst.into(); 438 } 439 block_node.last_inst = inst.into(); 440 } 441 self.assign_inst_seq(inst); 442 } 443 444 /// Fetch a block's first instruction. 445 pub fn first_inst(&self, block: Block) -> Option<Inst> { 446 self.blocks[block].first_inst.into() 447 } 448 449 /// Fetch a block's last instruction. 450 pub fn last_inst(&self, block: Block) -> Option<Inst> { 451 self.blocks[block].last_inst.into() 452 } 453 454 /// Fetch the instruction following `inst`. 455 pub fn next_inst(&self, inst: Inst) -> Option<Inst> { 456 self.insts[inst].next.expand() 457 } 458 459 /// Fetch the instruction preceding `inst`. 460 pub fn prev_inst(&self, inst: Inst) -> Option<Inst> { 461 self.insts[inst].prev.expand() 462 } 463 464 /// Insert `inst` before the instruction `before` in the same block. 465 pub fn insert_inst(&mut self, inst: Inst, before: Inst) { 466 debug_assert_eq!(self.inst_block(inst), None); 467 let block = self 468 .inst_block(before) 469 .expect("Instruction before insertion point not in the layout"); 470 let after = self.insts[before].prev; 471 { 472 let inst_node = &mut self.insts[inst]; 473 inst_node.block = block.into(); 474 inst_node.next = before.into(); 475 inst_node.prev = after; 476 } 477 self.insts[before].prev = inst.into(); 478 match after.expand() { 479 None => self.blocks[block].first_inst = inst.into(), 480 Some(a) => self.insts[a].next = inst.into(), 481 } 482 self.assign_inst_seq(inst); 483 } 484 485 /// Remove `inst` from the layout. 486 pub fn remove_inst(&mut self, inst: Inst) { 487 let block = self.inst_block(inst).expect("Instruction already removed."); 488 // Clear the `inst` node and extract links. 489 let prev; 490 let next; 491 { 492 let n = &mut self.insts[inst]; 493 prev = n.prev; 494 next = n.next; 495 n.block = None.into(); 496 n.prev = None.into(); 497 n.next = None.into(); 498 } 499 // Fix up links to `inst`. 500 match prev.expand() { 501 None => self.blocks[block].first_inst = next, 502 Some(p) => self.insts[p].next = next, 503 } 504 match next.expand() { 505 None => self.blocks[block].last_inst = prev, 506 Some(n) => self.insts[n].prev = prev, 507 } 508 } 509 510 /// Iterate over the instructions in `block` in layout order. 511 pub fn block_insts(&self, block: Block) -> Insts<'_> { 512 Insts { 513 layout: self, 514 head: self.blocks[block].first_inst.into(), 515 tail: self.blocks[block].last_inst.into(), 516 } 517 } 518 519 /// Does the given block contain exactly one instruction? 520 pub fn block_contains_exactly_one_inst(&self, block: Block) -> bool { 521 let block = &self.blocks[block]; 522 block.first_inst.is_some() && block.first_inst == block.last_inst 523 } 524 525 /// Split the block containing `before` in two. 526 /// 527 /// Insert `new_block` after the old block and move `before` and the following instructions to 528 /// `new_block`: 529 /// 530 /// ```text 531 /// old_block: 532 /// i1 533 /// i2 534 /// i3 << before 535 /// i4 536 /// ``` 537 /// becomes: 538 /// 539 /// ```text 540 /// old_block: 541 /// i1 542 /// i2 543 /// new_block: 544 /// i3 << before 545 /// i4 546 /// ``` 547 pub fn split_block(&mut self, new_block: Block, before: Inst) { 548 let old_block = self 549 .inst_block(before) 550 .expect("The `before` instruction must be in the layout"); 551 debug_assert!(!self.is_block_inserted(new_block)); 552 553 // Insert new_block after old_block. 554 let next_block = self.blocks[old_block].next; 555 let last_inst = self.blocks[old_block].last_inst; 556 { 557 let node = &mut self.blocks[new_block]; 558 node.prev = old_block.into(); 559 node.next = next_block; 560 node.first_inst = before.into(); 561 node.last_inst = last_inst; 562 } 563 self.blocks[old_block].next = new_block.into(); 564 565 // Fix backwards link. 566 if Some(old_block) == self.last_block { 567 self.last_block = Some(new_block); 568 } else { 569 self.blocks[next_block.unwrap()].prev = new_block.into(); 570 } 571 572 // Disconnect the instruction links. 573 let prev_inst = self.insts[before].prev; 574 self.insts[before].prev = None.into(); 575 self.blocks[old_block].last_inst = prev_inst; 576 match prev_inst.expand() { 577 None => self.blocks[old_block].first_inst = None.into(), 578 Some(pi) => self.insts[pi].next = None.into(), 579 } 580 581 // Fix the instruction -> block pointers. 582 let mut opt_i = Some(before); 583 while let Some(i) = opt_i { 584 debug_assert_eq!(self.insts[i].block.expand(), Some(old_block)); 585 self.insts[i].block = new_block.into(); 586 opt_i = self.insts[i].next.into(); 587 } 588 } 589 } 590 591 #[derive(Clone, Debug, Default)] 592 struct InstNode { 593 /// The Block containing this instruction, or `None` if the instruction is not yet inserted. 594 block: PackedOption<Block>, 595 prev: PackedOption<Inst>, 596 next: PackedOption<Inst>, 597 seq: SequenceNumber, 598 } 599 600 impl PartialEq for InstNode { 601 fn eq(&self, other: &Self) -> bool { 602 // Ignore the sequence number as it is an optimization used by pp_cmp and may be different 603 // even for equivalent layouts. 604 self.block == other.block && self.prev == other.prev && self.next == other.next 605 } 606 } 607 608 impl core::hash::Hash for InstNode { 609 fn hash<H: core::hash::Hasher>(&self, state: &mut H) { 610 // Ignore the sequence number as it is an optimization used by pp_cmp and may be different 611 // even for equivalent layouts. 612 self.block.hash(state); 613 self.prev.hash(state); 614 self.next.hash(state); 615 } 616 } 617 618 /// Iterate over instructions in a block in layout order. See `Layout::block_insts()`. 619 pub struct Insts<'f> { 620 layout: &'f Layout, 621 head: Option<Inst>, 622 tail: Option<Inst>, 623 } 624 625 impl<'f> Iterator for Insts<'f> { 626 type Item = Inst; 627 628 fn next(&mut self) -> Option<Inst> { 629 let rval = self.head; 630 if let Some(inst) = rval { 631 if self.head == self.tail { 632 self.head = None; 633 self.tail = None; 634 } else { 635 self.head = self.layout.insts[inst].next.into(); 636 } 637 } 638 rval 639 } 640 } 641 642 impl<'f> DoubleEndedIterator for Insts<'f> { 643 fn next_back(&mut self) -> Option<Inst> { 644 let rval = self.tail; 645 if let Some(inst) = rval { 646 if self.head == self.tail { 647 self.head = None; 648 self.tail = None; 649 } else { 650 self.tail = self.layout.insts[inst].prev.into(); 651 } 652 } 653 rval 654 } 655 } 656 657 /// A custom serialize and deserialize implementation for [`Layout`]. 658 /// 659 /// This doesn't use a derived implementation as [`Layout`] is a manual implementation of a linked 660 /// list. Storing it directly as a regular list saves a lot of space. 661 /// 662 /// The following format is used. (notated in EBNF form) 663 /// 664 /// ```plain 665 /// data = block_data * ; 666 /// block_data = "block_id" , "cold" , "inst_count" , ( "inst_id" * ) ; 667 /// ``` 668 #[cfg(feature = "enable-serde")] 669 mod serde { 670 use ::serde::de::{Deserializer, Error, SeqAccess, Visitor}; 671 use ::serde::ser::{SerializeSeq, Serializer}; 672 use ::serde::{Deserialize, Serialize}; 673 use core::fmt; 674 use core::marker::PhantomData; 675 676 use super::*; 677 678 impl Serialize for Layout { 679 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 680 where 681 S: Serializer, 682 { 683 let size = self.blocks().count() * 3 684 + self 685 .blocks() 686 .map(|block| self.block_insts(block).count()) 687 .sum::<usize>(); 688 let mut seq = serializer.serialize_seq(Some(size))?; 689 for block in self.blocks() { 690 seq.serialize_element(&block)?; 691 seq.serialize_element(&self.blocks[block].cold)?; 692 seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?; 693 for inst in self.block_insts(block) { 694 seq.serialize_element(&inst)?; 695 } 696 } 697 seq.end() 698 } 699 } 700 701 impl<'de> Deserialize<'de> for Layout { 702 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 703 where 704 D: Deserializer<'de>, 705 { 706 deserializer.deserialize_seq(LayoutVisitor { 707 marker: PhantomData, 708 }) 709 } 710 } 711 712 struct LayoutVisitor { 713 marker: PhantomData<fn() -> Layout>, 714 } 715 716 impl<'de> Visitor<'de> for LayoutVisitor { 717 type Value = Layout; 718 719 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 720 write!(formatter, "a `cranelift_codegen::ir::Layout`") 721 } 722 723 fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error> 724 where 725 M: SeqAccess<'de>, 726 { 727 let mut layout = Layout::new(); 728 729 while let Some(block) = access.next_element::<Block>()? { 730 layout.append_block(block); 731 732 let cold = access 733 .next_element::<bool>()? 734 .ok_or_else(|| Error::missing_field("cold"))?; 735 layout.blocks[block].cold = cold; 736 737 let count = access 738 .next_element::<u32>()? 739 .ok_or_else(|| Error::missing_field("count"))?; 740 741 for _ in 0..count { 742 let inst = access 743 .next_element::<Inst>()? 744 .ok_or_else(|| Error::missing_field("inst"))?; 745 layout.append_inst(inst, block); 746 } 747 } 748 749 Ok(layout) 750 } 751 } 752 } 753 754 #[cfg(test)] 755 mod tests { 756 use super::*; 757 use crate::cursor::{Cursor, CursorPosition}; 758 use crate::entity::EntityRef; 759 use crate::ir::{Block, Inst, SourceLoc}; 760 use alloc::vec::Vec; 761 use core::cmp::Ordering; 762 763 #[test] 764 fn test_midpoint() { 765 assert_eq!(midpoint(0, 1), None); 766 assert_eq!(midpoint(0, 2), Some(1)); 767 assert_eq!(midpoint(0, 3), Some(1)); 768 assert_eq!(midpoint(0, 4), Some(2)); 769 assert_eq!(midpoint(1, 4), Some(2)); 770 assert_eq!(midpoint(2, 4), Some(3)); 771 assert_eq!(midpoint(3, 4), None); 772 assert_eq!(midpoint(3, 4), None); 773 } 774 775 struct LayoutCursor<'f> { 776 /// Borrowed function layout. Public so it can be re-borrowed from this cursor. 777 pub layout: &'f mut Layout, 778 pos: CursorPosition, 779 } 780 781 impl<'f> Cursor for LayoutCursor<'f> { 782 fn position(&self) -> CursorPosition { 783 self.pos 784 } 785 786 fn set_position(&mut self, pos: CursorPosition) { 787 self.pos = pos; 788 } 789 790 fn srcloc(&self) -> SourceLoc { 791 unimplemented!() 792 } 793 794 fn set_srcloc(&mut self, _srcloc: SourceLoc) { 795 unimplemented!() 796 } 797 798 fn layout(&self) -> &Layout { 799 self.layout 800 } 801 802 fn layout_mut(&mut self) -> &mut Layout { 803 self.layout 804 } 805 } 806 807 impl<'f> LayoutCursor<'f> { 808 /// Create a new `LayoutCursor` for `layout`. 809 /// The cursor holds a mutable reference to `layout` for its entire lifetime. 810 pub fn new(layout: &'f mut Layout) -> Self { 811 Self { 812 layout, 813 pos: CursorPosition::Nowhere, 814 } 815 } 816 } 817 818 fn verify(layout: &mut Layout, blocks: &[(Block, &[Inst])]) { 819 // Check that blocks are inserted and instructions belong the right places. 820 // Check forward linkage with iterators. 821 // Check that layout sequence numbers are strictly monotonic. 822 { 823 let mut block_iter = layout.blocks(); 824 for &(block, insts) in blocks { 825 assert!(layout.is_block_inserted(block)); 826 assert_eq!(block_iter.next(), Some(block)); 827 828 let mut seq = 0; 829 let mut inst_iter = layout.block_insts(block); 830 for &inst in insts { 831 assert_eq!(layout.inst_block(inst), Some(block)); 832 assert_eq!(inst_iter.next(), Some(inst)); 833 assert!(layout.insts[inst].seq > seq); 834 seq = layout.insts[inst].seq; 835 } 836 assert_eq!(inst_iter.next(), None); 837 } 838 assert_eq!(block_iter.next(), None); 839 } 840 841 // Check backwards linkage with a cursor. 842 let mut cur = LayoutCursor::new(layout); 843 for &(block, insts) in blocks.into_iter().rev() { 844 assert_eq!(cur.prev_block(), Some(block)); 845 for &inst in insts.into_iter().rev() { 846 assert_eq!(cur.prev_inst(), Some(inst)); 847 } 848 assert_eq!(cur.prev_inst(), None); 849 } 850 assert_eq!(cur.prev_block(), None); 851 } 852 853 #[test] 854 fn append_block() { 855 let mut layout = Layout::new(); 856 let e0 = Block::new(0); 857 let e1 = Block::new(1); 858 let e2 = Block::new(2); 859 860 { 861 let imm = &layout; 862 assert!(!imm.is_block_inserted(e0)); 863 assert!(!imm.is_block_inserted(e1)); 864 } 865 verify(&mut layout, &[]); 866 867 layout.append_block(e1); 868 assert!(!layout.is_block_inserted(e0)); 869 assert!(layout.is_block_inserted(e1)); 870 assert!(!layout.is_block_inserted(e2)); 871 let v: Vec<Block> = layout.blocks().collect(); 872 assert_eq!(v, [e1]); 873 874 layout.append_block(e2); 875 assert!(!layout.is_block_inserted(e0)); 876 assert!(layout.is_block_inserted(e1)); 877 assert!(layout.is_block_inserted(e2)); 878 let v: Vec<Block> = layout.blocks().collect(); 879 assert_eq!(v, [e1, e2]); 880 881 layout.append_block(e0); 882 assert!(layout.is_block_inserted(e0)); 883 assert!(layout.is_block_inserted(e1)); 884 assert!(layout.is_block_inserted(e2)); 885 let v: Vec<Block> = layout.blocks().collect(); 886 assert_eq!(v, [e1, e2, e0]); 887 888 { 889 let imm = &layout; 890 let mut v = Vec::new(); 891 for e in imm { 892 v.push(e); 893 } 894 assert_eq!(v, [e1, e2, e0]); 895 } 896 897 // Test cursor positioning. 898 let mut cur = LayoutCursor::new(&mut layout); 899 assert_eq!(cur.position(), CursorPosition::Nowhere); 900 assert_eq!(cur.next_inst(), None); 901 assert_eq!(cur.position(), CursorPosition::Nowhere); 902 assert_eq!(cur.prev_inst(), None); 903 assert_eq!(cur.position(), CursorPosition::Nowhere); 904 905 assert_eq!(cur.next_block(), Some(e1)); 906 assert_eq!(cur.position(), CursorPosition::Before(e1)); 907 assert_eq!(cur.next_inst(), None); 908 assert_eq!(cur.position(), CursorPosition::After(e1)); 909 assert_eq!(cur.next_inst(), None); 910 assert_eq!(cur.position(), CursorPosition::After(e1)); 911 assert_eq!(cur.next_block(), Some(e2)); 912 assert_eq!(cur.prev_inst(), None); 913 assert_eq!(cur.position(), CursorPosition::Before(e2)); 914 assert_eq!(cur.next_block(), Some(e0)); 915 assert_eq!(cur.next_block(), None); 916 assert_eq!(cur.position(), CursorPosition::Nowhere); 917 918 // Backwards through the blocks. 919 assert_eq!(cur.prev_block(), Some(e0)); 920 assert_eq!(cur.position(), CursorPosition::After(e0)); 921 assert_eq!(cur.prev_block(), Some(e2)); 922 assert_eq!(cur.prev_block(), Some(e1)); 923 assert_eq!(cur.prev_block(), None); 924 assert_eq!(cur.position(), CursorPosition::Nowhere); 925 } 926 927 #[test] 928 fn insert_block() { 929 let mut layout = Layout::new(); 930 let e0 = Block::new(0); 931 let e1 = Block::new(1); 932 let e2 = Block::new(2); 933 934 { 935 let imm = &layout; 936 assert!(!imm.is_block_inserted(e0)); 937 assert!(!imm.is_block_inserted(e1)); 938 939 let v: Vec<Block> = layout.blocks().collect(); 940 assert_eq!(v, []); 941 } 942 943 layout.append_block(e1); 944 assert!(!layout.is_block_inserted(e0)); 945 assert!(layout.is_block_inserted(e1)); 946 assert!(!layout.is_block_inserted(e2)); 947 verify(&mut layout, &[(e1, &[])]); 948 949 layout.insert_block(e2, e1); 950 assert!(!layout.is_block_inserted(e0)); 951 assert!(layout.is_block_inserted(e1)); 952 assert!(layout.is_block_inserted(e2)); 953 verify(&mut layout, &[(e2, &[]), (e1, &[])]); 954 955 layout.insert_block(e0, e1); 956 assert!(layout.is_block_inserted(e0)); 957 assert!(layout.is_block_inserted(e1)); 958 assert!(layout.is_block_inserted(e2)); 959 verify(&mut layout, &[(e2, &[]), (e0, &[]), (e1, &[])]); 960 } 961 962 #[test] 963 fn insert_block_after() { 964 let mut layout = Layout::new(); 965 let e0 = Block::new(0); 966 let e1 = Block::new(1); 967 let e2 = Block::new(2); 968 969 layout.append_block(e1); 970 layout.insert_block_after(e2, e1); 971 verify(&mut layout, &[(e1, &[]), (e2, &[])]); 972 973 layout.insert_block_after(e0, e1); 974 verify(&mut layout, &[(e1, &[]), (e0, &[]), (e2, &[])]); 975 } 976 977 #[test] 978 fn append_inst() { 979 let mut layout = Layout::new(); 980 let e1 = Block::new(1); 981 982 layout.append_block(e1); 983 let v: Vec<Inst> = layout.block_insts(e1).collect(); 984 assert_eq!(v, []); 985 986 let i0 = Inst::new(0); 987 let i1 = Inst::new(1); 988 let i2 = Inst::new(2); 989 990 assert_eq!(layout.inst_block(i0), None); 991 assert_eq!(layout.inst_block(i1), None); 992 assert_eq!(layout.inst_block(i2), None); 993 994 layout.append_inst(i1, e1); 995 assert_eq!(layout.inst_block(i0), None); 996 assert_eq!(layout.inst_block(i1), Some(e1)); 997 assert_eq!(layout.inst_block(i2), None); 998 let v: Vec<Inst> = layout.block_insts(e1).collect(); 999 assert_eq!(v, [i1]); 1000 1001 layout.append_inst(i2, e1); 1002 assert_eq!(layout.inst_block(i0), None); 1003 assert_eq!(layout.inst_block(i1), Some(e1)); 1004 assert_eq!(layout.inst_block(i2), Some(e1)); 1005 let v: Vec<Inst> = layout.block_insts(e1).collect(); 1006 assert_eq!(v, [i1, i2]); 1007 1008 // Test double-ended instruction iterator. 1009 let v: Vec<Inst> = layout.block_insts(e1).rev().collect(); 1010 assert_eq!(v, [i2, i1]); 1011 1012 layout.append_inst(i0, e1); 1013 verify(&mut layout, &[(e1, &[i1, i2, i0])]); 1014 1015 // Test cursor positioning. 1016 let mut cur = LayoutCursor::new(&mut layout).at_top(e1); 1017 assert_eq!(cur.position(), CursorPosition::Before(e1)); 1018 assert_eq!(cur.prev_inst(), None); 1019 assert_eq!(cur.position(), CursorPosition::Before(e1)); 1020 assert_eq!(cur.next_inst(), Some(i1)); 1021 assert_eq!(cur.position(), CursorPosition::At(i1)); 1022 assert_eq!(cur.next_inst(), Some(i2)); 1023 assert_eq!(cur.next_inst(), Some(i0)); 1024 assert_eq!(cur.prev_inst(), Some(i2)); 1025 assert_eq!(cur.position(), CursorPosition::At(i2)); 1026 assert_eq!(cur.next_inst(), Some(i0)); 1027 assert_eq!(cur.position(), CursorPosition::At(i0)); 1028 assert_eq!(cur.next_inst(), None); 1029 assert_eq!(cur.position(), CursorPosition::After(e1)); 1030 assert_eq!(cur.next_inst(), None); 1031 assert_eq!(cur.position(), CursorPosition::After(e1)); 1032 assert_eq!(cur.prev_inst(), Some(i0)); 1033 assert_eq!(cur.prev_inst(), Some(i2)); 1034 assert_eq!(cur.prev_inst(), Some(i1)); 1035 assert_eq!(cur.prev_inst(), None); 1036 assert_eq!(cur.position(), CursorPosition::Before(e1)); 1037 1038 // Test remove_inst. 1039 cur.goto_inst(i2); 1040 assert_eq!(cur.remove_inst(), i2); 1041 verify(cur.layout, &[(e1, &[i1, i0])]); 1042 assert_eq!(cur.layout.inst_block(i2), None); 1043 assert_eq!(cur.remove_inst(), i0); 1044 verify(cur.layout, &[(e1, &[i1])]); 1045 assert_eq!(cur.layout.inst_block(i0), None); 1046 assert_eq!(cur.position(), CursorPosition::After(e1)); 1047 cur.layout.remove_inst(i1); 1048 verify(cur.layout, &[(e1, &[])]); 1049 assert_eq!(cur.layout.inst_block(i1), None); 1050 } 1051 1052 #[test] 1053 fn insert_inst() { 1054 let mut layout = Layout::new(); 1055 let e1 = Block::new(1); 1056 1057 layout.append_block(e1); 1058 let v: Vec<Inst> = layout.block_insts(e1).collect(); 1059 assert_eq!(v, []); 1060 1061 let i0 = Inst::new(0); 1062 let i1 = Inst::new(1); 1063 let i2 = Inst::new(2); 1064 1065 assert_eq!(layout.inst_block(i0), None); 1066 assert_eq!(layout.inst_block(i1), None); 1067 assert_eq!(layout.inst_block(i2), None); 1068 1069 layout.append_inst(i1, e1); 1070 assert_eq!(layout.inst_block(i0), None); 1071 assert_eq!(layout.inst_block(i1), Some(e1)); 1072 assert_eq!(layout.inst_block(i2), None); 1073 let v: Vec<Inst> = layout.block_insts(e1).collect(); 1074 assert_eq!(v, [i1]); 1075 1076 layout.insert_inst(i2, i1); 1077 assert_eq!(layout.inst_block(i0), None); 1078 assert_eq!(layout.inst_block(i1), Some(e1)); 1079 assert_eq!(layout.inst_block(i2), Some(e1)); 1080 let v: Vec<Inst> = layout.block_insts(e1).collect(); 1081 assert_eq!(v, [i2, i1]); 1082 1083 layout.insert_inst(i0, i1); 1084 verify(&mut layout, &[(e1, &[i2, i0, i1])]); 1085 } 1086 1087 #[test] 1088 fn multiple_blocks() { 1089 let mut layout = Layout::new(); 1090 1091 let e0 = Block::new(0); 1092 let e1 = Block::new(1); 1093 1094 assert_eq!(layout.entry_block(), None); 1095 layout.append_block(e0); 1096 assert_eq!(layout.entry_block(), Some(e0)); 1097 layout.append_block(e1); 1098 assert_eq!(layout.entry_block(), Some(e0)); 1099 1100 let i0 = Inst::new(0); 1101 let i1 = Inst::new(1); 1102 let i2 = Inst::new(2); 1103 let i3 = Inst::new(3); 1104 1105 layout.append_inst(i0, e0); 1106 layout.append_inst(i1, e0); 1107 layout.append_inst(i2, e1); 1108 layout.append_inst(i3, e1); 1109 1110 let v0: Vec<Inst> = layout.block_insts(e0).collect(); 1111 let v1: Vec<Inst> = layout.block_insts(e1).collect(); 1112 assert_eq!(v0, [i0, i1]); 1113 assert_eq!(v1, [i2, i3]); 1114 } 1115 1116 #[test] 1117 fn split_block() { 1118 let mut layout = Layout::new(); 1119 1120 let e0 = Block::new(0); 1121 let e1 = Block::new(1); 1122 let e2 = Block::new(2); 1123 1124 let i0 = Inst::new(0); 1125 let i1 = Inst::new(1); 1126 let i2 = Inst::new(2); 1127 let i3 = Inst::new(3); 1128 1129 layout.append_block(e0); 1130 layout.append_inst(i0, e0); 1131 assert_eq!(layout.inst_block(i0), Some(e0)); 1132 layout.split_block(e1, i0); 1133 assert_eq!(layout.inst_block(i0), Some(e1)); 1134 1135 { 1136 let mut cur = LayoutCursor::new(&mut layout); 1137 assert_eq!(cur.next_block(), Some(e0)); 1138 assert_eq!(cur.next_inst(), None); 1139 assert_eq!(cur.next_block(), Some(e1)); 1140 assert_eq!(cur.next_inst(), Some(i0)); 1141 assert_eq!(cur.next_inst(), None); 1142 assert_eq!(cur.next_block(), None); 1143 1144 // Check backwards links. 1145 assert_eq!(cur.prev_block(), Some(e1)); 1146 assert_eq!(cur.prev_inst(), Some(i0)); 1147 assert_eq!(cur.prev_inst(), None); 1148 assert_eq!(cur.prev_block(), Some(e0)); 1149 assert_eq!(cur.prev_inst(), None); 1150 assert_eq!(cur.prev_block(), None); 1151 } 1152 1153 layout.append_inst(i1, e0); 1154 layout.append_inst(i2, e0); 1155 layout.append_inst(i3, e0); 1156 layout.split_block(e2, i2); 1157 1158 assert_eq!(layout.inst_block(i0), Some(e1)); 1159 assert_eq!(layout.inst_block(i1), Some(e0)); 1160 assert_eq!(layout.inst_block(i2), Some(e2)); 1161 assert_eq!(layout.inst_block(i3), Some(e2)); 1162 1163 { 1164 let mut cur = LayoutCursor::new(&mut layout); 1165 assert_eq!(cur.next_block(), Some(e0)); 1166 assert_eq!(cur.next_inst(), Some(i1)); 1167 assert_eq!(cur.next_inst(), None); 1168 assert_eq!(cur.next_block(), Some(e2)); 1169 assert_eq!(cur.next_inst(), Some(i2)); 1170 assert_eq!(cur.next_inst(), Some(i3)); 1171 assert_eq!(cur.next_inst(), None); 1172 assert_eq!(cur.next_block(), Some(e1)); 1173 assert_eq!(cur.next_inst(), Some(i0)); 1174 assert_eq!(cur.next_inst(), None); 1175 assert_eq!(cur.next_block(), None); 1176 1177 assert_eq!(cur.prev_block(), Some(e1)); 1178 assert_eq!(cur.prev_inst(), Some(i0)); 1179 assert_eq!(cur.prev_inst(), None); 1180 assert_eq!(cur.prev_block(), Some(e2)); 1181 assert_eq!(cur.prev_inst(), Some(i3)); 1182 assert_eq!(cur.prev_inst(), Some(i2)); 1183 assert_eq!(cur.prev_inst(), None); 1184 assert_eq!(cur.prev_block(), Some(e0)); 1185 assert_eq!(cur.prev_inst(), Some(i1)); 1186 assert_eq!(cur.prev_inst(), None); 1187 assert_eq!(cur.prev_block(), None); 1188 } 1189 1190 // Check `ProgramOrder`. 1191 assert_eq!(layout.pp_cmp(e2, e2), Ordering::Equal); 1192 assert_eq!(layout.pp_cmp(e2, i2), Ordering::Less); 1193 assert_eq!(layout.pp_cmp(i3, i2), Ordering::Greater) 1194 } 1195 } 1196