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);
// Free temporary register
self.allocator.free_temp(&result_reg);
self.allocator.free_temp(result_reg);
} else {
// Just declaring variable without initialization
self.allocator.alloc_var(&var.name)?;
@@ -267,8 +267,8 @@ impl CodeGenerator {
code.push(format!("\tstw {}, {}", result_reg, ptr_reg));
self.allocator.free_temp(&result_reg);
self.allocator.free_temp(&ptr_reg);
self.allocator.free_temp(result_reg);
self.allocator.free_temp(ptr_reg);
}
Statement::Assign { varname, value } => {
@@ -288,7 +288,7 @@ impl CodeGenerator {
}
// Free temporary register
self.allocator.free_temp(&result_reg);
self.allocator.free_temp(result_reg);
}
Statement::Return(expr) => {
@@ -298,7 +298,7 @@ impl CodeGenerator {
code.extend(expr_code);
code.push(format!("\tstw {}, bpr, 8", result_reg));
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
code.push(format!("\tcmp {}, zero", cond_reg));
self.allocator.free_temp(&cond_reg);
self.allocator.free_temp(cond_reg);
// Generate unique labels
let then_label = format!("_then_{}", self.get_unique_label());
@@ -361,7 +361,7 @@ impl CodeGenerator {
code.extend(cond_code);
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));
@@ -390,7 +390,7 @@ impl CodeGenerator {
let (result_reg, expr_code) =
self.generate_expression(expr, false, func_body)?;
code.extend(expr_code);
self.allocator.free_temp(&result_reg);
self.allocator.free_temp(result_reg);
}
Statement::Block(statements) => {
@@ -562,8 +562,8 @@ impl CodeGenerator {
}
// Free operand registers (allocator will protect variables)
self.allocator.free_temp(&left_reg);
self.allocator.free_temp(&right_reg);
self.allocator.free_temp(left_reg);
self.allocator.free_temp(right_reg);
Ok((result_reg, code))
}
@@ -592,7 +592,7 @@ impl CodeGenerator {
let saved_regs = self.allocator.get_caller_saved_registers();
for reg in &saved_regs {
// 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
@@ -651,7 +651,7 @@ impl CodeGenerator {
// Free argument registers
for reg in arg_regs {
self.allocator.free_temp(&reg);
self.allocator.free_temp(reg);
}
Ok((result_reg, code))
@@ -678,16 +678,18 @@ impl CodeGenerator {
code.push(format!("\tldw {}, {}", operand_reg, result_reg));
}
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!(
"\tsubi bpr {} {}",
-(4 + self.allocator.get_stack_offset()),
"\taddi spr, {}, {}",
offset - self.allocator.get_stack_offset(),
result_reg
))
));
}
}
self.allocator.free_temp(&operand_reg);
self.allocator.free_temp(operand_reg);
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> {
// Try to find an unused register
println!("finding! {:#?}", self.in_use);
// println!("finding! {:#?}", self.in_use);
if let Some(reg) = self.find_free_register() {
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
/// NOTE: This will NOT free registers that contain variables!
/// 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
if self.register_contents.contains_key(reg) {
if self.register_contents.contains_key(&reg) {
// This register holds a variable - don't free it!
// Variables are only freed when they go out of scope via free_var()
return;
}
// 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) {
// Check if this variable is in a register
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.in_use.insert(reg, false);
}
@@ -165,12 +173,12 @@ impl RegisterAllocator {
location.register = Some(reg);
// 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!(
"\tldw {}, {} // bpr{}: {}",
"\tldw spr, {}, {} // spr+{}: {}",
reg,
reg,
offset - 4,
offset - self.stack_offset,
offset - self.stack_offset,
var_name
));
@@ -217,8 +225,8 @@ impl RegisterAllocator {
if let Some(reg) = location.register {
if reg == *source_reg {
return vec![format!(
"\tmov {}, {} // var {}",
source_reg, reg, var_name
"\tmov {}, {} // save var:{} reg:{}",
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 let Some(offset) = location.stack {
return vec![format!(
"\tstw {}, bpr, {} // var {}",
source_reg, offset, var_name
"\tstw {}, spr, {} // save var:{} offset:{}",
source_reg,
offset - self.stack_offset,
var_name,
offset
)];
}
}
@@ -268,7 +279,8 @@ impl RegisterAllocator {
}
/// 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,
reg: &Register,
) -> Result<Vec<String>, CompilerError> {
@@ -281,22 +293,31 @@ impl RegisterAllocator {
// check if var is on the stack
if let Some(offset) = location.stack {
// 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);
}
// 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
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
// Note: We track offset from bpr for consistency
location.stack = Some(self.stack_offset);
location.stack = Some(offset);
Ok(code)
} else {
Err(CompilerError::Generic(format!(
@@ -311,7 +332,7 @@ impl RegisterAllocator {
pub fn free_register(
&mut self,
reg: &Register,
) -> Result<Vec<String>, CompilerError> {
) -> Result<(i32, Vec<String>), CompilerError> {
let mut code = Vec::new();
// check if the variable is declared.
@@ -321,30 +342,36 @@ impl RegisterAllocator {
// check if var name is on the stack
if let Some(offset) = location.stack {
// 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.
location.register = None;
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
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
location.stack = Some(self.stack_offset);
location.stack = Some(offset);
location.register = None;
self.register_contents.remove(reg);
Ok(code)
Ok((offset, code))
} else {
Err(CompilerError::Generic(format!(
"Register {} does not contain a variable to spill!",
@@ -357,7 +384,7 @@ impl RegisterAllocator {
fn find_free_register(&self) -> Option<Register> {
self.in_use
.iter()
.filter(|(_, in_use)| !**in_use)
.filter(|(_, in_use)| !*in_use)
.map(|(reg, _)| *reg)
.next()
}
@@ -371,7 +398,7 @@ impl RegisterAllocator {
for reg in regs_to_spill {
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)]
pub enum Register {
Rg0,
Rg1,
Rg2,
Rg3,
Rg4,
Rg5,
Rg6,
Rg7,
Rg8,
Rg9,
Rga,
Rgb,
Rgc,
Rgd,
Rge,
Rgf,
Zero,
Null,
Rg0 = 0,
Rg1 = 1,
Rg2 = 2,
Rg3 = 3,
Rg4 = 4,
Rg5 = 5,
Rg6 = 6,
Rg7 = 7,
Rg8 = 8,
Rg9 = 9,
Rga = 10,
Rgb = 11,
Rgc = 12,
Rgd = 13,
Rge = 14,
Rgf = 15,
Zero = 16,
Null = 17,
}
impl fmt::Display for Register {