Add stack offset propagation, clean up some deprecated things.
This commit is contained in:
parent
12c4d0eb83
commit
12174c9cf6
@ -64,16 +64,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
for ir_function in &mut ir_functions {
|
||||
ir_function.assign_registers(args.register_count);
|
||||
}
|
||||
|
||||
let mut functions: Vec<Function> = vec![];
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
|
||||
let functions: Vec<Function> = ir_functions
|
||||
.iter()
|
||||
.map(|ir_function| ir_function.assemble(&mut constants_table))
|
||||
.collect();
|
||||
for ir_function in &mut ir_functions {
|
||||
let (_, stack_size) = ir_function.assign_registers(args.register_count);
|
||||
let function = ir_function.assemble(stack_size, &mut constants_table);
|
||||
functions.push(function);
|
||||
}
|
||||
|
||||
if args.show_asm {
|
||||
for function in &functions {
|
||||
|
||||
@ -87,14 +87,9 @@ impl Function {
|
||||
// handle parameters
|
||||
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
||||
let mut parameter_symbols = vec![];
|
||||
let parameter_count = self.parameters.len();
|
||||
let stack_frame_offset_base = (parameter_count as isize).neg();
|
||||
for (i, parameter) in self.parameters.iter_mut().enumerate() {
|
||||
for parameter in &mut self.parameters {
|
||||
match parameter.gather_declared_names(symbol_table) {
|
||||
Ok(parameter_symbol) => {
|
||||
parameter_symbol
|
||||
.borrow_mut()
|
||||
.set_stack_frame_offset(stack_frame_offset_base + (i as isize));
|
||||
parameter_symbols.push(parameter_symbol);
|
||||
}
|
||||
Err(mut parameter_diagnostics) => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::VrUser;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use dvm_lib::instruction::AddOperand;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -68,4 +68,8 @@ impl VrUser for IrAdd {
|
||||
self.left.propagate_register_assignments(assignments);
|
||||
self.right.propagate_register_assignments(assignments);
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||
// no-op, no definitions here
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ 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::register_allocation::{OffsetCounter, VrUser};
|
||||
use dvm_lib::instruction::{Instruction, Location};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -68,6 +68,13 @@ impl VrUser for IrAssign {
|
||||
}
|
||||
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 {
|
||||
|
||||
@ -2,7 +2,7 @@ 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};
|
||||
use crate::ir::register_allocation::{HasVrUsers, OffsetCounter, VrUser};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -75,6 +75,12 @@ impl VrUser for IrBlock {
|
||||
statement.propagate_register_assignments(assignments);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
|
||||
for statement in &mut self.statements {
|
||||
statement.propagate_stack_offsets(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Assemble for IrBlock {
|
||||
@ -145,7 +151,7 @@ mod tests {
|
||||
|
||||
if let ModuleLevelDeclaration::Function(main) = main {
|
||||
let mut main_ir = main.to_ir(&symbol_table);
|
||||
let register_assignments = main_ir.assign_registers(2);
|
||||
let (register_assignments, _) = main_ir.assign_registers(2);
|
||||
assert_eq!(register_assignments.len(), 4);
|
||||
} else {
|
||||
unreachable!()
|
||||
|
||||
@ -2,7 +2,7 @@ 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::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use crate::symbol::FunctionSymbol;
|
||||
use dvm_lib::instruction::Instruction;
|
||||
use std::cell::RefCell;
|
||||
@ -53,6 +53,10 @@ impl VrUser for IrCall {
|
||||
argument.propagate_register_assignments(assignments);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||
// no-op, because no definitions here
|
||||
}
|
||||
}
|
||||
|
||||
impl Assemble for IrCall {
|
||||
@ -74,7 +78,6 @@ impl Assemble for IrCall {
|
||||
symbol.parameters().len(),
|
||||
));
|
||||
}
|
||||
// todo: handle function postlude
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::ir::ir_parameter::IrParameter;
|
||||
use crate::ir::ir_variable::{
|
||||
IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor,
|
||||
};
|
||||
use crate::ir::register_allocation::VrUser;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use crate::type_info::TypeInfo;
|
||||
use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand};
|
||||
use std::cell::RefCell;
|
||||
@ -225,4 +225,8 @@ impl VrUser for IrExpression {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,21 +34,21 @@ impl IrFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the register assignments for debugging purposes
|
||||
pub fn assign_registers(
|
||||
&mut self,
|
||||
register_count: usize,
|
||||
) -> HashMap<IrVrVariableDescriptor, usize> {
|
||||
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
|
||||
self.entry.borrow_mut().assign_registers(register_count)
|
||||
}
|
||||
|
||||
pub fn assemble(&self, constants_table: &mut ConstantsTable) -> Function {
|
||||
pub fn assemble(&self, stack_size: isize, 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(),
|
||||
stack_size,
|
||||
instructions,
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::ir::ir_add::IrAdd;
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::VrUser;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
@ -75,4 +75,8 @@ impl VrUser for IrOperation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ 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::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use dvm_lib::instruction::Instruction;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -44,10 +44,14 @@ impl VrUser for IrReturn {
|
||||
ir_expression.propagate_register_assignments(assignments);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
impl Assemble for IrReturn {
|
||||
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||
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()));
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_return::IrReturn;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::VrUser;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
@ -61,6 +61,20 @@ impl VrUser for IrStatement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
|
||||
match self {
|
||||
IrStatement::Assign(ir_assign) => {
|
||||
ir_assign.propagate_stack_offsets(counter);
|
||||
}
|
||||
IrStatement::Call(ir_call) => {
|
||||
ir_call.propagate_stack_offsets(counter);
|
||||
}
|
||||
IrStatement::Return(ir_return) => {
|
||||
ir_return.propagate_stack_offsets(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Assemble for IrStatement {
|
||||
|
||||
@ -139,6 +139,10 @@ impl IrStackVariableDescriptor {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn set_offset(&mut self, offset: isize) {
|
||||
self.offset = Some(offset);
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> isize {
|
||||
self.offset.unwrap()
|
||||
}
|
||||
@ -146,6 +150,6 @@ impl IrStackVariableDescriptor {
|
||||
|
||||
impl Display for IrStackVariableDescriptor {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}_b{}", self.name, self.block_id)
|
||||
write!(f, "{}_{}", self.name, self.block_id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ pub trait HasVrUsers {
|
||||
fn assign_registers(
|
||||
&mut self,
|
||||
register_count: usize,
|
||||
) -> HashMap<IrVrVariableDescriptor, usize> {
|
||||
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
|
||||
let mut spills: HashSet<IrVrVariableDescriptor> = HashSet::new();
|
||||
loop {
|
||||
let mut interference_graph = self.interference_graph();
|
||||
@ -122,7 +122,13 @@ pub trait HasVrUsers {
|
||||
for vr_user in self.vr_users_mut() {
|
||||
vr_user.propagate_register_assignments(®isters);
|
||||
}
|
||||
return registers;
|
||||
// also set offsets
|
||||
let mut offset_counter = OffsetCounter::new();
|
||||
for vr_user in self.vr_users_mut() {
|
||||
vr_user.propagate_stack_offsets(&mut offset_counter);
|
||||
}
|
||||
|
||||
return (registers, offset_counter.get_count());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,6 +142,27 @@ pub trait VrUser {
|
||||
&mut self,
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
);
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter);
|
||||
}
|
||||
|
||||
pub struct OffsetCounter {
|
||||
counter: isize,
|
||||
}
|
||||
|
||||
impl OffsetCounter {
|
||||
pub fn new() -> Self {
|
||||
Self { counter: 0 }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> isize {
|
||||
let offset = self.counter;
|
||||
self.counter += 1;
|
||||
offset
|
||||
}
|
||||
|
||||
pub fn get_count(&self) -> isize {
|
||||
self.counter
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -51,9 +51,6 @@ pub struct ParameterSymbol {
|
||||
name: Rc<str>,
|
||||
type_info: TypeInfo,
|
||||
ir_parameter: Option<Rc<IrParameter>>,
|
||||
|
||||
#[deprecated]
|
||||
stack_frame_offset: Option<isize>,
|
||||
}
|
||||
|
||||
impl ParameterSymbol {
|
||||
@ -62,7 +59,6 @@ impl ParameterSymbol {
|
||||
name: name.into(),
|
||||
type_info,
|
||||
ir_parameter: None,
|
||||
stack_frame_offset: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,25 +81,12 @@ impl ParameterSymbol {
|
||||
pub fn ir_parameter(&self) -> &Rc<IrParameter> {
|
||||
self.ir_parameter.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn set_stack_frame_offset(&mut self, offset: isize) {
|
||||
self.stack_frame_offset = Some(offset);
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn stack_frame_offset(&self) -> isize {
|
||||
self.stack_frame_offset.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VariableSymbol {
|
||||
name: Rc<str>,
|
||||
type_info: Option<TypeInfo>,
|
||||
vr_variable: Option<Rc<RefCell<IrVariable>>>,
|
||||
|
||||
#[deprecated]
|
||||
register: Option<usize>,
|
||||
}
|
||||
|
||||
impl VariableSymbol {
|
||||
@ -112,7 +95,6 @@ impl VariableSymbol {
|
||||
name: name.into(),
|
||||
type_info: None,
|
||||
vr_variable: None,
|
||||
register: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,14 +125,6 @@ impl VariableSymbol {
|
||||
.as_ref()
|
||||
.expect("ir_variable not yet initialized")
|
||||
}
|
||||
|
||||
pub fn set_register(&mut self, register: usize) {
|
||||
self.register = Some(register);
|
||||
}
|
||||
|
||||
pub fn register(&self) -> usize {
|
||||
self.register.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ExpressibleSymbol {
|
||||
|
||||
@ -72,7 +72,7 @@ impl Display for Location {
|
||||
write!(f, "r{}", register)
|
||||
}
|
||||
Location::StackFrameOffset(offset) => {
|
||||
if offset.is_positive() {
|
||||
if offset.is_positive() || *offset == 0 {
|
||||
write!(f, "fp+{}", offset)
|
||||
} else {
|
||||
write!(f, "fp{}", offset)
|
||||
|
||||
@ -5,14 +5,21 @@ use std::rc::Rc;
|
||||
pub struct Function {
|
||||
name: Rc<str>,
|
||||
parameter_count: usize,
|
||||
stack_size: isize,
|
||||
instructions: Vec<Instruction>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(name: Rc<str>, parameter_count: usize, instructions: Vec<Instruction>) -> Self {
|
||||
pub fn new(
|
||||
name: Rc<str>,
|
||||
parameter_count: usize,
|
||||
stack_size: isize,
|
||||
instructions: Vec<Instruction>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
parameter_count,
|
||||
stack_size,
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
@ -29,6 +36,10 @@ impl Function {
|
||||
self.parameter_count
|
||||
}
|
||||
|
||||
pub fn stack_size(&self) -> isize {
|
||||
self.stack_size
|
||||
}
|
||||
|
||||
pub fn instructions(&self) -> &Vec<Instruction> {
|
||||
&self.instructions
|
||||
}
|
||||
|
||||
@ -234,10 +234,16 @@ pub fn call<'a>(
|
||||
call_stack.push(CallFrame::new(function));
|
||||
|
||||
// put each arg on the stack
|
||||
for argument in arguments {
|
||||
call_stack.top_mut().stack_mut().push(argument);
|
||||
for argument in &arguments {
|
||||
call_stack.top_mut().stack_mut().push(argument.clone());
|
||||
}
|
||||
|
||||
// ensure enough stack space
|
||||
call_stack.top_mut().stack_mut().resize(
|
||||
arguments.len() + (function.stack_size() as usize),
|
||||
Value::Null,
|
||||
);
|
||||
|
||||
while call_stack.maybe_top().is_some()
|
||||
&& call_stack.top().ip() < call_stack.top().instructions().len()
|
||||
{
|
||||
@ -314,6 +320,12 @@ pub fn call<'a>(
|
||||
// push args
|
||||
call_stack.top_mut().stack_mut().append(&mut args);
|
||||
|
||||
// ensure enough stack space
|
||||
call_stack
|
||||
.top_mut()
|
||||
.stack_mut()
|
||||
.resize(arg_count + (function.stack_size() as usize), Value::Null);
|
||||
|
||||
// set fp for callee frame
|
||||
let callee_frame = call_stack.top_mut();
|
||||
callee_frame.set_fp(*arg_count);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user