diff --git a/dm/src/main.rs b/dm/src/main.rs index 29c0529..cca055a 100644 --- a/dm/src/main.rs +++ b/dm/src/main.rs @@ -64,16 +64,14 @@ fn main() { } } - for ir_function in &mut ir_functions { - ir_function.assign_registers(args.register_count); - } - + let mut functions: Vec = vec![]; let mut constants_table = ConstantsTable::new(); - let functions: Vec = ir_functions - .iter() - .map(|ir_function| ir_function.assemble(&mut constants_table)) - .collect(); + for ir_function in &mut ir_functions { + let (_, stack_size) = ir_function.assign_registers(args.register_count); + let function = ir_function.assemble(stack_size, &mut constants_table); + functions.push(function); + } if args.show_asm { for function in &functions { diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 13f10b3..64ed7a5 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -87,14 +87,9 @@ impl Function { // handle parameters symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name)); let mut parameter_symbols = vec![]; - let parameter_count = self.parameters.len(); - let stack_frame_offset_base = (parameter_count as isize).neg(); - for (i, parameter) in self.parameters.iter_mut().enumerate() { + for parameter in &mut self.parameters { match parameter.gather_declared_names(symbol_table) { Ok(parameter_symbol) => { - parameter_symbol - .borrow_mut() - .set_stack_frame_offset(stack_frame_offset_base + (i as isize)); parameter_symbols.push(parameter_symbol); } Err(mut parameter_diagnostics) => { diff --git a/dmc-lib/src/ir/ir_add.rs b/dmc-lib/src/ir/ir_add.rs index 15a3dc4..d614971 100644 --- a/dmc-lib/src/ir/ir_add.rs +++ b/dmc-lib/src/ir/ir_add.rs @@ -1,7 +1,7 @@ use crate::constants_table::ConstantsTable; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use dvm_lib::instruction::AddOperand; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -68,4 +68,8 @@ impl VrUser for IrAdd { self.left.propagate_register_assignments(assignments); self.right.propagate_register_assignments(assignments); } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no-op, no definitions here + } } diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index 88f3af7..108b548 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -2,7 +2,7 @@ use crate::constants_table::ConstantsTable; use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use dvm_lib::instruction::{Instruction, Location}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; @@ -68,6 +68,13 @@ impl VrUser for IrAssign { } self.initializer.propagate_register_assignments(assignments); } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { + let mut borrowed_destination = self.destination.borrow_mut(); + if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() { + stack_variable.set_offset(counter.next()); + } + } } impl Assemble for IrAssign { diff --git a/dmc-lib/src/ir/ir_block.rs b/dmc-lib/src/ir/ir_block.rs index f86329c..d9cfcb0 100644 --- a/dmc-lib/src/ir/ir_block.rs +++ b/dmc-lib/src/ir/ir_block.rs @@ -2,7 +2,7 @@ use crate::constants_table::ConstantsTable; use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::{HasVrUsers, VrUser}; +use crate::ir::register_allocation::{HasVrUsers, OffsetCounter, VrUser}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -75,6 +75,12 @@ impl VrUser for IrBlock { statement.propagate_register_assignments(assignments); } } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { + for statement in &mut self.statements { + statement.propagate_stack_offsets(counter); + } + } } impl Assemble for IrBlock { @@ -145,7 +151,7 @@ mod tests { if let ModuleLevelDeclaration::Function(main) = main { let mut main_ir = main.to_ir(&symbol_table); - let register_assignments = main_ir.assign_registers(2); + let (register_assignments, _) = main_ir.assign_registers(2); assert_eq!(register_assignments.len(), 4); } else { unreachable!() diff --git a/dmc-lib/src/ir/ir_call.rs b/dmc-lib/src/ir/ir_call.rs index 8b59096..b55fd1e 100644 --- a/dmc-lib/src/ir/ir_call.rs +++ b/dmc-lib/src/ir/ir_call.rs @@ -2,7 +2,7 @@ use crate::constants_table::ConstantsTable; use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use crate::symbol::FunctionSymbol; use dvm_lib::instruction::Instruction; use std::cell::RefCell; @@ -53,6 +53,10 @@ impl VrUser for IrCall { argument.propagate_register_assignments(assignments); } } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no-op, because no definitions here + } } impl Assemble for IrCall { @@ -74,7 +78,6 @@ impl Assemble for IrCall { symbol.parameters().len(), )); } - // todo: handle function postlude } } diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index a8df47a..a5d976b 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -3,7 +3,7 @@ use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::{ IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor, }; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use crate::type_info::TypeInfo; use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand}; use std::cell::RefCell; @@ -225,4 +225,8 @@ impl VrUser for IrExpression { } } } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no-op + } } diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index 0ef6c1f..0b98c80 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -34,21 +34,21 @@ impl IrFunction { } } - /// Returns the register assignments for debugging purposes pub fn assign_registers( &mut self, register_count: usize, - ) -> HashMap { + ) -> (HashMap, isize) { self.entry.borrow_mut().assign_registers(register_count) } - pub fn assemble(&self, constants_table: &mut ConstantsTable) -> Function { + pub fn assemble(&self, stack_size: isize, constants_table: &mut ConstantsTable) -> Function { let mut builder = InstructionsBuilder::new(); self.entry.borrow().assemble(&mut builder, constants_table); let instructions = builder.take_instructions(); Function::new( self.function_symbol.borrow().name_owned(), self.parameters.len(), + stack_size, instructions, ) } diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index e7dc8a7..1d562f7 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -2,7 +2,7 @@ use crate::ir::ir_add::IrAdd; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -75,4 +75,8 @@ impl VrUser for IrOperation { } } } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no-op + } } diff --git a/dmc-lib/src/ir/ir_return.rs b/dmc-lib/src/ir/ir_return.rs index aad49e8..c58eeef 100644 --- a/dmc-lib/src/ir/ir_return.rs +++ b/dmc-lib/src/ir/ir_return.rs @@ -2,7 +2,7 @@ use crate::constants_table::ConstantsTable; use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use dvm_lib::instruction::Instruction; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -44,10 +44,14 @@ impl VrUser for IrReturn { ir_expression.propagate_register_assignments(assignments); } } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no-op + } } impl Assemble for IrReturn { - fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + fn assemble(&self, builder: &mut InstructionsBuilder, _constants_table: &mut ConstantsTable) { if let Some(ir_expression) = self.value.as_ref() { builder.push(Instruction::SetReturnValue(ir_expression.return_operand())); } diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index deb0d92..55dd94c 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -4,7 +4,7 @@ use crate::ir::ir_assign::IrAssign; use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -61,6 +61,20 @@ impl VrUser for IrStatement { } } } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { + match self { + IrStatement::Assign(ir_assign) => { + ir_assign.propagate_stack_offsets(counter); + } + IrStatement::Call(ir_call) => { + ir_call.propagate_stack_offsets(counter); + } + IrStatement::Return(ir_return) => { + ir_return.propagate_stack_offsets(counter); + } + } + } } impl Assemble for IrStatement { diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 2597191..35bdd90 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -139,6 +139,10 @@ impl IrStackVariableDescriptor { &self.name } + pub fn set_offset(&mut self, offset: isize) { + self.offset = Some(offset); + } + pub fn offset(&self) -> isize { self.offset.unwrap() } @@ -146,6 +150,6 @@ impl IrStackVariableDescriptor { impl Display for IrStackVariableDescriptor { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}_b{}", self.name, self.block_id) + write!(f, "{}_{}", self.name, self.block_id) } } diff --git a/dmc-lib/src/ir/register_allocation.rs b/dmc-lib/src/ir/register_allocation.rs index 349956d..0f77f0c 100644 --- a/dmc-lib/src/ir/register_allocation.rs +++ b/dmc-lib/src/ir/register_allocation.rs @@ -104,7 +104,7 @@ pub trait HasVrUsers { fn assign_registers( &mut self, register_count: usize, - ) -> HashMap { + ) -> (HashMap, isize) { let mut spills: HashSet = HashSet::new(); loop { let mut interference_graph = self.interference_graph(); @@ -122,7 +122,13 @@ pub trait HasVrUsers { for vr_user in self.vr_users_mut() { vr_user.propagate_register_assignments(®isters); } - return registers; + // also set offsets + let mut offset_counter = OffsetCounter::new(); + for vr_user in self.vr_users_mut() { + vr_user.propagate_stack_offsets(&mut offset_counter); + } + + return (registers, offset_counter.get_count()); } } } @@ -136,6 +142,27 @@ pub trait VrUser { &mut self, assignments: &HashMap, ); + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter); +} + +pub struct OffsetCounter { + counter: isize, +} + +impl OffsetCounter { + pub fn new() -> Self { + Self { counter: 0 } + } + + pub fn next(&mut self) -> isize { + let offset = self.counter; + self.counter += 1; + offset + } + + pub fn get_count(&self) -> isize { + self.counter + } } #[derive(Debug)] diff --git a/dmc-lib/src/symbol.rs b/dmc-lib/src/symbol.rs index fbecf5e..e8c53ff 100644 --- a/dmc-lib/src/symbol.rs +++ b/dmc-lib/src/symbol.rs @@ -51,9 +51,6 @@ pub struct ParameterSymbol { name: Rc, type_info: TypeInfo, ir_parameter: Option>, - - #[deprecated] - stack_frame_offset: Option, } impl ParameterSymbol { @@ -62,7 +59,6 @@ impl ParameterSymbol { name: name.into(), type_info, ir_parameter: None, - stack_frame_offset: None, } } @@ -85,25 +81,12 @@ impl ParameterSymbol { pub fn ir_parameter(&self) -> &Rc { self.ir_parameter.as_ref().unwrap() } - - #[deprecated] - pub fn set_stack_frame_offset(&mut self, offset: isize) { - self.stack_frame_offset = Some(offset); - } - - #[deprecated] - pub fn stack_frame_offset(&self) -> isize { - self.stack_frame_offset.unwrap() - } } pub struct VariableSymbol { name: Rc, type_info: Option, vr_variable: Option>>, - - #[deprecated] - register: Option, } impl VariableSymbol { @@ -112,7 +95,6 @@ impl VariableSymbol { name: name.into(), type_info: None, vr_variable: None, - register: None, } } @@ -143,14 +125,6 @@ impl VariableSymbol { .as_ref() .expect("ir_variable not yet initialized") } - - pub fn set_register(&mut self, register: usize) { - self.register = Some(register); - } - - pub fn register(&self) -> usize { - self.register.unwrap() - } } pub enum ExpressibleSymbol { diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index d0f62c4..012aff4 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -72,7 +72,7 @@ impl Display for Location { write!(f, "r{}", register) } Location::StackFrameOffset(offset) => { - if offset.is_positive() { + if offset.is_positive() || *offset == 0 { write!(f, "fp+{}", offset) } else { write!(f, "fp{}", offset) diff --git a/dvm-lib/src/vm/function.rs b/dvm-lib/src/vm/function.rs index 5f38296..081f9c1 100644 --- a/dvm-lib/src/vm/function.rs +++ b/dvm-lib/src/vm/function.rs @@ -5,14 +5,21 @@ use std::rc::Rc; pub struct Function { name: Rc, parameter_count: usize, + stack_size: isize, instructions: Vec, } impl Function { - pub fn new(name: Rc, parameter_count: usize, instructions: Vec) -> Self { + pub fn new( + name: Rc, + parameter_count: usize, + stack_size: isize, + instructions: Vec, + ) -> Self { Self { name, parameter_count, + stack_size, instructions, } } @@ -29,6 +36,10 @@ impl Function { self.parameter_count } + pub fn stack_size(&self) -> isize { + self.stack_size + } + pub fn instructions(&self) -> &Vec { &self.instructions } diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index 05c8ec2..4718bfc 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -234,10 +234,16 @@ pub fn call<'a>( call_stack.push(CallFrame::new(function)); // put each arg on the stack - for argument in arguments { - call_stack.top_mut().stack_mut().push(argument); + for argument in &arguments { + call_stack.top_mut().stack_mut().push(argument.clone()); } + // ensure enough stack space + call_stack.top_mut().stack_mut().resize( + arguments.len() + (function.stack_size() as usize), + Value::Null, + ); + while call_stack.maybe_top().is_some() && call_stack.top().ip() < call_stack.top().instructions().len() { @@ -314,6 +320,12 @@ pub fn call<'a>( // push args call_stack.top_mut().stack_mut().append(&mut args); + // ensure enough stack space + call_stack + .top_mut() + .stack_mut() + .resize(arg_count + (function.stack_size() as usize), Value::Null); + // set fp for callee frame let callee_frame = call_stack.top_mut(); callee_frame.set_fp(*arg_count);