Skip to main content

oxilean_codegen/kotlin_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6use std::collections::HashSet;
7
8use super::functions::KOTLIN_KEYWORDS;
9
10use super::functions::*;
11use std::collections::{HashMap, VecDeque};
12
13/// Analysis cache for KotlinExt.
14#[allow(dead_code)]
15#[derive(Debug)]
16pub struct KotlinExtCache {
17    pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
18    pub(super) cap: usize,
19    pub(super) total_hits: u64,
20    pub(super) total_misses: u64,
21}
22impl KotlinExtCache {
23    #[allow(dead_code)]
24    pub fn new(cap: usize) -> Self {
25        Self {
26            entries: Vec::new(),
27            cap,
28            total_hits: 0,
29            total_misses: 0,
30        }
31    }
32    #[allow(dead_code)]
33    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
34        for e in self.entries.iter_mut() {
35            if e.0 == key && e.2 {
36                e.3 += 1;
37                self.total_hits += 1;
38                return Some(&e.1);
39            }
40        }
41        self.total_misses += 1;
42        None
43    }
44    #[allow(dead_code)]
45    pub fn put(&mut self, key: u64, data: Vec<u8>) {
46        if self.entries.len() >= self.cap {
47            self.entries.retain(|e| e.2);
48            if self.entries.len() >= self.cap {
49                self.entries.remove(0);
50            }
51        }
52        self.entries.push((key, data, true, 0));
53    }
54    #[allow(dead_code)]
55    pub fn invalidate(&mut self) {
56        for e in self.entries.iter_mut() {
57            e.2 = false;
58        }
59    }
60    #[allow(dead_code)]
61    pub fn hit_rate(&self) -> f64 {
62        let t = self.total_hits + self.total_misses;
63        if t == 0 {
64            0.0
65        } else {
66            self.total_hits as f64 / t as f64
67        }
68    }
69    #[allow(dead_code)]
70    pub fn live_count(&self) -> usize {
71        self.entries.iter().filter(|e| e.2).count()
72    }
73}
74/// A single branch in a `when` expression.
75#[derive(Debug, Clone, PartialEq)]
76pub struct KotlinWhenBranch {
77    pub condition: KotlinExpr,
78    pub body: KotlinExpr,
79}
80/// Configuration for KotlinExt passes.
81#[allow(dead_code)]
82#[derive(Debug, Clone)]
83pub struct KotlinExtPassConfig {
84    pub name: String,
85    pub phase: KotlinExtPassPhase,
86    pub enabled: bool,
87    pub max_iterations: usize,
88    pub debug: u32,
89    pub timeout_ms: Option<u64>,
90}
91impl KotlinExtPassConfig {
92    #[allow(dead_code)]
93    pub fn new(name: impl Into<String>) -> Self {
94        Self {
95            name: name.into(),
96            phase: KotlinExtPassPhase::Middle,
97            enabled: true,
98            max_iterations: 100,
99            debug: 0,
100            timeout_ms: None,
101        }
102    }
103    #[allow(dead_code)]
104    pub fn with_phase(mut self, phase: KotlinExtPassPhase) -> Self {
105        self.phase = phase;
106        self
107    }
108    #[allow(dead_code)]
109    pub fn with_max_iter(mut self, n: usize) -> Self {
110        self.max_iterations = n;
111        self
112    }
113    #[allow(dead_code)]
114    pub fn with_debug(mut self, d: u32) -> Self {
115        self.debug = d;
116        self
117    }
118    #[allow(dead_code)]
119    pub fn disabled(mut self) -> Self {
120        self.enabled = false;
121        self
122    }
123    #[allow(dead_code)]
124    pub fn with_timeout(mut self, ms: u64) -> Self {
125        self.timeout_ms = Some(ms);
126        self
127    }
128    #[allow(dead_code)]
129    pub fn is_debug_enabled(&self) -> bool {
130        self.debug > 0
131    }
132}
133#[allow(dead_code)]
134#[derive(Debug, Clone)]
135pub struct KtDepGraph {
136    pub(super) nodes: Vec<u32>,
137    pub(super) edges: Vec<(u32, u32)>,
138}
139impl KtDepGraph {
140    #[allow(dead_code)]
141    pub fn new() -> Self {
142        KtDepGraph {
143            nodes: Vec::new(),
144            edges: Vec::new(),
145        }
146    }
147    #[allow(dead_code)]
148    pub fn add_node(&mut self, id: u32) {
149        if !self.nodes.contains(&id) {
150            self.nodes.push(id);
151        }
152    }
153    #[allow(dead_code)]
154    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
155        self.add_node(dep);
156        self.add_node(dependent);
157        self.edges.push((dep, dependent));
158    }
159    #[allow(dead_code)]
160    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
161        self.edges
162            .iter()
163            .filter(|(d, _)| *d == node)
164            .map(|(_, dep)| *dep)
165            .collect()
166    }
167    #[allow(dead_code)]
168    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
169        self.edges
170            .iter()
171            .filter(|(_, dep)| *dep == node)
172            .map(|(d, _)| *d)
173            .collect()
174    }
175    #[allow(dead_code)]
176    pub fn topological_sort(&self) -> Vec<u32> {
177        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
178        for &n in &self.nodes {
179            in_degree.insert(n, 0);
180        }
181        for (_, dep) in &self.edges {
182            *in_degree.entry(*dep).or_insert(0) += 1;
183        }
184        let mut queue: std::collections::VecDeque<u32> = self
185            .nodes
186            .iter()
187            .filter(|&&n| in_degree[&n] == 0)
188            .copied()
189            .collect();
190        let mut result = Vec::new();
191        while let Some(node) = queue.pop_front() {
192            result.push(node);
193            for dep in self.dependents_of(node) {
194                let cnt = in_degree.entry(dep).or_insert(0);
195                *cnt = cnt.saturating_sub(1);
196                if *cnt == 0 {
197                    queue.push_back(dep);
198                }
199            }
200        }
201        result
202    }
203    #[allow(dead_code)]
204    pub fn has_cycle(&self) -> bool {
205        self.topological_sort().len() < self.nodes.len()
206    }
207}
208/// Dominator tree for KotlinExt.
209#[allow(dead_code)]
210#[derive(Debug, Clone)]
211pub struct KotlinExtDomTree {
212    pub(super) idom: Vec<Option<usize>>,
213    pub(super) children: Vec<Vec<usize>>,
214    pub(super) depth: Vec<usize>,
215}
216impl KotlinExtDomTree {
217    #[allow(dead_code)]
218    pub fn new(n: usize) -> Self {
219        Self {
220            idom: vec![None; n],
221            children: vec![Vec::new(); n],
222            depth: vec![0; n],
223        }
224    }
225    #[allow(dead_code)]
226    pub fn set_idom(&mut self, node: usize, dom: usize) {
227        if node < self.idom.len() {
228            self.idom[node] = Some(dom);
229            if dom < self.children.len() {
230                self.children[dom].push(node);
231            }
232            self.depth[node] = if dom < self.depth.len() {
233                self.depth[dom] + 1
234            } else {
235                1
236            };
237        }
238    }
239    #[allow(dead_code)]
240    pub fn dominates(&self, a: usize, mut b: usize) -> bool {
241        if a == b {
242            return true;
243        }
244        let n = self.idom.len();
245        for _ in 0..n {
246            match self.idom.get(b).copied().flatten() {
247                None => return false,
248                Some(p) if p == a => return true,
249                Some(p) if p == b => return false,
250                Some(p) => b = p,
251            }
252        }
253        false
254    }
255    #[allow(dead_code)]
256    pub fn children_of(&self, n: usize) -> &[usize] {
257        self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
258    }
259    #[allow(dead_code)]
260    pub fn depth_of(&self, n: usize) -> usize {
261        self.depth.get(n).copied().unwrap_or(0)
262    }
263    #[allow(dead_code)]
264    pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
265        let n = self.idom.len();
266        for _ in 0..(2 * n) {
267            if a == b {
268                return a;
269            }
270            if self.depth_of(a) > self.depth_of(b) {
271                a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
272            } else {
273                b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
274            }
275        }
276        0
277    }
278}
279/// Pass registry for KotlinExt.
280#[allow(dead_code)]
281#[derive(Debug, Default)]
282pub struct KotlinExtPassRegistry {
283    pub(super) configs: Vec<KotlinExtPassConfig>,
284    pub(super) stats: Vec<KotlinExtPassStats>,
285}
286impl KotlinExtPassRegistry {
287    #[allow(dead_code)]
288    pub fn new() -> Self {
289        Self::default()
290    }
291    #[allow(dead_code)]
292    pub fn register(&mut self, c: KotlinExtPassConfig) {
293        self.stats.push(KotlinExtPassStats::new());
294        self.configs.push(c);
295    }
296    #[allow(dead_code)]
297    pub fn len(&self) -> usize {
298        self.configs.len()
299    }
300    #[allow(dead_code)]
301    pub fn is_empty(&self) -> bool {
302        self.configs.is_empty()
303    }
304    #[allow(dead_code)]
305    pub fn get(&self, i: usize) -> Option<&KotlinExtPassConfig> {
306        self.configs.get(i)
307    }
308    #[allow(dead_code)]
309    pub fn get_stats(&self, i: usize) -> Option<&KotlinExtPassStats> {
310        self.stats.get(i)
311    }
312    #[allow(dead_code)]
313    pub fn enabled_passes(&self) -> Vec<&KotlinExtPassConfig> {
314        self.configs.iter().filter(|c| c.enabled).collect()
315    }
316    #[allow(dead_code)]
317    pub fn passes_in_phase(&self, ph: &KotlinExtPassPhase) -> Vec<&KotlinExtPassConfig> {
318        self.configs
319            .iter()
320            .filter(|c| c.enabled && &c.phase == ph)
321            .collect()
322    }
323    #[allow(dead_code)]
324    pub fn total_nodes_visited(&self) -> usize {
325        self.stats.iter().map(|s| s.nodes_visited).sum()
326    }
327    #[allow(dead_code)]
328    pub fn any_changed(&self) -> bool {
329        self.stats.iter().any(|s| s.changed)
330    }
331}
332/// Dependency graph for KotlinExt.
333#[allow(dead_code)]
334#[derive(Debug, Clone)]
335pub struct KotlinExtDepGraph {
336    pub(super) n: usize,
337    pub(super) adj: Vec<Vec<usize>>,
338    pub(super) rev: Vec<Vec<usize>>,
339    pub(super) edge_count: usize,
340}
341impl KotlinExtDepGraph {
342    #[allow(dead_code)]
343    pub fn new(n: usize) -> Self {
344        Self {
345            n,
346            adj: vec![Vec::new(); n],
347            rev: vec![Vec::new(); n],
348            edge_count: 0,
349        }
350    }
351    #[allow(dead_code)]
352    pub fn add_edge(&mut self, from: usize, to: usize) {
353        if from < self.n && to < self.n {
354            if !self.adj[from].contains(&to) {
355                self.adj[from].push(to);
356                self.rev[to].push(from);
357                self.edge_count += 1;
358            }
359        }
360    }
361    #[allow(dead_code)]
362    pub fn succs(&self, n: usize) -> &[usize] {
363        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
364    }
365    #[allow(dead_code)]
366    pub fn preds(&self, n: usize) -> &[usize] {
367        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
368    }
369    #[allow(dead_code)]
370    pub fn topo_sort(&self) -> Option<Vec<usize>> {
371        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
372        let mut q: std::collections::VecDeque<usize> =
373            (0..self.n).filter(|&i| deg[i] == 0).collect();
374        let mut out = Vec::with_capacity(self.n);
375        while let Some(u) = q.pop_front() {
376            out.push(u);
377            for &v in &self.adj[u] {
378                deg[v] -= 1;
379                if deg[v] == 0 {
380                    q.push_back(v);
381                }
382            }
383        }
384        if out.len() == self.n {
385            Some(out)
386        } else {
387            None
388        }
389    }
390    #[allow(dead_code)]
391    pub fn has_cycle(&self) -> bool {
392        self.topo_sort().is_none()
393    }
394    #[allow(dead_code)]
395    pub fn reachable(&self, start: usize) -> Vec<usize> {
396        let mut vis = vec![false; self.n];
397        let mut stk = vec![start];
398        let mut out = Vec::new();
399        while let Some(u) = stk.pop() {
400            if u < self.n && !vis[u] {
401                vis[u] = true;
402                out.push(u);
403                for &v in &self.adj[u] {
404                    if !vis[v] {
405                        stk.push(v);
406                    }
407                }
408            }
409        }
410        out
411    }
412    #[allow(dead_code)]
413    pub fn scc(&self) -> Vec<Vec<usize>> {
414        let mut visited = vec![false; self.n];
415        let mut order = Vec::new();
416        for i in 0..self.n {
417            if !visited[i] {
418                let mut stk = vec![(i, 0usize)];
419                while let Some((u, idx)) = stk.last_mut() {
420                    if !visited[*u] {
421                        visited[*u] = true;
422                    }
423                    if *idx < self.adj[*u].len() {
424                        let v = self.adj[*u][*idx];
425                        *idx += 1;
426                        if !visited[v] {
427                            stk.push((v, 0));
428                        }
429                    } else {
430                        order.push(*u);
431                        stk.pop();
432                    }
433                }
434            }
435        }
436        let mut comp = vec![usize::MAX; self.n];
437        let mut components: Vec<Vec<usize>> = Vec::new();
438        for &start in order.iter().rev() {
439            if comp[start] == usize::MAX {
440                let cid = components.len();
441                let mut component = Vec::new();
442                let mut stk = vec![start];
443                while let Some(u) = stk.pop() {
444                    if comp[u] == usize::MAX {
445                        comp[u] = cid;
446                        component.push(u);
447                        for &v in &self.rev[u] {
448                            if comp[v] == usize::MAX {
449                                stk.push(v);
450                            }
451                        }
452                    }
453                }
454                components.push(component);
455            }
456        }
457        components
458    }
459    #[allow(dead_code)]
460    pub fn node_count(&self) -> usize {
461        self.n
462    }
463    #[allow(dead_code)]
464    pub fn edge_count(&self) -> usize {
465        self.edge_count
466    }
467}
468/// Statistics for KotlinX2 passes.
469#[allow(dead_code)]
470#[derive(Debug, Clone, Default)]
471pub struct KotlinX2PassStats {
472    pub iterations: usize,
473    pub changed: bool,
474    pub nodes_visited: usize,
475    pub nodes_modified: usize,
476    pub time_ms: u64,
477    pub memory_bytes: usize,
478    pub errors: usize,
479}
480impl KotlinX2PassStats {
481    #[allow(dead_code)]
482    pub fn new() -> Self {
483        Self::default()
484    }
485    #[allow(dead_code)]
486    pub fn visit(&mut self) {
487        self.nodes_visited += 1;
488    }
489    #[allow(dead_code)]
490    pub fn modify(&mut self) {
491        self.nodes_modified += 1;
492        self.changed = true;
493    }
494    #[allow(dead_code)]
495    pub fn iterate(&mut self) {
496        self.iterations += 1;
497    }
498    #[allow(dead_code)]
499    pub fn error(&mut self) {
500        self.errors += 1;
501    }
502    #[allow(dead_code)]
503    pub fn efficiency(&self) -> f64 {
504        if self.nodes_visited == 0 {
505            0.0
506        } else {
507            self.nodes_modified as f64 / self.nodes_visited as f64
508        }
509    }
510    #[allow(dead_code)]
511    pub fn merge(&mut self, o: &KotlinX2PassStats) {
512        self.iterations += o.iterations;
513        self.changed |= o.changed;
514        self.nodes_visited += o.nodes_visited;
515        self.nodes_modified += o.nodes_modified;
516        self.time_ms += o.time_ms;
517        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
518        self.errors += o.errors;
519    }
520}
521/// Kotlin statement AST.
522#[derive(Debug, Clone, PartialEq)]
523pub enum KotlinStmt {
524    /// `val name: Type = expr`
525    Val(String, KotlinType, KotlinExpr),
526    /// `var name: Type = expr`
527    Var(String, KotlinType, KotlinExpr),
528    /// `name = expr`
529    Assign(String, KotlinExpr),
530    /// `return expr`
531    Return(KotlinExpr),
532    /// Expression statement
533    Expr(KotlinExpr),
534    /// `if (cond) { then } else { else_ }`
535    If(KotlinExpr, Vec<KotlinStmt>, Vec<KotlinStmt>),
536    /// `when (expr) { branches each as (cond, stmts) } else { default }`
537    When(
538        KotlinExpr,
539        Vec<(KotlinExpr, Vec<KotlinStmt>)>,
540        Vec<KotlinStmt>,
541    ),
542}
543/// Constant folding helper for KotlinExt.
544#[allow(dead_code)]
545#[derive(Debug, Clone, Default)]
546pub struct KotlinExtConstFolder {
547    pub(super) folds: usize,
548    pub(super) failures: usize,
549    pub(super) enabled: bool,
550}
551impl KotlinExtConstFolder {
552    #[allow(dead_code)]
553    pub fn new() -> Self {
554        Self {
555            folds: 0,
556            failures: 0,
557            enabled: true,
558        }
559    }
560    #[allow(dead_code)]
561    pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
562        self.folds += 1;
563        a.checked_add(b)
564    }
565    #[allow(dead_code)]
566    pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
567        self.folds += 1;
568        a.checked_sub(b)
569    }
570    #[allow(dead_code)]
571    pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
572        self.folds += 1;
573        a.checked_mul(b)
574    }
575    #[allow(dead_code)]
576    pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
577        if b == 0 {
578            self.failures += 1;
579            None
580        } else {
581            self.folds += 1;
582            a.checked_div(b)
583        }
584    }
585    #[allow(dead_code)]
586    pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
587        if b == 0 {
588            self.failures += 1;
589            None
590        } else {
591            self.folds += 1;
592            a.checked_rem(b)
593        }
594    }
595    #[allow(dead_code)]
596    pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
597        self.folds += 1;
598        a.checked_neg()
599    }
600    #[allow(dead_code)]
601    pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
602        if s >= 64 {
603            self.failures += 1;
604            None
605        } else {
606            self.folds += 1;
607            a.checked_shl(s)
608        }
609    }
610    #[allow(dead_code)]
611    pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
612        if s >= 64 {
613            self.failures += 1;
614            None
615        } else {
616            self.folds += 1;
617            a.checked_shr(s)
618        }
619    }
620    #[allow(dead_code)]
621    pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
622        self.folds += 1;
623        a & b
624    }
625    #[allow(dead_code)]
626    pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
627        self.folds += 1;
628        a | b
629    }
630    #[allow(dead_code)]
631    pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
632        self.folds += 1;
633        a ^ b
634    }
635    #[allow(dead_code)]
636    pub fn not_i64(&mut self, a: i64) -> i64 {
637        self.folds += 1;
638        !a
639    }
640    #[allow(dead_code)]
641    pub fn fold_count(&self) -> usize {
642        self.folds
643    }
644    #[allow(dead_code)]
645    pub fn failure_count(&self) -> usize {
646        self.failures
647    }
648    #[allow(dead_code)]
649    pub fn enable(&mut self) {
650        self.enabled = true;
651    }
652    #[allow(dead_code)]
653    pub fn disable(&mut self) {
654        self.enabled = false;
655    }
656    #[allow(dead_code)]
657    pub fn is_enabled(&self) -> bool {
658        self.enabled
659    }
660}
661/// Worklist for KotlinX2.
662#[allow(dead_code)]
663#[derive(Debug, Clone)]
664pub struct KotlinX2Worklist {
665    pub(super) items: std::collections::VecDeque<usize>,
666    pub(super) present: Vec<bool>,
667}
668impl KotlinX2Worklist {
669    #[allow(dead_code)]
670    pub fn new(capacity: usize) -> Self {
671        Self {
672            items: std::collections::VecDeque::new(),
673            present: vec![false; capacity],
674        }
675    }
676    #[allow(dead_code)]
677    pub fn push(&mut self, id: usize) {
678        if id < self.present.len() && !self.present[id] {
679            self.present[id] = true;
680            self.items.push_back(id);
681        }
682    }
683    #[allow(dead_code)]
684    pub fn push_front(&mut self, id: usize) {
685        if id < self.present.len() && !self.present[id] {
686            self.present[id] = true;
687            self.items.push_front(id);
688        }
689    }
690    #[allow(dead_code)]
691    pub fn pop(&mut self) -> Option<usize> {
692        let id = self.items.pop_front()?;
693        if id < self.present.len() {
694            self.present[id] = false;
695        }
696        Some(id)
697    }
698    #[allow(dead_code)]
699    pub fn is_empty(&self) -> bool {
700        self.items.is_empty()
701    }
702    #[allow(dead_code)]
703    pub fn len(&self) -> usize {
704        self.items.len()
705    }
706    #[allow(dead_code)]
707    pub fn contains(&self, id: usize) -> bool {
708        id < self.present.len() && self.present[id]
709    }
710    #[allow(dead_code)]
711    pub fn drain_all(&mut self) -> Vec<usize> {
712        let v: Vec<usize> = self.items.drain(..).collect();
713        for &id in &v {
714            if id < self.present.len() {
715                self.present[id] = false;
716            }
717        }
718        v
719    }
720}
721#[allow(dead_code)]
722#[derive(Debug, Clone, Default)]
723pub struct KtPassStats {
724    pub total_runs: u32,
725    pub successful_runs: u32,
726    pub total_changes: u64,
727    pub time_ms: u64,
728    pub iterations_used: u32,
729}
730impl KtPassStats {
731    #[allow(dead_code)]
732    pub fn new() -> Self {
733        Self::default()
734    }
735    #[allow(dead_code)]
736    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
737        self.total_runs += 1;
738        self.successful_runs += 1;
739        self.total_changes += changes;
740        self.time_ms += time_ms;
741        self.iterations_used = iterations;
742    }
743    #[allow(dead_code)]
744    pub fn average_changes_per_run(&self) -> f64 {
745        if self.total_runs == 0 {
746            return 0.0;
747        }
748        self.total_changes as f64 / self.total_runs as f64
749    }
750    #[allow(dead_code)]
751    pub fn success_rate(&self) -> f64 {
752        if self.total_runs == 0 {
753            return 0.0;
754        }
755        self.successful_runs as f64 / self.total_runs as f64
756    }
757    #[allow(dead_code)]
758    pub fn format_summary(&self) -> String {
759        format!(
760            "Runs: {}/{}, Changes: {}, Time: {}ms",
761            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
762        )
763    }
764}
765#[allow(dead_code)]
766#[derive(Debug, Clone)]
767pub struct KtLivenessInfo {
768    pub live_in: Vec<std::collections::HashSet<u32>>,
769    pub live_out: Vec<std::collections::HashSet<u32>>,
770    pub defs: Vec<std::collections::HashSet<u32>>,
771    pub uses: Vec<std::collections::HashSet<u32>>,
772}
773impl KtLivenessInfo {
774    #[allow(dead_code)]
775    pub fn new(block_count: usize) -> Self {
776        KtLivenessInfo {
777            live_in: vec![std::collections::HashSet::new(); block_count],
778            live_out: vec![std::collections::HashSet::new(); block_count],
779            defs: vec![std::collections::HashSet::new(); block_count],
780            uses: vec![std::collections::HashSet::new(); block_count],
781        }
782    }
783    #[allow(dead_code)]
784    pub fn add_def(&mut self, block: usize, var: u32) {
785        if block < self.defs.len() {
786            self.defs[block].insert(var);
787        }
788    }
789    #[allow(dead_code)]
790    pub fn add_use(&mut self, block: usize, var: u32) {
791        if block < self.uses.len() {
792            self.uses[block].insert(var);
793        }
794    }
795    #[allow(dead_code)]
796    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
797        self.live_in
798            .get(block)
799            .map(|s| s.contains(&var))
800            .unwrap_or(false)
801    }
802    #[allow(dead_code)]
803    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
804        self.live_out
805            .get(block)
806            .map(|s| s.contains(&var))
807            .unwrap_or(false)
808    }
809}
810/// Statistics for KotlinExt passes.
811#[allow(dead_code)]
812#[derive(Debug, Clone, Default)]
813pub struct KotlinExtPassStats {
814    pub iterations: usize,
815    pub changed: bool,
816    pub nodes_visited: usize,
817    pub nodes_modified: usize,
818    pub time_ms: u64,
819    pub memory_bytes: usize,
820    pub errors: usize,
821}
822impl KotlinExtPassStats {
823    #[allow(dead_code)]
824    pub fn new() -> Self {
825        Self::default()
826    }
827    #[allow(dead_code)]
828    pub fn visit(&mut self) {
829        self.nodes_visited += 1;
830    }
831    #[allow(dead_code)]
832    pub fn modify(&mut self) {
833        self.nodes_modified += 1;
834        self.changed = true;
835    }
836    #[allow(dead_code)]
837    pub fn iterate(&mut self) {
838        self.iterations += 1;
839    }
840    #[allow(dead_code)]
841    pub fn error(&mut self) {
842        self.errors += 1;
843    }
844    #[allow(dead_code)]
845    pub fn efficiency(&self) -> f64 {
846        if self.nodes_visited == 0 {
847            0.0
848        } else {
849            self.nodes_modified as f64 / self.nodes_visited as f64
850        }
851    }
852    #[allow(dead_code)]
853    pub fn merge(&mut self, o: &KotlinExtPassStats) {
854        self.iterations += o.iterations;
855        self.changed |= o.changed;
856        self.nodes_visited += o.nodes_visited;
857        self.nodes_modified += o.nodes_modified;
858        self.time_ms += o.time_ms;
859        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
860        self.errors += o.errors;
861    }
862}
863/// Liveness analysis for KotlinExt.
864#[allow(dead_code)]
865#[derive(Debug, Clone, Default)]
866pub struct KotlinExtLiveness {
867    pub live_in: Vec<Vec<usize>>,
868    pub live_out: Vec<Vec<usize>>,
869    pub defs: Vec<Vec<usize>>,
870    pub uses: Vec<Vec<usize>>,
871}
872impl KotlinExtLiveness {
873    #[allow(dead_code)]
874    pub fn new(n: usize) -> Self {
875        Self {
876            live_in: vec![Vec::new(); n],
877            live_out: vec![Vec::new(); n],
878            defs: vec![Vec::new(); n],
879            uses: vec![Vec::new(); n],
880        }
881    }
882    #[allow(dead_code)]
883    pub fn live_in(&self, b: usize, v: usize) -> bool {
884        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
885    }
886    #[allow(dead_code)]
887    pub fn live_out(&self, b: usize, v: usize) -> bool {
888        self.live_out
889            .get(b)
890            .map(|s| s.contains(&v))
891            .unwrap_or(false)
892    }
893    #[allow(dead_code)]
894    pub fn add_def(&mut self, b: usize, v: usize) {
895        if let Some(s) = self.defs.get_mut(b) {
896            if !s.contains(&v) {
897                s.push(v);
898            }
899        }
900    }
901    #[allow(dead_code)]
902    pub fn add_use(&mut self, b: usize, v: usize) {
903        if let Some(s) = self.uses.get_mut(b) {
904            if !s.contains(&v) {
905                s.push(v);
906            }
907        }
908    }
909    #[allow(dead_code)]
910    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
911        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
912    }
913    #[allow(dead_code)]
914    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
915        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
916    }
917}
918#[allow(dead_code)]
919#[derive(Debug, Clone)]
920pub struct KtPassConfig {
921    pub phase: KtPassPhase,
922    pub enabled: bool,
923    pub max_iterations: u32,
924    pub debug_output: bool,
925    pub pass_name: String,
926}
927impl KtPassConfig {
928    #[allow(dead_code)]
929    pub fn new(name: impl Into<String>, phase: KtPassPhase) -> Self {
930        KtPassConfig {
931            phase,
932            enabled: true,
933            max_iterations: 10,
934            debug_output: false,
935            pass_name: name.into(),
936        }
937    }
938    #[allow(dead_code)]
939    pub fn disabled(mut self) -> Self {
940        self.enabled = false;
941        self
942    }
943    #[allow(dead_code)]
944    pub fn with_debug(mut self) -> Self {
945        self.debug_output = true;
946        self
947    }
948    #[allow(dead_code)]
949    pub fn max_iter(mut self, n: u32) -> Self {
950        self.max_iterations = n;
951        self
952    }
953}
954/// Pass execution phase for KotlinExt.
955#[allow(dead_code)]
956#[derive(Debug, Clone, PartialEq, Eq, Hash)]
957pub enum KotlinExtPassPhase {
958    Early,
959    Middle,
960    Late,
961    Finalize,
962}
963impl KotlinExtPassPhase {
964    #[allow(dead_code)]
965    pub fn is_early(&self) -> bool {
966        matches!(self, Self::Early)
967    }
968    #[allow(dead_code)]
969    pub fn is_middle(&self) -> bool {
970        matches!(self, Self::Middle)
971    }
972    #[allow(dead_code)]
973    pub fn is_late(&self) -> bool {
974        matches!(self, Self::Late)
975    }
976    #[allow(dead_code)]
977    pub fn is_finalize(&self) -> bool {
978        matches!(self, Self::Finalize)
979    }
980    #[allow(dead_code)]
981    pub fn order(&self) -> u32 {
982        match self {
983            Self::Early => 0,
984            Self::Middle => 1,
985            Self::Late => 2,
986            Self::Finalize => 3,
987        }
988    }
989    #[allow(dead_code)]
990    pub fn from_order(n: u32) -> Option<Self> {
991        match n {
992            0 => Some(Self::Early),
993            1 => Some(Self::Middle),
994            2 => Some(Self::Late),
995            3 => Some(Self::Finalize),
996            _ => None,
997        }
998    }
999}
1000/// Kotlin expression AST.
1001#[derive(Debug, Clone, PartialEq)]
1002pub enum KotlinExpr {
1003    /// Variable reference: `foo`
1004    Var(String),
1005    /// Literal value
1006    Lit(KotlinLit),
1007    /// Function call: `f(a, b)`
1008    Call(Box<KotlinExpr>, Vec<KotlinExpr>),
1009    /// Binary operation: `a + b`
1010    BinOp(String, Box<KotlinExpr>, Box<KotlinExpr>),
1011    /// Member access: `obj.field`
1012    Member(Box<KotlinExpr>, String),
1013    /// Index access: `arr[i]`
1014    Index(Box<KotlinExpr>, Box<KotlinExpr>),
1015    /// Unary operation: `!x`
1016    Unary(String, Box<KotlinExpr>),
1017    /// Lambda: `{ x, y -> body }`
1018    Lambda(Vec<String>, Box<KotlinExpr>),
1019    /// When expression: `when (scrutinee) { branches... else -> default }`
1020    When(
1021        Box<KotlinExpr>,
1022        Vec<KotlinWhenBranch>,
1023        Option<Box<KotlinExpr>>,
1024    ),
1025    /// Elvis operator: `a ?: b`
1026    Elvis(Box<KotlinExpr>, Box<KotlinExpr>),
1027}
1028/// A Kotlin `data class` definition.
1029#[derive(Debug, Clone)]
1030pub struct KotlinDataClass {
1031    pub name: String,
1032    pub fields: Vec<(String, KotlinType)>,
1033}
1034/// Worklist for KotlinExt.
1035#[allow(dead_code)]
1036#[derive(Debug, Clone)]
1037pub struct KotlinExtWorklist {
1038    pub(super) items: std::collections::VecDeque<usize>,
1039    pub(super) present: Vec<bool>,
1040}
1041impl KotlinExtWorklist {
1042    #[allow(dead_code)]
1043    pub fn new(capacity: usize) -> Self {
1044        Self {
1045            items: std::collections::VecDeque::new(),
1046            present: vec![false; capacity],
1047        }
1048    }
1049    #[allow(dead_code)]
1050    pub fn push(&mut self, id: usize) {
1051        if id < self.present.len() && !self.present[id] {
1052            self.present[id] = true;
1053            self.items.push_back(id);
1054        }
1055    }
1056    #[allow(dead_code)]
1057    pub fn push_front(&mut self, id: usize) {
1058        if id < self.present.len() && !self.present[id] {
1059            self.present[id] = true;
1060            self.items.push_front(id);
1061        }
1062    }
1063    #[allow(dead_code)]
1064    pub fn pop(&mut self) -> Option<usize> {
1065        let id = self.items.pop_front()?;
1066        if id < self.present.len() {
1067            self.present[id] = false;
1068        }
1069        Some(id)
1070    }
1071    #[allow(dead_code)]
1072    pub fn is_empty(&self) -> bool {
1073        self.items.is_empty()
1074    }
1075    #[allow(dead_code)]
1076    pub fn len(&self) -> usize {
1077        self.items.len()
1078    }
1079    #[allow(dead_code)]
1080    pub fn contains(&self, id: usize) -> bool {
1081        id < self.present.len() && self.present[id]
1082    }
1083    #[allow(dead_code)]
1084    pub fn drain_all(&mut self) -> Vec<usize> {
1085        let v: Vec<usize> = self.items.drain(..).collect();
1086        for &id in &v {
1087            if id < self.present.len() {
1088                self.present[id] = false;
1089            }
1090        }
1091        v
1092    }
1093}
1094/// A Kotlin function definition.
1095#[derive(Debug, Clone)]
1096pub struct KotlinFunc {
1097    pub name: String,
1098    pub params: Vec<(String, KotlinType)>,
1099    pub return_type: KotlinType,
1100    pub body: Vec<KotlinStmt>,
1101    pub is_tailrec: bool,
1102}
1103/// Kotlin literal values.
1104#[derive(Debug, Clone, PartialEq)]
1105pub enum KotlinLit {
1106    Int(i64),
1107    Long(i64),
1108    Bool(bool),
1109    Str(String),
1110    Null,
1111}
1112/// Analysis cache for KotlinX2.
1113#[allow(dead_code)]
1114#[derive(Debug)]
1115pub struct KotlinX2Cache {
1116    pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1117    pub(super) cap: usize,
1118    pub(super) total_hits: u64,
1119    pub(super) total_misses: u64,
1120}
1121impl KotlinX2Cache {
1122    #[allow(dead_code)]
1123    pub fn new(cap: usize) -> Self {
1124        Self {
1125            entries: Vec::new(),
1126            cap,
1127            total_hits: 0,
1128            total_misses: 0,
1129        }
1130    }
1131    #[allow(dead_code)]
1132    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1133        for e in self.entries.iter_mut() {
1134            if e.0 == key && e.2 {
1135                e.3 += 1;
1136                self.total_hits += 1;
1137                return Some(&e.1);
1138            }
1139        }
1140        self.total_misses += 1;
1141        None
1142    }
1143    #[allow(dead_code)]
1144    pub fn put(&mut self, key: u64, data: Vec<u8>) {
1145        if self.entries.len() >= self.cap {
1146            self.entries.retain(|e| e.2);
1147            if self.entries.len() >= self.cap {
1148                self.entries.remove(0);
1149            }
1150        }
1151        self.entries.push((key, data, true, 0));
1152    }
1153    #[allow(dead_code)]
1154    pub fn invalidate(&mut self) {
1155        for e in self.entries.iter_mut() {
1156            e.2 = false;
1157        }
1158    }
1159    #[allow(dead_code)]
1160    pub fn hit_rate(&self) -> f64 {
1161        let t = self.total_hits + self.total_misses;
1162        if t == 0 {
1163            0.0
1164        } else {
1165            self.total_hits as f64 / t as f64
1166        }
1167    }
1168    #[allow(dead_code)]
1169    pub fn live_count(&self) -> usize {
1170        self.entries.iter().filter(|e| e.2).count()
1171    }
1172}
1173/// Kotlin type representation.
1174#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1175pub enum KotlinType {
1176    /// `Int`
1177    KtInt,
1178    /// `Long`
1179    KtLong,
1180    /// `Boolean`
1181    KtBool,
1182    /// `String`
1183    KtString,
1184    /// `Unit`
1185    KtUnit,
1186    /// `Any`
1187    KtAny,
1188    /// `List<T>`
1189    KtList(Box<KotlinType>),
1190    /// `Pair<A, B>`
1191    KtPair(Box<KotlinType>, Box<KotlinType>),
1192    /// `(P0, P1, ...) -> R`
1193    KtFunc(Vec<KotlinType>, Box<KotlinType>),
1194    /// `T?`
1195    KtNullable(Box<KotlinType>),
1196    /// Named class / data class
1197    KtObject(String),
1198}
1199/// Kotlin code generation backend.
1200pub struct KotlinBackend {
1201    /// Counter for fresh temporary variable names.
1202    pub(super) var_counter: u64,
1203}
1204impl KotlinBackend {
1205    /// Create a new `KotlinBackend`.
1206    pub fn new() -> Self {
1207        KotlinBackend { var_counter: 0 }
1208    }
1209    /// Mangle a name so it does not clash with Kotlin keywords.
1210    pub fn mangle_name(&self, name: &str) -> String {
1211        let sanitized: String = name
1212            .chars()
1213            .map(|c| match c {
1214                'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => c,
1215                '.' | ':' | '\'' | '!' | '?' => '_',
1216                _ => '_',
1217            })
1218            .collect();
1219        let sanitized = if sanitized.starts_with(|c: char| c.is_ascii_digit()) {
1220            format!("_{}", sanitized)
1221        } else {
1222            sanitized
1223        };
1224        if KOTLIN_KEYWORDS.contains(&sanitized.as_str()) {
1225            format!("{}_", sanitized)
1226        } else if sanitized.is_empty() {
1227            "_anon".to_string()
1228        } else {
1229            sanitized
1230        }
1231    }
1232    /// Generate a fresh temporary variable name.
1233    pub fn fresh_var(&mut self) -> String {
1234        let v = self.var_counter;
1235        self.var_counter += 1;
1236        format!("_t{}", v)
1237    }
1238    /// Compile a slice of LCNF function declarations into a Kotlin source string.
1239    pub fn compile_module(decls: &[LcnfFunDecl]) -> Result<String, String> {
1240        let mut backend = KotlinBackend::new();
1241        let mut funs = Vec::new();
1242        let mut ctor_names: HashSet<String> = HashSet::new();
1243        for decl in decls {
1244            collect_ctor_names_from_expr(&decl.body, &mut ctor_names);
1245        }
1246        for decl in decls {
1247            let f = backend.compile_decl(decl)?;
1248            funs.push(f);
1249        }
1250        let data_classes: Vec<KotlinDataClass> = ctor_names
1251            .into_iter()
1252            .collect::<Vec<_>>()
1253            .into_iter()
1254            .map(|name| KotlinDataClass {
1255                fields: vec![("tag".to_string(), KotlinType::KtInt)],
1256                name,
1257            })
1258            .collect();
1259        let module = KotlinModule {
1260            package: "oxilean.generated".to_string(),
1261            imports: vec![],
1262            data_classes,
1263            funs,
1264        };
1265        Ok(module.to_string())
1266    }
1267    /// Compile a single LCNF function declaration to a `KotlinFunc`.
1268    pub fn compile_decl(&mut self, decl: &LcnfFunDecl) -> Result<KotlinFunc, String> {
1269        let name = self.mangle_name(&decl.name.to_string());
1270        let params: Vec<(String, KotlinType)> = decl
1271            .params
1272            .iter()
1273            .map(|p| (self.mangle_name(&p.name), lcnf_type_to_kotlin(&p.ty)))
1274            .collect();
1275        let return_type = lcnf_type_to_kotlin(&decl.ret_type);
1276        let mut stmts: Vec<KotlinStmt> = Vec::new();
1277        let result_expr = self.compile_expr(&decl.body, &mut stmts)?;
1278        stmts.push(KotlinStmt::Return(result_expr));
1279        Ok(KotlinFunc {
1280            name,
1281            params,
1282            return_type,
1283            body: stmts,
1284            is_tailrec: false,
1285        })
1286    }
1287    /// Compile an LCNF expression, appending any necessary binding statements
1288    /// into `stmts`, and returning the resulting Kotlin expression.
1289    pub fn compile_expr(
1290        &mut self,
1291        expr: &LcnfExpr,
1292        stmts: &mut Vec<KotlinStmt>,
1293    ) -> Result<KotlinExpr, String> {
1294        match expr {
1295            LcnfExpr::Return(arg) => Ok(self.compile_arg(arg)),
1296            LcnfExpr::Unreachable => Ok(KotlinExpr::Call(
1297                Box::new(KotlinExpr::Member(
1298                    Box::new(KotlinExpr::Var("OxiLeanRuntime".to_string())),
1299                    "unreachable".to_string(),
1300                )),
1301                vec![],
1302            )),
1303            LcnfExpr::TailCall(func, args) => {
1304                let callee = self.compile_arg(func);
1305                let kt_args: Vec<KotlinExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1306                Ok(KotlinExpr::Call(Box::new(callee), kt_args))
1307            }
1308            LcnfExpr::Let {
1309                id: _,
1310                name,
1311                ty,
1312                value,
1313                body,
1314            } => {
1315                let kt_val = self.compile_let_value(value)?;
1316                let var_name = self.mangle_name(name);
1317                let kt_ty = lcnf_type_to_kotlin(ty);
1318                stmts.push(KotlinStmt::Val(var_name.clone(), kt_ty, kt_val));
1319                self.compile_expr(body, stmts)
1320            }
1321            LcnfExpr::Case {
1322                scrutinee,
1323                scrutinee_ty: _,
1324                alts,
1325                default,
1326            } => {
1327                let scrutinee_expr = KotlinExpr::Var(format!("_x{}", scrutinee.0));
1328                let result_var = self.fresh_var();
1329                let mut branches: Vec<(KotlinExpr, Vec<KotlinStmt>)> = Vec::new();
1330                for alt in alts {
1331                    let mut branch_stmts: Vec<KotlinStmt> = Vec::new();
1332                    for (idx, param) in alt.params.iter().enumerate() {
1333                        let param_name = self.mangle_name(&param.name);
1334                        let field_access = KotlinExpr::Member(
1335                            Box::new(KotlinExpr::Var(format!("_x{}", scrutinee.0))),
1336                            format!("field{}", idx),
1337                        );
1338                        branch_stmts.push(KotlinStmt::Val(
1339                            param_name,
1340                            lcnf_type_to_kotlin(&param.ty),
1341                            field_access,
1342                        ));
1343                    }
1344                    let branch_result = self.compile_expr(&alt.body, &mut branch_stmts)?;
1345                    branch_stmts.push(KotlinStmt::Assign(result_var.clone(), branch_result));
1346                    let tag_cond = KotlinExpr::Lit(KotlinLit::Int(alt.ctor_tag as i64));
1347                    branches.push((tag_cond, branch_stmts));
1348                }
1349                let mut default_stmts: Vec<KotlinStmt> = Vec::new();
1350                if let Some(def) = default {
1351                    let def_result = self.compile_expr(def, &mut default_stmts)?;
1352                    default_stmts.push(KotlinStmt::Assign(result_var.clone(), def_result));
1353                } else {
1354                    default_stmts.push(KotlinStmt::Expr(KotlinExpr::Call(
1355                        Box::new(KotlinExpr::Member(
1356                            Box::new(KotlinExpr::Var("OxiLeanRuntime".to_string())),
1357                            "unreachable".to_string(),
1358                        )),
1359                        vec![],
1360                    )));
1361                }
1362                let discriminant = KotlinExpr::Member(Box::new(scrutinee_expr), "tag".to_string());
1363                stmts.push(KotlinStmt::Var(
1364                    result_var.clone(),
1365                    KotlinType::KtAny,
1366                    KotlinExpr::Lit(KotlinLit::Null),
1367                ));
1368                stmts.push(KotlinStmt::When(discriminant, branches, default_stmts));
1369                Ok(KotlinExpr::Var(result_var))
1370            }
1371        }
1372    }
1373    /// Compile an LCNF let-value to a Kotlin expression.
1374    pub(super) fn compile_let_value(&mut self, value: &LcnfLetValue) -> Result<KotlinExpr, String> {
1375        match value {
1376            LcnfLetValue::Lit(lit) => Ok(self.compile_lit(lit)),
1377            LcnfLetValue::Erased => Ok(KotlinExpr::Lit(KotlinLit::Null)),
1378            LcnfLetValue::FVar(id) => Ok(KotlinExpr::Var(format!("_x{}", id.0))),
1379            LcnfLetValue::App(func, args) => {
1380                let callee = self.compile_arg(func);
1381                let kt_args: Vec<KotlinExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1382                Ok(KotlinExpr::Call(Box::new(callee), kt_args))
1383            }
1384            LcnfLetValue::Proj(_name, idx, var) => {
1385                let base = KotlinExpr::Var(format!("_x{}", var.0));
1386                Ok(KotlinExpr::Member(Box::new(base), format!("field{}", idx)))
1387            }
1388            LcnfLetValue::Ctor(name, _tag, args) => {
1389                let ctor_name = self.mangle_name(name);
1390                let kt_args: Vec<KotlinExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1391                Ok(KotlinExpr::Call(
1392                    Box::new(KotlinExpr::Var(ctor_name)),
1393                    kt_args,
1394                ))
1395            }
1396            LcnfLetValue::Reset(_var) => Ok(KotlinExpr::Lit(KotlinLit::Null)),
1397            LcnfLetValue::Reuse(_slot, name, _tag, args) => {
1398                let ctor_name = self.mangle_name(name);
1399                let kt_args: Vec<KotlinExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
1400                Ok(KotlinExpr::Call(
1401                    Box::new(KotlinExpr::Var(ctor_name)),
1402                    kt_args,
1403                ))
1404            }
1405        }
1406    }
1407    /// Compile an LCNF argument to a Kotlin expression.
1408    pub(super) fn compile_arg(&self, arg: &LcnfArg) -> KotlinExpr {
1409        match arg {
1410            LcnfArg::Var(id) => KotlinExpr::Var(format!("_x{}", id.0)),
1411            LcnfArg::Lit(lit) => self.compile_lit_ref(lit),
1412            LcnfArg::Erased => KotlinExpr::Lit(KotlinLit::Null),
1413            LcnfArg::Type(_) => KotlinExpr::Lit(KotlinLit::Null),
1414        }
1415    }
1416    /// Compile an LCNF literal (owned).
1417    pub(super) fn compile_lit(&self, lit: &LcnfLit) -> KotlinExpr {
1418        match lit {
1419            LcnfLit::Nat(n) => KotlinExpr::Lit(KotlinLit::Long(*n as i64)),
1420            LcnfLit::Str(s) => KotlinExpr::Lit(KotlinLit::Str(s.clone())),
1421        }
1422    }
1423    /// Compile an LCNF literal (reference, for use in `compile_arg`).
1424    pub(super) fn compile_lit_ref(&self, lit: &LcnfLit) -> KotlinExpr {
1425        self.compile_lit(lit)
1426    }
1427}
1428#[allow(dead_code)]
1429#[derive(Debug, Clone)]
1430pub struct KtDominatorTree {
1431    pub idom: Vec<Option<u32>>,
1432    pub dom_children: Vec<Vec<u32>>,
1433    pub dom_depth: Vec<u32>,
1434}
1435impl KtDominatorTree {
1436    #[allow(dead_code)]
1437    pub fn new(size: usize) -> Self {
1438        KtDominatorTree {
1439            idom: vec![None; size],
1440            dom_children: vec![Vec::new(); size],
1441            dom_depth: vec![0; size],
1442        }
1443    }
1444    #[allow(dead_code)]
1445    pub fn set_idom(&mut self, node: usize, idom: u32) {
1446        self.idom[node] = Some(idom);
1447    }
1448    #[allow(dead_code)]
1449    pub fn dominates(&self, a: usize, b: usize) -> bool {
1450        if a == b {
1451            return true;
1452        }
1453        let mut cur = b;
1454        loop {
1455            match self.idom[cur] {
1456                Some(parent) if parent as usize == a => return true,
1457                Some(parent) if parent as usize == cur => return false,
1458                Some(parent) => cur = parent as usize,
1459                None => return false,
1460            }
1461        }
1462    }
1463    #[allow(dead_code)]
1464    pub fn depth(&self, node: usize) -> u32 {
1465        self.dom_depth.get(node).copied().unwrap_or(0)
1466    }
1467}
1468/// Pass registry for KotlinX2.
1469#[allow(dead_code)]
1470#[derive(Debug, Default)]
1471pub struct KotlinX2PassRegistry {
1472    pub(super) configs: Vec<KotlinX2PassConfig>,
1473    pub(super) stats: Vec<KotlinX2PassStats>,
1474}
1475impl KotlinX2PassRegistry {
1476    #[allow(dead_code)]
1477    pub fn new() -> Self {
1478        Self::default()
1479    }
1480    #[allow(dead_code)]
1481    pub fn register(&mut self, c: KotlinX2PassConfig) {
1482        self.stats.push(KotlinX2PassStats::new());
1483        self.configs.push(c);
1484    }
1485    #[allow(dead_code)]
1486    pub fn len(&self) -> usize {
1487        self.configs.len()
1488    }
1489    #[allow(dead_code)]
1490    pub fn is_empty(&self) -> bool {
1491        self.configs.is_empty()
1492    }
1493    #[allow(dead_code)]
1494    pub fn get(&self, i: usize) -> Option<&KotlinX2PassConfig> {
1495        self.configs.get(i)
1496    }
1497    #[allow(dead_code)]
1498    pub fn get_stats(&self, i: usize) -> Option<&KotlinX2PassStats> {
1499        self.stats.get(i)
1500    }
1501    #[allow(dead_code)]
1502    pub fn enabled_passes(&self) -> Vec<&KotlinX2PassConfig> {
1503        self.configs.iter().filter(|c| c.enabled).collect()
1504    }
1505    #[allow(dead_code)]
1506    pub fn passes_in_phase(&self, ph: &KotlinX2PassPhase) -> Vec<&KotlinX2PassConfig> {
1507        self.configs
1508            .iter()
1509            .filter(|c| c.enabled && &c.phase == ph)
1510            .collect()
1511    }
1512    #[allow(dead_code)]
1513    pub fn total_nodes_visited(&self) -> usize {
1514        self.stats.iter().map(|s| s.nodes_visited).sum()
1515    }
1516    #[allow(dead_code)]
1517    pub fn any_changed(&self) -> bool {
1518        self.stats.iter().any(|s| s.changed)
1519    }
1520}
1521/// Configuration for KotlinX2 passes.
1522#[allow(dead_code)]
1523#[derive(Debug, Clone)]
1524pub struct KotlinX2PassConfig {
1525    pub name: String,
1526    pub phase: KotlinX2PassPhase,
1527    pub enabled: bool,
1528    pub max_iterations: usize,
1529    pub debug: u32,
1530    pub timeout_ms: Option<u64>,
1531}
1532impl KotlinX2PassConfig {
1533    #[allow(dead_code)]
1534    pub fn new(name: impl Into<String>) -> Self {
1535        Self {
1536            name: name.into(),
1537            phase: KotlinX2PassPhase::Middle,
1538            enabled: true,
1539            max_iterations: 100,
1540            debug: 0,
1541            timeout_ms: None,
1542        }
1543    }
1544    #[allow(dead_code)]
1545    pub fn with_phase(mut self, phase: KotlinX2PassPhase) -> Self {
1546        self.phase = phase;
1547        self
1548    }
1549    #[allow(dead_code)]
1550    pub fn with_max_iter(mut self, n: usize) -> Self {
1551        self.max_iterations = n;
1552        self
1553    }
1554    #[allow(dead_code)]
1555    pub fn with_debug(mut self, d: u32) -> Self {
1556        self.debug = d;
1557        self
1558    }
1559    #[allow(dead_code)]
1560    pub fn disabled(mut self) -> Self {
1561        self.enabled = false;
1562        self
1563    }
1564    #[allow(dead_code)]
1565    pub fn with_timeout(mut self, ms: u64) -> Self {
1566        self.timeout_ms = Some(ms);
1567        self
1568    }
1569    #[allow(dead_code)]
1570    pub fn is_debug_enabled(&self) -> bool {
1571        self.debug > 0
1572    }
1573}
1574/// Dependency graph for KotlinX2.
1575#[allow(dead_code)]
1576#[derive(Debug, Clone)]
1577pub struct KotlinX2DepGraph {
1578    pub(super) n: usize,
1579    pub(super) adj: Vec<Vec<usize>>,
1580    pub(super) rev: Vec<Vec<usize>>,
1581    pub(super) edge_count: usize,
1582}
1583impl KotlinX2DepGraph {
1584    #[allow(dead_code)]
1585    pub fn new(n: usize) -> Self {
1586        Self {
1587            n,
1588            adj: vec![Vec::new(); n],
1589            rev: vec![Vec::new(); n],
1590            edge_count: 0,
1591        }
1592    }
1593    #[allow(dead_code)]
1594    pub fn add_edge(&mut self, from: usize, to: usize) {
1595        if from < self.n && to < self.n {
1596            if !self.adj[from].contains(&to) {
1597                self.adj[from].push(to);
1598                self.rev[to].push(from);
1599                self.edge_count += 1;
1600            }
1601        }
1602    }
1603    #[allow(dead_code)]
1604    pub fn succs(&self, n: usize) -> &[usize] {
1605        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1606    }
1607    #[allow(dead_code)]
1608    pub fn preds(&self, n: usize) -> &[usize] {
1609        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1610    }
1611    #[allow(dead_code)]
1612    pub fn topo_sort(&self) -> Option<Vec<usize>> {
1613        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1614        let mut q: std::collections::VecDeque<usize> =
1615            (0..self.n).filter(|&i| deg[i] == 0).collect();
1616        let mut out = Vec::with_capacity(self.n);
1617        while let Some(u) = q.pop_front() {
1618            out.push(u);
1619            for &v in &self.adj[u] {
1620                deg[v] -= 1;
1621                if deg[v] == 0 {
1622                    q.push_back(v);
1623                }
1624            }
1625        }
1626        if out.len() == self.n {
1627            Some(out)
1628        } else {
1629            None
1630        }
1631    }
1632    #[allow(dead_code)]
1633    pub fn has_cycle(&self) -> bool {
1634        self.topo_sort().is_none()
1635    }
1636    #[allow(dead_code)]
1637    pub fn reachable(&self, start: usize) -> Vec<usize> {
1638        let mut vis = vec![false; self.n];
1639        let mut stk = vec![start];
1640        let mut out = Vec::new();
1641        while let Some(u) = stk.pop() {
1642            if u < self.n && !vis[u] {
1643                vis[u] = true;
1644                out.push(u);
1645                for &v in &self.adj[u] {
1646                    if !vis[v] {
1647                        stk.push(v);
1648                    }
1649                }
1650            }
1651        }
1652        out
1653    }
1654    #[allow(dead_code)]
1655    pub fn scc(&self) -> Vec<Vec<usize>> {
1656        let mut visited = vec![false; self.n];
1657        let mut order = Vec::new();
1658        for i in 0..self.n {
1659            if !visited[i] {
1660                let mut stk = vec![(i, 0usize)];
1661                while let Some((u, idx)) = stk.last_mut() {
1662                    if !visited[*u] {
1663                        visited[*u] = true;
1664                    }
1665                    if *idx < self.adj[*u].len() {
1666                        let v = self.adj[*u][*idx];
1667                        *idx += 1;
1668                        if !visited[v] {
1669                            stk.push((v, 0));
1670                        }
1671                    } else {
1672                        order.push(*u);
1673                        stk.pop();
1674                    }
1675                }
1676            }
1677        }
1678        let mut comp = vec![usize::MAX; self.n];
1679        let mut components: Vec<Vec<usize>> = Vec::new();
1680        for &start in order.iter().rev() {
1681            if comp[start] == usize::MAX {
1682                let cid = components.len();
1683                let mut component = Vec::new();
1684                let mut stk = vec![start];
1685                while let Some(u) = stk.pop() {
1686                    if comp[u] == usize::MAX {
1687                        comp[u] = cid;
1688                        component.push(u);
1689                        for &v in &self.rev[u] {
1690                            if comp[v] == usize::MAX {
1691                                stk.push(v);
1692                            }
1693                        }
1694                    }
1695                }
1696                components.push(component);
1697            }
1698        }
1699        components
1700    }
1701    #[allow(dead_code)]
1702    pub fn node_count(&self) -> usize {
1703        self.n
1704    }
1705    #[allow(dead_code)]
1706    pub fn edge_count(&self) -> usize {
1707        self.edge_count
1708    }
1709}
1710/// Dominator tree for KotlinX2.
1711#[allow(dead_code)]
1712#[derive(Debug, Clone)]
1713pub struct KotlinX2DomTree {
1714    pub(super) idom: Vec<Option<usize>>,
1715    pub(super) children: Vec<Vec<usize>>,
1716    pub(super) depth: Vec<usize>,
1717}
1718impl KotlinX2DomTree {
1719    #[allow(dead_code)]
1720    pub fn new(n: usize) -> Self {
1721        Self {
1722            idom: vec![None; n],
1723            children: vec![Vec::new(); n],
1724            depth: vec![0; n],
1725        }
1726    }
1727    #[allow(dead_code)]
1728    pub fn set_idom(&mut self, node: usize, dom: usize) {
1729        if node < self.idom.len() {
1730            self.idom[node] = Some(dom);
1731            if dom < self.children.len() {
1732                self.children[dom].push(node);
1733            }
1734            self.depth[node] = if dom < self.depth.len() {
1735                self.depth[dom] + 1
1736            } else {
1737                1
1738            };
1739        }
1740    }
1741    #[allow(dead_code)]
1742    pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1743        if a == b {
1744            return true;
1745        }
1746        let n = self.idom.len();
1747        for _ in 0..n {
1748            match self.idom.get(b).copied().flatten() {
1749                None => return false,
1750                Some(p) if p == a => return true,
1751                Some(p) if p == b => return false,
1752                Some(p) => b = p,
1753            }
1754        }
1755        false
1756    }
1757    #[allow(dead_code)]
1758    pub fn children_of(&self, n: usize) -> &[usize] {
1759        self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1760    }
1761    #[allow(dead_code)]
1762    pub fn depth_of(&self, n: usize) -> usize {
1763        self.depth.get(n).copied().unwrap_or(0)
1764    }
1765    #[allow(dead_code)]
1766    pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1767        let n = self.idom.len();
1768        for _ in 0..(2 * n) {
1769            if a == b {
1770                return a;
1771            }
1772            if self.depth_of(a) > self.depth_of(b) {
1773                a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1774            } else {
1775                b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1776            }
1777        }
1778        0
1779    }
1780}
1781/// Liveness analysis for KotlinX2.
1782#[allow(dead_code)]
1783#[derive(Debug, Clone, Default)]
1784pub struct KotlinX2Liveness {
1785    pub live_in: Vec<Vec<usize>>,
1786    pub live_out: Vec<Vec<usize>>,
1787    pub defs: Vec<Vec<usize>>,
1788    pub uses: Vec<Vec<usize>>,
1789}
1790impl KotlinX2Liveness {
1791    #[allow(dead_code)]
1792    pub fn new(n: usize) -> Self {
1793        Self {
1794            live_in: vec![Vec::new(); n],
1795            live_out: vec![Vec::new(); n],
1796            defs: vec![Vec::new(); n],
1797            uses: vec![Vec::new(); n],
1798        }
1799    }
1800    #[allow(dead_code)]
1801    pub fn live_in(&self, b: usize, v: usize) -> bool {
1802        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1803    }
1804    #[allow(dead_code)]
1805    pub fn live_out(&self, b: usize, v: usize) -> bool {
1806        self.live_out
1807            .get(b)
1808            .map(|s| s.contains(&v))
1809            .unwrap_or(false)
1810    }
1811    #[allow(dead_code)]
1812    pub fn add_def(&mut self, b: usize, v: usize) {
1813        if let Some(s) = self.defs.get_mut(b) {
1814            if !s.contains(&v) {
1815                s.push(v);
1816            }
1817        }
1818    }
1819    #[allow(dead_code)]
1820    pub fn add_use(&mut self, b: usize, v: usize) {
1821        if let Some(s) = self.uses.get_mut(b) {
1822            if !s.contains(&v) {
1823                s.push(v);
1824            }
1825        }
1826    }
1827    #[allow(dead_code)]
1828    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1829        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1830    }
1831    #[allow(dead_code)]
1832    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1833        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1834    }
1835}
1836#[allow(dead_code)]
1837#[derive(Debug, Clone, PartialEq)]
1838pub enum KtPassPhase {
1839    Analysis,
1840    Transformation,
1841    Verification,
1842    Cleanup,
1843}
1844impl KtPassPhase {
1845    #[allow(dead_code)]
1846    pub fn name(&self) -> &str {
1847        match self {
1848            KtPassPhase::Analysis => "analysis",
1849            KtPassPhase::Transformation => "transformation",
1850            KtPassPhase::Verification => "verification",
1851            KtPassPhase::Cleanup => "cleanup",
1852        }
1853    }
1854    #[allow(dead_code)]
1855    pub fn is_modifying(&self) -> bool {
1856        matches!(self, KtPassPhase::Transformation | KtPassPhase::Cleanup)
1857    }
1858}
1859#[allow(dead_code)]
1860#[derive(Debug, Clone)]
1861pub struct KtCacheEntry {
1862    pub key: String,
1863    pub data: Vec<u8>,
1864    pub timestamp: u64,
1865    pub valid: bool,
1866}
1867/// A complete Kotlin compilation unit (file).
1868#[derive(Debug, Clone)]
1869pub struct KotlinModule {
1870    pub package: String,
1871    pub imports: Vec<String>,
1872    pub data_classes: Vec<KotlinDataClass>,
1873    pub funs: Vec<KotlinFunc>,
1874}
1875/// Pass execution phase for KotlinX2.
1876#[allow(dead_code)]
1877#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1878pub enum KotlinX2PassPhase {
1879    Early,
1880    Middle,
1881    Late,
1882    Finalize,
1883}
1884impl KotlinX2PassPhase {
1885    #[allow(dead_code)]
1886    pub fn is_early(&self) -> bool {
1887        matches!(self, Self::Early)
1888    }
1889    #[allow(dead_code)]
1890    pub fn is_middle(&self) -> bool {
1891        matches!(self, Self::Middle)
1892    }
1893    #[allow(dead_code)]
1894    pub fn is_late(&self) -> bool {
1895        matches!(self, Self::Late)
1896    }
1897    #[allow(dead_code)]
1898    pub fn is_finalize(&self) -> bool {
1899        matches!(self, Self::Finalize)
1900    }
1901    #[allow(dead_code)]
1902    pub fn order(&self) -> u32 {
1903        match self {
1904            Self::Early => 0,
1905            Self::Middle => 1,
1906            Self::Late => 2,
1907            Self::Finalize => 3,
1908        }
1909    }
1910    #[allow(dead_code)]
1911    pub fn from_order(n: u32) -> Option<Self> {
1912        match n {
1913            0 => Some(Self::Early),
1914            1 => Some(Self::Middle),
1915            2 => Some(Self::Late),
1916            3 => Some(Self::Finalize),
1917            _ => None,
1918        }
1919    }
1920}
1921#[allow(dead_code)]
1922#[derive(Debug, Clone)]
1923pub struct KtWorklist {
1924    pub(super) items: std::collections::VecDeque<u32>,
1925    pub(super) in_worklist: std::collections::HashSet<u32>,
1926}
1927impl KtWorklist {
1928    #[allow(dead_code)]
1929    pub fn new() -> Self {
1930        KtWorklist {
1931            items: std::collections::VecDeque::new(),
1932            in_worklist: std::collections::HashSet::new(),
1933        }
1934    }
1935    #[allow(dead_code)]
1936    pub fn push(&mut self, item: u32) -> bool {
1937        if self.in_worklist.insert(item) {
1938            self.items.push_back(item);
1939            true
1940        } else {
1941            false
1942        }
1943    }
1944    #[allow(dead_code)]
1945    pub fn pop(&mut self) -> Option<u32> {
1946        let item = self.items.pop_front()?;
1947        self.in_worklist.remove(&item);
1948        Some(item)
1949    }
1950    #[allow(dead_code)]
1951    pub fn is_empty(&self) -> bool {
1952        self.items.is_empty()
1953    }
1954    #[allow(dead_code)]
1955    pub fn len(&self) -> usize {
1956        self.items.len()
1957    }
1958    #[allow(dead_code)]
1959    pub fn contains(&self, item: u32) -> bool {
1960        self.in_worklist.contains(&item)
1961    }
1962}
1963/// Constant folding helper for KotlinX2.
1964#[allow(dead_code)]
1965#[derive(Debug, Clone, Default)]
1966pub struct KotlinX2ConstFolder {
1967    pub(super) folds: usize,
1968    pub(super) failures: usize,
1969    pub(super) enabled: bool,
1970}
1971impl KotlinX2ConstFolder {
1972    #[allow(dead_code)]
1973    pub fn new() -> Self {
1974        Self {
1975            folds: 0,
1976            failures: 0,
1977            enabled: true,
1978        }
1979    }
1980    #[allow(dead_code)]
1981    pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1982        self.folds += 1;
1983        a.checked_add(b)
1984    }
1985    #[allow(dead_code)]
1986    pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1987        self.folds += 1;
1988        a.checked_sub(b)
1989    }
1990    #[allow(dead_code)]
1991    pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1992        self.folds += 1;
1993        a.checked_mul(b)
1994    }
1995    #[allow(dead_code)]
1996    pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1997        if b == 0 {
1998            self.failures += 1;
1999            None
2000        } else {
2001            self.folds += 1;
2002            a.checked_div(b)
2003        }
2004    }
2005    #[allow(dead_code)]
2006    pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
2007        if b == 0 {
2008            self.failures += 1;
2009            None
2010        } else {
2011            self.folds += 1;
2012            a.checked_rem(b)
2013        }
2014    }
2015    #[allow(dead_code)]
2016    pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
2017        self.folds += 1;
2018        a.checked_neg()
2019    }
2020    #[allow(dead_code)]
2021    pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
2022        if s >= 64 {
2023            self.failures += 1;
2024            None
2025        } else {
2026            self.folds += 1;
2027            a.checked_shl(s)
2028        }
2029    }
2030    #[allow(dead_code)]
2031    pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
2032        if s >= 64 {
2033            self.failures += 1;
2034            None
2035        } else {
2036            self.folds += 1;
2037            a.checked_shr(s)
2038        }
2039    }
2040    #[allow(dead_code)]
2041    pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
2042        self.folds += 1;
2043        a & b
2044    }
2045    #[allow(dead_code)]
2046    pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
2047        self.folds += 1;
2048        a | b
2049    }
2050    #[allow(dead_code)]
2051    pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
2052        self.folds += 1;
2053        a ^ b
2054    }
2055    #[allow(dead_code)]
2056    pub fn not_i64(&mut self, a: i64) -> i64 {
2057        self.folds += 1;
2058        !a
2059    }
2060    #[allow(dead_code)]
2061    pub fn fold_count(&self) -> usize {
2062        self.folds
2063    }
2064    #[allow(dead_code)]
2065    pub fn failure_count(&self) -> usize {
2066        self.failures
2067    }
2068    #[allow(dead_code)]
2069    pub fn enable(&mut self) {
2070        self.enabled = true;
2071    }
2072    #[allow(dead_code)]
2073    pub fn disable(&mut self) {
2074        self.enabled = false;
2075    }
2076    #[allow(dead_code)]
2077    pub fn is_enabled(&self) -> bool {
2078        self.enabled
2079    }
2080}
2081#[allow(dead_code)]
2082pub struct KtConstantFoldingHelper;
2083impl KtConstantFoldingHelper {
2084    #[allow(dead_code)]
2085    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
2086        a.checked_add(b)
2087    }
2088    #[allow(dead_code)]
2089    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
2090        a.checked_sub(b)
2091    }
2092    #[allow(dead_code)]
2093    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
2094        a.checked_mul(b)
2095    }
2096    #[allow(dead_code)]
2097    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
2098        if b == 0 {
2099            None
2100        } else {
2101            a.checked_div(b)
2102        }
2103    }
2104    #[allow(dead_code)]
2105    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
2106        a + b
2107    }
2108    #[allow(dead_code)]
2109    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
2110        a * b
2111    }
2112    #[allow(dead_code)]
2113    pub fn fold_neg_i64(a: i64) -> Option<i64> {
2114        a.checked_neg()
2115    }
2116    #[allow(dead_code)]
2117    pub fn fold_not_bool(a: bool) -> bool {
2118        !a
2119    }
2120    #[allow(dead_code)]
2121    pub fn fold_and_bool(a: bool, b: bool) -> bool {
2122        a && b
2123    }
2124    #[allow(dead_code)]
2125    pub fn fold_or_bool(a: bool, b: bool) -> bool {
2126        a || b
2127    }
2128    #[allow(dead_code)]
2129    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
2130        a.checked_shl(b)
2131    }
2132    #[allow(dead_code)]
2133    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
2134        a.checked_shr(b)
2135    }
2136    #[allow(dead_code)]
2137    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
2138        if b == 0 {
2139            None
2140        } else {
2141            Some(a % b)
2142        }
2143    }
2144    #[allow(dead_code)]
2145    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
2146        a & b
2147    }
2148    #[allow(dead_code)]
2149    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
2150        a | b
2151    }
2152    #[allow(dead_code)]
2153    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
2154        a ^ b
2155    }
2156    #[allow(dead_code)]
2157    pub fn fold_bitnot_i64(a: i64) -> i64 {
2158        !a
2159    }
2160}
2161#[allow(dead_code)]
2162pub struct KtPassRegistry {
2163    pub(super) configs: Vec<KtPassConfig>,
2164    pub(super) stats: std::collections::HashMap<String, KtPassStats>,
2165}
2166impl KtPassRegistry {
2167    #[allow(dead_code)]
2168    pub fn new() -> Self {
2169        KtPassRegistry {
2170            configs: Vec::new(),
2171            stats: std::collections::HashMap::new(),
2172        }
2173    }
2174    #[allow(dead_code)]
2175    pub fn register(&mut self, config: KtPassConfig) {
2176        self.stats
2177            .insert(config.pass_name.clone(), KtPassStats::new());
2178        self.configs.push(config);
2179    }
2180    #[allow(dead_code)]
2181    pub fn enabled_passes(&self) -> Vec<&KtPassConfig> {
2182        self.configs.iter().filter(|c| c.enabled).collect()
2183    }
2184    #[allow(dead_code)]
2185    pub fn get_stats(&self, name: &str) -> Option<&KtPassStats> {
2186        self.stats.get(name)
2187    }
2188    #[allow(dead_code)]
2189    pub fn total_passes(&self) -> usize {
2190        self.configs.len()
2191    }
2192    #[allow(dead_code)]
2193    pub fn enabled_count(&self) -> usize {
2194        self.enabled_passes().len()
2195    }
2196    #[allow(dead_code)]
2197    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
2198        if let Some(stats) = self.stats.get_mut(name) {
2199            stats.record_run(changes, time_ms, iter);
2200        }
2201    }
2202}
2203#[allow(dead_code)]
2204#[derive(Debug, Clone)]
2205pub struct KtAnalysisCache {
2206    pub(super) entries: std::collections::HashMap<String, KtCacheEntry>,
2207    pub(super) max_size: usize,
2208    pub(super) hits: u64,
2209    pub(super) misses: u64,
2210}
2211impl KtAnalysisCache {
2212    #[allow(dead_code)]
2213    pub fn new(max_size: usize) -> Self {
2214        KtAnalysisCache {
2215            entries: std::collections::HashMap::new(),
2216            max_size,
2217            hits: 0,
2218            misses: 0,
2219        }
2220    }
2221    #[allow(dead_code)]
2222    pub fn get(&mut self, key: &str) -> Option<&KtCacheEntry> {
2223        if self.entries.contains_key(key) {
2224            self.hits += 1;
2225            self.entries.get(key)
2226        } else {
2227            self.misses += 1;
2228            None
2229        }
2230    }
2231    #[allow(dead_code)]
2232    pub fn insert(&mut self, key: String, data: Vec<u8>) {
2233        if self.entries.len() >= self.max_size {
2234            if let Some(oldest) = self.entries.keys().next().cloned() {
2235                self.entries.remove(&oldest);
2236            }
2237        }
2238        self.entries.insert(
2239            key.clone(),
2240            KtCacheEntry {
2241                key,
2242                data,
2243                timestamp: 0,
2244                valid: true,
2245            },
2246        );
2247    }
2248    #[allow(dead_code)]
2249    pub fn invalidate(&mut self, key: &str) {
2250        if let Some(entry) = self.entries.get_mut(key) {
2251            entry.valid = false;
2252        }
2253    }
2254    #[allow(dead_code)]
2255    pub fn clear(&mut self) {
2256        self.entries.clear();
2257    }
2258    #[allow(dead_code)]
2259    pub fn hit_rate(&self) -> f64 {
2260        let total = self.hits + self.misses;
2261        if total == 0 {
2262            return 0.0;
2263        }
2264        self.hits as f64 / total as f64
2265    }
2266    #[allow(dead_code)]
2267    pub fn size(&self) -> usize {
2268        self.entries.len()
2269    }
2270}