diff --git a/driver.py b/driver.py index d618391be..149e3594a 100755 --- a/driver.py +++ b/driver.py @@ -147,10 +147,8 @@ def build(features): install(features) cmd = ["cargo", "build"] - if mode: - cmd += ["--" + mode] - else: - # default to release mode + if mode != "debug": + # debug is cargo's default; only pass --release when needed cmd += ["--release"] cmd += ["--examples"] @@ -231,10 +229,8 @@ def benchmark(features): install(features) cmd = ["cargo", "build"] - if mode: - cmd += ["--" + mode] - else: - # default to release mode + if mode != "debug": + # debug is cargo's default; only pass --release when needed cmd += ["--release"] cmd += ["--examples"] diff --git a/src/front/zsharpcurly/mod.rs b/src/front/zsharpcurly/mod.rs index 3476b51d4..dade35c49 100644 --- a/src/front/zsharpcurly/mod.rs +++ b/src/front/zsharpcurly/mod.rs @@ -1308,7 +1308,9 @@ impl<'ast> ZGen<'ast> { fn expr_impl_(&self, e: &ast::Expression<'ast>) -> Result { self.expr_impl_inner_::(e) - .map(const_fold) + // Only fold during const evaluation; for normal paths, folding is deferred + // to statement boundaries to avoid O(n^2) re-traversal of the term DAG. + .map(|v| if IS_CNST { const_fold(v) } else { v }) .and_then(|v| if IS_CNST { const_val_simple(v) } else { Ok(v) }) .map_err(|err| format!("{}; context:\n{}", err, span_to_string(e.span()))) } @@ -1560,14 +1562,14 @@ impl<'ast> ZGen<'ast> { match s { ast::Statement::Return(r) => if let Some(e) = r.expression.as_ref() { self.set_lhs_ty_ret(r); - let ret = self.expr_impl_::(e)?; + let ret = const_fold(self.expr_impl_::(e)?); self.ret_impl_::(Some(ret)) } else { self.ret_impl_::(None) } .map_err(|e| format!("{e}")), ast::Statement::Assertion(e) => { - let expr = self.expr_impl_::(&e.expression)?; + let expr = const_fold(self.expr_impl_::(&e.expression)?); match const_bool_simple(expr.clone()) { Some(true) => Ok(()), Some(false) => Err(format!( @@ -1628,7 +1630,7 @@ impl<'ast> ZGen<'ast> { } ast::Statement::Definition(d) => { self.set_lhs_ty_defn::(d)?; - let e = self.expr_impl_::(&d.expression)?; + let e = const_fold(self.expr_impl_::(&d.expression)?); match &d.lhs { ast::TypedIdentifierOrAssignee::Assignee(l) => { diff --git a/src/ir/opt/flat.rs b/src/ir/opt/flat.rs index 6a04c4dde..d134b7e3e 100644 --- a/src/ir/opt/flat.rs +++ b/src/ir/opt/flat.rs @@ -110,13 +110,24 @@ pub fn flatten_nary_ops_cached(term_: Term, Cache(ref mut rewritten): &mut Cache None, ) } - _ => Entry::Term(Rc::new(term( - t.op().clone(), - t.cs() - .iter() - .map(|c| rewritten.get_mut(c).unwrap().as_term()) - .collect(), - ))), + _ => { + if t.cs().iter().all(|c| { + rewritten.get(c).and_then(|e| match e { + Entry::Term(t) => Some(&**t), + _ => None, + }) == Some(c) + }) { + Entry::Term(Rc::new(t.clone())) + } else { + Entry::Term(Rc::new(term( + t.op().clone(), + t.cs() + .iter() + .map(|c| rewritten.get_mut(c).unwrap().as_term()) + .collect(), + ))) + } + } }; rewritten.insert(t, entry); } diff --git a/src/ir/opt/visit.rs b/src/ir/opt/visit.rs index 2a7e7e00f..791988669 100644 --- a/src/ir/opt/visit.rs +++ b/src/ir/opt/visit.rs @@ -65,14 +65,18 @@ pub trait RewritePass { } else { let new_t_opt = self.visit_cache(computation, &top, &cache); let new_t = new_t_opt.unwrap_or_else(|| { - term( - top.op().clone(), - top.cs() - .iter() - .map(|c| cache.get(c).unwrap()) - .cloned() - .collect(), - ) + if top.cs().iter().all(|c| cache.get(c).unwrap() == c) { + top.clone() + } else { + term( + top.op().clone(), + top.cs() + .iter() + .map(|c| cache.get(c).unwrap()) + .cloned() + .collect(), + ) + } }); cache.insert(top.clone(), new_t); }