Refactor optimizer utilities
Removes unused `flatten_tuple` function from optimizer utilities. The functionality was moved to the `Folder` struct, making it more contextually appropriate. This change streamlines the utility module and improves code organization.
This commit is contained in:
@@ -1,6 +1,4 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{
|
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx, UpvalueIdx};
|
||||||
Address, AnalyzedNode, BoundKind, GlobalIdx, UpvalueIdx,
|
|
||||||
};
|
|
||||||
use crate::ast::nodes::Node;
|
use crate::ast::nodes::Node;
|
||||||
use crate::ast::types::{Purity, Value};
|
use crate::ast::types::{Purity, Value};
|
||||||
use crate::ast::vm::Closure;
|
use crate::ast::vm::Closure;
|
||||||
@@ -8,9 +6,9 @@ use std::cell::RefCell;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::substitution_map::SubstitutionMap;
|
|
||||||
use super::folder::Folder;
|
use super::folder::Folder;
|
||||||
use super::inliner::Inliner;
|
use super::inliner::Inliner;
|
||||||
|
use super::substitution_map::SubstitutionMap;
|
||||||
use super::utils::{PathTracker, UsageInfo};
|
use super::utils::{PathTracker, UsageInfo};
|
||||||
|
|
||||||
pub struct Optimizer {
|
pub struct Optimizer {
|
||||||
@@ -177,6 +175,9 @@ impl Optimizer {
|
|||||||
let args = self.visit_node(*args, sub, path);
|
let args = self.visit_node(*args, sub, path);
|
||||||
|
|
||||||
if self.enabled {
|
if self.enabled {
|
||||||
|
let mut arg_nodes = Vec::new();
|
||||||
|
self.flatten_tuple(args.clone(), &mut arg_nodes);
|
||||||
|
|
||||||
if let BoundKind::Lambda {
|
if let BoundKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
@@ -192,7 +193,7 @@ impl Optimizer {
|
|||||||
path.inlining_depth += 1;
|
path.inlining_depth += 1;
|
||||||
let mut inner_sub = SubstitutionMap::new();
|
let mut inner_sub = SubstitutionMap::new();
|
||||||
let collapsed = if inliner
|
let collapsed = if inliner
|
||||||
.prepare_beta_reduction(params, &args, body, &mut inner_sub)
|
.prepare_beta_reduction(params, &arg_nodes, body, &mut inner_sub)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
Some(self.visit_node((**body).clone(), &mut inner_sub, path))
|
Some(self.visit_node((**body).clone(), &mut inner_sub, path))
|
||||||
@@ -231,7 +232,7 @@ impl Optimizer {
|
|||||||
path.inlining_stack.insert(*idx);
|
path.inlining_stack.insert(*idx);
|
||||||
path.inlining_depth += 1;
|
path.inlining_depth += 1;
|
||||||
let collapsed = if inliner
|
let collapsed = if inliner
|
||||||
.prepare_beta_reduction(params, &args, body, &mut inner_sub)
|
.prepare_beta_reduction(params, &arg_nodes, body, &mut inner_sub)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
Some(self.visit_node((**body).clone(), &mut inner_sub, path))
|
Some(self.visit_node((**body).clone(), &mut inner_sub, path))
|
||||||
@@ -273,7 +274,7 @@ impl Optimizer {
|
|||||||
let collapsed = if inliner
|
let collapsed = if inliner
|
||||||
.prepare_beta_reduction(
|
.prepare_beta_reduction(
|
||||||
&closure.parameter_node,
|
&closure.parameter_node,
|
||||||
&args,
|
&arg_nodes,
|
||||||
&inlined_body,
|
&inlined_body,
|
||||||
&mut closure_sub,
|
&mut closure_sub,
|
||||||
)
|
)
|
||||||
@@ -291,7 +292,7 @@ impl Optimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(folded) = folder.try_fold_pure(&callee, &args) {
|
if let Some(folded) = folder.try_fold_pure(&callee, &arg_nodes) {
|
||||||
return folded;
|
return folded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,4 +534,21 @@ impl Optimizer {
|
|||||||
ty: metrics,
|
ty: metrics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flatten_tuple(&self, node: AnalyzedNode, into: &mut Vec<AnalyzedNode>) {
|
||||||
|
match node.kind {
|
||||||
|
BoundKind::Tuple { elements } => {
|
||||||
|
for el in elements {
|
||||||
|
self.flatten_tuple(el, into);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BoundKind::Record { fields } => {
|
||||||
|
for (_, v) in fields {
|
||||||
|
self.flatten_tuple(v, into);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BoundKind::Nop => {}
|
||||||
|
_ => into.push(node),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +1,82 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, NodeMetrics};
|
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, NodeMetrics};
|
||||||
use crate::ast::nodes::Node;
|
use crate::ast::nodes::Node;
|
||||||
use crate::ast::types::{Purity, StaticType, Value};
|
use crate::ast::types::{Purity, StaticType, Value};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::utils::flatten_tuple;
|
pub struct Folder<'a> {
|
||||||
|
pub globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
|
||||||
pub struct Folder<'a> {
|
}
|
||||||
pub globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
|
|
||||||
}
|
impl<'a> Folder<'a> {
|
||||||
|
pub fn new(globals: &'a Option<Rc<RefCell<Vec<Value>>>>) -> Self {
|
||||||
impl<'a> Folder<'a> {
|
Self { globals }
|
||||||
pub fn new(globals: &'a Option<Rc<RefCell<Vec<Value>>>>) -> Self {
|
}
|
||||||
Self { globals }
|
|
||||||
}
|
pub fn make_constant_node(&self, val: Value, template: &AnalyzedNode) -> AnalyzedNode {
|
||||||
|
let ty = val.static_type();
|
||||||
pub fn make_constant_node(&self, val: Value, template: &AnalyzedNode) -> AnalyzedNode {
|
let typed_original = Rc::new(Node {
|
||||||
let ty = val.static_type();
|
identity: template.identity.clone(),
|
||||||
let typed_original = Rc::new(Node {
|
kind: BoundKind::Constant(val.clone()),
|
||||||
identity: template.identity.clone(),
|
ty: ty.clone(),
|
||||||
kind: BoundKind::Constant(val.clone()),
|
});
|
||||||
ty: ty.clone(),
|
Node {
|
||||||
});
|
identity: template.identity.clone(),
|
||||||
Node {
|
kind: BoundKind::Constant(val),
|
||||||
identity: template.identity.clone(),
|
ty: NodeMetrics {
|
||||||
kind: BoundKind::Constant(val),
|
original: typed_original,
|
||||||
ty: NodeMetrics {
|
purity: Purity::Pure,
|
||||||
original: typed_original,
|
is_recursive: false,
|
||||||
purity: Purity::Pure,
|
},
|
||||||
is_recursive: false,
|
}
|
||||||
},
|
}
|
||||||
}
|
|
||||||
}
|
pub fn make_nop_node(&self, template: &AnalyzedNode) -> AnalyzedNode {
|
||||||
|
let typed_original = Rc::new(Node {
|
||||||
pub fn make_nop_node(&self, template: &AnalyzedNode) -> AnalyzedNode {
|
identity: template.identity.clone(),
|
||||||
let typed_original = Rc::new(Node {
|
kind: BoundKind::Nop,
|
||||||
identity: template.identity.clone(),
|
ty: StaticType::Void,
|
||||||
kind: BoundKind::Nop,
|
});
|
||||||
ty: StaticType::Void,
|
Node {
|
||||||
});
|
identity: template.identity.clone(),
|
||||||
Node {
|
kind: BoundKind::Nop,
|
||||||
identity: template.identity.clone(),
|
ty: NodeMetrics {
|
||||||
kind: BoundKind::Nop,
|
original: typed_original,
|
||||||
ty: NodeMetrics {
|
purity: Purity::Pure,
|
||||||
original: typed_original,
|
is_recursive: false,
|
||||||
purity: Purity::Pure,
|
},
|
||||||
is_recursive: false,
|
}
|
||||||
},
|
}
|
||||||
}
|
|
||||||
}
|
pub fn try_fold_pure(
|
||||||
|
&self,
|
||||||
pub fn try_fold_pure(&self, callee: &AnalyzedNode, args: &AnalyzedNode) -> Option<AnalyzedNode> {
|
callee: &AnalyzedNode,
|
||||||
if callee.ty.purity < Purity::Pure || args.ty.purity < Purity::Pure {
|
arg_nodes: &[AnalyzedNode],
|
||||||
return None;
|
) -> Option<AnalyzedNode> {
|
||||||
}
|
if callee.ty.purity < Purity::Pure {
|
||||||
|
return None;
|
||||||
let mut arg_nodes = Vec::new();
|
}
|
||||||
flatten_tuple(args.clone(), &mut arg_nodes);
|
|
||||||
let mut arg_values = Vec::with_capacity(arg_nodes.len());
|
let mut arg_values = Vec::with_capacity(arg_nodes.len());
|
||||||
for node in arg_nodes {
|
for node in arg_nodes {
|
||||||
if let BoundKind::Constant(val) = node.kind {
|
if let BoundKind::Constant(val) = &node.kind {
|
||||||
arg_values.push(val);
|
arg_values.push(val.clone());
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let func_val = match &callee.kind {
|
let func_val = match &callee.kind {
|
||||||
BoundKind::Get {
|
BoundKind::Get {
|
||||||
addr: Address::Global(idx),
|
addr: Address::Global(idx),
|
||||||
..
|
..
|
||||||
} => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(),
|
} => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(),
|
||||||
BoundKind::Constant(val) => val.clone(),
|
BoundKind::Constant(val) => val.clone(),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let result = match func_val {
|
let result = match func_val {
|
||||||
Value::Function(f) => (f.func)(arg_values),
|
Value::Function(f) => (f.func)(arg_values),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(self.make_constant_node(result, callee))
|
Some(self.make_constant_node(result, callee))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::substitution_map::SubstitutionMap;
|
use super::substitution_map::SubstitutionMap;
|
||||||
use super::utils::{flatten_tuple, UsageInfo};
|
use super::utils::UsageInfo;
|
||||||
|
|
||||||
pub struct Inliner<'a> {
|
pub struct Inliner<'a> {
|
||||||
pub globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
|
pub globals: &'a Option<Rc<RefCell<Vec<Value>>>>,
|
||||||
@@ -64,18 +64,15 @@ impl<'a> Inliner<'a> {
|
|||||||
pub fn prepare_beta_reduction(
|
pub fn prepare_beta_reduction(
|
||||||
&self,
|
&self,
|
||||||
params: &AnalyzedNode,
|
params: &AnalyzedNode,
|
||||||
args: &AnalyzedNode,
|
arg_vals: &[AnalyzedNode],
|
||||||
body: &AnalyzedNode,
|
body: &AnalyzedNode,
|
||||||
sub: &mut SubstitutionMap,
|
sub: &mut SubstitutionMap,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let mut body_usage = UsageInfo::default();
|
let mut body_usage = UsageInfo::default();
|
||||||
body_usage.collect(body);
|
body_usage.collect(body);
|
||||||
|
|
||||||
let mut arg_vals = Vec::new();
|
|
||||||
flatten_tuple(args.clone(), &mut arg_vals);
|
|
||||||
|
|
||||||
let mut slot_index = 0;
|
let mut slot_index = 0;
|
||||||
self.map_params_to_args(params, &arg_vals, &mut slot_index, sub, &body_usage);
|
self.map_params_to_args(params, arg_vals, &mut slot_index, sub, &body_usage);
|
||||||
|
|
||||||
if slot_index != arg_vals.len() {
|
if slot_index != arg_vals.len() {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ pub use engine::Optimizer;
|
|||||||
pub use folder::Folder;
|
pub use folder::Folder;
|
||||||
pub use inliner::Inliner;
|
pub use inliner::Inliner;
|
||||||
pub use substitution_map::SubstitutionMap;
|
pub use substitution_map::SubstitutionMap;
|
||||||
pub use utils::{PathTracker, UsageInfo, flatten_tuple};
|
pub use utils::{PathTracker, UsageInfo};
|
||||||
|
|||||||
@@ -1,174 +1,174 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot, UpvalueIdx};
|
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot, UpvalueIdx};
|
||||||
use crate::ast::nodes::Node;
|
use crate::ast::nodes::Node;
|
||||||
use crate::ast::types::{Value};
|
use crate::ast::types::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SubstitutionMap {
|
pub struct SubstitutionMap {
|
||||||
pub values: HashMap<Address, Value>,
|
pub values: HashMap<Address, Value>,
|
||||||
pub ast_substitutions: HashMap<Address, AnalyzedNode>,
|
pub ast_substitutions: HashMap<Address, AnalyzedNode>,
|
||||||
pub slot_mapping: HashMap<LocalSlot, LocalSlot>,
|
pub slot_mapping: HashMap<LocalSlot, LocalSlot>,
|
||||||
pub assigned: HashSet<Address>,
|
pub assigned: HashSet<Address>,
|
||||||
pub next_slot: u32,
|
pub next_slot: u32,
|
||||||
pub used: HashSet<Address>,
|
pub used: HashSet<Address>,
|
||||||
pub captured_slots: HashSet<LocalSlot>,
|
pub captured_slots: HashSet<LocalSlot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubstitutionMap {
|
impl SubstitutionMap {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) {
|
pub fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) {
|
||||||
self.ast_substitutions.insert(addr, node);
|
self.ast_substitutions.insert(addr, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_slot(&mut self, old_slot: LocalSlot) -> LocalSlot {
|
pub fn map_slot(&mut self, old_slot: LocalSlot) -> LocalSlot {
|
||||||
if let Some(&new_slot) = self.slot_mapping.get(&old_slot) {
|
if let Some(&new_slot) = self.slot_mapping.get(&old_slot) {
|
||||||
return new_slot;
|
return new_slot;
|
||||||
}
|
}
|
||||||
let new_slot = LocalSlot(self.next_slot);
|
let new_slot = LocalSlot(self.next_slot);
|
||||||
self.slot_mapping.insert(old_slot, new_slot);
|
self.slot_mapping.insert(old_slot, new_slot);
|
||||||
self.next_slot += 1;
|
self.next_slot += 1;
|
||||||
new_slot
|
new_slot
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_address(&mut self, addr: Address) -> Address {
|
pub fn map_address(&mut self, addr: Address) -> Address {
|
||||||
match addr {
|
match addr {
|
||||||
Address::Local(slot) => Address::Local(self.map_slot(slot)),
|
Address::Local(slot) => Address::Local(self.map_slot(slot)),
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_value(&mut self, addr: Address, val: Value) {
|
pub fn add_value(&mut self, addr: Address, val: Value) {
|
||||||
self.values.insert(addr, val);
|
self.values.insert(addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self, addr: &Address) -> Option<&Value> {
|
pub fn get_value(&self, addr: &Address) -> Option<&Value> {
|
||||||
self.values.get(addr)
|
self.values.get(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_value(&mut self, addr: &Address) {
|
pub fn remove_value(&mut self, addr: &Address) {
|
||||||
self.values.remove(addr);
|
self.values.remove(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reindex_addr(&self, addr: Address, mapping: &[Option<u32>]) -> Address {
|
fn reindex_addr(&self, addr: Address, mapping: &[Option<u32>]) -> Address {
|
||||||
if let Address::Upvalue(idx) = addr
|
if let Address::Upvalue(idx) = addr
|
||||||
&& let Some(res) = mapping.get(idx.0 as usize)
|
&& let Some(res) = mapping.get(idx.0 as usize)
|
||||||
&& let Some(new_idx) = res
|
&& let Some(new_idx) = res
|
||||||
{
|
{
|
||||||
Address::Upvalue(UpvalueIdx(*new_idx))
|
Address::Upvalue(UpvalueIdx(*new_idx))
|
||||||
} else {
|
} else {
|
||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reindex_upvalues(&self, node: AnalyzedNode, mapping: &[Option<u32>]) -> AnalyzedNode {
|
pub fn reindex_upvalues(&self, node: AnalyzedNode, mapping: &[Option<u32>]) -> AnalyzedNode {
|
||||||
let (new_kind, metrics) = match node.kind {
|
let (new_kind, metrics) = match node.kind {
|
||||||
BoundKind::Get { addr, name } => (
|
BoundKind::Get { addr, name } => (
|
||||||
BoundKind::Get {
|
BoundKind::Get {
|
||||||
addr: self.reindex_addr(addr, mapping),
|
addr: self.reindex_addr(addr, mapping),
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
),
|
),
|
||||||
BoundKind::Lambda {
|
BoundKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues,
|
upvalues,
|
||||||
body,
|
body,
|
||||||
positional_count,
|
positional_count,
|
||||||
} => {
|
} => {
|
||||||
let mut next_upvalues = Vec::new();
|
let mut next_upvalues = Vec::new();
|
||||||
for addr in upvalues {
|
for addr in upvalues {
|
||||||
next_upvalues.push(self.reindex_addr(addr, mapping));
|
next_upvalues.push(self.reindex_addr(addr, mapping));
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
BoundKind::Lambda {
|
BoundKind::Lambda {
|
||||||
params,
|
params,
|
||||||
upvalues: next_upvalues,
|
upvalues: next_upvalues,
|
||||||
body,
|
body,
|
||||||
positional_count,
|
positional_count,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::If {
|
BoundKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => {
|
} => {
|
||||||
let cond = Box::new(self.reindex_upvalues(*cond, mapping));
|
let cond = Box::new(self.reindex_upvalues(*cond, mapping));
|
||||||
let then_br = Box::new(self.reindex_upvalues(*then_br, mapping));
|
let then_br = Box::new(self.reindex_upvalues(*then_br, mapping));
|
||||||
let else_br = else_br.map(|e| Box::new(self.reindex_upvalues(*e, mapping)));
|
let else_br = else_br.map(|e| Box::new(self.reindex_upvalues(*e, mapping)));
|
||||||
(
|
(
|
||||||
BoundKind::If {
|
BoundKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
BoundKind::Block { exprs } => {
|
||||||
let exprs = exprs
|
let exprs = exprs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| self.reindex_upvalues(e, mapping))
|
.map(|e| self.reindex_upvalues(e, mapping))
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Block { exprs }, node.ty.clone())
|
(BoundKind::Block { exprs }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
BoundKind::Call { callee, args } => {
|
||||||
let callee = Box::new(self.reindex_upvalues(*callee, mapping));
|
let callee = Box::new(self.reindex_upvalues(*callee, mapping));
|
||||||
let args = Box::new(self.reindex_upvalues(*args, mapping));
|
let args = Box::new(self.reindex_upvalues(*args, mapping));
|
||||||
(BoundKind::Call { callee, args }, node.ty.clone())
|
(BoundKind::Call { callee, args }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Define {
|
BoundKind::Define {
|
||||||
name,
|
name,
|
||||||
addr,
|
addr,
|
||||||
kind,
|
kind,
|
||||||
value,
|
value,
|
||||||
captured_by,
|
captured_by,
|
||||||
} => {
|
} => {
|
||||||
let value = Box::new(self.reindex_upvalues(*value, mapping));
|
let value = Box::new(self.reindex_upvalues(*value, mapping));
|
||||||
(
|
(
|
||||||
BoundKind::Define {
|
BoundKind::Define {
|
||||||
name,
|
name,
|
||||||
addr,
|
addr,
|
||||||
kind,
|
kind,
|
||||||
value,
|
value,
|
||||||
captured_by,
|
captured_by,
|
||||||
},
|
},
|
||||||
node.ty.clone(),
|
node.ty.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value } => {
|
BoundKind::Set { addr, value } => {
|
||||||
let value = Box::new(self.reindex_upvalues(*value, mapping));
|
let value = Box::new(self.reindex_upvalues(*value, mapping));
|
||||||
(BoundKind::Set { addr, value }, node.ty.clone())
|
(BoundKind::Set { addr, value }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
BoundKind::Tuple { elements } => {
|
||||||
let elements = elements
|
let elements = elements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| self.reindex_upvalues(e, mapping))
|
.map(|e| self.reindex_upvalues(e, mapping))
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Tuple { elements }, node.ty.clone())
|
(BoundKind::Tuple { elements }, node.ty.clone())
|
||||||
}
|
}
|
||||||
BoundKind::Record { fields } => {
|
BoundKind::Record { fields } => {
|
||||||
let fields = fields
|
let fields = fields
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
(
|
(
|
||||||
self.reindex_upvalues(k, mapping),
|
self.reindex_upvalues(k, mapping),
|
||||||
self.reindex_upvalues(v, mapping),
|
self.reindex_upvalues(v, mapping),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
(BoundKind::Record { fields }, node.ty.clone())
|
(BoundKind::Record { fields }, node.ty.clone())
|
||||||
}
|
}
|
||||||
k => (k, node.ty.clone()),
|
k => (k, node.ty.clone()),
|
||||||
};
|
};
|
||||||
Node {
|
Node {
|
||||||
identity: node.identity.clone(),
|
identity: node.identity.clone(),
|
||||||
kind: new_kind,
|
kind: new_kind,
|
||||||
ty: metrics,
|
ty: metrics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+170
-188
@@ -1,188 +1,170 @@
|
|||||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx};
|
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx};
|
||||||
use crate::ast::types::{Identity, Value};
|
use crate::ast::types::{Identity, Value};
|
||||||
use crate::ast::vm::Closure;
|
use crate::ast::vm::Closure;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
// --- PathTracker ---
|
// --- PathTracker ---
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PathTracker {
|
pub struct PathTracker {
|
||||||
pub inlining_depth: usize,
|
pub inlining_depth: usize,
|
||||||
pub inlining_stack: HashSet<GlobalIdx>,
|
pub inlining_stack: HashSet<GlobalIdx>,
|
||||||
pub identity_stack: HashSet<Identity>,
|
pub identity_stack: HashSet<Identity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathTracker {
|
impl PathTracker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_lambda(&mut self, identity: &Identity) -> bool {
|
pub fn enter_lambda(&mut self, identity: &Identity) -> bool {
|
||||||
if self.identity_stack.contains(identity) {
|
if self.identity_stack.contains(identity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self.identity_stack.insert(identity.clone());
|
self.identity_stack.insert(identity.clone());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit_lambda(&mut self, identity: &Identity) {
|
pub fn exit_lambda(&mut self, identity: &Identity) {
|
||||||
self.identity_stack.remove(identity);
|
self.identity_stack.remove(identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- UsageInfo ---
|
// --- UsageInfo ---
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct UsageInfo {
|
pub struct UsageInfo {
|
||||||
pub used: HashSet<Address>,
|
pub used: HashSet<Address>,
|
||||||
pub assigned: HashSet<Address>,
|
pub assigned: HashSet<Address>,
|
||||||
pub used_identities: HashSet<Identity>,
|
pub used_identities: HashSet<Identity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsageInfo {
|
impl UsageInfo {
|
||||||
pub fn is_assigned(&self, addr: &Address) -> bool {
|
pub fn is_assigned(&self, addr: &Address) -> bool {
|
||||||
self.assigned.contains(addr)
|
self.assigned.contains(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_used(&self, addr: &Address) -> bool {
|
pub fn is_used(&self, addr: &Address) -> bool {
|
||||||
self.used.contains(addr)
|
self.used.contains(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect(&mut self, node: &AnalyzedNode) {
|
pub fn collect(&mut self, node: &AnalyzedNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Destructure { pattern, value } => {
|
BoundKind::Destructure { pattern, value } => {
|
||||||
self.collect_pattern(pattern);
|
self.collect_pattern(pattern);
|
||||||
self.collect(value);
|
self.collect(value);
|
||||||
}
|
}
|
||||||
BoundKind::Constant(v) => {
|
BoundKind::Constant(v) => {
|
||||||
if let Value::Object(obj) = v
|
if let Value::Object(obj) = v
|
||||||
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
||||||
{
|
{
|
||||||
self.used_identities
|
self.used_identities
|
||||||
.insert(closure.function_node.identity.clone());
|
.insert(closure.function_node.identity.clone());
|
||||||
self.collect(&closure.function_node);
|
self.collect(&closure.function_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Get { addr, .. } => {
|
BoundKind::Get { addr, .. } => {
|
||||||
self.used.insert(*addr);
|
self.used.insert(*addr);
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, value } => {
|
BoundKind::Set { addr, value } => {
|
||||||
self.assigned.insert(*addr);
|
self.assigned.insert(*addr);
|
||||||
self.collect(value);
|
self.collect(value);
|
||||||
}
|
}
|
||||||
BoundKind::Lambda {
|
BoundKind::Lambda {
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
upvalues,
|
upvalues,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.used_identities.insert(node.identity.clone());
|
self.used_identities.insert(node.identity.clone());
|
||||||
|
|
||||||
let mut inner_info = UsageInfo::default();
|
let mut inner_info = UsageInfo::default();
|
||||||
inner_info.collect(params);
|
inner_info.collect(params);
|
||||||
inner_info.collect(body);
|
inner_info.collect(body);
|
||||||
|
|
||||||
// Propagate globals and identities
|
// Propagate globals and identities
|
||||||
for addr in &inner_info.used {
|
for addr in &inner_info.used {
|
||||||
if let Address::Global(_) = addr {
|
if let Address::Global(_) = addr {
|
||||||
self.used.insert(*addr);
|
self.used.insert(*addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for addr in &inner_info.assigned {
|
for addr in &inner_info.assigned {
|
||||||
if let Address::Global(_) = addr {
|
if let Address::Global(_) = addr {
|
||||||
self.assigned.insert(*addr);
|
self.assigned.insert(*addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.used_identities.extend(inner_info.used_identities);
|
self.used_identities.extend(inner_info.used_identities);
|
||||||
|
|
||||||
// Map used upvalues to parent scope
|
// Map used upvalues to parent scope
|
||||||
for addr in &inner_info.used {
|
for addr in &inner_info.used {
|
||||||
if let Address::Upvalue(idx) = addr
|
if let Address::Upvalue(idx) = addr
|
||||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||||
{
|
{
|
||||||
self.used.insert(*parent_addr);
|
self.used.insert(*parent_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Map assigned upvalues to parent scope
|
// Map assigned upvalues to parent scope
|
||||||
for addr in &inner_info.assigned {
|
for addr in &inner_info.assigned {
|
||||||
if let Address::Upvalue(idx) = addr
|
if let Address::Upvalue(idx) = addr
|
||||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||||
{
|
{
|
||||||
self.assigned.insert(*parent_addr);
|
self.assigned.insert(*parent_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Block { exprs } => {
|
BoundKind::Block { exprs } => {
|
||||||
for e in exprs {
|
for e in exprs {
|
||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::If {
|
BoundKind::If {
|
||||||
cond,
|
cond,
|
||||||
then_br,
|
then_br,
|
||||||
else_br,
|
else_br,
|
||||||
} => {
|
} => {
|
||||||
self.collect(cond);
|
self.collect(cond);
|
||||||
self.collect(then_br);
|
self.collect(then_br);
|
||||||
if let Some(e) = else_br {
|
if let Some(e) = else_br {
|
||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Call { callee, args } => {
|
BoundKind::Call { callee, args } => {
|
||||||
self.collect(callee);
|
self.collect(callee);
|
||||||
self.collect(args);
|
self.collect(args);
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
BoundKind::Tuple { elements } => {
|
||||||
for e in elements {
|
for e in elements {
|
||||||
self.collect(e);
|
self.collect(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Record { fields } => {
|
BoundKind::Record { fields } => {
|
||||||
for (k, v) in fields {
|
for (k, v) in fields {
|
||||||
self.collect(k);
|
self.collect(k);
|
||||||
self.collect(v);
|
self.collect(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoundKind::Define { value, .. } => {
|
BoundKind::Define { value, .. } => {
|
||||||
self.collect(value);
|
self.collect(value);
|
||||||
}
|
}
|
||||||
BoundKind::Expansion { bound_expanded, .. } => {
|
BoundKind::Expansion { bound_expanded, .. } => {
|
||||||
self.collect(bound_expanded);
|
self.collect(bound_expanded);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
BoundKind::Define { addr, .. } => {
|
BoundKind::Define { addr, .. } => {
|
||||||
self.assigned.insert(*addr);
|
self.assigned.insert(*addr);
|
||||||
}
|
}
|
||||||
BoundKind::Set { addr, .. } => {
|
BoundKind::Set { addr, .. } => {
|
||||||
self.assigned.insert(*addr);
|
self.assigned.insert(*addr);
|
||||||
}
|
}
|
||||||
BoundKind::Tuple { elements } => {
|
BoundKind::Tuple { elements } => {
|
||||||
for el in elements {
|
for el in elements {
|
||||||
self.collect_pattern(el);
|
self.collect_pattern(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Structural Helpers ---
|
|
||||||
pub fn flatten_tuple(node: AnalyzedNode, into: &mut Vec<AnalyzedNode>) {
|
|
||||||
match node.kind {
|
|
||||||
BoundKind::Tuple { elements } => {
|
|
||||||
for el in elements {
|
|
||||||
flatten_tuple(el, into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BoundKind::Record { fields } => {
|
|
||||||
for (_, v) in fields {
|
|
||||||
flatten_tuple(v, into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BoundKind::Nop => {}
|
|
||||||
_ => into.push(node),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user