use crate::isa::aarch64::inst::OperandSize;
use crate::isa::aarch64::inst::ScalarSize;
use crate::isa::aarch64::inst::VectorSize;
use crate::machinst::AllocationConsumer;
use crate::machinst::RealReg;
use crate::machinst::{Reg, RegClass, Writable};
use crate::settings;
use regalloc2::MachineEnv;
use regalloc2::PReg;
use regalloc2::VReg;
use std::string::{String, ToString};
pub const PINNED_REG: u8 = 21;
pub fn xreg(num: u8) -> Reg {
Reg::from(xreg_preg(num))
}
pub(crate) const fn xreg_preg(num: u8) -> PReg {
assert!(num < 31);
PReg::new(num as usize, RegClass::Int)
}
pub fn writable_xreg(num: u8) -> Writable<Reg> {
Writable::from_reg(xreg(num))
}
pub fn vreg(num: u8) -> Reg {
Reg::from(vreg_preg(num))
}
pub(crate) const fn vreg_preg(num: u8) -> PReg {
assert!(num < 32);
PReg::new(num as usize, RegClass::Float)
}
#[cfg(test)] pub fn writable_vreg(num: u8) -> Writable<Reg> {
Writable::from_reg(vreg(num))
}
pub fn zero_reg() -> Reg {
let preg = PReg::new(31, RegClass::Int);
Reg::from(VReg::new(preg.index(), RegClass::Int))
}
pub fn writable_zero_reg() -> Writable<Reg> {
Writable::from_reg(zero_reg())
}
pub fn stack_reg() -> Reg {
let preg = PReg::new(31 + 32, RegClass::Int);
Reg::from(VReg::new(preg.index(), RegClass::Int))
}
pub fn writable_stack_reg() -> Writable<Reg> {
Writable::from_reg(stack_reg())
}
pub fn link_reg() -> Reg {
xreg(30)
}
pub fn writable_link_reg() -> Writable<Reg> {
Writable::from_reg(link_reg())
}
pub fn fp_reg() -> Reg {
xreg(29)
}
pub fn writable_fp_reg() -> Writable<Reg> {
Writable::from_reg(fp_reg())
}
pub fn spilltmp_reg() -> Reg {
xreg(16)
}
pub fn writable_spilltmp_reg() -> Writable<Reg> {
Writable::from_reg(spilltmp_reg())
}
pub fn tmp2_reg() -> Reg {
xreg(17)
}
pub fn writable_tmp2_reg() -> Writable<Reg> {
Writable::from_reg(tmp2_reg())
}
pub fn create_reg_env(flags: &settings::Flags) -> MachineEnv {
fn preg(r: Reg) -> PReg {
r.to_real_reg().unwrap().into()
}
let mut env = MachineEnv {
preferred_regs_by_class: [
vec![
preg(xreg(0)),
preg(xreg(1)),
preg(xreg(2)),
preg(xreg(3)),
preg(xreg(4)),
preg(xreg(5)),
preg(xreg(6)),
preg(xreg(7)),
preg(xreg(8)),
preg(xreg(9)),
preg(xreg(10)),
preg(xreg(11)),
preg(xreg(12)),
preg(xreg(13)),
preg(xreg(14)),
preg(xreg(15)),
],
vec![
preg(vreg(0)),
preg(vreg(1)),
preg(vreg(2)),
preg(vreg(3)),
preg(vreg(4)),
preg(vreg(5)),
preg(vreg(6)),
preg(vreg(7)),
preg(vreg(16)),
preg(vreg(17)),
preg(vreg(18)),
preg(vreg(19)),
preg(vreg(20)),
preg(vreg(21)),
preg(vreg(22)),
preg(vreg(23)),
preg(vreg(24)),
preg(vreg(25)),
preg(vreg(26)),
preg(vreg(27)),
preg(vreg(28)),
preg(vreg(29)),
preg(vreg(30)),
preg(vreg(31)),
],
],
non_preferred_regs_by_class: [
vec![
preg(xreg(19)),
preg(xreg(20)),
preg(xreg(22)),
preg(xreg(23)),
preg(xreg(24)),
preg(xreg(25)),
preg(xreg(26)),
preg(xreg(27)),
preg(xreg(28)),
],
vec![
preg(vreg(8)),
preg(vreg(9)),
preg(vreg(10)),
preg(vreg(11)),
preg(vreg(12)),
preg(vreg(13)),
preg(vreg(14)),
preg(vreg(15)),
],
],
fixed_stack_slots: vec![],
};
if !flags.enable_pinned_reg() {
debug_assert_eq!(PINNED_REG, 21); env.non_preferred_regs_by_class[0].push(preg(xreg(PINNED_REG)));
}
env
}
fn show_ireg(reg: RealReg) -> String {
match reg.hw_enc() {
29 => "fp".to_string(),
30 => "lr".to_string(),
31 => "xzr".to_string(),
63 => "sp".to_string(),
x => {
debug_assert!(x < 29);
format!("x{}", x)
}
}
}
fn show_vreg(reg: RealReg) -> String {
format!("v{}", reg.hw_enc() & 31)
}
fn show_reg(reg: Reg) -> String {
if let Some(rreg) = reg.to_real_reg() {
match rreg.class() {
RegClass::Int => show_ireg(rreg),
RegClass::Float => show_vreg(rreg),
}
} else {
format!("%{:?}", reg)
}
}
pub fn pretty_print_reg(reg: Reg, allocs: &mut AllocationConsumer<'_>) -> String {
let reg = allocs.next(reg);
show_reg(reg)
}
pub fn show_ireg_sized(reg: Reg, size: OperandSize) -> String {
let mut s = show_reg(reg);
if reg.class() != RegClass::Int || !size.is32() {
return s;
}
if reg.class() == RegClass::Int && size.is32() && s.starts_with("x") {
s = "w".to_string() + &s[1..];
}
s
}
pub fn show_vreg_scalar(reg: Reg, size: ScalarSize) -> String {
let mut s = show_reg(reg);
if reg.class() != RegClass::Float {
return s;
}
if s.starts_with("v") {
let replacement = match size {
ScalarSize::Size8 => "b",
ScalarSize::Size16 => "h",
ScalarSize::Size32 => "s",
ScalarSize::Size64 => "d",
ScalarSize::Size128 => "q",
};
s.replace_range(0..1, replacement);
}
s
}
pub fn show_vreg_vector(reg: Reg, size: VectorSize) -> String {
assert_eq!(RegClass::Float, reg.class());
let mut s = show_reg(reg);
let suffix = match size {
VectorSize::Size8x8 => ".8b",
VectorSize::Size8x16 => ".16b",
VectorSize::Size16x4 => ".4h",
VectorSize::Size16x8 => ".8h",
VectorSize::Size32x2 => ".2s",
VectorSize::Size32x4 => ".4s",
VectorSize::Size64x2 => ".2d",
};
s.push_str(suffix);
s
}
pub fn show_vreg_element(reg: Reg, idx: u8, size: ScalarSize) -> String {
assert_eq!(RegClass::Float, reg.class());
let s = show_reg(reg);
let suffix = match size {
ScalarSize::Size8 => ".b",
ScalarSize::Size16 => ".h",
ScalarSize::Size32 => ".s",
ScalarSize::Size64 => ".d",
_ => panic!("Unexpected vector element size: {:?}", size),
};
format!("{}{}[{}]", s, suffix, idx)
}
pub fn pretty_print_ireg(
reg: Reg,
size: OperandSize,
allocs: &mut AllocationConsumer<'_>,
) -> String {
let reg = allocs.next(reg);
show_ireg_sized(reg, size)
}
pub fn pretty_print_vreg_scalar(
reg: Reg,
size: ScalarSize,
allocs: &mut AllocationConsumer<'_>,
) -> String {
let reg = allocs.next(reg);
show_vreg_scalar(reg, size)
}
pub fn pretty_print_vreg_vector(
reg: Reg,
size: VectorSize,
allocs: &mut AllocationConsumer<'_>,
) -> String {
let reg = allocs.next(reg);
show_vreg_vector(reg, size)
}
pub fn pretty_print_vreg_element(
reg: Reg,
idx: usize,
size: ScalarSize,
allocs: &mut AllocationConsumer<'_>,
) -> String {
let reg = allocs.next(reg);
show_vreg_element(reg, idx as u8, size)
}