deimos-lang/dmc-lib/src/ir/ir_assign.rs
2026-03-25 10:12:05 -05:00

127 lines
4.4 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::VrUser;
use crate::ir::util::propagate_spills;
use crate::offset_counter::OffsetCounter;
use dvm_lib::instruction::Instruction;
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> {
self.destination
.borrow()
.descriptor()
.vr_variable_descriptors()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
self.initializer.vr_uses()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
propagate_spills(&mut self.destination, spills);
}
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]);
}
}
}
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.use_next_offset(counter);
}
}
}
impl Assemble for IrAssign {
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
let destination = self.destination.borrow().descriptor().as_location();
match self.initializer.as_ref() {
IrOperation::GetFieldRef(ir_get_field_ref) => {
let self_location = ir_get_field_ref.self_parameter_or_variable().as_location();
builder.push(Instruction::GetFieldPointer(
self_location,
ir_get_field_ref.field_index(),
destination,
));
}
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => {
let self_location = ir_get_field_ref_mut
.self_parameter_or_variable()
.as_location();
builder.push(Instruction::GetFieldPointerMut(
self_location,
ir_get_field_ref_mut.field_index(),
destination,
));
}
IrOperation::ReadField(ir_read_field) => {
let field_ref_location = ir_read_field
.field_ref_variable()
.borrow()
.descriptor()
.as_location();
builder.push(Instruction::ReadField(field_ref_location, destination));
}
IrOperation::Load(ir_expression) => {
let move_operand = ir_expression.move_operand(constants_table);
builder.push(Instruction::Move(move_operand, destination));
}
IrOperation::Binary(ir_binary_operation) => {
ir_binary_operation.assemble_assign(builder, constants_table, destination);
}
IrOperation::Call(ir_call) => {
ir_call.assemble(builder, constants_table);
builder.push(Instruction::Pop(Some(destination)));
}
IrOperation::Allocate(ir_allocate) => builder.push(Instruction::Allocate(
ir_allocate.class_fqn_owned(),
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
)
}
}