refactor(backend): Remove literal pool

This commit is contained in:
2026-06-12 18:51:43 +08:00
parent e3aa2e21c0
commit 1de7e2876c
3 changed files with 91 additions and 33 deletions
+53 -17
View File
@@ -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
View File
@@ -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 -1
View File
@@ -2,4 +2,5 @@ pub struct ARMAsmVar {
pub name: String,
pub size: usize,
pub align: usize,
}
pub init: Option<i32>,
}