Coverage Report

Created: 2026-10-24 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/regalloc2/src/lib.rs
Line
Count
Source
1
/*
2
 * The following license applies to this file, which derives many
3
 * details (register and constraint definitions, for example) from the
4
 * files `BacktrackingAllocator.h`, `BacktrackingAllocator.cpp`,
5
 * `LIR.h`, and possibly definitions in other related files in
6
 * `js/src/jit/`:
7
 *
8
 * This Source Code Form is subject to the terms of the Mozilla Public
9
 * License, v. 2.0. If a copy of the MPL was not distributed with this
10
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11
 */
12
13
#![allow(dead_code)]
14
#![allow(clippy::all)]
15
#![no_std]
16
17
#[cfg(feature = "fuzzing")]
18
extern crate std;
19
20
extern crate alloc;
21
22
// Even when trace logging is disabled, the trace macro has a significant
23
// performance cost so we disable it in release builds.
24
macro_rules! trace {
25
    ($($tt:tt)*) => {
26
        if cfg!(feature = "trace-log") {
27
            ::log::trace!($($tt)*);
28
        }
29
    };
30
}
31
32
macro_rules! trace_enabled {
33
    () => {
34
        cfg!(feature = "trace-log") && ::log::log_enabled!(::log::Level::Trace)
35
    };
36
}
37
38
use alloc::rc::Rc;
39
use allocator_api2::vec::Vec as Vec2;
40
use core::ops::Deref as _;
41
use core::{hash::BuildHasherDefault, iter::FromIterator};
42
use rustc_hash::FxHasher;
43
type FxHashMap<K, V> = hashbrown::HashMap<K, V, BuildHasherDefault<FxHasher>>;
44
type FxHashSet<V> = hashbrown::HashSet<V, BuildHasherDefault<FxHasher>>;
45
46
pub(crate) mod cfg;
47
pub(crate) mod domtree;
48
pub(crate) mod fastalloc;
49
pub mod indexset;
50
pub(crate) mod ion;
51
pub(crate) mod moves;
52
pub(crate) mod postorder;
53
pub mod ssa;
54
55
#[macro_use]
56
mod index;
57
58
pub use self::ion::data_structures::Ctx;
59
use alloc::vec::Vec;
60
pub use index::{Block, Inst, InstRange};
61
62
pub mod checker;
63
64
#[cfg(feature = "fuzzing")]
65
pub mod fuzzing;
66
67
#[cfg(feature = "enable-serde")]
68
pub mod serialize;
69
70
#[cfg(feature = "enable-serde")]
71
use serde::{Deserialize, Serialize};
72
73
/// Register classes.
74
///
75
/// Every value has a "register class", which is like a type at the
76
/// register-allocator level. Every register must belong to only one
77
/// class; i.e., they are disjoint.
78
///
79
/// For tight bit-packing throughout our data structures, we support
80
/// only three classes, "int", "float" and "vector". Usually two will
81
/// be enough on modern machines, as they have one class of general-purpose
82
/// integer registers of machine width (e.g. 64 bits), and another
83
/// class of float/vector registers used both for FP and for vector
84
/// operations. Additionally for machines with totally separate vector
85
/// registers a third class is provided.
86
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
87
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
88
pub enum RegClass {
89
    Int = 0,
90
    Float = 1,
91
    Vector = 2,
92
}
93
94
/// A physical register. Contains a physical register number and a class.
95
///
96
/// The `hw_enc` field contains the physical register number and is in
97
/// a logically separate index space per class; in other words, Int
98
/// register 0 is different than Float register 0.
99
///
100
/// Because of bit-packed encodings throughout the implementation,
101
/// `hw_enc` must fit in 6 bits, i.e., at most 64 registers per class.
102
///
103
/// The value returned by `index()`, in contrast, is in a single index
104
/// space shared by all classes, in order to enable uniform reasoning
105
/// about physical registers. This is done by putting the class bit at
106
/// the MSB, or equivalently, declaring that indices 0..=63 are the 64
107
/// integer registers and indices 64..=127 are the 64 float registers.
108
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
109
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
110
pub struct PReg {
111
    bits: u8,
112
}
113
114
impl PReg {
115
    pub const MAX_BITS: usize = 6;
116
    pub const MAX: usize = (1 << Self::MAX_BITS) - 1;
117
    pub const NUM_INDEX: usize = 1 << (Self::MAX_BITS + 2); // including RegClass bits
118
    pub const INVALID: u8 = ((RegClass::Int as u8) << Self::MAX_BITS) | (Self::MAX as u8);
119
120
    /// Create a new PReg. The `hw_enc` range is 6 bits.
121
    #[inline(always)]
122
41.5M
    pub const fn new(hw_enc: usize, class: RegClass) -> Self {
123
41.5M
        debug_assert!(hw_enc <= PReg::MAX);
124
41.5M
        PReg {
125
41.5M
            bits: ((class as u8) << Self::MAX_BITS) | (hw_enc as u8),
126
41.5M
        }
127
41.5M
    }
128
129
    /// The physical register number, as encoded by the ISA for the particular register class.
130
    #[inline(always)]
131
73.1M
    pub const fn hw_enc(self) -> usize {
132
73.1M
        self.bits as usize & Self::MAX
133
73.1M
    }
134
135
    /// The register class.
136
    #[inline(always)]
137
3.00M
    pub const fn class(self) -> RegClass {
138
3.00M
        match (self.bits >> Self::MAX_BITS) & 0b11 {
139
859k
            0 => RegClass::Int,
140
1.28M
            1 => RegClass::Float,
141
863k
            2 => RegClass::Vector,
142
0
            _ => unreachable!(),
143
        }
144
3.00M
    }
145
146
    /// Get an index into the (not necessarily contiguous) index space of
147
    /// all physical registers. Allows one to maintain an array of data for
148
    /// all PRegs and index it efficiently.
149
    #[inline(always)]
150
131M
    pub const fn index(self) -> usize {
151
131M
        self.bits as usize
152
131M
    }
153
154
    /// Construct a PReg from the value returned from `.index()`.
155
    #[inline(always)]
156
91.3M
    pub const fn from_index(index: usize) -> Self {
157
91.3M
        PReg {
158
91.3M
            bits: (index & (Self::NUM_INDEX - 1)) as u8,
159
91.3M
        }
160
91.3M
    }
161
162
    /// Return the "invalid PReg", which can be used to initialize
163
    /// data structures.
164
    #[inline(always)]
165
36.5M
    pub const fn invalid() -> Self {
166
36.5M
        PReg {
167
36.5M
            bits: Self::INVALID,
168
36.5M
        }
169
36.5M
    }
170
171
    /// Return a valid [`PReg`] or [`None`] if it is invalid.
172
    #[inline(always)]
173
8.91M
    pub const fn as_valid(self) -> Option<Self> {
174
8.91M
        if self.bits == Self::INVALID {
175
7.39M
            None
176
        } else {
177
1.52M
            Some(self)
178
        }
179
8.91M
    }
180
}
181
182
impl Default for PReg {
183
3
    fn default() -> Self {
184
3
        Self::invalid()
185
3
    }
186
}
187
188
impl core::fmt::Debug for PReg {
189
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
190
0
        write!(
191
0
            f,
192
            "PReg(hw = {}, class = {:?}, index = {})",
193
0
            self.hw_enc(),
194
0
            self.class(),
195
0
            self.index()
196
        )
197
0
    }
198
}
199
200
impl core::fmt::Display for PReg {
201
2.90M
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
202
2.90M
        let class = match self.class() {
203
818k
            RegClass::Int => "i",
204
1.25M
            RegClass::Float => "f",
205
831k
            RegClass::Vector => "v",
206
        };
207
2.90M
        write!(f, "p{}{}", self.hw_enc(), class)
208
2.90M
    }
