feat: Implement purity inference for optimization
This commit introduces purity inference to the compiler's optimizer. This allows for more aggressive constant folding and dead code elimination by tracking which functions and global variables are free of side effects. Key changes include: - Added `global_purity` field to `Optimizer` and `Environment`. - Modified `Optimizer::is_pure` to recursively determine if an AST node represents a pure computation. - Introduced `Optimizer::try_fold_pure` to replace the old `try_fold_intrinsic`, enabling folding of pure function calls with constant arguments. - Updated `Environment::register_native` and `Environment::register_constant` to optionally record purity. - Added purity flags to several built-in functions in `core.rs` and `datetime.rs`. - A new example `optimizer_purity.myc` demonstrates the new feature.
This commit is contained in:
+14
-2
@@ -21,6 +21,7 @@ use crate::ast::rtl::intrinsics;
|
||||
pub struct Environment {
|
||||
pub global_names: Rc<RefCell<HashMap<Symbol, u32>>>,
|
||||
pub global_types: Rc<RefCell<HashMap<u32, StaticType>>>,
|
||||
pub global_purity: Rc<RefCell<HashMap<u32, bool>>>,
|
||||
pub global_values: Rc<RefCell<Vec<Value>>>,
|
||||
pub function_registry: Rc<RefCell<HashMap<u32, BoundNode>>>,
|
||||
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
||||
@@ -85,6 +86,7 @@ impl Environment {
|
||||
let env = Self {
|
||||
global_names: Rc::new(RefCell::new(HashMap::new())),
|
||||
global_types: Rc::new(RefCell::new(HashMap::new())),
|
||||
global_purity: Rc::new(RefCell::new(HashMap::new())),
|
||||
global_values: Rc::new(RefCell::new(Vec::new())),
|
||||
function_registry: Rc::new(RefCell::new(HashMap::new())),
|
||||
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
|
||||
@@ -112,15 +114,18 @@ impl Environment {
|
||||
&self,
|
||||
name: &str,
|
||||
ty: StaticType,
|
||||
is_pure: bool,
|
||||
func: impl Fn(Vec<Value>) -> Value + 'static,
|
||||
) {
|
||||
let mut names = self.global_names.borrow_mut();
|
||||
let mut types = self.global_types.borrow_mut();
|
||||
let mut values = self.global_values.borrow_mut();
|
||||
let mut purity = self.global_purity.borrow_mut();
|
||||
|
||||
let idx = values.len() as u32;
|
||||
names.insert(Symbol::from(name), idx);
|
||||
types.insert(idx, ty);
|
||||
purity.insert(idx, is_pure);
|
||||
values.push(Value::Function(Rc::new(func)));
|
||||
}
|
||||
|
||||
@@ -128,10 +133,12 @@ impl Environment {
|
||||
let mut names = self.global_names.borrow_mut();
|
||||
let mut types = self.global_types.borrow_mut();
|
||||
let mut values = self.global_values.borrow_mut();
|
||||
let mut purity = self.global_purity.borrow_mut();
|
||||
|
||||
let idx = values.len() as u32;
|
||||
names.insert(Symbol::from(name), idx);
|
||||
types.insert(idx, ty);
|
||||
purity.insert(idx, true); // Constants are always pure
|
||||
values.push(val);
|
||||
}
|
||||
|
||||
@@ -182,7 +189,9 @@ impl Environment {
|
||||
let specialized = self.specialize_node(node);
|
||||
|
||||
// 2. Optimize (Level 1: Cracking, Level 2: Collapsing)
|
||||
let optimizer = Optimizer::new(self.optimization_level).with_globals(self.global_values.clone());
|
||||
let optimizer = Optimizer::new(self.optimization_level)
|
||||
.with_globals(self.global_values.clone())
|
||||
.with_purity(self.global_purity.clone());
|
||||
let optimized = optimizer.optimize(specialized);
|
||||
|
||||
// 3. TCO (Always performed, converts to ExecNode)
|
||||
@@ -200,6 +209,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 global_purity = self.global_purity.clone();
|
||||
let opt_level = self.optimization_level;
|
||||
|
||||
let compiler = Rc::new(
|
||||
@@ -227,7 +237,9 @@ impl Environment {
|
||||
let specialized_ast = sub_specializer.specialize(retyped_ast);
|
||||
|
||||
// 3. Optimize (Phase 2: Cracking & Folding)
|
||||
let optimizer = Optimizer::new(opt_level).with_globals(global_values.clone());
|
||||
let optimizer = Optimizer::new(opt_level)
|
||||
.with_globals(global_values.clone())
|
||||
.with_purity(global_purity.clone());
|
||||
let optimized_ast = optimizer.optimize(specialized_ast);
|
||||
|
||||
// 4. TCO (converts to ExecNode)
|
||||
|
||||
Reference in New Issue
Block a user