refactor(backend): Remove literal pool
This commit is contained in:
+53
-17
@@ -3,8 +3,9 @@ use std::{fmt::Display, ops::Add};
|
||||
use crate::{backend::register_allocator::{REG_FP, REG_LR, REG_PC, REG_R0, REG_R1, REG_R2, REG_R3, REG_R12, REG_SP, Register}, ir::types::CmpOp as IRCmpOp};
|
||||
pub enum ARMInstr{
|
||||
Move(MoveInstr),
|
||||
Movw(MovwInstr),
|
||||
Movt(MovtInstr),
|
||||
Load(LoadInstr),
|
||||
LoadPseudo(LoadPseudoInstr),
|
||||
Store(StoreInstr),
|
||||
Mul(MulInstr),
|
||||
SDiv(SDivInstr),
|
||||
@@ -24,8 +25,9 @@ impl Display for ARMInstr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ARMInstr::Move(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::Movw(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::Movt(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::Load(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::LoadPseudo(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::Store(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::Mul(instr) => write!(f, "{}", instr),
|
||||
ARMInstr::SDiv(instr) => write!(f, "{}", instr),
|
||||
@@ -45,7 +47,7 @@ impl Display for ARMInstr {
|
||||
pub enum RegisterOrImm {
|
||||
Reg(Register),
|
||||
Imm(i32),
|
||||
}
|
||||
}
|
||||
impl Display for RegisterOrImm {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
@@ -73,7 +75,7 @@ impl From<IRCmpOp> for ConditionCode {
|
||||
IRCmpOp::Ge => ConditionCode::Ge,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Display for ConditionCode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let code_str = match self {
|
||||
@@ -127,6 +129,52 @@ impl Display for MoveInstr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MoveWideOperand {
|
||||
Imm(u16),
|
||||
Symbol(String),
|
||||
}
|
||||
|
||||
pub struct MovwInstr(Register, MoveWideOperand);
|
||||
impl MovwInstr {
|
||||
pub fn new_imm(dest: Register, value: u16) -> ARMInstr {
|
||||
ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Imm(value)))
|
||||
}
|
||||
|
||||
pub fn new_symbol(dest: Register, name: String) -> ARMInstr {
|
||||
ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Symbol(name)))
|
||||
}
|
||||
}
|
||||
impl Display for MovwInstr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let MovwInstr(dest, operand) = self;
|
||||
match operand {
|
||||
MoveWideOperand::Imm(value) => write!(f, "movw {}, #{}", dest, value),
|
||||
MoveWideOperand::Symbol(name) => write!(f, "movw {}, #:lower16:{}", dest, name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MovtInstr(Register, MoveWideOperand);
|
||||
impl MovtInstr {
|
||||
pub fn new_imm(dest: Register, value: u16) -> ARMInstr {
|
||||
ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Imm(value)))
|
||||
}
|
||||
|
||||
pub fn new_symbol(dest: Register, name: String) -> ARMInstr {
|
||||
ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Symbol(name)))
|
||||
}
|
||||
}
|
||||
impl Display for MovtInstr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let MovtInstr(dest, operand) = self;
|
||||
match operand {
|
||||
MoveWideOperand::Imm(value) => write!(f, "movt {}, #{}", dest, value),
|
||||
MoveWideOperand::Symbol(name) => write!(f, "movt {}, #:upper16:{}", dest, name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoadInstr(Register, Register, Option<RegisterOrImm>);
|
||||
impl LoadInstr {
|
||||
pub fn new(dest: Register, base: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
||||
@@ -146,18 +194,6 @@ impl Display for LoadInstr {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct LoadPseudoInstr(Register, String);
|
||||
impl LoadPseudoInstr {
|
||||
pub fn new(dest: Register, name: String) -> ARMInstr {
|
||||
ARMInstr::LoadPseudo(LoadPseudoInstr(dest, name))
|
||||
}
|
||||
}
|
||||
impl Display for LoadPseudoInstr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let LoadPseudoInstr(dest, name) = self;
|
||||
write!(f, "ldr {}, ={}", dest, name)
|
||||
}
|
||||
}
|
||||
pub struct StoreInstr(Register, Register, Option<RegisterOrImm>);
|
||||
impl StoreInstr {
|
||||
pub fn new(src: Register, dest: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
||||
@@ -347,4 +383,4 @@ impl BInstr {
|
||||
pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr {
|
||||
ARMInstr::B(BInstr(Some(condition), label_name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-15
@@ -1,6 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_FP, REG_R0, REG_R1, REG_R2, REG_R3, REG_SP, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}};
|
||||
use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, MoveInstr, MovtInstr, MovwInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_FP, REG_R0, REG_R1, REG_R2, REG_R3, REG_SP, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}};
|
||||
use crate::ir::types::BinaryOp as IRBinaryOp;
|
||||
use crate::ir::types::CmpOp as IRCmpOp;
|
||||
use crate::ir::types::UnaryOp as IRUnaryOp;
|
||||
@@ -19,6 +19,22 @@ const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3];
|
||||
const ARM_DATA_IMM_CHUNK: i32 = 255;
|
||||
const ARM_LOAD_STORE_MAX_OFFSET: i32 = 4095;
|
||||
|
||||
fn emit_load_imm32(dest: Register, value: i32, instrs: &mut Vec<ARMInstr>) {
|
||||
let bits = value as u32;
|
||||
let lower = (bits & 0xffff) as u16;
|
||||
let upper = (bits >> 16) as u16;
|
||||
|
||||
instrs.push(MovwInstr::new_imm(dest, lower));
|
||||
if upper != 0 {
|
||||
instrs.push(MovtInstr::new_imm(dest, upper));
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_load_symbol_addr(dest: Register, name: String, instrs: &mut Vec<ARMInstr>) {
|
||||
instrs.push(MovwInstr::new_symbol(dest, name.clone()));
|
||||
instrs.push(MovtInstr::new_symbol(dest, name));
|
||||
}
|
||||
|
||||
fn emit_sub_imm(dest: Register, left: Register, imm: i32, instrs: &mut Vec<ARMInstr>) {
|
||||
if imm == 0 {
|
||||
if dest != left {
|
||||
@@ -97,7 +113,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
|
||||
}
|
||||
match variable.var_type {
|
||||
VariableType::Global => {
|
||||
instrs.push(LoadPseudoInstr::new(var_alloc.reg, format!("global_var_{}", variable.index)));
|
||||
emit_load_symbol_addr(var_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||
}
|
||||
_ => {
|
||||
let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared");
|
||||
@@ -112,7 +128,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
|
||||
let var_reg = var_alloc.reg;
|
||||
// if !var_alloc.is_reused {
|
||||
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
||||
instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index)));
|
||||
emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||
instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None));
|
||||
// }
|
||||
var_alloc
|
||||
@@ -144,7 +160,7 @@ fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut Register
|
||||
match variable.var_type {
|
||||
VariableType::Global => {
|
||||
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
||||
instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index)));
|
||||
emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||
instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
|
||||
},
|
||||
VariableType::ParamTemp(_) => {
|
||||
@@ -169,7 +185,7 @@ impl Generator {
|
||||
for ir_instr in ir_instrs {
|
||||
match ir_instr {
|
||||
IRInstr::DefineFunc(func, args, body) => self.emit_func_def(func, args, body),
|
||||
IRInstr::Declare(var) => self.emit_global_decl(var),
|
||||
IRInstr::DeclareGlobal(var, init) => self.emit_global_decl(var, init),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -181,8 +197,8 @@ impl Generator {
|
||||
text.push_str(&format!(".comm {}, {}, {}\n", var.name, var.size, var.align));
|
||||
}
|
||||
for var in &self.var_inited {
|
||||
text.push_str(&format!(".data\n.align {}\n.global {}\n.type {}, @object\n:{}\n", var.align, var.name, var.name, var.name));
|
||||
text.push_str(&format!(".word 0\n"));
|
||||
text.push_str(&format!(".data\n.align {}\n.global {}\n.type {}, %object\n{}:\n", var.align, var.name, var.name, var.name));
|
||||
text.push_str(&format!(".word {}\n", var.init.unwrap_or(0)));
|
||||
}
|
||||
text.push_str(".text\n");
|
||||
for instr in &self.instrs {
|
||||
@@ -191,13 +207,18 @@ impl Generator {
|
||||
text
|
||||
}
|
||||
|
||||
|
||||
fn emit_global_decl(&mut self, var: Variable) {
|
||||
self.var_uninited.push(ARMAsmVar {
|
||||
fn emit_global_decl(&mut self, var: Variable, init: Option<i32>) {
|
||||
let asm_var = ARMAsmVar {
|
||||
name: format!("global_var_{}", var.index),
|
||||
size: var.data_type.size_in_bytes(),
|
||||
align: DEFAULT_VAR_ALIGN,
|
||||
});
|
||||
init,
|
||||
};
|
||||
if asm_var.init.is_some() {
|
||||
self.var_inited.push(asm_var);
|
||||
} else {
|
||||
self.var_uninited.push(asm_var);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_func_def(&mut self, func: Function, _args: Vec<Variable>, body: Vec<IRInstr>) {
|
||||
@@ -239,7 +260,7 @@ impl Generator {
|
||||
encounter_entry = true;
|
||||
emit_sub_sp_imm(stack_size_needed as i32, &mut self.instrs);
|
||||
},
|
||||
IRInstr::DefineFunc(_, _, _) => unreachable!(),
|
||||
IRInstr::DefineFunc(_, _, _) | IRInstr::DeclareGlobal(_, _) => unreachable!(),
|
||||
IRInstr::Cmp(variable, left, cmp_op, right) => self.emit_cmp(variable, left, cmp_op, right, &var_index_to_stack_offset),
|
||||
IRInstr::Unary(variable, unary_op, variable1) => self.emit_unary(variable, unary_op, variable1, &var_index_to_stack_offset),
|
||||
IRInstr::Goto(index) => self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, index))),
|
||||
@@ -272,7 +293,7 @@ impl Generator {
|
||||
},
|
||||
VariableOrIntLit::IntLit(lit) => {
|
||||
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
||||
self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit)));
|
||||
emit_load_imm32(alloc.reg, lit, &mut self.instrs);
|
||||
alloc
|
||||
},
|
||||
};
|
||||
@@ -283,7 +304,7 @@ impl Generator {
|
||||
},
|
||||
VariableOrIntLit::IntLit(lit) => {
|
||||
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
||||
self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit)));
|
||||
emit_load_imm32(alloc.reg, lit, &mut self.instrs);
|
||||
alloc
|
||||
},
|
||||
};
|
||||
@@ -335,7 +356,7 @@ impl Generator {
|
||||
let src_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
||||
self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Reg(src_alloc.reg)));
|
||||
},
|
||||
MoveRValue::ConstInt(literal_int) => self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Imm(literal_int))),
|
||||
MoveRValue::ConstInt(literal_int) => emit_load_imm32(dest_register, literal_int, &mut self.instrs),
|
||||
};
|
||||
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ pub struct ARMAsmVar {
|
||||
pub name: String,
|
||||
pub size: usize,
|
||||
pub align: usize,
|
||||
}
|
||||
pub init: Option<i32>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user