209
}
210
211
/// A type for internal bit arrays.
212
type Bits = u64;
213
214
/// A physical register set. Used to represent clobbers
215
/// efficiently.
216
///
217
/// The set is `Copy` and is guaranteed to have constant, and small,
218
/// size, as it is based on a bitset internally.
219
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
220
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
221
pub struct PRegSet {
222
    bits: [Bits; Self::LEN],
223
}
224
225
impl PRegSet {
226
    /// The number of bits per element in the internal bit array.
227
    const BITS: usize = core::mem::size_of::<Bits>() * 8;
228
229
    /// Length of the internal bit array.
230
    const LEN: usize = (PReg::NUM_INDEX + Self::BITS - 1) / Self::BITS;
231
232
    /// Create an empty set.
233
21.3M
    pub const fn empty() -> Self {
234
21.3M
        Self {
235
21.3M
            bits: [0; Self::LEN],
236
21.3M
        }
237
21.3M
    }
238
239
    /// Splits the given register index into parts to access the internal bit array.
240
29.0M
    const fn split_index(reg: PReg) -> (usize, usize) {
241
29.0M
        let index = reg.index();
242
29.0M
        (index >> Self::BITS.ilog2(), index & (Self::BITS - 1))
243
29.0M
    }
244
245
    /// Returns whether the given register is part of the set.
246
2.40M
    pub fn contains(&self, reg: PReg) -> bool {
247
2.40M
        let (index, bit) = Self::split_index(reg);
248
2.40M
        self.bits[index] & (1 << bit) != 0
249
2.40M
    }
250
251
    /// Add a physical register (PReg) to the set, returning the new value.
252
3.13M
    pub const fn with(self, reg: PReg) -> Self {
253
3.13M
        let (index, bit) = Self::split_index(reg);
254
3.13M
        let mut out = self;
255
3.13M
        out.bits[index] |= 1 << bit;
256
3.13M
        out
257
3.13M
    }
258
259
    /// Add a physical register (PReg) to the set.
260
2.10M
    pub const fn add(&mut self, reg: PReg) {
261
2.10M
        let (index, bit) = Self::split_index(reg);
262
2.10M
        self.bits[index] |= 1 << bit;
263
2.10M
    }
264
265
    /// Remove a physical register (PReg) from the set.
266
0
    pub fn remove(&mut self, reg: PReg) {
267
0
        let (index, bit) = Self::split_index(reg);
268
0
        self.bits[index] &= !(1 << bit);
269
0
    }
270
271
    /// Add all of the registers in one set to this one, mutating in
272
    /// place.
273
0
    pub fn union_from(&mut self, other: PRegSet) {
274
0
        for i in 0..self.bits.len() {
275
0
            self.bits[i] |= other.bits[i];
276
0
        }
277
0
    }
278
279
42.7M
    pub fn intersect_from(&mut self, other: PRegSet) {
280
171M
        for i in 0..self.bits.len() {
281
171M
            self.bits[i] &= other.bits[i];
282
171M
        }
283
42.7M
    }
284
285
21.3M
    pub fn invert(&self) -> PRegSet {
286
21.3M
        let mut set = self.bits;
287
85.5M
        for i in 0..self.bits.len() {
288
85.5M
            set[i] = !self.bits[i];
289
85.5M
        }
290
21.3M
        PRegSet { bits: set }
291
21.3M
    }
292
293
0
    pub fn is_empty(&self, regclass: RegClass) -> bool {
294
0
        self.bits[regclass as usize] == 0
295
0
    }
296
297
    /// Returns the number of register in this set.
298
0
    pub fn len(&self) -> u32 {
299
0
        self.bits.iter().map(|s| s.count_ones()).sum()
300
0
    }
301
302
    /// Returns the maximum register in this set, with the highest hw_enc value.
303
73.0k
    pub fn max_preg(&self) -> Option<PReg> {
304
73.0k
        self.into_iter().last()
305
73.0k
    }
306
307
    /// Add all registers from `0..reg` to this set, not including `reg` itself.
308
21.3M
    pub fn add_up_to(&mut self, reg: PReg) {
309
21.3M
        let (index, bit) = Self::split_index(reg);
310
21.3M
        for i in 0..index {
311
20.8M
            self.bits[i] = !0;
312
20.8M
        }
313
21.3M
        self.bits[index] = (1 << bit) - 1;
314
21.3M
    }
315
}
316
317
impl core::ops::BitAnd<PRegSet> for PRegSet {
318
    type Output = PRegSet;
319
320
42.7M
    fn bitand(self, rhs: PRegSet) -> Self::Output {
321
42.7M
        let mut out = self;
322
42.7M
        out.intersect_from(rhs);
323
42.7M
        out
324
42.7M
    }
325
}
326
327
impl core::ops::BitOr<PRegSet> for PRegSet {
328
    type Output = PRegSet;
329
330
0
    fn bitor(self, rhs: PRegSet) -> Self::Output {
331
0
        let mut out = self;
332
0
        out.union_from(rhs);
333
0
        out
334
0
    }
335
}
336
337
impl IntoIterator for &PRegSet {
338
    type Item = PReg;
339
    type IntoIter = PRegSetIter;
340
73.0k
    fn into_iter(self) -> PRegSetIter {
341
73.0k
        (*self).into_iter()
342
73.0k
    }
343
}
344
345
impl IntoIterator for PRegSet {
346
    type Item = PReg;
347
    type IntoIter = PRegSetIter;
348
53.3M
    fn into_iter(self) -> PRegSetIter {
349
53.3M
        PRegSetIter {
350
53.3M
            bits: self.bits,
351
53.3M
            cur: 0,
352
53.3M
        }
353
53.3M
    }
354
}
355
356
pub struct PRegSetIter {
357
    bits: [Bits; PRegSet::LEN],
358
    cur: usize,
359
}
360
361
impl Iterator for PRegSetIter {
362
    type Item = PReg;
363
151M
    fn next(&mut self) -> Option<PReg> {
364
        loop {
365
235M
            let bits = self.bits.get_mut(self.cur)?;
366
153M
            if *bits != 0 {
367
70.1M
                let bit = bits.trailing_zeros();
368
70.1M
                *bits &= !(1 << bit);
369
70.1M
                let index = bit as usize + self.cur * PRegSet::BITS;
370
70.1M
                return Some(PReg::from_index(index));
371
83.6M
            }
372
83.6M
            self.cur += 1;
373
        }
374
151M
    }
375
}
376
377
impl From<&MachineEnv> for PRegSet {
378
0
    fn from(env: &MachineEnv) -> Self {
379
0
        let mut res = Self::default();
380
381
0
        for class in env.preferred_regs_by_class.iter() {
382
0
            res.union_from(*class)
383
        }
384
385
0
        for class in env.non_preferred_regs_by_class.iter() {
386
0
            res.union_from(*class)
387
        }
388
389
0
        res
390
0
    }
391
}
392
393
impl FromIterator<PReg> for PRegSet {
394
73.0k
    fn from_iter<T: IntoIterator<Item = PReg>>(iter: T) -> Self {
395
73.0k
        let mut set = Self::default();
396
1.16M
        for preg in iter {
397
1.16M
            set.add(preg);
398
1.16M
        }
399
73.0k
        set
400
73.0k
    }
<regalloc2::PRegSet as core::iter::traits::collect::FromIterator<regalloc2::PReg>>::from_iter::<core::iter::adapters::map::Map<core::ops::range::Range<usize>, regalloc2::fuzzing::func::machine_env::regs::{closure#0}>>
Line
Count
Source
394
73.0k
    fn from_iter<T: IntoIterator<Item = PReg>>(iter: T) -> Self {
395
73.0k
        let mut set = Self::default();
396
1.16M
        for preg in iter {
397
1.16M
            set.add(preg);
398
1.16M
        }
399
73.0k
        set
400
73.0k
    }
Unexecuted instantiation: <regalloc2::PRegSet as core::iter::traits::collect::FromIterator<regalloc2::PReg>>::from_iter::<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<regalloc2::PReg>>>
401
}
402
403
impl core::fmt::Display for PRegSet {
404
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
405
0
        write!(f, "{{")?;
406
0
        for preg in self.into_iter() {
407
0
            write!(f, "{preg}, ")?;
408
        }
409
0
        write!(f, "}}")
410
0
    }
411
}
412
413
/// A virtual register. Contains a virtual register number and a
414
/// class.
415
///
416
/// A virtual register ("vreg") corresponds to an SSA value. All
417
/// dataflow in the input program is specified via flow through a
418
/// virtual register; even uses of specially-constrained locations,
419
/// such as fixed physical registers, are done by using vregs, because
420
/// we need the vreg's live range in order to track the use of that
421
/// location.
422
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
423
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
424
pub struct VReg {
425
    bits: u32,
426
}
427
428
impl VReg {
429
    pub const MAX_BITS: usize = 30;
430
    pub const MAX: usize = (1 << Self::MAX_BITS) - 1;
431
432
    #[inline(always)]
433
464M
    pub const fn new(virt_reg: usize, class: RegClass) -> Self {
434
464M
        debug_assert!(virt_reg <= VReg::MAX);
435
464M
        VReg {
436
464M
            bits: ((virt_reg as u32) << 2) | (class as u8 as u32),
437
464M
        }
438
464M
    }
439
440
    #[inline(always)]
441
481M
    pub const fn vreg(self) -> usize {
442
481M
        let vreg = (self.bits >> 2) as usize;
443
481M
        vreg
444
481M
    }
445
446
    #[inline(always)]
447
122M
    pub const fn class(self) -> RegClass {
448
122M
        match self.bits & 0b11 {
449
38.8M
            0 => RegClass::Int,
450
48.0M
            1 => RegClass::Float,
451
36.0M
            2 => RegClass::Vector,
452
0
            _ => unreachable!(),
453
        }
454
122M
    }
455
456
    #[inline(always)]
457
0
    pub const fn invalid() -> Self {
458
0
        VReg::new(Self::MAX, RegClass::Int)
459
0
    }
460
461
    #[inline(always)]
462
0
    pub const fn bits(self) -> usize {
463
0
        self.bits as usize
464
0
    }
465
466
    #[inline(always)]
467
0
    pub const fn from_bits(bits: u32) -> VReg {
468
0
        Self { bits }
469
0
    }
470
}
471
472
impl From<u32> for VReg {
473
0
    fn from(value: u32) -> Self {
474
0
        Self { bits: value }
475
0
    }
476
}
477
478
impl core::fmt::Debug for VReg {
479
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
480
0
        write!(
481
0
            f,
482
            "VReg(vreg = {}, class = {:?})",
483
0
            self.vreg(),
484
0
            self.class()
485
        )
486
0
    }
487
}
488
489
impl core::fmt::Display for VReg {
490
1.54M
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
491
1.54M
        write!(f, "v{}", self.vreg())
492
1.54M
    }
493
}
494
495
/// A spillslot is a space in the stackframe used by the allocator to
496
/// temporarily store a value.
497
///
498
/// The allocator is responsible for allocating indices in this space,
499
/// and will specify how many spillslots have been used when the
500
/// allocation is completed.
501
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
502
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
503
pub struct SpillSlot {
504
    bits: u32,
505
}
506
507
impl SpillSlot {
508
    /// The maximum spillslot index.
509
    pub const MAX: usize = (1 << 24) - 1;
510
511
    /// Create a new SpillSlot.
512
    #[inline(always)]
513
141k
    pub fn new(slot: usize) -> Self {
514
141k
        debug_assert!(slot <= Self::MAX);
515
141k
        SpillSlot { bits: slot as u32 }
516
141k
    }
517
518
    /// Get the spillslot index for this spillslot.
519
    #[inline(always)]
520
346k
    pub fn index(self) -> usize {
521
346k
        (self.bits & 0x00ffffff) as usize
522
346k
    }
523
524
    /// Get the spillslot `offset` slots away.
525
    #[inline(always)]
526
0
    pub fn plus(self, offset: usize) -> Self {
527
0
        SpillSlot::new(self.index() + offset)
528
0
    }
529
530
    /// Get the invalid spillslot, used for initializing data structures.
531
    #[inline(always)]
532
0
    pub fn invalid() -> Self {
533
0
        SpillSlot { bits: 0xffff_ffff }
534
0
    }
535
536
    /// Is this the invalid spillslot?
537
    #[inline(always)]
538
0
    pub fn is_invalid(self) -> bool {
539
0
        self == Self::invalid()
540
0
    }
541
542
    /// Is this a valid spillslot (not `SpillSlot::invalid()`)?
543
    #[inline(always)]
544
0
    pub fn is_valid(self) -> bool {
545
0
        self != Self::invalid()
546
0
    }
547
}
548
549
impl core::fmt::Display for SpillSlot {
550
346k
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
551
346k
        write!(f, "stack{}", self.index())
552
346k
    }
