use crate::ir::{Module, Function, FunctionValue};
use crate::entities::{Symbol};
use crate::instruction::{InstructionData, Opcode};
use std::collections::HashMap;
use vermilion_object::{Artifact};
pub struct Binemit {
pub module: Module,
artifact: Artifact,
offset: usize,
symbols: HashMap<String, i64>,
}
impl Binemit {
pub fn new(module: Module) -> Self {
Binemit {
module,
artifact: Artifact::new(),
offset: 0,
symbols: HashMap::new()
}
}
fn opcode_byte(opcode: Opcode) -> u8 {
match opcode {
Opcode::Pop => 0x05,
Opcode::Clone => 0x06,
Opcode::Clear => 0x07,
Opcode::Trap => 0x0a,
Opcode::BooleanAdd => 0x0e,
Opcode::BooleanSubtract => 0x0f,
Opcode::ByteAdd => 0x10,
Opcode::ByteSubtract => 0x11,
Opcode::ByteMultiply => 0x12,
Opcode::ByteDivide => 0x13,
Opcode::ByteRemainder => 0x14,
Opcode::IntegerAdd => 0x15,
Opcode::IntegerSubtract => 0x16,
Opcode::IntegerMultiply => 0x17,
Opcode::IntegerDivide => 0x18,
Opcode::IntegerRemainder => 0x19,
Opcode::FloatAdd => 0x1a,
Opcode::FloatSubtract => 0x1b,
Opcode::FloatMultiply => 0x1c,
Opcode::FloatDivide => 0x1d,
Opcode::FloatRemainder => 0x1e,
Opcode::CastBoolean => 0x1f,
Opcode::CastByte => 0x20,
Opcode::CastInteger => 0x21,
Opcode::CastFloat => 0x22,
Opcode::NegateBoolean => 0x23,
Opcode::NegateByte => 0x0, Opcode::NegateInteger => 0x24,
Opcode::NegateFloat => 0x25,
Opcode::Load => 0x26,
Opcode::Store => 0x27,
Opcode::Realloc => 0x28,
Opcode::HeapSize => 0x29,
Opcode::Alloc => 0x2a,
Opcode::ReallocSection => 0x2b,
Opcode::SectionAddr => 0x2c,
Opcode::SectionShiftLeft => 0x2d,
Opcode::SectionShiftRight => 0x2e,
Opcode::Free => 0x2f,
Opcode::FreeAndShift => 0x30,
Opcode::Branch => 0x31,
Opcode::BranchIfZero => 0x32,
Opcode::BranchIfNotZero => 0x33,
Opcode::Equal => 0x34,
Opcode::GreaterThan => 0x35,
Opcode::LessThan => 0x36,
Opcode::GreaterThanOrEqual => 0x37,
Opcode::LessThanOrEqual => 0x38,
Opcode::Call => 0x39,
Opcode::Return => 0x3a
}
}
fn get_instruction_size(&self, func: &Function, inst: &InstructionData) -> i64 {
let mut size = 0;
for item in &inst.args {
size += self.get_size(func, func.values.get(item.0 as usize).unwrap());
}
size += 1;
size
}
pub fn get_size(&self, func: &Function, value: &FunctionValue) -> i64 {
let size: i64;
match value {
FunctionValue::Block(_) => {
size = 9;
},
FunctionValue::Boolean(_) => {
size = 2;
},
FunctionValue::Byte(_) => {
size = 2;
},
FunctionValue::Integer(_) => {
size = 9;
},
FunctionValue::Float(_) => {
size = 9;
},
FunctionValue::Symbol(_) => {
size = 9;
},
FunctionValue::Instruction(data) => {
size = self.get_instruction_size(func, data);
}
}
size
}
fn compile_instruction(&self, func: &Function, blocks: &Vec<usize>, inst: &InstructionData) -> Vec<u8> {
let mut val = Vec::new();
for arg in &inst.args {
val.append(&mut self.compile_value(func, blocks, &func.values[arg.0 as usize]));
}
val.push(Binemit::opcode_byte(inst.opcode.clone()));
val
}
fn compile_value(&self, func: &Function, blocks: &Vec<usize>, value: &FunctionValue) -> Vec<u8> {
let mut val = Vec::new();
match value {
FunctionValue::Block(bl) => {
val.push(3);
let mut addr = (bl.0 as i64).to_le_bytes().to_vec();
val.append(&mut addr);
},
FunctionValue::Boolean(r) => {
val.push(1);
if *r {
val.push(1);
} else {
val.push(0);
}
},
FunctionValue::Byte(r) => {
val.push(2);
val.push(*r);
},
FunctionValue::Integer(r) => {
val.push(3);
let mut addr = r.to_le_bytes().to_vec();
val.append(&mut addr);
},
FunctionValue::Float(r) => {
val.push(4);
let mut addr = r.to_le_bytes().to_vec();
val.append(&mut addr);
},
FunctionValue::Symbol(r) => {
val.push(3);
let mut addr = self.symbols.get(r).unwrap().to_le_bytes().to_vec();
val.append(&mut addr);
},
FunctionValue::Instruction(data) => {
val = self.compile_instruction(func, blocks, &data);
}
}
val
}
fn calc_addresses(&self, func: &Function) -> Vec<usize> {
let mut blocks = Vec::new();
let mut end = self.offset;
for block in &func.blocks {
let insts = &block.instructions;
let mut size = 0;
for inst in insts {
size += self.get_instruction_size(&func, &inst);
}
blocks.push(end);
end += size as usize;
}
blocks
}
fn compile_function(&self, func: &Function) -> Vec<u8> {
let mut bytes = Vec::new();
let blocks = self.calc_addresses(&func);
for block in &func.blocks {
for inst in &block.instructions {
bytes.append(&mut self.compile_instruction(func, &blocks, &inst))
}
}
bytes
}
pub fn emit(&mut self) -> Artifact {
let mut artifact = self.artifact.clone();
let mut bytes = Vec::new();
let mut id = 0;
for symbol in &self.module.symbols {
self.symbols.insert(symbol.0.to_string(), id);
id += 1;
}
for symbol in &self.module.symbols {
match symbol.1 {
Symbol::Local(func) => {
artifact.symbols.insert(self.symbols[&symbol.0.clone()], vermilion_object::Symbol::Local(symbol.0.to_string(), self.offset));
bytes.append(&mut self.compile_function(&func));
},
Symbol::External => {
artifact.declare_function(self.symbols[&symbol.0.clone()], symbol.0.to_string());
}
}
}
artifact.program = bytes;
artifact
}
}