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}; 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{ pub enum ARMInstr{
Move(MoveInstr), Move(MoveInstr),
Movw(MovwInstr),
Movt(MovtInstr),
Load(LoadInstr), Load(LoadInstr),
LoadPseudo(LoadPseudoInstr),
Store(StoreInstr), Store(StoreInstr),
Mul(MulInstr), Mul(MulInstr),
SDiv(SDivInstr), SDiv(SDivInstr),
@@ -24,8 +25,9 @@ impl Display for ARMInstr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
ARMInstr::Move(instr) => write!(f, "{}", instr), 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::Load(instr) => write!(f, "{}", instr),
ARMInstr::LoadPseudo(instr) => write!(f, "{}", instr),
ARMInstr::Store(instr) => write!(f, "{}", instr), ARMInstr::Store(instr) => write!(f, "{}", instr),
ARMInstr::Mul(instr) => write!(f, "{}", instr), ARMInstr::Mul(instr) => write!(f, "{}", instr),
ARMInstr::SDiv(instr) => write!(f, "{}", instr), ARMInstr::SDiv(instr) => write!(f, "{}", instr),
@@ -45,7 +47,7 @@ impl Display for ARMInstr {
pub enum RegisterOrImm { pub enum RegisterOrImm {
Reg(Register), Reg(Register),
Imm(i32), Imm(i32),
} }
impl Display for RegisterOrImm { impl Display for RegisterOrImm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@@ -73,7 +75,7 @@ impl From<IRCmpOp> for ConditionCode {
IRCmpOp::Ge => ConditionCode::Ge, IRCmpOp::Ge => ConditionCode::Ge,
} }
} }
} }
impl Display for ConditionCode { impl Display for ConditionCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let code_str = match self { 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>); pub struct LoadInstr(Register, Register, Option<RegisterOrImm>);
impl LoadInstr { impl LoadInstr {
pub fn new(dest: Register, base: Register, offset: Option<RegisterOrImm>) -> ARMInstr { 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>); pub struct StoreInstr(Register, Register, Option<RegisterOrImm>);
impl StoreInstr { impl StoreInstr {
pub fn new(src: Register, dest: Register, offset: Option<RegisterOrImm>) -> ARMInstr { 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 { pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr {
ARMInstr::B(BInstr(Some(condition), label_name)) ARMInstr::B(BInstr(Some(condition), label_name))
} }
} }
+36 -15
View File
@@ -1,6 +1,6 @@
use std::collections::BTreeMap; 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::BinaryOp as IRBinaryOp;
use crate::ir::types::CmpOp as IRCmpOp; use crate::ir::types::CmpOp as IRCmpOp;
use crate::ir::types::UnaryOp as IRUnaryOp; 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_DATA_IMM_CHUNK: i32 = 255;
const ARM_LOAD_STORE_MAX_OFFSET: i32 = 4095; 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>) { fn emit_sub_imm(dest: Register, left: Register, imm: i32, instrs: &mut Vec<ARMInstr>) {
if imm == 0 { if imm == 0 {
if dest != left { if dest != left {
@@ -97,7 +113,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
} }
match variable.var_type { match variable.var_type {
VariableType::Global => { 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"); 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; let var_reg = var_alloc.reg;
// if !var_alloc.is_reused { // if !var_alloc.is_reused {
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); 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)); instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None));
// } // }
var_alloc var_alloc
@@ -144,7 +160,7 @@ fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut Register
match variable.var_type { match variable.var_type {
VariableType::Global => { VariableType::Global => {
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); 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)); instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
}, },
VariableType::ParamTemp(_) => { VariableType::ParamTemp(_) => {
@@ -169,7 +185,7 @@ impl Generator {
for ir_instr in ir_instrs { for ir_instr in ir_instrs {
match ir_instr { match ir_instr {
IRInstr::DefineFunc(func, args, body) => self.emit_func_def(func, args, body), 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!(), _ => unreachable!(),
} }
} }
@@ -181,8 +197,8 @@ impl Generator {
text.push_str(&format!(".comm {}, {}, {}\n", var.name, var.size, var.align)); text.push_str(&format!(".comm {}, {}, {}\n", var.name, var.size, var.align));
} }
for var in &self.var_inited { 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!(".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!(".word {}\n", var.init.unwrap_or(0)));
} }
text.push_str(".text\n"); text.push_str(".text\n");
for instr in &self.instrs { for instr in &self.instrs {
@@ -191,13 +207,18 @@ impl Generator {
text text
} }
fn emit_global_decl(&mut self, var: Variable, init: Option<i32>) {
fn emit_global_decl(&mut self, var: Variable) { let asm_var = ARMAsmVar {
self.var_uninited.push(ARMAsmVar {
name: format!("global_var_{}", var.index), name: format!("global_var_{}", var.index),
size: var.data_type.size_in_bytes(), size: var.data_type.size_in_bytes(),
align: DEFAULT_VAR_ALIGN, 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>) { fn emit_func_def(&mut self, func: Function, _args: Vec<Variable>, body: Vec<IRInstr>) {
@@ -239,7 +260,7 @@ impl Generator {
encounter_entry = true; encounter_entry = true;
emit_sub_sp_imm(stack_size_needed as i32, &mut self.instrs); 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::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::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))), IRInstr::Goto(index) => self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, index))),
@@ -272,7 +293,7 @@ impl Generator {
}, },
VariableOrIntLit::IntLit(lit) => { VariableOrIntLit::IntLit(lit) => {
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); 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 alloc
}, },
}; };
@@ -283,7 +304,7 @@ impl Generator {
}, },
VariableOrIntLit::IntLit(lit) => { VariableOrIntLit::IntLit(lit) => {
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); 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 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); 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))); 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); 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 name: String,
pub size: usize, pub size: usize,
pub align: usize, pub align: usize,
} pub init: Option<i32>,
}