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;