Address review comments:
- Undo temporary changes to default features (`all-arch`) and a
signal-handler test.
- Remove `SIGTRAP` handler: no longer needed now that we've found an
"undefined opcode" option on ARM64.
- Rename pp.rs to pretty_print.rs in machinst/.
- Only use empty stack-probe on non-x86. As per a comment in
rust-lang/compiler-builtins [1], LLVM only supports stack probes on
x86 and x86-64. Thus, on any other CPU architecture, we cannot refer
to `__rust_probestack`, because it does not exist.
- Rename arm64 to aarch64.
- Use `target` directive in vcode filetests.
- Run the flags verifier, but without encinfo, when using new backends.
- Clean up warning overrides.
- Fix up use of casts: use u32::from(x) and siblings when possible,
u32::try_from(x).unwrap() when not, to avoid silent truncation.
- Take immutable `Function` borrows as input; we don't actually
mutate the input IR.
- Lots of other miscellaneous cleanups.
[1] cae3e6ea23/src/probestack.rs (L39)
This commit is contained in:
270
cranelift/codegen/src/isa/aarch64/inst/regs.rs
Normal file
270
cranelift/codegen/src/isa/aarch64/inst/regs.rs
Normal file
@@ -0,0 +1,270 @@
|
||||
//! AArch64 ISA definitions: registers.
|
||||
|
||||
use crate::isa::aarch64::inst::InstSize;
|
||||
use crate::machinst::*;
|
||||
|
||||
use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES};
|
||||
|
||||
use std::string::{String, ToString};
|
||||
|
||||
//=============================================================================
|
||||
// Registers, the Universe thereof, and printing
|
||||
|
||||
#[rustfmt::skip]
|
||||
const XREG_INDICES: [u8; 31] = [
|
||||
// X0 - X7
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
// X8 - X14
|
||||
40, 41, 42, 43, 44, 45, 46,
|
||||
// X15
|
||||
59,
|
||||
// X16, X17
|
||||
47, 48,
|
||||
// X18
|
||||
60,
|
||||
// X19 - X28
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
||||
// X29
|
||||
61,
|
||||
// X30
|
||||
62,
|
||||
];
|
||||
|
||||
const ZERO_REG_INDEX: u8 = 63;
|
||||
|
||||
const SP_REG_INDEX: u8 = 64;
|
||||
|
||||
/// Get a reference to an X-register (integer register).
|
||||
pub fn xreg(num: u8) -> Reg {
|
||||
assert!(num < 31);
|
||||
Reg::new_real(
|
||||
RegClass::I64,
|
||||
/* enc = */ num,
|
||||
/* index = */ XREG_INDICES[num as usize],
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a writable reference to an X-register.
|
||||
pub fn writable_xreg(num: u8) -> Writable<Reg> {
|
||||
Writable::from_reg(xreg(num))
|
||||
}
|
||||
|
||||
/// Get a reference to a V-register (vector/FP register).
|
||||
pub fn vreg(num: u8) -> Reg {
|
||||
assert!(num < 32);
|
||||
Reg::new_real(RegClass::V128, /* enc = */ num, /* index = */ num)
|
||||
}
|
||||
|
||||
/// Get a writable reference to a V-register.
|
||||
pub fn writable_vreg(num: u8) -> Writable<Reg> {
|
||||
Writable::from_reg(vreg(num))
|
||||
}
|
||||
|
||||
/// Get a reference to the zero-register.
|
||||
pub fn zero_reg() -> Reg {
|
||||
// This should be the same as what xreg(31) returns, except that
|
||||
// we use the special index into the register index space.
|
||||
Reg::new_real(
|
||||
RegClass::I64,
|
||||
/* enc = */ 31,
|
||||
/* index = */ ZERO_REG_INDEX,
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the zero-register (this discards a result).
|
||||
pub fn writable_zero_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(zero_reg())
|
||||
}
|
||||
|
||||
/// Get a reference to the stack-pointer register.
|
||||
pub fn stack_reg() -> Reg {
|
||||
// XSP (stack) and XZR (zero) are logically different registers which have
|
||||
// the same hardware encoding, and whose meaning, in real aarch64
|
||||
// instructions, is context-dependent. For convenience of
|
||||
// universe-construction and for correct printing, we make them be two
|
||||
// different real registers.
|
||||
Reg::new_real(
|
||||
RegClass::I64,
|
||||
/* enc = */ 31,
|
||||
/* index = */ SP_REG_INDEX,
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the stack-pointer register.
|
||||
pub fn writable_stack_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(stack_reg())
|
||||
}
|
||||
|
||||
/// Get a reference to the link register (x30).
|
||||
pub fn link_reg() -> Reg {
|
||||
xreg(30)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the link register.
|
||||
pub fn writable_link_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(link_reg())
|
||||
}
|
||||
|
||||
/// Get a reference to the frame pointer (x29).
|
||||
pub fn fp_reg() -> Reg {
|
||||
xreg(29)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the frame pointer.
|
||||
pub fn writable_fp_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(fp_reg())
|
||||
}
|
||||
|
||||
/// Get a reference to the "spill temp" register. This register is used to
|
||||
/// compute the address of a spill slot when a direct offset addressing mode from
|
||||
/// FP is not sufficient (+/- 2^11 words). We exclude this register from regalloc
|
||||
/// and reserve it for this purpose for simplicity; otherwise we need a
|
||||
/// multi-stage analysis where we first determine how many spill slots we have,
|
||||
/// then perhaps remove the reg from the pool and recompute regalloc.
|
||||
pub fn spilltmp_reg() -> Reg {
|
||||
xreg(15)
|
||||
}
|
||||
|
||||
/// Get a writable reference to the spilltmp reg.
|
||||
pub fn writable_spilltmp_reg() -> Writable<Reg> {
|
||||
Writable::from_reg(spilltmp_reg())
|
||||
}
|
||||
|
||||
/// Create the register universe for AArch64.
|
||||
pub fn create_reg_universe() -> RealRegUniverse {
|
||||
let mut regs = vec![];
|
||||
let mut allocable_by_class = [None; NUM_REG_CLASSES];
|
||||
|
||||
// Numbering Scheme: we put V-regs first, then X-regs. The X-regs
|
||||
// exclude several registers: x18 (globally reserved for platform-specific
|
||||
// purposes), x29 (frame pointer), x30 (link register), x31 (stack pointer
|
||||
// or zero register, depending on context).
|
||||
|
||||
let v_reg_base = 0u8; // in contiguous real-register index space
|
||||
let v_reg_count = 32;
|
||||
for i in 0u8..v_reg_count {
|
||||
let reg = Reg::new_real(
|
||||
RegClass::V128,
|
||||
/* enc = */ i,
|
||||
/* index = */ v_reg_base + i,
|
||||
)
|
||||
.to_real_reg();
|
||||
let name = format!("v{}", i);
|
||||
regs.push((reg, name));
|
||||
}
|
||||
let v_reg_last = v_reg_base + v_reg_count - 1;
|
||||
|
||||
// Add the X registers. N.B.: the order here must match the order implied
|
||||
// by XREG_INDICES, ZERO_REG_INDEX, and SP_REG_INDEX above.
|
||||
|
||||
let x_reg_base = 32u8; // in contiguous real-register index space
|
||||
let mut x_reg_count = 0;
|
||||
for i in 0u8..32u8 {
|
||||
// See above for excluded registers.
|
||||
if i == 15 || i == 18 || i == 29 || i == 30 || i == 31 {
|
||||
continue;
|
||||
}
|
||||
let reg = Reg::new_real(
|
||||
RegClass::I64,
|
||||
/* enc = */ i,
|
||||
/* index = */ x_reg_base + x_reg_count,
|
||||
)
|
||||
.to_real_reg();
|
||||
let name = format!("x{}", i);
|
||||
regs.push((reg, name));
|
||||
x_reg_count += 1;
|
||||
}
|
||||
let x_reg_last = x_reg_base + x_reg_count - 1;
|
||||
|
||||
allocable_by_class[RegClass::I64.rc_to_usize()] = Some(RegClassInfo {
|
||||
first: x_reg_base as usize,
|
||||
last: x_reg_last as usize,
|
||||
suggested_scratch: Some(XREG_INDICES[13] as usize),
|
||||
});
|
||||
allocable_by_class[RegClass::V128.rc_to_usize()] = Some(RegClassInfo {
|
||||
first: v_reg_base as usize,
|
||||
last: v_reg_last as usize,
|
||||
suggested_scratch: Some(/* V31: */ 31),
|
||||
});
|
||||
|
||||
// Other regs, not available to the allocator.
|
||||
let allocable = regs.len();
|
||||
regs.push((xreg(15).to_real_reg(), "x15".to_string()));
|
||||
regs.push((xreg(18).to_real_reg(), "x18".to_string()));
|
||||
regs.push((fp_reg().to_real_reg(), "fp".to_string()));
|
||||
regs.push((link_reg().to_real_reg(), "lr".to_string()));
|
||||
regs.push((zero_reg().to_real_reg(), "xzr".to_string()));
|
||||
regs.push((stack_reg().to_real_reg(), "sp".to_string()));
|
||||
// FIXME JRS 2020Feb06: unfortunately this pushes the number of real regs
|
||||
// to 65, which is potentially inconvenient from a compiler performance
|
||||
// standpoint. We could possibly drop back to 64 by "losing" a vector
|
||||
// register in future.
|
||||
|
||||
// Assert sanity: the indices in the register structs must match their
|
||||
// actual indices in the array.
|
||||
for (i, reg) in regs.iter().enumerate() {
|
||||
assert_eq!(i, reg.0.get_index());
|
||||
}
|
||||
|
||||
RealRegUniverse {
|
||||
regs,
|
||||
allocable,
|
||||
allocable_by_class,
|
||||
}
|
||||
}
|
||||
|
||||
/// If `ireg` denotes an I64-classed reg, make a best-effort attempt to show
|
||||
/// its name at the 32-bit size.
|
||||
pub fn show_ireg_sized(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: InstSize) -> String {
|
||||
let mut s = reg.show_rru(mb_rru);
|
||||
if reg.get_class() != RegClass::I64 || !size.is32() {
|
||||
// We can't do any better.
|
||||
return s;
|
||||
}
|
||||
|
||||
if reg.is_real() {
|
||||
// Change (eg) "x42" into "w42" as appropriate
|
||||
if reg.get_class() == RegClass::I64 && size.is32() && s.starts_with("x") {
|
||||
s = "w".to_string() + &s[1..];
|
||||
}
|
||||
} else {
|
||||
// Add a "w" suffix to RegClass::I64 vregs used in a 32-bit role
|
||||
if reg.get_class() == RegClass::I64 && size.is32() {
|
||||
s.push('w');
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Show a vector register when its use as a 32-bit or 64-bit float is known.
|
||||
pub fn show_freg_sized(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: InstSize) -> String {
|
||||
let mut s = reg.show_rru(mb_rru);
|
||||
if reg.get_class() != RegClass::V128 {
|
||||
return s;
|
||||
}
|
||||
let prefix = if size.is32() { "s" } else { "d" };
|
||||
s.replace_range(0..1, prefix);
|
||||
s
|
||||
}
|
||||
|
||||
/// Show a vector register used in a scalar context.
|
||||
pub fn show_vreg_scalar(reg: Reg, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
let mut s = reg.show_rru(mb_rru);
|
||||
if reg.get_class() != RegClass::V128 {
|
||||
// We can't do any better.
|
||||
return s;
|
||||
}
|
||||
|
||||
if reg.is_real() {
|
||||
// Change (eg) "v0" into "d0".
|
||||
if reg.get_class() == RegClass::V128 && s.starts_with("v") {
|
||||
s.replace_range(0..1, "d");
|
||||
}
|
||||
} else {
|
||||
// Add a "d" suffix to RegClass::V128 vregs.
|
||||
if reg.get_class() == RegClass::V128 {
|
||||
s.push('d');
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
Reference in New Issue
Block a user