553
}
554
555
/// An `OperandConstraint` specifies where a vreg's value must be
556
/// placed at a particular reference to that vreg via an
557
/// `Operand`. The constraint may be loose -- "any register of a given
558
/// class", for example -- or very specific, such as "this particular
559
/// physical register". The allocator's result will always satisfy all
560
/// given constraints; however, if the input has a combination of
561
/// constraints that are impossible to satisfy, then allocation may
562
/// fail or the allocator may panic (providing impossible constraints
563
/// is usually a programming error in the client, rather than a
564
/// function of bad input).
565
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
566
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
567
pub enum OperandConstraint {
568
    /// Any location is fine (register or stack slot).
569
    Any,
570
    /// Operand must be in a register. Register is read-only for Uses.
571
    Reg,
572
    /// Operand must be on the stack.
573
    Stack,
574
    /// Operand must be in a fixed register.
575
    FixedReg(PReg),
576
    /// On defs only: reuse a use's register.
577
    Reuse(usize),
578
    /// Operand must be in a specific range of registers.
579
    ///
580
    /// The contained `usize` indicates the (exclusive) upper limit of a
581
    /// register range, `n`. An operand with this constraint may allocate a
582
    /// register between `0 ..= n-1`. Due to encoding constraints, `n` must be a
583
    /// power of two and below 2^16.
584
    Limit(usize),
585
}
586
587
impl core::fmt::Display for OperandConstraint {
588
1.20M
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
589
1.20M
        match self {
590
801k
            Self::Any => write!(f, "any"),
591
328k
            Self::Reg => write!(f, "reg"),
592
0
            Self::Stack => write!(f, "stack"),
593
30.1k
            Self::FixedReg(preg) => write!(f, "fixed({preg})"),
594
41.8k
            Self::Reuse(idx) => write!(f, "reuse({idx})"),
595
0
            Self::Limit(max) => write!(f, "limit(0..={})", max - 1),
596
        }
597
1.20M
    }
