feat(parser,ir,backend): Fully support func params and disable r0-r3 alloc temporarily

This commit is contained in:
2026-05-19 20:10:11 +08:00
parent a5b1cb6c9a
commit 3f64f1a965
6 changed files with 71 additions and 14 deletions
+10 -4
View File
@@ -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<usize, usize>, instrs: &mut Vec<ARMInstr>) -> 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"));
+4
View File
@@ -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");
}
}
+37 -2
View File
@@ -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<RefCell<RegisterAllocatorInner>>,
pub reg: Register,
@@ -102,7 +105,17 @@ impl RegisterAllocator {
})),
}
}
fn debug_use(&self) {
let inner = self.inner.borrow();
for (&reg, 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<RegisterAlloc> {
let mut inner = self.inner.borrow_mut();
if let Some(&reg) = inner.variable_to_register.get(&var) {
@@ -122,6 +135,9 @@ impl RegisterAllocator {
// Find a free register
for (&reg, use_kind) in inner.register_map.iter_mut() {
// Find free register first
if REGISTERS_RESERVED.contains(&reg) {
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 (&reg, use_kind) in register_map.iter_mut() {
// Find allocated register then
if REGISTERS_RESERVED.contains(&reg) {
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 (&reg, use_kind) in inner.register_map.iter_mut() {
if REGISTERS_RESERVED.contains(&reg) {
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 (&reg, use_kind) in register_map.iter_mut() {
if REGISTERS_RESERVED.contains(&reg) {
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
}
}
+4
View File
@@ -1096,4 +1096,8 @@ mod tests {
fn test_error() {
test_case("999");
}
#[test]
fn test_func() {
test_case("12-13,58-60");
}
}
+14 -6
View File
@@ -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::<Vec<_>>();
let temp_parameters = parameters.iter().enumerate()
.map(|(i, param)| self.var_manager.declare_param_temp(param.data_type, i))
.collect::<Vec<_>>();
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<IRInstr> {
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");
}
}
+2 -2
View File
@@ -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)
}