diff --git a/src/backend/generator.rs b/src/backend/generator.rs index 8dba967..7c31c31 100644 --- a/src/backend/generator.rs +++ b/src/backend/generator.rs @@ -15,6 +15,7 @@ pub struct Generator { const DEFAULT_VAR_ALIGN: usize = 4; +const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3]; fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap, instrs: &mut Vec) -> RegisterAlloc { match variable.var_type { VariableType::Global => { @@ -27,8 +28,14 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_ // } var_alloc }, - VariableType::ParamTemp => { - todo!() + VariableType::ParamTemp(param_index) => { + if param_index < ARG_REGS.len() { + let reg = ARG_REGS[param_index]; + let var_alloc = reg_allocator.alloc_reg(reg).expect("Ran out of registers"); + var_alloc + } else { + todo!("More than 4 parameters not supported yet"); + } }, _ => { let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); @@ -48,7 +55,7 @@ fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut Register instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index))); instrs.push(StoreInstr::new(reg, address_alloc.reg, None)); }, - VariableType::ParamTemp => { + VariableType::ParamTemp(_) => { todo!() }, _ => { @@ -199,7 +206,6 @@ impl Generator { if args.len() > 4 { todo!("More than 4 arguments not supported yet"); } - const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3]; let mut arg_reg_allocs = Vec::new(); for (i, arg) in args.into_iter().enumerate() { arg_reg_allocs.push(self.register_allocator.alloc_reg(ARG_REGS[i]).expect("Ran out of registers")); diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 30c6c5e..8d7d5c8 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -78,4 +78,8 @@ mod tests { fn test_if_while() { test_case("26-32,34-41,46-51,57"); } + #[test] + fn test_func() { + test_case("12-13,58-60"); + } } \ No newline at end of file diff --git a/src/backend/register_allocator.rs b/src/backend/register_allocator.rs index a1ff524..795df33 100644 --- a/src/backend/register_allocator.rs +++ b/src/backend/register_allocator.rs @@ -45,6 +45,9 @@ pub const REGISTERS: &[Register] = &[ pub const REGISTERS_CAN_ALLOC: &[Register] = &[ REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, REG_R8, REG_R9, REG_R10, REG_R12 ]; +pub const REGISTERS_RESERVED: &[Register] = &[ + REG_R0, REG_R1, REG_R2, REG_R3 +]; pub struct RegisterAlloc { allocator: Weak>, pub reg: Register, @@ -102,7 +105,17 @@ impl RegisterAllocator { })), } } - + fn debug_use(&self) { + let inner = self.inner.borrow(); + for (®, use_kind) in inner.register_map.iter() { + match use_kind { + RegisterUseKind::Designated => println!("{}: Designated", reg), + RegisterUseKind::UsedByVariable(var) => println!("{}: UsedByVariable({})", reg, var), + RegisterUseKind::AllocatedToVariable(var) => println!("{}: AllocatedToVariable({})", reg, var), + RegisterUseKind::Free => println!("{}: Free", reg), + } + } + } pub fn alloc(&mut self, var: Variable) -> Option { let mut inner = self.inner.borrow_mut(); if let Some(®) = inner.variable_to_register.get(&var) { @@ -122,6 +135,9 @@ impl RegisterAllocator { // Find a free register for (®, use_kind) in inner.register_map.iter_mut() { // Find free register first + if REGISTERS_RESERVED.contains(®) { + continue; + } if let RegisterUseKind::Free = use_kind { *use_kind = RegisterUseKind::UsedByVariable(var); inner.variable_to_register.insert(var, reg); @@ -135,6 +151,9 @@ impl RegisterAllocator { let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner; for (®, use_kind) in register_map.iter_mut() { // Find allocated register then + if REGISTERS_RESERVED.contains(®) { + continue; + } if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind { assert!(variable_to_register.remove(&ori_var).is_some()); *use_kind = RegisterUseKind::UsedByVariable(var); @@ -146,6 +165,8 @@ impl RegisterAllocator { }); } } + std::mem::drop(inner); + self.debug_use(); // No free register available None } @@ -164,6 +185,10 @@ impl RegisterAllocator { }); }, RegisterUseKind::UsedByVariable(_var) => { + std::mem::drop(inner); + + println!("{}", reg); + self.debug_use(); return None; }, RegisterUseKind::AllocatedToVariable(var) => { @@ -176,6 +201,9 @@ impl RegisterAllocator { }); }, RegisterUseKind::Designated => { + std::mem::drop(inner); + println!("{}", reg); + self.debug_use(); return None; }, } @@ -186,6 +214,9 @@ impl RegisterAllocator { let mut inner = self.inner.borrow_mut(); for (®, use_kind) in inner.register_map.iter_mut() { + if REGISTERS_RESERVED.contains(®) { + continue; + } if let RegisterUseKind::Free = use_kind { *use_kind = RegisterUseKind::Designated; return Some(RegisterAlloc { @@ -197,6 +228,9 @@ impl RegisterAllocator { } let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner; for (®, use_kind) in register_map.iter_mut() { + if REGISTERS_RESERVED.contains(®) { + continue; + } if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind { variable_to_register.remove(&ori_var); *use_kind = RegisterUseKind::Designated; @@ -207,7 +241,8 @@ impl RegisterAllocator { }); } } - + std::mem::drop(inner); + self.debug_use(); None } } \ No newline at end of file diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index ec959db..1f8972d 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1096,4 +1096,8 @@ mod tests { fn test_error() { test_case("999"); } + #[test] + fn test_func() { + test_case("12-13,58-60"); + } } diff --git a/src/ir/generator.rs b/src/ir/generator.rs index b83245f..ea6bebb 100644 --- a/src/ir/generator.rs +++ b/src/ir/generator.rs @@ -106,7 +106,9 @@ impl Generator { Ok(p) => p, Err(()) => return vec![], }; - let temp_parameters = parameters.iter().map(|param| self.var_manager.declare_param_temp(param.data_type)).collect::>(); + let temp_parameters = parameters.iter().enumerate() + .map(|(i, param)| self.var_manager.declare_param_temp(param.data_type, i)) + .collect::>(); let mut body_instrs = vec![]; self.func_exit = Some((self.request_label(), { let ret_type = func_decl.return_type.into(); @@ -118,14 +120,14 @@ impl Generator { })); let block_instrs = self.generate_block_stmt(func_decl.body); for var in self.var_manager.get_cur_func_variables() { - if matches!(var.var_type, VariableType::ParamTemp) { + if matches!(var.var_type, VariableType::ParamTemp(_)) { continue; } body_instrs.push(IRInstr::Declare(var)); } body_instrs.push(IRInstr::Entry); parameters.iter().zip(temp_parameters.iter()).for_each(|(param, temp_param)| { - body_instrs.push(IRInstr::Move(*temp_param, MoveRValue::Var(*param))); + body_instrs.push(IRInstr::Move(*param, MoveRValue::Var(*temp_param))); }); body_instrs.extend(block_instrs); let func_exit = self.func_exit.take().unwrap(); @@ -140,7 +142,7 @@ impl Generator { return_type: func_decl.return_type.into(), }; self.function_map.insert(func.name.clone(), func.clone()); - vec![IRInstr::DefineFunc(func, parameters, body_instrs)] + vec![IRInstr::DefineFunc(func, temp_parameters, body_instrs)] } fn generate_block_stmt(&mut self, block_stmt: BlockStmt) -> Vec { let mut instrs = vec![]; @@ -633,7 +635,9 @@ impl Generator { return None; } for (i, arg) in args.into_iter().enumerate() { + self.current_exit_label.push(None); let (arg_instrs, arg_var) = self.generate_expr(arg)?; + self.current_exit_label.pop(); let parameter_type = func_def.parameter_types.get(i).unwrap(); if *parameter_type != arg_var.map_or(IRType::Void, |v| v.data_type) { self.diagnostic.add_from_ir_error(IRError::TypeMismatch(*parameter_type, arg_var.map_or(IRType::Void, |v| v.data_type)), expr.span); @@ -737,8 +741,8 @@ impl VariableManager { self.local_var_type.push(var); var } - pub fn declare_param_temp(&mut self, var_data_type: IRType) -> Variable { - let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp, data_type: var_data_type }; + pub fn declare_param_temp(&mut self, var_data_type: IRType, param_index: usize) -> Variable { + let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp(param_index), data_type: var_data_type }; self.local_counter += 1; self.local_var_type.push(var); var @@ -830,4 +834,8 @@ mod tests { fn test_if_while() { test_case("26-32,34-41,46-51,57"); } + #[test] + fn test_func() { + test_case("12-13,58-60"); + } } \ No newline at end of file diff --git a/src/ir/types.rs b/src/ir/types.rs index 5260214..3af7c1e 100644 --- a/src/ir/types.rs +++ b/src/ir/types.rs @@ -116,7 +116,7 @@ impl Display for MoveRValue { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub enum VariableType { Global, - ParamTemp, + ParamTemp(usize), Local, Temp, } @@ -155,7 +155,7 @@ impl Display for Variable { VariableType::Global => "@g", VariableType::Local => "%l", VariableType::Temp => "%t", - VariableType::ParamTemp => "%t", + VariableType::ParamTemp(_) => "%t", }; write!(f, "{}{}", prefix, self.index) }