598
}
599
600
/// The "kind" of the operand: whether it reads a vreg (Use) or writes
601
/// a vreg (Def).
602
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
603
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
604
pub enum OperandKind {
605
    Def = 0,
606
    Use = 1,
607
}
608
609
/// The "position" of the operand: where it has its read/write
610
/// effects. These are positions "in" the instruction, and "early" and
611
/// "late" are relative to the instruction's main effect or
612
/// computation. In other words, the allocator assumes that the
613
/// instruction (i) performs all reads and writes of "early" operands,
614
/// (ii) does its work, and (iii) performs all reads and writes of its
615
/// "late" operands.
616
///
617
/// A "write" (def) at "early" or a "read" (use) at "late" may be
618
/// slightly nonsensical, given the above, if the read is necessary
619
/// for the computation or the write is a result of it. A way to think
620
/// of it is that the value (even if a result of execution) *could*
621
/// have been read or written at the given location without causing
622
/// any register-usage conflicts. In other words, these write-early or
623
/// use-late operands ensure that the particular allocations are valid
624
/// for longer than usual and that a register is not reused between
625
/// the use (normally complete at "Early") and the def (normally
626
/// starting at "Late"). See `Operand` for more.
627
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
628
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
629
pub enum OperandPos {
630
    Early = 0,
631
    Late = 1,
632
}
633
634
/// An `Operand` encodes everything about a mention of a register in
635
/// an instruction: virtual register number, and any constraint that
636
/// applies to the register at this program point.
637
///
638
/// An Operand may be a use or def (this corresponds to `LUse` and
639
/// `LAllocation` in Ion).
640
///
641
/// Generally, regalloc2 considers operands to have their effects at
642
/// one of two points that exist in an instruction: "Early" or
643
/// "Late". All operands at a given program-point are assigned
644
/// non-conflicting locations based on their constraints. Each operand
645
/// has a "kind", one of use/def/mod, corresponding to
646
/// read/write/read-write, respectively.
647
///
648
/// Usually, an instruction's inputs will be "early uses" and outputs
649
/// will be "late defs", though there are valid use-cases for other
650
/// combinations too. For example, a single "instruction" seen by the
651
/// regalloc that lowers into multiple machine instructions and reads
652
/// some of its inputs after it starts to write outputs must either
653
/// make those input(s) "late uses" or those output(s) "early defs" so
654
/// that the conflict (overlap) is properly accounted for. See
655
/// comments on the constructors below for more.
656
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
657
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
658
pub struct Operand {
659
    /// Bit-pack into 64 bits.
660
    ///
661
    /// unused:21 constraint:7 kind:1 pos:1 class:2 vreg:32
662
    ///
663
    /// where `constraint` is an `OperandConstraint`, `kind` is an
664
    /// `OperandKind`, `pos` is an `OperandPos`, `class` is a
665
    /// `RegClass`, and `vreg` is a vreg index.
666
    ///
667
    /// The constraints are encoded as follows:
668
    /// - 1xxxxxx => FixedReg(preg)
669
    /// - 01xxxxx => Reuse(index)
670
    /// - 001xxxx => Limit(max)
671
    /// - 0000000 => Any
672
    /// - 0000001 => Reg
673
    /// - 0000010 => Stack
674
    /// - _ => Unused for now
675
    bits: u64,
676
}
677
678
impl Operand {
679
    const VREG_BITS: usize = 32;
680
    const VREG_SHIFT: usize = 0;
681
    const VREG_MASK: u64 = (1 << Self::VREG_BITS) - 1;
682
683
    const CLASS_BITS: usize = 2;
684
    const CLASS_SHIFT: usize = Self::VREG_SHIFT + Self::VREG_BITS;
685
    const CLASS_MASK: u64 = (1 << Self::CLASS_BITS) - 1;
686
687
    const POS_BITS: usize = 1;
688
    const POS_SHIFT: usize = Self::CLASS_SHIFT + Self::CLASS_BITS;
689
    const POS_MASK: u64 = (1 << Self::POS_BITS) - 1;
690
691
    const KIND_BITS: usize = 1;
692
    const KIND_SHIFT: usize = Self::POS_SHIFT + Self::POS_BITS;
693
    const KIND_MASK: u64 = (1 << Self::KIND_BITS) - 1;
694
695
    const CONSTRAINT_BITS: usize = 7;
696
    const CONSTRAINT_SHIFT: usize = Self::KIND_SHIFT + Self::KIND_BITS;
697
    const CONSTRAINT_MASK: u64 = (1 << Self::CONSTRAINT_BITS) - 1;
698
699
    const TOTAL_BITS: usize = Self::CONSTRAINT_SHIFT + Self::CONSTRAINT_BITS;
700
701
    /// Construct a new operand.
702
    #[inline(always)]
703
23.4M
    pub fn new(
704
23.4M
        vreg: VReg,
705
23.4M
        constraint: OperandConstraint,
706
23.4M
        kind: OperandKind,
707
23.4M
        pos: OperandPos,
708
23.4M
    ) -> Self {
709
23.4M
        let constraint_field = match constraint {
710
14.9M
            OperandConstraint::Any => 0,
711
7.10M
            OperandConstraint::Reg => 1,
712
0
            OperandConstraint::Stack => 2,
713
676k
            OperandConstraint::FixedReg(preg) => {
714
676k
                debug_assert_eq!(preg.class(), vreg.class());
715
676k
                0b1000000 | preg.hw_enc() as u64
716
            }
717
709k
            OperandConstraint::Reuse(which) => {
718
709k
                debug_assert!(which <= 0b11111);
719
709k
                0b0100000 | which as u64
720
            }
721
0
            OperandConstraint::Limit(max) => {
722
0
                assert!(max.is_power_of_two());
723
0
                assert!(
724
0
                    max <= PReg::MAX + 1,
725
                    "limit is larger than the allowed register encoding"
726
                );
727
0
                let log2 = max.ilog2();
728
0
                debug_assert!(log2 <= 0b1111);
729
0
                0b0010000 | log2 as u64
730
            }
731
        };
732
23.4M
        let class_field = vreg.class() as u8 as u64;
733
23.4M
        let pos_field = pos as u8 as u64;
734
23.4M
        let kind_field = kind as u8 as u64;
735
23.4M
        Operand {
736
23.4M
            bits: ((vreg.vreg() as u64) << Self::VREG_SHIFT)
737
23.4M
                | (class_field << Self::CLASS_SHIFT)
738
23.4M
                | (pos_field << Self::POS_SHIFT)
739
23.4M
                | (kind_field << Self::KIND_SHIFT)
740
23.4M
                | (constraint_field << Self::CONSTRAINT_SHIFT),
741
23.4M
        }
742
23.4M
    }
743
744
    /// Create an `Operand` that designates a use of a VReg that must
745
    /// be in a register, and that is used at the "before" point,
746
    /// i.e., can be overwritten by a result.
747
    #[inline(always)]
748
0
    pub fn reg_use(vreg: VReg) -> Self {
749
0
        Operand::new(
750
0
            vreg,
751
0
            OperandConstraint::Reg,
752
0
            OperandKind::Use,
753
0
            OperandPos::Early,
754
        )
755
0
    }
756
757
    /// Create an `Operand` that designates a use of a VReg that must
758
    /// be in a register, and that is used up until the "after" point,
759
    /// i.e., must not conflict with any results.
760
    #[inline(always)]
761
0
    pub fn reg_use_at_end(vreg: VReg) -> Self {
762
0
        Operand::new(
763
0
            vreg,
764
0
            OperandConstraint::Reg,
765
0
            OperandKind::Use,
766
0
            OperandPos::Late,
767
        )
768
0
    }
769
770
    /// Create an `Operand` that designates a definition of a VReg
771
    /// that must be in a register, and that occurs at the "after"
772
    /// point, i.e. may reuse a register that carried a use into this
773
    /// instruction.
774
    #[inline(always)]
775
0
    pub fn reg_def(vreg: VReg) -> Self {
776
0
        Operand::new(
777
0
            vreg,
778
0
            OperandConstraint::Reg,
779
0
            OperandKind::Def,
780
0
            OperandPos::Late,
781
        )
782
0
    }
783
784
    /// Create an `Operand` that designates a definition of a VReg
785
    /// that must be in a register, and that occurs early at the
786
    /// "before" point, i.e., must not conflict with any input to the
787
    /// instruction.
788
    ///
789
    /// Note that the register allocator will ensure that such an
790
    /// early-def operand is live throughout the instruction, i.e., also
791
    /// at the after-point. Hence it will also avoid conflicts with all
792
    /// outputs to the instruction. As such, early defs are appropriate
793
    /// for use as "temporary registers" that an instruction can use
794
    /// throughout its execution separately from the inputs and outputs.
795
    #[inline(always)]
796
0
    pub fn reg_def_at_start(vreg: VReg) -> Self {
797
0
        Operand::new(
798
0
            vreg,
799
0
            OperandConstraint::Reg,
800
0
            OperandKind::Def,
801
0
            OperandPos::Early,
802
        )
803
0
    }
804
805
    /// Create an `Operand` that designates a def (and use) of a
806
    /// temporary *within* the instruction. This register is assumed
807
    /// to be written by the instruction, and will not conflict with
808
    /// any input or output, but should not be used after the
809
    /// instruction completes.
810
    ///
811
    /// Note that within a single instruction, the dedicated scratch
812
    /// register (as specified in the `MachineEnv`) is also always
813
    /// available for use. The register allocator may use the register
814
    /// *between* instructions in order to implement certain sequences
815
    /// of moves, but will never hold a value live in the scratch
816
    /// register across an instruction.
817
    #[inline(always)]
818
0
    pub fn reg_temp(vreg: VReg) -> Self {
819
        // For now a temp is equivalent to a def-at-start operand,
820
        // which gives the desired semantics but does not enforce the
821
        // "not reused later" constraint.
822
0
        Operand::new(
823
0
            vreg,
824
0
            OperandConstraint::Reg,
825
0
            OperandKind::Def,
826
0
            OperandPos::Early,
827
        )
828
0
    }
829
830
    /// Create an `Operand` that designates a def of a vreg that must
831
    /// reuse the register assigned to an input to the
832
    /// instruction. The input is identified by `idx` (is the `idx`th
833
    /// `Operand` for the instruction) and must be constraint to a
834
    /// register, i.e., be the result of `Operand::reg_use(vreg)`.
835
    #[inline(always)]
836
0
    pub fn reg_reuse_def(vreg: VReg, idx: usize) -> Self {
837
0
        Operand::new(
838
0
            vreg,
839
0
            OperandConstraint::Reuse(idx),
840
0
            OperandKind::Def,
841
0
            OperandPos::Late,
842
        )
843
0
    }
844
845
    /// Create an `Operand` that designates a use of a vreg and
846
    /// ensures that it is placed in the given, fixed PReg at the
847
    /// use. It is guaranteed that the `Allocation` resulting for this
848
    /// operand will be `preg`.
849
    #[inline(always)]
850
0
    pub fn reg_fixed_use(vreg: VReg, preg: PReg) -> Self {
851
0
        Operand::new(
852
0
            vreg,
853
0
            OperandConstraint::FixedReg(preg),
854
0
            OperandKind::Use,
855
0
            OperandPos::Early,
856
        )
857
0
    }
858
859
    /// Create an `Operand` that designates a def of a vreg and
860
    /// ensures that it is placed in the given, fixed PReg at the
861
    /// def. It is guaranteed that the `Allocation` resulting for this
862
    /// operand will be `preg`.
863
    #[inline(always)]
864
0
    pub fn reg_fixed_def(vreg: VReg, preg: PReg) -> Self {
865
0
        Operand::new(
866
0
            vreg,
867
0
            OperandConstraint::FixedReg(preg),
868
0
            OperandKind::Def,
869
0
            OperandPos::Late,
870
        )
871
0
    }
872
873
    /// Same as `reg_fixed_use` but at `OperandPos::Late`.
874
    #[inline(always)]
875
0
    pub fn reg_fixed_use_at_end(vreg: VReg, preg: PReg) -> Self {
876
0
        Operand::new(
877
0
            vreg,
878
0
            OperandConstraint::FixedReg(preg),
879
0
            OperandKind::Use,
880
0
            OperandPos::Late,
881
        )
882
0
    }
883
884
    /// Same as `reg_fixed_def` but at `OperandPos::Early`.
885
    #[inline(always)]
886
0
    pub fn reg_fixed_def_at_start(vreg: VReg, preg: PReg) -> Self {
887
0
        Operand::new(
888
0
            vreg,
889
0
            OperandConstraint::FixedReg(preg),
890
0
            OperandKind::Def,
891
0
            OperandPos::Early,
892
        )
893
0
    }
894
895
    /// Create an `Operand` that designates a use of a vreg and places
896
    /// no constraints on its location (i.e., it can be allocated into
897
    /// either a register or on the stack).
898
    #[inline(always)]
899
0
    pub fn any_use(vreg: VReg) -> Self {
900
0
        Operand::new(
901
0
            vreg,
902
0
            OperandConstraint::Any,
903
0
            OperandKind::Use,
904
0
            OperandPos::Early,
905
        )
906
0
    }
907
908
    /// Create an `Operand` that designates a def of a vreg and places
909
    /// no constraints on its location (i.e., it can be allocated into
910
    /// either a register or on the stack).
911
    #[inline(always)]
912
5.34M
    pub fn any_def(vreg: VReg) -> Self {
913
5.34M
        Operand::new(
914
5.34M
            vreg,
915
5.34M
            OperandConstraint::Any,
916
5.34M
            OperandKind::Def,
917
5.34M
            OperandPos::Late,
918
        )
919
5.34M
    }
920
921
    /// Create an `Operand` that always results in an assignment to the
922
    /// given fixed `preg`, *without* tracking liveranges in that
923
    /// `preg`. Must only be used for non-allocatable registers.
924
    #[inline(always)]
925
103k
    pub fn fixed_nonallocatable(preg: PReg) -> Self {
926
103k
        Operand::new(
927
103k
            VReg::new(VReg::MAX, preg.class()),
928
103k
            OperandConstraint::FixedReg(preg),
929
103k
            OperandKind::Use,
930
103k
            OperandPos::Early,
931
        )
932
103k
    }
933
934
    /// Get the virtual register designated by an operand. Every
935
    /// operand must name some virtual register, even if it constrains
936
    /// the operand to a fixed physical register as well; the vregs
937
    /// are used to track dataflow.
938
    #[inline(always)]
939
430M
    pub fn vreg(self) -> VReg {
940
430M
        let vreg_idx = ((self.bits >> Self::VREG_SHIFT) & Self::VREG_MASK) as usize;
941
430M
        VReg::new(vreg_idx, self.class())
942
430M
    }
943
944
    /// Get the register class used by this operand.
945
    #[inline(always)]
946
449M
    pub fn class(self) -> RegClass {
947
449M
        let class_field = (self.bits >> Self::CLASS_SHIFT) & Self::CLASS_MASK;
948
449M
        match class_field {
949
137M
            0 => RegClass::Int,
950
179M
            1 => RegClass::Float,
951
133M
            2 => RegClass::Vector,
952
0
            _ => unreachable!(),
953
        }
954
449M
    }
955
956
    /// Get the "kind" of this operand: a definition (write) or a use
957
    /// (read).
958
    #[inline(always)]
959
293M
    pub fn kind(self) -> OperandKind {
960
293M
        let kind_field = (self.bits >> Self::KIND_SHIFT) & Self::KIND_MASK;
961
293M
        match kind_field {
962
160M
            0 => OperandKind::Def,
963
133M
            1 => OperandKind::Use,
964
0
            _ => unreachable!(),
965
        }
966
293M
    }
967
968
    /// Get the "position" of this operand, i.e., where its read
969
    /// and/or write occurs: either before the instruction executes,
970
    /// or after it does. Ordinarily, uses occur at "before" and defs
971
    /// at "after", though there are cases where this is not true.
972
    #[inline(always)]
973
242M
    pub fn pos(self) -> OperandPos {
974
242M
        let pos_field = (self.bits >> Self::POS_SHIFT) & Self::POS_MASK;
975
242M
        match pos_field {
976
159M
            0 => OperandPos::Early,
977
82.7M
            1 => OperandPos::Late,
978
0
            _ => unreachable!(),
979
        }
980
242M
    }
981
982
    /// Get the "constraint" of this operand, i.e., what requirements
983
    /// its allocation must fulfill.
984
    #[inline(always)]
985
512M
    pub fn constraint(self) -> OperandConstraint {
986
512M
        let constraint_field =
987
512M
            ((self.bits >> Self::CONSTRAINT_SHIFT) & Self::CONSTRAINT_MASK) as usize;
988
512M
        if constraint_field & 0b1000000 != 0 {
989
15.3M
            OperandConstraint::FixedReg(PReg::new(constraint_field & 0b0111111, self.class()))
990
497M
        } else if constraint_field & 0b0100000 != 0 {
991
16.2M
            OperandConstraint::Reuse(constraint_field & 0b0011111)
992
481M
        } else if constraint_field & 0b0010000 != 0 {
993
0
            OperandConstraint::Limit(1 << (constraint_field & 0b0001111))
994
        } else {
995
481M
            match constraint_field {
996
335M
                0 => OperandConstraint::Any,
997
145M
                1 => OperandConstraint::Reg,
998
0
                2 => OperandConstraint::Stack,
999
0
                _ => unreachable!(),
1000
            }
1001
        }
1002
512M
    }
1003
1004
    /// If this operand is for a fixed non-allocatable register (see
1005
    /// [`Operand::fixed_nonallocatable`]), then returns the physical register that it will
1006
    /// be assigned to.
1007
    #[inline(always)]
1008
215M
    pub fn as_fixed_nonallocatable(self) -> Option<PReg> {
1009
215M
        match self.constraint() {
1010
6.07M
            OperandConstraint::FixedReg(preg) if self.vreg().vreg() == VReg::MAX => Some(preg),
1011
214M
            _ => None,
1012
        }
1013
215M
    }
1014
1015
    /// Get the raw 64-bit encoding of this operand's fields.
1016
    #[inline(always)]
1017
0
    pub fn bits(self) -> u64 {
1018
0
        self.bits
1019
0
    }
1020
1021
    /// Construct an `Operand` from the raw 64-bit encoding returned
1022
    /// from `bits()`.
1023
    #[inline(always)]
1024
0
    pub fn from_bits(bits: u64) -> Self {
1025
0
        debug_assert_eq!(bits >> Self::TOTAL_BITS, 0);
1026
0
        Operand { bits }
1027
0
    }
1028
}
1029
1030
impl core::fmt::Debug for Operand {
1031
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1032
0
        core::fmt::Display::fmt(self, f)
1033
0
    }
