use super::msp430_instr_info::Msp430Opcode;
use super::msp430_register_info::*;
use crate::codegen::*;
use crate::opcode::Opcode;
use crate::value::Value;
use std::collections::HashMap;
pub struct Msp430InstructionSelector {
pub vreg_map: HashMap<usize, VirtReg>,
pub mbb: MachineBasicBlock,
pub func_name: String,
}
impl Msp430InstructionSelector {
pub fn new() -> Self {
Msp430InstructionSelector {
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_two_op(inst, Msp430Opcode::ADD as u32)],
Opcode::Sub => vec![self.lower_two_op(inst, Msp430Opcode::SUB as u32)],
Opcode::Mul => vec![self.lower_call_runtime(inst, "__mspabi_mpyi")],
Opcode::And => vec![self.lower_two_op(inst, Msp430Opcode::AND as u32)],
Opcode::Or => vec![self.lower_two_op(inst, Msp430Opcode::BIS as u32)],
Opcode::Xor => vec![self.lower_two_op(inst, Msp430Opcode::XOR as u32)],
Opcode::Shl => vec![self.lower_shl(inst)],
Opcode::LShr => vec![self.lower_shift_r(inst)],
Opcode::AShr => vec![self.lower_shift_ra(inst)],
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_mov(inst)],
Opcode::SExt => vec![self.lower_mov(inst)],
Opcode::Trunc => vec![self.lower_mov(inst)],
Opcode::GetElementPtr => vec![self.lower_gep(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_two_op(&mut self, inst: &Value, opcode: u32) -> MachineInstr {
let src = self.get_vreg_for_operand(inst, 0);
let dst = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(opcode);
mi.push_reg(dst); mi.push_reg(src);
mi.def = Some(dst);
mi
}
fn lower_mov(&mut self, inst: &Value) -> MachineInstr {
let src = self.get_vreg_for_operand(inst, 0);
let dst = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(Msp430Opcode::MOV as u32);
mi.push_reg(dst);
mi.push_reg(src);
mi.def = Some(dst);
mi
}
fn lower_shl(&mut self, inst: &Value) -> MachineInstr {
let dst = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(Msp430Opcode::RLA as u32);
mi.push_reg(dst);
mi.def = Some(dst);
mi
}
fn lower_shift_r(&mut self, _inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(Msp430Opcode::CLR as u32);
mi
}
fn lower_shift_ra(&mut self, _inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(Msp430Opcode::RRA as u32);
mi
}
fn lower_icmp(&mut self, inst: &Value) -> Vec<MachineInstr> {
let src = self.get_vreg_for_operand(inst, 0);
let dst_val = self.get_vreg_for_operand(inst, 1);
let rd = self.get_or_create_vreg(inst);
let mut cmp = MachineInstr::new(Msp430Opcode::CMP as u32);
cmp.push_reg(dst_val);
cmp.push_reg(src);
let mut clr = MachineInstr::new(Msp430Opcode::CLR as u32);
clr.push_reg(rd);
clr.def = Some(rd);
vec![cmp, clr]
}
fn lower_br(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(Msp430Opcode::JMP 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 {
MachineInstr::new(Msp430Opcode::RET as u32)
}
fn lower_call(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(Msp430Opcode::CALL as u32);
if let Some(callee) = inst.operands.get(0) {
let func = callee.borrow();
mi.push_label(&func.name);
}
mi
}
fn lower_call_runtime(&mut self, _inst: &Value, name: &str) -> MachineInstr {
let mut mi = MachineInstr::new(Msp430Opcode::CALL as u32);
mi.push_label(name);
mi
}
fn lower_alloca(&mut self, inst: &Value) -> MachineInstr {
let rd = self.get_or_create_vreg(inst);
let mut mi = MachineInstr::new(Msp430Opcode::MOV as u32);
mi.push_reg(rd);
mi.push_reg(SP as u32);
mi.def = Some(rd);
mi
}
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(Msp430Opcode::MOV as u32);
mi.push_reg(rd);
mi.push_reg(base);
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(Msp430Opcode::MOV as u32);
mi.push_reg(val);
mi.push_reg(addr);
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(Msp430Opcode::ADD as u32);
mi.push_reg(rd);
mi.push_reg(base);
mi.push_reg(offset);
mi.def = Some(rd);
mi
}
}