Remove ancient register allocation (#3401)
This commit is contained in:
@@ -8,9 +8,8 @@
|
||||
//! are satisfied.
|
||||
|
||||
use crate::binemit::CodeOffset;
|
||||
use crate::ir::{Function, Inst, ValueLoc};
|
||||
use crate::ir::ValueLoc;
|
||||
use crate::isa::{RegClass, RegUnit};
|
||||
use crate::regalloc::RegDiversions;
|
||||
|
||||
/// Register constraint for a single value operand or instruction result.
|
||||
#[derive(PartialEq, Debug)]
|
||||
@@ -87,69 +86,6 @@ pub enum ConstraintKind {
|
||||
Stack,
|
||||
}
|
||||
|
||||
/// Value operand constraints for an encoding recipe.
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub struct RecipeConstraints {
|
||||
/// Constraints for the instruction's fixed value operands.
|
||||
///
|
||||
/// If the instruction takes a variable number of operands, the register constraints for those
|
||||
/// operands must be computed dynamically.
|
||||
///
|
||||
/// - For branches and jumps, block arguments must match the expectations of the destination block.
|
||||
/// - For calls and returns, the calling convention ABI specifies constraints.
|
||||
pub ins: &'static [OperandConstraint],
|
||||
|
||||
/// Constraints for the instruction's fixed results.
|
||||
///
|
||||
/// If the instruction produces a variable number of results, it's probably a call and the
|
||||
/// constraints must be derived from the calling convention ABI.
|
||||
pub outs: &'static [OperandConstraint],
|
||||
|
||||
/// Are any of the input constraints `FixedReg` or `FixedTied`?
|
||||
pub fixed_ins: bool,
|
||||
|
||||
/// Are any of the output constraints `FixedReg` or `FixedTied`?
|
||||
pub fixed_outs: bool,
|
||||
|
||||
/// Are any of the input/output constraints `Tied` (but not `FixedTied`)?
|
||||
pub tied_ops: bool,
|
||||
|
||||
/// Does this instruction clobber the CPU flags?
|
||||
///
|
||||
/// When true, SSA values of type `iflags` or `fflags` can not be live across the instruction.
|
||||
pub clobbers_flags: bool,
|
||||
}
|
||||
|
||||
impl RecipeConstraints {
|
||||
/// Check that these constraints are satisfied by the operands on `inst`.
|
||||
pub fn satisfied(&self, inst: Inst, divert: &RegDiversions, func: &Function) -> bool {
|
||||
for (&arg, constraint) in func.dfg.inst_args(inst).iter().zip(self.ins) {
|
||||
let loc = divert.get(arg, &func.locations);
|
||||
|
||||
if let ConstraintKind::Tied(out_index) = constraint.kind {
|
||||
let out_val = func.dfg.inst_results(inst)[out_index as usize];
|
||||
let out_loc = func.locations[out_val];
|
||||
if loc != out_loc {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if !constraint.satisfied(loc) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (&arg, constraint) in func.dfg.inst_results(inst).iter().zip(self.outs) {
|
||||
let loc = divert.get(arg, &func.locations);
|
||||
if !constraint.satisfied(loc) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Constraints on the range of a branch instruction.
|
||||
///
|
||||
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
//! Support types for generated encoding tables.
|
||||
//!
|
||||
//! This module contains types and functions for working with the encoding tables generated by
|
||||
//! `cranelift-codegen/meta/src/gen_encodings.rs`.
|
||||
|
||||
use crate::constant_hash::Table;
|
||||
use crate::ir::{Function, InstructionData, Opcode, Type};
|
||||
use crate::isa::{Encoding, Legalize};
|
||||
use crate::settings::PredicateView;
|
||||
|
||||
/// A recipe predicate.
|
||||
///
|
||||
/// This is a predicate function capable of testing ISA and instruction predicates simultaneously.
|
||||
///
|
||||
/// A None predicate is always satisfied.
|
||||
pub type RecipePredicate = Option<fn(PredicateView, &InstructionData) -> bool>;
|
||||
|
||||
/// An instruction predicate.
|
||||
///
|
||||
/// This is a predicate function that needs to be tested in addition to the recipe predicate. It
|
||||
/// can't depend on ISA settings.
|
||||
pub type InstPredicate = fn(&Function, &InstructionData) -> bool;
|
||||
|
||||
/// Legalization action to perform when no encoding can be found for an instruction.
|
||||
///
|
||||
/// This is an index into an ISA-specific table of legalization actions.
|
||||
pub type LegalizeCode = u8;
|
||||
|
||||
/// Level 1 hash table entry.
|
||||
///
|
||||
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
|
||||
/// variable, using `INVALID` for non-polymorphic instructions.
|
||||
///
|
||||
/// The hash table values are references to level 2 hash tables, encoded as an offset in `LEVEL2`
|
||||
/// where the table begins, and the binary logarithm of its length. All the level 2 hash tables
|
||||
/// have a power-of-two size.
|
||||
///
|
||||
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
|
||||
/// size of the `LEVEL2` table.
|
||||
///
|
||||
/// Empty entries are encoded with a `!0` value for `log2len` which will always be out of range.
|
||||
/// Entries that have a `legalize` value but no level 2 table have an `offset` field that is out of
|
||||
/// bounds.
|
||||
pub struct Level1Entry<OffT: Into<u32> + Copy> {
|
||||
pub ty: Type,
|
||||
pub log2len: u8,
|
||||
pub legalize: LegalizeCode,
|
||||
pub offset: OffT,
|
||||
}
|
||||
|
||||
impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn key(&self, idx: usize) -> Option<Type> {
|
||||
if self[idx].log2len != !0 {
|
||||
Some(self[idx].ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Level 2 hash table entry.
|
||||
///
|
||||
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
|
||||
/// table where the encoding recipes for the instruction are stored.
|
||||
///
|
||||
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
|
||||
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
|
||||
/// for tiny ISAs. The entries won't shrink below 32 bits since the opcode is expected to be 16
|
||||
/// bits.
|
||||
///
|
||||
/// Empty entries are encoded with a `NotAnOpcode` `opcode` field.
|
||||
pub struct Level2Entry<OffT: Into<u32> + Copy> {
|
||||
pub opcode: Option<Opcode>,
|
||||
pub offset: OffT,
|
||||
}
|
||||
|
||||
impl<OffT: Into<u32> + Copy> Table<Opcode> for [Level2Entry<OffT>] {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn key(&self, idx: usize) -> Option<Opcode> {
|
||||
self[idx].opcode
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoding list entry.
|
||||
///
|
||||
/// Encoding lists are represented as sequences of u16 words.
|
||||
pub type EncListEntry = u16;
|
||||
|
||||
/// Number of bits used to represent a predicate. c.f. `meta/src/gen_encodings.rs`.
|
||||
const PRED_BITS: u8 = 12;
|
||||
const PRED_MASK: usize = (1 << PRED_BITS) - 1;
|
||||
/// First code word representing a predicate check. c.f. `meta/src/gen_encodings.rs`.
|
||||
const PRED_START: usize = 0x1000;
|
||||
|
||||
/// An iterator over legal encodings for the instruction.
|
||||
pub struct Encodings<'a> {
|
||||
// Current offset into `enclist`, or out of bounds after we've reached the end.
|
||||
offset: usize,
|
||||
// Legalization code to use of no encoding is found.
|
||||
legalize: LegalizeCode,
|
||||
inst: &'a InstructionData,
|
||||
func: &'a Function,
|
||||
enclist: &'static [EncListEntry],
|
||||
legalize_actions: &'static [Legalize],
|
||||
recipe_preds: &'static [RecipePredicate],
|
||||
inst_preds: &'static [InstPredicate],
|
||||
isa_preds: PredicateView<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Encodings<'a> {
|
||||
/// Creates a new instance of `Encodings`.
|
||||
///
|
||||
/// This iterator provides search for encodings that applies to the given instruction. The
|
||||
/// encoding lists are laid out such that first call to `next` returns valid entry in the list
|
||||
/// or `None`.
|
||||
pub fn new(
|
||||
offset: usize,
|
||||
legalize: LegalizeCode,
|
||||
inst: &'a InstructionData,
|
||||
func: &'a Function,
|
||||
enclist: &'static [EncListEntry],
|
||||
legalize_actions: &'static [Legalize],
|
||||
recipe_preds: &'static [RecipePredicate],
|
||||
inst_preds: &'static [InstPredicate],
|
||||
isa_preds: PredicateView<'a>,
|
||||
) -> Self {
|
||||
Encodings {
|
||||
offset,
|
||||
inst,
|
||||
func,
|
||||
legalize,
|
||||
isa_preds,
|
||||
recipe_preds,
|
||||
inst_preds,
|
||||
enclist,
|
||||
legalize_actions,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the legalization action that caused the enumeration of encodings to stop.
|
||||
/// This can be the default legalization action for the type or a custom code for the
|
||||
/// instruction.
|
||||
///
|
||||
/// This method must only be called after the iterator returns `None`.
|
||||
pub fn legalize(&self) -> Legalize {
|
||||
debug_assert_eq!(self.offset, !0, "Premature Encodings::legalize()");
|
||||
self.legalize_actions[self.legalize as usize]
|
||||
}
|
||||
|
||||
/// Check if the `rpred` recipe predicate is satisfied.
|
||||
fn check_recipe(&self, rpred: RecipePredicate) -> bool {
|
||||
match rpred {
|
||||
Some(p) => p(self.isa_preds, self.inst),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check an instruction or isa predicate.
|
||||
fn check_pred(&self, pred: usize) -> bool {
|
||||
if let Some(&p) = self.inst_preds.get(pred) {
|
||||
p(self.func, self.inst)
|
||||
} else {
|
||||
let pred = pred - self.inst_preds.len();
|
||||
self.isa_preds.test(pred)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Encodings<'a> {
|
||||
type Item = Encoding;
|
||||
|
||||
fn next(&mut self) -> Option<Encoding> {
|
||||
while let Some(entryref) = self.enclist.get(self.offset) {
|
||||
let entry = *entryref as usize;
|
||||
|
||||
// Check for "recipe+bits".
|
||||
let recipe = entry >> 1;
|
||||
if let Some(&rpred) = self.recipe_preds.get(recipe) {
|
||||
let bits = self.offset + 1;
|
||||
if entry & 1 == 0 {
|
||||
self.offset += 2; // Next entry.
|
||||
} else {
|
||||
self.offset = !0; // Stop.
|
||||
}
|
||||
if self.check_recipe(rpred) {
|
||||
return Some(Encoding::new(recipe as u16, self.enclist[bits]));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for "stop with legalize".
|
||||
if entry < PRED_START {
|
||||
self.legalize = (entry - 2 * self.recipe_preds.len()) as LegalizeCode;
|
||||
self.offset = !0; // Stop.
|
||||
return None;
|
||||
}
|
||||
|
||||
// Finally, this must be a predicate entry.
|
||||
let pred_entry = entry - PRED_START;
|
||||
let skip = pred_entry >> PRED_BITS;
|
||||
let pred = pred_entry & PRED_MASK;
|
||||
|
||||
if self.check_pred(pred) {
|
||||
self.offset += 1;
|
||||
} else if skip == 0 {
|
||||
self.offset = !0; // Stop.
|
||||
return None;
|
||||
} else {
|
||||
self.offset += 1 + skip;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
//! The `Encoding` struct.
|
||||
|
||||
use crate::binemit::CodeOffset;
|
||||
use crate::ir::{Function, Inst};
|
||||
use crate::isa::constraints::{BranchRange, RecipeConstraints};
|
||||
use crate::regalloc::RegDiversions;
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Bits needed to encode an instruction as binary machine code.
|
||||
///
|
||||
/// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
|
||||
/// encoding *bits*. The recipe determines the native instruction format and the mapping of
|
||||
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
|
||||
/// typically parts of the opcode.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub struct Encoding {
|
||||
recipe: u16,
|
||||
bits: u16,
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
/// Create a new `Encoding` containing `(recipe, bits)`.
|
||||
pub fn new(recipe: u16, bits: u16) -> Self {
|
||||
Self { recipe, bits }
|
||||
}
|
||||
|
||||
/// Get the recipe number in this encoding.
|
||||
pub fn recipe(self) -> usize {
|
||||
self.recipe as usize
|
||||
}
|
||||
|
||||
/// Get the recipe-specific encoding bits.
|
||||
pub fn bits(self) -> u16 {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Is this a legal encoding, or the default placeholder?
|
||||
pub fn is_legal(self) -> bool {
|
||||
self != Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// The default encoding is the illegal one.
|
||||
impl Default for Encoding {
|
||||
fn default() -> Self {
|
||||
Self::new(0xffff, 0xffff)
|
||||
}
|
||||
}
|
||||
|
||||
/// ISA-independent display of an encoding.
|
||||
impl fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.is_legal() {
|
||||
write!(f, "{}#{:02x}", self.recipe, self.bits)
|
||||
} else {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Temporary object that holds enough context to properly display an encoding.
|
||||
/// This is meant to be created by `EncInfo::display()`.
|
||||
pub struct DisplayEncoding {
|
||||
pub encoding: Encoding,
|
||||
pub recipe_names: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl fmt::Display for DisplayEncoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.encoding.is_legal() {
|
||||
write!(
|
||||
f,
|
||||
"{}#{:02x}",
|
||||
self.recipe_names[self.encoding.recipe()],
|
||||
self.encoding.bits
|
||||
)
|
||||
} else {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type SizeCalculatorFn = fn(&RecipeSizing, Encoding, Inst, &RegDiversions, &Function) -> u8;
|
||||
|
||||
/// Returns the base size of the Recipe, assuming it's fixed. This is the default for most
|
||||
/// encodings; others can be variable and longer than this base size, depending on the registers
|
||||
/// they're using and use a different function, specific per platform.
|
||||
pub fn base_size(
|
||||
sizing: &RecipeSizing,
|
||||
_: Encoding,
|
||||
_: Inst,
|
||||
_: &RegDiversions,
|
||||
_: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size
|
||||
}
|
||||
|
||||
/// Code size information for an encoding recipe.
|
||||
///
|
||||
/// Encoding recipes may have runtime-determined instruction size.
|
||||
pub struct RecipeSizing {
|
||||
/// Minimum size in bytes of instructions encoded with this recipe.
|
||||
pub base_size: u8,
|
||||
|
||||
/// Method computing the instruction's real size, given inputs and outputs.
|
||||
pub compute_size: SizeCalculatorFn,
|
||||
|
||||
/// Allowed branch range in this recipe, if any.
|
||||
///
|
||||
/// All encoding recipes for branches have exact branch range information.
|
||||
pub branch_range: Option<BranchRange>,
|
||||
}
|
||||
|
||||
/// Information about all the encodings in this ISA.
|
||||
#[derive(Clone)]
|
||||
pub struct EncInfo {
|
||||
/// Constraints on value operands per recipe.
|
||||
pub constraints: &'static [RecipeConstraints],
|
||||
|
||||
/// Code size information per recipe.
|
||||
pub sizing: &'static [RecipeSizing],
|
||||
|
||||
/// Names of encoding recipes.
|
||||
pub names: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl EncInfo {
|
||||
/// Get the value operand constraints for `enc` if it is a legal encoding.
|
||||
pub fn operand_constraints(&self, enc: Encoding) -> Option<&'static RecipeConstraints> {
|
||||
self.constraints.get(enc.recipe())
|
||||
}
|
||||
|
||||
/// Create an object that can display an ISA-dependent encoding properly.
|
||||
pub fn display(&self, enc: Encoding) -> DisplayEncoding {
|
||||
DisplayEncoding {
|
||||
encoding: enc,
|
||||
recipe_names: self.names,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the size in bytes of `inst`, if it were encoded with `enc`.
|
||||
///
|
||||
/// Returns 0 for illegal encodings.
|
||||
pub fn byte_size(
|
||||
&self,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> CodeOffset {
|
||||
self.sizing.get(enc.recipe()).map_or(0, |s| {
|
||||
let compute_size = s.compute_size;
|
||||
CodeOffset::from(compute_size(&s, enc, inst, divert, func))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the branch range that is supported by `enc`, if any.
|
||||
///
|
||||
/// This will never return `None` for a legal branch encoding.
|
||||
pub fn branch_range(&self, enc: Encoding) -> Option<BranchRange> {
|
||||
self.sizing.get(enc.recipe()).and_then(|s| s.branch_range)
|
||||
}
|
||||
}
|
||||
@@ -44,26 +44,19 @@
|
||||
//! concurrent function compilations.
|
||||
|
||||
pub use crate::isa::call_conv::CallConv;
|
||||
pub use crate::isa::constraints::{
|
||||
BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints,
|
||||
};
|
||||
pub use crate::isa::enc_tables::Encodings;
|
||||
pub use crate::isa::encoding::{base_size, EncInfo, Encoding};
|
||||
pub use crate::isa::constraints::{BranchRange, ConstraintKind, OperandConstraint};
|
||||
pub use crate::isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit};
|
||||
pub use crate::isa::stack::{StackBase, StackBaseMask, StackRef};
|
||||
|
||||
use crate::binemit;
|
||||
use crate::flowgraph;
|
||||
use crate::ir;
|
||||
#[cfg(feature = "unwind")]
|
||||
use crate::isa::unwind::systemv::RegisterMappingError;
|
||||
use crate::machinst::{MachBackend, UnwindInfoKind};
|
||||
use crate::regalloc;
|
||||
use crate::result::CodegenResult;
|
||||
use crate::settings;
|
||||
use crate::settings::SetResult;
|
||||
use crate::timing;
|
||||
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::any::Any;
|
||||
use core::fmt;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
@@ -88,8 +81,6 @@ pub mod unwind;
|
||||
|
||||
mod call_conv;
|
||||
mod constraints;
|
||||
mod enc_tables;
|
||||
mod encoding;
|
||||
pub mod registers;
|
||||
mod stack;
|
||||
|
||||
@@ -329,125 +320,6 @@ pub trait TargetIsa: fmt::Display + Send + Sync {
|
||||
Err(RegisterMappingError::UnsupportedArchitecture)
|
||||
}
|
||||
|
||||
/// Returns an iterator over legal encodings for the instruction.
|
||||
fn legal_encodings<'a>(
|
||||
&'a self,
|
||||
func: &'a ir::Function,
|
||||
inst: &'a ir::InstructionData,
|
||||
ctrl_typevar: ir::Type,
|
||||
) -> Encodings<'a>;
|
||||
|
||||
/// Encode an instruction after determining it is legal.
|
||||
///
|
||||
/// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
|
||||
/// Otherwise, return `Legalize` action.
|
||||
///
|
||||
/// This is also the main entry point for determining if an instruction is legal.
|
||||
fn encode(
|
||||
&self,
|
||||
func: &ir::Function,
|
||||
inst: &ir::InstructionData,
|
||||
ctrl_typevar: ir::Type,
|
||||
) -> Result<Encoding, Legalize> {
|
||||
let mut iter = self.legal_encodings(func, inst, ctrl_typevar);
|
||||
iter.next().ok_or_else(|| iter.legalize())
|
||||
}
|
||||
|
||||
/// Get a data structure describing the instruction encodings in this ISA.
|
||||
fn encoding_info(&self) -> EncInfo;
|
||||
|
||||
/// Legalize a function signature.
|
||||
///
|
||||
/// This is used to legalize both the signature of the function being compiled and any called
|
||||
/// functions. The signature should be modified by adding `ArgumentLoc` annotations to all
|
||||
/// arguments and return values.
|
||||
///
|
||||
/// Arguments with types that are not supported by the ABI can be expanded into multiple
|
||||
/// arguments:
|
||||
///
|
||||
/// - Integer types that are too large to fit in a register can be broken into multiple
|
||||
/// arguments of a smaller integer type.
|
||||
/// - Floating point types can be bit-cast to an integer type of the same size, and possible
|
||||
/// broken into smaller integer types.
|
||||
/// - Vector types can be bit-cast and broken down into smaller vectors or scalars.
|
||||
///
|
||||
/// The legalizer will adapt argument and return values as necessary at all ABI boundaries.
|
||||
///
|
||||
/// When this function is called to legalize the signature of the function currently being
|
||||
/// compiled, `current` is true. The legalized signature can then also contain special purpose
|
||||
/// arguments and return values such as:
|
||||
///
|
||||
/// - A `link` argument representing the link registers on RISC architectures that don't push
|
||||
/// the return address on the stack.
|
||||
/// - A `link` return value which will receive the value that was passed to the `link`
|
||||
/// argument.
|
||||
/// - An `sret` argument can be added if one wasn't present already. This is necessary if the
|
||||
/// signature returns more values than registers are available for returning values.
|
||||
/// - An `sret` return value can be added if the ABI requires a function to return its `sret`
|
||||
/// argument in a register.
|
||||
///
|
||||
/// Arguments and return values for the caller's frame pointer and other callee-saved registers
|
||||
/// should not be added by this function. These arguments are not added until after register
|
||||
/// allocation.
|
||||
fn legalize_signature(&self, sig: &mut Cow<ir::Signature>, current: bool);
|
||||
|
||||
/// Get the register class that should be used to represent an ABI argument or return value of
|
||||
/// type `ty`. This should be the top-level register class that contains the argument
|
||||
/// registers.
|
||||
///
|
||||
/// This function can assume that it will only be asked to provide register classes for types
|
||||
/// that `legalize_signature()` produces in `ArgumentLoc::Reg` entries.
|
||||
fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass;
|
||||
|
||||
/// Get the set of allocatable registers that can be used when compiling `func`.
|
||||
///
|
||||
/// This set excludes reserved registers like the stack pointer and other special-purpose
|
||||
/// registers.
|
||||
fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet;
|
||||
|
||||
/// Compute the stack layout and insert prologue and epilogue code into `func`.
|
||||
///
|
||||
/// Return an error if the stack frame is too large.
|
||||
fn prologue_epilogue(&self, func: &mut ir::Function) -> CodegenResult<()> {
|
||||
let _tt = timing::prologue_epilogue();
|
||||
// This default implementation is unlikely to be good enough.
|
||||
use crate::ir::stackslot::{StackOffset, StackSize};
|
||||
use crate::stack_layout::layout_stack;
|
||||
|
||||
let word_size = StackSize::from(self.pointer_bytes());
|
||||
|
||||
// Account for the SpiderMonkey standard prologue pushes.
|
||||
if func.signature.call_conv.extends_baldrdash() {
|
||||
let bytes = StackSize::from(self.flags().baldrdash_prologue_words()) * word_size;
|
||||
let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
|
||||
ss.offset = Some(-(bytes as StackOffset));
|
||||
func.stack_slots.push(ss);
|
||||
}
|
||||
|
||||
let is_leaf = func.is_leaf();
|
||||
layout_stack(&mut func.stack_slots, is_leaf, word_size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emit binary machine code for a single instruction into the `sink` trait object.
|
||||
///
|
||||
/// Note that this will call `put*` methods on the `sink` trait object via its vtable which
|
||||
/// is not the fastest way of emitting code.
|
||||
///
|
||||
/// This function is under the "testing_hooks" feature, and is only suitable for use by
|
||||
/// test harnesses. It increases code size, and is inefficient.
|
||||
#[cfg(feature = "testing_hooks")]
|
||||
fn emit_inst(
|
||||
&self,
|
||||
func: &ir::Function,
|
||||
inst: ir::Inst,
|
||||
divert: &mut regalloc::RegDiversions,
|
||||
sink: &mut dyn binemit::CodeSink,
|
||||
);
|
||||
|
||||
/// Emit a whole function into memory.
|
||||
fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
|
||||
|
||||
/// IntCC condition for Unsigned Addition Overflow (Carry).
|
||||
fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user