fixed pointers and stuff.

This commit is contained in:
2026-02-08 11:45:26 +00:00
parent 6699333b2c
commit 828f5bfb2d
2 changed files with 102 additions and 73 deletions
+19 -17
View File
@@ -245,7 +245,7 @@ impl CodeGenerator {
code.extend(store_code); code.extend(store_code);
// Free temporary register // Free temporary register
self.allocator.free_temp(&result_reg); self.allocator.free_temp(result_reg);
} else { } else {
// Just declaring variable without initialization // Just declaring variable without initialization
self.allocator.alloc_var(&var.name)?; self.allocator.alloc_var(&var.name)?;
@@ -267,8 +267,8 @@ impl CodeGenerator {
code.push(format!("\tstw {}, {}", result_reg, ptr_reg)); code.push(format!("\tstw {}, {}", result_reg, ptr_reg));
self.allocator.free_temp(&result_reg); self.allocator.free_temp(result_reg);
self.allocator.free_temp(&ptr_reg); self.allocator.free_temp(ptr_reg);
} }
Statement::Assign { varname, value } => { Statement::Assign { varname, value } => {
@@ -288,7 +288,7 @@ impl CodeGenerator {
} }
// Free temporary register // Free temporary register
self.allocator.free_temp(&result_reg); self.allocator.free_temp(result_reg);
} }
Statement::Return(expr) => { Statement::Return(expr) => {
@@ -298,7 +298,7 @@ impl CodeGenerator {
code.extend(expr_code); code.extend(expr_code);
code.push(format!("\tstw {}, bpr, 8", result_reg)); code.push(format!("\tstw {}, bpr, 8", result_reg));
code.push(format!("\tjmp _ret")); code.push(format!("\tjmp _ret"));
self.allocator.free_temp(&result_reg); self.allocator.free_temp(result_reg);
} }
} }
@@ -314,7 +314,7 @@ impl CodeGenerator {
// Compare with zero // Compare with zero
code.push(format!("\tcmp {}, zero", cond_reg)); code.push(format!("\tcmp {}, zero", cond_reg));
self.allocator.free_temp(&cond_reg); self.allocator.free_temp(cond_reg);
// Generate unique labels // Generate unique labels
let then_label = format!("_then_{}", self.get_unique_label()); let then_label = format!("_then_{}", self.get_unique_label());
@@ -361,7 +361,7 @@ impl CodeGenerator {
code.extend(cond_code); code.extend(cond_code);
code.push(format!("\tcmp {}, zero", cond_reg)); code.push(format!("\tcmp {}, zero", cond_reg));
self.allocator.free_temp(&cond_reg); self.allocator.free_temp(cond_reg);
code.push(format!("\tjeq {}", loop_end)); code.push(format!("\tjeq {}", loop_end));
@@ -390,7 +390,7 @@ impl CodeGenerator {
let (result_reg, expr_code) = let (result_reg, expr_code) =
self.generate_expression(expr, false, func_body)?; self.generate_expression(expr, false, func_body)?;
code.extend(expr_code); code.extend(expr_code);
self.allocator.free_temp(&result_reg); self.allocator.free_temp(result_reg);
} }
Statement::Block(statements) => { Statement::Block(statements) => {
@@ -562,8 +562,8 @@ impl CodeGenerator {
} }
// Free operand registers (allocator will protect variables) // Free operand registers (allocator will protect variables)
self.allocator.free_temp(&left_reg); self.allocator.free_temp(left_reg);
self.allocator.free_temp(&right_reg); self.allocator.free_temp(right_reg);
Ok((result_reg, code)) Ok((result_reg, code))
} }
@@ -592,7 +592,7 @@ impl CodeGenerator {
let saved_regs = self.allocator.get_caller_saved_registers(); let saved_regs = self.allocator.get_caller_saved_registers();
for reg in &saved_regs { for reg in &saved_regs {
// spill variables to stack // spill variables to stack
code.extend(self.allocator.free_register(reg).unwrap()); code.extend(self.allocator.free_register(reg).unwrap().1);
} }
// Evaluate and push arguments in reverse order // Evaluate and push arguments in reverse order
@@ -651,7 +651,7 @@ impl CodeGenerator {
// Free argument registers // Free argument registers
for reg in arg_regs { for reg in arg_regs {
self.allocator.free_temp(&reg); self.allocator.free_temp(reg);
} }
Ok((result_reg, code)) Ok((result_reg, code))
@@ -678,16 +678,18 @@ impl CodeGenerator {
code.push(format!("\tldw {}, {}", operand_reg, result_reg)); code.push(format!("\tldw {}, {}", operand_reg, result_reg));
} }
UnaryOperator::Reference => { UnaryOperator::Reference => {
code.extend(self.allocator.spill_register(&operand_reg)?); let (offset, alloc_code) =
self.allocator.free_register(&operand_reg)?;
code.extend(alloc_code);
code.push(format!( code.push(format!(
"\tsubi bpr {} {}", "\taddi spr, {}, {}",
-(4 + self.allocator.get_stack_offset()), offset - self.allocator.get_stack_offset(),
result_reg result_reg
)) ));
} }
} }
self.allocator.free_temp(&operand_reg); self.allocator.free_temp(operand_reg);
Ok((result_reg, code)) Ok((result_reg, code))
} }
+83 -56
View File
@@ -82,7 +82,7 @@ impl RegisterAllocator {
pub fn alloc_temp(&mut self) -> Result<(Register, Vec<String>), CompilerError> { pub fn alloc_temp(&mut self) -> Result<(Register, Vec<String>), CompilerError> {
// Try to find an unused register // Try to find an unused register
println!("finding! {:#?}", self.in_use); // println!("finding! {:#?}", self.in_use);
if let Some(reg) = self.find_free_register() { if let Some(reg) = self.find_free_register() {
self.in_use.insert(reg, true); self.in_use.insert(reg, true);
@@ -116,25 +116,33 @@ impl RegisterAllocator {
)) ))
} }
// fn set_in_use(&mut self, reg: Register, in_use: bool) {
// self.in_use[reg as usize].1 = in_use;
// }
/// Free a temporary register after use /// Free a temporary register after use
/// NOTE: This will NOT free registers that contain variables! /// NOTE: This will NOT free registers that contain variables!
/// Variables persist throughout their scope and must not be freed /// Variables persist throughout their scope and must not be freed
pub fn free_temp(&mut self, reg: &Register) { pub fn free_temp(&mut self, reg: Register) {
// Check if this register contains a variable // Check if this register contains a variable
if self.register_contents.contains_key(reg) { if self.register_contents.contains_key(&reg) {
// This register holds a variable - don't free it! // This register holds a variable - don't free it!
// Variables are only freed when they go out of scope via free_var() // Variables are only freed when they go out of scope via free_var()
return; return;
} }
// This is a true temporary - safe to free // This is a true temporary - safe to free
self.in_use.insert(*reg, false); if reg != Register::Zero {
self.in_use.insert(reg, false);
}
} }
pub fn free_var(&mut self, var: &str) { pub fn free_var(&mut self, var: &str) {
// Check if this variable is in a register // Check if this variable is in a register
if let Some(location) = self.variable_locations.get(var).cloned() { if let Some(location) = self.variable_locations.get(var).cloned() {
if let Some(reg) = location.register { if let Some(reg) = location.register
&& reg != Register::Zero
{
self.register_contents.remove(&reg); self.register_contents.remove(&reg);
self.in_use.insert(reg, false); self.in_use.insert(reg, false);
} }
@@ -165,12 +173,12 @@ impl RegisterAllocator {
location.register = Some(reg); location.register = Some(reg);
// Load from bpr + offset (offset is negative) // Load from bpr + offset (offset is negative)
code.push(format!("\tsubi bpr {} {}", -(offset + 4), reg)); // code.push(format!("\tsubi bpr {} {}", -(offset + 4), reg));
code.push(format!( code.push(format!(
"\tldw {}, {} // bpr{}: {}", "\tldw spr, {}, {} // spr+{}: {}",
reg, reg,
reg, offset - self.stack_offset,
offset - 4, offset - self.stack_offset,
var_name var_name
)); ));
@@ -217,8 +225,8 @@ impl RegisterAllocator {
if let Some(reg) = location.register { if let Some(reg) = location.register {
if reg == *source_reg { if reg == *source_reg {
return vec![format!( return vec![format!(
"\tmov {}, {} // var {}", "\tmov {}, {} // save var:{} reg:{}",
source_reg, reg, var_name source_reg, reg, var_name, reg
)]; )];
} }
} }
@@ -226,8 +234,11 @@ impl RegisterAllocator {
// if the variable exists on the stack but not a register we write here. // if the variable exists on the stack but not a register we write here.
if let Some(offset) = location.stack { if let Some(offset) = location.stack {
return vec![format!( return vec![format!(
"\tstw {}, bpr, {} // var {}", "\tstw {}, spr, {} // save var:{} offset:{}",
source_reg, offset, var_name source_reg,
offset - self.stack_offset,
var_name,
offset
)]; )];
} }
} }
@@ -268,7 +279,8 @@ impl RegisterAllocator {
} }
/// spill a register to the stack (WITHOUT FREEING) /// spill a register to the stack (WITHOUT FREEING)
pub fn spill_register( /// DO NOT USE this if it's for a pointer!!!!
pub fn _spill_register(
&mut self, &mut self,
reg: &Register, reg: &Register,
) -> Result<Vec<String>, CompilerError> { ) -> Result<Vec<String>, CompilerError> {
@@ -281,22 +293,31 @@ impl RegisterAllocator {
// check if var is on the stack // check if var is on the stack
if let Some(offset) = location.stack { if let Some(offset) = location.stack {
// ensure stack value is up to date with register value. // ensure stack value is up to date with register value.
code.push(format!("\tstw {}, {}", reg, offset)); code.push(format!(
"\tstw {}, spr, {} // save var:{} offset:{}",
reg,
offset - self.stack_offset,
var_name,
offset
));
return Ok(code); return Ok(code);
} }
// if the variable is not on the stack:
// push register to stack (spr decrements automatically)
code.push(format!(
"\tpush {} // bpr{}: {}",
reg, self.stack_offset, var_name
));
// Track that we pushed one word // Track that we pushed one word
self.stack_offset -= 4; self.stack_offset -= 4;
// if the variable is not on the stack:
// push register to stack (spr decrements automatically)
let offset = self.stack_offset;
code.push(format!(
"\tpush {} // free var:{} offset:{}",
reg, var_name, offset
));
// Update variable location - it's now at current spr // Update variable location - it's now at current spr
// Note: We track offset from bpr for consistency // Note: We track offset from bpr for consistency
location.stack = Some(self.stack_offset); location.stack = Some(offset);
Ok(code) Ok(code)
} else { } else {
Err(CompilerError::Generic(format!( Err(CompilerError::Generic(format!(
@@ -311,7 +332,7 @@ impl RegisterAllocator {
pub fn free_register( pub fn free_register(
&mut self, &mut self,
reg: &Register, reg: &Register,
) -> Result<Vec<String>, CompilerError> { ) -> Result<(i32, Vec<String>), CompilerError> {
let mut code = Vec::new(); let mut code = Vec::new();
// check if the variable is declared. // check if the variable is declared.
@@ -321,30 +342,36 @@ impl RegisterAllocator {
// check if var name is on the stack // check if var name is on the stack
if let Some(offset) = location.stack { if let Some(offset) = location.stack {
// store current register value in stack location // store current register value in stack location
code.push(format!("\tstw {}, {}", reg, offset)); code.push(format!(
"\tstw {}, spr, {} // save var:{} offset:{}",
reg,
offset - self.stack_offset,
var_name,
offset
));
// free the register. // free the register.
location.register = None; location.register = None;
self.register_contents.remove(reg); self.register_contents.remove(reg);
return Ok(code); return Ok((offset, code));
} }
// if the variable is not on the stack:
// push register to stack (spr decrements automatically)
code.push(format!(
"\tpush {} // bpr{}: {}",
reg, self.stack_offset, var_name
));
// Track that we pushed one word // Track that we pushed one word
self.stack_offset -= 4; self.stack_offset -= 4;
// Update variable location - it's now at current spr
let offset = self.stack_offset;
code.push(format!(
"\tpush {} // free var:{} offset:{}",
reg, var_name, offset
));
// Update variable location
// Note: We track offset from bpr for consistency // Note: We track offset from bpr for consistency
location.stack = Some(self.stack_offset); location.stack = Some(offset);
location.register = None; location.register = None;
self.register_contents.remove(reg); self.register_contents.remove(reg);
Ok(code) Ok((offset, code))
} else { } else {
Err(CompilerError::Generic(format!( Err(CompilerError::Generic(format!(
"Register {} does not contain a variable to spill!", "Register {} does not contain a variable to spill!",
@@ -357,7 +384,7 @@ impl RegisterAllocator {
fn find_free_register(&self) -> Option<Register> { fn find_free_register(&self) -> Option<Register> {
self.in_use self.in_use
.iter() .iter()
.filter(|(_, in_use)| !**in_use) .filter(|(_, in_use)| !*in_use)
.map(|(reg, _)| *reg) .map(|(reg, _)| *reg)
.next() .next()
} }
@@ -371,7 +398,7 @@ impl RegisterAllocator {
for reg in regs_to_spill { for reg in regs_to_spill {
if let Ok(spill_code) = self.free_register(&reg) { if let Ok(spill_code) = self.free_register(&reg) {
code.extend(spill_code); code.extend(spill_code.1);
} }
} }
@@ -469,24 +496,24 @@ impl RegisterAllocator {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Register { pub enum Register {
Rg0, Rg0 = 0,
Rg1, Rg1 = 1,
Rg2, Rg2 = 2,
Rg3, Rg3 = 3,
Rg4, Rg4 = 4,
Rg5, Rg5 = 5,
Rg6, Rg6 = 6,
Rg7, Rg7 = 7,
Rg8, Rg8 = 8,
Rg9, Rg9 = 9,
Rga, Rga = 10,
Rgb, Rgb = 11,
Rgc, Rgc = 12,
Rgd, Rgd = 13,
Rge, Rge = 14,
Rgf, Rgf = 15,
Zero, Zero = 16,
Null, Null = 17,
} }
impl fmt::Display for Register { impl fmt::Display for Register {