Coverage Report

Created: 2024-10-16 07:58

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