regalloc/
lib.rs

1//! Main file / top-level module for regalloc library.
2//!
3//! We have tried hard to make the library's interface as simple as possible,
4//! yet flexible enough that the allocators it implements can provide good
5//! quality allocations in reasonable time.  Nevertheless, there is still
6//! significant semantic complexity in parts of the interface.  If you intend
7//! to use this library in your own code, you would be well advised to read
8//! the comments in this file very carefully.
9
10// Make the analysis module public for fuzzing.
11#[cfg(feature = "fuzzing")]
12pub mod analysis_main;
13#[cfg(not(feature = "fuzzing"))]
14mod analysis_main;
15
16mod analysis_control_flow;
17mod analysis_data_flow;
18mod analysis_reftypes;
19mod avl_tree;
20mod bt_coalescing_analysis;
21mod bt_commitment_map;
22mod bt_main;
23mod bt_spillslot_allocator;
24mod bt_vlr_priority_queue;
25mod checker;
26mod data_structures;
27mod inst_stream;
28mod linear_scan;
29mod pretty_print;
30mod reg_maps;
31mod snapshot;
32mod sparse_set;
33mod union_find;
34
35use log::{debug, log_enabled, Level};
36use std::default;
37use std::{borrow::Cow, fmt};
38
39// Stuff that is defined by the library
40
41// Pretty-printing utilities.
42pub use crate::pretty_print::*;
43
44// Sets and maps of things.  We can refine these later; but for now the
45// interface needs some way to speak about them, so let's use the
46// library-provided versions.
47
48pub use crate::data_structures::Map;
49pub use crate::data_structures::Set;
50
51// Register classes
52
53pub use crate::data_structures::RegClass;
54
55// Registers, both real and virtual, and ways to create them
56
57pub use crate::data_structures::Reg;
58
59pub use crate::data_structures::RealReg;
60pub use crate::data_structures::VirtualReg;
61
62pub use crate::data_structures::Writable;
63pub use crate::data_structures::WritableBase;
64
65pub use crate::data_structures::NUM_REG_CLASSES;
66
67// Spill slots
68
69pub use crate::data_structures::SpillSlot;
70
71// The "register universe".  This describes the registers available to the
72// allocator.  There are very strict requirements on the structure of the
73// universe.  If you fail to observe these requirements, either the allocator
74// itself, or the resulting code, will fail in mysterious ways, and your life
75// will be miserable while you try to figure out what happened.  There are
76// lower level details on the definition of RealRegUniverse which you also
77// need to take note of.  The overall contract is as follows.
78//
79// === (1) === Basic structure ===
80//
81// A "register universe" is a read-only structure that contains all
82// information about real registers on a given host.  For each register class
83// (RegClass) supported by the target, the universe must provide a vector of
84// registers that the allocator may use.
85//
86// The universe may also list other registers that the incoming
87// virtual-registerised code may use, but which are not available for use by
88// the allocator.  Indeed, the universe *must* list *all* registers that will
89// ever be mentioned in the incoming code.  Failure to do so will cause the
90// allocator's analysis phase to return an error.
91//
92// === (2) === Ordering of registers within each class
93//
94// The ordering of available registers within these vectors does not affect
95// the correctness of the final allocation.  However, it will affect the
96// quality of final allocation.  Clients are recommended to list, for each
97// class, the callee-saved registers first, and the caller-saved registers
98// after that.  The currently supported allocation algorithms (Backtracking
99// and LinearScan) will try to use the first available registers in each
100// class, that is to say, callee-saved ones first.  The purpose of this is to
101// try and minimise spilling around calls by avoiding use of caller-saved ones
102// if possible.
103//
104// There is a twist here, however.  The abovementioned heuristic works well
105// for non-leaf functions (functions that contain at least one call).  But for
106// leaf functions, we would prefer to use the caller-saved registers first,
107// since doing so has potential to minimise the number of registers that must
108// be saved/restored in the prologue and epilogue.  Presently there is no way
109// to tell this interface that the function is a leaf function, and so the
110// only way to get optimal code in this case is to present a universe with the
111// registers listed in the opposite order.
112//
113// This is of course inconvenient for the caller, since it requires
114// maintenance of two separate universes.  In the future we will add a boolean
115// parameter to the top level function `allocate_registers` that indicates
116// that whether or not the function is a leaf function.
117//
118// === (3) === The "suggested scratch register" ===
119//
120// Some allocation algorithms, particularly linear-scan, may need to have a
121// scratch register available for their own use.  The register universe must
122// nominate a scratch register in each class, specified in
123// RealRegUniverse::allocable_by_class[..]::Some(suggested_scratch).  The
124// choice of scratch register is influenced by the architecture, the ABI, and
125// client-side fixed-use register conventions.  There rules are as follows:
126//
127// (1) For each class, the universe must offer a reserved register.
128//
129// (2) The reserved register may not have any implied-by-the architecture
130//     reads/modifies/writes for any instruction in the vcode.  Unfortunately
131//     there is no easy way for this library to check that.
132//
133// (3) The reserved register must not have any reads or modifies by any
134//     instruction in the vcode.  In other words, it must not be handed to
135//     either the `add_use` or `add_mod` function of the `RegUsageCollector`
136//     that is presented to the client's `get_regs` function.  If any such
137//     mention is detected, the library will return an error.
138//
139// (4) The reserved reg may be mentioned as written by instructions in the
140//     vcode, though -- in other words it may be handed to `add_def`.  The
141//     library will tolerate and correctly handle that.  However, because no
142//     vcode instruction may read or modify the reserved register, all such
143//     writes are "dead".  This in turn guarantees that the allocator can, if
144//     it wants, change the value in it at any time, without changing the
145//     behaviour of the final generated code.
146//
147// Currently, the LinearScan algorithm may use the reserved registers.  The
148// Backtracking algorithm will ignore the hints and treat them as "normal"
149// allocatable registers.
150
151pub use crate::data_structures::RealRegUniverse;
152pub use crate::data_structures::RegClassInfo;
153
154// A structure for collecting information about which registers each
155// instruction uses.
156
157pub use crate::data_structures::RegUsageCollector;
158
159/// A trait for providing mapping results for a given instruction.
160///
161/// This provides virtual to real register mappings for every mention in an instruction: use, mod
162/// or def. The main purpose of this trait is to be used when re-writing the instruction stream
163/// after register allocation happened; see also `Function::map_regs`.
164pub trait RegUsageMapper: fmt::Debug {
165    /// Return the `RealReg` if mapped, or `None`, for `vreg` occuring as a use
166    /// on the current instruction.
167    fn get_use(&self, vreg: VirtualReg) -> Option<RealReg>;
168
169    /// Return the `RealReg` if mapped, or `None`, for `vreg` occuring as a def
170    /// on the current instruction.
171    fn get_def(&self, vreg: VirtualReg) -> Option<RealReg>;
172
173    /// Return the `RealReg` if mapped, or `None`, for a `vreg` occuring as a
174    /// mod on the current instruction.
175    fn get_mod(&self, vreg: VirtualReg) -> Option<RealReg>;
176}
177
178// TypedIxVector, so that the interface can speak about vectors of blocks and
179// instructions.
180
181pub use crate::data_structures::TypedIxVec;
182pub use crate::data_structures::{BlockIx, InstIx, Range};
183
184/// A trait defined by the regalloc client to provide access to its
185/// machine-instruction / CFG representation.
186pub trait Function {
187    /// Regalloc is parameterized on F: Function and so can use the projected
188    /// type F::Inst.
189    type Inst: Clone + fmt::Debug;
190
191    // -------------
192    // CFG traversal
193    // -------------
194
195    /// Allow access to the underlying vector of instructions.
196    fn insns(&self) -> &[Self::Inst];
197
198    /// Get all instruction indices as an iterable range.
199    fn insn_indices(&self) -> Range<InstIx> {
200        Range::new(InstIx::new(0), self.insns().len())
201    }
202
203    /// Allow mutable access to the underlying vector of instructions.
204    fn insns_mut(&mut self) -> &mut [Self::Inst];
205
206    /// Get an instruction with a type-safe InstIx index.
207    fn get_insn(&self, insn: InstIx) -> &Self::Inst;
208
209    /// Get a mutable borrow of an instruction with the given type-safe InstIx
210    /// index.
211    fn get_insn_mut(&mut self, insn: InstIx) -> &mut Self::Inst;
212
213    /// Allow iteration over basic blocks (in instruction order).
214    fn blocks(&self) -> Range<BlockIx>;
215
216    /// Get the index of the entry block.
217    fn entry_block(&self) -> BlockIx;
218
219    /// Provide the range of instruction indices contained in each block.
220    fn block_insns(&self, block: BlockIx) -> Range<InstIx>;
221
222    /// Get CFG successors for a given block.
223    fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]>;
224
225    /// Determine whether an instruction is a return instruction.
226    fn is_ret(&self, insn: InstIx) -> bool;
227
228    /// Determine whether an instruction should be considered while computing
229    /// the set of registers that need to be saved/restored in the function's
230    /// prologue/epilogue, that is, the registers returned in
231    /// `clobbered_registers` in `RegAllocResult`.  computation. Only
232    /// instructions for which this function returns `true` will be used to
233    /// compute that set.
234    ///
235    /// One reason that a client might *not* want an instruction to be included
236    /// would be if it can handle the clobbers some other way: for example,
237    /// ABI-support code might exclude call instructions' defs and mods from the
238    /// clobber set, because (given the callee has same ABI as the caller) the
239    /// registers possibly written by the callee are all registers that the
240    /// caller is also allowed to clobber (not save/restore in
241    /// prologue/epilogue).
242    fn is_included_in_clobbers(&self, _insn: &Self::Inst) -> bool {
243        // Default impl includes all instructions.
244        true
245    }
246
247    // --------------------------
248    // Instruction register slots
249    // --------------------------
250
251    /// Add to `collector` the used, defined, and modified registers for an
252    /// instruction.
253    fn get_regs(insn: &Self::Inst, collector: &mut RegUsageCollector);
254
255    /// Map each register slot through a virtual-to-real mapping indexed
256    /// by virtual register. The two separate maps in `maps.pre` and
257    /// `maps.post` provide the mapping to use for uses (which semantically
258    /// occur just prior to the instruction's effect) and defs (which
259    /// semantically occur just after the instruction's effect). Regs that were
260    /// "modified" can use either map; the vreg should be the same in both.
261    ///
262    /// Note that this does not take a `self`, because we want to allow the
263    /// regalloc to have a mutable borrow of an insn (which borrows the whole
264    /// Function in turn) outstanding while calling this.
265    fn map_regs<RUM: RegUsageMapper>(insn: &mut Self::Inst, maps: &RUM);
266
267    /// Allow the regalloc to query whether this is a move. Returns (dst, src).
268    fn is_move(&self, insn: &Self::Inst) -> Option<(Writable<Reg>, Reg)>;
269
270    /// Get the precise number of `VirtualReg` in use in this function, to allow preallocating data
271    /// structures. This number *must* be a correct lower-bound, otherwise invalid index failures
272    /// may happen; it is of course better if it is exact.
273    fn get_num_vregs(&self) -> usize;
274
275    // --------------
276    // Spills/reloads
277    // --------------
278
279    /// How many logical spill slots does the given regclass require?  E.g., on a
280    /// 64-bit machine, spill slots may nominally be 64-bit words, but a 128-bit
281    /// vector value will require two slots.  The regalloc will always align on
282    /// this size.
283    ///
284    /// This passes the associated virtual register to the client as well,
285    /// because the way in which we spill a real register may depend on the
286    /// value that we are using it for. E.g., if a machine has V128 registers
287    /// but we also use them for F32 and F64 values, we may use a different
288    /// store-slot size and smaller-operand store/load instructions for an F64
289    /// than for a true V128.
290    fn get_spillslot_size(&self, regclass: RegClass, for_vreg: VirtualReg) -> u32;
291
292    /// Generate a spill instruction for insertion into the instruction
293    /// sequence. The associated virtual register (whose value is being spilled)
294    /// is passed, if it exists, so that the client may make decisions about the
295    /// instruction to generate based on the type of value in question.  Because
296    /// the register allocator will insert spill instructions at arbitrary points,
297    /// the returned instruction here must not modify the machine's condition codes.
298    fn gen_spill(
299        &self,
300        to_slot: SpillSlot,
301        from_reg: RealReg,
302        for_vreg: Option<VirtualReg>,
303    ) -> Self::Inst;
304
305    /// Generate a reload instruction for insertion into the instruction
306    /// sequence. The associated virtual register (whose value is being loaded)
307    /// is passed as well, if it exists.  The returned instruction must not modify
308    /// the machine's condition codes.
309    fn gen_reload(
310        &self,
311        to_reg: Writable<RealReg>,
312        from_slot: SpillSlot,
313        for_vreg: Option<VirtualReg>,
314    ) -> Self::Inst;
315
316    /// Generate a register-to-register move for insertion into the instruction
317    /// sequence. The associated virtual register is passed as well.  The
318    /// returned instruction must not modify the machine's condition codes.
319    fn gen_move(
320        &self,
321        to_reg: Writable<RealReg>,
322        from_reg: RealReg,
323        for_vreg: VirtualReg,
324    ) -> Self::Inst;
325
326    /// Generate an instruction which is a no-op and has zero length.
327    fn gen_zero_len_nop(&self) -> Self::Inst;
328
329    /// Try to alter an existing instruction to use a value directly in a
330    /// spillslot (accessing memory directly) instead of the given register. May
331    /// be useful on ISAs that have mem/reg ops, like x86.
332    ///
333    /// Note that this is not *quite* just fusing a load with the op; if the
334    /// value is def'd or modified, it should be written back to the spill slot
335    /// as well. In other words, it is just using the spillslot as if it were a
336    /// real register, for reads and/or writes.
337    ///
338    /// FIXME JRS 2020Feb06: state precisely the constraints on condition code
339    /// changes.
340    fn maybe_direct_reload(
341        &self,
342        insn: &Self::Inst,
343        reg: VirtualReg,
344        slot: SpillSlot,
345    ) -> Option<Self::Inst>;
346
347    // ----------------------------------------------------------
348    // Function liveins, liveouts, and direct-mode real registers
349    // ----------------------------------------------------------
350
351    /// Return the set of registers that should be considered live at the
352    /// beginning of the function. This is semantically equivalent to an
353    /// instruction at the top of the entry block def'ing all registers in this
354    /// set.
355    fn func_liveins(&self) -> Set<RealReg>;
356
357    /// Return the set of registers that should be considered live at the
358    /// end of the function (after every return instruction). This is
359    /// semantically equivalent to an instruction at each block with no successors
360    /// that uses each of these registers.
361    fn func_liveouts(&self) -> Set<RealReg>;
362}
363
364/// The result of register allocation.  Note that allocation can fail!
365pub struct RegAllocResult<F: Function> {
366    /// A new sequence of instructions with all register slots filled with real
367    /// registers, and spills/fills/moves possibly inserted (and unneeded moves
368    /// elided).
369    pub insns: Vec<F::Inst>,
370
371    /// Basic-block start indices for the new instruction list, indexed by the
372    /// original basic block indices. May be used by the client to, e.g., remap
373    /// branch targets appropriately.
374    pub target_map: TypedIxVec<BlockIx, InstIx>,
375
376    /// Full mapping from new instruction indices to original instruction
377    /// indices. May be needed by the client to, for example, update metadata
378    /// such as debug/source-location info as the instructions are spliced
379    /// and reordered.
380    ///
381    /// Each entry is an `InstIx`, but may be `InstIx::invalid_value()` if the
382    /// new instruction at this new index was inserted by the allocator
383    /// (i.e., if it is a load, spill or move instruction).
384    pub orig_insn_map: TypedIxVec</* new */ InstIx, /* orig */ InstIx>,
385
386    /// Which real registers were overwritten? This will contain all real regs
387    /// that appear as defs or modifies in register slots of the output
388    /// instruction list.  This will only list registers that are available to
389    /// the allocator.  If one of the instructions clobbers a register which
390    /// isn't available to the allocator, it won't be mentioned here.
391    pub clobbered_registers: Set<RealReg>,
392
393    /// How many spill slots were used?
394    pub num_spill_slots: u32,
395
396    /// Block annotation strings, for debugging.  Requires requesting in the
397    /// call to `allocate_registers`.  Creating of these annotations is
398    /// potentially expensive, so don't request them if you don't need them.
399    pub block_annotations: Option<TypedIxVec<BlockIx, Vec<String>>>,
400
401    /// If stackmap support was requested: one stackmap for each of the safepoint instructions
402    /// declared.  Otherwise empty.
403    pub stackmaps: Vec<Vec<SpillSlot>>,
404
405    /// If stackmap support was requested: one InstIx for each safepoint instruction declared,
406    /// indicating the corresponding location in the final instruction stream.  Otherwise empty.
407    pub new_safepoint_insns: Vec<InstIx>,
408}
409
410/// A choice of register allocation algorithm to run.
411#[derive(Clone, Copy, Debug, PartialEq, Eq)]
412pub enum AlgorithmWithDefaults {
413    Backtracking,
414    LinearScan,
415}
416
417pub use crate::analysis_main::AnalysisError;
418pub use crate::checker::{CheckerError, CheckerErrors};
419
420/// An error from the register allocator.
421#[derive(Clone, Debug)]
422pub enum RegAllocError {
423    OutOfRegisters(RegClass),
424    MissingSuggestedScratchReg(RegClass),
425    Analysis(AnalysisError),
426    RegChecker(CheckerErrors),
427    Other(String),
428}
429
430impl fmt::Display for RegAllocError {
431    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
432        write!(f, "{:?}", self)
433    }
434}
435
436pub use crate::bt_main::BacktrackingOptions;
437pub use crate::linear_scan::LinearScanOptions;
438
439#[derive(Clone)]
440pub enum Algorithm {
441    LinearScan(LinearScanOptions),
442    Backtracking(BacktrackingOptions),
443}
444
445impl fmt::Debug for Algorithm {
446    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
447        match self {
448            Algorithm::LinearScan(opts) => write!(fmt, "{:?}", opts),
449            Algorithm::Backtracking(opts) => write!(fmt, "{:?}", opts),
450        }
451    }
452}
453
454/// Tweakable options shared by all the allocators.
455#[derive(Clone)]
456pub struct Options {
457    /// Should the register allocator check that its results are valid? This adds runtime to the
458    /// compiler, so this is disabled by default.
459    pub run_checker: bool,
460
461    /// Which algorithm should be used for register allocation? By default, selects backtracking,
462    /// which is slower to compile but creates code of better quality.
463    pub algorithm: Algorithm,
464}
465
466impl default::Default for Options {
467    fn default() -> Self {
468        Self {
469            run_checker: false,
470            algorithm: Algorithm::Backtracking(Default::default()),
471        }
472    }
473}
474
475impl fmt::Debug for Options {
476    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477        write!(
478            f,
479            "checker: {:?}, algorithm: {:?}",
480            self.run_checker, self.algorithm
481        )
482    }
483}
484
485/// A structure with which callers can request stackmap information.
486pub struct StackmapRequestInfo {
487    /// The register class that holds reftypes.  This may only be RegClass::I32 or
488    /// RegClass::I64, and it must equal the word size of the target architecture.
489    pub reftype_class: RegClass,
490
491    /// The virtual regs that hold reftyped values.  These must be provided in ascending order
492    /// of register index and be duplicate-free.  They must have class `reftype_class`.
493    pub reftyped_vregs: Vec<VirtualReg>,
494
495    /// The indices of instructions for which the allocator will construct stackmaps.  These
496    /// must be provided in ascending order and be duplicate-free.  The specified instructions
497    /// may not be coalescable move instructions (as the allocator may remove those) and they
498    /// may not modify any register carrying a reftyped value (they may "def" or "use" them,
499    /// though).  The reason is that, at a safepoint, the client's garbage collector may change
500    /// the values of all live references, so it would be meaningless for a safepoint
501    /// instruction also to attempt to do that -- we'd end up with two competing new values.
502    pub safepoint_insns: Vec<InstIx>,
503}
504
505/// Allocate registers for a function's code, given a universe of real registers that we are
506/// allowed to use.  Optionally, stackmap support may be requested.
507///
508/// The control flow graph must not contain any critical edges, that is, any edge coming from a
509/// block with multiple successors must not flow into a block with multiple predecessors. The
510/// embedder must have split critical edges before handing over the function to this function.
511/// Otherwise, an error will be returned.
512///
513/// Allocation may succeed, returning a `RegAllocResult` with the new instruction sequence, or
514/// it may fail, returning an error.
515///
516/// Runtime options can be passed to the allocators, through the use of [Options] for options
517/// common to all the backends. The choice of algorithm is done by passing a given [Algorithm]
518/// instance, with options tailored for each algorithm.
519#[inline(never)]
520pub fn allocate_registers_with_opts<F: Function>(
521    func: &mut F,
522    rreg_universe: &RealRegUniverse,
523    stackmap_info: Option<&StackmapRequestInfo>,
524    opts: Options,
525) -> Result<RegAllocResult<F>, RegAllocError> {
526    debug!("");
527    debug!("================ regalloc.rs: BEGIN function ================");
528
529    if log_enabled!(Level::Debug) {
530        debug!("with options: {:?}", opts);
531        let strs = rreg_universe.show();
532        debug!("using RealRegUniverse:");
533        for s in strs {
534            debug!("  {}", s);
535        }
536    }
537
538    // If stackmap support has been requested, perform some initial sanity checks.
539    if let Some(&StackmapRequestInfo {
540        reftype_class,
541        ref reftyped_vregs,
542        ref safepoint_insns,
543    }) = stackmap_info
544    {
545        if reftype_class != RegClass::I64 && reftype_class != RegClass::I32 {
546            return Err(RegAllocError::Other(
547                "stackmap request: invalid reftype_class".to_string(),
548            ));
549        }
550
551        let num_avail_vregs = func.get_num_vregs();
552        for (i, vreg) in reftyped_vregs.iter().enumerate() {
553            if vreg.get_class() != reftype_class {
554                return Err(RegAllocError::Other(
555                    "stackmap request: invalid vreg class".to_string(),
556                ));
557            }
558            if vreg.get_index() >= num_avail_vregs {
559                return Err(RegAllocError::Other(
560                    "stackmap request: out of range vreg".to_string(),
561                ));
562            }
563            if i > 0 && reftyped_vregs[i - 1].get_index() >= vreg.get_index() {
564                return Err(RegAllocError::Other(
565                    "stackmap request: non-ascending vregs".to_string(),
566                ));
567            }
568        }
569
570        let num_inst = func.insns().len();
571        for (i, &safepoint_iix) in safepoint_insns.iter().enumerate() {
572            if safepoint_iix.get() as usize >= num_inst {
573                return Err(RegAllocError::Other(
574                    "stackmap request: out of range safepoint insn".to_string(),
575                ));
576            }
577            if i > 0 && safepoint_insns[i - 1].get() >= safepoint_iix.get() {
578                return Err(RegAllocError::Other(
579                    "stackmap request: non-ascending safepoint insns".to_string(),
580                ));
581            }
582            if func.is_move(func.get_insn(safepoint_iix)).is_some() {
583                return Err(RegAllocError::Other(
584                    "stackmap request: safepoint insn is a move insn".to_string(),
585                ));
586            }
587        }
588
589        // We can't check here that reftyped regs are not *modified* by safepoint insns. That is
590        // done deep in the stackmap creation logic, for BT in `get_stackmap_artefacts_at`.
591    }
592
593    let run_checker = opts.run_checker;
594    let res = match &opts.algorithm {
595        Algorithm::Backtracking(opts) => {
596            bt_main::alloc_main(func, rreg_universe, stackmap_info, run_checker, opts)
597        }
598        Algorithm::LinearScan(opts) => {
599            linear_scan::run(func, rreg_universe, stackmap_info, run_checker, opts)
600        }
601    };
602
603    debug!("================ regalloc.rs: END function ================");
604    res
605}
606
607/// Allocate registers for a function's code, given a universe of real registers that we are
608/// allowed to use.
609///
610/// The control flow graph must not contain any critical edges, that is, any edge coming from a
611/// block with multiple successors must not flow into a block with multiple predecessors. The
612/// embedder must have split critical edges before handing over the function to this function.
613/// Otherwise, an error will be returned.
614///
615/// Allocate may succeed, returning a `RegAllocResult` with the new instruction sequence, or it may
616/// fail, returning an error.
617///
618/// This is a convenient function that uses standard options for the allocator, according to the
619/// selected algorithm.
620#[inline(never)]
621pub fn allocate_registers<F: Function>(
622    func: &mut F,
623    rreg_universe: &RealRegUniverse,
624    stackmap_info: Option<&StackmapRequestInfo>,
625    algorithm: AlgorithmWithDefaults,
626) -> Result<RegAllocResult<F>, RegAllocError> {
627    let algorithm = match algorithm {
628        AlgorithmWithDefaults::Backtracking => Algorithm::Backtracking(Default::default()),
629        AlgorithmWithDefaults::LinearScan => Algorithm::LinearScan(Default::default()),
630    };
631    let opts = Options {
632        algorithm,
633        ..Default::default()
634    };
635    allocate_registers_with_opts(func, rreg_universe, stackmap_info, opts)
636}
637
638// Facilities to snapshot regalloc inputs and reproduce them in regalloc.rs.
639pub use crate::snapshot::IRSnapshot;