- renamed assembler_runner to just assembler
- implemented type parsing including custom types and generics (useless for now as we do no semantic analysis) - implemented struct literal parsing - implemented struct definition parsing (no generics yet) - implemented tuple parsing - registers are now allocated starting from zero - updated to-dos
This commit is contained in:
@@ -65,6 +65,10 @@ impl CodeGenerator {
|
||||
Declaration::Dependency(Dependency { name, .. }) => {
|
||||
self.symbols.push(name)
|
||||
}
|
||||
Declaration::Struct { .. } => {} /* we can't do any code generation for
|
||||
* a struct yet. we may need to later
|
||||
* once these become class-like
|
||||
* objects with implementations */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +168,8 @@ impl CodeGenerator {
|
||||
Declaration::Dependency(Dependency { name, path }) => {
|
||||
self.imports.insert(name, path);
|
||||
}
|
||||
Declaration::Struct { .. } => {} /* can't do any codegen for these yet,
|
||||
* they're just types. */
|
||||
};
|
||||
|
||||
Ok(())
|
||||
@@ -536,6 +542,11 @@ impl CodeGenerator {
|
||||
}
|
||||
|
||||
Expression::ArrayLiteral { elements, type_id } => todo!(),
|
||||
Expression::StructLiteral {
|
||||
name,
|
||||
fields,
|
||||
type_id,
|
||||
} => todo!(),
|
||||
|
||||
Expression::Variable { name, .. } => {
|
||||
if self.is_global(&name.name) {
|
||||
|
||||
@@ -18,7 +18,7 @@ pub struct RegisterAllocator {
|
||||
stack_offset: i32,
|
||||
|
||||
/// Track which registers are currently in use
|
||||
in_use: HashMap<Register, bool>,
|
||||
in_use: Vec<(Register, bool)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -85,7 +85,7 @@ impl RegisterAllocator {
|
||||
// println!("finding! {:#?}", self.in_use);
|
||||
|
||||
if let Some(reg) = self.find_free_register() {
|
||||
self.in_use.insert(reg, true);
|
||||
self.in_use[reg as usize].1 = true;
|
||||
return Ok((reg, Vec::new()));
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ impl RegisterAllocator {
|
||||
|
||||
// This is a true temporary - safe to free
|
||||
if !matches!(reg, Register::Zero | Register::Null) {
|
||||
self.in_use.insert(reg, false);
|
||||
self.in_use[reg as usize].1 = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ impl RegisterAllocator {
|
||||
&& !matches!(reg, Register::Zero | Register::Null)
|
||||
{
|
||||
self.register_contents.remove(®);
|
||||
self.in_use.insert(reg, false);
|
||||
self.in_use[reg as usize].1 = false;
|
||||
}
|
||||
|
||||
self.variable_locations.remove(var);
|
||||
@@ -252,7 +252,7 @@ impl RegisterAllocator {
|
||||
.insert(var_name.to_string(), Location::register(*source_reg));
|
||||
self.register_contents
|
||||
.insert(*source_reg, var_name.to_string());
|
||||
self.in_use.insert(*source_reg, true);
|
||||
self.in_use[*source_reg as usize].1 = true;
|
||||
|
||||
return Vec::new();
|
||||
}
|
||||
@@ -264,7 +264,7 @@ impl RegisterAllocator {
|
||||
.insert(var_name.to_string(), Location::register(free_reg));
|
||||
self.register_contents
|
||||
.insert(free_reg.clone(), var_name.to_string());
|
||||
self.in_use.insert(free_reg, true);
|
||||
self.in_use[free_reg as usize].1 = true;
|
||||
|
||||
return vec![format!("\tmov {}, {}", source_reg, free_reg)];
|
||||
}
|
||||
@@ -459,26 +459,31 @@ impl RegisterAllocator {
|
||||
pub fn get_caller_saved_registers(&self) -> Vec<Register> {
|
||||
self.register_contents
|
||||
.iter()
|
||||
.filter(|(reg, _)| *self.in_use.get(*reg).unwrap_or(&false))
|
||||
.filter(|(reg, _)| {
|
||||
self.in_use
|
||||
.get(**reg as usize)
|
||||
.unwrap_or(&(Register::Null, false))
|
||||
.1
|
||||
})
|
||||
.map(|(reg, _)| reg.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Save caller-saved registers before a function call
|
||||
/// Returns assembly code to save them
|
||||
pub fn _save_caller_saved(&mut self) -> Vec<String> {
|
||||
let mut code = Vec::new();
|
||||
// pub fn _save_caller_saved(&mut self) -> Vec<String> {
|
||||
// let mut code = Vec::new();
|
||||
|
||||
// For simplicity, save all currently used registers
|
||||
// In a more sophisticated compiler, you'd only save registers that are live
|
||||
for (reg, _) in self.register_contents.clone() {
|
||||
if *self.in_use.get(®).unwrap_or(&false) {
|
||||
code.push(format!("\tpush {}", reg));
|
||||
}
|
||||
}
|
||||
// // For simplicity, save all currently used registers
|
||||
// // In a more sophisticated compiler, you'd only save registers that are live
|
||||
// for (reg, _) in self.register_contents.clone() {
|
||||
// if *self.in_use.get(reg as usize).unwrap_or(&false) {
|
||||
// code.push(format!("\tpush {}", reg));
|
||||
// }
|
||||
// }
|
||||
|
||||
code
|
||||
}
|
||||
// code
|
||||
// }
|
||||
|
||||
/// Restore caller-saved registers after a function call
|
||||
/// Returns assembly code to restore them
|
||||
|
||||
Reference in New Issue
Block a user