From 2d87760c7924b438d79a54baeb11fd445dc02735 Mon Sep 17 00:00:00 2001 From: Hydrostic Date: Sat, 13 Jun 2026 09:09:53 +0800 Subject: [PATCH] feat(backend): Add local local --- src/backend/arm_instr.rs | 16 ++++---- src/backend/generator.rs | 84 +++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/backend/arm_instr.rs b/src/backend/arm_instr.rs index 504add2..c0798e8 100644 --- a/src/backend/arm_instr.rs +++ b/src/backend/arm_instr.rs @@ -19,6 +19,7 @@ pub enum ARMInstr{ Bl(BlInstr), B(BInstr), Label(String), + LocalLabel(String), } impl Display for ARMInstr { @@ -41,6 +42,7 @@ impl Display for ARMInstr { ARMInstr::B(instr) => write!(f, "{}", instr), ARMInstr::FunctionHead(name, align_size) => write!(f, ".align {}\n.global {}\n.type {}, %function\n{}:", align_size, name, name, name), ARMInstr::Label(name) => write!(f, "{}:", name), + ARMInstr::LocalLabel(name) => write!(f, "{}:", name), } } } @@ -132,7 +134,7 @@ impl Display for MoveInstr { pub enum MoveWideOperand { Imm(u16), - Symbol(String), + Symbol(String, String), } pub struct MovwInstr(Register, MoveWideOperand); @@ -141,8 +143,8 @@ impl MovwInstr { ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Imm(value))) } - pub fn new_symbol(dest: Register, name: String) -> ARMInstr { - ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Symbol(name))) + pub fn new_symbol(dest: Register, name: String, anchor: String) -> ARMInstr { + ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Symbol(name, anchor))) } } impl Display for MovwInstr { @@ -150,7 +152,7 @@ impl Display for MovwInstr { let MovwInstr(dest, operand) = self; match operand { MoveWideOperand::Imm(value) => write!(f, "movw {}, #{}", dest, value), - MoveWideOperand::Symbol(name) => write!(f, "movw {}, #:lower16:{}", dest, name), + MoveWideOperand::Symbol(name, anchor) => write!(f, "movw {}, #:lower16:{}-({}+8)", dest, name, anchor), } } } @@ -161,8 +163,8 @@ impl MovtInstr { ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Imm(value))) } - pub fn new_symbol(dest: Register, name: String) -> ARMInstr { - ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Symbol(name))) + pub fn new_symbol(dest: Register, name: String, anchor: String) -> ARMInstr { + ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Symbol(name, anchor))) } } impl Display for MovtInstr { @@ -170,7 +172,7 @@ impl Display for MovtInstr { let MovtInstr(dest, operand) = self; match operand { MoveWideOperand::Imm(value) => write!(f, "movt {}, #{}", dest, value), - MoveWideOperand::Symbol(name) => write!(f, "movt {}, #:upper16:{}", dest, name), + MoveWideOperand::Symbol(name, anchor) => write!(f, "movt {}, #:upper16:{}-({}+8)", dest, name, anchor), } } } diff --git a/src/backend/generator.rs b/src/backend/generator.rs index 601e31c..d5a130f 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, 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::{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_PC, 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; @@ -11,6 +11,7 @@ pub struct Generator { var_inited: Vec, var_uninited: Vec, register_allocator: RegisterAllocator, + symbol_addr_label_counter: usize, } const DEFAULT_VAR_ALIGN: usize = 4; @@ -30,11 +31,6 @@ fn emit_load_imm32(dest: Register, value: i32, instrs: &mut Vec) { } } -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 { @@ -91,33 +87,34 @@ fn emit_store_stack(src: Register, offset: i32, reg_allocator: &mut RegisterAllo } } -fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap, instrs: &mut Vec) -> RegisterAlloc { +fn load_variable(variable: Variable, generator: &mut Generator, var_index_to_stack_offset: &BTreeMap) -> RegisterAlloc { + let reg_allocator = &mut generator.register_allocator; if variable.data_type.is_array() { let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers"); if variable.data_type.is_array_param() { match variable.var_type { VariableType::ParamTemp(param_index) => { if param_index < ARG_REGS.len() { - instrs.push(MoveInstr::new_uncond(var_alloc.reg, RegisterOrImm::Reg(ARG_REGS[param_index]))); + generator.instrs.push(MoveInstr::new_uncond(var_alloc.reg, RegisterOrImm::Reg(ARG_REGS[param_index]))); } else { let stack_arg_offset = 8 + ((param_index - ARG_REGS.len()) * 4); - instrs.push(LoadInstr::new(var_alloc.reg, REG_FP, Some(RegisterOrImm::Imm(stack_arg_offset as i32)))); + generator.instrs.push(LoadInstr::new(var_alloc.reg, REG_FP, Some(RegisterOrImm::Imm(stack_arg_offset as i32)))); } } _ => { let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); - emit_load_stack(var_alloc.reg, *stack_offset as i32, reg_allocator, instrs); + emit_load_stack(var_alloc.reg, *stack_offset as i32, &mut generator.register_allocator, &mut generator.instrs); } } return var_alloc; } match variable.var_type { VariableType::Global => { - emit_load_symbol_addr(var_alloc.reg, format!("global_var_{}", variable.index), instrs); + generator.emit_load_symbol_addr(var_alloc.reg, format!("global_var_{}", variable.index)); } _ => { let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); - emit_sub_imm(var_alloc.reg, REG_FP, *stack_offset as i32, instrs); + emit_sub_imm(var_alloc.reg, REG_FP, *stack_offset as i32, &mut generator.instrs); } } return var_alloc; @@ -128,8 +125,8 @@ 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"); - emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs); - instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None)); + generator.emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index)); + generator.instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None)); // } var_alloc }, @@ -141,7 +138,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_ } else { let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers"); let stack_arg_offset = 8 + ((param_index - ARG_REGS.len()) * 4); - instrs.push(LoadInstr::new(var_alloc.reg, REG_FP, Some(RegisterOrImm::Imm(stack_arg_offset as i32)))); + generator.instrs.push(LoadInstr::new(var_alloc.reg, REG_FP, Some(RegisterOrImm::Imm(stack_arg_offset as i32)))); var_alloc } }, @@ -149,26 +146,26 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_ let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers"); // if !var_alloc.is_reused { - emit_load_stack(var_alloc.reg, *stack_offset as i32, reg_allocator, instrs); + emit_load_stack(var_alloc.reg, *stack_offset as i32, &mut generator.register_allocator, &mut generator.instrs); // } var_alloc } } } -fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap, instrs: &mut Vec) { +fn save_variable(variable: Variable, reg: Register, generator: &mut Generator, var_index_to_stack_offset: &BTreeMap) { match variable.var_type { VariableType::Global => { - let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); - emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs); - instrs.push(StoreInstr::new(reg, address_alloc.reg, None)); + let address_alloc = generator.register_allocator.alloc_any().expect("Ran out of registers"); + generator.emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index)); + generator.instrs.push(StoreInstr::new(reg, address_alloc.reg, None)); }, VariableType::ParamTemp(_) => { todo!() }, _ => { let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); - emit_store_stack(reg, *stack_offset as i32, reg_allocator, instrs); + emit_store_stack(reg, *stack_offset as i32, &mut generator.register_allocator, &mut generator.instrs); } } } @@ -179,8 +176,17 @@ impl Generator { var_inited: Vec::new(), var_uninited: Vec::new(), register_allocator: RegisterAllocator::new(), + symbol_addr_label_counter: 0, } } + fn emit_load_symbol_addr(&mut self, dest: Register, name: String) { + let anchor = format!(".Laddr_{}", self.symbol_addr_label_counter); + self.symbol_addr_label_counter += 1; + self.instrs.push(MovwInstr::new_symbol(dest, name.clone(), anchor.clone())); + self.instrs.push(MovtInstr::new_symbol(dest, name, anchor.clone())); + self.instrs.push(ARMInstr::LocalLabel(anchor)); + self.instrs.push(AddInstr::new(dest, REG_PC, RegisterOrImm::Reg(dest))); + } pub fn emit(&mut self, ir_instrs: Vec) { for ir_instr in ir_instrs { match ir_instr { @@ -239,7 +245,7 @@ impl Generator { if let Some(v) = v { let ret_alloc = self.register_allocator.alloc_reg(REG_R0).expect("Ran out of registers"); let ret_reg = ret_alloc.reg; - let v_alloc = load_variable(v, &mut self.register_allocator, &var_index_to_stack_offset, &mut self.instrs); + let v_alloc = load_variable(v, self, &var_index_to_stack_offset); self.instrs.push(MoveInstr::new_uncond(ret_reg, RegisterOrImm::Reg(v_alloc.reg))); } self.instrs.push(MoveInstr::new_fp_to_sp()); @@ -265,7 +271,7 @@ impl Generator { 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::CondGoto(variable, true_label_index, false_label_index) => { - let variable_alloc = load_variable(variable, &mut self.register_allocator, &var_index_to_stack_offset, &mut self.instrs); + let variable_alloc = load_variable(variable, self, &var_index_to_stack_offset); let variable_reg = variable_alloc.reg; self.instrs.push(CmpInstr::new(variable_reg, RegisterOrImm::Imm(0))); self.instrs.push(BInstr::new_cond(ConditionCode::Ne, format!("label_{}_{}", func_name, true_label_index))); @@ -277,19 +283,19 @@ impl Generator { } } fn emit_unary(&mut self, dest: Variable, unary_op: IRUnaryOp, variable: Variable, var_index_to_stack_offset: &BTreeMap) { - let variable_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let variable_alloc = load_variable(variable, self, var_index_to_stack_offset); let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers"); match unary_op { IRUnaryOp::Neg => { self.instrs.push(RsbInstr::new(dest_alloc.reg, variable_alloc.reg, RegisterOrImm::Imm(0))); }, } - save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + save_variable(dest, dest_alloc.reg, self, var_index_to_stack_offset); } fn emit_cmp(&mut self, variable: Variable, left: VariableOrIntLit, cmp_op: IRCmpOp, right: VariableOrIntLit, var_index_to_stack_offset: &BTreeMap) { let left_alloc = match left { VariableOrIntLit::Var(var) => { - load_variable(var, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs) + load_variable(var, self, var_index_to_stack_offset) }, VariableOrIntLit::IntLit(lit) => { let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); @@ -300,7 +306,7 @@ impl Generator { // TODO: check left == right let right_alloc = match right { VariableOrIntLit::Var(var) => { - load_variable(var, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs) + load_variable(var, self, var_index_to_stack_offset) }, VariableOrIntLit::IntLit(lit) => { let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); @@ -313,7 +319,7 @@ impl Generator { self.instrs.push(CmpInstr::new(left_alloc.reg, RegisterOrImm::Reg(right_alloc.reg))); self.instrs.push(MoveInstr::new_uncond(variable_reg, RegisterOrImm::Imm(0))); self.instrs.push(MoveInstr::new_cond(cmp_op.into(), variable_reg, RegisterOrImm::Imm(1))); - save_variable(variable, variable_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + save_variable(variable, variable_alloc.reg, self, var_index_to_stack_offset); } fn emit_func_call(&mut self, func: Function, args: Vec, ret: Option, var_index_to_stack_offset: &BTreeMap) { @@ -328,7 +334,7 @@ impl Generator { } let mut arg_reg_allocs = Vec::new(); for (i, arg) in args.into_iter().enumerate() { - let arg_alloc = load_variable(arg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let arg_alloc = load_variable(arg, self, var_index_to_stack_offset); if i < ARG_REGS.len() { arg_reg_allocs.push(self.register_allocator.alloc_reg(ARG_REGS[i]).expect("Ran out of registers")); self.instrs.push(MoveInstr::new_uncond(ARG_REGS[i], RegisterOrImm::Reg(arg_alloc.reg))); @@ -339,7 +345,7 @@ impl Generator { } self.instrs.push(BlInstr::new(func.name.clone())); if let Some(ret) = ret { - save_variable(ret, REG_R0, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + save_variable(ret, REG_R0, self, var_index_to_stack_offset); } if extra_stack_size > 0 { @@ -353,24 +359,24 @@ impl Generator { let dest_register = dest_alloc.reg; match src { MoveRValue::Var(variable) => { - let src_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let src_alloc = load_variable(variable, self, var_index_to_stack_offset); self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Reg(src_alloc.reg))); }, 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, self, var_index_to_stack_offset); } fn emit_load(&mut self, dest: Variable, addr: Variable, var_index_to_stack_offset: &BTreeMap) { - let addr_alloc = load_variable(addr, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let addr_alloc = load_variable(addr, self, var_index_to_stack_offset); let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers"); self.instrs.push(LoadInstr::new(dest_alloc.reg, addr_alloc.reg, None)); - save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + save_variable(dest, dest_alloc.reg, self, var_index_to_stack_offset); } fn emit_store(&mut self, addr: Variable, value: Variable, var_index_to_stack_offset: &BTreeMap) { - let addr_alloc = load_variable(addr, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); - let value_alloc = load_variable(value, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let addr_alloc = load_variable(addr, self, var_index_to_stack_offset); + let value_alloc = load_variable(value, self, var_index_to_stack_offset); self.instrs.push(StoreInstr::new(value_alloc.reg, addr_alloc.reg, None)); } @@ -378,9 +384,9 @@ impl Generator { let dest_alloc = self.register_allocator.alloc(dest.clone()).expect("Ran out of registers"); let dest_reg = dest_alloc.reg; // should consider left == right - let left_alloc = load_variable(left.clone(), &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let left_alloc = load_variable(left.clone(), self, var_index_to_stack_offset); let (_right_alloc, right_reg) = if left != right { - let right_alloc = load_variable(right, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let right_alloc = load_variable(right, self, var_index_to_stack_offset); let right_reg = right_alloc.reg; (Some(right_alloc), right_reg) } else { @@ -407,7 +413,7 @@ impl Generator { self.instrs.push(SubInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(temp_reg))); }, } - save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + save_variable(dest, dest_alloc.reg, self, var_index_to_stack_offset); } }