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