1034
}
1035
1036
impl core::fmt::Display for Operand {
1037
1.20M
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1038
1.20M
        if let Some(preg) = self.as_fixed_nonallocatable() {
1039
3.48k
            return write!(f, "Fixed: {preg}");
1040
1.20M
        }
1041
1.20M
        match (self.kind(), self.pos()) {
1042
            (OperandKind::Def, OperandPos::Late) | (OperandKind::Use, OperandPos::Early) => {
1043
1.11M
                write!(f, "{:?}", self.kind())?;
1044
            }
1045
            _ => {
1046
90.2k
                write!(f, "{:?}@{:?}", self.kind(), self.pos())?;
1047
            }
1048
        }
1049
1.20M
        write!(
1050
1.20M
            f,
1051
            ": {}{} {}",
1052
1.20M
            self.vreg(),
1053
1.20M
            match self.class() {
1054
346k
                RegClass::Int => "i",
1055
531k
                RegClass::Float => "f",
1056
323k
                RegClass::Vector => "v",
1057
            },
1058
1.20M
            self.constraint()
1059
        )
1060
1.20M
    }
1061
}
1062
1063
/// An Allocation represents the end result of regalloc for an
1064
/// Operand.
1065
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1066
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1067
pub struct Allocation {
1068
    /// Bit-pack in 32 bits.
1069
    ///
1070
    /// kind:3 unused:1 index:28
1071
    bits: u32,
1072
}
1073
1074
impl core::fmt::Debug for Allocation {
1075
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1076
0
        core::fmt::Display::fmt(self, f)
1077
0
    }
1078
}
1079
1080
impl core::fmt::Display for Allocation {
1081
3.16M
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1082
3.16M
        match self.kind() {
1083
0
            AllocationKind::None => write!(f, "none"),
1084
2.82M
            AllocationKind::Reg => write!(f, "{}", self.as_reg().unwrap()),
1085
346k
            AllocationKind::Stack => write!(f, "{}", self.as_stack().unwrap()),
1086
        }
1087
3.16M
    }
1088
}
1089
1090
impl Allocation {
1091
    /// Construct a new Allocation.
1092
    #[inline(always)]
1093
89.6M
    pub(crate) fn new(kind: AllocationKind, index: usize) -> Self {
1094
89.6M
        debug_assert!(index < (1 << 28));
1095
89.6M
        Self {
1096
89.6M
            bits: ((kind as u8 as u32) << 29) | (index as u32),
1097
89.6M
        }
1098
89.6M
    }
1099
1100
    /// Get the "none" allocation, which is distinct from the other
1101
    /// possibilities and is used to initialize data structures.
1102
    #[inline(always)]
1103
71.5M
    pub fn none() -> Allocation {
1104
71.5M
        Allocation::new(AllocationKind::None, 0)
1105
71.5M
    }
1106
1107
    /// Create an allocation into a register.
1108
    #[inline(always)]
1109
17.9M
    pub fn reg(preg: PReg) -> Allocation {
1110
17.9M
        Allocation::new(AllocationKind::Reg, preg.index())
1111
17.9M
    }
1112
1113
    /// Create an allocation into a spillslot.
1114
    #[inline(always)]
1115
141k
    pub fn stack(slot: SpillSlot) -> Allocation {
1116
141k
        Allocation::new(AllocationKind::Stack, slot.bits as usize)
1117
141k
    }
1118
1119
    /// Get the allocation's "kind": none, register, or stack (spillslot).
1120
    #[inline(always)]
1121
22.9M
    pub fn kind(self) -> AllocationKind {
1122
22.9M
        match (self.bits >> 29) & 7 {
1123
1.82M
            0 => AllocationKind::None,
1124
18.7M
            1 => AllocationKind::Reg,
1125
2.33M
            2 => AllocationKind::Stack,
1126
0
            _ => unreachable!(),
1127
        }
1128
22.9M
    }
1129
1130
    /// Is the allocation "none"?
1131
    #[inline(always)]
1132
10.9k
    pub fn is_none(self) -> bool {
1133
10.9k
        self.kind() == AllocationKind::None
1134
10.9k
    }
1135
1136
    /// Is the allocation not "none"?
1137
    #[inline(always)]
1138
1.81M
    pub fn is_some(self) -> bool {
1139
1.81M
        self.kind() != AllocationKind::None
1140
1.81M
    }
1141
1142
    /// Is the allocation a register?
1143
    #[inline(always)]
1144
3.04M
    pub fn is_reg(self) -> bool {
1145
3.04M
        self.kind() == AllocationKind::Reg
1146
3.04M
    }
1147
1148
    /// Is the allocation on the stack (a spillslot)?
1149
    #[inline(always)]
1150
418k
    pub fn is_stack(self) -> bool {
1151
418k
        self.kind() == AllocationKind::Stack
1152
418k
    }
1153
1154
    /// Get the index of the spillslot or register. If register, this
1155
    /// is an index that can be used by `PReg::from_index()`.
1156
    #[inline(always)]
1157
13.7M
    pub fn index(self) -> usize {
1158
13.7M
        (self.bits & ((1 << 28) - 1)) as usize
1159
13.7M
    }
1160
1161
    /// Get the allocation as a physical register, if any.
1162
    #[inline(always)]
1163
14.1M
    pub fn as_reg(self) -> Option<PReg> {
1164
14.1M
        if self.kind() == AllocationKind::Reg {
1165
13.3M
            Some(PReg::from_index(self.index()))
1166
        } else {
1167
731k
            None
1168
        }
1169
14.1M
    }
1170
1171
    /// Get the allocation as a spillslot, if any.
1172
    #[inline(always)]
1173
346k
    pub fn as_stack(self) -> Option<SpillSlot> {
1174
346k
        if self.kind() == AllocationKind::Stack {
1175
346k
            Some(SpillSlot {
1176
346k
                bits: self.index() as u32,
1177
346k
            })
1178
        } else {
1179
0
            None
1180
        }
1181
346k
    }
1182
1183
    /// Get the raw bits for the packed encoding of this allocation.
1184
    #[inline(always)]
1185
4.35M
    pub fn bits(self) -> u32 {
1186
4.35M
        self.bits
1187
4.35M
    }
1188
1189
    /// Construct an allocation from its packed encoding.
1190
    #[inline(always)]
1191
0
    pub fn from_bits(bits: u32) -> Self {
1192
0
        debug_assert!(bits >> 29 >= 5);
1193
0
        Self { bits }
1194
0
    }
1195
}
1196
1197
/// An allocation is one of two "kinds" (or "none"): register or
1198
/// spillslot/stack.
1199
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1200
#[repr(u8)]
1201
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1202
pub enum AllocationKind {
1203
    None = 0,
1204
    Reg = 1,
1205
    Stack = 2,
1206
}
1207
1208
/// A trait defined by the regalloc client to provide access to its
1209
/// machine-instruction / CFG representation.
1210
///
1211
/// (This trait's design is inspired by, and derives heavily from, the
1212
/// trait of the same name in regalloc.rs.)
1213
///
1214
/// The ids used in [`Block`] and [`VReg`] must start their numbering
1215
/// at zero and be sequential.
1216
pub trait Function {
1217
    // -------------
1218
    // CFG traversal
1219
    // -------------
1220
1221
    /// How many instructions are there?
1222
    fn num_insts(&self) -> usize;
1223
1224
    /// How many blocks are there?
1225
    fn num_blocks(&self) -> usize;
1226
1227
    /// Get the index of the entry block.
1228
    fn entry_block(&self) -> Block;
1229
1230
    /// Provide the range of instruction indices contained in each block.
1231
    fn block_insns(&self, block: Block) -> InstRange;
1232
1233
    /// Get CFG successors for a given block.
1234
    fn block_succs(&self, block: Block) -> &[Block];
1235
1236
    /// Get the CFG predecessors for a given block.
1237
    fn block_preds(&self, block: Block) -> &[Block];
1238
1239
    /// Get the block parameters for a given block.
1240
    fn block_params(&self, block: Block) -> &[VReg];
1241
1242
    /// Determine whether an instruction is a return instruction.
1243
    fn is_ret(&self, insn: Inst) -> bool;
1244
1245
    /// Determine whether an instruction is the end-of-block
1246
    /// branch.
1247
    fn is_branch(&self, insn: Inst) -> bool;
1248
1249
    /// If `insn` is a branch at the end of `block`, returns the
1250
    /// outgoing blockparam arguments for the given successor. The
1251
    /// number of arguments must match the number incoming blockparams
1252
    /// for each respective successor block.
1253
    fn branch_blockparams(&self, block: Block, insn: Inst, succ_idx: usize) -> &[VReg];
1254
1255
    // --------------------------
1256
    // Instruction register slots
1257
    // --------------------------
1258
1259
    /// Get the Operands for an instruction.
1260
    fn inst_operands(&self, insn: Inst) -> &[Operand];
1261
1262
    /// Get the clobbers for an instruction; these are the registers
1263
    /// that, after the instruction has executed, hold values that are
1264
    /// arbitrary, separately from the usual outputs to the
1265
    /// instruction. It is invalid to read a register that has been
1266
    /// clobbered; the register allocator is free to assume that
1267
    /// clobbered registers are filled with garbage and available for
1268
    /// reuse. It will avoid storing any value in a clobbered register
1269
    /// that must be live across the instruction.
1270
    ///
1271
    /// Another way of seeing this is that a clobber is equivalent to
1272
    /// a "late def" of a fresh vreg that is not used anywhere else
1273
    /// in the program, with a fixed-register constraint that places
1274
    /// it in a given PReg chosen by the client prior to regalloc.
1275
    ///
1276
    /// Every register written by an instruction must either
1277
    /// correspond to (be assigned to) an Operand of kind `Def`, or
1278
    /// else must be a "clobber".
1279
    ///
1280
    /// This can be used to, for example, describe ABI-specified
1281
    /// registers that are not preserved by a call instruction, or
1282
    /// fixed physical registers written by an instruction but not
1283
    /// used as a vreg output, or fixed physical registers used as
1284
    /// temps within an instruction out of necessity.
1285
    ///
1286
    /// Note that clobbers and defs and late-uses must not collide: it
1287
    /// is illegal to name the same physical register both as a clobber
1288
    /// and in a fixed-register constraint on a def or late use.
1289
    /// Internally, clobbers are modeled as defs (of throwaway vregs) at
1290
    /// the instruction's late-point constrained to the named register.
1291
    fn inst_clobbers(&self, insn: Inst) -> PRegSet;
1292
1293
    /// Get the number of `VReg` in use in this function.
1294
    fn num_vregs(&self) -> usize;
1295
1296
    /// Get the VRegs for which we should generate value-location
1297
    /// metadata for debugging purposes. This can be used to generate
1298
    /// e.g. DWARF with valid prgram-point ranges for each value
1299
    /// expression in a way that is more efficient than a post-hoc
1300
    /// analysis of the allocator's output.
1301
    ///
1302
    /// Each tuple is (vreg, inclusive_start, exclusive_end,
1303
    /// label). In the `Output` there will be (label, inclusive_start,
1304
    /// exclusive_end, alloc)` tuples. The ranges may not exactly
1305
    /// match -- specifically, the returned metadata may cover only a
1306
    /// subset of the requested ranges -- if the value is not live for
1307
    /// the entire requested ranges.
1308
    ///
1309
    /// The instruction indices imply a program point just *before*
1310
    /// the instruction.
1311
    ///
1312
    /// Precondition: we require this slice to be sorted by vreg.
1313
0
    fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] {
1314
0
        &[]
1315
0
    }
