* Bump RA2 to 0.7.0 * Certify the RA2 update * Import the rustc-hash audit * Updates for regalloc2 prtest:full * Update tests
335 lines
8.7 KiB
Rust
335 lines
8.7 KiB
Rust
//! Register definitions for regalloc2.
|
|
//!
|
|
//! We define 16 GPRs, with indices equal to the hardware encoding,
|
|
//! and 16 XMM registers.
|
|
//!
|
|
//! Note also that we make use of pinned VRegs to refer to PRegs.
|
|
|
|
use crate::machinst::{AllocationConsumer, RealReg, Reg};
|
|
use crate::settings;
|
|
use alloc::string::ToString;
|
|
use regalloc2::{MachineEnv, PReg, RegClass, VReg};
|
|
use std::string::String;
|
|
|
|
// Hardware encodings (note the special rax, rcx, rdx, rbx order).
|
|
|
|
pub const ENC_RAX: u8 = 0;
|
|
pub const ENC_RCX: u8 = 1;
|
|
pub const ENC_RDX: u8 = 2;
|
|
pub const ENC_RBX: u8 = 3;
|
|
pub const ENC_RSP: u8 = 4;
|
|
pub const ENC_RBP: u8 = 5;
|
|
pub const ENC_RSI: u8 = 6;
|
|
pub const ENC_RDI: u8 = 7;
|
|
pub const ENC_R8: u8 = 8;
|
|
pub const ENC_R9: u8 = 9;
|
|
pub const ENC_R10: u8 = 10;
|
|
pub const ENC_R11: u8 = 11;
|
|
pub const ENC_R12: u8 = 12;
|
|
pub const ENC_R13: u8 = 13;
|
|
pub const ENC_R14: u8 = 14;
|
|
pub const ENC_R15: u8 = 15;
|
|
|
|
// Constructors for Regs.
|
|
|
|
fn gpr(enc: u8) -> Reg {
|
|
let preg = gpr_preg(enc);
|
|
Reg::from(VReg::new(preg.index(), RegClass::Int))
|
|
}
|
|
pub(crate) const fn gpr_preg(enc: u8) -> PReg {
|
|
PReg::new(enc as usize, RegClass::Int)
|
|
}
|
|
|
|
pub(crate) fn rsi() -> Reg {
|
|
gpr(ENC_RSI)
|
|
}
|
|
pub(crate) fn rdi() -> Reg {
|
|
gpr(ENC_RDI)
|
|
}
|
|
pub(crate) fn rax() -> Reg {
|
|
gpr(ENC_RAX)
|
|
}
|
|
pub(crate) fn rcx() -> Reg {
|
|
gpr(ENC_RCX)
|
|
}
|
|
pub(crate) fn rdx() -> Reg {
|
|
gpr(ENC_RDX)
|
|
}
|
|
pub(crate) fn r8() -> Reg {
|
|
gpr(ENC_R8)
|
|
}
|
|
pub(crate) fn r9() -> Reg {
|
|
gpr(ENC_R9)
|
|
}
|
|
pub(crate) fn r10() -> Reg {
|
|
gpr(ENC_R10)
|
|
}
|
|
pub(crate) fn r11() -> Reg {
|
|
gpr(ENC_R11)
|
|
}
|
|
pub(crate) fn r12() -> Reg {
|
|
gpr(ENC_R12)
|
|
}
|
|
pub(crate) fn r13() -> Reg {
|
|
gpr(ENC_R13)
|
|
}
|
|
pub(crate) fn r14() -> Reg {
|
|
gpr(ENC_R14)
|
|
}
|
|
pub(crate) fn rbx() -> Reg {
|
|
gpr(ENC_RBX)
|
|
}
|
|
|
|
pub(crate) fn r15() -> Reg {
|
|
gpr(ENC_R15)
|
|
}
|
|
|
|
pub(crate) fn rsp() -> Reg {
|
|
gpr(ENC_RSP)
|
|
}
|
|
pub(crate) fn rbp() -> Reg {
|
|
gpr(ENC_RBP)
|
|
}
|
|
|
|
/// The pinned register on this architecture.
|
|
/// It must be the same as Spidermonkey's HeapReg, as found in this file.
|
|
/// https://searchfox.org/mozilla-central/source/js/src/jit/x64/Assembler-x64.h#99
|
|
pub(crate) fn pinned_reg() -> Reg {
|
|
r15()
|
|
}
|
|
|
|
fn fpr(enc: u8) -> Reg {
|
|
let preg = fpr_preg(enc);
|
|
Reg::from(VReg::new(preg.index(), RegClass::Float))
|
|
}
|
|
|
|
pub(crate) const fn fpr_preg(enc: u8) -> PReg {
|
|
PReg::new(enc as usize, RegClass::Float)
|
|
}
|
|
|
|
pub(crate) fn xmm0() -> Reg {
|
|
fpr(0)
|
|
}
|
|
pub(crate) fn xmm1() -> Reg {
|
|
fpr(1)
|
|
}
|
|
pub(crate) fn xmm2() -> Reg {
|
|
fpr(2)
|
|
}
|
|
pub(crate) fn xmm3() -> Reg {
|
|
fpr(3)
|
|
}
|
|
pub(crate) fn xmm4() -> Reg {
|
|
fpr(4)
|
|
}
|
|
pub(crate) fn xmm5() -> Reg {
|
|
fpr(5)
|
|
}
|
|
pub(crate) fn xmm6() -> Reg {
|
|
fpr(6)
|
|
}
|
|
pub(crate) fn xmm7() -> Reg {
|
|
fpr(7)
|
|
}
|
|
pub(crate) fn xmm8() -> Reg {
|
|
fpr(8)
|
|
}
|
|
pub(crate) fn xmm9() -> Reg {
|
|
fpr(9)
|
|
}
|
|
pub(crate) fn xmm10() -> Reg {
|
|
fpr(10)
|
|
}
|
|
pub(crate) fn xmm11() -> Reg {
|
|
fpr(11)
|
|
}
|
|
pub(crate) fn xmm12() -> Reg {
|
|
fpr(12)
|
|
}
|
|
pub(crate) fn xmm13() -> Reg {
|
|
fpr(13)
|
|
}
|
|
pub(crate) fn xmm14() -> Reg {
|
|
fpr(14)
|
|
}
|
|
pub(crate) fn xmm15() -> Reg {
|
|
fpr(15)
|
|
}
|
|
|
|
/// Create the register environment for x64.
|
|
pub(crate) fn create_reg_env_systemv(flags: &settings::Flags) -> MachineEnv {
|
|
fn preg(r: Reg) -> PReg {
|
|
r.to_real_reg().unwrap().into()
|
|
}
|
|
|
|
let mut env = MachineEnv {
|
|
preferred_regs_by_class: [
|
|
// Preferred GPRs: caller-saved in the SysV ABI.
|
|
vec![
|
|
preg(rsi()),
|
|
preg(rdi()),
|
|
preg(rax()),
|
|
preg(rcx()),
|
|
preg(rdx()),
|
|
preg(r8()),
|
|
preg(r9()),
|
|
preg(r10()),
|
|
preg(r11()),
|
|
],
|
|
// Preferred XMMs: all of them.
|
|
vec![
|
|
preg(xmm0()),
|
|
preg(xmm1()),
|
|
preg(xmm2()),
|
|
preg(xmm3()),
|
|
preg(xmm4()),
|
|
preg(xmm5()),
|
|
preg(xmm6()),
|
|
preg(xmm7()),
|
|
preg(xmm8()),
|
|
preg(xmm9()),
|
|
preg(xmm10()),
|
|
preg(xmm11()),
|
|
preg(xmm12()),
|
|
preg(xmm13()),
|
|
preg(xmm14()),
|
|
preg(xmm15()),
|
|
],
|
|
],
|
|
non_preferred_regs_by_class: [
|
|
// Non-preferred GPRs: callee-saved in the SysV ABI.
|
|
vec![preg(rbx()), preg(r12()), preg(r13()), preg(r14())],
|
|
// Non-preferred XMMs: none.
|
|
vec![],
|
|
],
|
|
fixed_stack_slots: vec![],
|
|
scratch_by_class: [None, None],
|
|
};
|
|
|
|
debug_assert_eq!(r15(), pinned_reg());
|
|
if !flags.enable_pinned_reg() {
|
|
env.non_preferred_regs_by_class[0].push(preg(r15()));
|
|
}
|
|
|
|
env
|
|
}
|
|
|
|
/// Give the name of a RealReg.
|
|
pub fn realreg_name(reg: RealReg) -> &'static str {
|
|
let preg = PReg::from(reg);
|
|
match preg.class() {
|
|
RegClass::Int => match preg.hw_enc() as u8 {
|
|
ENC_RAX => "%rax",
|
|
ENC_RBX => "%rbx",
|
|
ENC_RCX => "%rcx",
|
|
ENC_RDX => "%rdx",
|
|
ENC_RSI => "%rsi",
|
|
ENC_RDI => "%rdi",
|
|
ENC_RBP => "%rbp",
|
|
ENC_RSP => "%rsp",
|
|
ENC_R8 => "%r8",
|
|
ENC_R9 => "%r9",
|
|
ENC_R10 => "%r10",
|
|
ENC_R11 => "%r11",
|
|
ENC_R12 => "%r12",
|
|
ENC_R13 => "%r13",
|
|
ENC_R14 => "%r14",
|
|
ENC_R15 => "%r15",
|
|
_ => panic!("Invalid PReg: {:?}", preg),
|
|
},
|
|
RegClass::Float => match preg.hw_enc() {
|
|
0 => "%xmm0",
|
|
1 => "%xmm1",
|
|
2 => "%xmm2",
|
|
3 => "%xmm3",
|
|
4 => "%xmm4",
|
|
5 => "%xmm5",
|
|
6 => "%xmm6",
|
|
7 => "%xmm7",
|
|
8 => "%xmm8",
|
|
9 => "%xmm9",
|
|
10 => "%xmm10",
|
|
11 => "%xmm11",
|
|
12 => "%xmm12",
|
|
13 => "%xmm13",
|
|
14 => "%xmm14",
|
|
15 => "%xmm15",
|
|
_ => panic!("Invalid PReg: {:?}", preg),
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn show_reg(reg: Reg) -> String {
|
|
if let Some(rreg) = reg.to_real_reg() {
|
|
realreg_name(rreg).to_string()
|
|
} else {
|
|
format!("%{:?}", reg)
|
|
}
|
|
}
|
|
|
|
/// If `ireg` denotes an I64-classed reg, make a best-effort attempt to show its name at some
|
|
/// smaller size (4, 2 or 1 bytes).
|
|
pub fn show_ireg_sized(reg: Reg, size: u8) -> String {
|
|
let mut s = show_reg(reg);
|
|
|
|
if reg.class() != RegClass::Int || size == 8 {
|
|
// We can't do any better.
|
|
return s;
|
|
}
|
|
|
|
if reg.is_real() {
|
|
// Change (eg) "rax" into "eax", "ax" or "al" as appropriate. This is something one could
|
|
// describe diplomatically as "a kludge", but it's only debug code.
|
|
let remapper = match s.as_str() {
|
|
"%rax" => Some(["%eax", "%ax", "%al"]),
|
|
"%rbx" => Some(["%ebx", "%bx", "%bl"]),
|
|
"%rcx" => Some(["%ecx", "%cx", "%cl"]),
|
|
"%rdx" => Some(["%edx", "%dx", "%dl"]),
|
|
"%rsi" => Some(["%esi", "%si", "%sil"]),
|
|
"%rdi" => Some(["%edi", "%di", "%dil"]),
|
|
"%rbp" => Some(["%ebp", "%bp", "%bpl"]),
|
|
"%rsp" => Some(["%esp", "%sp", "%spl"]),
|
|
"%r8" => Some(["%r8d", "%r8w", "%r8b"]),
|
|
"%r9" => Some(["%r9d", "%r9w", "%r9b"]),
|
|
"%r10" => Some(["%r10d", "%r10w", "%r10b"]),
|
|
"%r11" => Some(["%r11d", "%r11w", "%r11b"]),
|
|
"%r12" => Some(["%r12d", "%r12w", "%r12b"]),
|
|
"%r13" => Some(["%r13d", "%r13w", "%r13b"]),
|
|
"%r14" => Some(["%r14d", "%r14w", "%r14b"]),
|
|
"%r15" => Some(["%r15d", "%r15w", "%r15b"]),
|
|
_ => None,
|
|
};
|
|
if let Some(smaller_names) = remapper {
|
|
match size {
|
|
4 => s = smaller_names[0].into(),
|
|
2 => s = smaller_names[1].into(),
|
|
1 => s = smaller_names[2].into(),
|
|
_ => panic!("show_ireg_sized: real"),
|
|
}
|
|
}
|
|
} else {
|
|
// Add a "l", "w" or "b" suffix to RegClass::I64 vregs used at narrower widths.
|
|
let suffix = match size {
|
|
4 => "l",
|
|
2 => "w",
|
|
1 => "b",
|
|
_ => panic!("show_ireg_sized: virtual"),
|
|
};
|
|
s = s + suffix;
|
|
}
|
|
|
|
s
|
|
}
|
|
|
|
// N.B.: this is not an `impl PrettyPrint for Reg` because it is
|
|
// specific to x64; other backends have analogous functions. The
|
|
// disambiguation happens statically by virtue of higher-level,
|
|
// x64-specific, types calling the right `pretty_print_reg`. (In other
|
|
// words, we can't pretty-print a `Reg` all by itself in a build that
|
|
// may have multiple backends; but we can pretty-print one as part of
|
|
// an x64 Inst or x64 RegMemImm.)
|
|
pub fn pretty_print_reg(reg: Reg, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
|
|
let reg = allocs.next(reg);
|
|
show_ireg_sized(reg, size)
|
|
}
|