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