feat(parser,ir,backend): Fully support func params and disable r0-r3 alloc temporarily
This commit is contained in:
@@ -15,6 +15,7 @@ pub struct Generator {
|
|||||||
|
|
||||||
const DEFAULT_VAR_ALIGN: usize = 4;
|
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 {
|
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 {
|
match variable.var_type {
|
||||||
VariableType::Global => {
|
VariableType::Global => {
|
||||||
@@ -27,8 +28,14 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
|
|||||||
// }
|
// }
|
||||||
var_alloc
|
var_alloc
|
||||||
},
|
},
|
||||||
VariableType::ParamTemp => {
|
VariableType::ParamTemp(param_index) => {
|
||||||
todo!()
|
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");
|
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(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index)));
|
||||||
instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
|
instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
|
||||||
},
|
},
|
||||||
VariableType::ParamTemp => {
|
VariableType::ParamTemp(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
@@ -199,7 +206,6 @@ impl Generator {
|
|||||||
if args.len() > 4 {
|
if args.len() > 4 {
|
||||||
todo!("More than 4 arguments not supported yet");
|
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();
|
let mut arg_reg_allocs = Vec::new();
|
||||||
for (i, arg) in args.into_iter().enumerate() {
|
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"));
|
arg_reg_allocs.push(self.register_allocator.alloc_reg(ARG_REGS[i]).expect("Ran out of registers"));
|
||||||
|
|||||||
@@ -78,4 +78,8 @@ mod tests {
|
|||||||
fn test_if_while() {
|
fn test_if_while() {
|
||||||
test_case("26-32,34-41,46-51,57");
|
test_case("26-32,34-41,46-51,57");
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_func() {
|
||||||
|
test_case("12-13,58-60");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,9 @@ pub const REGISTERS: &[Register] = &[
|
|||||||
pub const REGISTERS_CAN_ALLOC: &[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
|
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 {
|
pub struct RegisterAlloc {
|
||||||
allocator: Weak<RefCell<RegisterAllocatorInner>>,
|
allocator: Weak<RefCell<RegisterAllocatorInner>>,
|
||||||
pub reg: Register,
|
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<RegisterAlloc> {
|
pub fn alloc(&mut self, var: Variable) -> Option<RegisterAlloc> {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
if let Some(®) = inner.variable_to_register.get(&var) {
|
if let Some(®) = inner.variable_to_register.get(&var) {
|
||||||
@@ -122,6 +135,9 @@ impl RegisterAllocator {
|
|||||||
// Find a free register
|
// Find a free register
|
||||||
for (®, use_kind) in inner.register_map.iter_mut() {
|
for (®, use_kind) in inner.register_map.iter_mut() {
|
||||||
// Find free register first
|
// Find free register first
|
||||||
|
if REGISTERS_RESERVED.contains(®) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let RegisterUseKind::Free = use_kind {
|
if let RegisterUseKind::Free = use_kind {
|
||||||
*use_kind = RegisterUseKind::UsedByVariable(var);
|
*use_kind = RegisterUseKind::UsedByVariable(var);
|
||||||
inner.variable_to_register.insert(var, reg);
|
inner.variable_to_register.insert(var, reg);
|
||||||
@@ -135,6 +151,9 @@ impl RegisterAllocator {
|
|||||||
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
||||||
for (®, use_kind) in register_map.iter_mut() {
|
for (®, use_kind) in register_map.iter_mut() {
|
||||||
// Find allocated register then
|
// Find allocated register then
|
||||||
|
if REGISTERS_RESERVED.contains(®) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
||||||
assert!(variable_to_register.remove(&ori_var).is_some());
|
assert!(variable_to_register.remove(&ori_var).is_some());
|
||||||
*use_kind = RegisterUseKind::UsedByVariable(var);
|
*use_kind = RegisterUseKind::UsedByVariable(var);
|
||||||
@@ -146,6 +165,8 @@ impl RegisterAllocator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::mem::drop(inner);
|
||||||
|
self.debug_use();
|
||||||
// No free register available
|
// No free register available
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -164,6 +185,10 @@ impl RegisterAllocator {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
RegisterUseKind::UsedByVariable(_var) => {
|
RegisterUseKind::UsedByVariable(_var) => {
|
||||||
|
std::mem::drop(inner);
|
||||||
|
|
||||||
|
println!("{}", reg);
|
||||||
|
self.debug_use();
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
RegisterUseKind::AllocatedToVariable(var) => {
|
RegisterUseKind::AllocatedToVariable(var) => {
|
||||||
@@ -176,6 +201,9 @@ impl RegisterAllocator {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
RegisterUseKind::Designated => {
|
RegisterUseKind::Designated => {
|
||||||
|
std::mem::drop(inner);
|
||||||
|
println!("{}", reg);
|
||||||
|
self.debug_use();
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -186,6 +214,9 @@ impl RegisterAllocator {
|
|||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
for (®, use_kind) in inner.register_map.iter_mut() {
|
for (®, use_kind) in inner.register_map.iter_mut() {
|
||||||
|
if REGISTERS_RESERVED.contains(®) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let RegisterUseKind::Free = use_kind {
|
if let RegisterUseKind::Free = use_kind {
|
||||||
*use_kind = RegisterUseKind::Designated;
|
*use_kind = RegisterUseKind::Designated;
|
||||||
return Some(RegisterAlloc {
|
return Some(RegisterAlloc {
|
||||||
@@ -197,6 +228,9 @@ impl RegisterAllocator {
|
|||||||
}
|
}
|
||||||
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
||||||
for (®, use_kind) in register_map.iter_mut() {
|
for (®, use_kind) in register_map.iter_mut() {
|
||||||
|
if REGISTERS_RESERVED.contains(®) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
||||||
variable_to_register.remove(&ori_var);
|
variable_to_register.remove(&ori_var);
|
||||||
*use_kind = RegisterUseKind::Designated;
|
*use_kind = RegisterUseKind::Designated;
|
||||||
@@ -207,7 +241,8 @@ impl RegisterAllocator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::mem::drop(inner);
|
||||||
|
self.debug_use();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1096,4 +1096,8 @@ mod tests {
|
|||||||
fn test_error() {
|
fn test_error() {
|
||||||
test_case("999");
|
test_case("999");
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_func() {
|
||||||
|
test_case("12-13,58-60");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-6
@@ -106,7 +106,9 @@ impl Generator {
|
|||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(()) => return vec![],
|
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![];
|
let mut body_instrs = vec![];
|
||||||
self.func_exit = Some((self.request_label(), {
|
self.func_exit = Some((self.request_label(), {
|
||||||
let ret_type = func_decl.return_type.into();
|
let ret_type = func_decl.return_type.into();
|
||||||
@@ -118,14 +120,14 @@ impl Generator {
|
|||||||
}));
|
}));
|
||||||
let block_instrs = self.generate_block_stmt(func_decl.body);
|
let block_instrs = self.generate_block_stmt(func_decl.body);
|
||||||
for var in self.var_manager.get_cur_func_variables() {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
body_instrs.push(IRInstr::Declare(var));
|
body_instrs.push(IRInstr::Declare(var));
|
||||||
}
|
}
|
||||||
body_instrs.push(IRInstr::Entry);
|
body_instrs.push(IRInstr::Entry);
|
||||||
parameters.iter().zip(temp_parameters.iter()).for_each(|(param, temp_param)| {
|
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);
|
body_instrs.extend(block_instrs);
|
||||||
let func_exit = self.func_exit.take().unwrap();
|
let func_exit = self.func_exit.take().unwrap();
|
||||||
@@ -140,7 +142,7 @@ impl Generator {
|
|||||||
return_type: func_decl.return_type.into(),
|
return_type: func_decl.return_type.into(),
|
||||||
};
|
};
|
||||||
self.function_map.insert(func.name.clone(), func.clone());
|
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> {
|
fn generate_block_stmt(&mut self, block_stmt: BlockStmt) -> Vec<IRInstr> {
|
||||||
let mut instrs = vec![];
|
let mut instrs = vec![];
|
||||||
@@ -633,7 +635,9 @@ impl Generator {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
for (i, arg) in args.into_iter().enumerate() {
|
for (i, arg) in args.into_iter().enumerate() {
|
||||||
|
self.current_exit_label.push(None);
|
||||||
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
|
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
|
||||||
|
self.current_exit_label.pop();
|
||||||
let parameter_type = func_def.parameter_types.get(i).unwrap();
|
let parameter_type = func_def.parameter_types.get(i).unwrap();
|
||||||
if *parameter_type != arg_var.map_or(IRType::Void, |v| v.data_type) {
|
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);
|
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);
|
self.local_var_type.push(var);
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
pub fn declare_param_temp(&mut self, var_data_type: IRType) -> Variable {
|
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, data_type: var_data_type };
|
let var = Variable { index: self.local_counter, var_type: VariableType::ParamTemp(param_index), data_type: var_data_type };
|
||||||
self.local_counter += 1;
|
self.local_counter += 1;
|
||||||
self.local_var_type.push(var);
|
self.local_var_type.push(var);
|
||||||
var
|
var
|
||||||
@@ -830,4 +834,8 @@ mod tests {
|
|||||||
fn test_if_while() {
|
fn test_if_while() {
|
||||||
test_case("26-32,34-41,46-51,57");
|
test_case("26-32,34-41,46-51,57");
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_func() {
|
||||||
|
test_case("12-13,58-60");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -116,7 +116,7 @@ impl Display for MoveRValue {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
pub enum VariableType {
|
pub enum VariableType {
|
||||||
Global,
|
Global,
|
||||||
ParamTemp,
|
ParamTemp(usize),
|
||||||
Local,
|
Local,
|
||||||
Temp,
|
Temp,
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ impl Display for Variable {
|
|||||||
VariableType::Global => "@g",
|
VariableType::Global => "@g",
|
||||||
VariableType::Local => "%l",
|
VariableType::Local => "%l",
|
||||||
VariableType::Temp => "%t",
|
VariableType::Temp => "%t",
|
||||||
VariableType::ParamTemp => "%t",
|
VariableType::ParamTemp(_) => "%t",
|
||||||
};
|
};
|
||||||
write!(f, "{}{}", prefix, self.index)
|
write!(f, "{}{}", prefix, self.index)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user