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