diff --git a/dm/src/main.rs b/dm/src/main.rs index 0f9b865..29c0529 100644 --- a/dm/src/main.rs +++ b/dm/src/main.rs @@ -4,16 +4,15 @@ use codespan_reporting::files::SimpleFiles; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use dm_std_lib::add_all_std_core; -use dmc_lib::ast::module_level_declaration::ModuleLevelDeclaration; use dmc_lib::constants_table::ConstantsTable; use dmc_lib::diagnostic::Diagnostic; use dmc_lib::parser::parse_compilation_unit; use dmc_lib::symbol_table::SymbolTable; use dvm_lib::vm::constant::{Constant, StringConstant}; +use dvm_lib::vm::function::Function; use dvm_lib::vm::value::Value; use dvm_lib::vm::{CallStack, DvmContext, call}; use std::path::PathBuf; -use std::rc::Rc; #[derive(Debug, Parser)] #[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)] @@ -57,23 +56,28 @@ fn main() { let type_check_diagnostics = compilation_unit.type_check(&symbol_table); check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics); + let mut ir_functions = compilation_unit.to_ir(&symbol_table); + if args.show_ir { - for declaration in compilation_unit.declarations() { - if let ModuleLevelDeclaration::Function(function) = declaration { - let mut ir_function = function.to_ir(&symbol_table); - let register_assignments = ir_function.assign_registers(args.register_count); - println!("{}", ir_function); - println!("{:?}", register_assignments); - } + for ir_function in &ir_functions { + println!("{}", ir_function); } } + for ir_function in &mut ir_functions { + ir_function.assign_registers(args.register_count); + } + let mut constants_table = ConstantsTable::new(); - let asm_functions = compilation_unit.assemble(&symbol_table, &mut constants_table); + + let functions: Vec = ir_functions + .iter() + .map(|ir_function| ir_function.assemble(&mut constants_table)) + .collect(); if args.show_asm { - for asm_function in &asm_functions { - println!("{:#?}", asm_function); + for function in &functions { + println!("{}", function); } } @@ -82,19 +86,20 @@ fn main() { // add std::core fns add_all_std_core(&mut dvm_context); - for asm_function in &asm_functions { - let function = asm_function.dvm(); - dvm_context.add_function(function); + for function in functions { + dvm_context + .functions_mut() + .insert(function.name_owned(), function); } for (name, content) in &constants_table.string_constants() { - dvm_context.add_constant(Constant::String(StringConstant::new( - Rc::from(name.clone()), - content.as_str(), - ))); + dvm_context.constants_mut().insert( + name.clone(), + Constant::String(StringConstant::new(name.clone(), content.clone())), + ); } - let mut registers: Vec = vec![]; + let mut registers: Vec = vec![Value::Null; args.register_count]; let mut call_stack = CallStack::new(); let result = call( diff --git a/dmc-lib/src/asm/asm_block.rs b/dmc-lib/src/asm/asm_block.rs deleted file mode 100644 index e0e3123..0000000 --- a/dmc-lib/src/asm/asm_block.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::asm::asm_instruction::AsmInstruction; - -#[derive(Debug)] -pub struct AsmBlock { - name: String, - instructions: Vec, -} - -impl AsmBlock { - pub fn new(name: &str, instructions: Vec) -> Self { - Self { - name: name.into(), - instructions, - } - } - - pub fn instructions(&self) -> &[AsmInstruction] { - &self.instructions - } -} diff --git a/dmc-lib/src/asm/asm_function.rs b/dmc-lib/src/asm/asm_function.rs deleted file mode 100644 index 6ee7ed7..0000000 --- a/dmc-lib/src/asm/asm_function.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::asm::asm_block::AsmBlock; -use crate::asm::asm_instruction::AsmInstruction; -use dvm_lib::vm::function::Function; - -#[derive(Debug)] -pub struct AsmFunction { - name: String, - blocks: Vec, -} - -impl AsmFunction { - pub fn new(name: &str, blocks: Vec) -> Self { - Self { - name: name.into(), - blocks, - } - } - - pub fn dvm(&self) -> Function { - // very naive impl - let dvm_instructions = self - .blocks - .iter() - .flat_map(|block| block.instructions().iter().map(AsmInstruction::dvm)) - .collect::>(); - - Function::new(&self.name, dvm_instructions, 16) - } -} diff --git a/dmc-lib/src/asm/asm_instruction.rs b/dmc-lib/src/asm/asm_instruction.rs deleted file mode 100644 index afc9f56..0000000 --- a/dmc-lib/src/asm/asm_instruction.rs +++ /dev/null @@ -1,217 +0,0 @@ -use dvm_lib::instruction::Instruction; -use std::rc::Rc; - -#[derive(Debug)] -pub enum AsmInstruction { - Move(Move), - Push(Push), - Pop(Pop), - InvokeStatic(InvokeStatic), - InvokePlatformStatic(InvokePlatformStatic), - LoadConstant(LoadConstant), - Add(Add), - SetReturnValue(SetReturnValue), - Return(Return), -} - -impl AsmInstruction { - pub fn dvm(&self) -> Instruction { - match self { - AsmInstruction::Move(asm_move) => asm_move.dvm(), - AsmInstruction::Push(push) => push.dvm(), - AsmInstruction::Pop(pop) => pop.dvm(), - AsmInstruction::InvokeStatic(invoke_static) => invoke_static.dvm(), - AsmInstruction::InvokePlatformStatic(invoke_platform_static) => { - invoke_platform_static.dvm() - } - AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(), - AsmInstruction::Add(add) => add.dvm(), - AsmInstruction::SetReturnValue(set_return_value) => set_return_value.dvm(), - AsmInstruction::Return(asm_return) => asm_return.dvm(), - } - } -} - -#[derive(Debug)] -pub enum Operand { - IntegerLiteral(i32), - Register(usize), - StackFrameOffset(isize), -} - -#[derive(Debug)] -pub struct Move { - source: Operand, - destination_register: usize, -} - -impl Move { - pub fn new(source: Operand, destination_register: usize) -> Self { - Self { - source, - destination_register, - } - } - - pub fn dvm(&self) -> Instruction { - match self.source { - Operand::IntegerLiteral(i) => Instruction::MoveInt(i, self.destination_register), - Operand::Register(register) => { - Instruction::MoveRegister(register, self.destination_register) - } - Operand::StackFrameOffset(offset) => { - Instruction::MoveStackFrameOffset(offset, self.destination_register) - } - } - } -} - -#[derive(Debug)] -pub struct Push { - source: Operand, -} - -impl Push { - pub fn new(source: Operand) -> Self { - Self { source } - } - - pub fn dvm(&self) -> Instruction { - match self.source { - Operand::IntegerLiteral(i) => Instruction::PushInt(i), - Operand::Register(register) => Instruction::PushRegister(register), - Operand::StackFrameOffset(offset) => Instruction::PushStackFrameOffset(offset), - } - } -} - -#[derive(Debug)] -pub struct Pop { - destination_register: Option, -} - -impl Pop { - pub fn new(destination_register: usize) -> Self { - Self { - destination_register: Some(destination_register), - } - } - - pub fn empty() -> Self { - Self { - destination_register: None, - } - } - - pub fn dvm(&self) -> Instruction { - Instruction::Pop(self.destination_register) - } -} - -#[derive(Debug)] -pub struct InvokeStatic { - name: String, - arg_count: usize, -} - -impl InvokeStatic { - pub fn new(name: &str, arg_count: usize) -> Self { - Self { - name: name.into(), - arg_count, - } - } - - pub fn dvm(&self) -> Instruction { - Instruction::InvokeStatic(Rc::from(self.name.clone()), self.arg_count) - } -} - -#[derive(Debug)] -pub struct InvokePlatformStatic { - name: String, - arg_count: usize, -} - -impl InvokePlatformStatic { - pub fn new(name: &str, arg_count: usize) -> Self { - Self { - name: name.into(), - arg_count, - } - } - - pub fn dvm(&self) -> Instruction { - Instruction::InvokePlatformStatic(Rc::from(self.name.clone()), self.arg_count) - } -} - -#[derive(Debug)] -pub struct LoadConstant { - name: String, - destination_register: usize, -} - -impl LoadConstant { - pub fn new(name: &str, destination_register: usize) -> Self { - LoadConstant { - name: name.into(), - destination_register, - } - } - - pub fn dvm(&self) -> Instruction { - Instruction::LoadStringConstant(Rc::from(self.name.clone()), self.destination_register) - } -} - -#[derive(Debug)] -pub enum Add { - IntInt(usize, usize, usize), - StringString(usize, usize, usize), - StringInt(usize, usize, usize), -} - -impl Add { - pub fn dvm(&self) -> Instruction { - match self { - Add::IntInt(lhs, rhs, destination) => Instruction::AddIntInt(*lhs, *rhs, *destination), - Add::StringString(lhs, rhs, destination) => { - Instruction::AddStringString(*lhs, *rhs, *destination) - } - Add::StringInt(lhs, rhs, destination) => { - Instruction::AddStringInt(*lhs, *rhs, *destination) - } - } - } -} - -#[derive(Debug)] -pub struct SetReturnValue { - source_register: usize, -} - -impl SetReturnValue { - pub fn new(source_register: usize) -> Self { - Self { source_register } - } - - pub fn dvm(&self) -> Instruction { - Instruction::SetReturnValue(self.source_register) - } -} - -#[derive(Debug)] -pub struct Return { - caller_pop_count: usize, -} - -impl Return { - pub fn new(caller_pop_count: usize) -> Self { - Self { caller_pop_count } - } - - pub fn dvm(&self) -> Instruction { - Instruction::Return(self.caller_pop_count) - } -} diff --git a/dmc-lib/src/asm/mod.rs b/dmc-lib/src/asm/mod.rs deleted file mode 100644 index b3359bb..0000000 --- a/dmc-lib/src/asm/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -pub mod asm_block; -pub mod asm_function; -pub mod asm_instruction; - -#[cfg(test)] -mod smoke_tests { - use crate::asm::asm_function::AsmFunction; - use crate::constants_table::ConstantsTable; - use crate::parser::parse_compilation_unit; - use crate::symbol_table::SymbolTable; - - fn assemble(src: &str) -> Vec { - let parse_result = parse_compilation_unit(src); - let mut compilation_unit = match parse_result { - Ok(compilation_unit) => compilation_unit, - Err(diagnostics) => { - for diagnostic in diagnostics { - eprintln!("{:?}", diagnostic); - } - panic!(); - } - }; - let mut symbol_table = SymbolTable::new(); - compilation_unit.gather_declared_names(&mut symbol_table); - compilation_unit.check_name_usages(&symbol_table); - compilation_unit.type_check(&symbol_table); - compilation_unit.assemble(&symbol_table, &mut ConstantsTable::new()) - } - - #[test] - fn multiple_statements() { - let asm_functions = assemble( - " - extern fn println() -> Void - fn main() - let x = 42 - println(x) - println(16) - let y = \"Hello, World!\" - println(y) - end", - ); - for asm_function in &asm_functions { - println!("{:#?}", asm_function); - } - } -} diff --git a/dmc-lib/src/ast/additive_expression.rs b/dmc-lib/src/ast/additive_expression.rs index 9008296..856933c 100644 --- a/dmc-lib/src/ast/additive_expression.rs +++ b/dmc-lib/src/ast/additive_expression.rs @@ -1,21 +1,10 @@ -use crate::asm::asm_instruction::{Add, AsmInstruction, LoadConstant, Move, Operand, Pop}; -use crate::ast::assemble_context::AssembleContext; -use crate::ast::ast_to_ir_util::expression_to_ir_expression; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_add::IrAdd; -use crate::ir::ir_assign::IrAssign; -use crate::ir::ir_expression::IrExpression; -use crate::ir::ir_operation::IrOperation; -use crate::ir::ir_statement::IrStatement; -use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; -use crate::symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; -use std::ops::Deref; pub struct AdditiveExpression { lhs: Box, @@ -75,111 +64,17 @@ impl AdditiveExpression { } pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrAdd { - let lhs_ir_expression = expression_to_ir_expression(&self.lhs, builder, symbol_table) + let lhs_ir_expression = self + .lhs + .to_ir(builder, symbol_table) .expect("Attempt to add non-expression"); - let rhs_ir_expression = expression_to_ir_expression(&self.rhs, builder, symbol_table) + let rhs_ir_expression = self + .rhs + .to_ir(builder, symbol_table) .expect("Attempt to add non-expression"); IrAdd::new(lhs_ir_expression, rhs_ir_expression) } - fn assemble_side( - expression: &Expression, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) -> usize { - match expression { - Expression::Call(call) => { - call.assemble(context, symbol_table, constants_table); - let register = context.new_local_register(); - context.instruction(AsmInstruction::Pop(Pop::new(register))); - register - } - Expression::IntegerLiteral(integer_literal) => { - let register = context.new_local_register(); - context.instruction(AsmInstruction::Move(Move::new( - Operand::IntegerLiteral(integer_literal.value()), - register, - ))); - register - } - Expression::String(string_literal) => { - let register = context.new_local_register(); - let constant_name = constants_table.insert_string(string_literal.content()); - context.instruction(AsmInstruction::LoadConstant(LoadConstant::new( - &constant_name, - register, - ))); - register - } - Expression::Identifier(identifier) => { - let register = context.new_local_register(); - match identifier.expressible_symbol() { - ExpressibleSymbol::Function(_) => unreachable!(), - ExpressibleSymbol::Parameter(parameter_symbol) => { - let offset = parameter_symbol.borrow().stack_frame_offset(); - context.instruction(AsmInstruction::Move(Move::new( - Operand::StackFrameOffset(offset), - register, - ))); - } - ExpressibleSymbol::Variable(variable_symbol) => { - context.instruction(AsmInstruction::Move(Move::new( - Operand::Register(variable_symbol.borrow().register()), - register, - ))); - } - } - register - } - Expression::Additive(additive_expression) => { - additive_expression.assemble(context, symbol_table, constants_table) - } - } - } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) -> usize { - let lhs_register = Self::assemble_side(&self.lhs, context, symbol_table, constants_table); - let rhs_register = Self::assemble_side(&self.rhs, context, symbol_table, constants_table); - let result_register = context.new_local_register(); - match self.lhs.type_info() { - TypeInfo::Integer => match self.rhs.type_info() { - TypeInfo::Integer => { - context.instruction(AsmInstruction::Add(Add::IntInt( - lhs_register, - rhs_register, - result_register, - ))); - } - _ => unreachable!(), - }, - TypeInfo::String => match self.rhs.type_info() { - TypeInfo::Integer => { - context.instruction(AsmInstruction::Add(Add::StringInt( - lhs_register, - rhs_register, - result_register, - ))); - } - TypeInfo::String => { - context.instruction(AsmInstruction::Add(Add::StringString( - lhs_register, - rhs_register, - result_register, - ))); - } - _ => unreachable!(), - }, - _ => unreachable!(), - } - result_register - } - pub fn type_info(&self) -> TypeInfo { self.lhs.type_info().additive_result(&self.rhs.type_info()) } diff --git a/dmc-lib/src/ast/assemble_context.rs b/dmc-lib/src/ast/assemble_context.rs deleted file mode 100644 index 7343369..0000000 --- a/dmc-lib/src/ast/assemble_context.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::asm::asm_block::AsmBlock; -use crate::asm::asm_function::AsmFunction; -use crate::asm::asm_instruction::AsmInstruction; -use crate::source_range::SourceRange; - -pub struct AssembleContext { - functions: Vec, - current_function: Option, -} - -impl AssembleContext { - pub fn new() -> Self { - Self { - functions: vec![], - current_function: None, - } - } - - pub fn take_functions(&mut self) -> Vec { - std::mem::take(&mut self.functions) - } - - pub fn new_function(&mut self, name: &str, source_range: &SourceRange) { - self.current_function = Some(FunctionAssembler::new(name, source_range)); - } - - pub fn complete_function(&mut self) { - let mut function_assembler = self.current_function.take().unwrap(); - function_assembler.complete_block(); - let asm_function = function_assembler.result(); - self.functions.push(asm_function); - } - - pub fn new_block(&mut self, name: &str) { - self.current_function.as_mut().unwrap().new_block(name); - } - - pub fn new_local_register(&mut self) -> usize { - self.current_function.as_mut().unwrap().new_local_register() - } - - pub fn instruction(&mut self, to_add: AsmInstruction) { - self.current_function.as_mut().unwrap().instruction(to_add); - } -} - -struct FunctionAssembler { - name: String, - source_range: SourceRange, - blocks: Vec, - current_block: Option, - local_register_counter: usize, -} - -impl FunctionAssembler { - fn new(name: &str, source_range: &SourceRange) -> Self { - Self { - name: name.into(), - source_range: source_range.clone(), - blocks: vec![], - current_block: None, - local_register_counter: 0, - } - } - - fn new_block(&mut self, name: &str) { - let maybe_block_assembler = self.current_block.take(); - if let Some(mut block_assembler) = maybe_block_assembler { - self.blocks.push(block_assembler.result()); - } - self.current_block = Some(BlockAssembler::new(name)) - } - - fn complete_block(&mut self) { - let mut block_assembler = self.current_block.take().unwrap(); - self.blocks.push(block_assembler.result()); - } - - fn result(&mut self) -> AsmFunction { - AsmFunction::new(&self.name, std::mem::take(&mut self.blocks)) - } - - fn new_local_register(&mut self) -> usize { - let register = self.local_register_counter; - self.local_register_counter += 1; - register - } - - fn instruction(&mut self, to_add: AsmInstruction) { - self.current_block.as_mut().unwrap().instruction(to_add); - } -} - -struct BlockAssembler { - name: String, - instructions: Vec, -} - -impl BlockAssembler { - fn new(name: &str) -> Self { - Self { - name: name.into(), - instructions: vec![], - } - } - - fn instruction(&mut self, to_add: AsmInstruction) { - self.instructions.push(to_add); - } - - fn result(&mut self) -> AsmBlock { - AsmBlock::new(&self.name, std::mem::take(&mut self.instructions)) - } -} diff --git a/dmc-lib/src/ast/ast_to_ir_util.rs b/dmc-lib/src/ast/ast_to_ir_util.rs deleted file mode 100644 index 9c0dfc1..0000000 --- a/dmc-lib/src/ast/ast_to_ir_util.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::ast::expression::Expression; -use crate::ast::ir_builder::IrBuilder; -use crate::ir::ir_assign::IrAssign; -use crate::ir::ir_expression::IrExpression; -use crate::ir::ir_operation::IrOperation; -use crate::ir::ir_statement::IrStatement; -use crate::ir::ir_variable::IrVariable; -use crate::symbol_table::SymbolTable; -use crate::type_info::TypeInfo; -use std::cell::RefCell; -use std::rc::Rc; - -pub fn expression_to_ir_expression( - expression: &Expression, - builder: &mut IrBuilder, - symbol_table: &SymbolTable, -) -> Option { - match expression { - Expression::Call(call) => { - let ir_call = call.to_ir(builder, symbol_table); - if matches!(call.type_info(), TypeInfo::Void) { - builder - .current_block_mut() - .add_statement(IrStatement::Call(ir_call)); - None - } else { - let t_var = IrVariable::new_vr( - builder.new_t_var().into(), - builder.current_block().id(), - call.type_info(), - ); - let as_rc = Rc::new(RefCell::new(t_var)); - let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call)); - builder - .current_block_mut() - .add_statement(IrStatement::Assign(assign)); - Some(IrExpression::Variable(as_rc)) - } - } - Expression::IntegerLiteral(integer_literal) => { - Some(IrExpression::Int(integer_literal.value())) - } - Expression::String(string_literal) => { - Some(IrExpression::String(string_literal.content().into())) - } - Expression::Identifier(identifier) => { - let expressible_symbol = identifier.expressible_symbol(); - Some(expressible_symbol.ir_expression()) - } - Expression::Additive(additive_expression) => { - let ir_add = additive_expression.to_ir(builder, symbol_table); - let t_var = IrVariable::new_vr( - builder.new_t_var().into(), - builder.current_block().id(), - additive_expression.type_info(), - ); - let as_rc = Rc::new(RefCell::new(t_var)); - let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add)); - builder - .current_block_mut() - .add_statement(IrStatement::Assign(assign)); - Some(IrExpression::Variable(as_rc)) - } - } -} diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index aa0c235..1b88cbd 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -1,11 +1,5 @@ -use crate::asm::asm_instruction::{ - AsmInstruction, InvokePlatformStatic, InvokeStatic, LoadConstant, Operand, Push, -}; -use crate::ast::assemble_context::AssembleContext; -use crate::ast::ast_to_ir_util::expression_to_ir_expression; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; @@ -144,7 +138,7 @@ impl Call { let arguments: Vec = self .arguments .iter() - .map(|argument| expression_to_ir_expression(argument, builder, symbol_table)) + .map(|argument| argument.to_ir(builder, symbol_table)) .inspect(|expression| { if expression.is_none() { panic!("Attempt to pass non-expression") @@ -153,88 +147,11 @@ impl Call { .map(Option::unwrap) .collect(); let function_symbol = self.get_callee_symbol(); - IrCall::new(function_symbol.borrow().name_owned(), arguments) - } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) { - // push all args - for argument in &self.arguments { - match argument { - Expression::Call(call) => { - call.assemble(context, symbol_table, constants_table); // will leave return val on stack - } - Expression::IntegerLiteral(integer_literal) => { - context.instruction(AsmInstruction::Push(Push::new(Operand::IntegerLiteral( - integer_literal.value(), - )))); - } - Expression::String(string_literal) => { - let name = constants_table.insert_string(string_literal.content()); - let temp_register = context.new_local_register(); - context.instruction(AsmInstruction::LoadConstant(LoadConstant::new( - &name, - temp_register, - ))); - context.instruction(AsmInstruction::Push(Push::new(Operand::Register( - temp_register, - )))); - } - Expression::Identifier(identifier) => match identifier.expressible_symbol() { - ExpressibleSymbol::Function(_) => { - panic!("Pushing function symbols not supported.") - } - ExpressibleSymbol::Parameter(parameter_symbol) => { - context.instruction(AsmInstruction::Push(Push::new( - Operand::StackFrameOffset( - parameter_symbol.borrow().stack_frame_offset(), - ), - ))); - } - ExpressibleSymbol::Variable(variable_symbol) => { - context.instruction(AsmInstruction::Push(Push::new(Operand::Register( - variable_symbol.borrow().register(), - )))) - } - }, - Expression::Additive(additive_expression) => { - let result_register = - additive_expression.assemble(context, symbol_table, constants_table); - context.instruction(AsmInstruction::Push(Push::new(Operand::Register( - result_register, - )))); - } - } - } - - let function_symbol = match self.callee() { - Expression::Identifier(identifier) => { - let expressible_symbol = identifier.expressible_symbol(); - match expressible_symbol { - ExpressibleSymbol::Function(function_symbol) => function_symbol.clone(), - _ => panic!("Calling things other than functions not yet supported."), - } - } - _ => panic!("Calling things other than identifiers not yet supported."), - }; - - let function_symbol = function_symbol.borrow(); - if function_symbol.is_platform() { - let arg_count = function_symbol.parameters().len(); - context.instruction(AsmInstruction::InvokePlatformStatic( - InvokePlatformStatic::new(function_symbol.name(), arg_count), - )); - } else { - let arg_count = function_symbol.parameters().len(); - context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new( - function_symbol.name(), - arg_count, - ))); - } + IrCall::new( + function_symbol.borrow().name_owned(), + arguments, + function_symbol.clone(), + ) } pub fn source_range(&self) -> &SourceRange { diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index 48a371e..1c8aaa1 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -1,8 +1,6 @@ -use crate::asm::asm_function::AsmFunction; -use crate::ast::assemble_context::AssembleContext; use crate::ast::module_level_declaration::ModuleLevelDeclaration; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; +use crate::ir::ir_function::IrFunction; use crate::symbol_table::SymbolTable; pub struct CompilationUnit { @@ -44,15 +42,13 @@ impl CompilationUnit { diagnostics } - pub fn assemble( - &self, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) -> Vec { - let mut context = AssembleContext::new(); + pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec { + let mut ir_functions = vec![]; for declaration in &self.declarations { - declaration.assemble(&mut context, symbol_table, constants_table); + if let ModuleLevelDeclaration::Function(function) = declaration { + ir_functions.push(function.to_ir(symbol_table)); + } } - context.take_functions() + ir_functions } } diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 038685c..3ad63da 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -2,11 +2,19 @@ use crate::ast::additive_expression::AdditiveExpression; use crate::ast::call::Call; use crate::ast::identifier::Identifier; use crate::ast::integer_literal::IntegerLiteral; +use crate::ast::ir_builder::IrBuilder; use crate::ast::string_literal::StringLiteral; use crate::diagnostic::Diagnostic; +use crate::ir::ir_assign::IrAssign; +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_operation::IrOperation; +use crate::ir::ir_statement::IrStatement; +use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; +use std::cell::RefCell; +use std::rc::Rc; pub enum Expression { Call(Call), @@ -83,4 +91,58 @@ impl Expression { Expression::Additive(additive_expression) => additive_expression.source_range(), } } + + pub fn to_ir( + &self, + builder: &mut IrBuilder, + symbol_table: &SymbolTable, + ) -> Option { + match self { + Expression::Call(call) => { + let ir_call = call.to_ir(builder, symbol_table); + if matches!(call.type_info(), TypeInfo::Void) { + builder + .current_block_mut() + .add_statement(IrStatement::Call(ir_call)); + None + } else { + let t_var = IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + call.type_info(), + ); + let as_rc = Rc::new(RefCell::new(t_var)); + let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call)); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(assign)); + Some(IrExpression::Variable(as_rc)) + } + } + Expression::IntegerLiteral(integer_literal) => { + Some(IrExpression::Int(integer_literal.value())) + } + Expression::String(string_literal) => { + Some(IrExpression::String(string_literal.content().into())) + } + Expression::Identifier(identifier) => { + let expressible_symbol = identifier.expressible_symbol(); + Some(expressible_symbol.ir_expression()) + } + Expression::Additive(additive_expression) => { + let ir_add = additive_expression.to_ir(builder, symbol_table); + let t_var = IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + additive_expression.type_info(), + ); + let as_rc = Rc::new(RefCell::new(t_var)); + let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add)); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(assign)); + Some(IrExpression::Variable(as_rc)) + } + } + } } diff --git a/dmc-lib/src/ast/expression_statement.rs b/dmc-lib/src/ast/expression_statement.rs index d76e600..6c5878b 100644 --- a/dmc-lib/src/ast/expression_statement.rs +++ b/dmc-lib/src/ast/expression_statement.rs @@ -1,17 +1,9 @@ -use crate::asm::asm_instruction::{AsmInstruction, Pop, SetReturnValue}; -use crate::ast::assemble_context::AssembleContext; -use crate::ast::ast_to_ir_util::expression_to_ir_expression; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; -use crate::symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; -use crate::type_info::TypeInfo; -use std::cell::RefCell; -use std::rc::Rc; pub struct ExpressionStatement { expression: Box, @@ -41,50 +33,11 @@ impl ExpressionStatement { } pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable, is_last: bool) { - let ir_expression = expression_to_ir_expression(self.expression(), builder, symbol_table); + let ir_expression = self.expression.to_ir(builder, symbol_table); if ir_expression.is_some() && is_last { builder .current_block_mut() .add_statement(IrStatement::Return(IrReturn::new(ir_expression))); } } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - outer_function_symbol: &Rc>, - is_last: bool, - ) { - match self.expression.as_ref() { - Expression::Call(call) => { - call.assemble(context, symbol_table, constants_table); - // if last expression and the return value of the callee isn't void, return that - // return value - if is_last && !matches!(call.type_info(), TypeInfo::Void) { - // move to register - let return_value_register = context.new_local_register(); - context.instruction(AsmInstruction::Pop(Pop::new(return_value_register))); - - // set return value - context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new( - return_value_register, - ))); - } - } - Expression::Additive(additive) => { - let result_register = additive.assemble(context, symbol_table, constants_table); - if is_last - && !matches!(outer_function_symbol.borrow().return_type(), TypeInfo::Void) - { - // set return value - context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new( - result_register, - ))); - } - } - _ => unreachable!(), - } - } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index baac41d..13f10b3 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -1,10 +1,7 @@ -use crate::asm::asm_instruction::{AsmInstruction, Return}; -use crate::ast::assemble_context::AssembleContext; use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::ast::type_use::TypeUse; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_function::IrFunction; use crate::ir::ir_parameter::IrParameter; @@ -165,11 +162,13 @@ impl Function { let mut builder = IrBuilder::new(); // parameters - for parameter in &self.parameters { + for (i, parameter) in self.parameters.iter().enumerate() { let parameter_symbol = parameter.parameter_symbol(); + let stack_offset = (self.parameters.len() as isize).neg() + (i as isize); let ir_parameter = IrParameter::new( parameter_symbol.borrow().name(), parameter_symbol.borrow().type_info().clone(), + stack_offset, ); let as_rc = Rc::new(ir_parameter); builder.parameters_mut().push(as_rc.clone()); @@ -190,38 +189,10 @@ impl Function { .unwrap_or(TypeInfo::Void); let entry_block = builder.get_block(entry_block_id).clone(); IrFunction::new( - Rc::from(self.declared_name()), + self.function_symbol.as_ref().unwrap().clone(), builder.parameters(), return_type_info, entry_block, ) } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) { - context.new_function(&self.declared_name, &self.declared_name_source_range); - context.new_block(&format!("{}_enter", self.declared_name)); - let function_symbol = self - .function_symbol - .as_ref() - .expect("function_symbol not initialized; did you type check yet?"); - for (i, statement) in self.statements.iter().enumerate() { - let is_last = i == self.statements.len() - 1; - statement.assemble( - context, - symbol_table, - constants_table, - function_symbol, - is_last, - ); - } - // return - context.instruction(AsmInstruction::Return(Return::new(self.parameters.len()))); - - context.complete_function(); - } } diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index 270f835..b326e02 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -1,8 +1,5 @@ -use crate::asm::asm_instruction::{AsmInstruction, LoadConstant, Move, Operand, Pop}; -use crate::ast::assemble_context::AssembleContext; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; @@ -10,7 +7,7 @@ use crate::ir::ir_operation::IrOperation; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; -use crate::symbol::{ExpressibleSymbol, VariableSymbol}; +use crate::symbol::VariableSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::cell::RefCell; use std::rc::Rc; @@ -121,69 +118,4 @@ impl LetStatement { .current_block_mut() .add_statement(IrStatement::Assign(ir_assign)); } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) { - let destination_register = context.new_local_register(); - - // save register to symbol - let variable_symbol = - symbol_table.get_variable_symbol(self.scope_id.unwrap(), self.declared_name()); - variable_symbol - .borrow_mut() - .set_register(destination_register); - - match self.initializer() { - Expression::Call(call) => { - call.assemble(context, symbol_table, constants_table); - context.instruction(AsmInstruction::Pop(Pop::new(destination_register))); - } - Expression::IntegerLiteral(integer_literal) => { - context.instruction(AsmInstruction::Move(Move::new( - Operand::IntegerLiteral(integer_literal.value()), - destination_register, - ))); - } - Expression::String(string_literal) => { - let name = constants_table.insert_string(string_literal.content()); - context.instruction(AsmInstruction::LoadConstant(LoadConstant::new( - &name, - destination_register, - ))); - } - Expression::Identifier(identifier) => { - let expressible_symbol = identifier.expressible_symbol(); - match expressible_symbol { - ExpressibleSymbol::Function(_) => { - panic!("Moving functions to registers not yet supported"); - } - ExpressibleSymbol::Parameter(parameter_symbol) => { - context.instruction(AsmInstruction::Move(Move::new( - Operand::StackFrameOffset( - parameter_symbol.borrow().stack_frame_offset(), - ), - destination_register, - ))); - } - ExpressibleSymbol::Variable(variable_symbol) => { - context.instruction(AsmInstruction::Move(Move::new( - Operand::Register(variable_symbol.borrow().register()), - destination_register, - ))); - } - } - } - Expression::Additive(additive) => { - let result_register = additive.assemble(context, symbol_table, constants_table); - context.instruction(AsmInstruction::Move(Move::new( - Operand::Register(result_register), - destination_register, - ))); - } - } - } } diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index 10559b9..09bb6d8 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -1,6 +1,4 @@ pub mod additive_expression; -pub mod assemble_context; -mod ast_to_ir_util; pub mod call; pub mod compilation_unit; pub mod expression; @@ -10,7 +8,7 @@ pub mod fqn; pub mod function; pub mod identifier; pub mod integer_literal; -mod ir_builder; +pub mod ir_builder; pub mod let_statement; pub mod module_level_declaration; pub mod parameter; diff --git a/dmc-lib/src/ast/module_level_declaration.rs b/dmc-lib/src/ast/module_level_declaration.rs index 30f010a..4b3c69e 100644 --- a/dmc-lib/src/ast/module_level_declaration.rs +++ b/dmc-lib/src/ast/module_level_declaration.rs @@ -1,7 +1,5 @@ -use crate::ast::assemble_context::AssembleContext; use crate::ast::extern_function::ExternFunction; use crate::ast::function::Function; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::symbol_table::SymbolTable; @@ -39,20 +37,4 @@ impl ModuleLevelDeclaration { } } } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - ) { - match self { - ModuleLevelDeclaration::Function(function) => { - function.assemble(context, symbol_table, constants_table) - } - ModuleLevelDeclaration::ExternFunction(_) => { - // no-op - } - } - } } diff --git a/dmc-lib/src/ast/statement.rs b/dmc-lib/src/ast/statement.rs index 6d6cf76..c022791 100644 --- a/dmc-lib/src/ast/statement.rs +++ b/dmc-lib/src/ast/statement.rs @@ -1,13 +1,8 @@ -use crate::ast::assemble_context::AssembleContext; use crate::ast::expression_statement::ExpressionStatement; use crate::ast::ir_builder::IrBuilder; use crate::ast::let_statement::LetStatement; -use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; -use crate::symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; -use std::cell::RefCell; -use std::rc::Rc; pub enum Statement { Let(LetStatement), @@ -52,28 +47,4 @@ impl Statement { } } } - - pub fn assemble( - &self, - context: &mut AssembleContext, - symbol_table: &SymbolTable, - constants_table: &mut ConstantsTable, - outer_function_symbol: &Rc>, - is_last: bool, - ) { - match self { - Statement::Let(let_statement) => { - let_statement.assemble(context, symbol_table, constants_table); - } - Statement::Expression(expression_statement) => { - expression_statement.assemble( - context, - symbol_table, - constants_table, - outer_function_symbol, - is_last, - ); - } - } - } } diff --git a/dmc-lib/src/constants_table.rs b/dmc-lib/src/constants_table.rs index 1ab1adb..3a5a69f 100644 --- a/dmc-lib/src/constants_table.rs +++ b/dmc-lib/src/constants_table.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; +use std::rc::Rc; pub struct ConstantsTable { string_counter: usize, - strings_to_names: HashMap, + strings_to_names: HashMap, Rc>, } impl ConstantsTable { @@ -13,14 +14,18 @@ impl ConstantsTable { } } - pub fn insert_string(&mut self, s: &str) -> String { - let name = format!("s_{}", self.string_counter); - self.string_counter += 1; - self.strings_to_names.insert(s.into(), name.clone()); - name + pub fn get_or_insert(&mut self, s: &str) -> Rc { + if self.strings_to_names.contains_key(s) { + self.strings_to_names.get(s).unwrap().clone() + } else { + let name: Rc = Rc::from(format!("s_{}", self.string_counter).as_str()); + self.string_counter += 1; + self.strings_to_names.insert(s.into(), name.clone()); + name + } } - pub fn string_constants(&self) -> HashMap { + pub fn string_constants(&self) -> HashMap, Rc> { let mut constants = HashMap::new(); self.strings_to_names.iter().for_each(|(content, name)| { constants.insert(name.clone(), content.clone()); diff --git a/dmc-lib/src/ir/assemble.rs b/dmc-lib/src/ir/assemble.rs new file mode 100644 index 0000000..13894b1 --- /dev/null +++ b/dmc-lib/src/ir/assemble.rs @@ -0,0 +1,26 @@ +use crate::constants_table::ConstantsTable; +use dvm_lib::instruction::Instruction; + +pub trait Assemble { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable); +} + +pub struct InstructionsBuilder { + instructions: Vec, +} + +impl InstructionsBuilder { + pub fn new() -> Self { + Self { + instructions: vec![], + } + } + + pub fn push(&mut self, instruction: Instruction) { + self.instructions.push(instruction); + } + + pub fn take_instructions(&mut self) -> Vec { + std::mem::take(&mut self.instructions) + } +} diff --git a/dmc-lib/src/ir/ir_add.rs b/dmc-lib/src/ir/ir_add.rs index ff0d4f3..15a3dc4 100644 --- a/dmc-lib/src/ir/ir_add.rs +++ b/dmc-lib/src/ir/ir_add.rs @@ -1,6 +1,8 @@ +use crate::constants_table::ConstantsTable; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::VrUser; +use dvm_lib::instruction::AddOperand; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -16,6 +18,21 @@ impl IrAdd { right: right.into(), } } + + pub fn left(&self) -> &IrExpression { + &self.left + } + + pub fn right(&self) -> &IrExpression { + &self.right + } + + pub fn operand_pair(&self, constants_table: &mut ConstantsTable) -> (AddOperand, AddOperand) { + ( + self.left.add_operand(constants_table), + self.right.add_operand(constants_table), + ) + } } impl Display for IrAdd { diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index 903aaf6..88f3af7 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -1,6 +1,9 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; use crate::ir::register_allocation::VrUser; +use dvm_lib::instruction::{Instruction, Location}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -67,6 +70,34 @@ impl VrUser for IrAssign { } } +impl Assemble for IrAssign { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + let destination = match self.destination.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + Location::Register(vr_variable.assigned_register()) + } + IrVariableDescriptor::Stack(stack_variable) => { + Location::StackFrameOffset(stack_variable.offset()) + } + }; + + match self.initializer.as_ref() { + IrOperation::Load(ir_expression) => { + let move_operand = ir_expression.move_operand(constants_table); + builder.push(Instruction::Move(move_operand, destination)); + } + IrOperation::Add(ir_add) => { + let (left, right) = ir_add.operand_pair(constants_table); + builder.push(Instruction::Add(left, right, destination)); + } + IrOperation::Call(ir_call) => { + ir_call.assemble(builder, constants_table); + builder.push(Instruction::Pop(Some(destination))); + } + } + } +} + impl Display for IrAssign { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( diff --git a/dmc-lib/src/ir/ir_block.rs b/dmc-lib/src/ir/ir_block.rs index c858f34..f86329c 100644 --- a/dmc-lib/src/ir/ir_block.rs +++ b/dmc-lib/src/ir/ir_block.rs @@ -1,3 +1,5 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::{HasVrUsers, VrUser}; @@ -75,6 +77,14 @@ impl VrUser for IrBlock { } } +impl Assemble for IrBlock { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + for statement in &self.statements { + statement.assemble(builder, constants_table); + } + } +} + impl Display for IrBlock { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, " {}:", self.debug_label)?; diff --git a/dmc-lib/src/ir/ir_call.rs b/dmc-lib/src/ir/ir_call.rs index 449d9a1..8b59096 100644 --- a/dmc-lib/src/ir/ir_call.rs +++ b/dmc-lib/src/ir/ir_call.rs @@ -1,6 +1,11 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::VrUser; +use crate::symbol::FunctionSymbol; +use dvm_lib::instruction::Instruction; +use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -8,13 +13,19 @@ use std::rc::Rc; pub struct IrCall { function_name: Rc, arguments: Vec, + function_symbol: Rc>, } impl IrCall { - pub fn new(function_name: Rc, arguments: Vec) -> Self { + pub fn new( + function_name: Rc, + arguments: Vec, + function_symbol: Rc>, + ) -> Self { Self { function_name, arguments, + function_symbol, } } } @@ -44,6 +55,29 @@ impl VrUser for IrCall { } } +impl Assemble for IrCall { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + // push all args + self.arguments + .iter() + .map(|ir_expression| ir_expression.push_operand(constants_table)) + .for_each(|push_operand| builder.push(Instruction::Push(push_operand))); + let symbol = self.function_symbol.borrow(); + if symbol.is_platform() { + builder.push(Instruction::InvokePlatformStatic( + symbol.name_owned(), + symbol.parameters().len(), + )); + } else { + builder.push(Instruction::InvokeStatic( + symbol.name_owned(), + symbol.parameters().len(), + )); + } + // todo: handle function postlude + } +} + impl Display for IrCall { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}(", self.function_name)?; diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index 05bc390..a8df47a 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -1,8 +1,11 @@ +use crate::constants_table::ConstantsTable; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::{ IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor, }; use crate::ir::register_allocation::VrUser; +use crate::type_info::TypeInfo; +use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -15,6 +18,116 @@ pub enum IrExpression { String(Rc), } +impl IrExpression { + pub fn type_info(&self) -> TypeInfo { + match self { + IrExpression::Parameter(ir_parameter) => ir_parameter.type_info().clone(), + IrExpression::Variable(ir_variable) => ir_variable.borrow().type_info().clone(), + IrExpression::Int(_) => TypeInfo::Integer, + IrExpression::String(_) => TypeInfo::String, + } + } + + pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand { + match self { + IrExpression::Parameter(ir_parameter) => { + MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(register_variable) => { + MoveOperand::Location(Location::Register(register_variable.assigned_register())) + } + IrVariableDescriptor::Stack(stack_variable) => { + MoveOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + IrExpression::Int(i) => MoveOperand::Int(*i), + IrExpression::String(s) => { + let constant_name = constants_table.get_or_insert(s); + MoveOperand::String(constant_name) + } + } + } + + pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand { + match self { + IrExpression::Parameter(ir_parameter) => { + PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(register_variable) => { + PushOperand::Location(Location::Register(register_variable.assigned_register())) + } + IrVariableDescriptor::Stack(stack_variable) => { + PushOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + IrExpression::Int(i) => PushOperand::Int(*i), + IrExpression::String(s) => { + let constant_name = constants_table.get_or_insert(s); + PushOperand::String(constant_name) + } + } + } + + pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand { + match self { + IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() { + TypeInfo::Integer | TypeInfo::String => { + AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + _ => panic!( + "Attempt to add non-integer/non-string (found: {})", + ir_parameter.type_info() + ), + }, + IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() { + TypeInfo::Integer | TypeInfo::String => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(register_variable) => { + AddOperand::Location(Location::Register( + register_variable.assigned_register(), + )) + } + IrVariableDescriptor::Stack(stack_variable) => { + AddOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + _ => panic!( + "Attempt to add non-integer/non-string (found: {})", + ir_variable.borrow().type_info() + ), + }, + IrExpression::Int(i) => AddOperand::Int(*i), + IrExpression::String(s) => { + let constant_name = constants_table.get_or_insert(s); + AddOperand::String(constant_name) + } + } + } + + pub fn return_operand(&self) -> ReturnOperand { + match self { + IrExpression::Parameter(ir_parameter) => { + ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(register_variable) => { + ReturnOperand::Location(Location::Register( + register_variable.assigned_register(), + )) + } + IrVariableDescriptor::Stack(stack_variable) => { + ReturnOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + IrExpression::Int(i) => ReturnOperand::Int(*i), + IrExpression::String(s) => { + todo!("String constants") + } + } + } +} + impl Display for IrExpression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index 35ea071..0ef6c1f 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -1,15 +1,19 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_block::IrBlock; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVrVariableDescriptor; -use crate::ir::register_allocation::{HasVrUsers, VrUser}; +use crate::ir::register_allocation::HasVrUsers; +use crate::symbol::FunctionSymbol; use crate::type_info::TypeInfo; +use dvm_lib::vm::function::Function; use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Display; use std::rc::Rc; pub struct IrFunction { - name: Rc, + function_symbol: Rc>, parameters: Vec>, return_type_info: TypeInfo, entry: Rc>, @@ -17,13 +21,13 @@ pub struct IrFunction { impl IrFunction { pub fn new( - name: Rc, + function_symbol: Rc>, parameters: &[Rc], return_type_info: TypeInfo, entry: Rc>, ) -> Self { Self { - name, + function_symbol, parameters: parameters.to_vec(), return_type_info, entry, @@ -37,11 +41,22 @@ impl IrFunction { ) -> HashMap { self.entry.borrow_mut().assign_registers(register_count) } + + pub fn assemble(&self, constants_table: &mut ConstantsTable) -> Function { + let mut builder = InstructionsBuilder::new(); + self.entry.borrow().assemble(&mut builder, constants_table); + let instructions = builder.take_instructions(); + Function::new( + self.function_symbol.borrow().name_owned(), + self.parameters.len(), + instructions, + ) + } } impl Display for IrFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "fn {}(", self.name)?; + write!(f, "fn {}(", self.function_symbol.borrow().name())?; for (i, parameter) in self.parameters.iter().enumerate() { write!(f, "{}: {}", parameter, parameter.type_info())?; if i < self.parameters.len() - 1 { diff --git a/dmc-lib/src/ir/ir_parameter.rs b/dmc-lib/src/ir/ir_parameter.rs index 13542d7..72934e1 100644 --- a/dmc-lib/src/ir/ir_parameter.rs +++ b/dmc-lib/src/ir/ir_parameter.rs @@ -5,19 +5,25 @@ use std::rc::Rc; pub struct IrParameter { name: Rc, type_info: TypeInfo, + stack_offset: isize, } impl IrParameter { - pub fn new(name: &str, type_info: TypeInfo) -> Self { + pub fn new(name: &str, type_info: TypeInfo, stack_offset: isize) -> Self { Self { name: name.into(), type_info, + stack_offset, } } pub fn type_info(&self) -> &TypeInfo { &self.type_info } + + pub fn stack_offset(&self) -> isize { + self.stack_offset + } } impl Display for IrParameter { diff --git a/dmc-lib/src/ir/ir_return.rs b/dmc-lib/src/ir/ir_return.rs index 7ad8674..aad49e8 100644 --- a/dmc-lib/src/ir/ir_return.rs +++ b/dmc-lib/src/ir/ir_return.rs @@ -1,6 +1,9 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::VrUser; +use dvm_lib::instruction::Instruction; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -43,6 +46,15 @@ impl VrUser for IrReturn { } } +impl Assemble for IrReturn { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + if let Some(ir_expression) = self.value.as_ref() { + builder.push(Instruction::SetReturnValue(ir_expression.return_operand())); + } + builder.push(Instruction::Return); + } +} + impl Display for IrReturn { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "return")?; diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index 5676671..deb0d92 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -1,3 +1,5 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; @@ -61,6 +63,22 @@ impl VrUser for IrStatement { } } +impl Assemble for IrStatement { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + match self { + IrStatement::Assign(ir_assign) => { + ir_assign.assemble(builder, constants_table); + } + IrStatement::Call(ir_call) => { + ir_call.assemble(builder, constants_table); + } + IrStatement::Return(ir_return) => { + ir_return.assemble(builder, constants_table); + } + } + } +} + impl Display for IrStatement { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 1705776..2597191 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -102,6 +102,10 @@ impl IrVrVariableDescriptor { pub fn set_assigned_register(&mut self, register: usize) { self.assigned_register = Some(register); } + + pub fn assigned_register(&self) -> usize { + self.assigned_register.unwrap() + } } impl Display for IrVrVariableDescriptor { @@ -119,7 +123,7 @@ impl Debug for IrVrVariableDescriptor { pub struct IrStackVariableDescriptor { name: Rc, block_id: usize, - offset: Option, + offset: Option, } impl IrStackVariableDescriptor { @@ -134,6 +138,10 @@ impl IrStackVariableDescriptor { pub fn name(&self) -> &str { &self.name } + + pub fn offset(&self) -> isize { + self.offset.unwrap() + } } impl Display for IrStackVariableDescriptor { diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index 69806eb..006ba16 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -1,3 +1,4 @@ +mod assemble; pub mod ir_add; pub mod ir_assign; pub mod ir_block; diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index 5578421..14dc205 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -1,4 +1,3 @@ -pub mod asm; pub mod ast; pub mod constants_table; pub mod diagnostic; diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index b791cdf..d0f62c4 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -1,57 +1,35 @@ -use std::fmt::Display; +use std::fmt::{Display, Formatter}; use std::rc::Rc; pub type Register = usize; +pub type StackFrameOffset = isize; pub type ConstantName = Rc; pub type FunctionName = Rc; pub type ArgCount = usize; pub type CallerPopCount = usize; pub enum Instruction { - MoveRegister(Register, Register), - MoveInt(i32, Register), - MoveStackFrameOffset(isize, Register), - - PushRegister(Register), - PushInt(i32), - PushStackFrameOffset(isize), + Move(MoveOperand, Location), + Push(PushOperand), InvokeStatic(FunctionName, ArgCount), InvokePlatformStatic(FunctionName, ArgCount), - LoadStringConstant(ConstantName, Register), + Add(AddOperand, AddOperand, Location), - Pop(Option), + Pop(Option), - AddIntInt(Register, Register, Register), - AddStringInt(Register, Register, Register), - AddStringString(Register, Register, Register), - - SetReturnValue(Register), - Return(CallerPopCount), + SetReturnValue(ReturnOperand), + Return, } impl Display for Instruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Instruction::MoveRegister(source, destination) => { - write!(f, "movr r{}, r{}", source, destination) - } - Instruction::MoveInt(i, destination) => { - write!(f, "movi {}, r{}", i, destination) - } - Instruction::MoveStackFrameOffset(offset, destination) => { - write!(f, "movsf {}, r{}", offset, destination) - } - Instruction::PushRegister(source) => { - write!(f, "pushr r{}", source) - } - Instruction::PushInt(i) => { - write!(f, "pushi {}", i) - } - Instruction::PushStackFrameOffset(offset) => { - write!(f, "pushsf {}", offset) + Instruction::Move(source, destination) => { + write!(f, "mov {}, {}", source, destination) } + Instruction::Push(source) => write!(f, "push {}", source), Instruction::InvokeStatic(name, arg_count) => { write!(f, "invoke_static {} (arg_count: {})", name, arg_count) } @@ -62,30 +40,131 @@ impl Display for Instruction { name, arg_count ) } - Instruction::LoadStringConstant(name, destination) => { - write!(f, "loadsc {}, r{}", name, destination) - } Instruction::Pop(maybe_destination) => { if let Some(destination) = maybe_destination { - write!(f, "pop r{}", destination) + write!(f, "pop {}", destination) } else { write!(f, "pop") } } - Instruction::AddIntInt(left, right, destination) => { - write!(f, "addii r{}, r{}, r{}", left, right, destination) - } - Instruction::AddStringInt(left, right, destination) => { - write!(f, "addsi r{}, r{}, r{}", left, right, destination) - } - Instruction::AddStringString(left, right, destination) => { - write!(f, "addss r{}, r{}, r{}", left, right, destination) + Instruction::Add(left, right, destination) => { + write!(f, "add {}, {}, {}", left, right, destination) } Instruction::SetReturnValue(source) => { - write!(f, "srv r{}", source) + write!(f, "srv {}", source) } - Instruction::Return(caller_pop_count) => { - write!(f, "return (caller_pop_count: {})", caller_pop_count) + Instruction::Return => { + write!(f, "ret") + } + } + } +} + +pub enum Location { + Register(Register), + StackFrameOffset(StackFrameOffset), +} + +impl Display for Location { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Location::Register(register) => { + write!(f, "r{}", register) + } + Location::StackFrameOffset(offset) => { + if offset.is_positive() { + write!(f, "fp+{}", offset) + } else { + write!(f, "fp{}", offset) + } + } + } + } +} + +pub enum MoveOperand { + Location(Location), + Int(i32), + String(Rc), +} + +impl Display for MoveOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + MoveOperand::Location(location) => { + write!(f, "{}", location) + } + MoveOperand::Int(i) => { + write!(f, "{}", i) + } + MoveOperand::String(s) => { + write!(f, "{}", s) + } + } + } +} + +pub enum PushOperand { + Location(Location), + Int(i32), + String(Rc), +} + +impl Display for PushOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + PushOperand::Location(location) => { + write!(f, "{}", location) + } + PushOperand::Int(i) => { + write!(f, "{}", i) + } + PushOperand::String(s) => { + write!(f, "{}", s) + } + } + } +} + +pub enum AddOperand { + Location(Location), + Int(i32), + String(Rc), +} + +impl Display for AddOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + AddOperand::Location(location) => { + write!(f, "{}", location) + } + AddOperand::Int(i) => { + write!(f, "{}", i) + } + AddOperand::String(s) => { + write!(f, "{}", s) + } + } + } +} + +pub enum ReturnOperand { + Location(Location), + Int(i32), + String(Rc), +} + +impl Display for ReturnOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + ReturnOperand::Location(location) => { + write!(f, "{}", location) + } + ReturnOperand::Int(i) => { + write!(f, "{}", i) + } + ReturnOperand::String(s) => { + write!(f, "{}", s) } } } diff --git a/dvm-lib/src/vm/constant.rs b/dvm-lib/src/vm/constant.rs index d45717a..195f24c 100644 --- a/dvm-lib/src/vm/constant.rs +++ b/dvm-lib/src/vm/constant.rs @@ -10,11 +10,8 @@ pub struct StringConstant { } impl StringConstant { - pub fn new(name: Rc, content: &str) -> Self { - Self { - name, - content: content.into(), - } + pub fn new(name: Rc, content: Rc) -> Self { + Self { name, content } } pub fn name(&self) -> &str { diff --git a/dvm-lib/src/vm/function.rs b/dvm-lib/src/vm/function.rs index d682465..5f38296 100644 --- a/dvm-lib/src/vm/function.rs +++ b/dvm-lib/src/vm/function.rs @@ -1,18 +1,19 @@ use crate::instruction::Instruction; +use std::fmt::Display; use std::rc::Rc; pub struct Function { name: Rc, + parameter_count: usize, instructions: Vec, - register_count: usize, } impl Function { - pub fn new(name: &str, instructions: Vec, register_count: usize) -> Self { + pub fn new(name: Rc, parameter_count: usize, instructions: Vec) -> Self { Self { - name: name.into(), + name, + parameter_count, instructions, - register_count, } } @@ -24,11 +25,21 @@ impl Function { self.name.clone() } + pub fn parameter_count(&self) -> usize { + self.parameter_count + } + pub fn instructions(&self) -> &Vec { &self.instructions } +} - pub fn register_count(&self) -> usize { - self.register_count +impl Display for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "fn {}", self.name)?; + for instruction in &self.instructions { + writeln!(f, " {}", instruction)?; + } + Ok(()) } } diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index c3cc771..05c8ec2 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -1,4 +1,6 @@ -use crate::instruction::Instruction; +use crate::instruction::{ + AddOperand, ConstantName, Instruction, Location, MoveOperand, PushOperand, ReturnOperand, +}; use crate::platform_function::PlatformFunction; use crate::vm::constant::Constant; use crate::vm::function::Function; @@ -41,28 +43,17 @@ impl DvmContext { &mut self.platform_functions } - #[deprecated] - pub fn add_function(&mut self, function: Function) { - self.functions.insert(function.name_owned(), function); - } - pub fn constants(&self) -> &HashMap, Constant> { &self.constants } - #[deprecated] - pub fn add_constant(&mut self, constant: Constant) { - match &constant { - Constant::String(string_constant) => { - self.constants - .insert(string_constant.name_owned(), constant); - } - } + pub fn constants_mut(&mut self) -> &mut HashMap, Constant> { + &mut self.constants } } pub struct CallFrame<'a> { - function_name: Rc, + function: &'a Function, instructions: &'a Vec, ip: usize, stack: Vec, @@ -71,10 +62,10 @@ pub struct CallFrame<'a> { } impl<'a> CallFrame<'a> { - fn new(function_name: Rc, instructions: &'a Vec) -> Self { + fn new(function: &'a Function) -> Self { Self { - function_name, - instructions, + function, + instructions: function.instructions(), ip: 0, stack: vec![], fp: 0, @@ -82,8 +73,8 @@ impl<'a> CallFrame<'a> { } } - fn function_name(&self) -> &str { - &self.function_name + fn function(&self) -> &'a Function { + self.function } fn instructions(&self) -> &'a [Instruction] { @@ -173,6 +164,55 @@ impl<'a> CallStack<'a> { } } +fn load_value<'a>( + registers: &'a [Value], + stack: &'a [Value], + fp: usize, + location: &Location, +) -> &'a Value { + match location { + Location::Register(register) => ®isters[*register], + Location::StackFrameOffset(offset) => { + let value_index = fp.checked_add_signed(*offset).expect(&format!( + "Overflow when adding offset {} to fp {}", + *offset, fp + )); + &stack[value_index] + } + } +} + +fn load_constant_value( + constants: &HashMap, Constant>, + constant_name: &ConstantName, +) -> Value { + let constant = &constants[constant_name]; + match constant { + Constant::String(string_constant) => Value::String(string_constant.content_owned()), + } +} + +fn put_value( + registers: &mut Vec, + stack: &mut Vec, + fp: usize, + destination: &Location, + value: Value, +) { + match destination { + Location::Register(register) => { + registers[*register] = value; + } + Location::StackFrameOffset(offset) => { + let target_index = fp.checked_add_signed(*offset).expect(&format!( + "Failed to calculate target index from fp + offset ({} + {})", + fp, offset + )); + stack[target_index] = value; + } + } +} + pub fn call<'a>( context: &'a DvmContext, registers: &mut Vec, @@ -190,14 +230,8 @@ pub fn call<'a>( .get(function_name) .expect(&format!("Function {} not found", function_name)); - // ensure enough registers - registers.resize_with(function.register_count(), Default::default); - // push call frame - call_stack.push(CallFrame::new( - function.name_owned(), - function.instructions(), - )); + call_stack.push(CallFrame::new(function)); // put each arg on the stack for argument in arguments { @@ -214,52 +248,48 @@ pub fn call<'a>( match instruction { /* Move instructions */ - Instruction::MoveRegister(source, destination) => { - // copy value from one register to another register - let value = registers[*source].clone(); - registers[*destination] = value; - call_stack.top_mut().increment_ip(); - } - Instruction::MoveInt(value, destination) => { - registers[*destination] = Value::Int(*value); - call_stack.top_mut().increment_ip(); - } - Instruction::MoveStackFrameOffset(offset, destination) => { - // copy a value offset from the current frame pointer (fp) to a register - let value_index = - call_stack - .top() - .fp() - .checked_add_signed(*offset) - .expect(&format!( - "Overflow when adding offset {} to fp {}", - *offset, - call_stack.top().fp() - )); - let value = call_stack.top().stack()[value_index].clone(); - registers[*destination] = value; + Instruction::Move(source, destination) => { + // move a value to a destination + // could be a copy or an immediate + let value = match source { + MoveOperand::Location(location) => load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + location, + ) + .clone(), + MoveOperand::Int(i) => Value::Int(*i), + MoveOperand::String(constant_name) => { + load_constant_value(context.constants(), constant_name) + } + }; + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + destination, + value, + ); call_stack.top_mut().increment_ip(); } /* Push instructions */ - Instruction::PushRegister(source) => { - // copy a value from a register to the top of the stack - let value = registers[*source].clone(); - call_stack.top_mut().stack_mut().push(value); - call_stack.top_mut().increment_ip(); - } - Instruction::PushInt(value) => { - call_stack.top_mut().stack_mut().push(Value::Int(*value)); - call_stack.top_mut().increment_ip(); - } - Instruction::PushStackFrameOffset(offset) => { - // copy a value from somewhere on the stack to the top of the stack - let value_index = call_stack - .top() - .fp() - .checked_add_signed(*offset) - .expect("Overflow when adding offset to fp"); - let value = call_stack.top().stack()[value_index].clone(); + Instruction::Push(operand) => { + let value = match operand { + PushOperand::Location(location) => load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + location, + ) + .clone(), + PushOperand::Int(i) => Value::Int(*i), + PushOperand::String(constant_name) => { + load_constant_value(context.constants(), constant_name) + } + }; call_stack.top_mut().stack_mut().push(value); call_stack.top_mut().increment_ip(); } @@ -279,10 +309,7 @@ pub fn call<'a>( call_stack.top_mut().increment_ip(); // push a new call frame - call_stack.push(CallFrame::new( - function.name_owned(), - function.instructions(), - )); + call_stack.push(CallFrame::new(function)); // push args call_stack.top_mut().stack_mut().append(&mut args); @@ -316,62 +343,131 @@ pub fn call<'a>( call_stack.top_mut().increment_ip(); } - /* Load constant instructions */ - Instruction::LoadStringConstant(constant_name, destination) => { - let constant = &context.constants()[constant_name]; - match constant { - Constant::String(string_constant) => { - registers[*destination] = Value::String(string_constant.content_owned()); - } - } - call_stack.top_mut().increment_ip(); - } - /* Add instructions */ - Instruction::AddIntInt(lhs, rhs, destination) => { - let lhs_value = registers[*lhs].unwrap_int(); - let rhs_value = registers[*rhs].unwrap_int(); - let result = lhs_value + rhs_value; - registers[*destination] = Value::Int(result); - call_stack.top_mut().increment_ip(); - } - Instruction::AddStringInt(lhs, rhs, destination) => { - let lhs_value = registers[*lhs].unwrap_string(); - let rhs_value = registers[*rhs].unwrap_int(); - let formatted = format!("{}{}", lhs_value, rhs_value); - registers[*destination] = Value::String(Rc::from(formatted)); - call_stack.top_mut().increment_ip(); - } - Instruction::AddStringString(lhs, rhs, destination) => { - let lhs_value = registers[*lhs].unwrap_string(); - let rhs_value = registers[*rhs].unwrap_string(); - let formatted = format!("{}{}", lhs_value, rhs_value); - registers[*destination] = Value::String(Rc::from(formatted)); + Instruction::Add(left_operand, right_operand, destination) => { + let left_value = match left_operand { + AddOperand::Location(location) => load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + location, + ) + .clone(), + AddOperand::Int(i) => Value::Int(*i), + AddOperand::String(constant_name) => { + load_constant_value(context.constants(), constant_name) + } + }; + + let right_value = match right_operand { + AddOperand::Location(location) => load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + location, + ) + .clone(), + AddOperand::Int(i) => Value::Int(*i), + AddOperand::String(constant_name) => { + load_constant_value(context.constants(), constant_name) + } + }; + + if let Value::Int(left) = left_value { + if let Value::Int(right) = right_value { + let result = left + right; + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + destination, + Value::Int(result), + ); + } else if let Value::String(s) = right_value { + let result = format!("{}{}", left, s); + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + destination, + Value::String(result.into()), + ); + } else { + panic!("Attempt to add on non-addable type: {:?}", right_value); + } + } else if let Value::String(left) = left_value { + if let Value::Int(right) = right_value { + let result = format!("{}{}", left, right); + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + destination, + Value::String(result.into()), + ); + } else if let Value::String(right) = right_value { + let result = format!("{}{}", left, right); + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + destination, + Value::String(result.into()), + ); + } else { + panic!("Attempt to add on non-addable type: {:?}", right_value); + } + } else { + panic!("Attempt to add on non-addable type: {:?}", left_value); + } + call_stack.top_mut().increment_ip(); } /* Pop instructions */ - Instruction::Pop(maybe_register) => { + Instruction::Pop(maybe_location) => { let value = call_stack.top_mut().stack_mut().pop().unwrap(); - if let Some(register) = maybe_register { - registers[*register] = value; + if let Some(location) = maybe_location { + let fp = call_stack.top().fp(); + put_value( + registers, + call_stack.top_mut().stack_mut(), + fp, + location, + value, + ); } call_stack.top_mut().increment_ip(); } /* Return instructions */ - Instruction::SetReturnValue(register) => { - call_stack - .top_mut() - .set_return_value(registers[*register].clone()); + Instruction::SetReturnValue(return_operand) => { + let value = match return_operand { + ReturnOperand::Location(location) => load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + location, + ) + .clone(), + ReturnOperand::Int(i) => Value::Int(*i), + ReturnOperand::String(constant_name) => { + load_constant_value(context.constants(), constant_name) + } + }; + call_stack.top_mut().set_return_value(value); call_stack.top_mut().increment_ip(); } - Instruction::Return(caller_pop_count) => { + Instruction::Return => { let mut callee = call_stack.pop(); // pop this frame let maybe_caller = call_stack.maybe_top_mut(); if let Some(caller) = maybe_caller { - for _ in 0..*caller_pop_count { + for _ in 0..callee.function().parameter_count() { caller.stack_mut().pop(); } if let Some(return_value) = callee.take_return_value() { diff --git a/examples/register_alloc_test.dm b/examples/register_alloc_test.dm index 8427e15..6691170 100644 --- a/examples/register_alloc_test.dm +++ b/examples/register_alloc_test.dm @@ -5,4 +5,6 @@ fn main() let b = 2 let c = 3 let x = a + b + c + println(x) + println(a) end \ No newline at end of file