1316
1317
    // --------------
1318
    // Spills/reloads
1319
    // --------------
1320
1321
    /// How many logical spill slots does the given regclass require?  E.g., on
1322
    /// a 64-bit machine, spill slots may nominally be 64-bit words, but a
1323
    /// 128-bit vector value will require two slots.  The regalloc will always
1324
    /// align on this size.
1325
    ///
1326
    /// (This trait method's design and doc text derives from
1327
    /// regalloc.rs' trait of the same name.)
1328
    fn spillslot_size(&self, regclass: RegClass) -> usize;
1329
1330
    /// When providing a spillslot number for a multi-slot spillslot,
1331
    /// do we provide the first or the last? This is usually related
1332
    /// to which direction the stack grows and different clients may
1333
    /// have different preferences.
1334
140k
    fn multi_spillslot_named_by_last_slot(&self) -> bool {
1335
140k
        false
1336
140k
    }
1337
1338
    // -----------
1339
    // Misc config
1340
    // -----------
1341
1342
    /// Allow a single instruction to define a vreg multiple times. If
1343
    /// allowed, the semantics are as if the definition occurs only
1344
    /// once, and all defs will get the same alloc. This flexibility is
1345
    /// meant to allow the embedder to more easily aggregate operands
1346
    /// together in macro/pseudoinstructions, or e.g. add additional
1347
    /// clobbered vregs without taking care to deduplicate. This may be
1348
    /// particularly useful when referring to physical registers via
1349
    /// pinned vregs. It is optional functionality because a strict mode
1350
    /// (at most one def per vreg) is also useful for finding bugs in
1351
    /// other applications.
1352
22.5M
    fn allow_multiple_vreg_defs(&self) -> bool {
1353
22.5M
        false
1354
22.5M
    }
1355
}
1356
1357
/// A position before or after an instruction at which we can make an
1358
/// edit.
1359
///
1360
/// Note that this differs from `OperandPos` in that the former
1361
/// describes specifically a constraint on an operand, while this
1362
/// describes a program point. `OperandPos` could grow more options in
1363
/// the future, for example if we decide that an "early write" or
1364
/// "late read" phase makes sense, while `InstPosition` will always
1365
/// describe these two insertion points.
1366
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1367
#[repr(u8)]
1368
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1369
pub enum InstPosition {
1370
    Before = 0,
1371
    After = 1,
1372
}
1373
1374
/// A program point: a single point before or after a given instruction.
1375
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1376
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1377
pub struct ProgPoint {
1378
    bits: u32,
1379
}
1380
1381
impl core::fmt::Debug for ProgPoint {
1382
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1383
0
        write!(
1384
0
            f,
1385
            "progpoint{}{}",
1386
0
            self.inst().index(),
1387
0
            match self.pos() {
1388
0
                InstPosition::Before => "-pre",
1389
0
                InstPosition::After => "-post",
1390
            }
1391
        )
1392
0
    }
1393
}
1394
1395
impl ProgPoint {
1396
    /// Create a new ProgPoint before or after the given instruction.
1397
    #[inline(always)]
1398
135M
    pub fn new(inst: Inst, pos: InstPosition) -> Self {
1399
135M
        let bits = ((inst.0 as u32) << 1) | (pos as u8 as u32);
1400
135M
        Self { bits }
1401
135M
    }
1402
1403
    /// Create a new ProgPoint before the given instruction.
1404
    #[inline(always)]
1405
106M
    pub fn before(inst: Inst) -> Self {
1406
106M
        Self::new(inst, InstPosition::Before)
1407
106M
    }
1408
1409
    /// Create a new ProgPoint after the given instruction.
1410
    #[inline(always)]
1411
28.8M
    pub fn after(inst: Inst) -> Self {
1412
28.8M
        Self::new(inst, InstPosition::After)
1413
28.8M
    }
1414
1415
    /// Get the instruction that this ProgPoint is before or after.
1416
    #[inline(always)]
1417
166M
    pub fn inst(self) -> Inst {
1418
        // Cast to i32 to do an arithmetic right-shift, which will
1419
        // preserve an `Inst::invalid()` (which is -1, or all-ones).
1420
166M
        Inst::new(((self.bits as i32) >> 1) as usize)
1421
166M
    }
1422
1423
    /// Get the "position" (Before or After) relative to the
1424
    /// instruction.
1425
    #[inline(always)]
1426
54.5M
    pub fn pos(self) -> InstPosition {
1427
54.5M
        match self.bits & 1 {
1428
31.6M
            0 => InstPosition::Before,
1429
22.9M
            1 => InstPosition::After,
1430
0
            _ => unreachable!(),
1431
        }
1432
54.5M
    }
1433
1434
    /// Get the "next" program point: for After, this is the Before of
1435
    /// the next instruction, while for Before, this is After of the
1436
    /// same instruction.
1437
    #[inline(always)]
1438
42.2M
    pub fn next(self) -> ProgPoint {
1439
42.2M
        Self {
1440
42.2M
            bits: self.bits + 1,
1441
42.2M
        }
1442
42.2M
    }
1443
1444
    /// Get the "previous" program point, the inverse of `.next()`
1445
    /// above.
1446
    #[inline(always)]
1447
650k
    pub fn prev(self) -> ProgPoint {
1448
650k
        Self {
1449
650k
            bits: self.bits - 1,
1450
650k
        }
1451
650k
    }
1452
1453
    /// Convert to a raw encoding in 32 bits.
1454
    #[inline(always)]
1455
543M
    pub fn to_index(self) -> u32 {
1456
543M
        self.bits
1457
543M
    }
1458
1459
    /// Construct from the raw 32-bit encoding.
1460
    #[inline(always)]
1461
60.3M
    pub fn from_index(index: u32) -> Self {
1462
60.3M
        Self { bits: index }
1463
60.3M
    }
1464
1465
    #[inline(always)]
1466
0
    pub fn invalid() -> Self {
1467
0
        Self::before(Inst::new(usize::MAX))
1468
0
    }
1469
}
1470
1471
/// An instruction to insert into the program to perform some data movement.
1472
#[derive(Clone, Debug)]
1473
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1474
pub enum Edit {
1475
    /// Move one allocation to another. Each allocation may be a
1476
    /// register or a stack slot (spillslot). However, stack-to-stack
1477
    /// moves will never be generated.
1478
    ///
1479
    /// `Move` edits will be generated even if src and dst allocation
1480
    /// are the same if the vreg changes; this allows proper metadata
1481
    /// tracking even when moves are elided.
1482
    Move { from: Allocation, to: Allocation },
1483
}
1484
1485
/// Wrapper around either an original instruction or an inserted edit.
1486
#[derive(Clone, Debug)]
1487
pub enum InstOrEdit<'a> {
1488
    Inst(Inst),
1489
    Edit(&'a Edit),
1490
}
1491
1492
/// Iterator over the instructions and edits in a block.
1493
pub struct OutputIter<'a> {
1494
    /// List of edits starting at the first for the current block.
1495
    edits: &'a [(ProgPoint, Edit)],
1496
1497
    /// Remaining instructions in the current block.
1498
    inst_range: InstRange,
1499
}
1500
1501
impl<'a> Iterator for OutputIter<'a> {
1502
    type Item = InstOrEdit<'a>;
1503
1504
5.03M
    fn next(&mut self) -> Option<InstOrEdit<'a>> {
1505
        // There can't be any edits after the last instruction in a block, so
1506
        // we don't need to worry about that case.
1507
5.03M
        if self.inst_range.len() == 0 {
1508
403k
            return None;
1509
4.62M
        }
1510
1511
        // Return any edits that happen before the next instruction first.
1512
4.62M
        let next_inst = self.inst_range.first();
1513
4.62M
        if let Some((edit, remaining_edits)) = self.edits.split_first() {
1514
3.67M
            if edit.0 <= ProgPoint::before(next_inst) {
1515
957k
                self.edits = remaining_edits;
1516
957k
                return Some(InstOrEdit::Edit(&edit.1));
1517
2.71M
            }
1518
950k
        }
1519
1520
3.66M
        self.inst_range = self.inst_range.rest();
1521
3.66M
        Some(InstOrEdit::Inst(next_inst))
1522
5.03M
    }
