Compare commits

...

3 Commits

Author SHA1 Message Date
Jesse Brault
1e9a0ec993 Repl let statements working! 2026-08-08 12:13:11 -05:00
Jesse Brault
5edf8964dc StorageEnvironment abstraction in lowering module. 2026-08-07 20:32:28 -05:00
Jesse Brault
6b51545114 More progress on getting repl let statements to work. 2026-08-06 15:17:15 -05:00
30 changed files with 791 additions and 572 deletions

View File

@ -1,12 +1,10 @@
use dmc_lib::SyntheticFunctionSession;
use dmc_lib::ast::expression_statement::ExpressionStatement; use dmc_lib::ast::expression_statement::ExpressionStatement;
use dmc_lib::ast::statement::Statement; use dmc_lib::ast::statement::Statement;
use dmc_lib::compile_statement_to_synthetic_function;
use dmc_lib::constants_table::ConstantsTable; use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostics; use dmc_lib::diagnostic::Diagnostics;
use dmc_lib::ir::variable_locations::VariableLocations;
use dmc_lib::lexer::Lexer; use dmc_lib::lexer::Lexer;
use dmc_lib::parser::{parse_expression, parse_let_statement}; use dmc_lib::parser::{parse_expression, parse_let_statement};
use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
use dmc_lib::token::TokenKind; use dmc_lib::token::TokenKind;
use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function; use dvm_lib::vm::function::Function;
@ -14,7 +12,6 @@ use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop}; use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop};
use std::io; use std::io;
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
use std::rc::Rc;
// //
// pub fn repl(read: &mut impl BufRead, register_count: usize) { // pub fn repl(read: &mut impl BufRead, register_count: usize) {
// let mut buffer = String::new(); // let mut buffer = String::new();
@ -301,14 +298,12 @@ use std::rc::Rc;
pub fn repl_2(read: &mut impl BufRead, register_count: usize) { pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
let mut buffer = String::new(); let mut buffer = String::new();
let mut analysis_context = AnalysisContext::new(); let mut session = SyntheticFunctionSession::new("__repl");
let analysis_context = session.ctx_mut();
analysis_context.push_scope("__repl_root_scope"); analysis_context.push_scope("__repl_root_scope");
analysis_context.push_scope("__repl_function_scope"); analysis_context.push_scope("__repl_function_scope");
analysis_context.push_scope("__repl_body_scope"); analysis_context.push_scope("__repl_body_scope");
let fqn: Rc<str> = Rc::from("__repl");
let mut variable_locations = VariableLocations::new();
let mut constants_table = ConstantsTable::new(); let mut constants_table = ConstantsTable::new();
let mut dvm_context = DvmContext::new(); let mut dvm_context = DvmContext::new();
@ -343,9 +338,7 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
TokenKind::Let => { TokenKind::Let => {
let compile_result = compile_let_statement_2( let compile_result = compile_let_statement_2(
input, input,
&mut analysis_context, &mut session,
&fqn,
&mut variable_locations,
register_count, register_count,
&mut constants_table, &mut constants_table,
); );
@ -365,14 +358,8 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
} }
} }
_ => { _ => {
let compile_result = compile_expression_2( let compile_result =
input, compile_expression_2(input, &mut session, register_count, &mut constants_table);
&mut analysis_context,
&fqn,
&mut variable_locations,
register_count,
&mut constants_table,
);
match compile_result { match compile_result {
Ok(function) => { Ok(function) => {
dvm_context dvm_context
@ -426,9 +413,7 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
fn compile_expression_2( fn compile_expression_2(
input: &str, input: &str,
analysis_context: &mut AnalysisContext, session: &mut SyntheticFunctionSession,
fqn: &Rc<str>,
variable_locations: &mut VariableLocations,
register_count: usize, register_count: usize,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> { ) -> Result<Function, Diagnostics> {
@ -439,21 +424,12 @@ fn compile_expression_2(
let statement = Statement::Expression(ExpressionStatement::new(0, expression)); let statement = Statement::Expression(ExpressionStatement::new(0, expression));
compile_statement_to_synthetic_function( session.compile_statement(&statement, register_count, constants_table)
&statement,
analysis_context,
fqn.clone(),
variable_locations,
register_count,
constants_table,
)
} }
fn compile_let_statement_2( fn compile_let_statement_2(
input: &str, input: &str,
analysis_context: &mut AnalysisContext, session: &mut SyntheticFunctionSession,
fqn: &Rc<str>,
variable_locations: &mut VariableLocations,
register_count: usize, register_count: usize,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> { ) -> Result<Function, Diagnostics> {
@ -461,12 +437,6 @@ fn compile_let_statement_2(
if !parse_diagnostics.is_empty() { if !parse_diagnostics.is_empty() {
return Err(parse_diagnostics); return Err(parse_diagnostics);
} }
compile_statement_to_synthetic_function( let statement = Statement::Let(maybe_let_statement.unwrap());
&Statement::Let(maybe_let_statement.unwrap()), session.compile_statement(&statement, register_count, constants_table)
analysis_context,
fqn.clone(),
variable_locations,
register_count,
constants_table,
)
} }

View File

@ -603,7 +603,7 @@ impl BinaryExpression {
types_table: &TypesTable, types_table: &TypesTable,
) -> IrExpression { ) -> IrExpression {
let ir_operation = self.to_ir_operation(builder, symbol_table, types_table); 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 as_rc = Rc::new(RefCell::new(t_var));
let ir_assign = IrAssign::new(todo!(), ir_operation); let ir_assign = IrAssign::new(todo!(), ir_operation);
builder builder

View File

@ -489,6 +489,7 @@ impl Function {
todo!(), todo!(),
todo!(), todo!(),
todo!(), todo!(),
todo!(),
) )
} }
@ -546,6 +547,7 @@ impl Function {
todo!(), todo!(),
todo!(), todo!(),
todo!(), todo!(),
todo!(),
) )
} }
} }

View File

@ -10,32 +10,114 @@ use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_return::IrReturn; use crate::ir::ir_return::IrReturn;
use crate::ir::ir_statement::IrStatement; use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_type_info::IrTypeInfo; use crate::ir::ir_type_info::IrTypeInfo;
use crate::ir::ir_variable::IrVariable; use crate::ir::ir_variable::{
use crate::ir::variable_locations::{VariableLocation, VariableLocations}; IrFreeVariableId, IrFreeVariables, IrStackFrameVariableId, IrStackFrameVariables, IrVariable,
IrVariableInfo,
};
use crate::ir::register_allocation::RegisterAssignment;
use crate::ir::stack_variable_offset::StackVariableOffset;
use dvm_lib::instruction::{ use dvm_lib::instruction::{
AddOperand, Instruction, Location, LocationOrInteger, LocationOrNumber, MoveOperand, AddOperand, Instruction, Location, LocationOrInteger, LocationOrNumber, MoveOperand,
MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand, MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand,
}; };
use std::collections::{HashMap, HashSet};
struct FunctionAssemblyContext<'a> { struct FunctionAssemblyContext<'a> {
variable_locations: &'a VariableLocations,
parameters: &'a [IrParameter],
variables: &'a [IrVariable],
constants_table: &'a mut ConstantsTable, constants_table: &'a mut ConstantsTable,
storage: &'a FunctionStorageMap<'a>,
instructions: Vec<Instruction>, instructions: Vec<Instruction>,
} }
pub struct FunctionStorageMap<'a> {
parameters: &'a [IrParameter],
stack_frame_variables: &'a IrStackFrameVariables,
free_variables: &'a IrFreeVariables,
stack_frame_variable_assignments: HashMap<IrStackFrameVariableId, StackVariableOffset>,
register_assignments: &'a HashMap<IrFreeVariableId, RegisterAssignment>,
spilled_assignments: HashMap<IrFreeVariableId, StackVariableOffset>,
}
fn calculate_stack_frame_variable_offsets(
stack_frame_variables: &IrStackFrameVariables,
) -> HashMap<IrStackFrameVariableId, StackVariableOffset> {
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<IrFreeVariableId>,
base_offset: StackVariableOffset,
) -> HashMap<IrFreeVariableId, StackVariableOffset> {
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<IrFreeVariableId, RegisterAssignment>,
spilled_variables: &HashSet<IrFreeVariableId>,
) -> 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( pub fn assemble_ir_function(
ir_function: &IrFunction, ir_function: &IrFunction,
variable_locations: &VariableLocations, storage: &FunctionStorageMap,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Vec<Instruction> { ) -> Vec<Instruction> {
let mut ctx = FunctionAssemblyContext { let mut ctx = FunctionAssemblyContext {
variable_locations,
constants_table,
parameters: ir_function.parameters(),
variables: ir_function.variables(),
instructions: Vec::new(), instructions: Vec::new(),
storage,
constants_table,
}; };
for block in ir_function.blocks() { for block in ir_function.blocks() {
assemble_ir_block(block, &mut ctx); 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) { fn assemble_ir_assign(ir_assign: &IrAssign, ctx: &mut FunctionAssemblyContext) {
let destination_location = to_location( let destination_location = ctx.storage.get_variable_location(ir_assign.destination());
ctx.variable_locations
.get_variable_location(&ir_assign.destination()),
);
match ir_assign.initializer() { match ir_assign.initializer() {
IrOperation::GetFieldRef(_) => { IrOperation::GetFieldRef(_) => {
todo!() 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 { fn to_move_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> MoveOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => MoveOperand::Location( 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( IrExpression::Variable(ir_variable_id) => {
ctx.variable_locations.get_variable_location(ir_variable_id), MoveOperand::Location(ctx.storage.get_variable_location(ir_variable_id))
)), }
IrExpression::Int(i) => MoveOperand::Int(*i), IrExpression::Int(i) => MoveOperand::Int(*i),
IrExpression::Double(d) => MoveOperand::Double(*d), IrExpression::Double(d) => MoveOperand::Double(*d),
IrExpression::String(s) => { IrExpression::String(s) => {
@ -211,19 +290,18 @@ fn to_multiply_operand(
) -> MultiplyOperand { ) -> MultiplyOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => MultiplyOperand::Location( 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) => { IrExpression::Variable(ir_variable) => {
let ir_variable = &ctx.variables[*ir_variable_id]; let ir_variable_info = ctx.storage.get_variable_info(ir_variable);
match ir_variable.type_info() { match ir_variable_info.type_info() {
IrTypeInfo::Int | IrTypeInfo::Double => { IrTypeInfo::Int | IrTypeInfo::Double => {
let location = let location = ctx.storage.get_variable_location(ir_variable);
to_location(ctx.variable_locations.get_variable_location(ir_variable_id));
MultiplyOperand::Location(location) MultiplyOperand::Location(location)
} }
_ => panic!( _ => panic!(
"Attempt to multiply non-number (found {})", "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 { fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> AddOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => { 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() { match ir_parameter.type_info() {
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => { IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => {
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) 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) => { IrExpression::Variable(ir_variable) => {
let ir_variable = &ctx.variables[*ir_variable_id]; let ir_variable_info = ctx.storage.get_variable_info(ir_variable);
match ir_variable.type_info() { match ir_variable_info.type_info() {
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => AddOperand::Location( IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => {
to_location(ctx.variable_locations.get_variable_location(ir_variable_id)), AddOperand::Location(ctx.storage.get_variable_location(ir_variable))
), }
_ => panic!( _ => panic!(
"Attempt to add with non-integer type (found {})", "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 { ) -> SubtractOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => { 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() { match ir_parameter.type_info() {
IrTypeInfo::Int | IrTypeInfo::Double => SubtractOperand::Location( IrTypeInfo::Int | IrTypeInfo::Double => SubtractOperand::Location(
Location::StackFrameOffset(ir_parameter.stack_offset()), Location::StackFrameOffset(ir_parameter.stack_offset()),
@ -287,15 +365,15 @@ fn to_subtract_operand(
), ),
} }
} }
IrExpression::Variable(ir_variable_id) => { IrExpression::Variable(ir_variable) => {
let ir_variable = &ctx.variables[*ir_variable_id]; let ir_variable_info = ctx.storage.get_variable_info(ir_variable);
match ir_variable.type_info() { match ir_variable_info.type_info() {
IrTypeInfo::Int | IrTypeInfo::Double => SubtractOperand::Location(to_location( IrTypeInfo::Int | IrTypeInfo::Double => {
ctx.variable_locations.get_variable_location(ir_variable_id), SubtractOperand::Location(ctx.storage.get_variable_location(ir_variable))
)), }
_ => panic!( _ => panic!(
"Attempt to subtract with non-number type (found {})", "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 { ) -> LocationOrNumber {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => { 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())) LocationOrNumber::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
} }
IrExpression::Variable(ir_variable_id) => LocationOrNumber::Location(to_location( IrExpression::Variable(ir_variable) => {
ctx.variable_locations.get_variable_location(ir_variable_id), LocationOrNumber::Location(ctx.storage.get_variable_location(ir_variable))
)), }
IrExpression::Int(i) => LocationOrNumber::Int(*i), IrExpression::Int(i) => LocationOrNumber::Int(*i),
IrExpression::Double(d) => LocationOrNumber::Double(*d), IrExpression::Double(d) => LocationOrNumber::Double(*d),
_ => panic!( _ => panic!(
@ -331,11 +409,11 @@ fn to_location_or_number(
fn to_push_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> PushOperand { fn to_push_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContext) -> PushOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => PushOperand::Location( 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( IrExpression::Variable(ir_variable) => {
ctx.variable_locations.get_variable_location(ir_variable_id), PushOperand::Location(ctx.storage.get_variable_location(ir_variable))
)), }
IrExpression::Int(i) => PushOperand::Int(*i), IrExpression::Int(i) => PushOperand::Int(*i),
IrExpression::Double(d) => PushOperand::Double(*d), IrExpression::Double(d) => PushOperand::Double(*d),
IrExpression::String(s) => { IrExpression::String(s) => {
@ -351,11 +429,11 @@ fn to_return_operand(
) -> ReturnOperand { ) -> ReturnOperand {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => ReturnOperand::Location( 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( IrExpression::Variable(ir_variable) => {
ctx.variable_locations.get_variable_location(ir_variable), ReturnOperand::Location(ctx.storage.get_variable_location(ir_variable))
)), }
IrExpression::Int(i) => ReturnOperand::Int(*i), IrExpression::Int(i) => ReturnOperand::Int(*i),
IrExpression::Double(d) => ReturnOperand::Double(*d), IrExpression::Double(d) => ReturnOperand::Double(*d),
IrExpression::String(s) => { IrExpression::String(s) => {
@ -371,11 +449,11 @@ fn to_location_or_integer(
) -> LocationOrInteger { ) -> LocationOrInteger {
match ir_expression { match ir_expression {
IrExpression::Parameter(ir_parameter_id) => LocationOrInteger::Location( 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( IrExpression::Variable(ir_variable_id) => {
ctx.variable_locations.get_variable_location(ir_variable_id), LocationOrInteger::Location(ctx.storage.get_variable_location(ir_variable_id))
)), }
IrExpression::Int(i) => LocationOrInteger::Int(*i), IrExpression::Int(i) => LocationOrInteger::Int(*i),
_ => panic!( _ => panic!(
"Attempt to convert {} to a location or integer", "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)
}
}
}

View File

@ -8,11 +8,21 @@ use crate::ir::ir_function::IrFunction;
use crate::ir::ir_operation::IrOperation; use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_return::IrReturn; use crate::ir::ir_return::IrReturn;
use crate::ir::ir_statement::IrStatement; 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; use std::fmt::Formatter;
struct DebugPrintContext<'a> { 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 { 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 { 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() { for block in ir_function.blocks() {
@ -78,7 +89,7 @@ fn debug_format_assign(
f: &mut Formatter, f: &mut Formatter,
ctx: &DebugPrintContext, ctx: &DebugPrintContext,
) -> std::fmt::Result { ) -> 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)?; write!(f, "{} = ", variable_name)?;
debug_format_operation(ir_assign.initializer(), f, ctx)?; debug_format_operation(ir_assign.initializer(), f, ctx)?;
Ok(()) Ok(())
@ -117,8 +128,8 @@ fn debug_format_expression(
IrExpression::Parameter(ir_parameter) => { IrExpression::Parameter(ir_parameter) => {
todo!() todo!()
} }
IrExpression::Variable(ir_variable_id) => { IrExpression::Variable(ir_variable) => {
let variable_name = ctx.ir_variables[*ir_variable_id].name(); let variable_name = ctx.get_variable_info(ir_variable).name();
write!(f, "{}", variable_name) write!(f, "{}", variable_name)
} }
IrExpression::Int(i) => { IrExpression::Int(i) => {

View File

@ -1,24 +1,23 @@
use crate::ir::ir_operation::IrOperation; use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_variable::IrVariableId; use crate::ir::ir_variable::IrVariable;
use crate::ir::register_allocation::VrUser; use crate::ir::register_allocation::{VrCollector, VrUser};
use std::collections::HashSet;
#[derive(Debug)] #[derive(Debug)]
pub struct IrAssign { pub struct IrAssign {
destination: IrVariableId, destination: IrVariable,
initializer: Box<IrOperation>, initializer: Box<IrOperation>,
} }
impl IrAssign { impl IrAssign {
pub fn new(destination: IrVariableId, initializer: IrOperation) -> Self { pub fn new(destination: IrVariable, initializer: IrOperation) -> Self {
Self { Self {
destination, destination,
initializer: initializer.into(), initializer: initializer.into(),
} }
} }
pub fn destination(&self) -> IrVariableId { pub fn destination(&self) -> &IrVariable {
self.destination &self.destination
} }
pub fn initializer(&self) -> &IrOperation { pub fn initializer(&self) -> &IrOperation {
@ -27,11 +26,14 @@ impl IrAssign {
} }
impl VrUser for IrAssign { impl VrUser for IrAssign {
fn vr_definitions(&self) -> HashSet<IrVariableId> { fn vr_definitions(&self, vrs: &mut VrCollector) {
HashSet::from([self.destination]) match &self.destination {
IrVariable::Free(id) => vrs.push(*id),
_ => {}
}
} }
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
self.initializer.vr_uses() self.initializer.vr_uses(vrs);
} }
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -85,10 +85,8 @@ impl Display for IrBinaryOperation {
} }
impl VrUser for IrBinaryOperation { impl VrUser for IrBinaryOperation {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
[self.left.as_ref(), self.right.as_ref()] self.left.vr_uses(vrs);
.iter() self.right.vr_uses(vrs);
.flat_map(|e| e.vr_uses())
.collect()
} }
} }

View File

@ -1,7 +1,5 @@
use crate::ir::ir_statement::IrStatement; use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariableId; use crate::ir::register_allocation::{VrCollector, VrUser};
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
pub type IrBlockId = usize; pub type IrBlockId = usize;
@ -35,15 +33,16 @@ impl IrBlock {
} }
impl VrUser for IrBlock { impl VrUser for IrBlock {
fn vr_definitions(&self) -> HashSet<IrVariableId> { fn vr_definitions(&self, vrs: &mut VrCollector) {
self.statements for statement in &self.statements {
.iter() statement.vr_definitions(vrs);
.flat_map(|s| s.vr_definitions()) }
.collect()
} }
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
self.statements.iter().flat_map(|s| s.vr_uses()).collect() for statement in &self.statements {
statement.vr_uses(vrs);
}
} }
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;
@ -39,11 +39,10 @@ impl IrCall {
} }
impl VrUser for IrCall { impl VrUser for IrCall {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
self.arguments for argument in &self.arguments {
.iter() argument.vr_uses(vrs);
.flat_map(|ir_expression| ir_expression.vr_uses()) }
.collect()
} }
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_parameter::IrParameterId; use crate::ir::ir_parameter::IrParameterId;
use crate::ir::ir_variable::IrVariableId; use crate::ir::ir_variable::{IrVariable, IrVariableId};
use crate::ir::register_allocation::VrUser; use crate::ir::register_allocation::{VrCollector, VrUser};
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;
@ -8,7 +8,7 @@ use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub enum IrExpression { pub enum IrExpression {
Parameter(IrParameterId), Parameter(IrParameterId),
Variable(IrVariableId), Variable(IrVariable),
Int(i32), Int(i32),
Double(f64), Double(f64),
String(Rc<str>), String(Rc<str>),
@ -20,8 +20,8 @@ impl Display for IrExpression {
IrExpression::Parameter(ir_parameter) => { IrExpression::Parameter(ir_parameter) => {
write!(f, "{}", ir_parameter) write!(f, "{}", ir_parameter)
} }
IrExpression::Variable(ir_variable_id) => { IrExpression::Variable(ir_variable) => {
write!(f, "{}", ir_variable_id) write!(f, "{}", ir_variable)
} }
IrExpression::Int(i) => { IrExpression::Int(i) => {
write!(f, "{}", i) write!(f, "{}", i)
@ -37,13 +37,18 @@ impl Display for IrExpression {
} }
impl VrUser for IrExpression { impl VrUser for IrExpression {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
match self { match self {
IrExpression::Parameter(_) => HashSet::new(), IrExpression::Parameter(_) => {}
IrExpression::Variable(ir_variable) => HashSet::from([*ir_variable]), IrExpression::Variable(ir_variable) => match ir_variable {
IrExpression::Int(_) => HashSet::new(), IrVariable::Free(id) => {
IrExpression::Double(_) => HashSet::new(), vrs.push(*id);
IrExpression::String(_) => HashSet::new(), }
IrVariable::StackFrame(_) => {}
},
IrExpression::Int(_) => {}
IrExpression::Double(_) => {}
IrExpression::String(_) => {}
} }
} }
} }

View File

@ -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_block::IrBlock;
use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_type_info::{IrTypeInfo, IrTypeInfoId}; use crate::ir::ir_type_info::IrTypeInfo;
use crate::ir::ir_variable::{IrVariable, IrVariableId}; use crate::ir::ir_variable::{IrFreeVariables, IrStackFrameVariables};
use crate::ir::variable_locations::VariableLocations;
use dvm_lib::vm::function::Function;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct IrFunction { pub struct IrFunction {
fqn: Rc<str>, fqn: Rc<str>,
parameters: Vec<IrParameter>, parameters: Vec<IrParameter>,
variables: Vec<IrVariable>, stack_frame_variables: IrStackFrameVariables,
free_variables: IrFreeVariables,
return_type_info: Option<IrTypeInfo>, return_type_info: Option<IrTypeInfo>,
blocks: Vec<IrBlock>, blocks: Vec<IrBlock>,
} }
@ -22,14 +18,16 @@ impl IrFunction {
pub fn new( pub fn new(
fqn: Rc<str>, fqn: Rc<str>,
parameters: Vec<IrParameter>, parameters: Vec<IrParameter>,
variables: Vec<IrVariable>, stack_frame_variables: IrStackFrameVariables,
free_variables: IrFreeVariables,
return_type_info: Option<IrTypeInfo>, return_type_info: Option<IrTypeInfo>,
blocks: Vec<IrBlock>, blocks: Vec<IrBlock>,
) -> Self { ) -> Self {
Self { Self {
fqn, fqn,
parameters, parameters,
variables, stack_frame_variables,
free_variables,
return_type_info, return_type_info,
blocks, blocks,
} }
@ -47,41 +45,15 @@ impl IrFunction {
&self.parameters &self.parameters
} }
pub fn variables(&self) -> &[IrVariable] { pub fn stack_frame_variables(&self) -> &IrStackFrameVariables {
&self.variables &self.stack_frame_variables
}
pub fn free_variables(&self) -> &IrFreeVariables {
&self.free_variables
} }
pub fn return_type_info(&self) -> Option<&IrTypeInfo> { pub fn return_type_info(&self) -> Option<&IrTypeInfo> {
self.return_type_info.as_ref() 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<IrTypeInfo>,
variables_to_type_infos: &HashMap<IrVariableId, IrTypeInfoId>,
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,
)
}
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable; use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -38,7 +38,7 @@ impl Display for IrGetFieldRef {
} }
impl VrUser for IrGetFieldRef { impl VrUser for IrGetFieldRef {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
self.self_variable_or_parameter.vr_uses() unimplemented!()
} }
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable; use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -39,7 +39,7 @@ impl Display for IrGetFieldRefMut {
} }
impl VrUser for IrGetFieldRefMut { impl VrUser for IrGetFieldRefMut {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
self.self_variable_or_parameter.vr_uses() self.self_variable_or_parameter.vr_uses(vrs)
} }
} }

View File

@ -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_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_read_field::IrReadField; use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -50,15 +50,15 @@ impl Display for IrOperation {
} }
impl VrUser for IrOperation { impl VrUser for IrOperation {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
match self { match self {
IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(), 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(), 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(), IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(vrs),
IrOperation::Load(ir_expression) => ir_expression.vr_uses(), IrOperation::Load(ir_expression) => ir_expression.vr_uses(vrs),
IrOperation::Binary(ir_binary) => ir_binary.vr_uses(), IrOperation::Binary(ir_binary) => ir_binary.vr_uses(vrs),
IrOperation::Call(ir_call) => ir_call.vr_uses(), IrOperation::Call(ir_call) => ir_call.vr_uses(vrs),
IrOperation::Allocate(_) => HashSet::new(), IrOperation::Allocate(_) => {}
} }
} }
} }

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
pub type IrParameterId = usize; pub type IrParameterId = usize;
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct IrParameter { pub struct IrParameter {
name: Rc<str>, name: Rc<str>,
type_info: IrTypeInfo, type_info: IrTypeInfo,

View File

@ -1,10 +1,10 @@
use crate::ir::ir_parameter::IrParameterId; use crate::ir::ir_parameter::IrParameterId;
use crate::ir::ir_variable::IrVariableId; 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; use std::fmt::Display;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[deprecated]
pub enum IrParameterOrVariable { pub enum IrParameterOrVariable {
Parameter(IrParameterId), Parameter(IrParameterId),
Variable(IrVariableId), Variable(IrVariableId),
@ -17,11 +17,7 @@ impl Display for IrParameterOrVariable {
} }
impl VrUser for IrParameterOrVariable { impl VrUser for IrParameterOrVariable {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, _vrs: &mut VrCollector) {
if let IrParameterOrVariable::Variable(ir_variable_id) = self { unimplemented!()
HashSet::from([*ir_variable_id])
} else {
HashSet::new()
}
} }
} }

View File

@ -1,5 +1,5 @@
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -19,9 +19,7 @@ impl IrReadField {
} }
impl VrUser for IrReadField { impl VrUser for IrReadField {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {}
HashSet::from([self.field_ref_variable])
}
} }
impl Display for IrReadField { impl Display for IrReadField {

View File

@ -1,6 +1,5 @@
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVariableId; use crate::ir::register_allocation::{VrCollector, VrUser};
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -20,11 +19,9 @@ impl IrReturn {
} }
impl VrUser for IrReturn { impl VrUser for IrReturn {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
if let Some(ir_expression) = self.value.as_ref() { if let Some(ir_expression) = self.value.as_ref() {
ir_expression.vr_uses() ir_expression.vr_uses(vrs);
} else {
HashSet::new()
} }
} }
} }

View File

@ -1,6 +1,6 @@
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -20,11 +20,8 @@ impl IrSetField {
} }
impl VrUser for IrSetField { impl VrUser for IrSetField {
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
let mut set = HashSet::new(); unimplemented!()
set.insert(self.field_ref_variable);
set.extend(self.initializer.vr_uses());
set
} }
} }

View File

@ -3,7 +3,7 @@ use crate::ir::ir_call::IrCall;
use crate::ir::ir_return::IrReturn; use crate::ir::ir_return::IrReturn;
use crate::ir::ir_set_field::IrSetField; use crate::ir::ir_set_field::IrSetField;
use crate::ir::ir_variable::IrVariableId; 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::collections::HashSet;
#[derive(Debug)] #[derive(Debug)]
@ -15,21 +15,21 @@ pub enum IrStatement {
} }
impl VrUser for IrStatement { impl VrUser for IrStatement {
fn vr_definitions(&self) -> HashSet<IrVariableId> { fn vr_definitions(&self, vrs: &mut VrCollector) {
match self { match self {
IrStatement::Assign(ir_assign) => ir_assign.vr_definitions(), IrStatement::Assign(ir_assign) => ir_assign.vr_definitions(vrs),
IrStatement::Call(ir_call) => ir_call.vr_definitions(), IrStatement::Call(ir_call) => ir_call.vr_definitions(vrs),
IrStatement::Return(ir_return) => ir_return.vr_definitions(), IrStatement::Return(ir_return) => ir_return.vr_definitions(vrs),
IrStatement::SetField(ir_set_field) => ir_set_field.vr_definitions(), IrStatement::SetField(ir_set_field) => ir_set_field.vr_definitions(vrs),
} }
} }
fn vr_uses(&self) -> HashSet<IrVariableId> { fn vr_uses(&self, vrs: &mut VrCollector) {
match self { match self {
IrStatement::Assign(ir_assign) => ir_assign.vr_uses(), IrStatement::Assign(ir_assign) => ir_assign.vr_uses(vrs),
IrStatement::Call(ir_call) => ir_call.vr_uses(), IrStatement::Call(ir_call) => ir_call.vr_uses(vrs),
IrStatement::Return(ir_return) => ir_return.vr_uses(), IrStatement::Return(ir_return) => ir_return.vr_uses(vrs),
IrStatement::SetField(ir_set_field) => ir_set_field.vr_uses(), IrStatement::SetField(ir_set_field) => ir_set_field.vr_uses(vrs),
} }
} }
} }

View File

@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter};
pub type IrTypeInfoId = usize; pub type IrTypeInfoId = usize;
#[derive(Debug)] #[derive(Clone, Debug)]
pub enum IrTypeInfo { pub enum IrTypeInfo {
String, String,
Int, Int,

View File

@ -1,21 +1,127 @@
use crate::ir::ir_type_info::IrTypeInfo; use crate::ir::ir_type_info::IrTypeInfo;
use std::fmt::{Display, Formatter}; use std::fmt::Display;
use std::ops::Index;
use std::rc::Rc; use std::rc::Rc;
pub type IrVariableId = usize; #[derive(Debug)]
pub struct IrStackFrameVariables {
vs: Vec<IrVariableInfo>,
}
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<IrStackFrameVariableId> 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)] #[derive(Debug)]
pub struct IrVariable { pub struct IrFreeVariables {
vs: Vec<IrVariableInfo>,
}
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<IrVariableInfo> {
std::mem::take(&mut self.vs)
}
}
impl Clone for IrFreeVariables {
fn clone(&self) -> Self {
Self {
vs: self.vs.clone(),
}
}
}
impl Index<IrFreeVariableId> 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 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<str>, name: Rc<str>,
type_info: IrTypeInfo, type_info: IrTypeInfo,
} }
impl IrVariable { impl IrVariableInfo {
pub fn new(name: &str, type_info: IrTypeInfo) -> Self { pub fn new(name: Rc<str>, type_info: IrTypeInfo) -> Self {
Self { Self { name, type_info }
name: name.into(),
type_info,
}
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
@ -26,9 +132,3 @@ impl IrVariable {
&self.type_info &self.type_info
} }
} }
impl Display for IrVariable {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}

View File

@ -1,8 +1,7 @@
use crate::constants_table::ConstantsTable; 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::ir_function::IrFunction;
use crate::ir::register_allocation::{AssignRegistersResult, assign_registers}; use crate::ir::register_allocation::{AssignRegistersResult, assign_registers};
use crate::ir::variable_locations::VariableLocations;
use dvm_lib::vm::function::Function; use dvm_lib::vm::function::Function;
mod assemble; mod assemble;
@ -27,13 +26,11 @@ pub mod ir_statement;
pub mod ir_type_info; pub mod ir_type_info;
pub mod ir_variable; pub mod ir_variable;
mod register_allocation; mod register_allocation;
mod util; pub mod stack_variable_offset;
pub mod variable_locations;
pub fn compile_dvm_function( pub fn compile_dvm_function(
ir_function: &IrFunction, ir_function: &IrFunction,
register_count: usize, register_count: usize,
variable_locations: &mut VariableLocations,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Function { ) -> Function {
let AssignRegistersResult { let AssignRegistersResult {
@ -41,16 +38,14 @@ pub fn compile_dvm_function(
spilled_variables, spilled_variables,
} = assign_registers(ir_function, register_count); } = assign_registers(ir_function, register_count);
variable_locations.push_all_register_variables(&register_variables); let function_storage_map =
for spilled_variable in spilled_variables { FunctionStorageMap::new_from(ir_function, &register_variables, &spilled_variables);
variable_locations.push_stack_variable(spilled_variable);
}
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( Function::new(
ir_function.fqn().into(), ir_function.fqn().into(),
ir_function.parameters().len(), ir_function.parameters().len(),
variable_locations.stack_variables_count(), function_storage_map.stack_size(),
instructions, instructions,
) )
} }

View File

@ -2,17 +2,18 @@
/// https://www.youtube.com/watch?v=eWp_-XCwN1A /// https://www.youtube.com/watch?v=eWp_-XCwN1A
use crate::ir::ir_block::IrBlock; use crate::ir::ir_block::IrBlock;
use crate::ir::ir_function::IrFunction; 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 dvm_lib::instruction::Register;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
pub type RegisterAssignment = Register; pub type RegisterAssignment = Register;
pub type InterferenceGraph = HashMap<IrVariableId, HashSet<IrVariableId>>; pub type InterferenceGraph = HashMap<IrFreeVariableId, HashSet<IrFreeVariableId>>;
pub type LivenessSets = Vec<HashSet<IrVariableId>>; pub type LivenessSets = Vec<HashSet<IrFreeVariableId>>;
pub struct AssignRegistersResult { pub struct AssignRegistersResult {
pub register_variables: HashMap<IrVariableId, RegisterAssignment>, pub register_variables: HashMap<IrFreeVariableId, RegisterAssignment>,
pub spilled_variables: HashSet<IrVariableId>, pub spilled_variables: HashSet<IrFreeVariableId>,
} }
pub fn assign_registers(ir_function: &IrFunction, register_count: usize) -> AssignRegistersResult { 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) ) // 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 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 rhs = out_s - &def_s;
let new_ins = use_s.union(&rhs).map(|v| *v).collect::<HashSet<_>>(); let new_ins = use_s.union(&rhs).map(|v| *v).collect::<HashSet<_>>();
@ -77,13 +79,13 @@ fn block_live_in_live_out(ir_block: &IrBlock) -> (LivenessSets, LivenessSets) {
fn block_interference_graph( fn block_interference_graph(
ir_block: &IrBlock, ir_block: &IrBlock,
spilled: &HashSet<IrVariableId>, spilled: &HashSet<IrFreeVariableId>,
) -> InterferenceGraph { ) -> InterferenceGraph {
// create a set of all variables used in the block that are not already spilled // create a set of all variables used in the block that are not already spilled
let mut all_vr_variables: HashSet<IrVariableId> = HashSet::new(); let mut all_vr_variables: HashSet<IrFreeVariableId> = HashSet::new();
for statement in ir_block.statements() { for statement in ir_block.statements() {
let definitions = statement.vr_definitions(); let definitions = collect_statement_vr_definitions(statement);
let uses = statement.vr_uses(); let uses = collect_statement_vr_uses(statement);
let not_already_spilled = definitions let not_already_spilled = definitions
.union(&uses) .union(&uses)
.filter(|v| !spilled.contains(*v)) .filter(|v| !spilled.contains(*v))
@ -101,7 +103,7 @@ fn block_interference_graph(
for (statement_index, ir_statement) in ir_block.statements().iter().enumerate() { for (statement_index, ir_statement) in ir_block.statements().iter().enumerate() {
let statement_live_out = &live_out[statement_index]; 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 // check for spill
if spilled.contains(&definition_vr_variable) { if spilled.contains(&definition_vr_variable) {
continue; continue;
@ -128,7 +130,7 @@ fn block_interference_graph(
} }
fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> AssignRegistersResult { fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> AssignRegistersResult {
let mut spilled: HashSet<IrVariableId> = HashSet::new(); let mut spilled: HashSet<IrFreeVariableId> = HashSet::new();
loop { loop {
let mut interference_graph = block_interference_graph(ir_block, &spilled); let mut interference_graph = block_interference_graph(ir_block, &spilled);
let (registers, new_spills) = registers_and_spills(&mut interference_graph, register_count); 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 { pub trait VrUser {
fn vr_definitions(&self) -> HashSet<IrVariableId> { fn vr_definitions(&self, _vrs: &mut VrCollector) {}
HashSet::new()
fn vr_uses(&self, _vrs: &mut VrCollector);
} }
fn vr_uses(&self) -> HashSet<IrVariableId>; pub struct VrCollector {
vrs: HashSet<IrFreeVariableId>,
}
impl VrCollector {
pub fn new() -> VrCollector {
Self {
vrs: HashSet::new(),
}
}
pub fn push(&mut self, id: IrFreeVariableId) {
self.vrs.insert(id);
}
pub fn take_vrs(&mut self) -> HashSet<IrFreeVariableId> {
std::mem::take(&mut self.vrs)
}
}
fn collect_statement_vr_definitions(statement: &IrStatement) -> HashSet<IrFreeVariableId> {
let mut vr_collector = VrCollector::new();
statement.vr_definitions(&mut vr_collector);
vr_collector.take_vrs()
}
fn collect_statement_vr_uses(statement: &IrStatement) -> HashSet<IrFreeVariableId> {
let mut vr_collector = VrCollector::new();
statement.vr_definitions(&mut vr_collector);
vr_collector.take_vrs()
} }
#[derive(Debug)] #[derive(Debug)]
struct WorkItem { struct WorkItem {
vr: IrVariableId, vr: IrFreeVariableId,
edges: HashSet<IrVariableId>, edges: HashSet<IrFreeVariableId>,
color: bool, color: bool,
} }
@ -164,8 +196,8 @@ fn registers_and_spills(
interference_graph: &mut InterferenceGraph, interference_graph: &mut InterferenceGraph,
k: usize, k: usize,
) -> ( ) -> (
HashMap<IrVariableId, RegisterAssignment>, HashMap<IrFreeVariableId, RegisterAssignment>,
HashSet<IrVariableId>, HashSet<IrFreeVariableId>,
) { ) {
let mut work_stack: Vec<WorkItem> = vec![]; let mut work_stack: Vec<WorkItem> = vec![];
@ -175,8 +207,8 @@ fn registers_and_spills(
// 3. assign colors to registers // 3. assign colors to registers
let mut rebuilt_graph: InterferenceGraph = HashMap::new(); let mut rebuilt_graph: InterferenceGraph = HashMap::new();
let mut register_assignments: HashMap<IrVariableId, RegisterAssignment> = HashMap::new(); let mut register_assignments: HashMap<IrFreeVariableId, RegisterAssignment> = HashMap::new();
let mut spills: HashSet<IrVariableId> = HashSet::new(); let mut spills: HashSet<IrFreeVariableId> = HashSet::new();
while let Some(work_item) = work_stack.pop() { while let Some(work_item) = work_stack.pop() {
if work_item.color { if work_item.color {
@ -196,7 +228,7 @@ fn assign_register(
work_item: &WorkItem, work_item: &WorkItem,
graph: &mut InterferenceGraph, graph: &mut InterferenceGraph,
k: usize, k: usize,
register_assignments: &mut HashMap<IrVariableId, RegisterAssignment>, register_assignments: &mut HashMap<IrFreeVariableId, RegisterAssignment>,
) { ) {
rebuild_vr_and_edges(graph, work_item); 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<IrVariableId> { fn find_vr_lt_k(interference_graph: &InterferenceGraph, k: usize) -> Option<IrFreeVariableId> {
interference_graph.iter().find_map( interference_graph.iter().find_map(
|(vr, neighbors)| { |(vr, neighbors)| {
if neighbors.len() < k { Some(*vr) } else { None } if neighbors.len() < k { Some(*vr) } else { None }
@ -226,8 +258,8 @@ fn find_vr_lt_k(interference_graph: &InterferenceGraph, k: usize) -> Option<IrVa
/// Returns the (removed) outgoing edges for the given vr /// Returns the (removed) outgoing edges for the given vr
fn remove_vr_and_edges( fn remove_vr_and_edges(
interference_graph: &mut InterferenceGraph, interference_graph: &mut InterferenceGraph,
vr: &IrVariableId, vr: &IrFreeVariableId,
) -> HashSet<IrVariableId> { ) -> HashSet<IrFreeVariableId> {
// first, outgoing // first, outgoing
let outgoing_edges = interference_graph.remove(vr).unwrap(); 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( fn can_optimistically_color(
work_item: &WorkItem, work_item: &WorkItem,
register_assignments: &HashMap<IrVariableId, usize>, register_assignments: &HashMap<IrFreeVariableId, usize>,
k: usize, k: usize,
) -> bool { ) -> bool {
// see if we can optimistically color // see if we can optimistically color
@ -351,7 +383,7 @@ mod tests {
graph graph
} }
fn get_vrs() -> Vec<IrVariableId> { fn get_vrs() -> Vec<IrFreeVariableId> {
vec![0, 1, 2] vec![0, 1, 2]
} }

View File

@ -0,0 +1 @@
pub type StackVariableOffset = isize;

View File

@ -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<IrVariableId>,
stack_variables: &mut HashSet<IrVariableId>,
new_spills: &HashSet<IrVariableId>,
) {
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);
}
}

View File

@ -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<IrVariableId, RegisterAssignment>,
stack_variables: HashMap<IrVariableId, StackVariableOffset>,
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<IrVariableId, RegisterAssignment>,
) {
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;
}
}

View File

@ -2,9 +2,11 @@ use crate::ast::statement::Statement;
use crate::constants_table::ConstantsTable; use crate::constants_table::ConstantsTable;
use crate::diagnostic::Diagnostics; use crate::diagnostic::Diagnostics;
use crate::ir::compile_dvm_function; use crate::ir::compile_dvm_function;
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::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function};
use crate::parser::parse_compilation_unit; use crate::parser::parse_compilation_unit;
use crate::semantic_analysis::symbol::SymbolId;
use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement}; use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement};
use dvm_lib::vm::function::Function; use dvm_lib::vm::function::Function;
use semantic_analysis::analysis_context::AnalysisContext; use semantic_analysis::analysis_context::AnalysisContext;
@ -61,12 +63,7 @@ pub fn compile_compilation_unit(
let mut dvm_functions = HashMap::new(); let mut dvm_functions = HashMap::new();
for ir_function in &lower_to_ir_result.functions { for ir_function in &lower_to_ir_result.functions {
let dvm_function = compile_dvm_function( let dvm_function = compile_dvm_function(ir_function, register_count, constants_table);
ir_function,
register_count,
&mut VariableLocations::new(),
constants_table,
);
dvm_functions.insert(dvm_function.name_owned(), dvm_function); dvm_functions.insert(dvm_function.name_owned(), dvm_function);
} }
@ -75,23 +72,94 @@ pub fn compile_compilation_unit(
}) })
} }
pub fn compile_statement_to_synthetic_function( pub struct SyntheticFunctionSession {
statement: &Statement,
analysis_context: &mut AnalysisContext,
fqn: Rc<str>, fqn: Rc<str>,
variable_locations: &mut VariableLocations, ctx: Box<AnalysisContext>,
env: Box<SyntheticEnvironment>,
}
impl SyntheticFunctionSession {
pub fn new(fqn: &str) -> Self {
Self {
fqn: fqn.into(),
ctx: AnalysisContext::new().into(),
env: SyntheticEnvironment::new().into(),
}
}
pub fn ctx(&self) -> &AnalysisContext {
&self.ctx
}
pub fn ctx_mut(&mut self) -> &mut AnalysisContext {
&mut self.ctx
}
pub fn compile_statement(
&mut self,
statement: &Statement,
register_count: usize, register_count: usize,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> { ) -> Result<Function, Diagnostics> {
let diagnostics = analyze_statement(statement, analysis_context); let diagnostics = analyze_statement(statement, &mut self.ctx);
if !diagnostics.is_empty() { if !diagnostics.is_empty() {
return Err(diagnostics); return Err(diagnostics);
} }
let ir_function = lower_to_ir_synthetic_function(statement, analysis_context, fqn);
// 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( Ok(compile_dvm_function(
&ir_function, &ir_function,
register_count, register_count,
variable_locations,
constants_table, constants_table,
)) ))
} }
}
pub struct SyntheticEnvironment {
ir_stack_frame_variables: IrStackFrameVariables,
symbols_to_variables: HashMap<SymbolId, IrVariable>,
}
impl SyntheticEnvironment {
pub fn new() -> Self {
Self {
ir_stack_frame_variables: IrStackFrameVariables::new(),
symbols_to_variables: HashMap::new(),
}
}
pub fn ir_stack_frame_variables(&self) -> &IrStackFrameVariables {
&self.ir_stack_frame_variables
}
pub fn ir_stack_frame_variables_mut(&mut self) -> &mut IrStackFrameVariables {
&mut self.ir_stack_frame_variables
}
pub fn symbols_to_variables(&self) -> &HashMap<SymbolId, IrVariable> {
&self.symbols_to_variables
}
pub fn symbols_to_variables_mut(&mut self) -> &mut HashMap<SymbolId, IrVariable> {
&mut self.symbols_to_variables
}
}

View File

@ -1,6 +1,6 @@
mod util; pub mod util;
use crate::ast::NodeId; use crate::SyntheticFunctionSession;
use crate::ast::assign_statement::AssignStatement; use crate::ast::assign_statement::AssignStatement;
use crate::ast::binary_expression::BinaryOperation; use crate::ast::binary_expression::BinaryOperation;
use crate::ast::call::Call; use crate::ast::call::Call;
@ -21,68 +21,46 @@ use crate::ir::ir_parameter::{IrParameter, IrParameterId};
use crate::ir::ir_return::IrReturn; use crate::ir::ir_return::IrReturn;
use crate::ir::ir_statement::IrStatement; use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_type_info::IrTypeInfo; 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::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info};
use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::symbol::{Symbol, SymbolId}; use crate::semantic_analysis::symbol::{Symbol, SymbolId};
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId}; use crate::semantic_analysis::type_info::TypeInfo;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Neg; use std::ops::Neg;
use std::rc::Rc;
pub struct LowerToIrResult { pub struct LowerToIrResult {
pub functions: Vec<IrFunction>, pub functions: Vec<IrFunction>,
} }
#[derive(Debug)]
struct LowerToIrContext<'a> {
symbols: &'a [Symbol],
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
type_infos: &'a [TypeInfo],
symbols_to_type_infos: &'a HashMap<SymbolId, TypeInfoId>,
nodes_to_type_infos: &'a HashMap<NodeId, TypeInfoId>,
ir_functions: Vec<IrFunction>,
}
pub fn lower_to_ir_compilation_unit( pub fn lower_to_ir_compilation_unit(
compilation_unit: &CompilationUnit, compilation_unit: &CompilationUnit,
analysis_context: &AnalysisContext, analysis_context: &AnalysisContext,
) -> LowerToIrResult { ) -> LowerToIrResult {
let mut ctx = LowerToIrContext {
symbols: analysis_context.symbols(),
nodes_to_symbols: analysis_context.nodes_to_symbols(),
type_infos: analysis_context.type_infos(),
symbols_to_type_infos: analysis_context.symbols_to_type_infos(),
nodes_to_type_infos: analysis_context.nodes_to_type_infos(),
ir_functions: Vec::new(),
};
for function in compilation_unit.functions() {
lower_to_ir_function(function, &mut ctx);
}
LowerToIrResult { LowerToIrResult {
functions: ctx.ir_functions, functions: compilation_unit
.functions()
.iter()
.map(|function| lower_to_ir_function(function, analysis_context))
.collect(),
} }
} }
pub fn lower_to_ir_synthetic_function( pub fn lower_to_ir_synthetic_function(
statement: &Statement, statement: &Statement,
analysis_ctx: &AnalysisContext, session: &SyntheticFunctionSession,
fqn: Rc<str>,
) -> IrFunction { ) -> IrFunction {
let mut ctx = LowerToIrContext { let mut storage_env = StorageEnvironment::session_new(
symbols: analysis_ctx.symbols(), session.env.ir_stack_frame_variables(),
nodes_to_symbols: analysis_ctx.nodes_to_symbols(), &mut IrFreeVariables::new(),
type_infos: analysis_ctx.type_infos(), session.env.symbols_to_variables(),
symbols_to_type_infos: analysis_ctx.symbols_to_type_infos(), 0,
nodes_to_type_infos: analysis_ctx.nodes_to_type_infos(), );
ir_functions: Vec::new(),
};
let mut fn_ctx = LowerToIrFunctionContext::new(); let mut fn_ctx = LowerToIrFunctionContext::new(&mut storage_env);
lower_to_ir_statement(statement, &mut ctx, &mut fn_ctx, true); lower_to_ir_statement(statement, &session.ctx, &mut fn_ctx, true);
fn_ctx.finish_block(); fn_ctx.finish_block();
// infer return type from statement // infer return type from statement
@ -90,42 +68,35 @@ pub fn lower_to_ir_synthetic_function(
Statement::Let(_) | Statement::Assign(_) => None, Statement::Let(_) | Statement::Assign(_) => None,
Statement::Expression(expression_statement) => { Statement::Expression(expression_statement) => {
let type_info_id = let type_info_id =
ctx.nodes_to_type_infos[&expression_statement.expression().node_id()]; session.ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()];
let type_info = &ctx.type_infos[type_info_id]; let type_info = &session.ctx.type_infos()[type_info_id];
return_type_info_to_ir_type_info(type_info) return_type_info_to_ir_type_info(type_info)
} }
}; };
let blocks = std::mem::take(&mut fn_ctx.blocks);
IrFunction::new( IrFunction::new(
fqn, session.fqn.clone(),
fn_ctx.ir_parameters, storage_env.take_parameters(),
fn_ctx.ir_variables, storage_env.ir_stack_frame_variables,
storage_env.ir_free_variables,
maybe_return_ir_type_info, maybe_return_ir_type_info,
fn_ctx.blocks, blocks,
) )
} }
#[derive(Debug)] struct LowerToIrFunctionContext<'a> {
struct LowerToIrFunctionContext { storage_env: &'a mut StorageEnvironment,
blocks: Vec<IrBlock>, blocks: Vec<IrBlock>,
ir_variables: Vec<IrVariable>,
symbols_to_variables: HashMap<SymbolId, IrVariableId>,
ir_parameters: Vec<IrParameter>,
symbols_to_parameters: HashMap<SymbolId, IrParameterId>,
current_block_statements: Vec<IrStatement>, current_block_statements: Vec<IrStatement>,
t_var_counter: usize,
} }
impl LowerToIrFunctionContext { impl<'a> LowerToIrFunctionContext<'a> {
fn new() -> Self { fn new(storage_env: &'a mut StorageEnvironment) -> Self {
Self { Self {
storage_env,
blocks: Vec::new(), blocks: Vec::new(),
ir_variables: Vec::new(),
symbols_to_variables: HashMap::new(),
ir_parameters: Vec::new(),
symbols_to_parameters: HashMap::new(),
current_block_statements: Vec::new(), current_block_statements: Vec::new(),
t_var_counter: 0,
} }
} }
@ -143,59 +114,148 @@ impl LowerToIrFunctionContext {
self.blocks.push(ir_block); self.blocks.push(ir_block);
} }
fn insert_ir_parameter( fn storage_env(&self) -> &StorageEnvironment {
&mut self, self.storage_env
ir_parameter: IrParameter,
maybe_associated_symbol_id: Option<SymbolId>,
) -> IrParameterId {
self.ir_parameters.push(ir_parameter);
let ir_parameter_id = self.ir_parameters.len() - 1;
if let Some(associated_symbol_id) = maybe_associated_symbol_id {
self.symbols_to_parameters
.insert(associated_symbol_id, ir_parameter_id);
} }
fn storage_env_mut(&mut self) -> &mut StorageEnvironment {
self.storage_env
}
}
struct StorageEnvironment {
ir_stack_frame_variables: IrStackFrameVariables,
ir_free_variables: IrFreeVariables,
symbols_to_variables: HashMap<SymbolId, IrVariable>,
current_parameter_stack_offset: isize,
ir_parameters: Vec<IrParameter>,
symbols_to_parameters: HashMap<SymbolId, IrParameterId>,
t_var_counter: usize,
}
impl StorageEnvironment {
fn new(parameter_count: usize) -> Self {
Self {
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(),
symbols_to_parameters: HashMap::new(),
t_var_counter: 0,
}
}
fn session_new(
ir_stack_frame_variables: &IrStackFrameVariables,
ir_free_variables: &IrFreeVariables,
session_symbols_to_variables: &HashMap<SymbolId, IrVariable>,
parameter_count: usize,
) -> Self {
let mut this = Self::new(parameter_count);
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
}
fn next_parameter_stack_offset(&mut self) -> isize {
let current = self.current_parameter_stack_offset;
self.current_parameter_stack_offset += 1;
current
}
fn next_t_var_number(&mut self) -> usize {
let t_var = self.t_var_counter;
self.t_var_counter += 1;
t_var
}
fn new_parameter(&mut self, name: &str, ir_type_info: IrTypeInfo) -> IrParameterId {
let ir_parameter = IrParameter::new(name, ir_type_info, self.next_parameter_stack_offset());
self.ir_parameters.push(ir_parameter);
self.ir_parameters.len() - 1
}
fn new_parameter_for(
&mut self,
name: &str,
ir_type_info: IrTypeInfo,
symbol_id: SymbolId,
) -> IrParameterId {
let ir_parameter_id = self.new_parameter(name, ir_type_info);
self.symbols_to_parameters
.insert(symbol_id, ir_parameter_id);
ir_parameter_id ir_parameter_id
} }
fn insert_ir_variable( 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_free_variable_for(
&mut self, &mut self,
ir_variable: IrVariable, name: &str,
maybe_associated_symbol_id: Option<SymbolId>, ir_type_info: IrTypeInfo,
) -> IrVariableId { symbol_id: SymbolId,
self.ir_variables.push(ir_variable); ) -> IrVariable {
let ir_variable_id = self.ir_variables.len() - 1; let ir_variable = self.new_free_variable(name, ir_type_info);
if let Some(associated_symbol_id) = maybe_associated_symbol_id {
self.symbols_to_variables self.symbols_to_variables
.insert(associated_symbol_id, ir_variable_id); .insert(symbol_id, ir_variable.clone());
} ir_variable
ir_variable_id
} }
fn make_t_var(&mut self, ir_type_info: IrTypeInfo) -> IrVariableId { fn new_t_var(&mut self, ir_type_info: IrTypeInfo) -> IrVariable {
let t_var_id = self.t_var_counter; let t_var_number = self.next_t_var_number();
self.t_var_counter += 1; self.new_free_variable(&format!("t_{}", t_var_number), ir_type_info)
let t_var_ir_variable = IrVariable::new(&format!("t_{}", t_var_id), ir_type_info); }
self.insert_ir_variable(t_var_ir_variable, None)
fn get_variable_for(&self, symbol_id: SymbolId) -> &IrVariable {
self.symbols_to_variables
.get(&symbol_id)
.expect(&format!("No ir_variable for symbol_id {}", symbol_id))
}
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<IrParameterId> {
self.symbols_to_parameters.get(&symbol_id).cloned()
}
fn take_parameters(&mut self) -> Vec<IrParameter> {
std::mem::take(&mut self.ir_parameters)
} }
} }
fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) { fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunction {
let mut fn_ctx = LowerToIrFunctionContext::new(); 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); lower_to_ir_parameters(function, ctx, &mut fn_ctx);
// get various function info // get various function info
let function_symbol_id = ctx.nodes_to_symbols[&function.node_id()]; let function_symbol_id = ctx.nodes_to_symbols()[&function.node_id()];
let function_symbol = match &ctx.symbols[function_symbol_id] { let function_symbol = match &ctx.symbols()[function_symbol_id] {
Symbol::Function(function_symbol) => function_symbol, Symbol::Function(function_symbol) => function_symbol,
_ => panic!("Expected FunctionSymbol"), _ => panic!("Expected FunctionSymbol"),
}; };
let function_type_info_id = ctx.symbols_to_type_infos[&function_symbol_id]; let function_type_info_id = ctx.symbols_to_type_infos()[&function_symbol_id];
let function_type_info = match &ctx.type_infos[function_type_info_id] { let function_type_info = match &ctx.type_infos()[function_type_info_id] {
TypeInfo::Function(function_type_info) => function_type_info, TypeInfo::Function(function_type_info) => function_type_info,
_ => panic!("Expected FunctionTypeInfo"), _ => panic!("Expected FunctionTypeInfo"),
}; };
let return_type_info = &ctx.type_infos[function_type_info.return_type_id()]; let return_type_info = &ctx.type_infos()[function_type_info.return_type_id()];
let is_void_function = match return_type_info { let is_void_function = match return_type_info {
TypeInfo::Void => true, TypeInfo::Void => true,
_ => false, _ => false,
@ -209,41 +269,36 @@ fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) {
} }
fn_ctx.finish_block(); fn_ctx.finish_block();
let ir_function = IrFunction::new( let blocks = std::mem::take(&mut fn_ctx.blocks);
IrFunction::new(
function_symbol.fqn_owned(), function_symbol.fqn_owned(),
fn_ctx.ir_parameters, storage_env.take_parameters(),
fn_ctx.ir_variables, storage_env.ir_stack_frame_variables.clone(),
storage_env.ir_free_variables.clone(),
return_type_info_to_ir_type_info(return_type_info), return_type_info_to_ir_type_info(return_type_info),
fn_ctx.blocks, blocks,
); )
ctx.ir_functions.push(ir_function);
} }
fn lower_to_ir_parameters( fn lower_to_ir_parameters(
function: &Function, function: &Function,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) { ) {
let n_parameters = function.parameters().len() as isize; for parameter in function.parameters() {
for (i, parameter) in function.parameters().iter().enumerate() { let parameter_type_info_id = ctx.nodes_to_type_infos()[&parameter.node_id()];
let parameter_type_info_id = ctx.nodes_to_type_infos[&parameter.node_id()]; let parameter_type_info = &ctx.type_infos()[parameter_type_info_id];
let parameter_type_info = &ctx.type_infos[parameter_type_info_id]; fn_ctx.storage_env_mut().new_parameter_for(
let ir_parameter = IrParameter::new(
parameter.declared_name(), parameter.declared_name(),
to_ir_type_info(parameter_type_info), to_ir_type_info(parameter_type_info),
n_parameters.neg() + (i as isize), ctx.nodes_to_symbols()[&parameter.node_id()],
);
fn_ctx.insert_ir_parameter(
ir_parameter,
Some(ctx.nodes_to_symbols[&parameter.node_id()]),
); );
} }
} }
fn lower_to_ir_statement( fn lower_to_ir_statement(
statement: &Statement, statement: &Statement,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
can_return_value: bool, can_return_value: bool,
) { ) {
@ -277,28 +332,39 @@ fn lower_binary_operator(binary_operation: &BinaryOperation) -> IrBinaryOperator
fn lower_to_ir_let_statement( fn lower_to_ir_let_statement(
let_statement: &LetStatement, let_statement: &LetStatement,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) { ) {
let symbol_id = ctx.nodes_to_symbols[&let_statement.node_id()]; let symbol_id = ctx.nodes_to_symbols()[&let_statement.node_id()];
let type_info_id = ctx.nodes_to_type_infos[&let_statement.node_id()]; let type_info_id = ctx.nodes_to_type_infos()[&let_statement.node_id()];
let type_info = &ctx.type_infos[type_info_id]; let type_info = &ctx.type_infos()[type_info_id];
let ir_variable = IrVariable::new(let_statement.declared_name(), to_ir_type_info(type_info)); // We first fetch from the storage environment because we may have already allocated storage
let ir_variable_id = fn_ctx.insert_ir_variable(ir_variable, Some(symbol_id)); // 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 = let initializer_ir_operation =
lower_expression_to_ir_operation(let_statement.initializer(), ctx, fn_ctx); lower_expression_to_ir_operation(let_statement.initializer(), ctx, fn_ctx);
let ir_assign = IrAssign::new(ir_variable_id, initializer_ir_operation); let ir_assign = IrAssign::new(destination_ir_variable, initializer_ir_operation);
let ir_statement = IrStatement::Assign(ir_assign); let ir_statement = IrStatement::Assign(ir_assign);
fn_ctx.current_block_statements.push(ir_statement); fn_ctx.current_block_statements.push(ir_statement);
} }
fn lower_to_ir_expression_statement( fn lower_to_ir_expression_statement(
expression_statement: &ExpressionStatement, expression_statement: &ExpressionStatement,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
returns_value: bool, returns_value: bool,
) { ) {
@ -314,9 +380,11 @@ fn lower_to_ir_expression_statement(
lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx); lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx);
let result_type_info_id = let result_type_info_id =
ctx.nodes_to_type_infos[&expression_statement.expression().node_id()]; ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()];
let result_type_info = &ctx.type_infos[result_type_info_id]; let result_type_info = &ctx.type_infos()[result_type_info_id];
let t_var_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); let t_var_ir_variable_id = fn_ctx
.storage_env_mut()
.new_t_var(to_ir_type_info(result_type_info));
let ir_statement = IrStatement::Assign(IrAssign::new(t_var_ir_variable_id, ir_operation)); let ir_statement = IrStatement::Assign(IrAssign::new(t_var_ir_variable_id, ir_operation));
fn_ctx.current_block_statements.push(ir_statement); fn_ctx.current_block_statements.push(ir_statement);
@ -325,17 +393,20 @@ fn lower_to_ir_expression_statement(
fn lower_to_ir_assign_statement( fn lower_to_ir_assign_statement(
assign_statement: &AssignStatement, assign_statement: &AssignStatement,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) { ) {
match assign_statement.destination() { match assign_statement.destination() {
Expression::Identifier(identifier) => { Expression::Identifier(identifier) => {
let destination_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; let destination_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()];
let destination_ir_variable_id = fn_ctx.symbols_to_variables[&destination_symbol_id]; let destination_ir_variable = fn_ctx
.storage_env()
.get_variable_for(destination_symbol_id)
.clone();
let ir_operation = let ir_operation =
lower_expression_to_ir_operation(assign_statement.value(), ctx, fn_ctx); 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); let ir_statement = IrStatement::Assign(ir_assign);
fn_ctx.current_block_statements.push(ir_statement); fn_ctx.current_block_statements.push(ir_statement);
} }
@ -345,7 +416,7 @@ fn lower_to_ir_assign_statement(
fn lower_expression_to_ir_operation( fn lower_expression_to_ir_operation(
expression: &Expression, expression: &Expression,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) -> IrOperation { ) -> IrOperation {
match expression { match expression {
@ -369,9 +440,10 @@ fn lower_expression_to_ir_operation(
} }
Expression::Call(call) => IrOperation::Call(lower_to_ir_call(call, ctx, fn_ctx)), Expression::Call(call) => IrOperation::Call(lower_to_ir_call(call, ctx, fn_ctx)),
Expression::Identifier(identifier) => { Expression::Identifier(identifier) => {
let identifier_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; let identifier_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()];
let identifier_ir_variable_id = fn_ctx.symbols_to_variables[&identifier_symbol_id]; let identifier_ir_variable =
let ir_expression = IrExpression::Variable(identifier_ir_variable_id); fn_ctx.storage_env().get_variable_for(identifier_symbol_id);
let ir_expression = IrExpression::Variable(identifier_ir_variable.clone());
IrOperation::Load(ir_expression) IrOperation::Load(ir_expression)
} }
Expression::Integer(integer_literal) => { Expression::Integer(integer_literal) => {
@ -388,7 +460,7 @@ fn lower_expression_to_ir_operation(
fn lower_expression_to_ir_expression( fn lower_expression_to_ir_expression(
expression: &Expression, expression: &Expression,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) -> IrExpression { ) -> IrExpression {
match expression { match expression {
@ -403,18 +475,20 @@ fn lower_expression_to_ir_expression(
)); ));
// make destination temp var // make destination temp var
let result_type_info_id = ctx.nodes_to_type_infos[&binary_expression.node_id()]; 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 result_type_info = &ctx.type_infos()[result_type_info_id];
let destination_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); 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 // 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 fn_ctx
.current_block_statements .current_block_statements
.push(IrStatement::Assign(ir_assign)); .push(IrStatement::Assign(ir_assign));
// return location of temp var // return location of temp var
IrExpression::Variable(destination_ir_variable_id) IrExpression::Variable(destination_ir_variable)
} }
Expression::Negative(negative_expression) => { Expression::Negative(negative_expression) => {
let operand = let operand =
@ -425,47 +499,51 @@ fn lower_expression_to_ir_expression(
negative_one, negative_one,
IrBinaryOperator::Multiply, IrBinaryOperator::Multiply,
)); ));
let result_type_info_id = ctx.nodes_to_type_infos[&negative_expression.node_id()]; 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 result_type_info = &ctx.type_infos()[result_type_info_id];
let destination_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); let destination_ir_variable = fn_ctx
let ir_assign = IrAssign::new(destination_ir_variable_id, ir_operation); .storage_env_mut()
.new_t_var(to_ir_type_info(result_type_info));
let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation);
// push the statement which does the multiply by negative one // push the statement which does the multiply by negative one
fn_ctx fn_ctx
.current_block_statements .current_block_statements
.push(IrStatement::Assign(ir_assign)); .push(IrStatement::Assign(ir_assign));
IrExpression::Variable(destination_ir_variable_id) IrExpression::Variable(destination_ir_variable)
} }
Expression::Call(call) => { Expression::Call(call) => {
let ir_call = lower_to_ir_call(call, ctx, fn_ctx); let ir_call = lower_to_ir_call(call, ctx, fn_ctx);
// make temp var // make temp var
let return_type_info_id = ctx.nodes_to_type_infos[&call.node_id()]; 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 return_type_info = &ctx.type_infos()[return_type_info_id];
let return_ir_type_info = to_ir_type_info(return_type_info); let t_var_ir_variable = fn_ctx
let t_var_ir_variable_id = fn_ctx.make_t_var(return_ir_type_info); .storage_env_mut()
.new_t_var(to_ir_type_info(return_type_info));
// assign call to temp var, return temp var expression // assign call to temp var, return temp var expression
let ir_operation = IrOperation::Call(ir_call); 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 fn_ctx
.current_block_statements .current_block_statements
.push(IrStatement::Assign(ir_assign)); .push(IrStatement::Assign(ir_assign));
// return an expression referencing the temp var // return an expression referencing the temp var
IrExpression::Variable(t_var_ir_variable_id) IrExpression::Variable(t_var_ir_variable)
} }
Expression::Identifier(identifier) => { Expression::Identifier(identifier) => {
let rhs_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; let rhs_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()];
if let Some(rhs_ir_variable_id) = fn_ctx.symbols_to_variables.get(&rhs_symbol_id) { if let Some(rhs_ir_variable) =
IrExpression::Variable(*rhs_ir_variable_id) fn_ctx.storage_env().maybe_get_variable_for(rhs_symbol_id)
} else if let Some(rhs_ir_parameter_id) =
fn_ctx.symbols_to_parameters.get(&rhs_symbol_id)
{ {
IrExpression::Parameter(*rhs_ir_parameter_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)
{
IrExpression::Parameter(rhs_ir_parameter_id)
} else { } else {
println!("Dump:\n{:#?}\n{:#?}", ctx, fn_ctx);
panic!( panic!(
"Could not find parameter or variable for symbol_id {}", "Could not find parameter or variable for symbol_id {}",
rhs_symbol_id rhs_symbol_id
@ -480,11 +558,11 @@ fn lower_expression_to_ir_expression(
fn lower_to_ir_call( fn lower_to_ir_call(
call: &Call, call: &Call,
ctx: &LowerToIrContext, ctx: &AnalysisContext,
fn_ctx: &mut LowerToIrFunctionContext, fn_ctx: &mut LowerToIrFunctionContext,
) -> IrCall { ) -> IrCall {
let callee_symbol_id = ctx.nodes_to_symbols[&call.callee().node_id()]; let callee_symbol_id = ctx.nodes_to_symbols()[&call.callee().node_id()];
let callee_symbol = &ctx.symbols[callee_symbol_id]; let callee_symbol = &ctx.symbols()[callee_symbol_id];
match callee_symbol { match callee_symbol {
Symbol::Function(function_symbol) => { Symbol::Function(function_symbol) => {
let arguments = call let arguments = call

View File

@ -252,6 +252,12 @@ pub fn loop_instructions<'a>(
{ {
let instruction = &call_stack.top().instructions()[call_stack.top().ip()]; let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
if debug { if debug {
if let Some(top) = call_stack.maybe_top() {
println!("-- before instruction --");
println!(" stack: {:?}", top.stack());
println!(" registers: {:?}", registers);
println!(" rv: {:?}", top.return_value());
}
println!("{}", instruction); println!("{}", instruction);
} }
@ -717,6 +723,7 @@ pub fn loop_instructions<'a>(
if debug { if debug {
if let Some(top) = call_stack.maybe_top() { if let Some(top) = call_stack.maybe_top() {
println!("-- after instruction -- ");
println!(" stack: {:?}", top.stack()); println!(" stack: {:?}", top.stack());
println!(" registers: {:?}", registers); println!(" registers: {:?}", registers);
println!(" rv: {:?}", top.return_value()); println!(" rv: {:?}", top.return_value());