Repl let statements working!
This commit is contained in:
parent
5edf8964dc
commit
1e9a0ec993
@ -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
|
||||||
|
|||||||
@ -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!(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
#[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)]
|
||||||
|
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;
|
pub type IrVariableId = usize;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[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<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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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(®ister_variables);
|
let function_storage_map =
|
||||||
for spilled_variable in spilled_variables {
|
FunctionStorageMap::new_from(ir_function, ®ister_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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VrCollector {
|
||||||
|
vrs: HashSet<IrFreeVariableId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VrCollector {
|
||||||
|
pub fn new() -> VrCollector {
|
||||||
|
Self {
|
||||||
|
vrs: HashSet::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vr_uses(&self) -> HashSet<IrVariableId>;
|
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]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
dmc-lib/src/ir/stack_variable_offset.rs
Normal file
1
dmc-lib/src/ir/stack_variable_offset.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub type StackVariableOffset = isize;
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,8 +2,8 @@ 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::ir_variable::{IrVariable, IrVariableId};
|
use crate::ir::ir_variable::{IrStackFrameVariables, IrVariable, IrVariableInfo};
|
||||||
use crate::ir::variable_locations::VariableLocations;
|
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::symbol::SymbolId;
|
||||||
@ -63,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,42 +105,61 @@ impl SyntheticFunctionSession {
|
|||||||
if !diagnostics.is_empty() {
|
if !diagnostics.is_empty() {
|
||||||
return Err(diagnostics);
|
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);
|
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,
|
||||||
&mut VariableLocations::new(),
|
|
||||||
constants_table,
|
constants_table,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SyntheticEnvironment {
|
pub struct SyntheticEnvironment {
|
||||||
persisted_ir_variables: Vec<IrVariable>,
|
ir_stack_frame_variables: IrStackFrameVariables,
|
||||||
persisted_symbols_to_variables: HashMap<SymbolId, IrVariableId>,
|
symbols_to_variables: HashMap<SymbolId, IrVariable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyntheticEnvironment {
|
impl SyntheticEnvironment {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
persisted_ir_variables: Vec::new(),
|
ir_stack_frame_variables: IrStackFrameVariables::new(),
|
||||||
persisted_symbols_to_variables: HashMap::new(),
|
symbols_to_variables: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persisted_ir_variables(&self) -> &[IrVariable] {
|
pub fn ir_stack_frame_variables(&self) -> &IrStackFrameVariables {
|
||||||
&self.persisted_ir_variables
|
&self.ir_stack_frame_variables
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persisted_ir_variables_mut(&mut self) -> &mut Vec<IrVariable> {
|
pub fn ir_stack_frame_variables_mut(&mut self) -> &mut IrStackFrameVariables {
|
||||||
&mut self.persisted_ir_variables
|
&mut self.ir_stack_frame_variables
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persisted_symbols_to_variables(&self) -> &HashMap<SymbolId, IrVariableId> {
|
pub fn symbols_to_variables(&self) -> &HashMap<SymbolId, IrVariable> {
|
||||||
&self.persisted_symbols_to_variables
|
&self.symbols_to_variables
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persisted_symbols_to_variables_mut(&mut self) -> &mut HashMap<SymbolId, IrVariableId> {
|
pub fn symbols_to_variables_mut(&mut self) -> &mut HashMap<SymbolId, IrVariable> {
|
||||||
&mut self.persisted_symbols_to_variables
|
&mut self.symbols_to_variables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
mod util;
|
pub mod util;
|
||||||
|
|
||||||
use crate::SyntheticFunctionSession;
|
use crate::SyntheticFunctionSession;
|
||||||
use crate::ast::assign_statement::AssignStatement;
|
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_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};
|
||||||
@ -50,11 +51,14 @@ pub fn lower_to_ir_synthetic_function(
|
|||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
session: &SyntheticFunctionSession,
|
session: &SyntheticFunctionSession,
|
||||||
) -> IrFunction {
|
) -> 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,
|
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);
|
lower_to_ir_statement(statement, &session.ctx, &mut fn_ctx, true);
|
||||||
fn_ctx.finish_block();
|
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(
|
IrFunction::new(
|
||||||
session.fqn.clone(),
|
session.fqn.clone(),
|
||||||
fn_ctx.storage_env_mut().take_parameters(),
|
storage_env.take_parameters(),
|
||||||
fn_ctx.storage_env_mut().take_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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LowerToIrFunctionContext {
|
struct LowerToIrFunctionContext<'a> {
|
||||||
storage_env: Box<StorageEnvironment>,
|
storage_env: &'a mut StorageEnvironment,
|
||||||
blocks: Vec<IrBlock>,
|
blocks: Vec<IrBlock>,
|
||||||
current_block_statements: Vec<IrStatement>,
|
current_block_statements: Vec<IrStatement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LowerToIrFunctionContext {
|
impl<'a> LowerToIrFunctionContext<'a> {
|
||||||
fn new(storage_env: StorageEnvironment) -> Self {
|
fn new(storage_env: &'a mut StorageEnvironment) -> Self {
|
||||||
Self {
|
Self {
|
||||||
storage_env: storage_env.into(),
|
storage_env,
|
||||||
blocks: Vec::new(),
|
blocks: Vec::new(),
|
||||||
current_block_statements: Vec::new(),
|
current_block_statements: Vec::new(),
|
||||||
}
|
}
|
||||||
@ -109,17 +115,18 @@ impl LowerToIrFunctionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn storage_env(&self) -> &StorageEnvironment {
|
fn storage_env(&self) -> &StorageEnvironment {
|
||||||
&*self.storage_env
|
self.storage_env
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage_env_mut(&mut self) -> &mut StorageEnvironment {
|
fn storage_env_mut(&mut self) -> &mut StorageEnvironment {
|
||||||
&mut *self.storage_env
|
self.storage_env
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StorageEnvironment {
|
struct StorageEnvironment {
|
||||||
ir_variables: Vec<IrVariable>,
|
ir_stack_frame_variables: IrStackFrameVariables,
|
||||||
symbols_to_variables: HashMap<SymbolId, IrVariableId>,
|
ir_free_variables: IrFreeVariables,
|
||||||
|
symbols_to_variables: HashMap<SymbolId, IrVariable>,
|
||||||
current_parameter_stack_offset: isize,
|
current_parameter_stack_offset: isize,
|
||||||
ir_parameters: Vec<IrParameter>,
|
ir_parameters: Vec<IrParameter>,
|
||||||
symbols_to_parameters: HashMap<SymbolId, IrParameterId>,
|
symbols_to_parameters: HashMap<SymbolId, IrParameterId>,
|
||||||
@ -129,7 +136,8 @@ struct StorageEnvironment {
|
|||||||
impl StorageEnvironment {
|
impl StorageEnvironment {
|
||||||
fn new(parameter_count: usize) -> Self {
|
fn new(parameter_count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ir_variables: Vec::new(),
|
ir_stack_frame_variables: IrStackFrameVariables::new(),
|
||||||
|
ir_free_variables: IrFreeVariables::new(),
|
||||||
symbols_to_variables: HashMap::new(),
|
symbols_to_variables: HashMap::new(),
|
||||||
current_parameter_stack_offset: (parameter_count as isize).neg(),
|
current_parameter_stack_offset: (parameter_count as isize).neg(),
|
||||||
ir_parameters: Vec::new(),
|
ir_parameters: Vec::new(),
|
||||||
@ -138,15 +146,17 @@ impl StorageEnvironment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated]
|
fn session_new(
|
||||||
fn with_persisted_variables(
|
ir_stack_frame_variables: &IrStackFrameVariables,
|
||||||
|
ir_free_variables: &IrFreeVariables,
|
||||||
|
session_symbols_to_variables: &HashMap<SymbolId, IrVariable>,
|
||||||
parameter_count: usize,
|
parameter_count: usize,
|
||||||
persisted_ir_variables: &[IrVariable],
|
|
||||||
persisted_symbols_to_variables: &HashMap<SymbolId, IrVariableId>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut this = Self::new(parameter_count);
|
let mut this = Self::new(parameter_count);
|
||||||
this.ir_variables = persisted_ir_variables.to_vec();
|
this.ir_stack_frame_variables = ir_stack_frame_variables.clone();
|
||||||
this.symbols_to_variables = persisted_symbols_to_variables.clone();
|
this.ir_free_variables = ir_free_variables.clone();
|
||||||
|
this.symbols_to_variables
|
||||||
|
.extend(session_symbols_to_variables.clone()); // hopefully not costly
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,55 +190,57 @@ impl StorageEnvironment {
|
|||||||
ir_parameter_id
|
ir_parameter_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_variable(&mut self, name: &str, ir_type_info: IrTypeInfo) -> IrVariableId {
|
fn new_free_variable(&mut self, name: &str, ir_type_info: IrTypeInfo) -> IrVariable {
|
||||||
let ir_variable = IrVariable::new(name, ir_type_info);
|
let ir_variable_info = IrVariableInfo::new(name.into(), ir_type_info);
|
||||||
self.ir_variables.push(ir_variable);
|
let ir_free_variable_id = self.ir_free_variables.push(ir_variable_info);
|
||||||
self.ir_variables.len() - 1
|
IrVariable::Free(ir_free_variable_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_variable_for(
|
fn new_free_variable_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
ir_type_info: IrTypeInfo,
|
ir_type_info: IrTypeInfo,
|
||||||
symbol_id: SymbolId,
|
symbol_id: SymbolId,
|
||||||
) -> IrVariableId {
|
) -> IrVariable {
|
||||||
let ir_variable_id = self.new_variable(name, ir_type_info);
|
let ir_variable = self.new_free_variable(name, ir_type_info);
|
||||||
self.symbols_to_variables.insert(symbol_id, ir_variable_id);
|
self.symbols_to_variables
|
||||||
ir_variable_id
|
.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();
|
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
|
self.symbols_to_variables
|
||||||
.get(&symbol_id)
|
.get(&symbol_id)
|
||||||
.cloned()
|
|
||||||
.expect(&format!("No ir_variable for symbol_id {}", symbol_id))
|
.expect(&format!("No ir_variable for symbol_id {}", symbol_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_get_variable_for(&self, symbol_id: SymbolId) -> Option<IrVariableId> {
|
fn maybe_get_variable_for(&self, symbol_id: SymbolId) -> Option<&IrVariable> {
|
||||||
self.symbols_to_variables.get(&symbol_id).cloned()
|
self.symbols_to_variables.get(&symbol_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_get_parameter_for(&self, symbol_id: SymbolId) -> Option<IrParameterId> {
|
fn maybe_get_parameter_for(&self, symbol_id: SymbolId) -> Option<IrParameterId> {
|
||||||
self.symbols_to_parameters.get(&symbol_id).cloned()
|
self.symbols_to_parameters.get(&symbol_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_variables(&mut self) -> Vec<IrVariable> {
|
|
||||||
std::mem::take(&mut self.ir_variables)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_parameters(&mut self) -> Vec<IrParameter> {
|
fn take_parameters(&mut self) -> Vec<IrParameter> {
|
||||||
std::mem::take(&mut self.ir_parameters)
|
std::mem::take(&mut self.ir_parameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunction {
|
fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunction {
|
||||||
let mut fn_ctx =
|
let mut storage_env = StorageEnvironment::session_new(
|
||||||
LowerToIrFunctionContext::new(StorageEnvironment::new(function.parameters().len()));
|
&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);
|
||||||
|
|
||||||
@ -257,12 +269,14 @@ fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunctio
|
|||||||
}
|
}
|
||||||
fn_ctx.finish_block();
|
fn_ctx.finish_block();
|
||||||
|
|
||||||
|
let blocks = std::mem::take(&mut fn_ctx.blocks);
|
||||||
IrFunction::new(
|
IrFunction::new(
|
||||||
function_symbol.fqn_owned(),
|
function_symbol.fqn_owned(),
|
||||||
fn_ctx.storage_env_mut().take_parameters(),
|
storage_env.take_parameters(),
|
||||||
fn_ctx.storage_env_mut().take_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),
|
||||||
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_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 destination_ir_variable_id = fn_ctx.storage_env_mut().new_variable_for(
|
// 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(),
|
let_statement.declared_name(),
|
||||||
to_ir_type_info(type_info),
|
to_ir_type_info(type_info),
|
||||||
symbol_id,
|
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(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);
|
let ir_statement = IrStatement::Assign(ir_assign);
|
||||||
fn_ctx.current_block_statements.push(ir_statement);
|
fn_ctx.current_block_statements.push(ir_statement);
|
||||||
}
|
}
|
||||||
@ -377,12 +399,14 @@ fn lower_to_ir_assign_statement(
|
|||||||
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 =
|
let destination_ir_variable = fn_ctx
|
||||||
fn_ctx.storage_env().get_variable_for(destination_symbol_id);
|
.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);
|
||||||
}
|
}
|
||||||
@ -417,9 +441,9 @@ 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 =
|
let identifier_ir_variable =
|
||||||
fn_ctx.storage_env().get_variable_for(identifier_symbol_id);
|
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)
|
IrOperation::Load(ir_expression)
|
||||||
}
|
}
|
||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
@ -453,18 +477,18 @@ 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
|
let destination_ir_variable = fn_ctx
|
||||||
.storage_env_mut()
|
.storage_env_mut()
|
||||||
.new_t_var(to_ir_type_info(result_type_info));
|
.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 =
|
||||||
@ -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_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
|
let destination_ir_variable = fn_ctx
|
||||||
.storage_env_mut()
|
.storage_env_mut()
|
||||||
.new_t_var(to_ir_type_info(result_type_info));
|
.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
|
// 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);
|
||||||
@ -495,26 +519,26 @@ fn lower_expression_to_ir_expression(
|
|||||||
// 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 t_var_ir_variable_id = fn_ctx
|
let t_var_ir_variable = fn_ctx
|
||||||
.storage_env_mut()
|
.storage_env_mut()
|
||||||
.new_t_var(to_ir_type_info(return_type_info));
|
.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) =
|
if let Some(rhs_ir_variable) =
|
||||||
fn_ctx.storage_env().maybe_get_variable_for(rhs_symbol_id)
|
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) =
|
} else if let Some(rhs_ir_parameter_id) =
|
||||||
fn_ctx.storage_env().maybe_get_parameter_for(rhs_symbol_id)
|
fn_ctx.storage_env().maybe_get_parameter_for(rhs_symbol_id)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user