Skip to main content

oxilean_codegen/wasm_backend/
types.rs

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