1523
}
1524
1525
/// A machine environment tells the register allocator which registers
1526
/// are available to allocate and what register may be used as a
1527
/// scratch register for each class, and some other miscellaneous info
1528
/// as well.
1529
#[derive(Clone, Debug)]
1530
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1531
pub struct MachineEnv {
1532
    /// Preferred physical registers for each class. These are the
1533
    /// registers that will be allocated first, if free.
1534
    ///
1535
    /// If an explicit scratch register is provided in `scratch_by_class` then
1536
    /// it must not appear in this list.
1537
    pub preferred_regs_by_class: [PRegSet; 3],
1538
1539
    /// Non-preferred physical registers for each class. These are the
1540
    /// registers that will be allocated if a preferred register is
1541
    /// not available; using one of these is considered suboptimal,
1542
    /// but still better than spilling.
1543
    ///
1544
    /// If an explicit scratch register is provided in `scratch_by_class` then
1545
    /// it must not appear in this list.
1546
    pub non_preferred_regs_by_class: [PRegSet; 3],
1547
1548
    /// Optional dedicated scratch register per class. This is needed to perform
1549
    /// moves between registers when cyclic move patterns occur. The
1550
    /// register should not be placed in either the preferred or
1551
    /// non-preferred list (i.e., it is not otherwise allocatable).
1552
    ///
1553
    /// Note that the register allocator will freely use this register
1554
    /// between instructions, but *within* the machine code generated
1555
    /// by a single (regalloc-level) instruction, the client is free
1556
    /// to use the scratch register. E.g., if one "instruction" causes
1557
    /// the emission of two machine-code instructions, this lowering
1558
    /// can use the scratch register between them.
1559
    ///
1560
    /// If a scratch register is not provided then the register allocator will
1561
    /// automatically allocate one as needed, spilling a value to the stack if
1562
    /// necessary.
1563
    pub scratch_by_class: [Option<PReg>; 3],
1564
1565
    /// Some `PReg`s can be designated as locations on the stack rather than
1566
    /// actual registers. These can be used to tell the register allocator about
1567
    /// pre-defined stack slots used for function arguments and return values.
1568
    ///
1569
    /// `PReg`s in this list cannot be used as an allocatable or scratch
1570
    /// register.
1571
    pub fixed_stack_slots: Vec<PReg>,
1572
}
1573
1574
/// The output of the register allocator.
1575
#[derive(Clone, Debug, Default)]
1576
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1577
pub struct Output {
1578
    /// How many spillslots are needed in the frame?
1579
    pub num_spillslots: usize,
1580
1581
    /// Edits (insertions or removals). Guaranteed to be sorted by
1582
    /// program point.
1583
    pub edits: Vec<(ProgPoint, Edit)>,
1584
1585
    /// Allocations for each operand. Mapping from instruction to
1586
    /// allocations provided by `inst_alloc_offsets` below.
1587
    pub allocs: Vec<Allocation>,
1588
1589
    /// Allocation offset in `allocs` for each instruction.
1590
    pub inst_alloc_offsets: Vec<u32>,
1591
1592
    /// Debug info: a labeled value (as applied to vregs by
1593
    /// `Function::debug_value_labels()` on the input side) is located
1594
    /// in the given allocation from the first program point
1595
    /// (inclusive) to the second (exclusive). Guaranteed to be sorted
1596
    /// by label and program point, and the ranges are guaranteed to
1597
    /// be disjoint.
1598
    pub debug_locations: Vec<(u32, ProgPoint, ProgPoint, Allocation)>,
1599
1600
    /// Internal stats from the allocator.
1601
    pub stats: ion::Stats,
1602
}
1603
1604
impl Output {
1605
    /// Get the allocations assigned to a given instruction.
1606
3.66M
    pub fn inst_allocs(&self, inst: Inst) -> &[Allocation] {
1607
3.66M
        let start = self.inst_alloc_offsets[inst.index()] as usize;
1608
3.66M
        let end = if inst.index() + 1 == self.inst_alloc_offsets.len() {
1609
10.0k
            self.allocs.len()
1610
        } else {
1611
3.65M
            self.inst_alloc_offsets[inst.index() + 1] as usize
1612
        };
1613
3.66M
        &self.allocs[start..end]
1614
3.66M
    }
1615
1616
    /// Returns an iterator over the instructions and edits in a block, in
1617
    /// order.
1618
403k
    pub fn block_insts_and_edits(&self, func: &impl Function, block: Block) -> OutputIter<'_> {
1619
403k
        let inst_range = func.block_insns(block);
1620
1621
403k
        let edit_idx = self
1622
403k
            .edits
1623
2.49M
            .binary_search_by(|&(pos, _)| {
1624
                // This predicate effectively searches for a point *just* before
1625
                // the first ProgPoint. This never returns Ordering::Equal, but
1626
                // binary_search_by returns the index of where it would have
1627
                // been inserted in Err.
1628
2.49M
                if pos < ProgPoint::before(inst_range.first()) {
1629
1.43M
                    core::cmp::Ordering::Less
1630
                } else {
1631
1.05M
                    core::cmp::Ordering::Greater
1632
                }
1633
2.49M
            })
1634
403k
            .unwrap_err();
1635
1636
403k
        let edits = &self.edits[edit_idx..];
1637
403k
        OutputIter { inst_range, edits }
1638
403k
    }
1639
}
1640
1641
/// An error that prevents allocation.
1642
#[derive(Clone, Debug)]
1643
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
1644
pub enum RegAllocError {
1645
    /// Critical edge is not split between given blocks.
1646
    CritEdge(Block, Block),
1647
    /// Invalid SSA for given vreg at given inst: multiple defs or
1648
    /// illegal use. `inst` may be `Inst::invalid()` if this concerns
1649
    /// a block param.
1650
    SSA(VReg, Inst),
1651
    /// Invalid basic block: does not end in branch/ret, or contains a
1652
    /// branch/ret in the middle, or the VReg ids do not start at zero
1653
    /// or aren't numbered sequentially.
1654
    BB(Block),
1655
    /// Invalid branch: operand count does not match sum of block
1656
    /// params of successor blocks, or the block ids do not start at
1657
    /// zero or aren't numbered sequentially.
1658
    Branch(Inst),
1659
    /// A VReg is live-in on entry; this is not allowed.
1660
    EntryLivein,
1661
    /// A branch has non-blockparam arg(s) and at least one of the
1662
    /// successor blocks has more than one predecessor, forcing
1663
    /// edge-moves before this branch. This is disallowed because it
1664
    /// places a use after the edge moves occur; insert an edge block
1665
    /// to avoid the situation.
1666
    DisallowedBranchArg(Inst),
1667
    /// Too many pinned VRegs + Reg-constrained Operands are live at
1668
    /// once, making allocation impossible.
1669
    TooManyLiveRegs,
1670
    /// Too many operands on a single instruction (beyond limit of
1671
    /// 2^16 - 1).
1672
    TooManyOperands,
1673
}
1674
1675
impl core::fmt::Display for RegAllocError {
1676
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1677
0
        write!(f, "{:?}", self)
1678
0
    }
1679
}
1680
1681
impl core::error::Error for RegAllocError {}
1682
1683
/// Run the allocator.
1684
0
pub fn run<F: Function>(
1685
0
    func: &F,
1686
0
    env: &MachineEnv,
1687
0
    options: &RegallocOptions,
1688
0
) -> Result<Output, RegAllocError> {
1689
0
    match options.algorithm {
1690
        Algorithm::Ion => {
1691
0
            let mut ctx = Ctx::default();
1692
0
            run_with_ctx(func, env, options, &mut ctx)?;
1693
0
            Ok(ctx.output)
1694
        }
1695
        Algorithm::Fastalloc => {
1696
0
            fastalloc::run(func, env, options.verbose_log, options.validate_ssa)
1697
        }
1698
    }
1699
0
}
1700
1701
/// Run the allocator with reusable context.
1702
///
1703
/// Return value points to `ctx.output` that can be alternatively `std::mem::take`n.
1704
0
pub fn run_with_ctx<'a, F: Function>(
1705
0
    func: &F,
1706
0
    env: &MachineEnv,
1707
0
    options: &RegallocOptions,
1708
0
    ctx: &'a mut Ctx,
1709
0
) -> Result<&'a Output, RegAllocError> {
1710
0
    match options.algorithm {
1711
0
        Algorithm::Ion => ion::run(func, env, ctx, options.verbose_log, options.validate_ssa)?,
1712
        Algorithm::Fastalloc => {
1713
0
            ctx.output = fastalloc::run(func, env, options.verbose_log, options.validate_ssa)?
1714
        }
1715
    }
1716
0
    Ok(&ctx.output)
