tensorlogic_compiler/inline/config.rs
1/// Configuration for the let-inlining pass.
2///
3/// All flags default to `true` so that the pass is aggressive by default.
4/// Disable individual flags for conservative inlining or debugging.
5#[derive(Debug, Clone)]
6pub struct InlineConfig {
7 /// Inline `Let(x, e, body)` whenever `x` occurs free exactly once in
8 /// `body`, regardless of how complex `e` is (subject to `max_inline_depth`).
9 pub inline_single_use: bool,
10
11 /// Inline `Let(x, Constant(_), body)` regardless of how many times `x`
12 /// is used; constant duplication is essentially free.
13 pub inline_constants: bool,
14
15 /// Inline `Let(x, Pred(y, []), body)` — i.e. variable aliases — regardless
16 /// of use count; these are pure renames.
17 pub inline_vars: bool,
18
19 /// Maximum number of fixed-point passes before stopping.
20 pub max_passes: u32,
21
22 /// Do not inline a binding whose value expression has depth greater than
23 /// this threshold. Prevents unbounded code-size growth.
24 pub max_inline_depth: usize,
25}
26
27impl Default for InlineConfig {
28 fn default() -> Self {
29 Self {
30 inline_single_use: true,
31 inline_constants: true,
32 inline_vars: true,
33 max_passes: 20,
34 max_inline_depth: 10,
35 }
36 }
37}
38
39/// Statistics collected by the let-inlining pass.
40#[derive(Debug, Clone, Default)]
41pub struct InlineStats {
42 /// Number of bindings inlined because the variable had exactly one free
43 /// occurrence in the body (and the value was not a constant or alias).
44 pub single_use_inlines: u64,
45
46 /// Number of bindings inlined because the value was a constant literal.
47 pub constant_inlines: u64,
48
49 /// Number of bindings inlined because the value was a variable alias
50 /// (zero-argument predicate).
51 pub variable_inlines: u64,
52
53 /// Total node count before the first pass.
54 pub nodes_before: u64,
55
56 /// Total node count after the final pass.
57 pub nodes_after: u64,
58
59 /// Number of passes executed.
60 pub passes: u32,
61}
62
63impl InlineStats {
64 /// Sum of all inlining categories.
65 pub fn total(&self) -> u64 {
66 self.single_use_inlines
67 .saturating_add(self.constant_inlines)
68 .saturating_add(self.variable_inlines)
69 }
70
71 /// Fraction of nodes removed: `(before − after) / before`.
72 ///
73 /// Returns `0.0` when `nodes_before == 0`.
74 pub fn reduction_pct(&self) -> f64 {
75 if self.nodes_before == 0 {
76 return 0.0;
77 }
78 let before = self.nodes_before as f64;
79 let after = self.nodes_after as f64;
80 ((before - after) / before * 100.0).max(0.0)
81 }
82
83 /// Human-readable one-line summary.
84 pub fn summary(&self) -> String {
85 format!(
86 "Inline: {} passes, {}/{} nodes kept ({:.1}% reduction) — \
87 {} single-use, {} constant, {} variable-alias inlines",
88 self.passes,
89 self.nodes_after,
90 self.nodes_before,
91 self.reduction_pct(),
92 self.single_use_inlines,
93 self.constant_inlines,
94 self.variable_inlines,
95 )
96 }
97}