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