feat: Implement closure cracking and inlining
Introduces a new optimizer pass that can "crack" closures, allowing for more aggressive specialization. It also enables inlining of upvalues that point to immutable global variables. This removes overhead for higher-order functions and currying when arguments are statically resolvable.
This commit is contained in:
+21
-9
@@ -13,6 +13,7 @@ use crate::ast::compiler::lambda_collector::LambdaCollector;
|
||||
use crate::ast::compiler::dumper::Dumper;
|
||||
use crate::ast::compiler::macros::{MacroExpander, MacroRegistry, MacroEvaluator};
|
||||
use crate::ast::compiler::specializer::{Specializer, MonoCache, FunctionRegistry};
|
||||
use crate::ast::compiler::optimizer::Optimizer;
|
||||
use crate::ast::rtl;
|
||||
use crate::ast::rtl::intrinsics;
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundNode};
|
||||
@@ -24,6 +25,7 @@ pub struct Environment {
|
||||
pub function_registry: Rc<RefCell<HashMap<u32, BoundNode>>>,
|
||||
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
||||
pub debug_mode: bool,
|
||||
pub optimization_level: u32,
|
||||
}
|
||||
|
||||
struct EnvFunctionRegistry {
|
||||
@@ -81,6 +83,7 @@ impl Environment {
|
||||
function_registry: Rc::new(RefCell::new(HashMap::new())),
|
||||
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
|
||||
debug_mode: false,
|
||||
optimization_level: 0,
|
||||
};
|
||||
env.register_stdlib();
|
||||
env
|
||||
@@ -161,11 +164,15 @@ impl Environment {
|
||||
|
||||
/// Backend: Optimization (TCO, etc.)
|
||||
pub fn link(&self, node: TypedNode) -> TypedNode {
|
||||
// 1. Specialize
|
||||
// 1. Specialize (Always performed for correctness)
|
||||
let specialized = self.specialize_node(node);
|
||||
|
||||
// 2. Optimize
|
||||
TCO::optimize(specialized)
|
||||
// 2. Optimize (Level 1: Cracking, Level 2: Collapsing)
|
||||
let optimizer = Optimizer::new(self.optimization_level);
|
||||
let optimized = optimizer.optimize(specialized);
|
||||
|
||||
// 3. TCO (Always performed)
|
||||
TCO::optimize(optimized)
|
||||
}
|
||||
|
||||
fn specialize_node(&self, node: TypedNode) -> TypedNode {
|
||||
@@ -179,6 +186,7 @@ impl Environment {
|
||||
let mono_cache = self.monomorph_cache.clone();
|
||||
let global_values = self.global_values.clone();
|
||||
let global_types = self.global_types.clone();
|
||||
let opt_level = self.optimization_level;
|
||||
|
||||
let compiler = Rc::new(move |func_template: BoundNode, arg_types: &[StaticType]| -> Result<(Value, StaticType), String> {
|
||||
// 1. Re-TypeCheck the template with concrete argument types
|
||||
@@ -198,18 +206,22 @@ impl Environment {
|
||||
|
||||
let specialized_ast = sub_specializer.specialize(retyped_ast);
|
||||
|
||||
// 3. Optimize (TCO)
|
||||
let optimized_ast = TCO::optimize(specialized_ast);
|
||||
// 3. Optimize (Phase 2: Cracking & Folding)
|
||||
let optimizer = Optimizer::new(opt_level);
|
||||
let optimized_ast = optimizer.optimize(specialized_ast);
|
||||
|
||||
// 4. Compile to Value (VM)
|
||||
// 4. TCO
|
||||
let tco_ast = TCO::optimize(optimized_ast);
|
||||
|
||||
// 5. Compile to Value (VM)
|
||||
let mut vm = VM::new(global_values.clone());
|
||||
let compiled_val = match vm.run(&optimized_ast) {
|
||||
let compiled_val = match vm.run(&tco_ast) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(format!("VM Error during specialization: {}", e)),
|
||||
};
|
||||
|
||||
// 5. Determine correct return type from the newly inferred function signature
|
||||
let ret_type = if let StaticType::Function(sig) = &optimized_ast.ty {
|
||||
// 6. Determine correct return type from the newly inferred function signature
|
||||
let ret_type = if let StaticType::Function(sig) = &tco_ast.ty {
|
||||
sig.ret.clone()
|
||||
} else {
|
||||
StaticType::Any
|
||||
|
||||
Reference in New Issue
Block a user