use super::sparc_instr_info::SparcOpcode;
use super::sparc_register_info::*;
use crate::codegen::*;
use crate::opcode::Opcode;
use crate::value::Value;
use std::collections::HashMap;
pub struct SparcInstructionSelector {
pub is_64bit: bool,
pub vreg_map: HashMap<usize, VirtReg>,
pub mbb: MachineBasicBlock,
pub func_name: String,
}
impl SparcInstructionSelector {
pub fn new(is_64bit: bool) -> Self {
SparcInstructionSelector {
is_64bit,
vreg_map: HashMap::new(),
mbb: MachineBasicBlock {
name: String::new(),
instructions: Vec::new(),
successors: Vec::new(),
},
func_name: String::new(),
}
}
pub fn select(&mut self, mf: &mut MachineFunction, func: &Value) {
self.func_name = func.name.clone();
if self.func_name.is_empty() {
self.func_name = format!(".Lfunc{}", func.vid);
}
self.vreg_map.clear();
for bb_ref in &func.successors {
let bb = bb_ref.borrow();
self.mbb = MachineBasicBlock {
name: bb.name.clone(),
instructions: Vec::new(),
successors: Vec::new(),
};
for inst_ref in &bb.operands {
let inst = inst_ref.borrow();
if inst.is_instruction() {
let instrs = self.select_instruction(&inst);
self.mbb.instructions.extend(instrs);
}
}
mf.push_block(self.mbb.clone());
}
}
pub fn select_instruction(&mut self, inst: &Value) -> Vec<MachineInstr> {
let opcode = match inst.get_opcode() {
Some(op) => op,
None => return Vec::new(),
};
match opcode {
Opcode::Add => vec![self.lower_three_reg_op(inst, SparcOpcode::ADD as u32)],
Opcode::FAdd => vec![self.lower_fp_binop(
inst,
SparcOpcode::FADDS as u32,
SparcOpcode::FADDD as u32,
)],
Opcode::Sub => vec![self.lower_three_reg_op(inst, SparcOpcode::SUB as u32)],
Opcode::FSub => vec![self.lower_fp_binop(
inst,
SparcOpcode::FSUBS as u32,
SparcOpcode::FSUBD as u32,
)],
Opcode::Mul => vec![self.lower_mul_op(inst)],
Opcode::FMul => vec![self.lower_fp_binop(
inst,
SparcOpcode::FMULS as u32,
SparcOpcode::FMULD as u32,
)],
Opcode::SDiv => vec![self.lower_div_op(inst, true)],
Opcode::UDiv => vec![self.lower_div_op(inst, false)],
Opcode::FDiv => vec![self.lower_fp_binop(
inst,
SparcOpcode::FDIVS as u32,
SparcOpcode::FDIVD as u32,
)],
Opcode::And => vec![self.lower_three_reg_op(inst, SparcOpcode::AND as u32)],
Opcode::Or => vec![self.lower_three_reg_op(inst, SparcOpcode::OR as u32)],
Opcode::Xor => vec![self.lower_three_reg_op(inst, SparcOpcode::XOR as u32)],
Opcode::Shl => vec![self.lower_shift_op(inst, SparcOpcode::SLL as u32)],
Opcode::LShr => vec![self.lower_shift_op(inst, SparcOpcode::SRL as u32)],
Opcode::AShr => vec![self.lower_shift_op(inst, SparcOpcode::SRA as u32)],
Opcode::ICmp => self.lower_icmp(inst),
Opcode::Br => vec![self.lower_br(inst)],
Opcode::Ret => vec![self.lower_ret(inst)],
Opcode::Call => vec![self.lower_call(inst)],
Opcode::Alloca => vec![self.lower_alloca(inst)],
Opcode::Load => vec![self.lower_load(inst)],
Opcode::Store => vec![self.lower_store(inst)],
Opcode::ZExt => vec![self.lower_move(inst)],
Opcode::SExt => vec![self.lower_move(inst)],
Opcode::Trunc => vec![self.lower_move(inst)],
Opcode::GetElementPtr => vec![self.lower_gep(inst)],
Opcode::Select => self.lower_select(inst),
_ => Vec::new(),
}
}
fn get_or_create_vreg(&mut self, val: &Value) -> VirtReg {
let vid_key = val.vid as usize;
if let Some(vreg) = self.vreg_map.get(&vid_key) {
return *vreg;
}
let vreg = self.vreg_map.len() as u32;
self.vreg_map.insert(vid_key, vreg);
vreg
}
fn get_vreg_for_operand(&mut self, inst: &Value, index: usize) -> VirtReg {
if let Some(op) = inst.operands.get(index) {
self.get_or_create_vreg(&op.borrow())
} else {
0
}
}
fn lower_three_reg_op(&mut self, inst: &Value, opcode: u32) -> MachineInstr {
let rs1 = self.get_vreg_for_operand(inst, 0);
let rs2 = self.get_vreg_for_operand(inst, 1);
let rd = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rd);
mi.push_reg(rs1);
mi.push_reg(rs2);
mi.def = Some(rd);
mi
}
fn lower_shift_op(&mut self, inst: &Value, opcode: u32) -> MachineInstr {
self.lower_three_reg_op(inst, opcode)
}
fn lower_mul_op(&mut self, inst: &Value) -> MachineInstr {
if self.is_64bit {
self.lower_three_reg_op(inst, SparcOpcode::MULX as u32)
} else {
self.lower_three_reg_op(inst, SparcOpcode::SMUL as u32)
}
}
fn lower_div_op(&mut self, inst: &Value, signed: bool) -> MachineInstr {
let opcode = if self.is_64bit {
if signed {
SparcOpcode::SDIVX as u32
} else {
SparcOpcode::UDIVX as u32
}
} else {
if signed {
SparcOpcode::SDIV as u32
} else {
SparcOpcode::UDIV as u32
}
};
self.lower_three_reg_op(inst, opcode)
}
fn lower_fp_binop(
&mut self,
inst: &Value,
single_opcode: u32,
double_opcode: u32,
) -> MachineInstr {
let opcode = if self.is_64bit {
double_opcode
} else {
single_opcode
};
self.lower_three_reg_op(inst, opcode)
}
fn lower_move(&mut self, inst: &Value) -> MachineInstr {
let rs = self.get_vreg_for_operand(inst, 0);
let rd = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(SparcOpcode::OR as u32);
mi.push_reg(rd);
mi.push_reg(rs);
mi.push_reg(0); mi.def = Some(rd);
mi
}
fn lower_icmp(&mut self, inst: &Value) -> Vec<MachineInstr> {
let rs1 = self.get_vreg_for_operand(inst, 0);
let rs2 = self.get_vreg_for_operand(inst, 1);
let rd = self.get_or_create_vreg(inst);
let mut subcc = MachineInstr::new(SparcOpcode::SUBcc as u32);
subcc.push_reg(0); subcc.push_reg(rs1);
subcc.push_reg(rs2);
let mut mov_true = MachineInstr::new(SparcOpcode::OR as u32);
mov_true.push_reg(rd);
mov_true.push_reg(0); mov_true.push_reg(0);
mov_true.def = Some(rd);
vec![subcc, mov_true]
}
fn lower_br(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(SparcOpcode::BA as u32);
if let Some(dest) = inst.operands.get(0) {
let bb = dest.borrow();
mi.push_label(&bb.name);
}
mi
}
fn lower_ret(&mut self, _inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(SparcOpcode::RET as u32);
mi
}
fn lower_call(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(SparcOpcode::CALL as u32);
if let Some(callee) = inst.operands.get(0) {
let func = callee.borrow();
mi.push_label(&func.name);
}
mi
}
fn lower_alloca(&mut self, inst: &Value) -> MachineInstr {
let rd = self.get_or_create_vreg(inst);
let mut sub_sp = MachineInstr::new(SparcOpcode::SUB as u32);
sub_sp.push_reg(SP as u32); sub_sp.push_reg(SP as u32); sub_sp.push_imm(0);
let mut mov = MachineInstr::new(SparcOpcode::OR as u32);
mov.push_reg(rd);
mov.push_reg(SP as u32);
mov.push_reg(0); mov.def = Some(rd);
mov
}
fn lower_load(&mut self, inst: &Value) -> MachineInstr {
let rd = self.get_or_create_vreg(inst);
let base = self.get_vreg_for_operand(inst, 0);
let mut mi = MachineInstr::new(SparcOpcode::LD as u32);
mi.push_reg(rd);
mi.push_reg(base);
mi.push_reg(0); mi.def = Some(rd);
mi
}
fn lower_store(&mut self, inst: &Value) -> MachineInstr {
let val = self.get_vreg_for_operand(inst, 0);
let addr = self.get_vreg_for_operand(inst, 1);
let mut mi = MachineInstr::new(SparcOpcode::ST as u32);
mi.push_reg(val);
mi.push_reg(addr);
mi.push_reg(0); mi
}
fn lower_gep(&mut self, inst: &Value) -> MachineInstr {
let base = self.get_vreg_for_operand(inst, 0);
let offset = self.get_vreg_for_operand(inst, 1);
let rd = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(SparcOpcode::ADD as u32);
mi.push_reg(rd);
mi.push_reg(base);
mi.push_reg(offset);
mi.def = Some(rd);
mi
}
fn lower_select(&mut self, inst: &Value) -> Vec<MachineInstr> {
let cond = self.get_vreg_for_operand(inst, 0);
let true_val = self.get_vreg_for_operand(inst, 1);
let false_val = self.get_vreg_for_operand(inst, 2);
let rd = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(SparcOpcode::OR as u32);
mi.push_reg(rd);
mi.push_reg(true_val);
mi.push_reg(0);
mi.def = Some(rd);
vec![mi]
}
}