diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 05c8784..94f0f00 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -168,7 +168,9 @@ impl Expression { Expression::Subtract(subtract_expression) => { Some(subtract_expression.to_ir_expression(builder, symbol_table)) } - Expression::Negative(_) => todo!(), + Expression::Negative(negative_expression) => { + Some(negative_expression.to_ir(builder, symbol_table)) + } } } } diff --git a/dmc-lib/src/ast/negative_expression.rs b/dmc-lib/src/ast/negative_expression.rs index 762de49..4aaa0ef 100644 --- a/dmc-lib/src/ast/negative_expression.rs +++ b/dmc-lib/src/ast/negative_expression.rs @@ -1,8 +1,17 @@ use crate::ast::expression::Expression; +use crate::ast::ir_builder::IrBuilder; use crate::diagnostic::Diagnostic; +use crate::ir::ir_assign::IrAssign; +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_multiply::IrMultiply; +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 struct NegativeExpression { operand: Box, @@ -58,6 +67,67 @@ impl NegativeExpression { } } + pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression { + let operand_as_ir = self + .operand + .to_ir(builder, symbol_table) + .expect("Attempt to negate non-value expression"); + + match operand_as_ir { + IrExpression::Parameter(parameter) => { + let destination = Rc::new(RefCell::new(IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + parameter.type_info(), + ))); + + let rhs = match parameter.type_info() { + TypeInfo::Integer => IrExpression::Int(-1), + TypeInfo::Double => IrExpression::Double(-1.0), + _ => panic!("Trying to multiply with a non-integer/double"), + }; + + let operation = + IrOperation::Multiply(IrMultiply::new(IrExpression::Parameter(parameter), rhs)); + + let assign = IrAssign::new(destination.clone(), operation); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(assign)); + + IrExpression::Variable(destination) + } + IrExpression::Variable(variable) => { + let destination = Rc::new(RefCell::new(IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + variable.borrow().type_info(), + ))); + + let rhs = match variable.borrow().type_info() { + TypeInfo::Integer => IrExpression::Int(-1), + TypeInfo::Double => IrExpression::Double(-1.0), + _ => panic!("Trying to multiply with a non-integer/double"), + }; + + let operation = + IrOperation::Multiply(IrMultiply::new(IrExpression::Variable(variable), rhs)); + + let assign = IrAssign::new(destination.clone(), operation); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(assign)); + + IrExpression::Variable(destination) + } + IrExpression::Int(i) => IrExpression::Int(i * -1), + IrExpression::Double(d) => IrExpression::Double(d * -1.0), + IrExpression::String(_) => { + panic!("Attempt to negate IrExpression::String") + } + } + } + pub fn type_info(&self) -> &TypeInfo { self.type_info.as_ref().unwrap() } diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index d131fde..9591fa7 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -101,6 +101,10 @@ impl Assemble for IrAssign { let (left, right) = ir_subtract.operand_pair(); builder.push(Instruction::Subtract(left, right, destination)); } + IrOperation::Multiply(ir_multiply) => { + let (left, right) = ir_multiply.operand_pair(); + builder.push(Instruction::Multiply(left, right, destination)); + } IrOperation::Call(ir_call) => { ir_call.assemble(builder, constants_table); builder.push(Instruction::Pop(Some(destination))); diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index 99b3638..c9252da 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -6,7 +6,7 @@ use crate::ir::ir_variable::{ use crate::ir::register_allocation::{OffsetCounter, VrUser}; use crate::type_info::TypeInfo; use dvm_lib::instruction::{ - AddOperand, Location, MoveOperand, PushOperand, ReturnOperand, SubtractOperand, + AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand, }; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; @@ -149,6 +149,27 @@ impl IrExpression { } } + pub fn multiply_operand(&self) -> MultiplyOperand { + match self { + IrExpression::Parameter(ir_parameter) => { + MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + MultiplyOperand::Location(Location::Register(vr_variable.assigned_register())) + } + IrVariableDescriptor::Stack(stack_variable) => { + MultiplyOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + IrExpression::Int(i) => MultiplyOperand::Int(*i), + IrExpression::Double(d) => MultiplyOperand::Double(*d), + IrExpression::String(_) => { + panic!("Attempt to multiply with a string"); + } + } + } + pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand { match self { IrExpression::Parameter(ir_parameter) => { diff --git a/dmc-lib/src/ir/ir_multiply.rs b/dmc-lib/src/ir/ir_multiply.rs new file mode 100644 index 0000000..945e3f6 --- /dev/null +++ b/dmc-lib/src/ir/ir_multiply.rs @@ -0,0 +1,67 @@ +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::IrVrVariableDescriptor; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; +use dvm_lib::instruction::MultiplyOperand; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; + +pub struct IrMultiply { + left: Box, + right: Box, +} + +impl IrMultiply { + pub fn new(left: IrExpression, right: IrExpression) -> Self { + Self { + left: left.into(), + right: right.into(), + } + } + + pub fn operand_pair(&self) -> (MultiplyOperand, MultiplyOperand) { + (self.left.multiply_operand(), self.right.multiply_operand()) + } +} + +impl Display for IrMultiply { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{} * {}", self.left, self.right) + } +} + +impl VrUser for IrMultiply { + fn vr_definitions(&self) -> HashSet { + [&self.left, &self.right] + .iter() + .flat_map(|ir_expression| ir_expression.vr_definitions()) + .collect() + } + + fn vr_uses(&self) -> HashSet { + [&self.left, &self.right] + .iter() + .flat_map(|ir_expression| ir_expression.vr_uses()) + .collect() + } + + fn propagate_spills(&mut self, spills: &HashSet) { + [&mut self.left, &mut self.right] + .iter_mut() + .for_each(|ir_expression| ir_expression.propagate_spills(spills)); + } + + fn propagate_register_assignments( + &mut self, + assignments: &HashMap, + ) { + [&mut self.left, &mut self.right] + .iter_mut() + .for_each(|ir_expression| ir_expression.propagate_register_assignments(assignments)); + } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { + [&mut self.left, &mut self.right] + .iter_mut() + .for_each(|ir_expression| ir_expression.propagate_stack_offsets(counter)); + } +} diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index 58c0e01..106ce26 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -1,6 +1,7 @@ use crate::ir::ir_add::IrAdd; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_multiply::IrMultiply; use crate::ir::ir_subtract::IrSubtract; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::{OffsetCounter, VrUser}; @@ -11,6 +12,7 @@ pub enum IrOperation { Load(IrExpression), Add(IrAdd), Subtract(IrSubtract), + Multiply(IrMultiply), Call(IrCall), } @@ -26,6 +28,9 @@ impl Display for IrOperation { IrOperation::Subtract(ir_subtract) => { write!(f, "{}", ir_subtract) } + IrOperation::Multiply(ir_multiply) => { + write!(f, "{}", ir_multiply) + } IrOperation::Call(ir_call) => { write!(f, "{}", ir_call) } @@ -39,6 +44,7 @@ impl VrUser for IrOperation { IrOperation::Load(ir_expression) => ir_expression.vr_definitions(), IrOperation::Add(ir_add) => ir_add.vr_definitions(), IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(), + IrOperation::Multiply(ir_multiply) => ir_multiply.vr_definitions(), IrOperation::Call(ir_call) => ir_call.vr_definitions(), } } @@ -48,6 +54,7 @@ impl VrUser for IrOperation { IrOperation::Load(ir_expression) => ir_expression.vr_uses(), IrOperation::Add(ir_add) => ir_add.vr_uses(), IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(), + IrOperation::Multiply(ir_multiply) => ir_multiply.vr_uses(), IrOperation::Call(ir_call) => ir_call.vr_uses(), } } @@ -63,6 +70,9 @@ impl VrUser for IrOperation { IrOperation::Subtract(ir_subtract) => { ir_subtract.propagate_spills(spills); } + IrOperation::Multiply(ir_multiply) => { + ir_multiply.propagate_spills(spills); + } IrOperation::Call(ir_call) => { ir_call.propagate_spills(spills); } @@ -83,6 +93,9 @@ impl VrUser for IrOperation { IrOperation::Subtract(ir_subtract) => { ir_subtract.propagate_register_assignments(assignments); } + IrOperation::Multiply(ir_multiply) => { + ir_multiply.propagate_register_assignments(assignments); + } IrOperation::Call(ir_call) => { ir_call.propagate_register_assignments(assignments); } diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index ab76595..c2771f8 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -5,6 +5,7 @@ pub mod ir_block; pub mod ir_call; pub mod ir_expression; pub mod ir_function; +pub mod ir_multiply; pub mod ir_operation; pub mod ir_parameter; pub mod ir_return; diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 69c4995..49d66fd 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -127,12 +127,13 @@ impl TypeInfo { } pub fn can_negate(&self) -> bool { - matches!(self, TypeInfo::Integer) + matches!(self, TypeInfo::Integer | TypeInfo::Double) } pub fn negate_result(&self) -> TypeInfo { match self { TypeInfo::Integer => TypeInfo::Integer, + TypeInfo::Double => TypeInfo::Double, _ => panic!(), } } diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index 5f2e0a3..fca931f 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -17,6 +17,7 @@ pub enum Instruction { Add(AddOperand, AddOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location), + Multiply(MultiplyOperand, MultiplyOperand, Location), Pop(Option), @@ -54,6 +55,9 @@ impl Display for Instruction { Instruction::Subtract(left, right, destination) => { write!(f, "sub {}, {}, {}", left, right, destination) } + Instruction::Multiply(left, right, destination) => { + write!(f, "mul {}, {}, {}", left, right, destination) + } Instruction::SetReturnValue(source) => { write!(f, "srv {}", source) } @@ -186,6 +190,28 @@ impl Display for SubtractOperand { } } +pub enum MultiplyOperand { + Location(Location), + Int(i32), + Double(f64), +} + +impl Display for MultiplyOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + MultiplyOperand::Location(location) => { + write!(f, "{}", location) + } + MultiplyOperand::Int(i) => { + write!(f, "{}", i) + } + MultiplyOperand::Double(d) => { + write!(f, "{}", d) + } + } + } +} + pub enum ReturnOperand { Location(Location), Int(i32), diff --git a/dvm-lib/src/vm/instruction_helpers.rs b/dvm-lib/src/vm/instruction_helpers.rs index 515390d..3889938 100644 --- a/dvm-lib/src/vm/instruction_helpers.rs +++ b/dvm-lib/src/vm/instruction_helpers.rs @@ -1,4 +1,4 @@ -use crate::instruction::{AddOperand, SubtractOperand}; +use crate::instruction::{AddOperand, MultiplyOperand, SubtractOperand}; use crate::vm::CallFrame; use crate::vm::constant::Constant; use crate::vm::value::Value; @@ -43,3 +43,21 @@ pub fn subtract_operand_to_value( SubtractOperand::Double(d) => Value::Double(*d), } } + +pub fn multiply_operand_to_value( + multiply_operand: &MultiplyOperand, + registers: &[Value], + current_frame: &CallFrame, +) -> Value { + match multiply_operand { + MultiplyOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ) + .clone(), + MultiplyOperand::Int(i) => Value::Int(*i), + MultiplyOperand::Double(d) => Value::Double(*d), + } +} diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index 72768d3..3bd3895 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -2,7 +2,9 @@ use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand}; use crate::platform_function::PlatformFunction; use crate::vm::constant::Constant; use crate::vm::function::Function; -use crate::vm::instruction_helpers::{add_operand_to_value, subtract_operand_to_value}; +use crate::vm::instruction_helpers::{ + add_operand_to_value, multiply_operand_to_value, subtract_operand_to_value, +}; use crate::vm::value::Value; use crate::vm::value_util::*; use std::collections::HashMap; @@ -389,6 +391,29 @@ pub fn call<'a>( put_value(registers, call_stack.top_mut(), destination, result); call_stack.top_mut().increment_ip(); } + Instruction::Multiply(left_operand, right_operand, destination) => { + let left_value = + multiply_operand_to_value(left_operand, registers, call_stack.top()); + let right_value = + multiply_operand_to_value(right_operand, registers, call_stack.top()); + + let result = match left_value { + Value::Int(li) => match right_value { + Value::Int(ri) => Value::Int(li * ri), + Value::Double(rd) => Value::Double(li as f64 * rd), + _ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value), + }, + Value::Double(ld) => match right_value { + Value::Int(ri) => Value::Double(ld * ri as f64), + Value::Double(rd) => Value::Double(ld * rd), + _ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value), + }, + _ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value), + }; + + put_value(registers, call_stack.top_mut(), destination, result); + call_stack.top_mut().increment_ip(); + } /* Pop instructions */ Instruction::Pop(maybe_location) => {