use super::hexagon_instr_info::HexagonOpcode;
use super::hexagon_register_info::*;
use crate::codegen::*;
use crate::opcode::Opcode;
use crate::value::Value;
use std::collections::HashMap;
pub struct HexagonInstructionSelector {
pub is_64bit: bool,
pub vreg_map: HashMap<usize, VirtReg>,
pub mbb: MachineBasicBlock,
pub func_name: String,
}
impl HexagonInstructionSelector {
pub fn new(_is_64bit: bool) -> Self {
HexagonInstructionSelector {
is_64bit: false,
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(inst, HexagonOpcode::ADD as u32)],
Opcode::Sub => vec![self.lower_three_reg(inst, HexagonOpcode::SUB as u32)],
Opcode::Mul => vec![self.lower_three_reg(inst, HexagonOpcode::MPY as u32)],
Opcode::And => vec![self.lower_three_reg(inst, HexagonOpcode::AND as u32)],
Opcode::Or => vec![self.lower_three_reg(inst, HexagonOpcode::OR as u32)],
Opcode::Xor => vec![self.lower_three_reg(inst, HexagonOpcode::XOR as u32)],
Opcode::Shl => vec![self.lower_three_reg(inst, HexagonOpcode::LSL as u32)],
Opcode::LShr => vec![self.lower_three_reg(inst, HexagonOpcode::LSR as u32)],
Opcode::AShr => vec![self.lower_three_reg(inst, HexagonOpcode::ASR 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)],
_ => 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(&mut self, inst: &Value, opcode: u32) -> MachineInstr {
let rs = self.get_vreg_for_operand(inst, 0);
let rt = 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(rs);
mi.push_reg(rt);
mi.def = Some(rd);
mi
}
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(HexagonOpcode::MOV as u32);
mi.push_reg(rd);
mi.push_reg(rs);
mi.def = Some(rd);
mi
}
fn lower_icmp(&mut self, inst: &Value) -> Vec<MachineInstr> {
let rs = self.get_vreg_for_operand(inst, 0);
let rt = self.get_vreg_for_operand(inst, 1);
let rd = self.get_or_create_vreg(inst);
let mut cmp = MachineInstr::new(HexagonOpcode::CMPEQ as u32);
cmp.push_reg(0); cmp.push_reg(rs);
cmp.push_reg(rt);
let mut mux = MachineInstr::new(HexagonOpcode::MUX as u32);
mux.push_reg(rd);
mux.push_reg(0); mux.push_imm(1);
mux.push_imm(0);
mux.def = Some(rd);
vec![cmp, mux]
}
fn lower_br(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(HexagonOpcode::JUMP 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(HexagonOpcode::JUMPr as u32);
mi.push_reg(LR as u32);
mi
}
fn lower_call(&mut self, inst: &Value) -> MachineInstr {
let mut mi = MachineInstr::new(HexagonOpcode::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 alloc = MachineInstr::new(HexagonOpcode::ALLOCFRAME as u32);
alloc.push_reg(rd);
alloc.def = Some(rd);
alloc
}
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(HexagonOpcode::LDW as u32);
mi.push_reg(rd);
mi.push_reg(base);
mi.push_imm(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(HexagonOpcode::STW as u32);
mi.push_reg(val);
mi.push_reg(addr);
mi.push_imm(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(HexagonOpcode::ADD as u32);
mi.push_reg(rd);
mi.push_reg(base);
mi.push_reg(offset);
mi.def = Some(rd);
mi
}
}