| //! 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 alloc::string::ToString; |
| use regalloc2::{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) |
| } |
| |
| /// 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), |
| }, |
| RegClass::Vector => unreachable!(), |
| } |
| } |
| |
| 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) |
| } |