use crate::isa::aarch64::inst::OperandSize;
use crate::isa::aarch64::inst::ScalarSize;
use crate::isa::aarch64::inst::VectorSize;
use crate::settings;
use regalloc::{
PrettyPrint, RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES,
};
use std::string::{String, ToString};
pub const PINNED_REG: u8 = 21;
#[rustfmt::skip]
const XREG_INDICES: [u8; 31] = [
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
58, 59,
60,
48, 49,
57,
50, 51, 52, 53, 54, 55, 56,
61,
62,
];
const ZERO_REG_INDEX: u8 = 63;
const SP_REG_INDEX: u8 = 64;
pub fn xreg(num: u8) -> Reg {
assert!(num < 31);
Reg::new_real(
RegClass::I64,
num,
XREG_INDICES[num as usize],
)
}
pub fn writable_xreg(num: u8) -> Writable<Reg> {
Writable::from_reg(xreg(num))
}
pub fn vreg(num: u8) -> Reg {
assert!(num < 32);
Reg::new_real(RegClass::V128, num, num)
}
pub fn writable_vreg(num: u8) -> Writable<Reg> {
Writable::from_reg(vreg(num))
}
pub fn zero_reg() -> Reg {
Reg::new_real(
RegClass::I64,
31,
ZERO_REG_INDEX,
)
}
pub fn writable_zero_reg() -> Writable<Reg> {
Writable::from_reg(zero_reg())
}
pub fn stack_reg() -> Reg {
Reg::new_real(
RegClass::I64,
31,
SP_REG_INDEX,
)
}
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_universe(flags: &settings::Flags) -> RealRegUniverse {
let mut regs = vec![];
let mut allocable_by_class = [None; NUM_REG_CLASSES];
let v_reg_base = 0u8; let v_reg_count = 32;
for i in 0u8..v_reg_count {
let reg = Reg::new_real(
RegClass::V128,
i,
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;
let x_reg_base = 32u8; let mut x_reg_count = 0;
let uses_pinned_reg = flags.enable_pinned_reg();
for i in 0u8..32u8 {
if i == 16 || i == 17 || i == 18 || i == 29 || i == 30 || i == 31 || i == PINNED_REG {
continue;
}
let reg = Reg::new_real(
RegClass::I64,
i,
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[19] 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( 31),
});
let allocable = if uses_pinned_reg {
let len = regs.len();
regs.push((xreg(PINNED_REG).to_real_reg(), "x21/pinned_reg".to_string()));
len
} else {
regs.push((xreg(PINNED_REG).to_real_reg(), "x21".to_string()));
regs.len()
};
regs.push((xreg(16).to_real_reg(), "x16".to_string()));
regs.push((xreg(17).to_real_reg(), "x17".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()));
for (i, reg) in regs.iter().enumerate() {
assert_eq!(i, reg.0.get_index());
}
RealRegUniverse {
regs,
allocable,
allocable_by_class,
}
}
pub fn show_ireg_sized(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: OperandSize) -> String {
let mut s = reg.show_rru(mb_rru);
if reg.get_class() != RegClass::I64 || !size.is32() {
return s;
}
if reg.is_real() {
if reg.get_class() == RegClass::I64 && size.is32() && s.starts_with("x") {
s = "w".to_string() + &s[1..];
}
} else {
if reg.get_class() == RegClass::I64 && size.is32() {
s.push('w');
}
}
s
}
pub fn show_vreg_scalar(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: ScalarSize) -> String {
let mut s = reg.show_rru(mb_rru);
if reg.get_class() != RegClass::V128 {
return s;
}
if reg.is_real() {
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);
}
} else {
if reg.get_class() == RegClass::V128 {
s.push('d');
}
}
s
}
pub fn show_vreg_vector(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: VectorSize) -> String {
assert_eq!(RegClass::V128, reg.get_class());
let mut s = reg.show_rru(mb_rru);
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,
mb_rru: Option<&RealRegUniverse>,
idx: u8,
size: VectorSize,
) -> String {
assert_eq!(RegClass::V128, reg.get_class());
let mut s = reg.show_rru(mb_rru);
let suffix = match size {
VectorSize::Size8x8 => "b",
VectorSize::Size8x16 => "b",
VectorSize::Size16x4 => "h",
VectorSize::Size16x8 => "h",
VectorSize::Size32x2 => "s",
VectorSize::Size32x4 => "s",
VectorSize::Size64x2 => "d",
};
s.push_str(&format!(".{}[{}]", suffix, idx));
s
}