From 1de7e2876c5b817e8a39e2bcdeecd12566b91e78 Mon Sep 17 00:00:00 2001 From: Hydrostic Date: Fri, 12 Jun 2026 18:51:43 +0800 Subject: [PATCH] refactor(backend): Remove literal pool --- src/backend/arm_instr.rs | 70 ++++++++++++++++++++++++++++++---------- src/backend/generator.rs | 51 ++++++++++++++++++++--------- src/backend/types.rs | 3 +- 3 files changed, 91 insertions(+), 33 deletions(-) diff --git a/src/backend/arm_instr.rs b/src/backend/arm_instr.rs index 60f421c..504add2 100644 --- a/src/backend/arm_instr.rs +++ b/src/backend/arm_instr.rs @@ -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 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); impl LoadInstr { pub fn new(dest: Register, base: Register, offset: Option) -> 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); impl StoreInstr { pub fn new(src: Register, dest: Register, offset: Option) -> ARMInstr { @@ -347,4 +383,4 @@ impl BInstr { pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr { ARMInstr::B(BInstr(Some(condition), label_name)) } -} \ No newline at end of file +} diff --git a/src/backend/generator.rs b/src/backend/generator.rs index 77d716d..601e31c 100644 --- a/src/backend/generator.rs +++ b/src/backend/generator.rs @@ -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) { + 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) { + 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) { 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) { + 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, body: Vec) { @@ -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); } diff --git a/src/backend/types.rs b/src/backend/types.rs index b688dd4..ffb1d4b 100644 --- a/src/backend/types.rs +++ b/src/backend/types.rs @@ -2,4 +2,5 @@ pub struct ARMAsmVar { pub name: String, pub size: usize, pub align: usize, -} \ No newline at end of file + pub init: Option, +}