diff --git a/dmc-lib/src/ast/binary_expression.rs b/dmc-lib/src/ast/binary_expression.rs index ec25c5b..df2226b 100644 --- a/dmc-lib/src/ast/binary_expression.rs +++ b/dmc-lib/src/ast/binary_expression.rs @@ -603,7 +603,7 @@ impl BinaryExpression { types_table: &TypesTable, ) -> IrExpression { let ir_operation = self.to_ir_operation(builder, symbol_table, types_table); - let t_var = IrVariable::new(&builder.new_t_var(), todo!()); + let t_var = todo!(); let as_rc = Rc::new(RefCell::new(t_var)); let ir_assign = IrAssign::new(todo!(), ir_operation); builder diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 245da0e..1e34211 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -489,6 +489,7 @@ impl Function { todo!(), todo!(), todo!(), + todo!(), ) } @@ -546,6 +547,7 @@ impl Function { todo!(), todo!(), todo!(), + todo!(), ) } } diff --git a/dmc-lib/src/ir/assemble.rs b/dmc-lib/src/ir/assemble.rs index e48b94f..1535cff 100644 --- a/dmc-lib/src/ir/assemble.rs +++ b/dmc-lib/src/ir/assemble.rs @@ -10,32 +10,114 @@ use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_type_info::IrTypeInfo; -use crate::ir::ir_variable::IrVariable; -use crate::ir::variable_locations::{VariableLocation, VariableLocations}; +use crate::ir::ir_variable::{ + IrFreeVariableId, IrFreeVariables, IrStackFrameVariableId, IrStackFrameVariables, IrVariable, + IrVariableInfo, +}; +use crate::ir::register_allocation::RegisterAssignment; +use crate::ir::stack_variable_offset::StackVariableOffset; use dvm_lib::instruction::{ AddOperand, Instruction, Location, LocationOrInteger, LocationOrNumber, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand, }; +use std::collections::{HashMap, HashSet}; struct FunctionAssemblyContext<'a> { - variable_locations: &'a VariableLocations, - parameters: &'a [IrParameter], - variables: &'a [IrVariable], constants_table: &'a mut ConstantsTable, + storage: &'a FunctionStorageMap<'a>, instructions: Vec, } +pub struct FunctionStorageMap<'a> { + parameters: &'a [IrParameter], + stack_frame_variables: &'a IrStackFrameVariables, + free_variables: &'a IrFreeVariables, + + stack_frame_variable_assignments: HashMap, + register_assignments: &'a HashMap, + spilled_assignments: HashMap, +} + +fn calculate_stack_frame_variable_offsets( + stack_frame_variables: &IrStackFrameVariables, +) -> HashMap { + let mut m = HashMap::new(); + for i in 0..stack_frame_variables.len() { + m.insert(i as IrStackFrameVariableId, i as StackVariableOffset); + } + m +} + +fn calculate_spilled_variable_offsets( + spilled_variables: &HashSet, + base_offset: StackVariableOffset, +) -> HashMap { + let mut m = HashMap::new(); + for (i, v) in spilled_variables.iter().enumerate() { + m.insert(*v, (i as StackVariableOffset) + base_offset); + } + m +} + +impl<'a> FunctionStorageMap<'a> { + pub fn new_from( + ir_function: &'a IrFunction, + register_assignments: &'a HashMap, + spilled_variables: &HashSet, + ) -> Self { + Self { + parameters: ir_function.parameters(), + stack_frame_variables: ir_function.stack_frame_variables(), + free_variables: ir_function.free_variables(), + stack_frame_variable_assignments: calculate_stack_frame_variable_offsets( + ir_function.stack_frame_variables(), + ), + register_assignments, + spilled_assignments: calculate_spilled_variable_offsets( + spilled_variables, + ir_function.stack_frame_variables().len() as StackVariableOffset, + ), + } + } + + fn get_variable_location(&self, ir_variable: &IrVariable) -> Location { + match ir_variable { + IrVariable::StackFrame(id) => { + Location::StackFrameOffset(self.stack_frame_variable_assignments[id]) + } + IrVariable::Free(id) => { + if let Some(register_assignment) = self.register_assignments.get(id) { + Location::Register(*register_assignment) + } else if let Some(stack_variable_offset) = self.spilled_assignments.get(id) { + Location::StackFrameOffset(*stack_variable_offset) + } else { + panic!("Cannot calculate a location for id {}", id); + } + } + } + } + + fn get_variable_info(&self, ir_variable: &IrVariable) -> &IrVariableInfo { + match ir_variable { + IrVariable::StackFrame(id) => &self.stack_frame_variables[*id], + IrVariable::Free(id) => &self.free_variables[*id], + } + } + + pub fn stack_size(&self) -> usize { + self.stack_frame_variables.len() + self.spilled_assignments.len() + } +} + pub fn assemble_ir_function( ir_function: &IrFunction, - variable_locations: &VariableLocations, + storage: &FunctionStorageMap, constants_table: &mut ConstantsTable, ) -> Vec { let mut ctx = FunctionAssemblyContext { - variable_locations, - constants_table, - parameters: ir_function.parameters(), - variables: ir_function.variables(), instructions: Vec::new(), + storage, + constants_table, }; for block in ir_function.blocks() { assemble_ir_block(block, &mut ctx); @@ -67,10 +149,7 @@ fn assemble_ir_statement(statement: &IrStatement, ctx: &mut FunctionAssemblyCont } fn assemble_ir_assign(ir_assign: &IrAssign, ctx: &mut FunctionAssemblyContext) { - let destination_location = to_location( - ctx.variable_locations - .get_variable_location(&ir_assign.destination()), - ); + let destination_location = ctx.storage.get_variable_location(ir_assign.destination()); match ir_assign.initializer() { IrOperation::GetFieldRef(_) => { todo!() @@ -191,11 +270,11 @@ fn assemble_ir_return(ir_return: &IrReturn, ctx: &mut FunctionAssemblyContext) { fn to_move_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> MoveOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => MoveOperand::Location( - Location::StackFrameOffset(ctx.parameters[*ir_parameter_id].stack_offset()), + Location::StackFrameOffset(ctx.storage.parameters[*ir_parameter_id].stack_offset()), ), - IrExpression::Variable(ir_variable_id) => MoveOperand::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable_id), - )), + IrExpression::Variable(ir_variable_id) => { + MoveOperand::Location(ctx.storage.get_variable_location(ir_variable_id)) + } IrExpression::Int(i) => MoveOperand::Int(*i), IrExpression::Double(d) => MoveOperand::Double(*d), IrExpression::String(s) => { @@ -211,19 +290,18 @@ fn to_multiply_operand( ) -> MultiplyOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => MultiplyOperand::Location( - Location::StackFrameOffset(ctx.parameters[*ir_parameter_id].stack_offset()), + Location::StackFrameOffset(ctx.storage.parameters[*ir_parameter_id].stack_offset()), ), - IrExpression::Variable(ir_variable_id) => { - let ir_variable = &ctx.variables[*ir_variable_id]; - match ir_variable.type_info() { + IrExpression::Variable(ir_variable) => { + let ir_variable_info = ctx.storage.get_variable_info(ir_variable); + match ir_variable_info.type_info() { IrTypeInfo::Int | IrTypeInfo::Double => { - let location = - to_location(ctx.variable_locations.get_variable_location(ir_variable_id)); + let location = ctx.storage.get_variable_location(ir_variable); MultiplyOperand::Location(location) } _ => panic!( "Attempt to multiply non-number (found {})", - ir_variable.type_info() + ir_variable_info.type_info() ), } } @@ -238,7 +316,7 @@ fn to_multiply_operand( fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> AddOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => { - let ir_parameter = &ctx.parameters[*ir_parameter_id]; + let ir_parameter = &ctx.storage.parameters[*ir_parameter_id]; match ir_parameter.type_info() { IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => { AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) @@ -249,15 +327,15 @@ fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContex ), } } - IrExpression::Variable(ir_variable_id) => { - let ir_variable = &ctx.variables[*ir_variable_id]; - match ir_variable.type_info() { - IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => AddOperand::Location( - to_location(ctx.variable_locations.get_variable_location(ir_variable_id)), - ), + IrExpression::Variable(ir_variable) => { + let ir_variable_info = ctx.storage.get_variable_info(ir_variable); + match ir_variable_info.type_info() { + IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => { + AddOperand::Location(ctx.storage.get_variable_location(ir_variable)) + } _ => panic!( "Attempt to add with non-integer type (found {})", - ir_variable.type_info() + ir_variable_info.type_info() ), } } @@ -276,7 +354,7 @@ fn to_subtract_operand( ) -> SubtractOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => { - let ir_parameter = &ctx.parameters[*ir_parameter_id]; + let ir_parameter = &ctx.storage.parameters[*ir_parameter_id]; match ir_parameter.type_info() { IrTypeInfo::Int | IrTypeInfo::Double => SubtractOperand::Location( Location::StackFrameOffset(ir_parameter.stack_offset()), @@ -287,15 +365,15 @@ fn to_subtract_operand( ), } } - IrExpression::Variable(ir_variable_id) => { - let ir_variable = &ctx.variables[*ir_variable_id]; - match ir_variable.type_info() { - IrTypeInfo::Int | IrTypeInfo::Double => SubtractOperand::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable_id), - )), + IrExpression::Variable(ir_variable) => { + let ir_variable_info = ctx.storage.get_variable_info(ir_variable); + match ir_variable_info.type_info() { + IrTypeInfo::Int | IrTypeInfo::Double => { + SubtractOperand::Location(ctx.storage.get_variable_location(ir_variable)) + } _ => panic!( "Attempt to subtract with non-number type (found {})", - ir_variable.type_info() + ir_variable_info.type_info() ), } } @@ -313,12 +391,12 @@ fn to_location_or_number( ) -> LocationOrNumber { match ir_expression { IrExpression::Parameter(ir_parameter_id) => { - let ir_parameter = &ctx.parameters[*ir_parameter_id]; + let ir_parameter = &ctx.storage.parameters[*ir_parameter_id]; LocationOrNumber::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } - IrExpression::Variable(ir_variable_id) => LocationOrNumber::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable_id), - )), + IrExpression::Variable(ir_variable) => { + LocationOrNumber::Location(ctx.storage.get_variable_location(ir_variable)) + } IrExpression::Int(i) => LocationOrNumber::Int(*i), IrExpression::Double(d) => LocationOrNumber::Double(*d), _ => panic!( @@ -331,11 +409,11 @@ fn to_location_or_number( fn to_push_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> PushOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => PushOperand::Location( - Location::StackFrameOffset(ctx.parameters[*ir_parameter_id].stack_offset()), + Location::StackFrameOffset(ctx.storage.parameters[*ir_parameter_id].stack_offset()), ), - IrExpression::Variable(ir_variable_id) => PushOperand::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable_id), - )), + IrExpression::Variable(ir_variable) => { + PushOperand::Location(ctx.storage.get_variable_location(ir_variable)) + } IrExpression::Int(i) => PushOperand::Int(*i), IrExpression::Double(d) => PushOperand::Double(*d), IrExpression::String(s) => { @@ -351,11 +429,11 @@ fn to_return_operand( ) -> ReturnOperand { match ir_expression { IrExpression::Parameter(ir_parameter_id) => ReturnOperand::Location( - Location::StackFrameOffset(ctx.parameters[*ir_parameter_id].stack_offset()), + Location::StackFrameOffset(ctx.storage.parameters[*ir_parameter_id].stack_offset()), ), - IrExpression::Variable(ir_variable) => ReturnOperand::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable), - )), + IrExpression::Variable(ir_variable) => { + ReturnOperand::Location(ctx.storage.get_variable_location(ir_variable)) + } IrExpression::Int(i) => ReturnOperand::Int(*i), IrExpression::Double(d) => ReturnOperand::Double(*d), IrExpression::String(s) => { @@ -371,11 +449,11 @@ fn to_location_or_integer( ) -> LocationOrInteger { match ir_expression { IrExpression::Parameter(ir_parameter_id) => LocationOrInteger::Location( - Location::StackFrameOffset(ctx.parameters[*ir_parameter_id].stack_offset()), + Location::StackFrameOffset(ctx.storage.parameters[*ir_parameter_id].stack_offset()), ), - IrExpression::Variable(ir_variable_id) => LocationOrInteger::Location(to_location( - ctx.variable_locations.get_variable_location(ir_variable_id), - )), + IrExpression::Variable(ir_variable_id) => { + LocationOrInteger::Location(ctx.storage.get_variable_location(ir_variable_id)) + } IrExpression::Int(i) => LocationOrInteger::Int(*i), _ => panic!( "Attempt to convert {} to a location or integer", @@ -383,12 +461,3 @@ fn to_location_or_integer( ), } } - -fn to_location(variable_location: VariableLocation) -> Location { - match variable_location { - VariableLocation::Register(register_assignment) => Location::Register(register_assignment), - VariableLocation::Stack(stack_frame_offset) => { - Location::StackFrameOffset(stack_frame_offset) - } - } -} diff --git a/dmc-lib/src/ir/debug_print.rs b/dmc-lib/src/ir/debug_print.rs index 8cce0b9..b165702 100644 --- a/dmc-lib/src/ir/debug_print.rs +++ b/dmc-lib/src/ir/debug_print.rs @@ -8,11 +8,21 @@ use crate::ir::ir_function::IrFunction; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; -use crate::ir::ir_variable::IrVariable; +use crate::ir::ir_variable::{IrFreeVariables, IrStackFrameVariables, IrVariable, IrVariableInfo}; use std::fmt::Formatter; struct DebugPrintContext<'a> { - ir_variables: &'a [IrVariable], + stack_frame_variables: &'a IrStackFrameVariables, + free_variables: &'a IrFreeVariables, +} + +impl DebugPrintContext<'_> { + fn get_variable_info(&self, ir_variable: &IrVariable) -> &IrVariableInfo { + match ir_variable { + IrVariable::StackFrame(id) => &self.stack_frame_variables[*id], + IrVariable::Free(id) => &self.free_variables[*id], + } + } } pub fn debug_format(ir_function: &IrFunction, f: &mut Formatter) -> std::fmt::Result { @@ -31,7 +41,8 @@ pub fn debug_format(ir_function: &IrFunction, f: &mut Formatter) -> std::fmt::Re } let ctx = DebugPrintContext { - ir_variables: ir_function.variables(), + stack_frame_variables: ir_function.stack_frame_variables(), + free_variables: ir_function.free_variables(), }; for block in ir_function.blocks() { @@ -78,7 +89,7 @@ fn debug_format_assign( f: &mut Formatter, ctx: &DebugPrintContext, ) -> std::fmt::Result { - let variable_name = ctx.ir_variables[ir_assign.destination()].name(); + let variable_name = ctx.get_variable_info(ir_assign.destination()).name(); write!(f, "{} = ", variable_name)?; debug_format_operation(ir_assign.initializer(), f, ctx)?; Ok(()) @@ -117,8 +128,8 @@ fn debug_format_expression( IrExpression::Parameter(ir_parameter) => { todo!() } - IrExpression::Variable(ir_variable_id) => { - let variable_name = ctx.ir_variables[*ir_variable_id].name(); + IrExpression::Variable(ir_variable) => { + let variable_name = ctx.get_variable_info(ir_variable).name(); write!(f, "{}", variable_name) } IrExpression::Int(i) => { diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index cf7c781..4295999 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -1,24 +1,23 @@ use crate::ir::ir_operation::IrOperation; -use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; -use std::collections::HashSet; +use crate::ir::ir_variable::IrVariable; +use crate::ir::register_allocation::{VrCollector, VrUser}; #[derive(Debug)] pub struct IrAssign { - destination: IrVariableId, + destination: IrVariable, initializer: Box, } impl IrAssign { - pub fn new(destination: IrVariableId, initializer: IrOperation) -> Self { + pub fn new(destination: IrVariable, initializer: IrOperation) -> Self { Self { destination, initializer: initializer.into(), } } - pub fn destination(&self) -> IrVariableId { - self.destination + pub fn destination(&self) -> &IrVariable { + &self.destination } pub fn initializer(&self) -> &IrOperation { @@ -27,11 +26,14 @@ impl IrAssign { } impl VrUser for IrAssign { - fn vr_definitions(&self) -> HashSet { - HashSet::from([self.destination]) + fn vr_definitions(&self, vrs: &mut VrCollector) { + match &self.destination { + IrVariable::Free(id) => vrs.push(*id), + _ => {} + } } - fn vr_uses(&self) -> HashSet { - self.initializer.vr_uses() + fn vr_uses(&self, vrs: &mut VrCollector) { + self.initializer.vr_uses(vrs); } } diff --git a/dmc-lib/src/ir/ir_binary_operation.rs b/dmc-lib/src/ir/ir_binary_operation.rs index a4b33f1..66329eb 100644 --- a/dmc-lib/src/ir/ir_binary_operation.rs +++ b/dmc-lib/src/ir/ir_binary_operation.rs @@ -1,6 +1,6 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -85,10 +85,8 @@ impl Display for IrBinaryOperation { } impl VrUser for IrBinaryOperation { - fn vr_uses(&self) -> HashSet { - [self.left.as_ref(), self.right.as_ref()] - .iter() - .flat_map(|e| e.vr_uses()) - .collect() + fn vr_uses(&self, vrs: &mut VrCollector) { + self.left.vr_uses(vrs); + self.right.vr_uses(vrs); } } diff --git a/dmc-lib/src/ir/ir_block.rs b/dmc-lib/src/ir/ir_block.rs index ddc8a1d..3f6a808 100644 --- a/dmc-lib/src/ir/ir_block.rs +++ b/dmc-lib/src/ir/ir_block.rs @@ -1,7 +1,5 @@ use crate::ir::ir_statement::IrStatement; -use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; -use std::collections::HashSet; +use crate::ir::register_allocation::{VrCollector, VrUser}; pub type IrBlockId = usize; @@ -35,15 +33,16 @@ impl IrBlock { } impl VrUser for IrBlock { - fn vr_definitions(&self) -> HashSet { - self.statements - .iter() - .flat_map(|s| s.vr_definitions()) - .collect() + fn vr_definitions(&self, vrs: &mut VrCollector) { + for statement in &self.statements { + statement.vr_definitions(vrs); + } } - fn vr_uses(&self) -> HashSet { - self.statements.iter().flat_map(|s| s.vr_uses()).collect() + fn vr_uses(&self, vrs: &mut VrCollector) { + for statement in &self.statements { + statement.vr_uses(vrs); + } } } diff --git a/dmc-lib/src/ir/ir_call.rs b/dmc-lib/src/ir/ir_call.rs index 8d3d471..924ec61 100644 --- a/dmc-lib/src/ir/ir_call.rs +++ b/dmc-lib/src/ir/ir_call.rs @@ -1,6 +1,6 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -39,11 +39,10 @@ impl IrCall { } impl VrUser for IrCall { - fn vr_uses(&self) -> HashSet { - self.arguments - .iter() - .flat_map(|ir_expression| ir_expression.vr_uses()) - .collect() + fn vr_uses(&self, vrs: &mut VrCollector) { + for argument in &self.arguments { + argument.vr_uses(vrs); + } } } diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index 858a7a2..767aafe 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -1,6 +1,6 @@ use crate::ir::ir_parameter::IrParameterId; -use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::ir_variable::{IrVariable, IrVariableId}; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -8,7 +8,7 @@ use std::rc::Rc; #[derive(Debug)] pub enum IrExpression { Parameter(IrParameterId), - Variable(IrVariableId), + Variable(IrVariable), Int(i32), Double(f64), String(Rc), @@ -20,8 +20,8 @@ impl Display for IrExpression { IrExpression::Parameter(ir_parameter) => { write!(f, "{}", ir_parameter) } - IrExpression::Variable(ir_variable_id) => { - write!(f, "{}", ir_variable_id) + IrExpression::Variable(ir_variable) => { + write!(f, "{}", ir_variable) } IrExpression::Int(i) => { write!(f, "{}", i) @@ -37,13 +37,18 @@ impl Display for IrExpression { } impl VrUser for IrExpression { - fn vr_uses(&self) -> HashSet { + fn vr_uses(&self, vrs: &mut VrCollector) { match self { - IrExpression::Parameter(_) => HashSet::new(), - IrExpression::Variable(ir_variable) => HashSet::from([*ir_variable]), - IrExpression::Int(_) => HashSet::new(), - IrExpression::Double(_) => HashSet::new(), - IrExpression::String(_) => HashSet::new(), + IrExpression::Parameter(_) => {} + IrExpression::Variable(ir_variable) => match ir_variable { + IrVariable::Free(id) => { + vrs.push(*id); + } + IrVariable::StackFrame(_) => {} + }, + IrExpression::Int(_) => {} + IrExpression::Double(_) => {} + IrExpression::String(_) => {} } } } diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index 973cc24..0206c9e 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -1,19 +1,15 @@ -use crate::constants_table::ConstantsTable; -use crate::ir::assemble::assemble_ir_function; use crate::ir::ir_block::IrBlock; use crate::ir::ir_parameter::IrParameter; -use crate::ir::ir_type_info::{IrTypeInfo, IrTypeInfoId}; -use crate::ir::ir_variable::{IrVariable, IrVariableId}; -use crate::ir::variable_locations::VariableLocations; -use dvm_lib::vm::function::Function; -use std::collections::HashMap; +use crate::ir::ir_type_info::IrTypeInfo; +use crate::ir::ir_variable::{IrFreeVariables, IrStackFrameVariables}; use std::rc::Rc; #[derive(Debug)] pub struct IrFunction { fqn: Rc, parameters: Vec, - variables: Vec, + stack_frame_variables: IrStackFrameVariables, + free_variables: IrFreeVariables, return_type_info: Option, blocks: Vec, } @@ -22,14 +18,16 @@ impl IrFunction { pub fn new( fqn: Rc, parameters: Vec, - variables: Vec, + stack_frame_variables: IrStackFrameVariables, + free_variables: IrFreeVariables, return_type_info: Option, blocks: Vec, ) -> Self { Self { fqn, parameters, - variables, + stack_frame_variables, + free_variables, return_type_info, blocks, } @@ -47,41 +45,15 @@ impl IrFunction { &self.parameters } - pub fn variables(&self) -> &[IrVariable] { - &self.variables + pub fn stack_frame_variables(&self) -> &IrStackFrameVariables { + &self.stack_frame_variables + } + + pub fn free_variables(&self) -> &IrFreeVariables { + &self.free_variables } pub fn return_type_info(&self) -> Option<&IrTypeInfo> { self.return_type_info.as_ref() } - - #[deprecated] - pub fn assign_registers(&self, register_count: usize) -> VariableLocations { - if self.blocks.is_empty() { - return VariableLocations::new(); - } - if self.blocks.len() > 1 { - unimplemented!("having more than one block in a function is not yet implemented.") - } - let block = &self.blocks[0]; - //block_assign_registers(block, register_count) - todo!() - } - - #[deprecated] - pub fn assemble( - &self, - type_infos: &Vec, - variables_to_type_infos: &HashMap, - variable_locations: &VariableLocations, - constants_table: &mut ConstantsTable, - ) -> Function { - let instructions = assemble_ir_function(self, variable_locations, constants_table); - Function::new( - self.fqn.clone(), - self.parameters.len(), - variable_locations.stack_variables_count(), - instructions, - ) - } } diff --git a/dmc-lib/src/ir/ir_get_field_ref.rs b/dmc-lib/src/ir/ir_get_field_ref.rs index b54e489..5b74dde 100644 --- a/dmc-lib/src/ir/ir_get_field_ref.rs +++ b/dmc-lib/src/ir/ir_get_field_ref.rs @@ -1,6 +1,6 @@ use crate::ir::ir_parameter_or_variable::IrParameterOrVariable; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -38,7 +38,7 @@ impl Display for IrGetFieldRef { } impl VrUser for IrGetFieldRef { - fn vr_uses(&self) -> HashSet { - self.self_variable_or_parameter.vr_uses() + fn vr_uses(&self, vrs: &mut VrCollector) { + unimplemented!() } } diff --git a/dmc-lib/src/ir/ir_get_field_ref_mut.rs b/dmc-lib/src/ir/ir_get_field_ref_mut.rs index 6ded978..974b64c 100644 --- a/dmc-lib/src/ir/ir_get_field_ref_mut.rs +++ b/dmc-lib/src/ir/ir_get_field_ref_mut.rs @@ -1,6 +1,6 @@ use crate::ir::ir_parameter_or_variable::IrParameterOrVariable; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -39,7 +39,7 @@ impl Display for IrGetFieldRefMut { } impl VrUser for IrGetFieldRefMut { - fn vr_uses(&self) -> HashSet { - self.self_variable_or_parameter.vr_uses() + fn vr_uses(&self, vrs: &mut VrCollector) { + self.self_variable_or_parameter.vr_uses(vrs) } } diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index aec6117..12db7d4 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -6,7 +6,7 @@ use crate::ir::ir_get_field_ref::IrGetFieldRef; use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut; use crate::ir::ir_read_field::IrReadField; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -50,15 +50,15 @@ impl Display for IrOperation { } impl VrUser for IrOperation { - fn vr_uses(&self) -> HashSet { + fn vr_uses(&self, vrs: &mut VrCollector) { match self { - IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(), - IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(), - IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(), - IrOperation::Load(ir_expression) => ir_expression.vr_uses(), - IrOperation::Binary(ir_binary) => ir_binary.vr_uses(), - IrOperation::Call(ir_call) => ir_call.vr_uses(), - IrOperation::Allocate(_) => HashSet::new(), + IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(vrs), + IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(vrs), + IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(vrs), + IrOperation::Load(ir_expression) => ir_expression.vr_uses(vrs), + IrOperation::Binary(ir_binary) => ir_binary.vr_uses(vrs), + IrOperation::Call(ir_call) => ir_call.vr_uses(vrs), + IrOperation::Allocate(_) => {} } } } diff --git a/dmc-lib/src/ir/ir_parameter_or_variable.rs b/dmc-lib/src/ir/ir_parameter_or_variable.rs index 4de0110..e416006 100644 --- a/dmc-lib/src/ir/ir_parameter_or_variable.rs +++ b/dmc-lib/src/ir/ir_parameter_or_variable.rs @@ -1,10 +1,10 @@ use crate::ir::ir_parameter::IrParameterId; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; -use std::collections::HashSet; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::fmt::Display; #[derive(Clone, Debug)] +#[deprecated] pub enum IrParameterOrVariable { Parameter(IrParameterId), Variable(IrVariableId), @@ -17,11 +17,7 @@ impl Display for IrParameterOrVariable { } impl VrUser for IrParameterOrVariable { - fn vr_uses(&self) -> HashSet { - if let IrParameterOrVariable::Variable(ir_variable_id) = self { - HashSet::from([*ir_variable_id]) - } else { - HashSet::new() - } + fn vr_uses(&self, _vrs: &mut VrCollector) { + unimplemented!() } } diff --git a/dmc-lib/src/ir/ir_read_field.rs b/dmc-lib/src/ir/ir_read_field.rs index 107f437..ca13d5d 100644 --- a/dmc-lib/src/ir/ir_read_field.rs +++ b/dmc-lib/src/ir/ir_read_field.rs @@ -1,5 +1,5 @@ use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -19,9 +19,7 @@ impl IrReadField { } impl VrUser for IrReadField { - fn vr_uses(&self) -> HashSet { - HashSet::from([self.field_ref_variable]) - } + fn vr_uses(&self, vrs: &mut VrCollector) {} } impl Display for IrReadField { diff --git a/dmc-lib/src/ir/ir_return.rs b/dmc-lib/src/ir/ir_return.rs index d858e85..4f6d985 100644 --- a/dmc-lib/src/ir/ir_return.rs +++ b/dmc-lib/src/ir/ir_return.rs @@ -1,6 +1,5 @@ use crate::ir::ir_expression::IrExpression; -use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -20,11 +19,9 @@ impl IrReturn { } impl VrUser for IrReturn { - fn vr_uses(&self) -> HashSet { + fn vr_uses(&self, vrs: &mut VrCollector) { if let Some(ir_expression) = self.value.as_ref() { - ir_expression.vr_uses() - } else { - HashSet::new() + ir_expression.vr_uses(vrs); } } } diff --git a/dmc-lib/src/ir/ir_set_field.rs b/dmc-lib/src/ir/ir_set_field.rs index ebc5e46..a2b7ef6 100644 --- a/dmc-lib/src/ir/ir_set_field.rs +++ b/dmc-lib/src/ir/ir_set_field.rs @@ -1,6 +1,6 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -20,11 +20,8 @@ impl IrSetField { } impl VrUser for IrSetField { - fn vr_uses(&self) -> HashSet { - let mut set = HashSet::new(); - set.insert(self.field_ref_variable); - set.extend(self.initializer.vr_uses()); - set + fn vr_uses(&self, vrs: &mut VrCollector) { + unimplemented!() } } diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index 9100512..b55913c 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -3,7 +3,7 @@ use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; use crate::ir::ir_set_field::IrSetField; use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::VrUser; +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::collections::HashSet; #[derive(Debug)] @@ -15,21 +15,21 @@ pub enum IrStatement { } impl VrUser for IrStatement { - fn vr_definitions(&self) -> HashSet { + fn vr_definitions(&self, vrs: &mut VrCollector) { match self { - IrStatement::Assign(ir_assign) => ir_assign.vr_definitions(), - IrStatement::Call(ir_call) => ir_call.vr_definitions(), - IrStatement::Return(ir_return) => ir_return.vr_definitions(), - IrStatement::SetField(ir_set_field) => ir_set_field.vr_definitions(), + IrStatement::Assign(ir_assign) => ir_assign.vr_definitions(vrs), + IrStatement::Call(ir_call) => ir_call.vr_definitions(vrs), + IrStatement::Return(ir_return) => ir_return.vr_definitions(vrs), + IrStatement::SetField(ir_set_field) => ir_set_field.vr_definitions(vrs), } } - fn vr_uses(&self) -> HashSet { + fn vr_uses(&self, vrs: &mut VrCollector) { match self { - IrStatement::Assign(ir_assign) => ir_assign.vr_uses(), - IrStatement::Call(ir_call) => ir_call.vr_uses(), - IrStatement::Return(ir_return) => ir_return.vr_uses(), - IrStatement::SetField(ir_set_field) => ir_set_field.vr_uses(), + IrStatement::Assign(ir_assign) => ir_assign.vr_uses(vrs), + IrStatement::Call(ir_call) => ir_call.vr_uses(vrs), + IrStatement::Return(ir_return) => ir_return.vr_uses(vrs), + IrStatement::SetField(ir_set_field) => ir_set_field.vr_uses(vrs), } } } diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 0ee3627..581c215 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -1,21 +1,127 @@ use crate::ir::ir_type_info::IrTypeInfo; -use std::fmt::{Display, Formatter}; +use std::fmt::Display; +use std::ops::Index; use std::rc::Rc; +#[derive(Debug)] +pub struct IrStackFrameVariables { + vs: Vec, +} + +impl IrStackFrameVariables { + pub fn new() -> Self { + Self { vs: vec![] } + } + + pub fn push(&mut self, v: IrVariableInfo) -> IrStackFrameVariableId { + self.vs.push(v); + self.vs.len() - 1 + } + + pub fn len(&self) -> usize { + self.vs.len() + } +} + +impl Index for IrStackFrameVariables { + type Output = IrVariableInfo; + + fn index(&self, index: IrStackFrameVariableId) -> &Self::Output { + &self.vs[index] + } +} + +impl Clone for IrStackFrameVariables { + fn clone(&self) -> Self { + Self { + vs: self.vs.clone(), + } + } +} + +impl Default for IrStackFrameVariables { + fn default() -> Self { + Self::new() + } +} + +pub type IrStackFrameVariableId = usize; + +#[derive(Debug)] +pub struct IrFreeVariables { + vs: Vec, +} + +impl IrFreeVariables { + pub fn new() -> Self { + Self { vs: vec![] } + } + + pub fn push(&mut self, v: IrVariableInfo) -> IrFreeVariableId { + self.vs.push(v); + self.vs.len() - 1 + } + + pub fn take_vs(&mut self) -> Vec { + std::mem::take(&mut self.vs) + } +} + +impl Clone for IrFreeVariables { + fn clone(&self) -> Self { + Self { + vs: self.vs.clone(), + } + } +} + +impl Index for IrFreeVariables { + type Output = IrVariableInfo; + + fn index(&self, index: IrFreeVariableId) -> &Self::Output { + &self.vs[index] + } +} + +impl Default for IrFreeVariables { + fn default() -> Self { + Self::new() + } +} + +pub type IrFreeVariableId = usize; + +#[deprecated] pub type IrVariableId = usize; #[derive(Clone, Debug)] -pub struct IrVariable { +pub enum IrVariable { + StackFrame(IrStackFrameVariableId), + Free(IrFreeVariableId), +} + +impl Display for IrVariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + IrVariable::StackFrame(id) => id, + IrVariable::Free(id) => id, + } + ) + } +} + +#[derive(Debug, Clone)] +pub struct IrVariableInfo { name: Rc, type_info: IrTypeInfo, } -impl IrVariable { - pub fn new(name: &str, type_info: IrTypeInfo) -> Self { - Self { - name: name.into(), - type_info, - } +impl IrVariableInfo { + pub fn new(name: Rc, type_info: IrTypeInfo) -> Self { + Self { name, type_info } } pub fn name(&self) -> &str { @@ -26,9 +132,3 @@ impl IrVariable { &self.type_info } } - -impl Display for IrVariable { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name) - } -} diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index 7775f98..1831bee 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -1,8 +1,7 @@ use crate::constants_table::ConstantsTable; -use crate::ir::assemble::assemble_ir_function; +use crate::ir::assemble::{FunctionStorageMap, assemble_ir_function}; use crate::ir::ir_function::IrFunction; use crate::ir::register_allocation::{AssignRegistersResult, assign_registers}; -use crate::ir::variable_locations::VariableLocations; use dvm_lib::vm::function::Function; mod assemble; @@ -27,13 +26,11 @@ pub mod ir_statement; pub mod ir_type_info; pub mod ir_variable; mod register_allocation; -mod util; -pub mod variable_locations; +pub mod stack_variable_offset; pub fn compile_dvm_function( ir_function: &IrFunction, register_count: usize, - variable_locations: &mut VariableLocations, constants_table: &mut ConstantsTable, ) -> Function { let AssignRegistersResult { @@ -41,16 +38,14 @@ pub fn compile_dvm_function( spilled_variables, } = assign_registers(ir_function, register_count); - variable_locations.push_all_register_variables(®ister_variables); - for spilled_variable in spilled_variables { - variable_locations.push_stack_variable(spilled_variable); - } + let function_storage_map = + FunctionStorageMap::new_from(ir_function, ®ister_variables, &spilled_variables); - let instructions = assemble_ir_function(ir_function, &variable_locations, constants_table); + let instructions = assemble_ir_function(ir_function, &function_storage_map, constants_table); Function::new( ir_function.fqn().into(), ir_function.parameters().len(), - variable_locations.stack_variables_count(), + function_storage_map.stack_size(), instructions, ) } diff --git a/dmc-lib/src/ir/register_allocation.rs b/dmc-lib/src/ir/register_allocation.rs index 68c3296..f3f270d 100644 --- a/dmc-lib/src/ir/register_allocation.rs +++ b/dmc-lib/src/ir/register_allocation.rs @@ -2,17 +2,18 @@ /// https://www.youtube.com/watch?v=eWp_-XCwN1A use crate::ir::ir_block::IrBlock; use crate::ir::ir_function::IrFunction; -use crate::ir::ir_variable::IrVariableId; +use crate::ir::ir_statement::IrStatement; +use crate::ir::ir_variable::IrFreeVariableId; use dvm_lib::instruction::Register; use std::collections::{HashMap, HashSet}; pub type RegisterAssignment = Register; -pub type InterferenceGraph = HashMap>; -pub type LivenessSets = Vec>; +pub type InterferenceGraph = HashMap>; +pub type LivenessSets = Vec>; pub struct AssignRegistersResult { - pub register_variables: HashMap, - pub spilled_variables: HashSet, + pub register_variables: HashMap, + pub spilled_variables: HashSet, } pub fn assign_registers(ir_function: &IrFunction, register_count: usize) -> AssignRegistersResult { @@ -52,9 +53,10 @@ fn block_live_in_live_out(ir_block: &IrBlock) -> (LivenessSets, LivenessSets) { } // in: use(s) U ( out(s) - def(s) ) - let use_s = ir_statement.vr_uses(); + let use_s = collect_statement_vr_uses(ir_statement); let out_s = &live_out[statement_index]; - let def_s = ir_statement.vr_definitions(); + let def_s = collect_statement_vr_uses(ir_statement); + let rhs = out_s - &def_s; let new_ins = use_s.union(&rhs).map(|v| *v).collect::>(); @@ -77,13 +79,13 @@ fn block_live_in_live_out(ir_block: &IrBlock) -> (LivenessSets, LivenessSets) { fn block_interference_graph( ir_block: &IrBlock, - spilled: &HashSet, + spilled: &HashSet, ) -> InterferenceGraph { // create a set of all variables used in the block that are not already spilled - let mut all_vr_variables: HashSet = HashSet::new(); + let mut all_vr_variables: HashSet = HashSet::new(); for statement in ir_block.statements() { - let definitions = statement.vr_definitions(); - let uses = statement.vr_uses(); + let definitions = collect_statement_vr_definitions(statement); + let uses = collect_statement_vr_uses(statement); let not_already_spilled = definitions .union(&uses) .filter(|v| !spilled.contains(*v)) @@ -101,7 +103,7 @@ fn block_interference_graph( for (statement_index, ir_statement) in ir_block.statements().iter().enumerate() { let statement_live_out = &live_out[statement_index]; - for definition_vr_variable in ir_statement.vr_definitions() { + for definition_vr_variable in collect_statement_vr_definitions(ir_statement) { // check for spill if spilled.contains(&definition_vr_variable) { continue; @@ -128,7 +130,7 @@ fn block_interference_graph( } fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> AssignRegistersResult { - let mut spilled: HashSet = HashSet::new(); + let mut spilled: HashSet = HashSet::new(); loop { let mut interference_graph = block_interference_graph(ir_block, &spilled); let (registers, new_spills) = registers_and_spills(&mut interference_graph, register_count); @@ -146,17 +148,47 @@ fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> AssignRe } pub trait VrUser { - fn vr_definitions(&self) -> HashSet { - HashSet::new() + fn vr_definitions(&self, _vrs: &mut VrCollector) {} + + fn vr_uses(&self, _vrs: &mut VrCollector); +} + +pub struct VrCollector { + vrs: HashSet, +} + +impl VrCollector { + pub fn new() -> VrCollector { + Self { + vrs: HashSet::new(), + } } - fn vr_uses(&self) -> HashSet; + pub fn push(&mut self, id: IrFreeVariableId) { + self.vrs.insert(id); + } + + pub fn take_vrs(&mut self) -> HashSet { + std::mem::take(&mut self.vrs) + } +} + +fn collect_statement_vr_definitions(statement: &IrStatement) -> HashSet { + let mut vr_collector = VrCollector::new(); + statement.vr_definitions(&mut vr_collector); + vr_collector.take_vrs() +} + +fn collect_statement_vr_uses(statement: &IrStatement) -> HashSet { + let mut vr_collector = VrCollector::new(); + statement.vr_definitions(&mut vr_collector); + vr_collector.take_vrs() } #[derive(Debug)] struct WorkItem { - vr: IrVariableId, - edges: HashSet, + vr: IrFreeVariableId, + edges: HashSet, color: bool, } @@ -164,8 +196,8 @@ fn registers_and_spills( interference_graph: &mut InterferenceGraph, k: usize, ) -> ( - HashMap, - HashSet, + HashMap, + HashSet, ) { let mut work_stack: Vec = vec![]; @@ -175,8 +207,8 @@ fn registers_and_spills( // 3. assign colors to registers let mut rebuilt_graph: InterferenceGraph = HashMap::new(); - let mut register_assignments: HashMap = HashMap::new(); - let mut spills: HashSet = HashSet::new(); + let mut register_assignments: HashMap = HashMap::new(); + let mut spills: HashSet = HashSet::new(); while let Some(work_item) = work_stack.pop() { if work_item.color { @@ -196,7 +228,7 @@ fn assign_register( work_item: &WorkItem, graph: &mut InterferenceGraph, k: usize, - register_assignments: &mut HashMap, + register_assignments: &mut HashMap, ) { rebuild_vr_and_edges(graph, work_item); @@ -215,7 +247,7 @@ fn assign_register( } } -fn find_vr_lt_k(interference_graph: &InterferenceGraph, k: usize) -> Option { +fn find_vr_lt_k(interference_graph: &InterferenceGraph, k: usize) -> Option { interference_graph.iter().find_map( |(vr, neighbors)| { if neighbors.len() < k { Some(*vr) } else { None } @@ -226,8 +258,8 @@ fn find_vr_lt_k(interference_graph: &InterferenceGraph, k: usize) -> Option HashSet { + vr: &IrFreeVariableId, +) -> HashSet { // first, outgoing let outgoing_edges = interference_graph.remove(vr).unwrap(); @@ -304,7 +336,7 @@ fn rebuild_vr_and_edges(graph: &mut InterferenceGraph, work_item: &WorkItem) { fn can_optimistically_color( work_item: &WorkItem, - register_assignments: &HashMap, + register_assignments: &HashMap, k: usize, ) -> bool { // see if we can optimistically color @@ -351,7 +383,7 @@ mod tests { graph } - fn get_vrs() -> Vec { + fn get_vrs() -> Vec { vec![0, 1, 2] } diff --git a/dmc-lib/src/ir/stack_variable_offset.rs b/dmc-lib/src/ir/stack_variable_offset.rs new file mode 100644 index 0000000..22a0bf3 --- /dev/null +++ b/dmc-lib/src/ir/stack_variable_offset.rs @@ -0,0 +1 @@ +pub type StackVariableOffset = isize; diff --git a/dmc-lib/src/ir/util.rs b/dmc-lib/src/ir/util.rs deleted file mode 100644 index 997c8a7..0000000 --- a/dmc-lib/src/ir/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::ir::ir_variable::IrVariableId; -use std::collections::HashSet; - -pub fn propagate_spills( - target_ir_variable: IrVariableId, - register_variables: &mut HashSet, - stack_variables: &mut HashSet, - new_spills: &HashSet, -) { - if new_spills.contains(&target_ir_variable) && register_variables.contains(&target_ir_variable) - { - register_variables.remove(&target_ir_variable); - stack_variables.insert(target_ir_variable); - } -} diff --git a/dmc-lib/src/ir/variable_locations.rs b/dmc-lib/src/ir/variable_locations.rs deleted file mode 100644 index c841b24..0000000 --- a/dmc-lib/src/ir/variable_locations.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::ir::ir_variable::IrVariableId; -use crate::ir::register_allocation::RegisterAssignment; -use std::collections::HashMap; - -pub type StackVariableOffset = isize; - -pub enum VariableLocation { - Register(RegisterAssignment), - Stack(StackVariableOffset), -} - -pub struct VariableLocations { - register_variables: HashMap, - stack_variables: HashMap, - next_stack_variable_offset: StackVariableOffset, -} - -impl VariableLocations { - pub fn new() -> Self { - Self { - register_variables: HashMap::new(), - stack_variables: HashMap::new(), - next_stack_variable_offset: 0, - } - } - - pub fn push_all_register_variables( - &mut self, - register_variables: &HashMap, - ) { - self.register_variables.extend(register_variables); - } - - pub fn get_variable_location(&self, id: &IrVariableId) -> VariableLocation { - match self.register_variables.get(id) { - Some(register_assignment) => VariableLocation::Register(*register_assignment), - None => VariableLocation::Stack(self.stack_variables[id]), - } - } - - pub fn register_variables_count(&self) -> usize { - self.register_variables.len() - } - - pub fn stack_variables_count(&self) -> usize { - self.stack_variables.len() - } - - pub fn extend(&mut self, other: &VariableLocations) { - // todo: add logic to transpose the `other`'s stack assignments on top of the current ones. - - self.register_variables - .extend(other.register_variables.clone()); - self.stack_variables.extend(other.stack_variables.clone()); - } - - pub fn push_stack_variable(&mut self, ir_variable_id: IrVariableId) { - self.stack_variables - .insert(ir_variable_id, self.next_stack_variable_offset); - self.next_stack_variable_offset += 1; - } -} diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index 9c501a8..ae5d1b1 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -2,8 +2,8 @@ use crate::ast::statement::Statement; use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostics; use crate::ir::compile_dvm_function; -use crate::ir::ir_variable::{IrVariable, IrVariableId}; -use crate::ir::variable_locations::VariableLocations; +use crate::ir::ir_variable::{IrStackFrameVariables, IrVariable, IrVariableInfo}; +use crate::lowering::util::to_ir_type_info; use crate::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function}; use crate::parser::parse_compilation_unit; use crate::semantic_analysis::symbol::SymbolId; @@ -63,12 +63,7 @@ pub fn compile_compilation_unit( let mut dvm_functions = HashMap::new(); for ir_function in &lower_to_ir_result.functions { - let dvm_function = compile_dvm_function( - ir_function, - register_count, - &mut VariableLocations::new(), - constants_table, - ); + let dvm_function = compile_dvm_function(ir_function, register_count, constants_table); dvm_functions.insert(dvm_function.name_owned(), dvm_function); } @@ -110,42 +105,61 @@ impl SyntheticFunctionSession { if !diagnostics.is_empty() { return Err(diagnostics); } + + // Allocate stack frame variable for let statements only + match statement { + Statement::Let(let_statement) => { + let ir_variable_info = IrVariableInfo::new( + let_statement.declared_name_owned(), + to_ir_type_info(self.ctx.get_type_info_for_node(let_statement.node_id())), + ); + let ir_stack_frame_variable_id = self + .env + .ir_stack_frame_variables_mut() + .push(ir_variable_info); + self.env.symbols_to_variables_mut().insert( + self.ctx.nodes_to_symbols()[&let_statement.node_id()], + IrVariable::StackFrame(ir_stack_frame_variable_id), + ); + } + _ => {} + } + let ir_function = lower_to_ir_synthetic_function(statement, &self); Ok(compile_dvm_function( &ir_function, register_count, - &mut VariableLocations::new(), constants_table, )) } } pub struct SyntheticEnvironment { - persisted_ir_variables: Vec, - persisted_symbols_to_variables: HashMap, + ir_stack_frame_variables: IrStackFrameVariables, + symbols_to_variables: HashMap, } impl SyntheticEnvironment { pub fn new() -> Self { Self { - persisted_ir_variables: Vec::new(), - persisted_symbols_to_variables: HashMap::new(), + ir_stack_frame_variables: IrStackFrameVariables::new(), + symbols_to_variables: HashMap::new(), } } - pub fn persisted_ir_variables(&self) -> &[IrVariable] { - &self.persisted_ir_variables + pub fn ir_stack_frame_variables(&self) -> &IrStackFrameVariables { + &self.ir_stack_frame_variables } - pub fn persisted_ir_variables_mut(&mut self) -> &mut Vec { - &mut self.persisted_ir_variables + pub fn ir_stack_frame_variables_mut(&mut self) -> &mut IrStackFrameVariables { + &mut self.ir_stack_frame_variables } - pub fn persisted_symbols_to_variables(&self) -> &HashMap { - &self.persisted_symbols_to_variables + pub fn symbols_to_variables(&self) -> &HashMap { + &self.symbols_to_variables } - pub fn persisted_symbols_to_variables_mut(&mut self) -> &mut HashMap { - &mut self.persisted_symbols_to_variables + pub fn symbols_to_variables_mut(&mut self) -> &mut HashMap { + &mut self.symbols_to_variables } } diff --git a/dmc-lib/src/lowering/mod.rs b/dmc-lib/src/lowering/mod.rs index 9362086..19dc2cf 100644 --- a/dmc-lib/src/lowering/mod.rs +++ b/dmc-lib/src/lowering/mod.rs @@ -1,4 +1,4 @@ -mod util; +pub mod util; use crate::SyntheticFunctionSession; use crate::ast::assign_statement::AssignStatement; @@ -21,7 +21,8 @@ use crate::ir::ir_parameter::{IrParameter, IrParameterId}; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_type_info::IrTypeInfo; -use crate::ir::ir_variable::{IrVariable, IrVariableId}; +use crate::ir::ir_variable::IrVariable; +use crate::ir::ir_variable::{IrFreeVariables, IrStackFrameVariables, IrVariableInfo}; use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info}; use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::symbol::{Symbol, SymbolId}; @@ -50,11 +51,14 @@ pub fn lower_to_ir_synthetic_function( statement: &Statement, session: &SyntheticFunctionSession, ) -> IrFunction { - let mut fn_ctx = LowerToIrFunctionContext::new(StorageEnvironment::with_persisted_variables( + let mut storage_env = StorageEnvironment::session_new( + session.env.ir_stack_frame_variables(), + &mut IrFreeVariables::new(), + session.env.symbols_to_variables(), 0, - session.env.persisted_ir_variables(), - session.env.persisted_symbols_to_variables(), - )); + ); + + let mut fn_ctx = LowerToIrFunctionContext::new(&mut storage_env); lower_to_ir_statement(statement, &session.ctx, &mut fn_ctx, true); fn_ctx.finish_block(); @@ -70,25 +74,27 @@ pub fn lower_to_ir_synthetic_function( } }; + let blocks = std::mem::take(&mut fn_ctx.blocks); IrFunction::new( session.fqn.clone(), - fn_ctx.storage_env_mut().take_parameters(), - fn_ctx.storage_env_mut().take_variables(), + storage_env.take_parameters(), + storage_env.ir_stack_frame_variables, + storage_env.ir_free_variables, maybe_return_ir_type_info, - fn_ctx.blocks, + blocks, ) } -struct LowerToIrFunctionContext { - storage_env: Box, +struct LowerToIrFunctionContext<'a> { + storage_env: &'a mut StorageEnvironment, blocks: Vec, current_block_statements: Vec, } -impl LowerToIrFunctionContext { - fn new(storage_env: StorageEnvironment) -> Self { +impl<'a> LowerToIrFunctionContext<'a> { + fn new(storage_env: &'a mut StorageEnvironment) -> Self { Self { - storage_env: storage_env.into(), + storage_env, blocks: Vec::new(), current_block_statements: Vec::new(), } @@ -109,17 +115,18 @@ impl LowerToIrFunctionContext { } fn storage_env(&self) -> &StorageEnvironment { - &*self.storage_env + self.storage_env } fn storage_env_mut(&mut self) -> &mut StorageEnvironment { - &mut *self.storage_env + self.storage_env } } struct StorageEnvironment { - ir_variables: Vec, - symbols_to_variables: HashMap, + ir_stack_frame_variables: IrStackFrameVariables, + ir_free_variables: IrFreeVariables, + symbols_to_variables: HashMap, current_parameter_stack_offset: isize, ir_parameters: Vec, symbols_to_parameters: HashMap, @@ -129,7 +136,8 @@ struct StorageEnvironment { impl StorageEnvironment { fn new(parameter_count: usize) -> Self { Self { - ir_variables: Vec::new(), + ir_stack_frame_variables: IrStackFrameVariables::new(), + ir_free_variables: IrFreeVariables::new(), symbols_to_variables: HashMap::new(), current_parameter_stack_offset: (parameter_count as isize).neg(), ir_parameters: Vec::new(), @@ -138,15 +146,17 @@ impl StorageEnvironment { } } - #[deprecated] - fn with_persisted_variables( + fn session_new( + ir_stack_frame_variables: &IrStackFrameVariables, + ir_free_variables: &IrFreeVariables, + session_symbols_to_variables: &HashMap, parameter_count: usize, - persisted_ir_variables: &[IrVariable], - persisted_symbols_to_variables: &HashMap, ) -> Self { let mut this = Self::new(parameter_count); - this.ir_variables = persisted_ir_variables.to_vec(); - this.symbols_to_variables = persisted_symbols_to_variables.clone(); + this.ir_stack_frame_variables = ir_stack_frame_variables.clone(); + this.ir_free_variables = ir_free_variables.clone(); + this.symbols_to_variables + .extend(session_symbols_to_variables.clone()); // hopefully not costly this } @@ -180,55 +190,57 @@ impl StorageEnvironment { ir_parameter_id } - fn new_variable(&mut self, name: &str, ir_type_info: IrTypeInfo) -> IrVariableId { - let ir_variable = IrVariable::new(name, ir_type_info); - self.ir_variables.push(ir_variable); - self.ir_variables.len() - 1 + fn new_free_variable(&mut self, name: &str, ir_type_info: IrTypeInfo) -> IrVariable { + let ir_variable_info = IrVariableInfo::new(name.into(), ir_type_info); + let ir_free_variable_id = self.ir_free_variables.push(ir_variable_info); + IrVariable::Free(ir_free_variable_id) } - fn new_variable_for( + fn new_free_variable_for( &mut self, name: &str, ir_type_info: IrTypeInfo, symbol_id: SymbolId, - ) -> IrVariableId { - let ir_variable_id = self.new_variable(name, ir_type_info); - self.symbols_to_variables.insert(symbol_id, ir_variable_id); - ir_variable_id + ) -> IrVariable { + let ir_variable = self.new_free_variable(name, ir_type_info); + self.symbols_to_variables + .insert(symbol_id, ir_variable.clone()); + ir_variable } - fn new_t_var(&mut self, ir_type_info: IrTypeInfo) -> IrVariableId { + fn new_t_var(&mut self, ir_type_info: IrTypeInfo) -> IrVariable { let t_var_number = self.next_t_var_number(); - self.new_variable(&format!("t_{}", t_var_number), ir_type_info) + self.new_free_variable(&format!("t_{}", t_var_number), ir_type_info) } - fn get_variable_for(&self, symbol_id: SymbolId) -> IrVariableId { + fn get_variable_for(&self, symbol_id: SymbolId) -> &IrVariable { self.symbols_to_variables .get(&symbol_id) - .cloned() .expect(&format!("No ir_variable for symbol_id {}", symbol_id)) } - fn maybe_get_variable_for(&self, symbol_id: SymbolId) -> Option { - self.symbols_to_variables.get(&symbol_id).cloned() + fn maybe_get_variable_for(&self, symbol_id: SymbolId) -> Option<&IrVariable> { + self.symbols_to_variables.get(&symbol_id) } fn maybe_get_parameter_for(&self, symbol_id: SymbolId) -> Option { self.symbols_to_parameters.get(&symbol_id).cloned() } - fn take_variables(&mut self) -> Vec { - std::mem::take(&mut self.ir_variables) - } - fn take_parameters(&mut self) -> Vec { std::mem::take(&mut self.ir_parameters) } } fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunction { - let mut fn_ctx = - LowerToIrFunctionContext::new(StorageEnvironment::new(function.parameters().len())); + let mut storage_env = StorageEnvironment::session_new( + &IrStackFrameVariables::new(), + &mut IrFreeVariables::new(), + &mut HashMap::new(), + function.parameters().len(), + ); + + let mut fn_ctx = LowerToIrFunctionContext::new(&mut storage_env); lower_to_ir_parameters(function, ctx, &mut fn_ctx); @@ -257,12 +269,14 @@ fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunctio } fn_ctx.finish_block(); + let blocks = std::mem::take(&mut fn_ctx.blocks); IrFunction::new( function_symbol.fqn_owned(), - fn_ctx.storage_env_mut().take_parameters(), - fn_ctx.storage_env_mut().take_variables(), + storage_env.take_parameters(), + storage_env.ir_stack_frame_variables.clone(), + storage_env.ir_free_variables.clone(), return_type_info_to_ir_type_info(return_type_info), - std::mem::take(&mut fn_ctx.blocks), + blocks, ) } @@ -326,16 +340,24 @@ fn lower_to_ir_let_statement( let type_info_id = ctx.nodes_to_type_infos()[&let_statement.node_id()]; let type_info = &ctx.type_infos()[type_info_id]; - let destination_ir_variable_id = fn_ctx.storage_env_mut().new_variable_for( - let_statement.declared_name(), - to_ir_type_info(type_info), - symbol_id, - ); + // We first fetch from the storage environment because we may have already allocated storage + // for this variable (such as when we are top-level in a synthetic function). + let destination_ir_variable = fn_ctx + .storage_env() + .maybe_get_variable_for(symbol_id) + .cloned() + .unwrap_or_else(|| { + fn_ctx.storage_env_mut().new_free_variable_for( + let_statement.declared_name(), + to_ir_type_info(type_info), + symbol_id, + ) + }); let initializer_ir_operation = lower_expression_to_ir_operation(let_statement.initializer(), ctx, fn_ctx); - let ir_assign = IrAssign::new(destination_ir_variable_id, initializer_ir_operation); + let ir_assign = IrAssign::new(destination_ir_variable, initializer_ir_operation); let ir_statement = IrStatement::Assign(ir_assign); fn_ctx.current_block_statements.push(ir_statement); } @@ -377,12 +399,14 @@ fn lower_to_ir_assign_statement( match assign_statement.destination() { Expression::Identifier(identifier) => { let destination_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; - let destination_ir_variable_id = - fn_ctx.storage_env().get_variable_for(destination_symbol_id); + let destination_ir_variable = fn_ctx + .storage_env() + .get_variable_for(destination_symbol_id) + .clone(); let ir_operation = lower_expression_to_ir_operation(assign_statement.value(), ctx, fn_ctx); - let ir_assign = IrAssign::new(destination_ir_variable_id, ir_operation); + let ir_assign = IrAssign::new(destination_ir_variable, ir_operation); let ir_statement = IrStatement::Assign(ir_assign); fn_ctx.current_block_statements.push(ir_statement); } @@ -417,9 +441,9 @@ fn lower_expression_to_ir_operation( Expression::Call(call) => IrOperation::Call(lower_to_ir_call(call, ctx, fn_ctx)), Expression::Identifier(identifier) => { let identifier_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; - let identifier_ir_variable_id = + let identifier_ir_variable = fn_ctx.storage_env().get_variable_for(identifier_symbol_id); - let ir_expression = IrExpression::Variable(identifier_ir_variable_id); + let ir_expression = IrExpression::Variable(identifier_ir_variable.clone()); IrOperation::Load(ir_expression) } Expression::Integer(integer_literal) => { @@ -453,18 +477,18 @@ fn lower_expression_to_ir_expression( // make destination temp var let result_type_info_id = ctx.nodes_to_type_infos()[&binary_expression.node_id()]; let result_type_info = &ctx.type_infos()[result_type_info_id]; - let destination_ir_variable_id = fn_ctx + let destination_ir_variable = fn_ctx .storage_env_mut() .new_t_var(to_ir_type_info(result_type_info)); // make assign statement to destination temp var - let ir_assign = IrAssign::new(destination_ir_variable_id, ir_operation); + let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation); fn_ctx .current_block_statements .push(IrStatement::Assign(ir_assign)); // return location of temp var - IrExpression::Variable(destination_ir_variable_id) + IrExpression::Variable(destination_ir_variable) } Expression::Negative(negative_expression) => { let operand = @@ -477,17 +501,17 @@ fn lower_expression_to_ir_expression( )); let result_type_info_id = ctx.nodes_to_type_infos()[&negative_expression.node_id()]; let result_type_info = &ctx.type_infos()[result_type_info_id]; - let destination_ir_variable_id = fn_ctx + let destination_ir_variable = fn_ctx .storage_env_mut() .new_t_var(to_ir_type_info(result_type_info)); - let ir_assign = IrAssign::new(destination_ir_variable_id, ir_operation); + let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation); // push the statement which does the multiply by negative one fn_ctx .current_block_statements .push(IrStatement::Assign(ir_assign)); - IrExpression::Variable(destination_ir_variable_id) + IrExpression::Variable(destination_ir_variable) } Expression::Call(call) => { let ir_call = lower_to_ir_call(call, ctx, fn_ctx); @@ -495,26 +519,26 @@ fn lower_expression_to_ir_expression( // make temp var let return_type_info_id = ctx.nodes_to_type_infos()[&call.node_id()]; let return_type_info = &ctx.type_infos()[return_type_info_id]; - let t_var_ir_variable_id = fn_ctx + let t_var_ir_variable = fn_ctx .storage_env_mut() .new_t_var(to_ir_type_info(return_type_info)); // assign call to temp var, return temp var expression let ir_operation = IrOperation::Call(ir_call); - let ir_assign = IrAssign::new(t_var_ir_variable_id, ir_operation); + let ir_assign = IrAssign::new(t_var_ir_variable.clone(), ir_operation); fn_ctx .current_block_statements .push(IrStatement::Assign(ir_assign)); // return an expression referencing the temp var - IrExpression::Variable(t_var_ir_variable_id) + IrExpression::Variable(t_var_ir_variable) } Expression::Identifier(identifier) => { let rhs_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; - if let Some(rhs_ir_variable_id) = + if let Some(rhs_ir_variable) = fn_ctx.storage_env().maybe_get_variable_for(rhs_symbol_id) { - IrExpression::Variable(rhs_ir_variable_id) + IrExpression::Variable(rhs_ir_variable.clone()) } else if let Some(rhs_ir_parameter_id) = fn_ctx.storage_env().maybe_get_parameter_for(rhs_symbol_id) {