use super::hexagon_instr_info::HexagonOpcode;
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};
fn u32_to_le_bytes(word: u32) -> Vec<u8> {
word.to_le_bytes().to_vec()
}
pub struct HexagonMCEncoder {
pub is_64bit: bool,
pub output: Vec<u8>,
}
impl HexagonMCEncoder {
pub fn new(_is_64bit: bool) -> Self {
Self {
is_64bit: false,
output: Vec::with_capacity(256),
}
}
pub fn encode_instruction(&mut self, mi: &MachineInstr) -> Vec<u8> {
let bytes = self.instruction_to_bytes(mi);
self.output.extend_from_slice(&bytes);
bytes
}
pub fn encode_function(&mut self, mf: &MachineFunction) -> Vec<u8> {
for block in &mf.blocks {
for instr in &block.instructions {
self.encode_instruction(instr);
}
}
std::mem::take(&mut self.output)
}
fn instruction_to_bytes(&self, mi: &MachineInstr) -> Vec<u8> {
let word = self.encode_by_opcode(mi);
u32_to_le_bytes(word)
}
fn encode_by_opcode(&self, mi: &MachineInstr) -> u32 {
match get_hexagon_opcode(mi.opcode) {
HexagonOpcode::ADD => self.encode_alu(0x00, mi),
HexagonOpcode::SUB => self.encode_alu(0x01, mi),
HexagonOpcode::AND => self.encode_alu(0x02, mi),
HexagonOpcode::OR => self.encode_alu(0x03, mi),
HexagonOpcode::XOR => self.encode_alu(0x04, mi),
HexagonOpcode::NEG => self.encode_alu_2r(0x05, mi),
HexagonOpcode::NOT => self.encode_alu_2r(0x06, mi),
HexagonOpcode::ABS => self.encode_alu_2r(0x07, mi),
HexagonOpcode::LSL => self.encode_alu(0x10, mi),
HexagonOpcode::LSR => self.encode_alu(0x11, mi),
HexagonOpcode::ASR => self.encode_alu(0x12, mi),
HexagonOpcode::MPY => self.encode_alu(0x20, mi),
HexagonOpcode::MPYU => self.encode_alu(0x21, mi),
HexagonOpcode::MPYI => self.encode_alu(0x22, mi),
HexagonOpcode::LDW => self.encode_mem(0x30, mi),
HexagonOpcode::LDB => self.encode_mem(0x31, mi),
HexagonOpcode::LDH => self.encode_mem(0x32, mi),
HexagonOpcode::LDD => self.encode_mem(0x33, mi),
HexagonOpcode::STW => self.encode_mem(0x34, mi),
HexagonOpcode::STB => self.encode_mem(0x35, mi),
HexagonOpcode::STH => self.encode_mem(0x36, mi),
HexagonOpcode::STD => self.encode_mem(0x37, mi),
HexagonOpcode::CMPEQ => self.encode_cmp(0x40, mi),
HexagonOpcode::CMPGT => self.encode_cmp(0x41, mi),
HexagonOpcode::CMPGTU => self.encode_cmp(0x42, mi),
HexagonOpcode::JUMP => self.encode_jump(0x50, mi),
HexagonOpcode::JUMPR => self.encode_jumpr(0x51, mi),
HexagonOpcode::JUMPr => self.encode_jumpr(0x52, mi),
HexagonOpcode::CALL => self.encode_call(0x53, mi),
HexagonOpcode::CALLR => self.encode_jumpr(0x54, mi),
HexagonOpcode::MOV => self.encode_alu_2r(0x0F, mi),
HexagonOpcode::NOP => 0x7C00,
HexagonOpcode::LI => self.encode_li(mi),
HexagonOpcode::VADD => self.encode_vec(0x60, mi),
HexagonOpcode::VSUB => self.encode_vec(0x61, mi),
HexagonOpcode::VMPY => self.encode_vec(0x62, mi),
_ => 0x7C00, }
}
fn encode_alu(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let rd = Self::get_reg(mi, 0);
let rs = Self::get_reg(mi, 1);
let rt = Self::get_reg(mi, 2);
(sub_op << 28) | (rd << 21) | (rs << 16) | (rt << 0)
}
fn encode_alu_2r(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let rd = Self::get_reg(mi, 0);
let rs = Self::get_reg(mi, 1);
(sub_op << 28) | (rd << 21) | (rs << 16)
}
fn encode_mem(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let rd = Self::get_reg(mi, 0);
let rs = Self::get_reg(mi, 1);
let offset: u32 = Self::get_imm(mi, 2) as u32 & 0xFFFF;
(sub_op << 28) | (rd << 21) | (rs << 16) | offset
}
fn encode_cmp(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let pd = Self::get_reg(mi, 0);
let rs = Self::get_reg(mi, 1);
let rt = Self::get_reg(mi, 2);
(sub_op << 28) | (pd << 23) | (rs << 16) | (rt << 0)
}
fn encode_jump(&self, sub_op: u32, _mi: &MachineInstr) -> u32 {
(sub_op << 28)
}
fn encode_jumpr(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let rs = Self::get_reg(mi, 0);
(sub_op << 28) | (rs << 16)
}
fn encode_call(&self, sub_op: u32, _mi: &MachineInstr) -> u32 {
(sub_op << 28)
}
fn encode_li(&self, mi: &MachineInstr) -> u32 {
let rd = Self::get_reg(mi, 0);
let imm: u32 = Self::get_imm(mi, 1) as u32 & 0xFFFF;
(0x0E << 28) | (rd << 21) | imm
}
fn encode_vec(&self, sub_op: u32, mi: &MachineInstr) -> u32 {
let vd = Self::get_reg(mi, 0);
let vs = Self::get_reg(mi, 1);
let vt = Self::get_reg(mi, 2);
(sub_op << 28) | (vd << 21) | (vs << 16) | (vt << 0)
}
fn get_reg(mi: &MachineInstr, index: usize) -> u32 {
mi.operands
.get(index)
.map(|op| match op {
MachineOperand::Reg(vr) => *vr & 0x1F,
MachineOperand::PhysReg(pr) => *pr & 0x1F,
_ => 0,
})
.unwrap_or(0) as u32
}
fn get_imm(mi: &MachineInstr, index: usize) -> i64 {
mi.operands
.get(index)
.map(|op| match op {
MachineOperand::Imm(imm) => *imm,
_ => 0,
})
.unwrap_or(0)
}
}
fn get_hexagon_opcode(opcode: u32) -> HexagonOpcode {
match opcode {
0 => HexagonOpcode::ADD,
1 => HexagonOpcode::SUB,
2 => HexagonOpcode::AND,
3 => HexagonOpcode::OR,
4 => HexagonOpcode::XOR,
5 => HexagonOpcode::NEG,
6 => HexagonOpcode::NOT,
20 => HexagonOpcode::LSL,
21 => HexagonOpcode::LSR,
22 => HexagonOpcode::ASR,
30 => HexagonOpcode::MPY,
31 => HexagonOpcode::MPYU,
32 => HexagonOpcode::MPYI,
50 => HexagonOpcode::LDW,
51 => HexagonOpcode::LDB,
52 => HexagonOpcode::LDH,
53 => HexagonOpcode::LDD,
60 => HexagonOpcode::STW,
61 => HexagonOpcode::STB,
62 => HexagonOpcode::STH,
63 => HexagonOpcode::STD,
80 => HexagonOpcode::JUMP,
81 => HexagonOpcode::JUMPR,
82 => HexagonOpcode::JUMPr,
83 => HexagonOpcode::CALL,
84 => HexagonOpcode::CALLR,
100 => HexagonOpcode::CMPEQ,
101 => HexagonOpcode::CMPGT,
102 => HexagonOpcode::CMPGTU,
103 => HexagonOpcode::CMPLT,
104 => HexagonOpcode::CMPLTU,
120 => HexagonOpcode::VADD,
121 => HexagonOpcode::VSUB,
122 => HexagonOpcode::VMPY,
140 => HexagonOpcode::NOP,
141 => HexagonOpcode::LI,
142 => HexagonOpcode::MOV,
_ => HexagonOpcode::NOP,
}
}