use super::ppc_instr_info::PpcOpcode;
use super::ppc_register_info::*;
use crate::codegen::*;
use crate::opcode::Opcode;
use crate::value::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VsxElementType {
SP,
DP,
I8,
I16,
I32,
I64,
}
impl VsxElementType {
pub fn size_bytes(self) -> u32 {
match self {
VsxElementType::SP => 4,
VsxElementType::DP => 8,
VsxElementType::I8 => 1,
VsxElementType::I16 => 2,
VsxElementType::I32 => 4,
VsxElementType::I64 => 8,
}
}
pub fn is_float(self) -> bool {
matches!(self, VsxElementType::SP | VsxElementType::DP)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VsxReductionOp {
Sum,
Product,
Min,
Max,
MinIndex,
MaxIndex,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MmaAccTile(pub u8);
impl MmaAccTile {
pub const COUNT: u8 = 8;
pub fn new(idx: u8) -> Option<Self> {
if idx < Self::COUNT { Some(MmaAccTile(idx)) } else { None }
}
pub fn index(self) -> u8 { self.0 }
pub fn all() -> Vec<MmaAccTile> {
(0..Self::COUNT).filter_map(MmaAccTile::new).collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MmaOuterType {
I4,
I8,
I16,
F32,
F64,
}
impl MmaOuterType {
pub fn accumulation_width(self) -> u32 {
match self {
MmaOuterType::I4 | MmaOuterType::I8 | MmaOuterType::I16 |
MmaOuterType::F32 => 32,
MmaOuterType::F64 => 64,
}
}
pub fn operand_width(self) -> u32 {
match self {
MmaOuterType::I4 => 4,
MmaOuterType::I8 => 8,
MmaOuterType::I16 => 16,
MmaOuterType::F32 => 32,
MmaOuterType::F64 => 64,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MmaInterLane {
Inter4,
Inter8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrefixType {
LoadStore,
Arithmetic,
LoadExtended,
}
impl PrefixType {
pub fn has_prefix_word(self) -> bool { true }
pub fn prefix_word_mls(self) -> u8 {
match self {
PrefixType::LoadStore => 0b10,
PrefixType::Arithmetic => 0b00,
PrefixType::LoadExtended => 0b10,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DfpRoundingMode {
RoundNearestEven,
RoundTowardZero,
RoundTowardPositive,
RoundTowardNegative,
RoundNearestTiesAway,
RoundNearestTiesEven50,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DfpTestGroup {
Zero,
Special,
Ordered,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DfpClassTest {
SignalingNaN,
QuietNaN,
PositiveInfinity,
NegativeInfinity,
PositiveNormal,
NegativeNormal,
PositiveSubnormal,
NegativeSubnormal,
PositiveZero,
NegativeZero,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BfpConvertOp {
Fctiwz,
Fctiw,
Fctidz,
Fctid,
Fcfid,
Fctiwuz,
Fctiwu,
Fctiduz,
Fctidu,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VsxPermuteOp {
Permute,
PermuteDI,
SplatWord,
MergeHighWord,
MergeLowWord,
PermuteX,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VsxLoadStoreOp {
LoadIndexed,
StoreIndexed,
LoadLeftLength,
StoreLeftLength,
LoadLeftByteCount,
StoreLeftByteCount,
LoadDoubleSplat,
LoadWordIndexed,
StoreWordIndexed,
LoadDoublewordIndexed,
StoreDoublewordIndexed,
LoadByteIndexed,
StoreByteIndexed,
}
impl VsxLoadStoreOp {
pub fn is_load(self) -> bool {
!matches!(self, VsxLoadStoreOp::StoreIndexed | VsxLoadStoreOp::StoreLeftLength
| VsxLoadStoreOp::StoreLeftByteCount | VsxLoadStoreOp::StoreWordIndexed
| VsxLoadStoreOp::StoreDoublewordIndexed | VsxLoadStoreOp::StoreByteIndexed)
}
pub fn element_size(self) -> u32 {
match self {
VsxLoadStoreOp::LoadWordIndexed | VsxLoadStoreOp::StoreWordIndexed => 4,
VsxLoadStoreOp::LoadDoublewordIndexed | VsxLoadStoreOp::StoreDoublewordIndexed
| VsxLoadStoreOp::LoadDoubleSplat => 8,
VsxLoadStoreOp::LoadByteIndexed | VsxLoadStoreOp::StoreByteIndexed => 16,
_ => 16,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VleFormat {
Short,
Long,
}
impl VleFormat {
pub fn size_bytes(self) -> u32 {
match self {
VleFormat::Short => 2,
VleFormat::Long => 4,
}
}
}
pub struct PpcFullInstructionSelector {
pub is_64bit: bool,
pub has_vsx: bool,
pub has_mma: bool,
pub has_dfp: bool,
pub has_prefix: bool,
pub has_spe: bool,
pub has_vle: bool,
pub vreg_map: HashMap<usize, VirtReg>,
pub mbb: MachineBasicBlock,
pub func_name: String,
pub acc_map: HashMap<u8, VirtReg>,
pub vsx_in_use: Vec<bool>,
}
impl PpcFullInstructionSelector {
pub fn new(is_64bit: bool) -> Self {
PpcFullInstructionSelector {
is_64bit,
has_vsx: false,
has_mma: false,
has_dfp: false,
has_prefix: false,
has_spe: false,
has_vle: false,
vreg_map: HashMap::new(),
mbb: MachineBasicBlock {
name: String::new(),
instructions: Vec::new(),
successors: Vec::new(),
},
func_name: String::new(),
acc_map: HashMap::new(),
vsx_in_use: vec![false; 64],
}
}
pub fn with_vsx(mut self, has: bool) -> Self { self.has_vsx = has; self }
pub fn with_mma(mut self, has: bool) -> Self { self.has_mma = has; self }
pub fn with_dfp(mut self, has: bool) -> Self { self.has_dfp = has; self }
pub fn with_prefix(mut self, has: bool) -> Self { self.has_prefix = has; self }
pub fn lower_vsx_add(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVADDSP as u32,
VsxElementType::DP => PpcOpcode::XVADDDP as u32,
_ => PpcOpcode::XVADDSP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_sub(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVSUBSP as u32,
VsxElementType::DP => PpcOpcode::XVSUBDP as u32,
_ => PpcOpcode::XVSUBSP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_mul(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVMULSP as u32,
VsxElementType::DP => PpcOpcode::XVMULDP as u32,
_ => PpcOpcode::XVMULSP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_div(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVDIVSP as u32,
VsxElementType::DP => PpcOpcode::XVDIVDP as u32,
_ => PpcOpcode::XVDIVSP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_fma(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVMADDASP as u32,
VsxElementType::DP => PpcOpcode::XVMADDADP as u32, _ => PpcOpcode::XVMADDASP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_fms(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVMSUBASP as u32,
VsxElementType::DP => PpcOpcode::XVMSUBADP as u32,
_ => PpcOpcode::XVMSUBASP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_nmadd(&self, inst: &Value, elem: VsxElementType) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let opcode = match elem {
VsxElementType::SP => PpcOpcode::XVMADDMSP as u32,
VsxElementType::DP => PpcOpcode::XVMADDMDP as u32,
_ => PpcOpcode::XVMADDMSP as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_fma_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XSMADDASP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_fma_dp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XSMADDADP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_fms_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XSMSUBASP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_nmadd_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XSMADDMSP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_rsqrte_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vrb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::XVMADDASP as u32);
mi.push_reg(vrt);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_sqrte_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vrb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::XVMADDADP as u32);
mi.push_reg(vrt);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn emit_rsqrte_refinement(&self, result_vreg: VirtReg, input_vreg: VirtReg) -> Vec<MachineInstr> {
let mut instrs = Vec::new();
let half = self.get_or_create_vreg_for_vid(0); let temp1 = self.get_or_create_vreg_for_vid(1);
let temp2 = self.get_or_create_vreg_for_vid(2);
let mut rsqrte = MachineInstr::new(PpcOpcode::XVMADDASP as u32);
rsqrte.push_reg(result_vreg);
rsqrte.push_reg(input_vreg);
rsqrte.def = Some(result_vreg);
instrs.push(rsqrte);
instrs
}
pub fn lower_vsx_permute(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XXLXOR as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_permdi(&self, inst: &Value, dm: u8) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XXSPLTIB as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_imm(dm as i64);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_splat_word(&self, inst: &Value, word_idx: u8) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vrb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::XXSPLTIB as u32);
mi.push_reg(vrt);
mi.push_reg(vrb);
mi.push_imm((word_idx & 0x3) as i64);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_merge_high_word(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XXLXOR as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_merge_low_word(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::VADDFP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_permute_extended(&self, inst: &Value, uim: u8) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let vrc: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::XXLXOR as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.push_imm(uim as i64);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_load(&self, inst: &Value, op: VsxLoadStoreOp) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let opcode = match op {
VsxLoadStoreOp::LoadDoublewordIndexed => PpcOpcode::LVX as u32,
VsxLoadStoreOp::LoadWordIndexed => PpcOpcode::LVX as u32,
VsxLoadStoreOp::LoadByteIndexed => PpcOpcode::LVX as u32,
VsxLoadStoreOp::LoadDoubleSplat => PpcOpcode::LVX as u32,
VsxLoadStoreOp::LoadIndexed => PpcOpcode::LVX as u32,
_ => PpcOpcode::LVX as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(ra);
if inst.operands.len() >= 2 {
let rb: u32 = self.get_vreg_for_operand(inst, 1);
mi.push_reg(rb);
} else {
mi.push_imm(0);
}
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_store(&self, inst: &Value, op: VsxLoadStoreOp) -> MachineInstr {
let vs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = PpcOpcode::STVX as u32;
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vs);
mi.push_reg(ra);
if inst.operands.len() >= 3 {
let rb: u32 = self.get_vreg_for_operand(inst, 2);
mi.push_reg(rb);
} else {
mi.push_imm(0);
}
mi
}
pub fn lower_vsx_load_left_length(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let rb: u32 = self.get_vreg_for_operand(inst, 1); let mut mi = MachineInstr::new(PpcOpcode::LVX as u32);
mi.push_reg(vrt);
mi.push_reg(ra);
mi.push_reg(rb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_store_left_length(&self, inst: &Value) -> MachineInstr {
let vs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let rb: u32 = self.get_vreg_for_operand(inst, 2); let mut mi = MachineInstr::new(PpcOpcode::STVX as u32);
mi.push_reg(vs);
mi.push_reg(ra);
mi.push_reg(rb);
mi
}
pub fn lower_vsx_load_left_byte_count(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let rb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::LVX as u32);
mi.push_reg(vrt);
mi.push_reg(ra);
mi.push_reg(rb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_store_left_byte_count(&self, inst: &Value) -> MachineInstr {
let vs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let rb: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::STVX as u32);
mi.push_reg(vs);
mi.push_reg(ra);
mi.push_reg(rb);
mi
}
pub fn lower_vsx_load_double_splat(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let rb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::LVX as u32);
mi.push_reg(vrt);
mi.push_reg(ra);
mi.push_reg(rb);
mi.def = Some(vrt);
mi
}
pub fn lower_xxmfacc(&self, inst: &Value, acc: MmaAccTile) -> Vec<MachineInstr> {
let acc_reg = self.get_acc_vreg(acc);
let vrt: u32 = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(PpcOpcode::XXMFACC as u32);
mi.push_reg(vrt);
mi.push_reg(acc_reg);
mi.def = Some(vrt);
vec![mi]
}
pub fn lower_xxmtacc(&self, inst: &Value, acc: MmaAccTile) -> Vec<MachineInstr> {
let acc_reg = self.get_acc_vreg(acc);
let vs_src: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::XXMTACC as u32);
mi.push_reg(acc_reg);
mi.push_reg(vs_src);
mi.def = Some(acc_reg);
vec![mi]
}
pub fn lower_xxsetaccz(&self, inst: &Value, acc: MmaAccTile) -> Vec<MachineInstr> {
let acc_reg = self.get_acc_vreg(acc);
let mut mi = MachineInstr::new(PpcOpcode::XXSETACCZ as u32);
mi.push_reg(acc_reg);
mi.def = Some(acc_reg);
vec![mi]
}
pub fn lower_mma_outer_int(&self, inst: &Value, otype: MmaOuterType, acc: MmaAccTile) -> Vec<MachineInstr> {
let acc_reg = self.get_acc_vreg(acc);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match otype {
MmaOuterType::I4 => PpcOpcode::XVI4GER as u32,
MmaOuterType::I8 => PpcOpcode::XVI8GER as u32,
MmaOuterType::I16 => PpcOpcode::XVI16GER as u32,
_ => PpcOpcode::XVI4GER as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(acc_reg);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(acc_reg);
vec![mi]
}
pub fn lower_mma_outer_float(&self, inst: &Value, otype: MmaOuterType, acc: MmaAccTile) -> Vec<MachineInstr> {
let acc_reg = self.get_acc_vreg(acc);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match otype {
MmaOuterType::F32 => PpcOpcode::XVF32GER as u32,
MmaOuterType::F64 => PpcOpcode::XVF64GER as u32,
_ => PpcOpcode::XVF32GER as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(acc_reg);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(acc_reg);
vec![mi]
}
pub fn lower_xxmfacc_inter(&self, inst: &Value, inter: MmaInterLane) -> Vec<MachineInstr> {
let vrt: u32 = self.get_or_create_vreg(inst);
let acc_reg = self.get_vreg_for_operand(inst, 0);
let opcode = match inter {
MmaInterLane::Inter4 => PpcOpcode::XXMFACC_INTER4 as u32,
MmaInterLane::Inter8 => PpcOpcode::XXMFACC_INTER8 as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vrt);
mi.push_reg(acc_reg);
mi.def = Some(vrt);
vec![mi]
}
pub fn lower_xxmtacc_inter(&self, inst: &Value, inter: MmaInterLane) -> Vec<MachineInstr> {
let acc_reg = self.get_vreg_for_operand(inst, 0);
let vs_src: u32 = self.get_vreg_for_operand(inst, 1);
let opcode = match inter {
MmaInterLane::Inter4 => PpcOpcode::XXMTACC_INTER4 as u32,
MmaInterLane::Inter8 => PpcOpcode::XXMTACC_INTER8 as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(acc_reg);
mi.push_reg(vs_src);
mi.def = Some(acc_reg);
vec![mi]
}
pub fn lower_mma_paired_outer(&self, inst: &Value, otype: MmaOuterType) -> Vec<MachineInstr> {
let _acc_a = self.get_vreg_for_operand(inst, 0);
let _acc_b = self.get_vreg_for_operand(inst, 1);
let vra: u32 = self.get_vreg_for_operand(inst, 2);
let vrb: u32 = self.get_vreg_for_operand(inst, 3);
let vrc: u32 = self.get_vreg_for_operand(inst, 4);
let vrd: u32 = self.get_vreg_for_operand(inst, 5);
let opcode = match otype {
MmaOuterType::I4 => PpcOpcode::PMXVI4GER8 as u32,
MmaOuterType::I8 => PpcOpcode::PMXVI8GER4 as u32,
MmaOuterType::F32 => PpcOpcode::PMXVF32GER as u32,
MmaOuterType::F64 => PpcOpcode::PMXVF64GER as u32,
_ => PpcOpcode::PMXVI4GER8 as u32,
};
let mut mi = MachineInstr::new(opcode);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.push_reg(vrc);
mi.push_reg(vrd);
vec![mi]
}
pub fn lower_paddi(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_prefix { return vec![self.lower_simple_addi(inst)]; }
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let imm_val: i64 = self.extract_const_i64(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PADDI as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(imm_val & 0x3FFFF); mi.def = Some(rt);
vec![mi]
}
pub fn lower_pli(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_prefix { return vec![self.lower_load_imm(inst)]; }
let rt: u32 = self.get_or_create_vreg(inst);
let imm_val: i64 = self.extract_const_i64(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLI as u32);
mi.push_reg(rt);
mi.push_imm(imm_val & 0x3FFFF); mi.def = Some(rt);
vec![mi]
}
pub fn lower_psubi(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_prefix { return vec![self.lower_simple_subi(inst)]; }
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let imm_val: i64 = self.extract_const_i64(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PSUBIS as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(imm_val & 0x3FFFF);
mi.def = Some(rt);
vec![mi]
}
pub fn lower_plwz(&self, inst: &Value) -> MachineInstr {
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLWZ as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rt);
mi
}
pub fn lower_pstw(&self, inst: &Value) -> MachineInstr {
let rs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PSTW as u32);
mi.push_reg(rs);
mi.push_reg(ra);
mi.push_imm(0);
mi
}
pub fn lower_pld(&self, inst: &Value) -> MachineInstr {
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLD as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rt);
mi
}
pub fn lower_pstd(&self, inst: &Value) -> MachineInstr {
let rs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PSTD as u32);
mi.push_reg(rs);
mi.push_reg(ra);
mi.push_imm(0);
mi
}
pub fn lower_plfs(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLFS as u32);
mi.push_reg(frt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(frt);
mi
}
pub fn lower_pstfs(&self, inst: &Value) -> MachineInstr {
let frs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PSTFS as u32);
mi.push_reg(frs);
mi.push_reg(ra);
mi.push_imm(0);
mi
}
pub fn lower_plha(&self, inst: &Value) -> MachineInstr {
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLHA as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rt);
mi
}
pub fn lower_plhz(&self, inst: &Value) -> MachineInstr {
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLHZ as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rt);
mi
}
pub fn lower_plwa(&self, inst: &Value) -> MachineInstr {
let rt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLWA as u32);
mi.push_reg(rt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rt);
mi
}
pub fn lower_plfd(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::PLFD as u32);
mi.push_reg(frt);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(frt);
mi
}
pub fn lower_pstfd(&self, inst: &Value) -> MachineInstr {
let frs: u32 = self.get_vreg_for_operand(inst, 0);
let ra: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::PSTFD as u32);
mi.push_reg(frs);
mi.push_reg(ra);
mi.push_imm(0);
mi
}
fn lower_simple_addi(&self, inst: &Value) -> MachineInstr {
let rd: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::ADDI as u32);
mi.push_reg(rd);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rd);
mi
}
fn lower_simple_subi(&self, inst: &Value) -> MachineInstr {
let rd: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::SUBF as u32);
mi.push_reg(rd);
mi.push_reg(ra);
mi.push_reg(R0 as u32);
mi.def = Some(rd);
mi
}
fn lower_load_imm(&self, inst: &Value) -> MachineInstr {
let rd: u32 = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(PpcOpcode::LI as u32);
mi.push_reg(rd);
mi.push_imm(0);
mi.def = Some(rd);
mi
}
pub fn lower_dfp_add(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FADD as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DADD as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_sub(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FSUB as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DSUB as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_mul(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FMUL as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DMUL as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_div(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FDIV as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DDIV as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_cmpu(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_dfp { return vec![self.fallback_to_softfloat(inst, PpcOpcode::FCMPU as u32)]; }
let bf: u32 = CR0 as u32;
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DCMPU as u32);
mi.push_reg(bf);
mi.push_reg(fra);
mi.push_reg(frb);
vec![mi]
}
pub fn lower_dfp_dtstdc(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_dfp { return Vec::new(); }
let bf: u32 = CR0 as u32;
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let _dcm: u32 = 0; let mut mi = MachineInstr::new(PpcOpcode::DTSTDC as u32);
mi.push_reg(bf);
mi.push_reg(fra);
mi.push_imm(0);
vec![mi]
}
pub fn lower_dfp_dtstdg(&self, inst: &Value) -> Vec<MachineInstr> {
if !self.has_dfp { return Vec::new(); }
let bf: u32 = CR0 as u32;
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::DTSTDG as u32);
mi.push_reg(bf);
mi.push_reg(fra);
mi.push_imm(0);
vec![mi]
}
pub fn lower_dfp_ddedpd(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FADD as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::DADD as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_denbcd(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FADD as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::DADD as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_dfp_diex(&self, inst: &Value) -> MachineInstr {
if !self.has_dfp { return self.fallback_to_softfloat(inst, PpcOpcode::FADD as u32); }
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::DADD as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
fn fallback_to_softfloat(&self, _inst: &Value, opcode: u32) -> MachineInstr {
MachineInstr::new(PpcOpcode::NOP as u32)
}
pub fn lower_fctiwz(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FCTIWZ as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctiw(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FADD as u32); mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctidz(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FCFID as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctid(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FADD as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fcfid(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FCFID as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctiwuz(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FCTIWZ as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctiwu(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FADD as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctiduz(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FCFID as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fctidu(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FADD as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_spe_evaddw(&self, inst: &Value) -> MachineInstr {
let rd: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let rb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::ADD as u32);
mi.push_reg(rd);
mi.push_reg(ra);
mi.push_reg(rb);
mi.def = Some(rd);
mi
}
pub fn lower_spe_evldd(&self, inst: &Value) -> MachineInstr {
let rd: u32 = self.get_or_create_vreg(inst);
let ra: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::LD as u32);
mi.push_reg(rd);
mi.push_reg(ra);
mi.push_imm(0);
mi.def = Some(rd);
mi
}
pub fn lower_vsx_scalar_add_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSADDSP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_sub_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSSUBSP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_mul_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSMULSP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_div_sp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSDIVSP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_add_dp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSADDDP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_sub_dp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSSUBDP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_mul_dp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSMULDP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_vsx_scalar_div_dp(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XSDIVDP as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
fn get_acc_vreg(&self, acc: MmaAccTile) -> VirtReg {
*self.acc_map.get(&acc.0).unwrap_or(&0)
}
fn get_or_create_vreg(&self, inst: &Value) -> VirtReg {
*self.vreg_map.get(&(inst.vid as usize)).unwrap_or(&0)
}
fn get_vreg_for_operand(&self, inst: &Value, idx: usize) -> VirtReg {
if idx >= inst.operands.len() { return 0; }
let op_ref = &inst.operands[idx];
let op = op_ref.borrow();
*self.vreg_map.get(&(op.vid as usize)).unwrap_or(&0)
}
fn get_or_create_vreg_for_vid(&self, vid: usize) -> VirtReg {
*self.vreg_map.get(&vid).unwrap_or(&0)
}
fn extract_const_i64(&self, inst: &Value, idx: usize) -> i64 {
if idx >= inst.operands.len() { return 0; }
0 }
pub fn lower_frsp(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRSP as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_frdp(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRDP as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_frim(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRIM as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_frip(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRIP as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_friz(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRIZ as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_frin(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FRIN as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fsqrt(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let frb: u32 = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(PpcOpcode::FSQRT_BFP as u32);
mi.push_reg(frt);
mi.push_reg(frb);
mi.def = Some(frt);
mi
}
pub fn lower_fmadd(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frc: u32 = self.get_vreg_for_operand(inst, 1);
let frb: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::FMADD_BFP as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.push_reg(frc);
mi.def = Some(frt);
mi
}
pub fn lower_fmsub(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frc: u32 = self.get_vreg_for_operand(inst, 1);
let frb: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::FMSUB_BFP as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.push_reg(frc);
mi.def = Some(frt);
mi
}
pub fn lower_fnmadd(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frc: u32 = self.get_vreg_for_operand(inst, 1);
let frb: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::FNMADD_BFP as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.push_reg(frc);
mi.def = Some(frt);
mi
}
pub fn lower_fnmsub(&self, inst: &Value) -> MachineInstr {
let frt: u32 = self.get_or_create_vreg(inst);
let fra: u32 = self.get_vreg_for_operand(inst, 0);
let frc: u32 = self.get_vreg_for_operand(inst, 1);
let frb: u32 = self.get_vreg_for_operand(inst, 2);
let mut mi = MachineInstr::new(PpcOpcode::FNMSUB_BFP as u32);
mi.push_reg(frt);
mi.push_reg(fra);
mi.push_reg(frb);
mi.push_reg(frc);
mi.def = Some(frt);
mi
}
pub fn lower_xxlxor(&self, inst: &Value) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let vra: u32 = self.get_vreg_for_operand(inst, 0);
let vrb: u32 = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(PpcOpcode::XXLXOR as u32);
mi.push_reg(vrt);
mi.push_reg(vra);
mi.push_reg(vrb);
mi.def = Some(vrt);
mi
}
pub fn lower_xxspltib(&self, inst: &Value, imm: u8) -> MachineInstr {
let vrt: u32 = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(PpcOpcode::XXSPLTIB as u32);
mi.push_reg(vrt);
mi.push_imm(imm as i64);
mi.def = Some(vrt);
mi
}
}
pub trait PpcMachineInstrExt {
fn is_vsx_instr(&self) -> bool;
fn is_mma_instr(&self) -> bool;
fn is_prefix_instr(&self) -> bool;
fn has_load_opcode(&self) -> bool;
fn has_store_opcode(&self) -> bool;
}
impl PpcMachineInstrExt for MachineInstr {
fn is_vsx_instr(&self) -> bool {
let op = self.opcode as i32;
op >= PpcOpcode::XSADDSP as i32 && op <= PpcOpcode::XVDIVDP as i32
}
fn is_mma_instr(&self) -> bool {
let op = self.opcode as i32;
op >= PpcOpcode::XXMFACC as i32 && op <= PpcOpcode::XXMTACC_INTER8 as i32
}
fn is_prefix_instr(&self) -> bool {
let op = self.opcode as i32;
op >= PpcOpcode::PLD as i32 && op <= PpcOpcode::PLWA as i32
}
fn has_load_opcode(&self) -> bool {
let op = self.opcode as i32;
matches!(PpcOpcode::LWZ as i32..=PpcOpcode::LMW as i32, _) || op == PpcOpcode::LD as i32
|| op >= PpcOpcode::PLWZ as i32 && op <= PpcOpcode::PLFD as i32
}
fn has_store_opcode(&self) -> bool {
let op = self.opcode as i32;
matches!(PpcOpcode::STW as i32..=PpcOpcode::STB as i32, _) || op == PpcOpcode::STD as i32
|| op >= PpcOpcode::PSTW as i32 && op <= PpcOpcode::PSTFD as i32
}
}
pub struct VsxPattern {
pub ir_op: Opcode,
pub result_type: VsxElementType,
pub is_vector: bool,
pub requires_feature: &'static str,
}
impl VsxPattern {
pub fn new(ir_op: Opcode, result_type: VsxElementType, is_vector: bool, feature: &'static str) -> Self {
VsxPattern { ir_op, result_type, is_vector, requires_feature: feature }
}
pub fn all_patterns() -> Vec<VsxPattern> {
vec![
VsxPattern::new(Opcode::FAdd, VsxElementType::SP, true, "vsx"),
VsxPattern::new(Opcode::FAdd, VsxElementType::DP, true, "vsx"),
VsxPattern::new(Opcode::FSub, VsxElementType::SP, true, "vsx"),
VsxPattern::new(Opcode::FSub, VsxElementType::DP, true, "vsx"),
VsxPattern::new(Opcode::FMul, VsxElementType::SP, true, "vsx"),
VsxPattern::new(Opcode::FMul, VsxElementType::DP, true, "vsx"),
VsxPattern::new(Opcode::FDiv, VsxElementType::SP, true, "vsx"),
VsxPattern::new(Opcode::FDiv, VsxElementType::DP, true, "vsx"),
]
}
}
pub struct MmaPattern {
pub outer_type: MmaOuterType,
pub is_paired: bool,
pub accumulator_indices: Vec<u8>,
}
impl MmaPattern {
pub fn new(outer_type: MmaOuterType, is_paired: bool, acc_indices: Vec<u8>) -> Self {
MmaPattern { outer_type, is_paired, accumulator_indices: acc_indices }
}
pub fn all_patterns() -> Vec<MmaPattern> {
vec![
MmaPattern::new(MmaOuterType::I4, false, vec![0]),
MmaPattern::new(MmaOuterType::I8, false, vec![0]),
MmaPattern::new(MmaOuterType::I16, false, vec![0]),
MmaPattern::new(MmaOuterType::F32, false, vec![0]),
MmaPattern::new(MmaOuterType::F64, false, vec![0]),
MmaPattern::new(MmaOuterType::I4, true, vec![0, 1]),
MmaPattern::new(MmaOuterType::I8, true, vec![0, 1]),
MmaPattern::new(MmaOuterType::F32, true, vec![0, 1]),
MmaPattern::new(MmaOuterType::F64, true, vec![0, 1]),
]
}
}
pub struct PrefixInstrDesc {
pub opcode: u32,
pub mnemonic: &'static str,
pub is_load: bool,
pub is_store: bool,
pub operands_count: u8,
}
impl PrefixInstrDesc {
pub fn all_descs() -> Vec<PrefixInstrDesc> {
vec![
PrefixInstrDesc { opcode: PpcOpcode::PLI as u32, mnemonic: "pli", is_load: false, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PADDI as u32, mnemonic: "paddi", is_load: false, is_store: false, operands_count: 3 },
PrefixInstrDesc { opcode: PpcOpcode::PLWZ as u32, mnemonic: "plwz", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PSTW as u32, mnemonic: "pstw", is_load: false, is_store: true, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLD as u32, mnemonic: "pld", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PSTD as u32, mnemonic: "pstd", is_load: false, is_store: true, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLFS as u32, mnemonic: "plfs", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PSTFS as u32, mnemonic: "pstfs", is_load: false, is_store: true, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLFD as u32, mnemonic: "plfd", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PSTFD as u32, mnemonic: "pstfd", is_load: false, is_store: true, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLHA as u32, mnemonic: "plha", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLHZ as u32, mnemonic: "plhz", is_load: true, is_store: false, operands_count: 2 },
PrefixInstrDesc { opcode: PpcOpcode::PLWA as u32, mnemonic: "plwa", is_load: true, is_store: false, operands_count: 2 },
]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vsx_element_type_sizes() {
assert_eq!(VsxElementType::SP.size_bytes(), 4);
assert_eq!(VsxElementType::DP.size_bytes(), 8);
assert_eq!(VsxElementType::I8.size_bytes(), 1);
assert_eq!(VsxElementType::I16.size_bytes(), 2);
assert_eq!(VsxElementType::I32.size_bytes(), 4);
assert_eq!(VsxElementType::I64.size_bytes(), 8);
}
#[test]
fn test_vsx_element_is_float() {
assert!(VsxElementType::SP.is_float());
assert!(VsxElementType::DP.is_float());
assert!(!VsxElementType::I32.is_float());
}
#[test]
fn test_mma_acc_tile() {
let acc = MmaAccTile::new(0).unwrap();
assert_eq!(acc.index(), 0);
assert!(MmaAccTile::new(8).is_none());
assert_eq!(MmaAccTile::all().len(), 8);
}
#[test]
fn test_mma_outer_type_widths() {
assert_eq!(MmaOuterType::I4.operand_width(), 4);
assert_eq!(MmaOuterType::I8.operand_width(), 8);
assert_eq!(MmaOuterType::I16.operand_width(), 16);
assert_eq!(MmaOuterType::F32.operand_width(), 32);
assert_eq!(MmaOuterType::F64.operand_width(), 64);
}
#[test]
fn test_prefix_type_mls() {
assert_eq!(PrefixType::LoadStore.prefix_word_mls(), 0b10);
assert_eq!(PrefixType::Arithmetic.prefix_word_mls(), 0b00);
assert_eq!(PrefixType::LoadExtended.prefix_word_mls(), 0b10);
}
#[test]
fn test_vle_format_sizes() {
assert_eq!(VleFormat::Short.size_bytes(), 2);
assert_eq!(VleFormat::Long.size_bytes(), 4);
}
#[test]
fn test_vsx_load_store_op_is_load() {
assert!(VsxLoadStoreOp::LoadIndexed.is_load());
assert!(!VsxLoadStoreOp::StoreIndexed.is_load());
assert!(VsxLoadStoreOp::LoadDoubleSplat.is_load());
}
#[test]
fn test_vsx_load_store_element_sizes() {
assert_eq!(VsxLoadStoreOp::LoadWordIndexed.element_size(), 4);
assert_eq!(VsxLoadStoreOp::LoadDoublewordIndexed.element_size(), 8);
assert_eq!(VsxLoadStoreOp::LoadByteIndexed.element_size(), 16);
}
#[test]
fn test_create_selector() {
let sel = PpcFullInstructionSelector::new(true)
.with_vsx(true)
.with_mma(false)
.with_dfp(false)
.with_prefix(true);
assert!(sel.is_64bit);
assert!(sel.has_vsx);
assert!(!sel.has_mma);
assert!(!sel.has_dfp);
assert!(sel.has_prefix);
}
#[test]
fn test_vsx_patterns_count() {
let patterns = VsxPattern::all_patterns();
assert_eq!(patterns.len(), 8);
assert!(patterns.iter().all(|p| p.is_vector));
}
#[test]
fn test_mma_patterns_count() {
let patterns = MmaPattern::all_patterns();
assert_eq!(patterns.len(), 9);
}
#[test]
fn test_prefix_instr_descs_count() {
let descs = PrefixInstrDesc::all_descs();
assert_eq!(descs.len(), 13);
}
#[test]
fn test_selector_feature_flags() {
let sel = PpcFullInstructionSelector::new(false);
assert!(!sel.has_vsx);
assert!(!sel.has_mma);
let sel = sel.with_vsx(true);
assert!(sel.has_vsx);
}
#[test]
fn test_all_vsx_supported_opcodes() {
let ops = [
PpcOpcode::XSADDSP, PpcOpcode::XSSUBSP, PpcOpcode::XSMULSP, PpcOpcode::XSDIVSP,
PpcOpcode::XSADDDP, PpcOpcode::XSSUBDP, PpcOpcode::XSMULDP, PpcOpcode::XSDIVDP,
];
for op in &ops {
let val = *op as u32;
assert!(val > 0, "VSX opcode should be non-zero");
}
}
}