1717
0
}
1718
1719
#[derive(Clone, Copy, Debug, Default)]
1720
pub enum Algorithm {
1721
    #[default]
1722
    Ion,
1723
    Fastalloc,
1724
}
1725
1726
/// Options for allocation.
1727
#[derive(Clone, Copy, Debug, Default)]
1728
pub struct RegallocOptions {
1729
    /// Add extra verbosity to debug logs.
1730
    pub verbose_log: bool,
1731
1732
    /// Run the SSA validator before allocating registers.
1733
    pub validate_ssa: bool,
1734
1735
    /// The register allocation algorithm to be used.
1736
    pub algorithm: Algorithm,
1737
}
1738
1739
pub(crate) trait VecExt<T> {
1740
    /// Fills `self` with `value` up to `len` and return the mutable slice to the values.
1741
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1742
    where
1743
        T: Clone;
1744
    /// Clears the `self` and returns a mutable reference to it.
1745
    fn cleared(&mut self) -> &mut Self;
1746
    /// Makes sure `self` is empty and has at least `cap` capacity.
1747
    fn preallocate(&mut self, cap: usize) -> &mut Self;
1748
}
1749
1750
impl<T> VecExt<T> for Vec<T> {
1751
134k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
134k
    where
1753
134k
        T: Clone,
1754
    {
1755
134k
        self.clear();
1756
134k
        self.resize(len, value);
1757
134k
        self
1758
134k
    }
<alloc::vec::Vec<core::option::Option<u32>> as regalloc2::VecExt<core::option::Option<u32>>>::repopulate
Line
Count
Source
1751
24.3k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
24.3k
    where
1753
24.3k
        T: Clone,
1754
    {
1755
24.3k
        self.clear();
1756
24.3k
        self.resize(len, value);
1757
24.3k
        self
1758
24.3k
    }
<alloc::vec::Vec<regalloc2::ProgPoint> as regalloc2::VecExt<regalloc2::ProgPoint>>::repopulate
Line
Count
Source
1751
24.3k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
24.3k
    where
1753
24.3k
        T: Clone,
1754
    {
1755
24.3k
        self.clear();
1756
24.3k
        self.resize(len, value);
1757
24.3k
        self
1758
24.3k
    }
<alloc::vec::Vec<regalloc2::index::Block> as regalloc2::VecExt<regalloc2::index::Block>>::repopulate
Line
Count
Source
1751
36.5k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
36.5k
    where
1753
36.5k
        T: Clone,
1754
    {
1755
36.5k
        self.clear();
1756
36.5k
        self.resize(len, value);
1757
36.5k
        self
1758
36.5k
    }
<alloc::vec::Vec<regalloc2::ion::data_structures::LiveRangeIndex> as regalloc2::VecExt<regalloc2::ion::data_structures::LiveRangeIndex>>::repopulate
Line
Count
Source
1751
12.1k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
12.1k
    where
1753
12.1k
        T: Clone,
1754
    {
1755
12.1k
        self.clear();
1756
12.1k
        self.resize(len, value);
1757
12.1k
        self
1758
12.1k
    }
<alloc::vec::Vec<bool> as regalloc2::VecExt<bool>>::repopulate
Line
Count
Source
1751
24.3k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
24.3k
    where
1753
24.3k
        T: Clone,
1754
    {
1755
24.3k
        self.clear();
1756
24.3k
        self.resize(len, value);
1757
24.3k
        self
1758
24.3k
    }
<alloc::vec::Vec<u32> as regalloc2::VecExt<u32>>::repopulate
Line
Count
Source
1751
12.1k
    fn repopulate(&mut self, len: usize, value: T) -> &mut [T]
1752
12.1k
    where
1753
12.1k
        T: Clone,
1754
    {
1755
12.1k
        self.clear();
1756
12.1k
        self.resize(len, value);
1757
12.1k
        self
1758
12.1k
    }
1759
1760
12.1k
    fn cleared(&mut self) -> &mut Self {
1761
12.1k
        self.clear();
1762
12.1k
        self
1763
12.1k
    }
1764
1765
85.2k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
85.2k
        self.clear();
1767
85.2k
        self.reserve(cap);
1768
85.2k
        self
1769
85.2k
    }
<alloc::vec::Vec<regalloc2::Allocation> as regalloc2::VecExt<regalloc2::Allocation>>::preallocate
Line
Count
Source
1765
12.1k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
12.1k
        self.clear();
1767
12.1k
        self.reserve(cap);
1768
12.1k
        self
1769
12.1k
    }
<alloc::vec::Vec<regalloc2::indexset::IndexSet> as regalloc2::VecExt<regalloc2::indexset::IndexSet>>::preallocate
Line
Count
Source
1765
24.3k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
24.3k
        self.clear();
1767
24.3k
        self.reserve(cap);
1768
24.3k
        self
1769
24.3k
    }
<alloc::vec::Vec<regalloc2::ion::data_structures::LiveBundle> as regalloc2::VecExt<regalloc2::ion::data_structures::LiveBundle>>::preallocate
Line
Count
Source
1765
12.1k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
12.1k
        self.clear();
1767
12.1k
        self.reserve(cap);
1768
12.1k
        self
1769
12.1k
    }
<alloc::vec::Vec<regalloc2::ion::data_structures::SpillSet> as regalloc2::VecExt<regalloc2::ion::data_structures::SpillSet>>::preallocate
Line
Count
Source
1765
12.1k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
12.1k
        self.clear();
1767
12.1k
        self.reserve(cap);
1768
12.1k
        self
1769
12.1k
    }
<alloc::vec::Vec<regalloc2::ion::data_structures::VRegData> as regalloc2::VecExt<regalloc2::ion::data_structures::VRegData>>::preallocate
Line
Count
Source
1765
12.1k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
12.1k
        self.clear();
1767
12.1k
        self.reserve(cap);
1768
12.1k
        self
1769
12.1k
    }
<alloc::vec::Vec<regalloc2::ion::data_structures::LiveRange> as regalloc2::VecExt<regalloc2::ion::data_structures::LiveRange>>::preallocate
Line
Count
Source
1765
12.1k
    fn preallocate(&mut self, cap: usize) -> &mut Self {
1766
12.1k
        self.clear();
1767
12.1k
        self.reserve(cap);
1768
12.1k
        self
1769
12.1k
    }
1770
}
1771
1772
#[derive(Debug, Clone, Default)]
1773
pub(crate) struct Bump(Rc<bumpalo::Bump>);
1774
1775
impl Bump {
1776
12.1k
    pub(crate) fn get_mut(&mut self) -> Option<&mut bumpalo::Bump> {
1777
12.1k
        Rc::get_mut(&mut self.0)
1778
12.1k
    }
1779
}
1780
1781
// Simply delegating because `Rc<bumpalo::Bump>` does not implement `Allocator`.
1782
unsafe impl allocator_api2::alloc::Allocator for Bump {
1783
36.2M
    fn allocate(
1784
36.2M
        &self,
1785
36.2M
        layout: core::alloc::Layout,
1786
36.2M
    ) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
1787
36.2M
        self.0.deref().allocate(layout)
1788
36.2M
    }
1789
1790
36.1M
    unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: core::alloc::Layout) {
1791
36.1M
        self.0.deref().deallocate(ptr, layout);
1792
36.1M
    }
1793
1794
0
    fn allocate_zeroed(
1795
0
        &self,
1796
0
        layout: core::alloc::Layout,
1797
0
    ) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
1798
0
        self.0.deref().allocate_zeroed(layout)
1799
0
    }
1800
1801
3.06M
    unsafe fn grow(
1802
3.06M
        &self,
1803
3.06M
        ptr: core::ptr::NonNull<u8>,
1804
3.06M
        old_layout: core::alloc::Layout,
1805
3.06M
        new_layout: core::alloc::Layout,
1806
3.06M
    ) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
1807
3.06M
        self.0.deref().grow(ptr, old_layout, new_layout)
1808
3.06M
    }
1809
1810
0
    unsafe fn grow_zeroed(
1811
0
        &self,
1812
0
        ptr: core::ptr::NonNull<u8>,
1813
0
        old_layout: core::alloc::Layout,
1814
0
        new_layout: core::alloc::Layout,
1815
0
    ) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
1816
0
        self.0.deref().grow_zeroed(ptr, old_layout, new_layout)
1817
0
    }
1818
1819
969k
    unsafe fn shrink(
1820
969k
        &self,
1821
969k
        ptr: core::ptr::NonNull<u8>,
1822
969k
        old_layout: core::alloc::Layout,
1823
969k
        new_layout: core::alloc::Layout,
1824
969k
    ) -> Result<core::ptr::NonNull<[u8]>, allocator_api2::alloc::AllocError> {
1825
969k
        self.0.deref().shrink(ptr, old_layout, new_layout)
1826
969k
    }
1827
}
1828
1829
#[cfg(test)]
1830
mod tests {
1831
    use super::{PReg, PRegSet, RegClass::*};
1832
1833
    #[test]
1834
    fn preg_set_len() {
1835
        let mut set = PRegSet::empty();
1836
        assert_eq!(set.len(), 0);
1837
1838
        set.add(PReg::new(3, Int));
1839
        assert_eq!(set.len(), 1);
1840
        set.add(PReg::new(3, Int));
1841
        assert_eq!(set.len(), 1);
1842
1843
        set.add(PReg::new(4, Int));
1844
        assert_eq!(set.len(), 2);
1845
    }
1846
1847
    #[test]
1848
    fn preg_set_max_preg() {
1849
        let mut set = PRegSet::empty();
1850
        assert_eq!(set.max_preg(), None);
1851
1852
        set.add(PReg::new(3, Int));
1853
        assert_eq!(set.max_preg(), Some(PReg::new(3, Int)));
1854
1855
        set.add(PReg::new(4, Int));
1856
        assert_eq!(set.max_preg(), Some(PReg::new(4, Int)));
1857
1858
        set.add(PReg::new(2, Int));
1859
        assert_eq!(set.max_preg(), Some(PReg::new(4, Int)));
1860
    }
1861
1862
    #[test]
1863
    fn preg_set_new_up_to() {
1864
        for class in [Int, Float, Vector] {
1865
            let p0 = PReg::new(0, class);
1866
            let p1 = PReg::new(1, class);
1867
            let p2 = PReg::new(2, class);
1868
            let p3 = PReg::new(3, class);
1869
            {
1870
                let mut set = PRegSet::empty();
1871
                set.add_up_to(p1);
1872
                assert!(set.contains(p0));
1873
                assert!(!set.contains(p1));
1874
            }
1875
            {
1876
                let mut set = PRegSet::empty();
1877
                set.add_up_to(p0);
1878
                assert!(!set.contains(p0));
1879
            }
1880
            {
1881
                let mut set = PRegSet::empty();
1882
                set.add_up_to(p3);
1883
                assert!(set.contains(p0));
1884
                assert!(set.contains(p1));
1885
                assert!(set.contains(p2));
1886
                assert!(!set.contains(p3));
1887
            }
1888
            for i in 1..64 {
1889
                let mut set = PRegSet::empty();
1890
                set.add_up_to(PReg::new(i, class));
1891
                assert!(set.contains(p0));
1892
                assert!(set.contains(PReg::new(i - 1, class)));
1893
                assert!(!set.contains(PReg::new(i, class)));
1894
            }
1895
        }
1896
    }
1897
}