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::{OffsetCounter, VrUser}; use dvm_lib::instruction::{Instruction, Location}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; use std::rc::Rc; pub struct IrAssign { destination: Rc>, initializer: Box, } impl IrAssign { pub fn new(destination: Rc>, initializer: IrOperation) -> Self { Self { destination, initializer: initializer.into(), } } } impl VrUser for IrAssign { fn vr_definitions(&self) -> HashSet { match self.destination.borrow().descriptor() { IrVariableDescriptor::VirtualRegister(vr_descriptor) => { HashSet::from([vr_descriptor.clone()]) } IrVariableDescriptor::Stack(_) => HashSet::new(), } } fn vr_uses(&self) -> HashSet { self.initializer.vr_uses() } fn propagate_spills(&mut self, spills: &HashSet) { let borrowed_destination = self.destination.borrow(); if let IrVariableDescriptor::VirtualRegister(vr_variable) = borrowed_destination.descriptor() { if spills.contains(vr_variable) { let replacement = IrVariable::new_stack( vr_variable.name().into(), vr_variable.block_id(), borrowed_destination.type_info().clone(), ); drop(borrowed_destination); self.destination.replace(replacement); } } } fn propagate_register_assignments( &mut self, assignments: &HashMap, ) { let mut borrowed_destination = self.destination.borrow_mut(); if let IrVariableDescriptor::VirtualRegister(vr_variable) = borrowed_destination.descriptor_mut() { if assignments.contains_key(vr_variable) { vr_variable.set_assigned_register(assignments[vr_variable]); } } self.initializer.propagate_register_assignments(assignments); } fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { let mut borrowed_destination = self.destination.borrow_mut(); if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() { stack_variable.set_offset(counter.next()); } } } 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::Subtract(ir_subtract) => { 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))); } } } } impl Display for IrAssign { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "{}: {} = {}", self.destination.borrow(), self.destination.borrow().type_info(), self.initializer ) } }