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