1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Optimization passes for compiled logic trees.
//!
//! Two kinds of pass live here:
//!
//! - **Per-call rewrites**, run by [`optimize`] on each builtin call the
//! walker builds, to a fixpoint: `dead_code::eliminate`,
//! `constant_fold::fold` and `strength::reduce`. Each takes the node by
//! value and returns `(node, changed)`; the ones that consult the
//! engine's settings take `&Engine`.
//! - **Whole-tree passes**, run once by `Logic::compile_inner` on the
//! finished tree: `cse::apply`. `constant_fold::fold_static_node`
//! evaluates a fully static node at compile time for the walker.
//!
//! None of them run for a traced compile or on an engine built with
//! folding off.
//!
//! # Adding a per-call rewrite
//!
//! 1. Create a new file in this directory (e.g., `my_pass.rs`).
//! 2. Implement `fn my_pass(node: CompiledNode, ...) -> (CompiledNode, bool)`,
//! returning whether it changed anything.
//! 3. Call it from [`optimize`] below. If its decision reads the engine's
//! settings, fold its `changed` into the `observed` flag `optimize`
//! returns, so the rule is compiled again on an engine whose settings
//! differ.
//! 4. Run `cargo test --all-features`.
pub
pub
pub
pub
use crateEngine;
use crateCompiledNode;
/// Maximum number of fixpoint iterations for the optimiser pipeline.
///
/// Three passes (dead code / constant fold / strength reduction) can feed each
/// other: folding exposes new dead branches; strength reduction can expose new
/// constants. A small cap is enough to catch the compounds we've seen in practice
/// (1–2 iterations after the per-iteration cleanup pass below) while bounding
/// worst-case compile time.
const MAX_FIXPOINT_ITERATIONS: usize = 4;
/// Run all optimization passes on a compiled node tree until a fixpoint.
///
/// This is the main entry point for the optimization pipeline.
/// Called from the walker for each builtin call unless folding is skipped (a
/// traced compile, or an engine built with folding off).
///
/// Passes are applied in order until none report a change or
/// [`MAX_FIXPOINT_ITERATIONS`] is reached. Per iteration:
/// 1. Dead code elimination (remove unreachable branches)
/// 2. Constant folding (the leading integer literals of `+` / `*`, adjacent `cat` strings)
/// 3. Strength reduction (double negation collapse, etc.), skipped under a
/// custom truthy evaluator
/// 4. Dead code elimination (cleanup pass — catches branches that
/// became unreachable from the strength-reduction output, so the
/// fixpoint converges in one iteration instead of two for compound
/// cases like `!!!x → BoolCast(!x)` whose new shape exposes a
/// constant predicate to a surrounding `if`).
///
/// Each pass returns `(node, changed)`; the loop exits as soon as all
/// passes in one iteration report `changed = false`.
///
/// Also returns whether any rewrite rested on the engine's settings: dead
/// code elimination decides by the engine's truthiness, and strength
/// reduction runs only for a built-in truthiness.
pub