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