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`.
new() -> Self45 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.
clear(&mut self)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.
block_capacity(&self) -> usize63 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.
midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber>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.
pp_cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering where A: Into<ProgramPoint>, B: Into<ProgramPoint>,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.
assign_inst_seq(&mut self, inst: Inst)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.
renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber)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.
full_block_renumber(&mut self, block: Block)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?
is_block_inserted(&self, block: Block) -> bool221 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.
append_block(&mut self, block: Block)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`.
insert_block(&mut self, block: Block, before: Block)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`.
insert_block_after(&mut self, block: Block, after: Block)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.
remove_block(&mut self, block: Block)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.
blocks(&self) -> Blocks<'_>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.
entry_block(&self) -> Option<Block>327 pub fn entry_block(&self) -> Option<Block> {
328 self.first_block
329 }
330
331 /// Get the last block in the layout.
last_block(&self) -> Option<Block>332 pub fn last_block(&self) -> Option<Block> {
333 self.last_block
334 }
335
336 /// Get the block preceding `block` in the layout order.
prev_block(&self, block: Block) -> Option<Block>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.
next_block(&self, block: Block) -> Option<Block>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.
set_cold(&mut self, block: Block)350 pub fn set_cold(&mut self, block: Block) {
351 self.blocks[block].cold = true;
352 }
353
354 /// Is the given block cold?
is_cold(&self, block: Block) -> bool355 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
next(&mut self) -> Option<Block>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
into_iter(self) -> Blocks<'f>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.
inst_block(&self, inst: Inst) -> Option<Block>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.
pp_block(&self, pp: ProgramPoint) -> Block412 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`.
append_inst(&mut self, inst: Inst, block: 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.
first_inst(&self, block: Block) -> Option<Inst>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.
last_inst(&self, block: Block) -> Option<Inst>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`.
next_inst(&self, inst: Inst) -> Option<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`.
prev_inst(&self, inst: Inst) -> Option<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.
insert_inst(&mut self, inst: Inst, before: Inst)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.
remove_inst(&mut self, inst: Inst)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.
block_insts(&self, block: Block) -> Insts<'_>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?
block_contains_exactly_one_inst(&self, block: Block) -> bool520 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 /// ```
split_block(&mut self, new_block: Block, before: Inst)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 {
eq(&self, other: &Self) -> bool601 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 {
hash<H: core::hash::Hasher>(&self, state: &mut H)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
next(&mut self) -> Option<Inst>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> {
next_back(&mut self) -> Option<Inst>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 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,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 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,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
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result719 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
720 write!(formatter, "a `cranelift_codegen::ir::Layout`")
721 }
722
visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error> where M: SeqAccess<'de>,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]
test_midpoint()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> {
position(&self) -> CursorPosition782 fn position(&self) -> CursorPosition {
783 self.pos
784 }
785
set_position(&mut self, pos: CursorPosition)786 fn set_position(&mut self, pos: CursorPosition) {
787 self.pos = pos;
788 }
789
srcloc(&self) -> SourceLoc790 fn srcloc(&self) -> SourceLoc {
791 unimplemented!()
792 }
793
set_srcloc(&mut self, _srcloc: SourceLoc)794 fn set_srcloc(&mut self, _srcloc: SourceLoc) {
795 unimplemented!()
796 }
797
layout(&self) -> &Layout798 fn layout(&self) -> &Layout {
799 self.layout
800 }
801
layout_mut(&mut self) -> &mut Layout802 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.
new(layout: &'f mut Layout) -> Self810 pub fn new(layout: &'f mut Layout) -> Self {
811 Self {
812 layout,
813 pos: CursorPosition::Nowhere,
814 }
815 }
816 }
817
verify(layout: &mut Layout, blocks: &[(Block, &[Inst])])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]
append_block()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]
insert_block()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]
insert_block_after()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]
append_inst()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]
insert_inst()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]
multiple_blocks()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]
split_block()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