Skip to main content

oxilean_codegen/native_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::{HashMap, HashSet};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11/// A unique identifier for a basic block.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub struct BlockId(pub u32);
14#[allow(dead_code)]
15#[derive(Debug, Clone)]
16pub struct NatLivenessInfo {
17    pub live_in: Vec<std::collections::HashSet<u32>>,
18    pub live_out: Vec<std::collections::HashSet<u32>>,
19    pub defs: Vec<std::collections::HashSet<u32>>,
20    pub uses: Vec<std::collections::HashSet<u32>>,
21}
22impl NatLivenessInfo {
23    #[allow(dead_code)]
24    pub fn new(block_count: usize) -> Self {
25        NatLivenessInfo {
26            live_in: vec![std::collections::HashSet::new(); block_count],
27            live_out: vec![std::collections::HashSet::new(); block_count],
28            defs: vec![std::collections::HashSet::new(); block_count],
29            uses: vec![std::collections::HashSet::new(); block_count],
30        }
31    }
32    #[allow(dead_code)]
33    pub fn add_def(&mut self, block: usize, var: u32) {
34        if block < self.defs.len() {
35            self.defs[block].insert(var);
36        }
37    }
38    #[allow(dead_code)]
39    pub fn add_use(&mut self, block: usize, var: u32) {
40        if block < self.uses.len() {
41            self.uses[block].insert(var);
42        }
43    }
44    #[allow(dead_code)]
45    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
46        self.live_in
47            .get(block)
48            .map(|s| s.contains(&var))
49            .unwrap_or(false)
50    }
51    #[allow(dead_code)]
52    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
53        self.live_out
54            .get(block)
55            .map(|s| s.contains(&var))
56            .unwrap_or(false)
57    }
58}
59#[allow(dead_code)]
60pub struct NatConstantFoldingHelper;
61impl NatConstantFoldingHelper {
62    #[allow(dead_code)]
63    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
64        a.checked_add(b)
65    }
66    #[allow(dead_code)]
67    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
68        a.checked_sub(b)
69    }
70    #[allow(dead_code)]
71    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
72        a.checked_mul(b)
73    }
74    #[allow(dead_code)]
75    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
76        if b == 0 {
77            None
78        } else {
79            a.checked_div(b)
80        }
81    }
82    #[allow(dead_code)]
83    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
84        a + b
85    }
86    #[allow(dead_code)]
87    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
88        a * b
89    }
90    #[allow(dead_code)]
91    pub fn fold_neg_i64(a: i64) -> Option<i64> {
92        a.checked_neg()
93    }
94    #[allow(dead_code)]
95    pub fn fold_not_bool(a: bool) -> bool {
96        !a
97    }
98    #[allow(dead_code)]
99    pub fn fold_and_bool(a: bool, b: bool) -> bool {
100        a && b
101    }
102    #[allow(dead_code)]
103    pub fn fold_or_bool(a: bool, b: bool) -> bool {
104        a || b
105    }
106    #[allow(dead_code)]
107    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
108        a.checked_shl(b)
109    }
110    #[allow(dead_code)]
111    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
112        a.checked_shr(b)
113    }
114    #[allow(dead_code)]
115    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
116        if b == 0 {
117            None
118        } else {
119            Some(a % b)
120        }
121    }
122    #[allow(dead_code)]
123    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
124        a & b
125    }
126    #[allow(dead_code)]
127    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
128        a | b
129    }
130    #[allow(dead_code)]
131    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
132        a ^ b
133    }
134    #[allow(dead_code)]
135    pub fn fold_bitnot_i64(a: i64) -> i64 {
136        !a
137    }
138}
139/// A compiled native module.
140#[derive(Debug, Clone)]
141pub struct NativeModule {
142    /// Functions in this module.
143    pub functions: Vec<NativeFunc>,
144    /// Global variables.
145    pub globals: Vec<(String, NativeType, Option<i64>)>,
146    /// External function declarations.
147    pub extern_fns: Vec<(String, Vec<NativeType>, NativeType)>,
148    /// Module name.
149    pub name: String,
150}
151impl NativeModule {
152    /// Create a new empty module.
153    pub(super) fn new(name: &str) -> Self {
154        NativeModule {
155            functions: Vec::new(),
156            globals: Vec::new(),
157            extern_fns: Vec::new(),
158            name: name.to_string(),
159        }
160    }
161    /// Total number of instructions in the module.
162    pub fn total_instructions(&self) -> usize {
163        self.functions.iter().map(|f| f.instruction_count()).sum()
164    }
165    /// Find a function by name.
166    pub fn get_function(&self, name: &str) -> Option<&NativeFunc> {
167        self.functions.iter().find(|f| f.name == name)
168    }
169}
170#[allow(dead_code)]
171#[derive(Debug, Clone)]
172pub struct NatDepGraph {
173    pub(super) nodes: Vec<u32>,
174    pub(super) edges: Vec<(u32, u32)>,
175}
176impl NatDepGraph {
177    #[allow(dead_code)]
178    pub fn new() -> Self {
179        NatDepGraph {
180            nodes: Vec::new(),
181            edges: Vec::new(),
182        }
183    }
184    #[allow(dead_code)]
185    pub fn add_node(&mut self, id: u32) {
186        if !self.nodes.contains(&id) {
187            self.nodes.push(id);
188        }
189    }
190    #[allow(dead_code)]
191    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
192        self.add_node(dep);
193        self.add_node(dependent);
194        self.edges.push((dep, dependent));
195    }
196    #[allow(dead_code)]
197    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
198        self.edges
199            .iter()
200            .filter(|(d, _)| *d == node)
201            .map(|(_, dep)| *dep)
202            .collect()
203    }
204    #[allow(dead_code)]
205    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
206        self.edges
207            .iter()
208            .filter(|(_, dep)| *dep == node)
209            .map(|(d, _)| *d)
210            .collect()
211    }
212    #[allow(dead_code)]
213    pub fn topological_sort(&self) -> Vec<u32> {
214        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
215        for &n in &self.nodes {
216            in_degree.insert(n, 0);
217        }
218        for (_, dep) in &self.edges {
219            *in_degree.entry(*dep).or_insert(0) += 1;
220        }
221        let mut queue: std::collections::VecDeque<u32> = self
222            .nodes
223            .iter()
224            .filter(|&&n| in_degree[&n] == 0)
225            .copied()
226            .collect();
227        let mut result = Vec::new();
228        while let Some(node) = queue.pop_front() {
229            result.push(node);
230            for dep in self.dependents_of(node) {
231                let cnt = in_degree.entry(dep).or_insert(0);
232                *cnt = cnt.saturating_sub(1);
233                if *cnt == 0 {
234                    queue.push_back(dep);
235                }
236            }
237        }
238        result
239    }
240    #[allow(dead_code)]
241    pub fn has_cycle(&self) -> bool {
242        self.topological_sort().len() < self.nodes.len()
243    }
244}
245#[allow(dead_code)]
246#[derive(Debug, Clone)]
247pub struct NatDominatorTree {
248    pub idom: Vec<Option<u32>>,
249    pub dom_children: Vec<Vec<u32>>,
250    pub dom_depth: Vec<u32>,
251}
252impl NatDominatorTree {
253    #[allow(dead_code)]
254    pub fn new(size: usize) -> Self {
255        NatDominatorTree {
256            idom: vec![None; size],
257            dom_children: vec![Vec::new(); size],
258            dom_depth: vec![0; size],
259        }
260    }
261    #[allow(dead_code)]
262    pub fn set_idom(&mut self, node: usize, idom: u32) {
263        self.idom[node] = Some(idom);
264    }
265    #[allow(dead_code)]
266    pub fn dominates(&self, a: usize, b: usize) -> bool {
267        if a == b {
268            return true;
269        }
270        let mut cur = b;
271        loop {
272            match self.idom[cur] {
273                Some(parent) if parent as usize == a => return true,
274                Some(parent) if parent as usize == cur => return false,
275                Some(parent) => cur = parent as usize,
276                None => return false,
277            }
278        }
279    }
280    #[allow(dead_code)]
281    pub fn depth(&self, node: usize) -> u32 {
282        self.dom_depth.get(node).copied().unwrap_or(0)
283    }
284}
285/// Configuration for the native backend.
286#[derive(Debug, Clone)]
287pub struct NativeEmitConfig {
288    /// Optimization level: 0 = none, 1 = basic, 2 = full, 3 = aggressive.
289    pub opt_level: u8,
290    /// Whether to generate debug info.
291    pub debug_info: bool,
292    /// Target architecture hint.
293    pub target_arch: String,
294    /// Number of general-purpose registers available.
295    pub num_gp_regs: usize,
296    /// Whether to emit comments in the IR.
297    pub emit_comments: bool,
298}
299/// A register in the native IR (SSA form).
300///
301/// Registers numbered 0..65535 are virtual (pre-allocation).
302/// Registers >= 65536 are physical (post-allocation).
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
304pub struct Register(pub u32);
305
306/// The boundary between virtual and physical register indices.
307pub(super) const VIRT_PHYS_BOUNDARY: u32 = 65536;
308
309impl Register {
310    /// Whether this is a virtual register (pre-allocation).
311    pub fn is_virtual(&self) -> bool {
312        self.0 < VIRT_PHYS_BOUNDARY
313    }
314    /// Whether this is a physical register (post-allocation).
315    pub fn is_physical(&self) -> bool {
316        self.0 >= VIRT_PHYS_BOUNDARY
317    }
318    /// Create a virtual register.
319    pub fn virt(n: u32) -> Self {
320        assert!(
321            n < VIRT_PHYS_BOUNDARY,
322            "Virtual register index must be < {}",
323            VIRT_PHYS_BOUNDARY
324        );
325        Register(n)
326    }
327    /// Create a physical register.
328    pub fn phys(n: u32) -> Self {
329        Register(n + VIRT_PHYS_BOUNDARY)
330    }
331}
332#[allow(dead_code)]
333#[derive(Debug, Clone, Default)]
334pub struct NatPassStats {
335    pub total_runs: u32,
336    pub successful_runs: u32,
337    pub total_changes: u64,
338    pub time_ms: u64,
339    pub iterations_used: u32,
340}
341impl NatPassStats {
342    #[allow(dead_code)]
343    pub fn new() -> Self {
344        Self::default()
345    }
346    #[allow(dead_code)]
347    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
348        self.total_runs += 1;
349        self.successful_runs += 1;
350        self.total_changes += changes;
351        self.time_ms += time_ms;
352        self.iterations_used = iterations;
353    }
354    #[allow(dead_code)]
355    pub fn average_changes_per_run(&self) -> f64 {
356        if self.total_runs == 0 {
357            return 0.0;
358        }
359        self.total_changes as f64 / self.total_runs as f64
360    }
361    #[allow(dead_code)]
362    pub fn success_rate(&self) -> f64 {
363        if self.total_runs == 0 {
364            return 0.0;
365        }
366        self.successful_runs as f64 / self.total_runs as f64
367    }
368    #[allow(dead_code)]
369    pub fn format_summary(&self) -> String {
370        format!(
371            "Runs: {}/{}, Changes: {}, Time: {}ms",
372            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
373        )
374    }
375}
376/// The native code generation backend.
377///
378/// Compiles LCNF modules to native IR suitable for JIT or AOT compilation.
379pub struct NativeBackend {
380    pub(super) config: NativeEmitConfig,
381    pub(super) stats: NativeEmitStats,
382    /// Next virtual register to allocate.
383    pub(super) next_vreg: u32,
384    /// Next block ID to allocate.
385    pub(super) next_block: u32,
386    /// Mapping from LCNF variable IDs to native registers.
387    pub(super) var_map: HashMap<LcnfVarId, Register>,
388    /// Next stack slot.
389    pub(super) next_stack_slot: u32,
390}
391impl NativeBackend {
392    /// Create a new native backend.
393    pub fn new(config: NativeEmitConfig) -> Self {
394        NativeBackend {
395            config,
396            stats: NativeEmitStats::default(),
397            next_vreg: 0,
398            next_block: 0,
399            var_map: HashMap::new(),
400            next_stack_slot: 0,
401        }
402    }
403    /// Create a native backend with default configuration.
404    pub fn default_backend() -> Self {
405        Self::new(NativeEmitConfig::default())
406    }
407    /// Allocate a fresh virtual register.
408    pub(super) fn alloc_vreg(&mut self) -> Register {
409        let r = Register::virt(self.next_vreg);
410        self.next_vreg += 1;
411        self.stats.virtual_regs_used += 1;
412        r
413    }
414    /// Allocate a fresh block ID.
415    pub(super) fn alloc_block(&mut self) -> BlockId {
416        let id = BlockId(self.next_block);
417        self.next_block += 1;
418        self.stats.blocks_generated += 1;
419        id
420    }
421    /// Allocate a stack slot.
422    pub(super) fn alloc_stack_slot(&mut self) -> u32 {
423        let slot = self.next_stack_slot;
424        self.next_stack_slot += 1;
425        self.stats.stack_slots_allocated += 1;
426        slot
427    }
428    /// Reset per-function state.
429    pub(super) fn reset_function_state(&mut self) {
430        self.next_vreg = 0;
431        self.next_block = 0;
432        self.var_map.clear();
433        self.next_stack_slot = 0;
434    }
435    /// Get or allocate a register for an LCNF variable.
436    pub(super) fn get_var_reg(&mut self, id: LcnfVarId) -> Register {
437        if let Some(r) = self.var_map.get(&id) {
438            *r
439        } else {
440            let r = self.alloc_vreg();
441            self.var_map.insert(id, r);
442            r
443        }
444    }
445    /// Compile an entire LCNF module to native IR.
446    pub fn compile_module(&mut self, module: &LcnfModule) -> NativeModule {
447        let mut native_module = NativeModule::new(&module.name);
448        for ext in &module.extern_decls {
449            let params: Vec<NativeType> = ext
450                .params
451                .iter()
452                .filter(|p| !p.erased)
453                .map(|p| lcnf_type_to_native(&p.ty))
454                .collect();
455            let ret = lcnf_type_to_native(&ext.ret_type);
456            native_module
457                .extern_fns
458                .push((ext.name.clone(), params, ret));
459        }
460        for fun in &module.fun_decls {
461            let native_func = self.compile_fun_decl(fun);
462            native_module.functions.push(native_func);
463            self.stats.functions_compiled += 1;
464        }
465        native_module
466    }
467    /// Compile a single LCNF function declaration.
468    pub fn compile_fun_decl(&mut self, decl: &LcnfFunDecl) -> NativeFunc {
469        self.reset_function_state();
470        let mut params = Vec::new();
471        for p in &decl.params {
472            if p.erased {
473                continue;
474            }
475            let r = self.alloc_vreg();
476            self.var_map.insert(p.id, r);
477            params.push((r, lcnf_type_to_native(&p.ty)));
478        }
479        let ret_type = lcnf_type_to_native(&decl.ret_type);
480        let mut func = NativeFunc::new(&decl.name, params, ret_type);
481        func.is_recursive = decl.is_recursive;
482        let entry_id = self.alloc_block();
483        let mut entry_block = BasicBlock::new(entry_id);
484        if self.config.emit_comments {
485            entry_block.push_inst(NativeInst::Comment(format!("Function: {}", decl.name)));
486        }
487        let mut extra_blocks = Vec::new();
488        self.compile_expr(&decl.body, &mut entry_block, &mut extra_blocks, &ret_type);
489        func.blocks.push(entry_block);
490        func.blocks.extend(extra_blocks);
491        func.stack_size = self.next_stack_slot as usize * 8;
492        func
493    }
494    /// Compile an LCNF expression, appending instructions to the current block.
495    /// May create additional basic blocks for control flow.
496    pub(super) fn compile_expr(
497        &mut self,
498        expr: &LcnfExpr,
499        current_block: &mut BasicBlock,
500        extra_blocks: &mut Vec<BasicBlock>,
501        ret_type: &NativeType,
502    ) {
503        match expr {
504            LcnfExpr::Let {
505                id,
506                ty,
507                value,
508                body,
509                ..
510            } => {
511                let native_ty = lcnf_type_to_native(ty);
512                let dst = self.alloc_vreg();
513                self.var_map.insert(*id, dst);
514                self.compile_let_value(value, dst, &native_ty, current_block);
515                self.compile_expr(body, current_block, extra_blocks, ret_type);
516            }
517            LcnfExpr::Case {
518                scrutinee,
519                alts,
520                default,
521                ..
522            } => {
523                let scrut_reg = self.get_var_reg(*scrutinee);
524                if alts.is_empty() {
525                    if let Some(def) = default {
526                        self.compile_expr(def, current_block, extra_blocks, ret_type);
527                    } else {
528                        current_block.push_inst(NativeInst::Ret { value: None });
529                    }
530                    return;
531                }
532                let merge_id = self.alloc_block();
533                let merge_result_reg = self.alloc_vreg();
534                let mut merge_block = BasicBlock::new(merge_id);
535                if *ret_type != NativeType::Void {
536                    merge_block.params.push((merge_result_reg, *ret_type));
537                }
538                if alts.len() == 1 && default.is_some() {
539                    let alt = &alts[0];
540                    let tag_reg = self.alloc_vreg();
541                    current_block.push_inst(NativeInst::Call {
542                        dst: Some(tag_reg),
543                        func: NativeValue::FRef("lean_obj_tag".to_string()),
544                        args: vec![NativeValue::Reg(scrut_reg)],
545                        ret_type: NativeType::I32,
546                    });
547                    let cmp_reg = self.alloc_vreg();
548                    current_block.push_inst(NativeInst::Cmp {
549                        dst: cmp_reg,
550                        cc: CondCode::Eq,
551                        ty: NativeType::I32,
552                        lhs: NativeValue::Reg(tag_reg),
553                        rhs: NativeValue::Imm(alt.ctor_tag as i64),
554                    });
555                    let then_id = self.alloc_block();
556                    let else_id = self.alloc_block();
557                    current_block.push_inst(NativeInst::CondBr {
558                        cond: NativeValue::Reg(cmp_reg),
559                        then_target: then_id,
560                        else_target: else_id,
561                    });
562                    let mut then_block = BasicBlock::new(then_id);
563                    self.bind_ctor_params(&alt.params, scrut_reg, &mut then_block);
564                    self.compile_expr(&alt.body, &mut then_block, extra_blocks, ret_type);
565                    if then_block.terminator.is_none() {
566                        then_block.push_inst(NativeInst::Br { target: merge_id });
567                    }
568                    extra_blocks.push(then_block);
569                    let mut else_block = BasicBlock::new(else_id);
570                    self.compile_expr(
571                        default
572                            .as_ref()
573                            .expect(
574                                "default is Some; guaranteed by default.is_some() check at if condition",
575                            ),
576                        &mut else_block,
577                        extra_blocks,
578                        ret_type,
579                    );
580                    if else_block.terminator.is_none() {
581                        else_block.push_inst(NativeInst::Br { target: merge_id });
582                    }
583                    extra_blocks.push(else_block);
584                } else {
585                    let tag_reg = self.alloc_vreg();
586                    current_block.push_inst(NativeInst::Call {
587                        dst: Some(tag_reg),
588                        func: NativeValue::FRef("lean_obj_tag".to_string()),
589                        args: vec![NativeValue::Reg(scrut_reg)],
590                        ret_type: NativeType::I32,
591                    });
592                    let default_id = self.alloc_block();
593                    let mut targets = Vec::new();
594                    for alt in alts {
595                        let alt_block_id = self.alloc_block();
596                        targets.push((alt.ctor_tag as u64, alt_block_id));
597                        let mut alt_block = BasicBlock::new(alt_block_id);
598                        self.bind_ctor_params(&alt.params, scrut_reg, &mut alt_block);
599                        self.compile_expr(&alt.body, &mut alt_block, extra_blocks, ret_type);
600                        if alt_block.terminator.is_none() {
601                            alt_block.push_inst(NativeInst::Br { target: merge_id });
602                        }
603                        extra_blocks.push(alt_block);
604                    }
605                    current_block.push_inst(NativeInst::Switch {
606                        value: NativeValue::Reg(tag_reg),
607                        default: default_id,
608                        targets,
609                    });
610                    let mut def_block = BasicBlock::new(default_id);
611                    if let Some(def_expr) = default {
612                        self.compile_expr(def_expr, &mut def_block, extra_blocks, ret_type);
613                    } else {
614                        def_block.push_inst(NativeInst::Ret { value: None });
615                    }
616                    if def_block.terminator.is_none() {
617                        def_block.push_inst(NativeInst::Br { target: merge_id });
618                    }
619                    extra_blocks.push(def_block);
620                }
621                extra_blocks.push(merge_block);
622            }
623            LcnfExpr::Return(arg) => {
624                let val = self.compile_arg(arg, current_block);
625                current_block.push_inst(NativeInst::Ret { value: Some(val) });
626            }
627            LcnfExpr::Unreachable => {
628                current_block.push_inst(NativeInst::Call {
629                    dst: None,
630                    func: NativeValue::FRef("lean_internal_panic_unreachable".to_string()),
631                    args: vec![],
632                    ret_type: NativeType::Void,
633                });
634                current_block.push_inst(NativeInst::Ret { value: None });
635            }
636            LcnfExpr::TailCall(func, args) => {
637                let func_val = self.compile_arg(func, current_block);
638                let arg_vals: Vec<NativeValue> = args
639                    .iter()
640                    .map(|a| self.compile_arg(a, current_block))
641                    .collect();
642                let result_reg = self.alloc_vreg();
643                current_block.push_inst(NativeInst::Call {
644                    dst: Some(result_reg),
645                    func: func_val,
646                    args: arg_vals,
647                    ret_type: *ret_type,
648                });
649                current_block.push_inst(NativeInst::Ret {
650                    value: Some(NativeValue::Reg(result_reg)),
651                });
652            }
653        }
654    }
655    /// Compile a let-value into instructions.
656    pub(super) fn compile_let_value(
657        &mut self,
658        value: &LcnfLetValue,
659        dst: Register,
660        _ty: &NativeType,
661        block: &mut BasicBlock,
662    ) {
663        match value {
664            LcnfLetValue::App(func, args) => {
665                let func_val = self.compile_arg_to_value(func);
666                let arg_vals: Vec<NativeValue> =
667                    args.iter().map(|a| self.compile_arg_to_value(a)).collect();
668                block.push_inst(NativeInst::Call {
669                    dst: Some(dst),
670                    func: func_val,
671                    args: arg_vals,
672                    ret_type: NativeType::Ptr,
673                });
674                self.stats.instructions_generated += 1;
675            }
676            LcnfLetValue::Proj(_name, idx, var) => {
677                let obj_reg = self.get_var_reg(*var);
678                block.push_inst(NativeInst::Call {
679                    dst: Some(dst),
680                    func: NativeValue::FRef("lean_ctor_get".to_string()),
681                    args: vec![NativeValue::Reg(obj_reg), NativeValue::Imm(*idx as i64)],
682                    ret_type: NativeType::Ptr,
683                });
684                self.stats.instructions_generated += 1;
685            }
686            LcnfLetValue::Ctor(_name, tag, args) => {
687                let num_objs = args.len();
688                block.push_inst(NativeInst::Call {
689                    dst: Some(dst),
690                    func: NativeValue::FRef("lean_alloc_ctor".to_string()),
691                    args: vec![
692                        NativeValue::Imm(*tag as i64),
693                        NativeValue::Imm(num_objs as i64),
694                        NativeValue::Imm(0),
695                    ],
696                    ret_type: NativeType::Ptr,
697                });
698                self.stats.instructions_generated += 1;
699                for (i, arg) in args.iter().enumerate() {
700                    let val = self.compile_arg_to_value(arg);
701                    block.push_inst(NativeInst::Call {
702                        dst: None,
703                        func: NativeValue::FRef("lean_ctor_set".to_string()),
704                        args: vec![NativeValue::Reg(dst), NativeValue::Imm(i as i64), val],
705                        ret_type: NativeType::Void,
706                    });
707                    self.stats.instructions_generated += 1;
708                }
709            }
710            LcnfLetValue::Lit(lit) => match lit {
711                LcnfLit::Nat(n) => {
712                    block.push_inst(NativeInst::LoadImm {
713                        dst,
714                        ty: NativeType::I64,
715                        value: *n as i64,
716                    });
717                    self.stats.instructions_generated += 1;
718                }
719                LcnfLit::Int(i) => {
720                    block.push_inst(NativeInst::LoadImm {
721                        dst,
722                        ty: NativeType::I64,
723                        value: *i,
724                    });
725                    self.stats.instructions_generated += 1;
726                }
727                LcnfLit::Str(s) => {
728                    block.push_inst(NativeInst::Call {
729                        dst: Some(dst),
730                        func: NativeValue::FRef("lean_mk_string".to_string()),
731                        args: vec![NativeValue::StrRef(s.clone())],
732                        ret_type: NativeType::Ptr,
733                    });
734                    if self.config.emit_comments {
735                        block.push_inst(NativeInst::Comment(format!("string: \"{}\"", s)));
736                    }
737                    self.stats.instructions_generated += 1;
738                }
739            },
740            LcnfLetValue::Erased => {
741                block.push_inst(NativeInst::LoadImm {
742                    dst,
743                    ty: NativeType::Ptr,
744                    value: 0,
745                });
746                self.stats.instructions_generated += 1;
747            }
748            LcnfLetValue::FVar(var) => {
749                let src = self.get_var_reg(*var);
750                block.push_inst(NativeInst::Copy {
751                    dst,
752                    src: NativeValue::Reg(src),
753                });
754                self.stats.instructions_generated += 1;
755            }
756            LcnfLetValue::Reset(var) => {
757                let obj_reg = self.get_var_reg(*var);
758                block.push_inst(NativeInst::Call {
759                    dst: Some(dst),
760                    func: NativeValue::FRef("lean_obj_reset".to_string()),
761                    args: vec![NativeValue::Reg(obj_reg)],
762                    ret_type: NativeType::Ptr,
763                });
764                self.stats.instructions_generated += 1;
765            }
766            LcnfLetValue::Reuse(slot, _name, tag, args) => {
767                let num_objs = args.len();
768                let slot_reg = self.get_var_reg(*slot);
769                block.push_inst(NativeInst::Call {
770                    dst: Some(dst),
771                    func: NativeValue::FRef("lean_alloc_ctor_using".to_string()),
772                    args: vec![
773                        NativeValue::Reg(slot_reg),
774                        NativeValue::Imm(*tag as i64),
775                        NativeValue::Imm(num_objs as i64),
776                        NativeValue::Imm(0),
777                    ],
778                    ret_type: NativeType::Ptr,
779                });
780                self.stats.instructions_generated += 1;
781                for (i, arg) in args.iter().enumerate() {
782                    let val = self.compile_arg_to_value(arg);
783                    block.push_inst(NativeInst::Call {
784                        dst: None,
785                        func: NativeValue::FRef("lean_ctor_set".to_string()),
786                        args: vec![NativeValue::Reg(dst), NativeValue::Imm(i as i64), val],
787                        ret_type: NativeType::Void,
788                    });
789                    self.stats.instructions_generated += 1;
790                }
791            }
792        }
793    }
794    /// Bind constructor parameters to registers by extracting fields.
795    pub(super) fn bind_ctor_params(
796        &mut self,
797        params: &[LcnfParam],
798        scrut_reg: Register,
799        block: &mut BasicBlock,
800    ) {
801        for (i, param) in params.iter().enumerate() {
802            if param.erased {
803                continue;
804            }
805            let dst = self.alloc_vreg();
806            self.var_map.insert(param.id, dst);
807            block.push_inst(NativeInst::Call {
808                dst: Some(dst),
809                func: NativeValue::FRef("lean_ctor_get".to_string()),
810                args: vec![NativeValue::Reg(scrut_reg), NativeValue::Imm(i as i64)],
811                ret_type: NativeType::Ptr,
812            });
813            self.stats.instructions_generated += 1;
814        }
815    }
816    /// Compile an LCNF argument to a NativeValue, possibly emitting instructions.
817    pub(super) fn compile_arg(&mut self, arg: &LcnfArg, block: &mut BasicBlock) -> NativeValue {
818        match arg {
819            LcnfArg::Var(id) => {
820                let r = self.get_var_reg(*id);
821                NativeValue::Reg(r)
822            }
823            LcnfArg::Lit(lit) => match lit {
824                LcnfLit::Nat(n) => {
825                    let r = self.alloc_vreg();
826                    block.push_inst(NativeInst::LoadImm {
827                        dst: r,
828                        ty: NativeType::I64,
829                        value: *n as i64,
830                    });
831                    self.stats.instructions_generated += 1;
832                    NativeValue::Reg(r)
833                }
834                LcnfLit::Int(i) => {
835                    let r = self.alloc_vreg();
836                    block.push_inst(NativeInst::LoadImm {
837                        dst: r,
838                        ty: NativeType::I64,
839                        value: *i,
840                    });
841                    self.stats.instructions_generated += 1;
842                    NativeValue::Reg(r)
843                }
844                LcnfLit::Str(s) => {
845                    let r = self.alloc_vreg();
846                    block.push_inst(NativeInst::Call {
847                        dst: Some(r),
848                        func: NativeValue::FRef("lean_mk_string".to_string()),
849                        args: vec![NativeValue::StrRef(s.clone())],
850                        ret_type: NativeType::Ptr,
851                    });
852                    self.stats.instructions_generated += 1;
853                    NativeValue::Reg(r)
854                }
855            },
856            LcnfArg::Erased | LcnfArg::Type(_) => NativeValue::Imm(0),
857        }
858    }
859    /// Compile an LCNF argument to a NativeValue without emitting instructions.
860    pub(super) fn compile_arg_to_value(&mut self, arg: &LcnfArg) -> NativeValue {
861        match arg {
862            LcnfArg::Var(id) => NativeValue::Reg(self.get_var_reg(*id)),
863            LcnfArg::Lit(LcnfLit::Nat(n)) => NativeValue::Imm(*n as i64),
864            LcnfArg::Lit(LcnfLit::Int(i)) => NativeValue::Imm(*i),
865            LcnfArg::Lit(LcnfLit::Str(s)) => NativeValue::StrRef(s.clone()),
866            LcnfArg::Erased | LcnfArg::Type(_) => NativeValue::Imm(0),
867        }
868    }
869    /// Get accumulated statistics.
870    pub fn stats(&self) -> &NativeEmitStats {
871        &self.stats
872    }
873}
874/// Live interval for a virtual register.
875#[derive(Debug, Clone)]
876struct LiveInterval {
877    pub(super) vreg: Register,
878    pub(super) start: usize,
879    pub(super) end: usize,
880    pub(super) assigned_phys: Option<Register>,
881    pub(super) spill_slot: Option<u32>,
882}
883#[allow(dead_code)]
884#[derive(Debug, Clone, PartialEq)]
885pub enum NatPassPhase {
886    Analysis,
887    Transformation,
888    Verification,
889    Cleanup,
890}
891impl NatPassPhase {
892    #[allow(dead_code)]
893    pub fn name(&self) -> &str {
894        match self {
895            NatPassPhase::Analysis => "analysis",
896            NatPassPhase::Transformation => "transformation",
897            NatPassPhase::Verification => "verification",
898            NatPassPhase::Cleanup => "cleanup",
899        }
900    }
901    #[allow(dead_code)]
902    pub fn is_modifying(&self) -> bool {
903        matches!(self, NatPassPhase::Transformation | NatPassPhase::Cleanup)
904    }
905}
906#[allow(dead_code)]
907pub struct NatPassRegistry {
908    pub(super) configs: Vec<NatPassConfig>,
909    pub(super) stats: std::collections::HashMap<String, NatPassStats>,
910}
911impl NatPassRegistry {
912    #[allow(dead_code)]
913    pub fn new() -> Self {
914        NatPassRegistry {
915            configs: Vec::new(),
916            stats: std::collections::HashMap::new(),
917        }
918    }
919    #[allow(dead_code)]
920    pub fn register(&mut self, config: NatPassConfig) {
921        self.stats
922            .insert(config.pass_name.clone(), NatPassStats::new());
923        self.configs.push(config);
924    }
925    #[allow(dead_code)]
926    pub fn enabled_passes(&self) -> Vec<&NatPassConfig> {
927        self.configs.iter().filter(|c| c.enabled).collect()
928    }
929    #[allow(dead_code)]
930    pub fn get_stats(&self, name: &str) -> Option<&NatPassStats> {
931        self.stats.get(name)
932    }
933    #[allow(dead_code)]
934    pub fn total_passes(&self) -> usize {
935        self.configs.len()
936    }
937    #[allow(dead_code)]
938    pub fn enabled_count(&self) -> usize {
939        self.enabled_passes().len()
940    }
941    #[allow(dead_code)]
942    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
943        if let Some(stats) = self.stats.get_mut(name) {
944            stats.record_run(changes, time_ms, iter);
945        }
946    }
947}
948/// A value operand in the native IR.
949#[derive(Debug, Clone, PartialEq, Eq, Hash)]
950pub enum NativeValue {
951    /// A register (virtual or physical).
952    Reg(Register),
953    /// An immediate constant.
954    Imm(i64),
955    /// A function reference (by name).
956    FRef(String),
957    /// A stack slot.
958    StackSlot(u32),
959    /// An unsigned immediate.
960    UImm(u64),
961    /// A string literal reference (pointer to the string bytes).
962    StrRef(String),
963}
964impl NativeValue {
965    /// Create a register value.
966    pub(super) fn reg(r: Register) -> Self {
967        NativeValue::Reg(r)
968    }
969    /// Create an immediate value.
970    pub(super) fn imm(n: i64) -> Self {
971        NativeValue::Imm(n)
972    }
973    /// Create an unsigned immediate value.
974    pub(super) fn uimm(n: u64) -> Self {
975        NativeValue::UImm(n)
976    }
977}
978/// A basic block in the native IR.
979#[derive(Debug, Clone)]
980pub struct BasicBlock {
981    /// The block identifier.
982    pub label: BlockId,
983    /// Block parameters (for SSA phi-elimination).
984    pub params: Vec<(Register, NativeType)>,
985    /// The instructions in this block (excluding the terminator).
986    pub instructions: Vec<NativeInst>,
987    /// The terminator instruction.
988    pub terminator: Option<NativeInst>,
989}
990impl BasicBlock {
991    /// Create a new empty basic block.
992    pub(super) fn new(label: BlockId) -> Self {
993        BasicBlock {
994            label,
995            params: Vec::new(),
996            instructions: Vec::new(),
997            terminator: None,
998        }
999    }
1000    /// Append an instruction to this block.
1001    pub(super) fn push_inst(&mut self, inst: NativeInst) {
1002        if inst.is_terminator() {
1003            self.terminator = Some(inst);
1004        } else {
1005            self.instructions.push(inst);
1006        }
1007    }
1008    /// Get the successor block IDs of this block.
1009    pub fn successors(&self) -> Vec<BlockId> {
1010        match &self.terminator {
1011            Some(NativeInst::Br { target }) => vec![*target],
1012            Some(NativeInst::CondBr {
1013                then_target,
1014                else_target,
1015                ..
1016            }) => {
1017                vec![*then_target, *else_target]
1018            }
1019            Some(NativeInst::Switch {
1020                default, targets, ..
1021            }) => {
1022                let mut succs = vec![*default];
1023                for (_, t) in targets {
1024                    succs.push(*t);
1025                }
1026                succs
1027            }
1028            _ => vec![],
1029        }
1030    }
1031    /// Total number of instructions (including terminator).
1032    pub fn instruction_count(&self) -> usize {
1033        self.instructions.len() + if self.terminator.is_some() { 1 } else { 0 }
1034    }
1035}
1036#[allow(dead_code)]
1037#[derive(Debug, Clone)]
1038pub struct NatCacheEntry {
1039    pub key: String,
1040    pub data: Vec<u8>,
1041    pub timestamp: u64,
1042    pub valid: bool,
1043}
1044/// A function in the native IR.
1045#[derive(Debug, Clone)]
1046pub struct NativeFunc {
1047    /// Function name.
1048    pub name: String,
1049    /// Parameter registers and types.
1050    pub params: Vec<(Register, NativeType)>,
1051    /// Return type.
1052    pub ret_type: NativeType,
1053    /// Basic blocks (entry is blocks\[0\]).
1054    pub blocks: Vec<BasicBlock>,
1055    /// Total stack size needed.
1056    pub stack_size: usize,
1057    /// Whether this function is recursive.
1058    pub is_recursive: bool,
1059}
1060impl NativeFunc {
1061    /// Create a new function.
1062    pub(super) fn new(
1063        name: &str,
1064        params: Vec<(Register, NativeType)>,
1065        ret_type: NativeType,
1066    ) -> Self {
1067        NativeFunc {
1068            name: name.to_string(),
1069            params,
1070            ret_type,
1071            blocks: Vec::new(),
1072            stack_size: 0,
1073            is_recursive: false,
1074        }
1075    }
1076    /// Get the entry block.
1077    pub fn entry_block(&self) -> Option<&BasicBlock> {
1078        self.blocks.first()
1079    }
1080    /// Total number of instructions across all blocks.
1081    pub fn instruction_count(&self) -> usize {
1082        self.blocks.iter().map(|b| b.instruction_count()).sum()
1083    }
1084    /// Get a block by ID.
1085    pub fn get_block(&self, id: BlockId) -> Option<&BasicBlock> {
1086        self.blocks.iter().find(|b| b.label == id)
1087    }
1088    /// Get all virtual registers used in this function.
1089    pub fn virtual_registers(&self) -> HashSet<Register> {
1090        let mut regs = HashSet::new();
1091        for (r, _) in &self.params {
1092            if r.is_virtual() {
1093                regs.insert(*r);
1094            }
1095        }
1096        for block in &self.blocks {
1097            for (r, _) in &block.params {
1098                if r.is_virtual() {
1099                    regs.insert(*r);
1100                }
1101            }
1102            for inst in &block.instructions {
1103                if let Some(dst) = inst.dst_reg() {
1104                    if dst.is_virtual() {
1105                        regs.insert(dst);
1106                    }
1107                }
1108                for src in inst.src_regs() {
1109                    if src.is_virtual() {
1110                        regs.insert(src);
1111                    }
1112                }
1113            }
1114            if let Some(term) = &block.terminator {
1115                if let Some(dst) = term.dst_reg() {
1116                    if dst.is_virtual() {
1117                        regs.insert(dst);
1118                    }
1119                }
1120                for src in term.src_regs() {
1121                    if src.is_virtual() {
1122                        regs.insert(src);
1123                    }
1124                }
1125            }
1126        }
1127        regs
1128    }
1129}
1130/// A single instruction in the native IR.
1131#[derive(Debug, Clone, PartialEq)]
1132pub enum NativeInst {
1133    /// Load immediate: `dst = imm`.
1134    LoadImm {
1135        dst: Register,
1136        ty: NativeType,
1137        value: i64,
1138    },
1139    /// Add: `dst = lhs + rhs`.
1140    Add {
1141        dst: Register,
1142        ty: NativeType,
1143        lhs: NativeValue,
1144        rhs: NativeValue,
1145    },
1146    /// Subtract: `dst = lhs - rhs`.
1147    Sub {
1148        dst: Register,
1149        ty: NativeType,
1150        lhs: NativeValue,
1151        rhs: NativeValue,
1152    },
1153    /// Multiply: `dst = lhs * rhs`.
1154    Mul {
1155        dst: Register,
1156        ty: NativeType,
1157        lhs: NativeValue,
1158        rhs: NativeValue,
1159    },
1160    /// Divide: `dst = lhs / rhs`.
1161    Div {
1162        dst: Register,
1163        ty: NativeType,
1164        lhs: NativeValue,
1165        rhs: NativeValue,
1166    },
1167    /// Bitwise AND: `dst = lhs & rhs`.
1168    And {
1169        dst: Register,
1170        ty: NativeType,
1171        lhs: NativeValue,
1172        rhs: NativeValue,
1173    },
1174    /// Bitwise OR: `dst = lhs | rhs`.
1175    Or {
1176        dst: Register,
1177        ty: NativeType,
1178        lhs: NativeValue,
1179        rhs: NativeValue,
1180    },
1181    /// Bitwise XOR: `dst = lhs ^ rhs`.
1182    Xor {
1183        dst: Register,
1184        ty: NativeType,
1185        lhs: NativeValue,
1186        rhs: NativeValue,
1187    },
1188    /// Shift left: `dst = lhs << rhs`.
1189    Shl {
1190        dst: Register,
1191        ty: NativeType,
1192        lhs: NativeValue,
1193        rhs: NativeValue,
1194    },
1195    /// Shift right (arithmetic): `dst = lhs >> rhs`.
1196    Shr {
1197        dst: Register,
1198        ty: NativeType,
1199        lhs: NativeValue,
1200        rhs: NativeValue,
1201    },
1202    /// Compare: `dst = cmp(cc, lhs, rhs)`.
1203    Cmp {
1204        dst: Register,
1205        cc: CondCode,
1206        ty: NativeType,
1207        lhs: NativeValue,
1208        rhs: NativeValue,
1209    },
1210    /// Unconditional branch to a block.
1211    Br { target: BlockId },
1212    /// Conditional branch: if cond != 0, goto then_target, else goto else_target.
1213    CondBr {
1214        cond: NativeValue,
1215        then_target: BlockId,
1216        else_target: BlockId,
1217    },
1218    /// Function call: `dst = func(args...)`.
1219    Call {
1220        dst: Option<Register>,
1221        func: NativeValue,
1222        args: Vec<NativeValue>,
1223        ret_type: NativeType,
1224    },
1225    /// Return from function.
1226    Ret { value: Option<NativeValue> },
1227    /// Load from memory: `dst = *addr`.
1228    Load {
1229        dst: Register,
1230        ty: NativeType,
1231        addr: NativeValue,
1232    },
1233    /// Store to memory: `*addr = value`.
1234    Store {
1235        ty: NativeType,
1236        addr: NativeValue,
1237        value: NativeValue,
1238    },
1239    /// Allocate stack space: `dst = alloca(size, align)`.
1240    Alloc {
1241        dst: Register,
1242        size: usize,
1243        align: usize,
1244    },
1245    /// Free heap memory.
1246    Free { ptr: NativeValue },
1247    /// Phi node (SSA): `dst = phi([(val, block), ...])`.
1248    Phi {
1249        dst: Register,
1250        ty: NativeType,
1251        incoming: Vec<(NativeValue, BlockId)>,
1252    },
1253    /// Select: `dst = cond ? true_val : false_val`.
1254    Select {
1255        dst: Register,
1256        ty: NativeType,
1257        cond: NativeValue,
1258        true_val: NativeValue,
1259        false_val: NativeValue,
1260    },
1261    /// Copy: `dst = src`.
1262    Copy { dst: Register, src: NativeValue },
1263    /// No-operation (placeholder).
1264    Nop,
1265    /// Comment (for debugging).
1266    Comment(String),
1267    /// Integer to pointer cast.
1268    IntToPtr { dst: Register, src: NativeValue },
1269    /// Pointer to integer cast.
1270    PtrToInt { dst: Register, src: NativeValue },
1271    /// Get element pointer (pointer arithmetic).
1272    GetElementPtr {
1273        dst: Register,
1274        base: NativeValue,
1275        offset: NativeValue,
1276        elem_size: usize,
1277    },
1278    /// Switch/table branch.
1279    Switch {
1280        value: NativeValue,
1281        default: BlockId,
1282        targets: Vec<(u64, BlockId)>,
1283    },
1284}
1285impl NativeInst {
1286    /// Get the destination register of this instruction, if any.
1287    pub fn dst_reg(&self) -> Option<Register> {
1288        match self {
1289            NativeInst::LoadImm { dst, .. }
1290            | NativeInst::Add { dst, .. }
1291            | NativeInst::Sub { dst, .. }
1292            | NativeInst::Mul { dst, .. }
1293            | NativeInst::Div { dst, .. }
1294            | NativeInst::And { dst, .. }
1295            | NativeInst::Or { dst, .. }
1296            | NativeInst::Xor { dst, .. }
1297            | NativeInst::Shl { dst, .. }
1298            | NativeInst::Shr { dst, .. }
1299            | NativeInst::Cmp { dst, .. }
1300            | NativeInst::Load { dst, .. }
1301            | NativeInst::Alloc { dst, .. }
1302            | NativeInst::Phi { dst, .. }
1303            | NativeInst::Select { dst, .. }
1304            | NativeInst::Copy { dst, .. }
1305            | NativeInst::IntToPtr { dst, .. }
1306            | NativeInst::PtrToInt { dst, .. }
1307            | NativeInst::GetElementPtr { dst, .. } => Some(*dst),
1308            NativeInst::Call { dst, .. } => *dst,
1309            _ => None,
1310        }
1311    }
1312    /// Get all source registers read by this instruction.
1313    pub fn src_regs(&self) -> Vec<Register> {
1314        let mut regs = Vec::new();
1315        let extract = |v: &NativeValue, regs: &mut Vec<Register>| {
1316            if let NativeValue::Reg(r) = v {
1317                regs.push(*r);
1318            }
1319        };
1320        match self {
1321            NativeInst::Add { lhs, rhs, .. }
1322            | NativeInst::Sub { lhs, rhs, .. }
1323            | NativeInst::Mul { lhs, rhs, .. }
1324            | NativeInst::Div { lhs, rhs, .. }
1325            | NativeInst::And { lhs, rhs, .. }
1326            | NativeInst::Or { lhs, rhs, .. }
1327            | NativeInst::Xor { lhs, rhs, .. }
1328            | NativeInst::Shl { lhs, rhs, .. }
1329            | NativeInst::Shr { lhs, rhs, .. }
1330            | NativeInst::Cmp { lhs, rhs, .. } => {
1331                extract(lhs, &mut regs);
1332                extract(rhs, &mut regs);
1333            }
1334            NativeInst::CondBr { cond, .. } => extract(cond, &mut regs),
1335            NativeInst::Call { func, args, .. } => {
1336                extract(func, &mut regs);
1337                for a in args {
1338                    extract(a, &mut regs);
1339                }
1340            }
1341            NativeInst::Ret { value: Some(v) } => extract(v, &mut regs),
1342            NativeInst::Load { addr, .. } => extract(addr, &mut regs),
1343            NativeInst::Store { addr, value, .. } => {
1344                extract(addr, &mut regs);
1345                extract(value, &mut regs);
1346            }
1347            NativeInst::Free { ptr } => extract(ptr, &mut regs),
1348            NativeInst::Phi { incoming, .. } => {
1349                for (v, _) in incoming {
1350                    extract(v, &mut regs);
1351                }
1352            }
1353            NativeInst::Select {
1354                cond,
1355                true_val,
1356                false_val,
1357                ..
1358            } => {
1359                extract(cond, &mut regs);
1360                extract(true_val, &mut regs);
1361                extract(false_val, &mut regs);
1362            }
1363            NativeInst::Copy { src, .. } => extract(src, &mut regs),
1364            NativeInst::IntToPtr { src, .. } | NativeInst::PtrToInt { src, .. } => {
1365                extract(src, &mut regs)
1366            }
1367            NativeInst::GetElementPtr { base, offset, .. } => {
1368                extract(base, &mut regs);
1369                extract(offset, &mut regs);
1370            }
1371            NativeInst::Switch { value, .. } => extract(value, &mut regs),
1372            _ => {}
1373        }
1374        regs
1375    }
1376    /// Whether this instruction is a terminator (ends a basic block).
1377    pub fn is_terminator(&self) -> bool {
1378        matches!(
1379            self,
1380            NativeInst::Br { .. }
1381                | NativeInst::CondBr { .. }
1382                | NativeInst::Ret { .. }
1383                | NativeInst::Switch { .. }
1384        )
1385    }
1386}
1387/// Statistics from native code generation.
1388#[derive(Debug, Clone, Default)]
1389pub struct NativeEmitStats {
1390    /// Number of functions compiled.
1391    pub functions_compiled: usize,
1392    /// Number of basic blocks generated.
1393    pub blocks_generated: usize,
1394    /// Number of instructions generated.
1395    pub instructions_generated: usize,
1396    /// Number of virtual registers used.
1397    pub virtual_regs_used: usize,
1398    /// Number of stack slots allocated.
1399    pub stack_slots_allocated: usize,
1400    /// Number of spills during register allocation.
1401    pub spills: usize,
1402}
1403/// Machine-level types for the native IR.
1404#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1405pub enum NativeType {
1406    /// 8-bit integer.
1407    I8,
1408    /// 16-bit integer.
1409    I16,
1410    /// 32-bit integer.
1411    I32,
1412    /// 64-bit integer.
1413    I64,
1414    /// 32-bit floating point.
1415    F32,
1416    /// 64-bit floating point.
1417    F64,
1418    /// Pointer (word-sized).
1419    Ptr,
1420    /// Function reference.
1421    FuncRef,
1422    /// Void (no value).
1423    Void,
1424}
1425impl NativeType {
1426    /// Size in bytes of this type.
1427    pub fn size_bytes(&self) -> usize {
1428        match self {
1429            NativeType::I8 => 1,
1430            NativeType::I16 => 2,
1431            NativeType::I32 | NativeType::F32 => 4,
1432            NativeType::I64 | NativeType::F64 | NativeType::Ptr | NativeType::FuncRef => 8,
1433            NativeType::Void => 0,
1434        }
1435    }
1436    /// Alignment in bytes.
1437    pub fn alignment(&self) -> usize {
1438        self.size_bytes().max(1)
1439    }
1440    /// Whether this is a floating-point type.
1441    pub fn is_float(&self) -> bool {
1442        matches!(self, NativeType::F32 | NativeType::F64)
1443    }
1444    /// Whether this is an integer type.
1445    pub fn is_integer(&self) -> bool {
1446        matches!(
1447            self,
1448            NativeType::I8 | NativeType::I16 | NativeType::I32 | NativeType::I64
1449        )
1450    }
1451    /// Whether this is a pointer type.
1452    pub fn is_pointer(&self) -> bool {
1453        matches!(self, NativeType::Ptr | NativeType::FuncRef)
1454    }
1455}
1456/// Comparison condition code.
1457#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1458pub enum CondCode {
1459    Eq,
1460    Ne,
1461    Lt,
1462    Le,
1463    Gt,
1464    Ge,
1465    /// Unsigned less than.
1466    Ult,
1467    /// Unsigned less or equal.
1468    Ule,
1469    /// Unsigned greater than.
1470    Ugt,
1471    /// Unsigned greater or equal.
1472    Uge,
1473}
1474#[allow(dead_code)]
1475#[derive(Debug, Clone)]
1476pub struct NatPassConfig {
1477    pub phase: NatPassPhase,
1478    pub enabled: bool,
1479    pub max_iterations: u32,
1480    pub debug_output: bool,
1481    pub pass_name: String,
1482}
1483impl NatPassConfig {
1484    #[allow(dead_code)]
1485    pub fn new(name: impl Into<String>, phase: NatPassPhase) -> Self {
1486        NatPassConfig {
1487            phase,
1488            enabled: true,
1489            max_iterations: 10,
1490            debug_output: false,
1491            pass_name: name.into(),
1492        }
1493    }
1494    #[allow(dead_code)]
1495    pub fn disabled(mut self) -> Self {
1496        self.enabled = false;
1497        self
1498    }
1499    #[allow(dead_code)]
1500    pub fn with_debug(mut self) -> Self {
1501        self.debug_output = true;
1502        self
1503    }
1504    #[allow(dead_code)]
1505    pub fn max_iter(mut self, n: u32) -> Self {
1506        self.max_iterations = n;
1507        self
1508    }
1509}
1510#[allow(dead_code)]
1511#[derive(Debug, Clone)]
1512pub struct NatAnalysisCache {
1513    pub(super) entries: std::collections::HashMap<String, NatCacheEntry>,
1514    pub(super) max_size: usize,
1515    pub(super) hits: u64,
1516    pub(super) misses: u64,
1517}
1518impl NatAnalysisCache {
1519    #[allow(dead_code)]
1520    pub fn new(max_size: usize) -> Self {
1521        NatAnalysisCache {
1522            entries: std::collections::HashMap::new(),
1523            max_size,
1524            hits: 0,
1525            misses: 0,
1526        }
1527    }
1528    #[allow(dead_code)]
1529    pub fn get(&mut self, key: &str) -> Option<&NatCacheEntry> {
1530        if self.entries.contains_key(key) {
1531            self.hits += 1;
1532            self.entries.get(key)
1533        } else {
1534            self.misses += 1;
1535            None
1536        }
1537    }
1538    #[allow(dead_code)]
1539    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1540        if self.entries.len() >= self.max_size {
1541            if let Some(oldest) = self.entries.keys().next().cloned() {
1542                self.entries.remove(&oldest);
1543            }
1544        }
1545        self.entries.insert(
1546            key.clone(),
1547            NatCacheEntry {
1548                key,
1549                data,
1550                timestamp: 0,
1551                valid: true,
1552            },
1553        );
1554    }
1555    #[allow(dead_code)]
1556    pub fn invalidate(&mut self, key: &str) {
1557        if let Some(entry) = self.entries.get_mut(key) {
1558            entry.valid = false;
1559        }
1560    }
1561    #[allow(dead_code)]
1562    pub fn clear(&mut self) {
1563        self.entries.clear();
1564    }
1565    #[allow(dead_code)]
1566    pub fn hit_rate(&self) -> f64 {
1567        let total = self.hits + self.misses;
1568        if total == 0 {
1569            return 0.0;
1570        }
1571        self.hits as f64 / total as f64
1572    }
1573    #[allow(dead_code)]
1574    pub fn size(&self) -> usize {
1575        self.entries.len()
1576    }
1577}
1578/// Linear scan register allocator.
1579///
1580/// Takes a NativeFunc with virtual registers and assigns physical registers
1581/// using a simple linear scan algorithm.
1582pub struct RegisterAllocator {
1583    /// Number of available physical registers.
1584    pub(super) num_phys_regs: usize,
1585    /// Live intervals computed during analysis.
1586    pub(super) intervals: Vec<LiveInterval>,
1587    /// Active intervals (sorted by end point).
1588    pub(super) active: Vec<usize>,
1589    /// Next spill slot to allocate.
1590    pub(super) next_spill: u32,
1591    /// Set of free physical registers.
1592    pub(super) free_regs: Vec<bool>,
1593    /// Total number of spills performed.
1594    pub(super) spill_count: usize,
1595}
1596impl RegisterAllocator {
1597    /// Create a new register allocator.
1598    pub fn new(num_phys_regs: usize) -> Self {
1599        RegisterAllocator {
1600            num_phys_regs,
1601            intervals: Vec::new(),
1602            active: Vec::new(),
1603            next_spill: 0,
1604            free_regs: vec![true; num_phys_regs],
1605            spill_count: 0,
1606        }
1607    }
1608    /// Perform register allocation on a function.
1609    pub fn allocate(&mut self, func: &NativeFunc) -> HashMap<Register, Register> {
1610        self.intervals.clear();
1611        self.active.clear();
1612        self.free_regs = vec![true; self.num_phys_regs];
1613        self.spill_count = 0;
1614        self.compute_live_intervals(func);
1615        self.intervals.sort_by_key(|i| i.start);
1616        let mut assignment: HashMap<Register, Register> = HashMap::new();
1617        for idx in 0..self.intervals.len() {
1618            let current_start = self.intervals[idx].start;
1619            self.expire_old_intervals(current_start);
1620            if let Some(phys_idx) = self.find_free_reg() {
1621                self.intervals[idx].assigned_phys = Some(Register::phys(phys_idx as u32));
1622                self.free_regs[phys_idx] = false;
1623                self.active.push(idx);
1624                self.active.sort_by_key(|&i| self.intervals[i].end);
1625                assignment.insert(self.intervals[idx].vreg, Register::phys(phys_idx as u32));
1626            } else {
1627                self.spill_at_interval(idx, &mut assignment);
1628            }
1629        }
1630        assignment
1631    }
1632    /// Compute live intervals for all virtual registers.
1633    pub(super) fn compute_live_intervals(&mut self, func: &NativeFunc) {
1634        let mut intervals_map: HashMap<Register, (usize, usize)> = HashMap::new();
1635        let mut position = 0usize;
1636        for block in &func.blocks {
1637            for inst in &block.instructions {
1638                if let Some(dst) = inst.dst_reg() {
1639                    if dst.is_virtual() {
1640                        intervals_map
1641                            .entry(dst)
1642                            .and_modify(|(_s, e)| *e = position)
1643                            .or_insert((position, position));
1644                    }
1645                }
1646                for src in inst.src_regs() {
1647                    if src.is_virtual() {
1648                        intervals_map
1649                            .entry(src)
1650                            .and_modify(|(_s, e)| *e = position)
1651                            .or_insert((position, position));
1652                    }
1653                }
1654                position += 1;
1655            }
1656            if let Some(term) = &block.terminator {
1657                if let Some(dst) = term.dst_reg() {
1658                    if dst.is_virtual() {
1659                        intervals_map
1660                            .entry(dst)
1661                            .and_modify(|(_s, e)| *e = position)
1662                            .or_insert((position, position));
1663                    }
1664                }
1665                for src in term.src_regs() {
1666                    if src.is_virtual() {
1667                        intervals_map
1668                            .entry(src)
1669                            .and_modify(|(_s, e)| *e = position)
1670                            .or_insert((position, position));
1671                    }
1672                }
1673                position += 1;
1674            }
1675        }
1676        for (r, _) in &func.params {
1677            if r.is_virtual() {
1678                intervals_map
1679                    .entry(*r)
1680                    .and_modify(|(s, _e)| *s = 0)
1681                    .or_insert((0, 0));
1682            }
1683        }
1684        self.intervals = intervals_map
1685            .into_iter()
1686            .map(|(vreg, (start, end))| LiveInterval {
1687                vreg,
1688                start,
1689                end,
1690                assigned_phys: None,
1691                spill_slot: None,
1692            })
1693            .collect();
1694    }
1695    /// Expire intervals that end before the current position.
1696    pub(super) fn expire_old_intervals(&mut self, current_start: usize) {
1697        let mut to_remove = Vec::new();
1698        for (active_idx, &interval_idx) in self.active.iter().enumerate() {
1699            if self.intervals[interval_idx].end < current_start {
1700                if let Some(phys) = self.intervals[interval_idx].assigned_phys {
1701                    let phys_idx = (phys.0 - VIRT_PHYS_BOUNDARY) as usize;
1702                    if phys_idx < self.free_regs.len() {
1703                        self.free_regs[phys_idx] = true;
1704                    }
1705                }
1706                to_remove.push(active_idx);
1707            }
1708        }
1709        for idx in to_remove.into_iter().rev() {
1710            self.active.remove(idx);
1711        }
1712    }
1713    /// Find a free physical register.
1714    pub(super) fn find_free_reg(&self) -> Option<usize> {
1715        self.free_regs.iter().position(|&free| free)
1716    }
1717    /// Spill at the current interval.
1718    pub(super) fn spill_at_interval(
1719        &mut self,
1720        current_idx: usize,
1721        assignment: &mut HashMap<Register, Register>,
1722    ) {
1723        if !self.active.is_empty() {
1724            let last_active_idx = *self
1725                .active
1726                .last()
1727                .expect("active is non-empty; guaranteed by !self.active.is_empty() guard");
1728            if self.intervals[last_active_idx].end > self.intervals[current_idx].end {
1729                let phys = self
1730                    .intervals[last_active_idx]
1731                    .assigned_phys
1732                    .expect(
1733                        "last active interval must have an assigned physical register; invariant of linear scan regalloc",
1734                    );
1735                self.intervals[current_idx].assigned_phys = Some(phys);
1736                assignment.insert(self.intervals[current_idx].vreg, phys);
1737                let spill_slot = self.next_spill;
1738                self.next_spill += 1;
1739                self.intervals[last_active_idx].assigned_phys = None;
1740                self.intervals[last_active_idx].spill_slot = Some(spill_slot);
1741                assignment.remove(&self.intervals[last_active_idx].vreg);
1742                self.active.pop();
1743                self.active.push(current_idx);
1744                self.active.sort_by_key(|&i| self.intervals[i].end);
1745                self.spill_count += 1;
1746                return;
1747            }
1748        }
1749        let spill_slot = self.next_spill;
1750        self.next_spill += 1;
1751        self.intervals[current_idx].spill_slot = Some(spill_slot);
1752        self.spill_count += 1;
1753    }
1754    /// Get the number of spills performed.
1755    pub fn spill_count(&self) -> usize {
1756        self.spill_count
1757    }
1758}
1759#[allow(dead_code)]
1760#[derive(Debug, Clone)]
1761pub struct NatWorklist {
1762    pub(super) items: std::collections::VecDeque<u32>,
1763    pub(super) in_worklist: std::collections::HashSet<u32>,
1764}
1765impl NatWorklist {
1766    #[allow(dead_code)]
1767    pub fn new() -> Self {
1768        NatWorklist {
1769            items: std::collections::VecDeque::new(),
1770            in_worklist: std::collections::HashSet::new(),
1771        }
1772    }
1773    #[allow(dead_code)]
1774    pub fn push(&mut self, item: u32) -> bool {
1775        if self.in_worklist.insert(item) {
1776            self.items.push_back(item);
1777            true
1778        } else {
1779            false
1780        }
1781    }
1782    #[allow(dead_code)]
1783    pub fn pop(&mut self) -> Option<u32> {
1784        let item = self.items.pop_front()?;
1785        self.in_worklist.remove(&item);
1786        Some(item)
1787    }
1788    #[allow(dead_code)]
1789    pub fn is_empty(&self) -> bool {
1790        self.items.is_empty()
1791    }
1792    #[allow(dead_code)]
1793    pub fn len(&self) -> usize {
1794        self.items.len()
1795    }
1796    #[allow(dead_code)]
1797    pub fn contains(&self, item: u32) -> bool {
1798        self.in_worklist.contains(&item)
1799    }
1800}