diff --git a/dmc-lib/src/ast/ast_to_ir_util.rs b/dmc-lib/src/ast/ast_to_ir_util.rs index 8e47d05..b9d108f 100644 --- a/dmc-lib/src/ast/ast_to_ir_util.rs +++ b/dmc-lib/src/ast/ast_to_ir_util.rs @@ -5,7 +5,6 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; -use crate::symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; @@ -40,7 +39,7 @@ pub fn expression_to_ir_expression( } Expression::Identifier(identifier) => { let expressible_symbol = identifier.expressible_symbol(); - Some(IrExpression::Variable(expressible_symbol.ir_variable())) + Some(expressible_symbol.ir_expression()) } Expression::Additive(additive_expression) => { let ir_add = additive_expression.to_ir(builder, symbol_table); diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 4163a84..8bf2db3 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -7,6 +7,7 @@ use crate::ast::type_use::TypeUse; use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_function::IrFunction; +use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; use crate::symbol::FunctionSymbol; @@ -167,13 +168,13 @@ impl Function { // parameters for parameter in &self.parameters { let parameter_symbol = parameter.parameter_symbol(); - let ir_variable = IrVariable::new( + let ir_parameter = IrParameter::new( parameter_symbol.borrow().name(), parameter_symbol.borrow().type_info().clone(), ); - let as_rc = Rc::new(RefCell::new(ir_variable)); + let as_rc = Rc::new(ir_parameter); builder.parameters_mut().push(as_rc.clone()); - parameter_symbol.borrow_mut().set_ir_variable(as_rc); + parameter_symbol.borrow_mut().set_ir_parameter(as_rc); } let entry_block_id = builder.new_block(); diff --git a/dmc-lib/src/ast/ir_builder.rs b/dmc-lib/src/ast/ir_builder.rs index c1f0d82..25c592b 100644 --- a/dmc-lib/src/ast/ir_builder.rs +++ b/dmc-lib/src/ast/ir_builder.rs @@ -1,4 +1,5 @@ use crate::ir::ir_block::IrBlock; +use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use std::cell::RefCell; @@ -6,7 +7,7 @@ use std::collections::HashMap; use std::rc::Rc; pub struct IrBuilder { - parameters: Vec>>, + parameters: Vec>, block_counter: usize, t_var_counter: usize, blocks: HashMap>>, @@ -24,11 +25,11 @@ impl IrBuilder { } } - pub fn parameters(&self) -> &[Rc>] { + pub fn parameters(&self) -> &[Rc] { &self.parameters } - pub fn parameters_mut(&mut self) -> &mut Vec>> { + pub fn parameters_mut(&mut self) -> &mut Vec> { &mut self.parameters } @@ -86,6 +87,6 @@ impl IrBlockBuilder { } pub fn build(self) -> IrBlock { - IrBlock::new(self.id, &format!("b{}:", self.id), self.statements) + IrBlock::new(self.id, &format!("b{}", self.id), self.statements) } } diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index 8e39974..a597d7f 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -96,9 +96,9 @@ impl LetStatement { Expression::String(string_literal) => { IrOperation::Load(IrExpression::String(string_literal.content().into())) } - Expression::Identifier(identifier) => IrOperation::Load(IrExpression::Variable( - identifier.expressible_symbol().ir_variable(), - )), + Expression::Identifier(identifier) => { + IrOperation::Load(identifier.expressible_symbol().ir_expression()) + } Expression::Additive(additive_expression) => { IrOperation::Add(additive_expression.to_ir(builder, symbol_table)) } diff --git a/dmc-lib/src/ir/ir_add.rs b/dmc-lib/src/ir/ir_add.rs index ae70f6b..91f4244 100644 --- a/dmc-lib/src/ir/ir_add.rs +++ b/dmc-lib/src/ir/ir_add.rs @@ -1,5 +1,8 @@ use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::IrVariable; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; +use std::rc::Rc; pub struct IrAdd { left: Box, @@ -20,3 +23,12 @@ impl Display for IrAdd { write!(f, "{} + {}", self.left, self.right) } } + +impl IrAdd { + pub fn uses(&self) -> HashSet> { + let mut set = HashSet::new(); + set.extend(self.left.uses()); + set.extend(self.right.uses()); + set + } +} diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index 47124ab..d6d03a0 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -1,25 +1,33 @@ use crate::ir::ir_operation::IrOperation; use crate::ir::ir_variable::IrVariable; -use std::cell::RefCell; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::rc::Rc; pub struct IrAssign { - destination: Rc>, + destination: Rc, initializer: Box, } impl IrAssign { pub fn new(destination: IrVariable, initializer: IrOperation) -> Self { Self { - destination: Rc::new(RefCell::new(destination)), + destination: Rc::new(destination), initializer: initializer.into(), } } - pub fn destination(&self) -> &Rc> { + pub fn destination(&self) -> &Rc { &self.destination } + + pub fn initializer(&self) -> &IrOperation { + &self.initializer + } + + pub fn uses(&self) -> HashSet> { + self.initializer.uses() + } } impl Display for IrAssign { @@ -27,8 +35,8 @@ impl Display for IrAssign { write!( f, "{}: {} = {}", - self.destination.borrow(), - self.destination.borrow().type_info(), + self.destination, + self.destination.type_info(), self.initializer ) } diff --git a/dmc-lib/src/ir/ir_block.rs b/dmc-lib/src/ir/ir_block.rs index 2f4f692..927d1a9 100644 --- a/dmc-lib/src/ir/ir_block.rs +++ b/dmc-lib/src/ir/ir_block.rs @@ -1,5 +1,7 @@ use crate::ir::ir_statement::IrStatement; +use crate::ir::ir_variable::IrVariable; use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -29,14 +31,136 @@ impl IrBlock { pub fn statements(&self) -> &[IrStatement] { &self.statements } + + fn definitions(&self) -> HashSet> { + let mut set = HashSet::new(); + for statement in &self.statements { + set.extend(statement.definitions()) + } + set + } + + fn uses(&self) -> HashSet> { + let mut set = HashSet::new(); + for statement in &self.statements { + set.extend(statement.uses()); + } + set + } + + fn live_in_live_out( + &self, + ) -> ( + HashMap>>, + HashMap>>, + ) { + let mut live_in: HashMap>> = HashMap::new(); + let mut live_out: HashMap>> = HashMap::new(); + + loop { + let mut did_work = false; + for (statement_index, statement) in self.statements.iter().enumerate().rev() { + // init if necessary + if !live_in.contains_key(&statement_index) { + live_in.insert(statement_index, HashSet::new()); + } + if !live_out.contains_key(&statement_index) { + live_out.insert(statement_index, HashSet::new()); + } + + // out (union of successors ins) + // for now, a statement can only have one successor + // this will need to be updated when we add jumps + if let Some(successor_live_in) = live_in.get(&(statement_index + 1)) { + let statement_live_out = live_out.get_mut(&statement_index).unwrap(); + for ir_variable in successor_live_in { + if statement_live_out.insert(ir_variable.clone()) { + did_work = true; + } + } + } + + // in: use(s) U ( out(s) - def(s) ) + let mut new_ins = statement.uses(); + let statement_live_out = live_out.get(&statement_index).unwrap(); + let defs = statement.definitions(); + let rhs = statement_live_out - &defs; + new_ins.extend(rhs); + + let statement_live_in = live_in.get_mut(&statement_index).unwrap(); + for new_in in new_ins { + if statement_live_in.insert(new_in) { + did_work = true; + } + } + } + if !did_work { + break; + } + } + (live_in, live_out) + } + + fn interference_graph(&self) -> HashMap, HashSet>> { + let mut all_variables: HashSet> = HashSet::new(); + for statement in &self.statements { + all_variables.extend(statement.definitions()); + all_variables.extend(statement.uses()); + } + + let mut graph: HashMap, HashSet>> = HashMap::new(); + for variable in all_variables { + graph.insert(variable, HashSet::new()); + } + + let (_, live_out) = self.live_in_live_out(); + + for (statement_index, statement) in self.statements.iter().enumerate() { + let statement_live_out = live_out.get(&statement_index).unwrap(); + for definition_variable in statement.definitions() { + for live_out_variable in statement_live_out { + if definition_variable != *live_out_variable { + graph + .get_mut(&definition_variable) + .unwrap() + .insert(live_out_variable.clone()); + graph + .get_mut(live_out_variable) + .unwrap() + .insert(definition_variable.clone()); + } + } + } + } + + graph + } } impl Display for IrBlock { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, " {}", self.debug_label)?; - for statement in &self.statements { - writeln!(f, " {}", statement)?; + writeln!(f, " {}:", self.debug_label)?; + + let (live_in, live_out) = self.live_in_live_out(); + + for (statement_index, statement) in self.statements.iter().enumerate() { + let statement_live_in = live_in.get(&statement_index).unwrap(); + let statement_live_out = live_out.get(&statement_index).unwrap(); + + writeln!( + f, + " {} // live_in: {:?}, live_out: {:?}", + statement, statement_live_in, statement_live_out + )?; } + writeln!(f, " // ---- {} meta ----", self.debug_label)?; + writeln!(f, " // definitions: {:?}", self.definitions())?; + writeln!(f, " // uses: {:?}", self.uses())?; + writeln!( + f, + " // interference graph: {:?}", + self.interference_graph() + )?; Ok(()) } } diff --git a/dmc-lib/src/ir/ir_call.rs b/dmc-lib/src/ir/ir_call.rs index 5338424..b93e023 100644 --- a/dmc-lib/src/ir/ir_call.rs +++ b/dmc-lib/src/ir/ir_call.rs @@ -1,4 +1,6 @@ use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::IrVariable; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -14,6 +16,14 @@ impl IrCall { arguments, } } + + pub fn uses(&self) -> HashSet> { + let mut set = HashSet::new(); + for argument in &self.arguments { + set.extend(argument.uses()); + } + set + } } impl Display for IrCall { diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index 819a121..5846f76 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -1,10 +1,12 @@ +use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVariable; -use std::cell::RefCell; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::rc::Rc; pub enum IrExpression { - Variable(Rc>), + Parameter(Rc), + Variable(Rc), Int(i32), String(Rc), } @@ -12,8 +14,11 @@ pub enum IrExpression { impl Display for IrExpression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { + IrExpression::Parameter(ir_parameter) => { + write!(f, "{}", ir_parameter) + } IrExpression::Variable(ir_variable) => { - write!(f, "{}", ir_variable.borrow()) + write!(f, "{}", ir_variable) } IrExpression::Int(i) => { write!(f, "{}", i) @@ -24,3 +29,24 @@ impl Display for IrExpression { } } } + +impl IrExpression { + pub fn uses(&self) -> HashSet> { + let mut set = HashSet::new(); + match self { + IrExpression::Parameter(_) => { + // no-op + } + IrExpression::Variable(ir_variable) => { + set.insert(ir_variable.clone()); + } + IrExpression::Int(_) => { + // no-op + } + IrExpression::String(_) => { + // no-op + } + } + set + } +} diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index 3e1e70a..71352bf 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -1,4 +1,5 @@ use crate::ir::ir_block::IrBlock; +use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVariable; use crate::type_info::TypeInfo; use std::cell::RefCell; @@ -7,7 +8,7 @@ use std::rc::Rc; pub struct IrFunction { name: Rc, - parameters: Vec>>, + parameters: Vec>, return_type_info: TypeInfo, entry: Rc>, } @@ -15,7 +16,7 @@ pub struct IrFunction { impl IrFunction { pub fn new( name: Rc, - parameters: &[Rc>], + parameters: &[Rc], return_type_info: TypeInfo, entry: Rc>, ) -> Self { @@ -32,12 +33,7 @@ impl Display for IrFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "fn {}(", self.name)?; for (i, parameter) in self.parameters.iter().enumerate() { - write!( - f, - "{}: {}", - parameter.borrow(), - parameter.borrow().type_info() - )?; + write!(f, "{}: {}", parameter, parameter.type_info())?; if i < self.parameters.len() - 1 { write!(f, ", ")?; } diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index cac9be5..fc8ad59 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -1,7 +1,10 @@ use crate::ir::ir_add::IrAdd; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::IrVariable; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; +use std::rc::Rc; pub enum IrOperation { Load(IrExpression), @@ -24,3 +27,13 @@ impl Display for IrOperation { } } } + +impl IrOperation { + pub fn uses(&self) -> HashSet> { + match self { + IrOperation::Load(ir_expression) => ir_expression.uses(), + IrOperation::Add(ir_add) => ir_add.uses(), + IrOperation::Call(ir_call) => ir_call.uses(), + } + } +} diff --git a/dmc-lib/src/ir/ir_parameter.rs b/dmc-lib/src/ir/ir_parameter.rs new file mode 100644 index 0000000..13542d7 --- /dev/null +++ b/dmc-lib/src/ir/ir_parameter.rs @@ -0,0 +1,27 @@ +use crate::type_info::TypeInfo; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrParameter { + name: Rc, + type_info: TypeInfo, +} + +impl IrParameter { + pub fn new(name: &str, type_info: TypeInfo) -> Self { + Self { + name: name.into(), + type_info, + } + } + + pub fn type_info(&self) -> &TypeInfo { + &self.type_info + } +} + +impl Display for IrParameter { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} diff --git a/dmc-lib/src/ir/ir_return.rs b/dmc-lib/src/ir/ir_return.rs index fcf0332..a751174 100644 --- a/dmc-lib/src/ir/ir_return.rs +++ b/dmc-lib/src/ir/ir_return.rs @@ -1,5 +1,8 @@ use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::IrVariable; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; +use std::rc::Rc; pub struct IrReturn { value: Option, @@ -9,6 +12,10 @@ impl IrReturn { pub fn new(value: Option) -> Self { Self { value } } + + pub fn uses(&self) -> HashSet> { + self.value.as_ref().map_or(HashSet::new(), |v| v.uses()) + } } impl Display for IrReturn { diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index 128b9a5..a4378e8 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -1,7 +1,10 @@ use crate::ir::ir_assign::IrAssign; use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; +use crate::ir::ir_variable::IrVariable; +use std::collections::HashSet; use std::fmt::{Display, Formatter}; +use std::rc::Rc; pub enum IrStatement { Assign(IrAssign), @@ -9,6 +12,38 @@ pub enum IrStatement { Return(IrReturn), } +impl IrStatement { + pub fn definitions(&self) -> HashSet> { + let mut set = HashSet::new(); + match self { + IrStatement::Assign(ir_assign) => { + set.insert(ir_assign.destination().clone()); + } + IrStatement::Call(_) => { + // no-op + } + IrStatement::Return(_) => { + // no-op + } + } + set + } + + pub fn uses(&self) -> HashSet> { + let mut set = HashSet::new(); + match self { + IrStatement::Assign(ir_assign) => { + set.extend(ir_assign.uses()); + } + IrStatement::Call(ir_call) => { + set.extend(ir_call.uses()); + } + IrStatement::Return(ir_return) => set.extend(ir_return.uses()), + } + set + } +} + impl Display for IrStatement { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 7350d3f..0ae26d7 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -1,7 +1,9 @@ use crate::type_info::TypeInfo; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::{Hash, Hasher}; use std::rc::Rc; +/// Represents a virtual register pub struct IrVariable { name: Rc, type_info: TypeInfo, @@ -15,6 +17,10 @@ impl IrVariable { } } + pub fn name(&self) -> &str { + &self.name + } + pub fn type_info(&self) -> &TypeInfo { &self.type_info } @@ -25,3 +31,23 @@ impl Display for IrVariable { write!(f, "{}", self.name) } } + +impl Debug for IrVariable { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} + +impl Hash for IrVariable { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl PartialEq for IrVariable { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Eq for IrVariable {} diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index ecf90dc..af5c0c4 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -5,6 +5,7 @@ pub mod ir_call; pub mod ir_expression; pub mod ir_function; pub mod ir_operation; +pub mod ir_parameter; pub mod ir_return; pub mod ir_statement; pub mod ir_variable; diff --git a/dmc-lib/src/symbol.rs b/dmc-lib/src/symbol.rs index aa1b9b7..3ca7489 100644 --- a/dmc-lib/src/symbol.rs +++ b/dmc-lib/src/symbol.rs @@ -1,3 +1,5 @@ +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVariable; use crate::type_info::TypeInfo; use std::cell::RefCell; @@ -48,7 +50,7 @@ impl FunctionSymbol { pub struct ParameterSymbol { name: Rc, type_info: TypeInfo, - ir_variable: Option>>, + ir_parameter: Option>, #[deprecated] stack_frame_offset: Option, @@ -59,7 +61,7 @@ impl ParameterSymbol { Self { name: name.into(), type_info, - ir_variable: None, + ir_parameter: None, stack_frame_offset: None, } } @@ -76,14 +78,12 @@ impl ParameterSymbol { &self.type_info } - pub fn set_ir_variable(&mut self, ir_variable: Rc>) { - self.ir_variable = Some(ir_variable); + pub fn set_ir_parameter(&mut self, ir_parameter: Rc) { + self.ir_parameter = Some(ir_parameter); } - pub fn ir_variable(&self) -> &Rc> { - self.ir_variable - .as_ref() - .expect("ir_variable not yet initialized") + pub fn ir_parameter(&self) -> &Rc { + self.ir_parameter.as_ref().unwrap() } #[deprecated] @@ -100,7 +100,7 @@ impl ParameterSymbol { pub struct VariableSymbol { name: Rc, type_info: Option, - ir_variable: Option>>, + ir_variable: Option>, #[deprecated] register: Option, @@ -134,11 +134,11 @@ impl VariableSymbol { .expect("TypeInfo not initialized. Did you type check?") } - pub fn set_ir_variable(&mut self, ir_variable: Rc>) { + pub fn set_ir_variable(&mut self, ir_variable: Rc) { self.ir_variable = Some(ir_variable); } - pub fn ir_variable(&self) -> &Rc> { + pub fn ir_variable(&self) -> &Rc { self.ir_variable .as_ref() .expect("ir_variable not yet initialized") @@ -160,16 +160,16 @@ pub enum ExpressibleSymbol { } impl ExpressibleSymbol { - pub fn ir_variable(&self) -> Rc> { + pub fn ir_expression(&self) -> IrExpression { match self { ExpressibleSymbol::Function(_) => { panic!("Cannot get ir_variable for FunctionSymbol"); } ExpressibleSymbol::Parameter(parameter_symbol) => { - parameter_symbol.borrow().ir_variable().clone() + IrExpression::Parameter(parameter_symbol.borrow().ir_parameter().clone()) } ExpressibleSymbol::Variable(variable_symbol) => { - variable_symbol.borrow().ir_variable().clone() + IrExpression::Variable(variable_symbol.borrow().ir_variable().clone()) } } } diff --git a/examples/call.dm b/examples/call.dm index 0aa5ea2..dd44a62 100644 --- a/examples/call.dm +++ b/examples/call.dm @@ -8,4 +8,5 @@ fn main() let y = add(1, 2) println(y) println(add(3, add(4, 5))) + println(y) end \ No newline at end of file