1747ad3c4Slazypassion //! Function layout.
2747ad3c4Slazypassion //!
307f335dcSRyan Hunt //! The order of basic blocks in a function and the order of instructions in a block is
4747ad3c4Slazypassion //! determined by the `Layout` data structure defined in this module.
5747ad3c4Slazypassion 
6747ad3c4Slazypassion use crate::entity::SecondaryMap;
7a81c2068Sbjorn3 use crate::ir::progpoint::ProgramPoint;
8832666c4SRyan Hunt use crate::ir::{Block, Inst};
9747ad3c4Slazypassion use crate::packed_option::PackedOption;
108d022434SBenjamin Bouvier use crate::{timing, trace};
11747ad3c4Slazypassion use core::cmp;
12747ad3c4Slazypassion 
13832666c4SRyan Hunt /// The `Layout` struct determines the layout of blocks and instructions in a function. It does not
14832666c4SRyan Hunt /// contain definitions of instructions or blocks, but depends on `Inst` and `Block` entity references
15747ad3c4Slazypassion /// being defined elsewhere.
16747ad3c4Slazypassion ///
17747ad3c4Slazypassion /// This data structure determines:
18747ad3c4Slazypassion ///
19832666c4SRyan Hunt /// - The order of blocks in the function.
20832666c4SRyan Hunt /// - Which block contains a given instruction.
2107f335dcSRyan Hunt /// - The order of instructions with a block.
22747ad3c4Slazypassion ///
23747ad3c4Slazypassion /// While data dependencies are not recorded, instruction ordering does affect control
24747ad3c4Slazypassion /// dependencies, so part of the semantics of the program are determined by the layout.
25747ad3c4Slazypassion ///
268a9b1a90SBenjamin Bouvier #[derive(Debug, Clone, PartialEq, Hash)]
27747ad3c4Slazypassion pub struct Layout {
28832666c4SRyan Hunt     /// Linked list nodes for the layout order of blocks Forms a doubly linked list, terminated in
29747ad3c4Slazypassion     /// both ends by `None`.
30832666c4SRyan Hunt     blocks: SecondaryMap<Block, BlockNode>,
31747ad3c4Slazypassion 
32832666c4SRyan Hunt     /// Linked list nodes for the layout order of instructions. Forms a double linked list per block,
33747ad3c4Slazypassion     /// terminated in both ends by `None`.
34747ad3c4Slazypassion     insts: SecondaryMap<Inst, InstNode>,
35747ad3c4Slazypassion 
36832666c4SRyan Hunt     /// First block in the layout order, or `None` when no blocks have been laid out.
37832666c4SRyan Hunt     first_block: Option<Block>,
38747ad3c4Slazypassion 
39832666c4SRyan Hunt     /// Last block in the layout order, or `None` when no blocks have been laid out.
40832666c4SRyan Hunt     last_block: Option<Block>,
41747ad3c4Slazypassion }
42747ad3c4Slazypassion 
43747ad3c4Slazypassion impl Layout {
44747ad3c4Slazypassion     /// Create a new empty `Layout`.
new() -> Self45747ad3c4Slazypassion     pub fn new() -> Self {
46747ad3c4Slazypassion         Self {
47832666c4SRyan Hunt             blocks: SecondaryMap::new(),
48747ad3c4Slazypassion             insts: SecondaryMap::new(),
49832666c4SRyan Hunt             first_block: None,
50832666c4SRyan Hunt             last_block: None,
51747ad3c4Slazypassion         }
52747ad3c4Slazypassion     }
53747ad3c4Slazypassion 
54747ad3c4Slazypassion     /// Clear the layout.
clear(&mut self)55747ad3c4Slazypassion     pub fn clear(&mut self) {
56832666c4SRyan Hunt         self.blocks.clear();
57747ad3c4Slazypassion         self.insts.clear();
58832666c4SRyan Hunt         self.first_block = None;
59832666c4SRyan Hunt         self.last_block = None;
60747ad3c4Slazypassion     }
614b085b9cSSean Stangl 
62832666c4SRyan Hunt     /// Returns the capacity of the `BlockData` map.
block_capacity(&self) -> usize63832666c4SRyan Hunt     pub fn block_capacity(&self) -> usize {
64832666c4SRyan Hunt         self.blocks.capacity()
654b085b9cSSean Stangl     }
66747ad3c4Slazypassion }
67747ad3c4Slazypassion 
68747ad3c4Slazypassion /// Sequence numbers.
69747ad3c4Slazypassion ///
702c40c267Sbjorn3 /// All instructions are given a sequence number that can be used to quickly determine
712c40c267Sbjorn3 /// their relative position in a block. The sequence numbers are not contiguous, but are assigned
72747ad3c4Slazypassion /// like line numbers in BASIC: 10, 20, 30, ...
73747ad3c4Slazypassion ///
742c40c267Sbjorn3 /// Sequence numbers are strictly increasing within a block, but are reset between blocks.
75747ad3c4Slazypassion ///
76747ad3c4Slazypassion /// The result is that sequence numbers work like BASIC line numbers for the textual form of the IR.
77747ad3c4Slazypassion type SequenceNumber = u32;
78747ad3c4Slazypassion 
79747ad3c4Slazypassion /// Initial stride assigned to new sequence numbers.
80747ad3c4Slazypassion const MAJOR_STRIDE: SequenceNumber = 10;
81747ad3c4Slazypassion 
82747ad3c4Slazypassion /// Secondary stride used when renumbering locally.
83747ad3c4Slazypassion const MINOR_STRIDE: SequenceNumber = 2;
84747ad3c4Slazypassion 
85747ad3c4Slazypassion /// Limit on the sequence number range we'll renumber locally. If this limit is exceeded, we'll
862c40c267Sbjorn3 /// switch to a full block renumbering.
87747ad3c4Slazypassion const LOCAL_LIMIT: SequenceNumber = 100 * MINOR_STRIDE;
88747ad3c4Slazypassion 
89747ad3c4Slazypassion /// Compute the midpoint between `a` and `b`.
90747ad3c4Slazypassion /// Return `None` if the midpoint would be equal to either.
midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber>91747ad3c4Slazypassion fn midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber> {
92747ad3c4Slazypassion     debug_assert!(a < b);
93747ad3c4Slazypassion     // Avoid integer overflow.
94747ad3c4Slazypassion     let m = a + (b - a) / 2;
9590ac295eSAlex Crichton     if m > a { Some(m) } else { None }
96747ad3c4Slazypassion }
97747ad3c4Slazypassion 
98a81c2068Sbjorn3 impl Layout {
992c40c267Sbjorn3     /// Compare the program points `a` and `b` in the same block relative to this program order.
100a81c2068Sbjorn3     ///
101a81c2068Sbjorn3     /// Return `Less` if `a` appears in the program before `b`.
102a81c2068Sbjorn3     ///
103a81c2068Sbjorn3     /// This is declared as a generic such that it can be called with `Inst` and `Block` arguments
104a81c2068Sbjorn3     /// directly. Depending on the implementation, there is a good chance performance will be
105a81c2068Sbjorn3     /// 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>,106a81c2068Sbjorn3     pub fn pp_cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
107747ad3c4Slazypassion     where
108a81c2068Sbjorn3         A: Into<ProgramPoint>,
109a81c2068Sbjorn3         B: Into<ProgramPoint>,
110747ad3c4Slazypassion     {
1112c40c267Sbjorn3         let a = a.into();
1122c40c267Sbjorn3         let b = b.into();
1132c40c267Sbjorn3         debug_assert_eq!(self.pp_block(a), self.pp_block(b));
1142c40c267Sbjorn3         let a_seq = match a {
1152c40c267Sbjorn3             ProgramPoint::Block(_block) => 0,
1162c40c267Sbjorn3             ProgramPoint::Inst(inst) => self.insts[inst].seq,
1172c40c267Sbjorn3         };
1182c40c267Sbjorn3         let b_seq = match b {
1192c40c267Sbjorn3             ProgramPoint::Block(_block) => 0,
1202c40c267Sbjorn3             ProgramPoint::Inst(inst) => self.insts[inst].seq,
1212c40c267Sbjorn3         };
122747ad3c4Slazypassion         a_seq.cmp(&b_seq)
123747ad3c4Slazypassion     }
124747ad3c4Slazypassion }
125747ad3c4Slazypassion 
126747ad3c4Slazypassion // Private methods for dealing with sequence numbers.
127747ad3c4Slazypassion impl Layout {
128747ad3c4Slazypassion     /// Assign a valid sequence number to `inst` such that the numbers are still monotonic. This may
129747ad3c4Slazypassion     /// require renumbering.
assign_inst_seq(&mut self, inst: Inst)130747ad3c4Slazypassion     fn assign_inst_seq(&mut self, inst: Inst) {
131747ad3c4Slazypassion         // Get the sequence number immediately before `inst`.
132747ad3c4Slazypassion         let prev_seq = match self.insts[inst].prev.expand() {
133747ad3c4Slazypassion             Some(prev_inst) => self.insts[prev_inst].seq,
1342c40c267Sbjorn3             None => 0,
135747ad3c4Slazypassion         };
136747ad3c4Slazypassion 
137747ad3c4Slazypassion         // Get the sequence number immediately following `inst`.
138747ad3c4Slazypassion         let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() {
139747ad3c4Slazypassion             self.insts[next_inst].seq
140747ad3c4Slazypassion         } else {
141747ad3c4Slazypassion             // There is nothing after `inst`. We can just use a major stride.
142747ad3c4Slazypassion             self.insts[inst].seq = prev_seq + MAJOR_STRIDE;
143747ad3c4Slazypassion             return;
144747ad3c4Slazypassion         };
145747ad3c4Slazypassion 
146747ad3c4Slazypassion         // Check if there is room between these sequence numbers.
147747ad3c4Slazypassion         if let Some(seq) = midpoint(prev_seq, next_seq) {
148747ad3c4Slazypassion             self.insts[inst].seq = seq;
149747ad3c4Slazypassion         } else {
150747ad3c4Slazypassion             // No available integers between `prev_seq` and `next_seq`. We have to renumber.
1512c40c267Sbjorn3             self.renumber_insts(inst, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT);
152747ad3c4Slazypassion         }
153747ad3c4Slazypassion     }
154747ad3c4Slazypassion 
155832666c4SRyan Hunt     /// Renumber instructions starting from `inst` until the end of the block or until numbers catch
156747ad3c4Slazypassion     /// up.
157747ad3c4Slazypassion     ///
1582c40c267Sbjorn3     /// If sequence numbers exceed `limit`, switch to a full block renumbering.
renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber)1592c40c267Sbjorn3     fn renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber) {
160747ad3c4Slazypassion         let mut inst = inst;
161747ad3c4Slazypassion         let mut seq = seq;
162747ad3c4Slazypassion 
163747ad3c4Slazypassion         loop {
164747ad3c4Slazypassion             self.insts[inst].seq = seq;
165747ad3c4Slazypassion 
166747ad3c4Slazypassion             // Next instruction.
167747ad3c4Slazypassion             inst = match self.insts[inst].next.expand() {
1682c40c267Sbjorn3                 None => return,
169747ad3c4Slazypassion                 Some(next) => next,
170747ad3c4Slazypassion             };
171747ad3c4Slazypassion 
172747ad3c4Slazypassion             if seq < self.insts[inst].seq {
173747ad3c4Slazypassion                 // Sequence caught up.
1742c40c267Sbjorn3                 return;
175747ad3c4Slazypassion             }
176747ad3c4Slazypassion 
177747ad3c4Slazypassion             if seq > limit {
178747ad3c4Slazypassion                 // We're pushing too many instructions in front of us.
1792c40c267Sbjorn3                 // Switch to a full block renumbering to make some space.
1802c40c267Sbjorn3                 self.full_block_renumber(
1812c40c267Sbjorn3                     self.inst_block(inst)
1822c40c267Sbjorn3                         .expect("inst must be inserted before assigning an seq"),
1832c40c267Sbjorn3                 );
184747ad3c4Slazypassion                 return;
185747ad3c4Slazypassion             }
186747ad3c4Slazypassion 
187747ad3c4Slazypassion             seq += MINOR_STRIDE;
188747ad3c4Slazypassion         }
189747ad3c4Slazypassion     }
190747ad3c4Slazypassion 
1912c40c267Sbjorn3     /// Renumber all instructions in a block.
192747ad3c4Slazypassion     ///
193747ad3c4Slazypassion     /// This doesn't affect the position of anything, but it gives more room in the internal
194747ad3c4Slazypassion     /// sequence numbers for inserting instructions later.
full_block_renumber(&mut self, block: Block)19549bab6dbSbjorn3     fn full_block_renumber(&mut self, block: Block) {
196747ad3c4Slazypassion         let _tt = timing::layout_renumber();
1972c40c267Sbjorn3         // Avoid 0 as this is reserved for the program point indicating the block itself
1982c40c267Sbjorn3         let mut seq = MAJOR_STRIDE;
199832666c4SRyan Hunt         let mut next_inst = self.blocks[block].first_inst.expand();
200747ad3c4Slazypassion         while let Some(inst) = next_inst {
201747ad3c4Slazypassion             self.insts[inst].seq = seq;
202747ad3c4Slazypassion             seq += MAJOR_STRIDE;
203747ad3c4Slazypassion             next_inst = self.insts[inst].next.expand();
204747ad3c4Slazypassion         }
2052c40c267Sbjorn3 
2068d022434SBenjamin Bouvier         trace!("Renumbered {} program points", seq / MAJOR_STRIDE);
207747ad3c4Slazypassion     }
208747ad3c4Slazypassion }
209747ad3c4Slazypassion 
210832666c4SRyan Hunt /// Methods for laying out blocks.
211747ad3c4Slazypassion ///
212832666c4SRyan Hunt /// An unknown block starts out as *not inserted* in the block layout. The layout is a linear order of
21307f335dcSRyan Hunt /// inserted blocks. Once a block has been inserted in the layout, instructions can be added. A block
214747ad3c4Slazypassion /// can only be removed from the layout when it is empty.
215747ad3c4Slazypassion ///
216832666c4SRyan Hunt /// Since every block must end with a terminator instruction which cannot fall through, the layout of
217832666c4SRyan Hunt /// blocks do not affect the semantics of the program.
218747ad3c4Slazypassion ///
219747ad3c4Slazypassion impl Layout {
220832666c4SRyan Hunt     /// Is `block` currently part of the layout?
is_block_inserted(&self, block: Block) -> bool221832666c4SRyan Hunt     pub fn is_block_inserted(&self, block: Block) -> bool {
222832666c4SRyan Hunt         Some(block) == self.first_block || self.blocks[block].prev.is_some()
223747ad3c4Slazypassion     }
224747ad3c4Slazypassion 
225832666c4SRyan Hunt     /// Insert `block` as the last block in the layout.
append_block(&mut self, block: Block)226832666c4SRyan Hunt     pub fn append_block(&mut self, block: Block) {
227747ad3c4Slazypassion         debug_assert!(
228832666c4SRyan Hunt             !self.is_block_inserted(block),
229832666c4SRyan Hunt             "Cannot append block that is already in the layout"
230747ad3c4Slazypassion         );
231747ad3c4Slazypassion         {
232832666c4SRyan Hunt             let node = &mut self.blocks[block];
233747ad3c4Slazypassion             debug_assert!(node.first_inst.is_none() && node.last_inst.is_none());
234832666c4SRyan Hunt             node.prev = self.last_block.into();
235747ad3c4Slazypassion             node.next = None.into();
236747ad3c4Slazypassion         }
237832666c4SRyan Hunt         if let Some(last) = self.last_block {
238832666c4SRyan Hunt             self.blocks[last].next = block.into();
239747ad3c4Slazypassion         } else {
240832666c4SRyan Hunt             self.first_block = Some(block);
241747ad3c4Slazypassion         }
242832666c4SRyan Hunt         self.last_block = Some(block);
243747ad3c4Slazypassion     }
244747ad3c4Slazypassion 
245832666c4SRyan Hunt     /// Insert `block` in the layout before the existing block `before`.
insert_block(&mut self, block: Block, before: Block)246832666c4SRyan Hunt     pub fn insert_block(&mut self, block: Block, before: Block) {
247747ad3c4Slazypassion         debug_assert!(
248832666c4SRyan Hunt             !self.is_block_inserted(block),
249832666c4SRyan Hunt             "Cannot insert block that is already in the layout"
250747ad3c4Slazypassion         );
251747ad3c4Slazypassion         debug_assert!(
252832666c4SRyan Hunt             self.is_block_inserted(before),
253832666c4SRyan Hunt             "block Insertion point not in the layout"
254747ad3c4Slazypassion         );
255832666c4SRyan Hunt         let after = self.blocks[before].prev;
256747ad3c4Slazypassion         {
257832666c4SRyan Hunt             let node = &mut self.blocks[block];
258747ad3c4Slazypassion             node.next = before.into();
259747ad3c4Slazypassion             node.prev = after;
260747ad3c4Slazypassion         }
261832666c4SRyan Hunt         self.blocks[before].prev = block.into();
262747ad3c4Slazypassion         match after.expand() {
263832666c4SRyan Hunt             None => self.first_block = Some(block),
264832666c4SRyan Hunt             Some(a) => self.blocks[a].next = block.into(),
265747ad3c4Slazypassion         }
266747ad3c4Slazypassion     }
267747ad3c4Slazypassion 
268832666c4SRyan Hunt     /// Insert `block` in the layout *after* the existing block `after`.
insert_block_after(&mut self, block: Block, after: Block)269832666c4SRyan Hunt     pub fn insert_block_after(&mut self, block: Block, after: Block) {
270747ad3c4Slazypassion         debug_assert!(
271832666c4SRyan Hunt             !self.is_block_inserted(block),
272832666c4SRyan Hunt             "Cannot insert block that is already in the layout"
273747ad3c4Slazypassion         );
274747ad3c4Slazypassion         debug_assert!(
275832666c4SRyan Hunt             self.is_block_inserted(after),
276832666c4SRyan Hunt             "block Insertion point not in the layout"
277747ad3c4Slazypassion         );
278832666c4SRyan Hunt         let before = self.blocks[after].next;
279747ad3c4Slazypassion         {
280832666c4SRyan Hunt             let node = &mut self.blocks[block];
281747ad3c4Slazypassion             node.next = before;
282747ad3c4Slazypassion             node.prev = after.into();
283747ad3c4Slazypassion         }
284832666c4SRyan Hunt         self.blocks[after].next = block.into();
285747ad3c4Slazypassion         match before.expand() {
286832666c4SRyan Hunt             None => self.last_block = Some(block),
287832666c4SRyan Hunt             Some(b) => self.blocks[b].prev = block.into(),
288747ad3c4Slazypassion         }
289747ad3c4Slazypassion     }
290747ad3c4Slazypassion 
291832666c4SRyan Hunt     /// Remove `block` from the layout.
remove_block(&mut self, block: Block)292832666c4SRyan Hunt     pub fn remove_block(&mut self, block: Block) {
293832666c4SRyan Hunt         debug_assert!(self.is_block_inserted(block), "block not in the layout");
294832666c4SRyan Hunt         debug_assert!(self.first_inst(block).is_none(), "block must be empty.");
295747ad3c4Slazypassion 
296832666c4SRyan Hunt         // Clear the `block` node and extract links.
297747ad3c4Slazypassion         let prev;
298747ad3c4Slazypassion         let next;
299747ad3c4Slazypassion         {
300832666c4SRyan Hunt             let n = &mut self.blocks[block];
301747ad3c4Slazypassion             prev = n.prev;
302747ad3c4Slazypassion             next = n.next;
303747ad3c4Slazypassion             n.prev = None.into();
304747ad3c4Slazypassion             n.next = None.into();
305747ad3c4Slazypassion         }
306832666c4SRyan Hunt         // Fix up links to `block`.
307747ad3c4Slazypassion         match prev.expand() {
308832666c4SRyan Hunt             None => self.first_block = next.expand(),
309832666c4SRyan Hunt             Some(p) => self.blocks[p].next = next,
310747ad3c4Slazypassion         }
311747ad3c4Slazypassion         match next.expand() {
312832666c4SRyan Hunt             None => self.last_block = prev.expand(),
313832666c4SRyan Hunt             Some(n) => self.blocks[n].prev = prev,
314747ad3c4Slazypassion         }
315747ad3c4Slazypassion     }
316747ad3c4Slazypassion 
317832666c4SRyan Hunt     /// Return an iterator over all blocks in layout order.
blocks(&self) -> Blocks<'_>3188a42768fSAlex Crichton     pub fn blocks(&self) -> Blocks<'_> {
319832666c4SRyan Hunt         Blocks {
320747ad3c4Slazypassion             layout: self,
321832666c4SRyan Hunt             next: self.first_block,
322747ad3c4Slazypassion         }
323747ad3c4Slazypassion     }
324747ad3c4Slazypassion 
325747ad3c4Slazypassion     /// Get the function's entry block.
326832666c4SRyan Hunt     /// This is simply the first block in the layout order.
entry_block(&self) -> Option<Block>327832666c4SRyan Hunt     pub fn entry_block(&self) -> Option<Block> {
328832666c4SRyan Hunt         self.first_block
329747ad3c4Slazypassion     }
330747ad3c4Slazypassion 
331832666c4SRyan Hunt     /// Get the last block in the layout.
last_block(&self) -> Option<Block>332832666c4SRyan Hunt     pub fn last_block(&self) -> Option<Block> {
333832666c4SRyan Hunt         self.last_block
334747ad3c4Slazypassion     }
335747ad3c4Slazypassion 
336832666c4SRyan Hunt     /// Get the block preceding `block` in the layout order.
prev_block(&self, block: Block) -> Option<Block>337832666c4SRyan Hunt     pub fn prev_block(&self, block: Block) -> Option<Block> {
338832666c4SRyan Hunt         self.blocks[block].prev.expand()
339747ad3c4Slazypassion     }
340747ad3c4Slazypassion 
341832666c4SRyan Hunt     /// Get the block following `block` in the layout order.
next_block(&self, block: Block) -> Option<Block>342832666c4SRyan Hunt     pub fn next_block(&self, block: Block) -> Option<Block> {
343832666c4SRyan Hunt         self.blocks[block].next.expand()
344747ad3c4Slazypassion     }
345f489b838SChris Fallin 
346f489b838SChris Fallin     /// Mark a block as "cold".
347f489b838SChris Fallin     ///
348f489b838SChris Fallin     /// This will try to move it out of the ordinary path of execution
349f489b838SChris Fallin     /// when lowered to machine code.
set_cold(&mut self, block: Block)350f489b838SChris Fallin     pub fn set_cold(&mut self, block: Block) {
351f489b838SChris Fallin         self.blocks[block].cold = true;
352f489b838SChris Fallin     }
353f489b838SChris Fallin 
354f489b838SChris Fallin     /// Is the given block cold?
is_cold(&self, block: Block) -> bool355f489b838SChris Fallin     pub fn is_cold(&self, block: Block) -> bool {
356f489b838SChris Fallin         self.blocks[block].cold
357f489b838SChris Fallin     }
358747ad3c4Slazypassion }
359747ad3c4Slazypassion 
36043d4f0b9SBenjamin Bouvier /// A single node in the linked-list of blocks.
3614053ae9eSkevaundray // **Note:** Whenever you add new fields here, don't forget to update the custom serializer for `Layout` too.
3628a9b1a90SBenjamin Bouvier #[derive(Clone, Debug, Default, PartialEq, Hash)]
363832666c4SRyan Hunt struct BlockNode {
364832666c4SRyan Hunt     prev: PackedOption<Block>,
365832666c4SRyan Hunt     next: PackedOption<Block>,
366747ad3c4Slazypassion     first_inst: PackedOption<Inst>,
367747ad3c4Slazypassion     last_inst: PackedOption<Inst>,
368f489b838SChris Fallin     cold: bool,
369747ad3c4Slazypassion }
370747ad3c4Slazypassion 
37128ede835STeymour Aldridge /// Iterate over blocks in layout order. See [crate::ir::layout::Layout::blocks].
372832666c4SRyan Hunt pub struct Blocks<'f> {
373747ad3c4Slazypassion     layout: &'f Layout,
374832666c4SRyan Hunt     next: Option<Block>,
375747ad3c4Slazypassion }
376747ad3c4Slazypassion 
377832666c4SRyan Hunt impl<'f> Iterator for Blocks<'f> {
378832666c4SRyan Hunt     type Item = Block;
379747ad3c4Slazypassion 
next(&mut self) -> Option<Block>380832666c4SRyan Hunt     fn next(&mut self) -> Option<Block> {
381747ad3c4Slazypassion         match self.next {
382832666c4SRyan Hunt             Some(block) => {
383832666c4SRyan Hunt                 self.next = self.layout.next_block(block);
384832666c4SRyan Hunt                 Some(block)
385747ad3c4Slazypassion             }
386747ad3c4Slazypassion             None => None,
387747ad3c4Slazypassion         }
388747ad3c4Slazypassion     }
389747ad3c4Slazypassion }
390747ad3c4Slazypassion 
391747ad3c4Slazypassion /// Use a layout reference in a for loop.
392747ad3c4Slazypassion impl<'f> IntoIterator for &'f Layout {
393832666c4SRyan Hunt     type Item = Block;
394832666c4SRyan Hunt     type IntoIter = Blocks<'f>;
395747ad3c4Slazypassion 
into_iter(self) -> Blocks<'f>396832666c4SRyan Hunt     fn into_iter(self) -> Blocks<'f> {
397832666c4SRyan Hunt         self.blocks()
398747ad3c4Slazypassion     }
399747ad3c4Slazypassion }
400747ad3c4Slazypassion 
401747ad3c4Slazypassion /// Methods for arranging instructions.
402747ad3c4Slazypassion ///
403747ad3c4Slazypassion /// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into
40407f335dcSRyan Hunt /// a block at a given position.
405747ad3c4Slazypassion impl Layout {
406832666c4SRyan Hunt     /// Get the block containing `inst`, or `None` if `inst` is not inserted in the layout.
inst_block(&self, inst: Inst) -> Option<Block>407832666c4SRyan Hunt     pub fn inst_block(&self, inst: Inst) -> Option<Block> {
408832666c4SRyan Hunt         self.insts[inst].block.into()
409747ad3c4Slazypassion     }
410747ad3c4Slazypassion 
411832666c4SRyan Hunt     /// Get the block containing the program point `pp`. Panic if `pp` is not in the layout.
pp_block(&self, pp: ProgramPoint) -> Block412a81c2068Sbjorn3     pub fn pp_block(&self, pp: ProgramPoint) -> Block {
413a81c2068Sbjorn3         match pp {
414a81c2068Sbjorn3             ProgramPoint::Block(block) => block,
415a81c2068Sbjorn3             ProgramPoint::Inst(inst) => self.inst_block(inst).expect("Program point not in layout"),
416747ad3c4Slazypassion         }
417747ad3c4Slazypassion     }
418747ad3c4Slazypassion 
419832666c4SRyan Hunt     /// Append `inst` to the end of `block`.
append_inst(&mut self, inst: Inst, block: Block)420832666c4SRyan Hunt     pub fn append_inst(&mut self, inst: Inst, block: Block) {
421832666c4SRyan Hunt         debug_assert_eq!(self.inst_block(inst), None);
422747ad3c4Slazypassion         debug_assert!(
423832666c4SRyan Hunt             self.is_block_inserted(block),
424832666c4SRyan Hunt             "Cannot append instructions to block not in layout"
425747ad3c4Slazypassion         );
426747ad3c4Slazypassion         {
427832666c4SRyan Hunt             let block_node = &mut self.blocks[block];
428747ad3c4Slazypassion             {
429747ad3c4Slazypassion                 let inst_node = &mut self.insts[inst];
430832666c4SRyan Hunt                 inst_node.block = block.into();
431832666c4SRyan Hunt                 inst_node.prev = block_node.last_inst;
432747ad3c4Slazypassion                 debug_assert!(inst_node.next.is_none());
433747ad3c4Slazypassion             }
434832666c4SRyan Hunt             if block_node.first_inst.is_none() {
435832666c4SRyan Hunt                 block_node.first_inst = inst.into();
436747ad3c4Slazypassion             } else {
437832666c4SRyan Hunt                 self.insts[block_node.last_inst.unwrap()].next = inst.into();
438747ad3c4Slazypassion             }
439832666c4SRyan Hunt             block_node.last_inst = inst.into();
440747ad3c4Slazypassion         }
441747ad3c4Slazypassion         self.assign_inst_seq(inst);
442747ad3c4Slazypassion     }
443747ad3c4Slazypassion 
44407f335dcSRyan Hunt     /// Fetch a block's first instruction.
first_inst(&self, block: Block) -> Option<Inst>445832666c4SRyan Hunt     pub fn first_inst(&self, block: Block) -> Option<Inst> {
446832666c4SRyan Hunt         self.blocks[block].first_inst.into()
447747ad3c4Slazypassion     }
448747ad3c4Slazypassion 
44907f335dcSRyan Hunt     /// Fetch a block's last instruction.
last_inst(&self, block: Block) -> Option<Inst>450832666c4SRyan Hunt     pub fn last_inst(&self, block: Block) -> Option<Inst> {
451832666c4SRyan Hunt         self.blocks[block].last_inst.into()
452747ad3c4Slazypassion     }
453747ad3c4Slazypassion 
454747ad3c4Slazypassion     /// Fetch the instruction following `inst`.
next_inst(&self, inst: Inst) -> Option<Inst>455747ad3c4Slazypassion     pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
456747ad3c4Slazypassion         self.insts[inst].next.expand()
457747ad3c4Slazypassion     }
458747ad3c4Slazypassion 
459747ad3c4Slazypassion     /// Fetch the instruction preceding `inst`.
prev_inst(&self, inst: Inst) -> Option<Inst>460747ad3c4Slazypassion     pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
461747ad3c4Slazypassion         self.insts[inst].prev.expand()
462747ad3c4Slazypassion     }
463747ad3c4Slazypassion 
464832666c4SRyan Hunt     /// Insert `inst` before the instruction `before` in the same block.
insert_inst(&mut self, inst: Inst, before: Inst)465747ad3c4Slazypassion     pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
466832666c4SRyan Hunt         debug_assert_eq!(self.inst_block(inst), None);
467832666c4SRyan Hunt         let block = self
468832666c4SRyan Hunt             .inst_block(before)
469747ad3c4Slazypassion             .expect("Instruction before insertion point not in the layout");
470747ad3c4Slazypassion         let after = self.insts[before].prev;
471747ad3c4Slazypassion         {
472747ad3c4Slazypassion             let inst_node = &mut self.insts[inst];
473832666c4SRyan Hunt             inst_node.block = block.into();
474747ad3c4Slazypassion             inst_node.next = before.into();
475747ad3c4Slazypassion             inst_node.prev = after;
476747ad3c4Slazypassion         }
477747ad3c4Slazypassion         self.insts[before].prev = inst.into();
478747ad3c4Slazypassion         match after.expand() {
479832666c4SRyan Hunt             None => self.blocks[block].first_inst = inst.into(),
480747ad3c4Slazypassion             Some(a) => self.insts[a].next = inst.into(),
481747ad3c4Slazypassion         }
482747ad3c4Slazypassion         self.assign_inst_seq(inst);
483747ad3c4Slazypassion     }
484747ad3c4Slazypassion 
485747ad3c4Slazypassion     /// Remove `inst` from the layout.
remove_inst(&mut self, inst: Inst)486747ad3c4Slazypassion     pub fn remove_inst(&mut self, inst: Inst) {
487832666c4SRyan Hunt         let block = self.inst_block(inst).expect("Instruction already removed.");
488747ad3c4Slazypassion         // Clear the `inst` node and extract links.
489747ad3c4Slazypassion         let prev;
490747ad3c4Slazypassion         let next;
491747ad3c4Slazypassion         {
492747ad3c4Slazypassion             let n = &mut self.insts[inst];
493747ad3c4Slazypassion             prev = n.prev;
494747ad3c4Slazypassion             next = n.next;
495832666c4SRyan Hunt             n.block = None.into();
496747ad3c4Slazypassion             n.prev = None.into();
497747ad3c4Slazypassion             n.next = None.into();
498747ad3c4Slazypassion         }
499747ad3c4Slazypassion         // Fix up links to `inst`.
500747ad3c4Slazypassion         match prev.expand() {
501832666c4SRyan Hunt             None => self.blocks[block].first_inst = next,
502747ad3c4Slazypassion             Some(p) => self.insts[p].next = next,
503747ad3c4Slazypassion         }
504747ad3c4Slazypassion         match next.expand() {
505832666c4SRyan Hunt             None => self.blocks[block].last_inst = prev,
506747ad3c4Slazypassion             Some(n) => self.insts[n].prev = prev,
507747ad3c4Slazypassion         }
508747ad3c4Slazypassion     }
509747ad3c4Slazypassion 
510832666c4SRyan Hunt     /// Iterate over the instructions in `block` in layout order.
block_insts(&self, block: Block) -> Insts<'_>5118a42768fSAlex Crichton     pub fn block_insts(&self, block: Block) -> Insts<'_> {
512747ad3c4Slazypassion         Insts {
513747ad3c4Slazypassion             layout: self,
514832666c4SRyan Hunt             head: self.blocks[block].first_inst.into(),
515832666c4SRyan Hunt             tail: self.blocks[block].last_inst.into(),
516747ad3c4Slazypassion         }
517747ad3c4Slazypassion     }
518747ad3c4Slazypassion 
519*a80dd80dSNick Fitzgerald     /// Does the given block contain exactly one instruction?
block_contains_exactly_one_inst(&self, block: Block) -> bool520*a80dd80dSNick Fitzgerald     pub fn block_contains_exactly_one_inst(&self, block: Block) -> bool {
521*a80dd80dSNick Fitzgerald         let block = &self.blocks[block];
522*a80dd80dSNick Fitzgerald         block.first_inst.is_some() && block.first_inst == block.last_inst
523*a80dd80dSNick Fitzgerald     }
524*a80dd80dSNick Fitzgerald 
525832666c4SRyan Hunt     /// Split the block containing `before` in two.
526747ad3c4Slazypassion     ///
527832666c4SRyan Hunt     /// Insert `new_block` after the old block and move `before` and the following instructions to
528832666c4SRyan Hunt     /// `new_block`:
529747ad3c4Slazypassion     ///
530747ad3c4Slazypassion     /// ```text
531832666c4SRyan Hunt     /// old_block:
532747ad3c4Slazypassion     ///     i1
533747ad3c4Slazypassion     ///     i2
534747ad3c4Slazypassion     ///     i3 << before
535747ad3c4Slazypassion     ///     i4
536747ad3c4Slazypassion     /// ```
537747ad3c4Slazypassion     /// becomes:
538747ad3c4Slazypassion     ///
539747ad3c4Slazypassion     /// ```text
540832666c4SRyan Hunt     /// old_block:
541747ad3c4Slazypassion     ///     i1
542747ad3c4Slazypassion     ///     i2
543832666c4SRyan Hunt     /// new_block:
544747ad3c4Slazypassion     ///     i3 << before
545747ad3c4Slazypassion     ///     i4
546747ad3c4Slazypassion     /// ```
split_block(&mut self, new_block: Block, before: Inst)547832666c4SRyan Hunt     pub fn split_block(&mut self, new_block: Block, before: Inst) {
548832666c4SRyan Hunt         let old_block = self
549832666c4SRyan Hunt             .inst_block(before)
550747ad3c4Slazypassion             .expect("The `before` instruction must be in the layout");
551832666c4SRyan Hunt         debug_assert!(!self.is_block_inserted(new_block));
552747ad3c4Slazypassion 
553832666c4SRyan Hunt         // Insert new_block after old_block.
554832666c4SRyan Hunt         let next_block = self.blocks[old_block].next;
555832666c4SRyan Hunt         let last_inst = self.blocks[old_block].last_inst;
556747ad3c4Slazypassion         {
557832666c4SRyan Hunt             let node = &mut self.blocks[new_block];
558832666c4SRyan Hunt             node.prev = old_block.into();
559832666c4SRyan Hunt             node.next = next_block;
560747ad3c4Slazypassion             node.first_inst = before.into();
561747ad3c4Slazypassion             node.last_inst = last_inst;
562747ad3c4Slazypassion         }
563832666c4SRyan Hunt         self.blocks[old_block].next = new_block.into();
564747ad3c4Slazypassion 
565747ad3c4Slazypassion         // Fix backwards link.
566832666c4SRyan Hunt         if Some(old_block) == self.last_block {
567832666c4SRyan Hunt             self.last_block = Some(new_block);
568747ad3c4Slazypassion         } else {
569832666c4SRyan Hunt             self.blocks[next_block.unwrap()].prev = new_block.into();
570747ad3c4Slazypassion         }
571747ad3c4Slazypassion 
572747ad3c4Slazypassion         // Disconnect the instruction links.
573747ad3c4Slazypassion         let prev_inst = self.insts[before].prev;
574747ad3c4Slazypassion         self.insts[before].prev = None.into();
575832666c4SRyan Hunt         self.blocks[old_block].last_inst = prev_inst;
576747ad3c4Slazypassion         match prev_inst.expand() {
577832666c4SRyan Hunt             None => self.blocks[old_block].first_inst = None.into(),
578747ad3c4Slazypassion             Some(pi) => self.insts[pi].next = None.into(),
579747ad3c4Slazypassion         }
580747ad3c4Slazypassion 
581832666c4SRyan Hunt         // Fix the instruction -> block pointers.
582747ad3c4Slazypassion         let mut opt_i = Some(before);
583747ad3c4Slazypassion         while let Some(i) = opt_i {
584832666c4SRyan Hunt             debug_assert_eq!(self.insts[i].block.expand(), Some(old_block));
585832666c4SRyan Hunt             self.insts[i].block = new_block.into();
586747ad3c4Slazypassion             opt_i = self.insts[i].next.into();
587747ad3c4Slazypassion         }
588747ad3c4Slazypassion     }
589747ad3c4Slazypassion }
590747ad3c4Slazypassion 
59149bab6dbSbjorn3 #[derive(Clone, Debug, Default)]
592747ad3c4Slazypassion struct InstNode {
593832666c4SRyan Hunt     /// The Block containing this instruction, or `None` if the instruction is not yet inserted.
594832666c4SRyan Hunt     block: PackedOption<Block>,
595747ad3c4Slazypassion     prev: PackedOption<Inst>,
596747ad3c4Slazypassion     next: PackedOption<Inst>,
597747ad3c4Slazypassion     seq: SequenceNumber,
598747ad3c4Slazypassion }
599747ad3c4Slazypassion 
60049bab6dbSbjorn3 impl PartialEq for InstNode {
eq(&self, other: &Self) -> bool60149bab6dbSbjorn3     fn eq(&self, other: &Self) -> bool {
60249bab6dbSbjorn3         // Ignore the sequence number as it is an optimization used by pp_cmp and may be different
60349bab6dbSbjorn3         // even for equivalent layouts.
60449bab6dbSbjorn3         self.block == other.block && self.prev == other.prev && self.next == other.next
60549bab6dbSbjorn3     }
60649bab6dbSbjorn3 }
60749bab6dbSbjorn3 
60849bab6dbSbjorn3 impl core::hash::Hash for InstNode {
hash<H: core::hash::Hasher>(&self, state: &mut H)60949bab6dbSbjorn3     fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
61049bab6dbSbjorn3         // Ignore the sequence number as it is an optimization used by pp_cmp and may be different
61149bab6dbSbjorn3         // even for equivalent layouts.
61249bab6dbSbjorn3         self.block.hash(state);
61349bab6dbSbjorn3         self.prev.hash(state);
61449bab6dbSbjorn3         self.next.hash(state);
61549bab6dbSbjorn3     }
61649bab6dbSbjorn3 }
61749bab6dbSbjorn3 
61807f335dcSRyan Hunt /// Iterate over instructions in a block in layout order. See `Layout::block_insts()`.
619747ad3c4Slazypassion pub struct Insts<'f> {
620747ad3c4Slazypassion     layout: &'f Layout,
621747ad3c4Slazypassion     head: Option<Inst>,
622747ad3c4Slazypassion     tail: Option<Inst>,
623747ad3c4Slazypassion }
624747ad3c4Slazypassion 
625747ad3c4Slazypassion impl<'f> Iterator for Insts<'f> {
626747ad3c4Slazypassion     type Item = Inst;
627747ad3c4Slazypassion 
next(&mut self) -> Option<Inst>628747ad3c4Slazypassion     fn next(&mut self) -> Option<Inst> {
629747ad3c4Slazypassion         let rval = self.head;
630747ad3c4Slazypassion         if let Some(inst) = rval {
631747ad3c4Slazypassion             if self.head == self.tail {
632747ad3c4Slazypassion                 self.head = None;
633747ad3c4Slazypassion                 self.tail = None;
634747ad3c4Slazypassion             } else {
635747ad3c4Slazypassion                 self.head = self.layout.insts[inst].next.into();
636747ad3c4Slazypassion             }
637747ad3c4Slazypassion         }
638747ad3c4Slazypassion         rval
639747ad3c4Slazypassion     }
640747ad3c4Slazypassion }
641747ad3c4Slazypassion 
642747ad3c4Slazypassion impl<'f> DoubleEndedIterator for Insts<'f> {
next_back(&mut self) -> Option<Inst>643747ad3c4Slazypassion     fn next_back(&mut self) -> Option<Inst> {
644747ad3c4Slazypassion         let rval = self.tail;
645747ad3c4Slazypassion         if let Some(inst) = rval {
646747ad3c4Slazypassion             if self.head == self.tail {
647747ad3c4Slazypassion                 self.head = None;
648747ad3c4Slazypassion                 self.tail = None;
649747ad3c4Slazypassion             } else {
650747ad3c4Slazypassion                 self.tail = self.layout.insts[inst].prev.into();
651747ad3c4Slazypassion             }
652747ad3c4Slazypassion         }
653747ad3c4Slazypassion         rval
654747ad3c4Slazypassion     }
655747ad3c4Slazypassion }
656747ad3c4Slazypassion 
657720da205Sbjorn3 /// A custom serialize and deserialize implementation for [`Layout`].
658720da205Sbjorn3 ///
659720da205Sbjorn3 /// This doesn't use a derived implementation as [`Layout`] is a manual implementation of a linked
660720da205Sbjorn3 /// list. Storing it directly as a regular list saves a lot of space.
661720da205Sbjorn3 ///
662720da205Sbjorn3 /// The following format is used. (notated in EBNF form)
663720da205Sbjorn3 ///
664720da205Sbjorn3 /// ```plain
665720da205Sbjorn3 /// data = block_data * ;
66643d4f0b9SBenjamin Bouvier /// block_data = "block_id" , "cold" , "inst_count" , ( "inst_id" * ) ;
667720da205Sbjorn3 /// ```
6682fc964eaSbjorn3 #[cfg(feature = "enable-serde")]
6692fc964eaSbjorn3 mod serde {
6702fc964eaSbjorn3     use ::serde::de::{Deserializer, Error, SeqAccess, Visitor};
6712fc964eaSbjorn3     use ::serde::ser::{SerializeSeq, Serializer};
6722fc964eaSbjorn3     use ::serde::{Deserialize, Serialize};
6732fc964eaSbjorn3     use core::fmt;
6742fc964eaSbjorn3     use core::marker::PhantomData;
6752fc964eaSbjorn3 
6762fc964eaSbjorn3     use super::*;
6772fc964eaSbjorn3 
6782fc964eaSbjorn3     impl Serialize for Layout {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,6792fc964eaSbjorn3         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
6802fc964eaSbjorn3         where
6812fc964eaSbjorn3             S: Serializer,
6822fc964eaSbjorn3         {
68343d4f0b9SBenjamin Bouvier             let size = self.blocks().count() * 3
6842fc964eaSbjorn3                 + self
6852fc964eaSbjorn3                     .blocks()
6862fc964eaSbjorn3                     .map(|block| self.block_insts(block).count())
6872fc964eaSbjorn3                     .sum::<usize>();
6882fc964eaSbjorn3             let mut seq = serializer.serialize_seq(Some(size))?;
6892fc964eaSbjorn3             for block in self.blocks() {
6902fc964eaSbjorn3                 seq.serialize_element(&block)?;
69143d4f0b9SBenjamin Bouvier                 seq.serialize_element(&self.blocks[block].cold)?;
6922fc964eaSbjorn3                 seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?;
6932fc964eaSbjorn3                 for inst in self.block_insts(block) {
6942fc964eaSbjorn3                     seq.serialize_element(&inst)?;
6952fc964eaSbjorn3                 }
6962fc964eaSbjorn3             }
6972fc964eaSbjorn3             seq.end()
6982fc964eaSbjorn3         }
6992fc964eaSbjorn3     }
7002fc964eaSbjorn3 
7012fc964eaSbjorn3     impl<'de> Deserialize<'de> for Layout {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,7022fc964eaSbjorn3         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
7032fc964eaSbjorn3         where
7042fc964eaSbjorn3             D: Deserializer<'de>,
7052fc964eaSbjorn3         {
7062fc964eaSbjorn3             deserializer.deserialize_seq(LayoutVisitor {
7072fc964eaSbjorn3                 marker: PhantomData,
7082fc964eaSbjorn3             })
7092fc964eaSbjorn3         }
7102fc964eaSbjorn3     }
7112fc964eaSbjorn3 
7122fc964eaSbjorn3     struct LayoutVisitor {
7132fc964eaSbjorn3         marker: PhantomData<fn() -> Layout>,
7142fc964eaSbjorn3     }
7152fc964eaSbjorn3 
7162fc964eaSbjorn3     impl<'de> Visitor<'de> for LayoutVisitor {
7172fc964eaSbjorn3         type Value = Layout;
7182fc964eaSbjorn3 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result7192fc964eaSbjorn3         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
7202fc964eaSbjorn3             write!(formatter, "a `cranelift_codegen::ir::Layout`")
7212fc964eaSbjorn3         }
7222fc964eaSbjorn3 
visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error> where M: SeqAccess<'de>,7232fc964eaSbjorn3         fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
7242fc964eaSbjorn3         where
7252fc964eaSbjorn3             M: SeqAccess<'de>,
7262fc964eaSbjorn3         {
7272fc964eaSbjorn3             let mut layout = Layout::new();
7282fc964eaSbjorn3 
7292fc964eaSbjorn3             while let Some(block) = access.next_element::<Block>()? {
7302fc964eaSbjorn3                 layout.append_block(block);
7312fc964eaSbjorn3 
73243d4f0b9SBenjamin Bouvier                 let cold = access
73343d4f0b9SBenjamin Bouvier                     .next_element::<bool>()?
73443d4f0b9SBenjamin Bouvier                     .ok_or_else(|| Error::missing_field("cold"))?;
73543d4f0b9SBenjamin Bouvier                 layout.blocks[block].cold = cold;
73643d4f0b9SBenjamin Bouvier 
7372fc964eaSbjorn3                 let count = access
7382fc964eaSbjorn3                     .next_element::<u32>()?
7392fc964eaSbjorn3                     .ok_or_else(|| Error::missing_field("count"))?;
74043d4f0b9SBenjamin Bouvier 
7412fc964eaSbjorn3                 for _ in 0..count {
7422fc964eaSbjorn3                     let inst = access
7432fc964eaSbjorn3                         .next_element::<Inst>()?
7442fc964eaSbjorn3                         .ok_or_else(|| Error::missing_field("inst"))?;
7452fc964eaSbjorn3                     layout.append_inst(inst, block);
7462fc964eaSbjorn3                 }
7472fc964eaSbjorn3             }
7482fc964eaSbjorn3 
7492fc964eaSbjorn3             Ok(layout)
7502fc964eaSbjorn3         }
7512fc964eaSbjorn3     }
7522fc964eaSbjorn3 }
7532fc964eaSbjorn3 
754747ad3c4Slazypassion #[cfg(test)]
755747ad3c4Slazypassion mod tests {
756ec3b2d22SNick Fitzgerald     use super::*;
757747ad3c4Slazypassion     use crate::cursor::{Cursor, CursorPosition};
758747ad3c4Slazypassion     use crate::entity::EntityRef;
759a81c2068Sbjorn3     use crate::ir::{Block, Inst, SourceLoc};
76010e226f9Sbjorn3     use alloc::vec::Vec;
761bb8fa40eSbjorn3     use core::cmp::Ordering;
762747ad3c4Slazypassion 
763ec3b2d22SNick Fitzgerald     #[test]
test_midpoint()764ec3b2d22SNick Fitzgerald     fn test_midpoint() {
765ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(0, 1), None);
766ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(0, 2), Some(1));
767ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(0, 3), Some(1));
768ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(0, 4), Some(2));
769ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(1, 4), Some(2));
770ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(2, 4), Some(3));
771ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(3, 4), None);
772ec3b2d22SNick Fitzgerald         assert_eq!(midpoint(3, 4), None);
773ec3b2d22SNick Fitzgerald     }
774ec3b2d22SNick Fitzgerald 
775747ad3c4Slazypassion     struct LayoutCursor<'f> {
776747ad3c4Slazypassion         /// Borrowed function layout. Public so it can be re-borrowed from this cursor.
777747ad3c4Slazypassion         pub layout: &'f mut Layout,
778747ad3c4Slazypassion         pos: CursorPosition,
779747ad3c4Slazypassion     }
780747ad3c4Slazypassion 
781747ad3c4Slazypassion     impl<'f> Cursor for LayoutCursor<'f> {
position(&self) -> CursorPosition782747ad3c4Slazypassion         fn position(&self) -> CursorPosition {
783747ad3c4Slazypassion             self.pos
784747ad3c4Slazypassion         }
785747ad3c4Slazypassion 
set_position(&mut self, pos: CursorPosition)786747ad3c4Slazypassion         fn set_position(&mut self, pos: CursorPosition) {
787747ad3c4Slazypassion             self.pos = pos;
788747ad3c4Slazypassion         }
789747ad3c4Slazypassion 
srcloc(&self) -> SourceLoc790747ad3c4Slazypassion         fn srcloc(&self) -> SourceLoc {
791747ad3c4Slazypassion             unimplemented!()
792747ad3c4Slazypassion         }
793747ad3c4Slazypassion 
set_srcloc(&mut self, _srcloc: SourceLoc)794747ad3c4Slazypassion         fn set_srcloc(&mut self, _srcloc: SourceLoc) {
795747ad3c4Slazypassion             unimplemented!()
796747ad3c4Slazypassion         }
797747ad3c4Slazypassion 
layout(&self) -> &Layout798747ad3c4Slazypassion         fn layout(&self) -> &Layout {
799747ad3c4Slazypassion             self.layout
800747ad3c4Slazypassion         }
801747ad3c4Slazypassion 
layout_mut(&mut self) -> &mut Layout802747ad3c4Slazypassion         fn layout_mut(&mut self) -> &mut Layout {
803747ad3c4Slazypassion             self.layout
804747ad3c4Slazypassion         }
805747ad3c4Slazypassion     }
806747ad3c4Slazypassion 
807747ad3c4Slazypassion     impl<'f> LayoutCursor<'f> {
808747ad3c4Slazypassion         /// Create a new `LayoutCursor` for `layout`.
809747ad3c4Slazypassion         /// The cursor holds a mutable reference to `layout` for its entire lifetime.
new(layout: &'f mut Layout) -> Self810747ad3c4Slazypassion         pub fn new(layout: &'f mut Layout) -> Self {
811747ad3c4Slazypassion             Self {
812747ad3c4Slazypassion                 layout,
813747ad3c4Slazypassion                 pos: CursorPosition::Nowhere,
814747ad3c4Slazypassion             }
815747ad3c4Slazypassion         }
816747ad3c4Slazypassion     }
817747ad3c4Slazypassion 
verify(layout: &mut Layout, blocks: &[(Block, &[Inst])])818832666c4SRyan Hunt     fn verify(layout: &mut Layout, blocks: &[(Block, &[Inst])]) {
819832666c4SRyan Hunt         // Check that blocks are inserted and instructions belong the right places.
820747ad3c4Slazypassion         // Check forward linkage with iterators.
821747ad3c4Slazypassion         // Check that layout sequence numbers are strictly monotonic.
822747ad3c4Slazypassion         {
823832666c4SRyan Hunt             let mut block_iter = layout.blocks();
824832666c4SRyan Hunt             for &(block, insts) in blocks {
825832666c4SRyan Hunt                 assert!(layout.is_block_inserted(block));
826832666c4SRyan Hunt                 assert_eq!(block_iter.next(), Some(block));
827747ad3c4Slazypassion 
8282c40c267Sbjorn3                 let mut seq = 0;
829832666c4SRyan Hunt                 let mut inst_iter = layout.block_insts(block);
830747ad3c4Slazypassion                 for &inst in insts {
831832666c4SRyan Hunt                     assert_eq!(layout.inst_block(inst), Some(block));
832747ad3c4Slazypassion                     assert_eq!(inst_iter.next(), Some(inst));
833747ad3c4Slazypassion                     assert!(layout.insts[inst].seq > seq);
834747ad3c4Slazypassion                     seq = layout.insts[inst].seq;
835747ad3c4Slazypassion                 }
836747ad3c4Slazypassion                 assert_eq!(inst_iter.next(), None);
837747ad3c4Slazypassion             }
838832666c4SRyan Hunt             assert_eq!(block_iter.next(), None);
839747ad3c4Slazypassion         }
840747ad3c4Slazypassion 
841747ad3c4Slazypassion         // Check backwards linkage with a cursor.
842747ad3c4Slazypassion         let mut cur = LayoutCursor::new(layout);
843832666c4SRyan Hunt         for &(block, insts) in blocks.into_iter().rev() {
844832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(block));
845747ad3c4Slazypassion             for &inst in insts.into_iter().rev() {
846747ad3c4Slazypassion                 assert_eq!(cur.prev_inst(), Some(inst));
847747ad3c4Slazypassion             }
848747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
849747ad3c4Slazypassion         }
850832666c4SRyan Hunt         assert_eq!(cur.prev_block(), None);
851747ad3c4Slazypassion     }
852747ad3c4Slazypassion 
853747ad3c4Slazypassion     #[test]
append_block()854832666c4SRyan Hunt     fn append_block() {
855747ad3c4Slazypassion         let mut layout = Layout::new();
856832666c4SRyan Hunt         let e0 = Block::new(0);
857832666c4SRyan Hunt         let e1 = Block::new(1);
858832666c4SRyan Hunt         let e2 = Block::new(2);
859747ad3c4Slazypassion 
860747ad3c4Slazypassion         {
861747ad3c4Slazypassion             let imm = &layout;
862832666c4SRyan Hunt             assert!(!imm.is_block_inserted(e0));
863832666c4SRyan Hunt             assert!(!imm.is_block_inserted(e1));
864747ad3c4Slazypassion         }
865747ad3c4Slazypassion         verify(&mut layout, &[]);
866747ad3c4Slazypassion 
867832666c4SRyan Hunt         layout.append_block(e1);
868832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e0));
869832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
870832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e2));
871832666c4SRyan Hunt         let v: Vec<Block> = layout.blocks().collect();
872747ad3c4Slazypassion         assert_eq!(v, [e1]);
873747ad3c4Slazypassion 
874832666c4SRyan Hunt         layout.append_block(e2);
875832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e0));
876832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
877832666c4SRyan Hunt         assert!(layout.is_block_inserted(e2));
878832666c4SRyan Hunt         let v: Vec<Block> = layout.blocks().collect();
879747ad3c4Slazypassion         assert_eq!(v, [e1, e2]);
880747ad3c4Slazypassion 
881832666c4SRyan Hunt         layout.append_block(e0);
882832666c4SRyan Hunt         assert!(layout.is_block_inserted(e0));
883832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
884832666c4SRyan Hunt         assert!(layout.is_block_inserted(e2));
885832666c4SRyan Hunt         let v: Vec<Block> = layout.blocks().collect();
886747ad3c4Slazypassion         assert_eq!(v, [e1, e2, e0]);
887747ad3c4Slazypassion 
888747ad3c4Slazypassion         {
889747ad3c4Slazypassion             let imm = &layout;
890747ad3c4Slazypassion             let mut v = Vec::new();
891747ad3c4Slazypassion             for e in imm {
892747ad3c4Slazypassion                 v.push(e);
893747ad3c4Slazypassion             }
894747ad3c4Slazypassion             assert_eq!(v, [e1, e2, e0]);
895747ad3c4Slazypassion         }
896747ad3c4Slazypassion 
897747ad3c4Slazypassion         // Test cursor positioning.
898747ad3c4Slazypassion         let mut cur = LayoutCursor::new(&mut layout);
899747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Nowhere);
900747ad3c4Slazypassion         assert_eq!(cur.next_inst(), None);
901747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Nowhere);
902747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), None);
903747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Nowhere);
904747ad3c4Slazypassion 
905832666c4SRyan Hunt         assert_eq!(cur.next_block(), Some(e1));
906747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Before(e1));
907747ad3c4Slazypassion         assert_eq!(cur.next_inst(), None);
908747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e1));
909747ad3c4Slazypassion         assert_eq!(cur.next_inst(), None);
910747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e1));
911832666c4SRyan Hunt         assert_eq!(cur.next_block(), Some(e2));
912747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), None);
913747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Before(e2));
914832666c4SRyan Hunt         assert_eq!(cur.next_block(), Some(e0));
915832666c4SRyan Hunt         assert_eq!(cur.next_block(), None);
916747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Nowhere);
917747ad3c4Slazypassion 
918832666c4SRyan Hunt         // Backwards through the blocks.
919832666c4SRyan Hunt         assert_eq!(cur.prev_block(), Some(e0));
920747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e0));
921832666c4SRyan Hunt         assert_eq!(cur.prev_block(), Some(e2));
922832666c4SRyan Hunt         assert_eq!(cur.prev_block(), Some(e1));
923832666c4SRyan Hunt         assert_eq!(cur.prev_block(), None);
924747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Nowhere);
925747ad3c4Slazypassion     }
926747ad3c4Slazypassion 
927747ad3c4Slazypassion     #[test]
insert_block()928832666c4SRyan Hunt     fn insert_block() {
929747ad3c4Slazypassion         let mut layout = Layout::new();
930832666c4SRyan Hunt         let e0 = Block::new(0);
931832666c4SRyan Hunt         let e1 = Block::new(1);
932832666c4SRyan Hunt         let e2 = Block::new(2);
933747ad3c4Slazypassion 
934747ad3c4Slazypassion         {
935747ad3c4Slazypassion             let imm = &layout;
936832666c4SRyan Hunt             assert!(!imm.is_block_inserted(e0));
937832666c4SRyan Hunt             assert!(!imm.is_block_inserted(e1));
938747ad3c4Slazypassion 
939832666c4SRyan Hunt             let v: Vec<Block> = layout.blocks().collect();
940747ad3c4Slazypassion             assert_eq!(v, []);
941747ad3c4Slazypassion         }
942747ad3c4Slazypassion 
943832666c4SRyan Hunt         layout.append_block(e1);
944832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e0));
945832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
946832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e2));
947747ad3c4Slazypassion         verify(&mut layout, &[(e1, &[])]);
948747ad3c4Slazypassion 
949832666c4SRyan Hunt         layout.insert_block(e2, e1);
950832666c4SRyan Hunt         assert!(!layout.is_block_inserted(e0));
951832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
952832666c4SRyan Hunt         assert!(layout.is_block_inserted(e2));
953747ad3c4Slazypassion         verify(&mut layout, &[(e2, &[]), (e1, &[])]);
954747ad3c4Slazypassion 
955832666c4SRyan Hunt         layout.insert_block(e0, e1);
956832666c4SRyan Hunt         assert!(layout.is_block_inserted(e0));
957832666c4SRyan Hunt         assert!(layout.is_block_inserted(e1));
958832666c4SRyan Hunt         assert!(layout.is_block_inserted(e2));
959747ad3c4Slazypassion         verify(&mut layout, &[(e2, &[]), (e0, &[]), (e1, &[])]);
960747ad3c4Slazypassion     }
961747ad3c4Slazypassion 
962747ad3c4Slazypassion     #[test]
insert_block_after()963832666c4SRyan Hunt     fn insert_block_after() {
964747ad3c4Slazypassion         let mut layout = Layout::new();
965832666c4SRyan Hunt         let e0 = Block::new(0);
966832666c4SRyan Hunt         let e1 = Block::new(1);
967832666c4SRyan Hunt         let e2 = Block::new(2);
968747ad3c4Slazypassion 
969832666c4SRyan Hunt         layout.append_block(e1);
970832666c4SRyan Hunt         layout.insert_block_after(e2, e1);
971747ad3c4Slazypassion         verify(&mut layout, &[(e1, &[]), (e2, &[])]);
972747ad3c4Slazypassion 
973832666c4SRyan Hunt         layout.insert_block_after(e0, e1);
974747ad3c4Slazypassion         verify(&mut layout, &[(e1, &[]), (e0, &[]), (e2, &[])]);
975747ad3c4Slazypassion     }
976747ad3c4Slazypassion 
977747ad3c4Slazypassion     #[test]
append_inst()978747ad3c4Slazypassion     fn append_inst() {
979747ad3c4Slazypassion         let mut layout = Layout::new();
980832666c4SRyan Hunt         let e1 = Block::new(1);
981747ad3c4Slazypassion 
982832666c4SRyan Hunt         layout.append_block(e1);
983832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
984747ad3c4Slazypassion         assert_eq!(v, []);
985747ad3c4Slazypassion 
986747ad3c4Slazypassion         let i0 = Inst::new(0);
987747ad3c4Slazypassion         let i1 = Inst::new(1);
988747ad3c4Slazypassion         let i2 = Inst::new(2);
989747ad3c4Slazypassion 
990832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
991832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), None);
992832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), None);
993747ad3c4Slazypassion 
994747ad3c4Slazypassion         layout.append_inst(i1, e1);
995832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
996832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), Some(e1));
997832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), None);
998832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
999747ad3c4Slazypassion         assert_eq!(v, [i1]);
1000747ad3c4Slazypassion 
1001747ad3c4Slazypassion         layout.append_inst(i2, e1);
1002832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
1003832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), Some(e1));
1004832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), Some(e1));
1005832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
1006747ad3c4Slazypassion         assert_eq!(v, [i1, i2]);
1007747ad3c4Slazypassion 
1008747ad3c4Slazypassion         // Test double-ended instruction iterator.
1009832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).rev().collect();
1010747ad3c4Slazypassion         assert_eq!(v, [i2, i1]);
1011747ad3c4Slazypassion 
1012747ad3c4Slazypassion         layout.append_inst(i0, e1);
1013747ad3c4Slazypassion         verify(&mut layout, &[(e1, &[i1, i2, i0])]);
1014747ad3c4Slazypassion 
1015747ad3c4Slazypassion         // Test cursor positioning.
1016747ad3c4Slazypassion         let mut cur = LayoutCursor::new(&mut layout).at_top(e1);
1017747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Before(e1));
1018747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), None);
1019747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Before(e1));
1020747ad3c4Slazypassion         assert_eq!(cur.next_inst(), Some(i1));
1021747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::At(i1));
1022747ad3c4Slazypassion         assert_eq!(cur.next_inst(), Some(i2));
1023747ad3c4Slazypassion         assert_eq!(cur.next_inst(), Some(i0));
1024747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), Some(i2));
1025747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::At(i2));
1026747ad3c4Slazypassion         assert_eq!(cur.next_inst(), Some(i0));
1027747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::At(i0));
1028747ad3c4Slazypassion         assert_eq!(cur.next_inst(), None);
1029747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e1));
1030747ad3c4Slazypassion         assert_eq!(cur.next_inst(), None);
1031747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e1));
1032747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), Some(i0));
1033747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), Some(i2));
1034747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), Some(i1));
1035747ad3c4Slazypassion         assert_eq!(cur.prev_inst(), None);
1036747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::Before(e1));
1037747ad3c4Slazypassion 
1038747ad3c4Slazypassion         // Test remove_inst.
1039747ad3c4Slazypassion         cur.goto_inst(i2);
1040747ad3c4Slazypassion         assert_eq!(cur.remove_inst(), i2);
1041747ad3c4Slazypassion         verify(cur.layout, &[(e1, &[i1, i0])]);
1042832666c4SRyan Hunt         assert_eq!(cur.layout.inst_block(i2), None);
1043747ad3c4Slazypassion         assert_eq!(cur.remove_inst(), i0);
1044747ad3c4Slazypassion         verify(cur.layout, &[(e1, &[i1])]);
1045832666c4SRyan Hunt         assert_eq!(cur.layout.inst_block(i0), None);
1046747ad3c4Slazypassion         assert_eq!(cur.position(), CursorPosition::After(e1));
1047747ad3c4Slazypassion         cur.layout.remove_inst(i1);
1048747ad3c4Slazypassion         verify(cur.layout, &[(e1, &[])]);
1049832666c4SRyan Hunt         assert_eq!(cur.layout.inst_block(i1), None);
1050747ad3c4Slazypassion     }
1051747ad3c4Slazypassion 
1052747ad3c4Slazypassion     #[test]
insert_inst()1053747ad3c4Slazypassion     fn insert_inst() {
1054747ad3c4Slazypassion         let mut layout = Layout::new();
1055832666c4SRyan Hunt         let e1 = Block::new(1);
1056747ad3c4Slazypassion 
1057832666c4SRyan Hunt         layout.append_block(e1);
1058832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
1059747ad3c4Slazypassion         assert_eq!(v, []);
1060747ad3c4Slazypassion 
1061747ad3c4Slazypassion         let i0 = Inst::new(0);
1062747ad3c4Slazypassion         let i1 = Inst::new(1);
1063747ad3c4Slazypassion         let i2 = Inst::new(2);
1064747ad3c4Slazypassion 
1065832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
1066832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), None);
1067832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), None);
1068747ad3c4Slazypassion 
1069747ad3c4Slazypassion         layout.append_inst(i1, e1);
1070832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
1071832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), Some(e1));
1072832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), None);
1073832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
1074747ad3c4Slazypassion         assert_eq!(v, [i1]);
1075747ad3c4Slazypassion 
1076747ad3c4Slazypassion         layout.insert_inst(i2, i1);
1077832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), None);
1078832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), Some(e1));
1079832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), Some(e1));
1080832666c4SRyan Hunt         let v: Vec<Inst> = layout.block_insts(e1).collect();
1081747ad3c4Slazypassion         assert_eq!(v, [i2, i1]);
1082747ad3c4Slazypassion 
1083747ad3c4Slazypassion         layout.insert_inst(i0, i1);
1084747ad3c4Slazypassion         verify(&mut layout, &[(e1, &[i2, i0, i1])]);
1085747ad3c4Slazypassion     }
1086747ad3c4Slazypassion 
1087747ad3c4Slazypassion     #[test]
multiple_blocks()1088832666c4SRyan Hunt     fn multiple_blocks() {
1089747ad3c4Slazypassion         let mut layout = Layout::new();
1090747ad3c4Slazypassion 
1091832666c4SRyan Hunt         let e0 = Block::new(0);
1092832666c4SRyan Hunt         let e1 = Block::new(1);
1093747ad3c4Slazypassion 
1094747ad3c4Slazypassion         assert_eq!(layout.entry_block(), None);
1095832666c4SRyan Hunt         layout.append_block(e0);
1096747ad3c4Slazypassion         assert_eq!(layout.entry_block(), Some(e0));
1097832666c4SRyan Hunt         layout.append_block(e1);
1098747ad3c4Slazypassion         assert_eq!(layout.entry_block(), Some(e0));
1099747ad3c4Slazypassion 
1100747ad3c4Slazypassion         let i0 = Inst::new(0);
1101747ad3c4Slazypassion         let i1 = Inst::new(1);
1102747ad3c4Slazypassion         let i2 = Inst::new(2);
1103747ad3c4Slazypassion         let i3 = Inst::new(3);
1104747ad3c4Slazypassion 
1105747ad3c4Slazypassion         layout.append_inst(i0, e0);
1106747ad3c4Slazypassion         layout.append_inst(i1, e0);
1107747ad3c4Slazypassion         layout.append_inst(i2, e1);
1108747ad3c4Slazypassion         layout.append_inst(i3, e1);
1109747ad3c4Slazypassion 
1110832666c4SRyan Hunt         let v0: Vec<Inst> = layout.block_insts(e0).collect();
1111832666c4SRyan Hunt         let v1: Vec<Inst> = layout.block_insts(e1).collect();
1112747ad3c4Slazypassion         assert_eq!(v0, [i0, i1]);
1113747ad3c4Slazypassion         assert_eq!(v1, [i2, i3]);
1114747ad3c4Slazypassion     }
1115747ad3c4Slazypassion 
1116747ad3c4Slazypassion     #[test]
split_block()1117832666c4SRyan Hunt     fn split_block() {
1118747ad3c4Slazypassion         let mut layout = Layout::new();
1119747ad3c4Slazypassion 
1120832666c4SRyan Hunt         let e0 = Block::new(0);
1121832666c4SRyan Hunt         let e1 = Block::new(1);
1122832666c4SRyan Hunt         let e2 = Block::new(2);
1123747ad3c4Slazypassion 
1124747ad3c4Slazypassion         let i0 = Inst::new(0);
1125747ad3c4Slazypassion         let i1 = Inst::new(1);
1126747ad3c4Slazypassion         let i2 = Inst::new(2);
1127747ad3c4Slazypassion         let i3 = Inst::new(3);
1128747ad3c4Slazypassion 
1129832666c4SRyan Hunt         layout.append_block(e0);
1130747ad3c4Slazypassion         layout.append_inst(i0, e0);
1131832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), Some(e0));
1132832666c4SRyan Hunt         layout.split_block(e1, i0);
1133832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), Some(e1));
1134747ad3c4Slazypassion 
1135747ad3c4Slazypassion         {
1136747ad3c4Slazypassion             let mut cur = LayoutCursor::new(&mut layout);
1137832666c4SRyan Hunt             assert_eq!(cur.next_block(), Some(e0));
1138747ad3c4Slazypassion             assert_eq!(cur.next_inst(), None);
1139832666c4SRyan Hunt             assert_eq!(cur.next_block(), Some(e1));
1140747ad3c4Slazypassion             assert_eq!(cur.next_inst(), Some(i0));
1141747ad3c4Slazypassion             assert_eq!(cur.next_inst(), None);
1142832666c4SRyan Hunt             assert_eq!(cur.next_block(), None);
1143747ad3c4Slazypassion 
1144747ad3c4Slazypassion             // Check backwards links.
1145832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(e1));
1146747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), Some(i0));
1147747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
1148832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(e0));
1149747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
1150832666c4SRyan Hunt             assert_eq!(cur.prev_block(), None);
1151747ad3c4Slazypassion         }
1152747ad3c4Slazypassion 
1153747ad3c4Slazypassion         layout.append_inst(i1, e0);
1154747ad3c4Slazypassion         layout.append_inst(i2, e0);
1155747ad3c4Slazypassion         layout.append_inst(i3, e0);
1156832666c4SRyan Hunt         layout.split_block(e2, i2);
1157747ad3c4Slazypassion 
1158832666c4SRyan Hunt         assert_eq!(layout.inst_block(i0), Some(e1));
1159832666c4SRyan Hunt         assert_eq!(layout.inst_block(i1), Some(e0));
1160832666c4SRyan Hunt         assert_eq!(layout.inst_block(i2), Some(e2));
1161832666c4SRyan Hunt         assert_eq!(layout.inst_block(i3), Some(e2));
1162747ad3c4Slazypassion 
1163747ad3c4Slazypassion         {
1164747ad3c4Slazypassion             let mut cur = LayoutCursor::new(&mut layout);
1165832666c4SRyan Hunt             assert_eq!(cur.next_block(), Some(e0));
1166747ad3c4Slazypassion             assert_eq!(cur.next_inst(), Some(i1));
1167747ad3c4Slazypassion             assert_eq!(cur.next_inst(), None);
1168832666c4SRyan Hunt             assert_eq!(cur.next_block(), Some(e2));
1169747ad3c4Slazypassion             assert_eq!(cur.next_inst(), Some(i2));
1170747ad3c4Slazypassion             assert_eq!(cur.next_inst(), Some(i3));
1171747ad3c4Slazypassion             assert_eq!(cur.next_inst(), None);
1172832666c4SRyan Hunt             assert_eq!(cur.next_block(), Some(e1));
1173747ad3c4Slazypassion             assert_eq!(cur.next_inst(), Some(i0));
1174747ad3c4Slazypassion             assert_eq!(cur.next_inst(), None);
1175832666c4SRyan Hunt             assert_eq!(cur.next_block(), None);
1176747ad3c4Slazypassion 
1177832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(e1));
1178747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), Some(i0));
1179747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
1180832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(e2));
1181747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), Some(i3));
1182747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), Some(i2));
1183747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
1184832666c4SRyan Hunt             assert_eq!(cur.prev_block(), Some(e0));
1185747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), Some(i1));
1186747ad3c4Slazypassion             assert_eq!(cur.prev_inst(), None);
1187832666c4SRyan Hunt             assert_eq!(cur.prev_block(), None);
1188747ad3c4Slazypassion         }
1189747ad3c4Slazypassion 
1190747ad3c4Slazypassion         // Check `ProgramOrder`.
1191a81c2068Sbjorn3         assert_eq!(layout.pp_cmp(e2, e2), Ordering::Equal);
1192a81c2068Sbjorn3         assert_eq!(layout.pp_cmp(e2, i2), Ordering::Less);
1193a81c2068Sbjorn3         assert_eq!(layout.pp_cmp(i3, i2), Ordering::Greater)
1194747ad3c4Slazypassion     }
1195747ad3c4Slazypassion }
1196