deimos-lang/dmc-lib/src/ir/ir_assign.rs
2026-03-11 19:54:47 -05:00

127 lines
4.6 KiB
Rust

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<RefCell<IrVariable>>,
initializer: Box<IrOperation>,
}
impl IrAssign {
pub fn new(destination: Rc<RefCell<IrVariable>>, initializer: IrOperation) -> Self {
Self {
destination,
initializer: initializer.into(),
}
}
}
impl VrUser for IrAssign {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
match self.destination.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_descriptor) => {
HashSet::from([vr_descriptor.clone()])
}
IrVariableDescriptor::Stack(_) => HashSet::new(),
}
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
self.initializer.vr_uses()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
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<IrVrVariableDescriptor, usize>,
) {
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
)
}
}