fixed pointers and stuff.
This commit is contained in:
@@ -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(®);
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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(®) {
|
||||
// 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(®);
|
||||
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(®) {
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user