Skip to content

⚡ perf(mq-lang): add AST optimizer with multi-pass optimization pipeline #1818

Merged
harehare merged 12 commits into
mainfrom
feat/ast-optimizer
Jun 4, 2026
Merged

⚡ perf(mq-lang): add AST optimizer with multi-pass optimization pipeline #1818
harehare merged 12 commits into
mainfrom
feat/ast-optimizer

Conversation

@harehare

@harehare harehare commented Jun 2, 2026

Copy link
Copy Markdown
Owner

No description provided.

harehare added 2 commits June 2, 2026 21:30
Add Expr::SelectorChain(SmallVec<[Selector; 4]>) to the AST to represent
sequences of consecutive selectors that have been merged by the optimizer.
Update code.rs, eval.rs, macro_expand.rs, and lib.rs accordingly, and
hook the optimizer into Engine::compile and Engine::eval.
Introduce optimizer.rs with the following passes applied before evaluation:

- Phase 1: constant folding (arithmetic, string, comparison, logical),
  dead branch elimination, And/Or literal short-circuit, Paren unwrap
- Phase 2: SelectorChain fusion — merge consecutive Selector nodes into
  a single SelectorChain to reduce eval_program loop iterations
- Phase 3-1: InterpolatedString constant folding, let-binding literal
  propagation with re-fold after substitution
- Phase 3-2: small function inlining (single-node body, no free vars,
  no recursion) with post-inline constant folding
- Phase 3-3: tail-call optimization — rewrite self-tail-recursive
  functions as var + loop + break/continue to eliminate stack growth
@codspeed-hq

codspeed-hq Bot commented Jun 2, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 29 untouched benchmarks


Comparing feat/ast-optimizer (40f9d55) with main (8435856)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (13dba8c) during the generation of this report, so 8435856 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

harehare added 10 commits June 2, 2026 22:26
…Level

Redesign the optimizer to eliminate unnecessary allocations and add
configurable optimization levels via Engine::set_optimization_level().

Key changes:
- Add OptimizationLevel enum (None/Basic/Full) exposed on Engine
- Merge propagate_let_literals + optimize_node into single propagate_and_fold pass
- Skip inlining/TCO passes entirely when no Def nodes are present
- Add ptr_eq checks to avoid node allocations when sub-expressions are unchanged
- Add early return to merge_selector_chains when no consecutive selectors exist
- Add fast path to propagate_and_fold that returns original program when unchanged
- Replace HashMap with FxHashMap for inlinable function tracking
- Replace HashMap with stack-allocated SmallVec (LiteralEnv) for let propagation env
- Enable substitution into InterpolatedString Expr segments for compile-time folding
- Promote Expr(Literal(String)) segments to Text in InterpolatedString optimizer
- Replace FxHashMap with EnvContext (Small=SmallVec / Large=FxHashMap) in Env
  so child scopes with few bindings avoid heap allocation entirely
- Add lazy_map_program for zero-copy AST passes when no node changes
- Add optimize_nested to reuse parent user_defs in sub-program bodies
- Add dead-def elimination (top-level only) after function inlining
- Add builtin constants for math (ceil/round/abs/trunc), type conversion
  (to_string/to_number), and string ops (trim/upcase/starts_with/replace, etc.)
- Expand env tests with proptest property-based test suite
Collapse nested if-let blocks into a single if-let with && to satisfy
the clippy::collapsible_if lint required by --all-features --all-targets.
…ments

- Add doc comments to Optimizer::optimize, EnvError::to_runtime_error,
  EnvError::to_runtime_error_with_token, Env::len, Env::define, and Env::resolve
- Trim redundant implementation-detail paragraphs from private method comments
  in optimizer (optimize_nested, propagate_and_fold, LiteralEnv type alias)
- Remove obvious inline comments in try_fold_call and collect_called_fns_node
…Vec size

Replace magic number 6 in SmallVec type parameter with a named constant
derived from PROMOTE_THRESHOLD - 1, making the invariant explicit and
preventing future divergence between the two values.
Add `--optimize-level` CLI flag (none/basic/full) so users can select
the optimization pass at runtime. Change the default OptimizationLevel
from Full to None so behavior is stable unless explicitly opted in.
…r> in debugger feature

iter_entries is only used under the debugger feature (non-hot path),
so boxing is acceptable and removes the boilerplate Either enum and
its Iterator impl.
@harehare harehare merged commit 93b0534 into main Jun 4, 2026
10 checks passed
@harehare harehare deleted the feat/ast-optimizer branch June 4, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant