Skip to main content

oxilean_codegen/cranelift_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use std::collections::HashMap;
7
8/// An instruction together with its optional result SSA value.
9#[derive(Debug, Clone, PartialEq)]
10pub struct CraneliftInstResult {
11    /// The result SSA value produced by this instruction (None for void/side-effect-only)
12    pub result: Option<CraneliftValue>,
13    /// The instruction
14    pub instr: CraneliftInstr,
15}
16impl CraneliftInstResult {
17    /// Create an instruction with a result.
18    pub fn with_result(result: CraneliftValue, instr: CraneliftInstr) -> Self {
19        CraneliftInstResult {
20            result: Some(result),
21            instr,
22        }
23    }
24    /// Create an instruction with no result.
25    pub fn no_result(instr: CraneliftInstr) -> Self {
26        CraneliftInstResult {
27            result: None,
28            instr,
29        }
30    }
31    /// Emit this instruction as a textual IR string.
32    pub fn emit(&self) -> String {
33        let instr_str = emit_instr(&self.instr);
34        if let Some(ref v) = self.result {
35            format!("{} = {}", v, instr_str)
36        } else {
37            instr_str
38        }
39    }
40}
41/// Function signature.
42#[derive(Debug, Clone, PartialEq)]
43pub struct Signature {
44    /// Calling convention
45    pub call_conv: CallConv,
46    /// Parameter types
47    pub params: Vec<CraneliftType>,
48    /// Return types (Cranelift supports multiple returns)
49    pub returns: Vec<CraneliftType>,
50}
51impl Signature {
52    /// Create a new signature.
53    pub fn new(
54        call_conv: CallConv,
55        params: Vec<CraneliftType>,
56        returns: Vec<CraneliftType>,
57    ) -> Self {
58        Signature {
59            call_conv,
60            params,
61            returns,
62        }
63    }
64    /// Create a simple C-like signature.
65    pub fn c_like(params: Vec<CraneliftType>, returns: Vec<CraneliftType>) -> Self {
66        Signature::new(CallConv::SystemV, params, returns)
67    }
68}
69/// Helpers for generating type conversion instructions.
70#[allow(dead_code)]
71pub struct CraneliftTypeCoerce;
72impl CraneliftTypeCoerce {
73    /// Generate the instruction to narrow `val` from `src_ty` to `dst_ty` (truncation).
74    #[allow(dead_code)]
75    pub fn narrow(
76        src_ty: &CraneliftType,
77        dst_ty: &CraneliftType,
78        val: CraneliftValue,
79    ) -> Option<CraneliftInstr> {
80        match (src_ty, dst_ty) {
81            (CraneliftType::I64, CraneliftType::I32)
82            | (CraneliftType::I64, CraneliftType::I16)
83            | (CraneliftType::I64, CraneliftType::I8)
84            | (CraneliftType::I32, CraneliftType::I16)
85            | (CraneliftType::I32, CraneliftType::I8)
86            | (CraneliftType::I16, CraneliftType::I8) => {
87                Some(CraneliftInstr::Ireduce(dst_ty.clone(), val))
88            }
89            (CraneliftType::F64, CraneliftType::F32) => {
90                Some(CraneliftInstr::Fdemote(CraneliftType::F32, val))
91            }
92            _ => None,
93        }
94    }
95    /// Generate the instruction to widen `val` from `src_ty` to `dst_ty` (extension).
96    #[allow(dead_code)]
97    pub fn widen_signed(
98        _src_ty: &CraneliftType,
99        dst_ty: &CraneliftType,
100        val: CraneliftValue,
101    ) -> Option<CraneliftInstr> {
102        match dst_ty {
103            CraneliftType::I16 | CraneliftType::I32 | CraneliftType::I64 | CraneliftType::I128 => {
104                Some(CraneliftInstr::Sextend(dst_ty.clone(), val))
105            }
106            CraneliftType::F64 => Some(CraneliftInstr::Fpromote(CraneliftType::F64, val)),
107            _ => None,
108        }
109    }
110    /// Generate the instruction to zero-extend `val` to `dst_ty`.
111    #[allow(dead_code)]
112    pub fn widen_unsigned(
113        _src_ty: &CraneliftType,
114        dst_ty: &CraneliftType,
115        val: CraneliftValue,
116    ) -> Option<CraneliftInstr> {
117        match dst_ty {
118            CraneliftType::I16 | CraneliftType::I32 | CraneliftType::I64 | CraneliftType::I128 => {
119                Some(CraneliftInstr::Uextend(dst_ty.clone(), val))
120            }
121            _ => None,
122        }
123    }
124}
125/// How a global value is defined.
126#[derive(Debug, Clone)]
127#[allow(dead_code)]
128pub enum CraneliftGlobalValueDef {
129    /// A symbol external to the module.
130    Symbol { name: String, colocated: bool },
131    /// The value of another global value plus an offset.
132    IAddImm { base: u32, offset: i64 },
133    /// Loaded from memory (for GOT entries, etc.).
134    Load {
135        base: u32,
136        offset: i32,
137        global_type: CraneliftType,
138        readonly: bool,
139    },
140}
141/// Fluent builder for constructing CraneliftModule objects.
142#[derive(Debug)]
143#[allow(dead_code)]
144pub struct CraneliftModuleBuilder {
145    pub(super) module: CraneliftModule,
146}
147impl CraneliftModuleBuilder {
148    /// Start building a new module.
149    #[allow(dead_code)]
150    pub fn new(name: impl Into<String>) -> Self {
151        CraneliftModuleBuilder {
152            module: CraneliftModule::new(name),
153        }
154    }
155    /// Set the target triple.
156    #[allow(dead_code)]
157    pub fn target(mut self, triple: impl Into<String>) -> Self {
158        self.module.target = triple.into();
159        self
160    }
161    /// Declare an external function.
162    #[allow(dead_code)]
163    pub fn extern_func(mut self, name: impl Into<String>, sig: Signature) -> Self {
164        self.module.add_func_decl(name, sig);
165        self
166    }
167    /// Add a data object.
168    #[allow(dead_code)]
169    pub fn data(mut self, obj: CraneliftDataObject) -> Self {
170        self.module.add_data_object(obj);
171        self
172    }
173    /// Add a function definition.
174    #[allow(dead_code)]
175    pub fn func(mut self, f: CraneliftFunction) -> Self {
176        self.module.add_function(f);
177        self
178    }
179    /// Consume and return the completed module.
180    #[allow(dead_code)]
181    pub fn build(self) -> CraneliftModule {
182        self.module
183    }
184}
185/// Fluent builder for constructing CraneliftFunction objects.
186#[derive(Debug)]
187#[allow(dead_code)]
188pub struct CraneliftFunctionBuilder {
189    pub(super) func: CraneliftFunction,
190    pub(super) current_block: Option<u32>,
191}
192impl CraneliftFunctionBuilder {
193    /// Create a new builder for the named function with given signature.
194    #[allow(dead_code)]
195    pub fn new(name: impl Into<String>, sig: Signature) -> Self {
196        let func = CraneliftFunction::new(name, sig);
197        CraneliftFunctionBuilder {
198            func,
199            current_block: None,
200        }
201    }
202    /// Create an entry block and set it as current.
203    #[allow(dead_code)]
204    pub fn create_entry_block(mut self) -> Self {
205        let b = self.func.new_block();
206        self.current_block = Some(b);
207        self
208    }
209    /// Create a new block and set it as current.
210    #[allow(dead_code)]
211    pub fn create_block(mut self) -> (Self, u32) {
212        let b = self.func.new_block();
213        self.current_block = Some(b);
214        (self, b)
215    }
216    /// Switch to an existing block.
217    #[allow(dead_code)]
218    pub fn switch_to_block(mut self, block: u32) -> Self {
219        self.current_block = Some(block);
220        self
221    }
222    /// Emit a value-producing instruction in the current block.
223    #[allow(dead_code)]
224    pub fn ins_result(
225        mut self,
226        ty: CraneliftType,
227        instr: CraneliftInstr,
228    ) -> (Self, CraneliftValue) {
229        let val = self.func.fresh_value(ty);
230        if let Some(b_idx) = self.current_block {
231            if let Some(b) = self.func.block_mut(b_idx) {
232                b.push_with_result(val.clone(), instr);
233            }
234        }
235        (self, val)
236    }
237    /// Emit a void (side-effecting) instruction in the current block.
238    #[allow(dead_code)]
239    pub fn ins_void(mut self, instr: CraneliftInstr) -> Self {
240        if let Some(b_idx) = self.current_block {
241            if let Some(b) = self.func.block_mut(b_idx) {
242                b.push_void(instr);
243            }
244        }
245        self
246    }
247    /// Add a block parameter to the current block.
248    #[allow(dead_code)]
249    pub fn block_param(mut self, ty: CraneliftType) -> (Self, CraneliftValue) {
250        let val = self.func.fresh_value(ty);
251        if let Some(b_idx) = self.current_block {
252            if let Some(b) = self.func.block_mut(b_idx) {
253                b.params.push(val.clone());
254            }
255        }
256        (self, val)
257    }
258    /// Consume the builder and return the completed function.
259    #[allow(dead_code)]
260    pub fn finish(self) -> CraneliftFunction {
261        self.func
262    }
263}
264/// Cranelift IR type representation.
265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
266pub enum CraneliftType {
267    /// 1-bit boolean / integer
268    B1,
269    /// 8-bit integer
270    I8,
271    /// 16-bit integer
272    I16,
273    /// 32-bit integer
274    I32,
275    /// 64-bit integer
276    I64,
277    /// 128-bit integer
278    I128,
279    /// 32-bit float (IEEE 754 single-precision)
280    F32,
281    /// 64-bit float (IEEE 754 double-precision)
282    F64,
283    /// 32-bit reference (GC-managed pointer)
284    R32,
285    /// 64-bit reference (GC-managed pointer)
286    R64,
287    /// SIMD vector: `i32x4`, `f64x2`, etc.
288    Vector(Box<CraneliftType>, u32),
289    /// No type (used for void results / side-effecting instructions)
290    Void,
291}
292impl CraneliftType {
293    /// Return the byte width of this type (None for non-scalar or void).
294    pub fn byte_width(&self) -> Option<u32> {
295        match self {
296            CraneliftType::B1 => Some(1),
297            CraneliftType::I8 => Some(1),
298            CraneliftType::I16 => Some(2),
299            CraneliftType::I32 => Some(4),
300            CraneliftType::I64 => Some(8),
301            CraneliftType::I128 => Some(16),
302            CraneliftType::F32 => Some(4),
303            CraneliftType::F64 => Some(8),
304            CraneliftType::R32 => Some(4),
305            CraneliftType::R64 => Some(8),
306            CraneliftType::Vector(base, lanes) => base.byte_width().map(|w| w * lanes),
307            CraneliftType::Void => None,
308        }
309    }
310    /// Return true if this is an integer type.
311    pub fn is_int(&self) -> bool {
312        matches!(
313            self,
314            CraneliftType::I8
315                | CraneliftType::I16
316                | CraneliftType::I32
317                | CraneliftType::I64
318                | CraneliftType::I128
319                | CraneliftType::B1
320        )
321    }
322    /// Return true if this is a floating-point type.
323    pub fn is_float(&self) -> bool {
324        matches!(self, CraneliftType::F32 | CraneliftType::F64)
325    }
326}
327/// A basic block in Cranelift IR.
328#[derive(Debug, Clone, PartialEq)]
329pub struct CraneliftBlock {
330    /// Block ID (e.g. block0, block1)
331    pub id: u32,
332    /// Block parameters (like phi nodes in SSA form — Cranelift uses explicit params)
333    pub params: Vec<CraneliftValue>,
334    /// Instructions in this block
335    pub instrs: Vec<CraneliftInstResult>,
336}
337impl CraneliftBlock {
338    /// Create a new block.
339    pub fn new(id: u32) -> Self {
340        CraneliftBlock {
341            id,
342            params: vec![],
343            instrs: vec![],
344        }
345    }
346    /// Create a block with parameters.
347    pub fn with_params(id: u32, params: Vec<CraneliftValue>) -> Self {
348        CraneliftBlock {
349            id,
350            params,
351            instrs: vec![],
352        }
353    }
354    /// Return the block reference for this block.
355    pub fn block_ref(&self) -> BlockRef {
356        BlockRef::new(self.id)
357    }
358    /// Append an instruction with a result value.
359    pub fn push_with_result(&mut self, result: CraneliftValue, instr: CraneliftInstr) {
360        self.instrs
361            .push(CraneliftInstResult::with_result(result, instr));
362    }
363    /// Append a void instruction.
364    pub fn push_void(&mut self, instr: CraneliftInstr) {
365        self.instrs.push(CraneliftInstResult::no_result(instr));
366    }
367    /// Return true if this block ends with a terminator instruction.
368    pub fn is_terminated(&self) -> bool {
369        self.instrs.last().is_some_and(|ir| {
370            matches!(
371                ir.instr,
372                CraneliftInstr::Jump(_, _)
373                    | CraneliftInstr::Brif(_, _, _, _, _)
374                    | CraneliftInstr::BrTable(_, _, _)
375                    | CraneliftInstr::Return(_)
376                    | CraneliftInstr::Trap(_)
377                    | CraneliftInstr::Unreachable
378                    | CraneliftInstr::ReturnCall(_, _)
379            )
380        })
381    }
382    /// Emit this block as textual IR.
383    pub fn emit(&self) -> String {
384        let mut s = String::new();
385        if self.params.is_empty() {
386            s.push_str(&format!("block{}:\n", self.id));
387        } else {
388            let params = self
389                .params
390                .iter()
391                .map(|v| format!("{}: {}", v, v.ty))
392                .collect::<Vec<_>>()
393                .join(", ");
394            s.push_str(&format!("block{}({}):\n", self.id, params));
395        }
396        for ir in &self.instrs {
397            s.push_str(&format!("    {}\n", ir.emit()));
398        }
399        s
400    }
401}
402/// Helpers for recognizing common Cranelift instruction patterns.
403#[allow(dead_code)]
404pub struct CraneliftInstPattern;
405impl CraneliftInstPattern {
406    /// Return true if `instr` is a pure arithmetic (no side effects, no memory) instruction.
407    #[allow(dead_code)]
408    pub fn is_pure_arith(instr: &CraneliftInstr) -> bool {
409        matches!(
410            instr,
411            CraneliftInstr::Iconst(..)
412                | CraneliftInstr::F32Const(..)
413                | CraneliftInstr::F64Const(..)
414                | CraneliftInstr::Iadd(..)
415                | CraneliftInstr::Isub(..)
416                | CraneliftInstr::Imul(..)
417                | CraneliftInstr::Sdiv(..)
418                | CraneliftInstr::Udiv(..)
419                | CraneliftInstr::Srem(..)
420                | CraneliftInstr::Urem(..)
421                | CraneliftInstr::Ineg(..)
422                | CraneliftInstr::Iabs(..)
423                | CraneliftInstr::IaddImm(..)
424                | CraneliftInstr::ImulImm(..)
425                | CraneliftInstr::Band(..)
426                | CraneliftInstr::Bor(..)
427                | CraneliftInstr::Bxor(..)
428                | CraneliftInstr::Bnot(..)
429                | CraneliftInstr::Ishl(..)
430                | CraneliftInstr::Sshr(..)
431                | CraneliftInstr::Ushr(..)
432                | CraneliftInstr::Rotl(..)
433                | CraneliftInstr::Rotr(..)
434                | CraneliftInstr::Clz(..)
435                | CraneliftInstr::Ctz(..)
436                | CraneliftInstr::Popcnt(..)
437                | CraneliftInstr::Fadd(..)
438                | CraneliftInstr::Fsub(..)
439                | CraneliftInstr::Fmul(..)
440                | CraneliftInstr::Fdiv(..)
441                | CraneliftInstr::Fneg(..)
442                | CraneliftInstr::Fabs(..)
443                | CraneliftInstr::Sqrt(..)
444                | CraneliftInstr::Ceil(..)
445                | CraneliftInstr::Floor(..)
446                | CraneliftInstr::FTrunc(..)
447                | CraneliftInstr::Nearest(..)
448                | CraneliftInstr::Fmin(..)
449                | CraneliftInstr::Fmax(..)
450                | CraneliftInstr::Icmp(..)
451                | CraneliftInstr::Fcmp(..)
452        )
453    }
454    /// Return true if `instr` is a terminator (ends a block).
455    #[allow(dead_code)]
456    pub fn is_terminator(instr: &CraneliftInstr) -> bool {
457        matches!(
458            instr,
459            CraneliftInstr::Return(..)
460                | CraneliftInstr::Jump(..)
461                | CraneliftInstr::Brif(..)
462                | CraneliftInstr::BrTable(..)
463                | CraneliftInstr::Trap(..)
464        )
465    }
466    /// Return true if `instr` has side effects (memory or control flow).
467    #[allow(dead_code)]
468    pub fn has_side_effects(instr: &CraneliftInstr) -> bool {
469        matches!(
470            instr,
471            CraneliftInstr::Store(..)
472                | CraneliftInstr::Return(..)
473                | CraneliftInstr::Jump(..)
474                | CraneliftInstr::Brif(..)
475                | CraneliftInstr::BrTable(..)
476                | CraneliftInstr::Trap(..)
477                | CraneliftInstr::Call(..)
478        )
479    }
480    /// Try to extract the constant value from an `Iconst` instruction.
481    #[allow(dead_code)]
482    pub fn iconst_value(instr: &CraneliftInstr) -> Option<i64> {
483        match instr {
484            CraneliftInstr::Iconst(_, n) => Some(*n),
485            _ => None,
486        }
487    }
488}
489/// Cranelift IR code generation backend.
490pub struct CraneliftBackend {
491    /// The module being built
492    pub module: CraneliftModule,
493    /// Current function being constructed (if any)
494    pub(super) current_func: Option<CraneliftFunction>,
495    /// Current block id being populated (if any)
496    pub(super) current_block: Option<u32>,
497}
498impl CraneliftBackend {
499    /// Create a new Cranelift backend.
500    pub fn new(module_name: impl Into<String>) -> Self {
501        CraneliftBackend {
502            module: CraneliftModule::new(module_name),
503            current_func: None,
504            current_block: None,
505        }
506    }
507    /// Start building a new function.
508    pub fn begin_function(&mut self, name: impl Into<String>, sig: Signature) {
509        let mut func = CraneliftFunction::new(name, sig);
510        let entry_id = func.new_block();
511        for ty in func.sig.params.clone() {
512            let v = func.fresh_value(ty.clone());
513            if let Some(block) = func.blocks.iter_mut().find(|b| b.id == entry_id) {
514                block.params.push(v);
515            }
516        }
517        self.current_func = Some(func);
518        self.current_block = Some(entry_id);
519    }
520    /// End the current function and add it to the module.
521    pub fn end_function(&mut self) {
522        if let Some(func) = self.current_func.take() {
523            self.module.add_function(func);
524        }
525        self.current_block = None;
526    }
527    /// Switch to an existing block.
528    pub fn switch_to_block(&mut self, block_id: u32) {
529        self.current_block = Some(block_id);
530    }
531    /// Allocate a fresh SSA value in the current function.
532    pub fn fresh_value(&mut self, ty: CraneliftType) -> Option<CraneliftValue> {
533        self.current_func.as_mut().map(|f| f.fresh_value(ty))
534    }
535    /// Create a new block in the current function.
536    pub fn new_block(&mut self) -> Option<u32> {
537        self.current_func.as_mut().map(|f| f.new_block())
538    }
539    /// Emit an instruction with a result into the current block.
540    pub fn emit_with_result(
541        &mut self,
542        ty: CraneliftType,
543        instr: CraneliftInstr,
544    ) -> Option<CraneliftValue> {
545        let v = self.fresh_value(ty)?;
546        let block_id = self.current_block?;
547        let func = self.current_func.as_mut()?;
548        if let Some(block) = func.block_mut(block_id) {
549            block.push_with_result(v.clone(), instr);
550        }
551        Some(v)
552    }
553    /// Emit a void instruction into the current block.
554    pub fn emit_void(&mut self, instr: CraneliftInstr) {
555        let block_id = match self.current_block {
556            Some(id) => id,
557            None => return,
558        };
559        if let Some(func) = self.current_func.as_mut() {
560            if let Some(block) = func.block_mut(block_id) {
561                block.push_void(instr);
562            }
563        }
564    }
565    /// Emit an `iconst` instruction.
566    pub fn iconst(&mut self, ty: CraneliftType, val: i64) -> Option<CraneliftValue> {
567        self.emit_with_result(ty.clone(), CraneliftInstr::Iconst(ty, val))
568    }
569    /// Emit an `iadd` instruction.
570    pub fn iadd(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
571        let ty = a.ty.clone();
572        self.emit_with_result(ty, CraneliftInstr::Iadd(a, b))
573    }
574    /// Emit an `isub` instruction.
575    pub fn isub(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
576        let ty = a.ty.clone();
577        self.emit_with_result(ty, CraneliftInstr::Isub(a, b))
578    }
579    /// Emit an `imul` instruction.
580    pub fn imul(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
581        let ty = a.ty.clone();
582        self.emit_with_result(ty, CraneliftInstr::Imul(a, b))
583    }
584    /// Emit an `sdiv` instruction.
585    pub fn sdiv(&mut self, a: CraneliftValue, b: CraneliftValue) -> Option<CraneliftValue> {
586        let ty = a.ty.clone();
587        self.emit_with_result(ty, CraneliftInstr::Sdiv(a, b))
588    }
589    /// Emit an `icmp` instruction.
590    pub fn icmp(
591        &mut self,
592        cc: IntCC,
593        a: CraneliftValue,
594        b: CraneliftValue,
595    ) -> Option<CraneliftValue> {
596        self.emit_with_result(CraneliftType::B1, CraneliftInstr::Icmp(cc, a, b))
597    }
598    /// Emit an `fcmp` instruction.
599    pub fn fcmp(
600        &mut self,
601        cc: FloatCC,
602        a: CraneliftValue,
603        b: CraneliftValue,
604    ) -> Option<CraneliftValue> {
605        self.emit_with_result(CraneliftType::B1, CraneliftInstr::Fcmp(cc, a, b))
606    }
607    /// Emit a `load` instruction.
608    pub fn load(
609        &mut self,
610        ty: CraneliftType,
611        flags: MemFlags,
612        addr: CraneliftValue,
613        offset: i32,
614    ) -> Option<CraneliftValue> {
615        self.emit_with_result(ty.clone(), CraneliftInstr::Load(ty, flags, addr, offset))
616    }
617    /// Emit a `store` instruction.
618    pub fn store(
619        &mut self,
620        flags: MemFlags,
621        val: CraneliftValue,
622        addr: CraneliftValue,
623        offset: i32,
624    ) {
625        self.emit_void(CraneliftInstr::Store(flags, val, addr, offset));
626    }
627    /// Emit a `call` instruction returning a single value.
628    pub fn call_single(
629        &mut self,
630        ret_ty: CraneliftType,
631        func: impl Into<String>,
632        args: Vec<CraneliftValue>,
633    ) -> Option<CraneliftValue> {
634        self.emit_with_result(ret_ty, CraneliftInstr::Call(func.into(), args))
635    }
636    /// Emit a `jump` terminator.
637    pub fn jump(&mut self, target: BlockRef, args: Vec<CraneliftValue>) {
638        self.emit_void(CraneliftInstr::Jump(target, args));
639    }
640    /// Emit a `brif` terminator.
641    pub fn brif(
642        &mut self,
643        cond: CraneliftValue,
644        t: BlockRef,
645        t_args: Vec<CraneliftValue>,
646        f: BlockRef,
647        f_args: Vec<CraneliftValue>,
648    ) {
649        self.emit_void(CraneliftInstr::Brif(cond, t, t_args, f, f_args));
650    }
651    /// Emit a `return` terminator.
652    pub fn emit_return(&mut self, vals: Vec<CraneliftValue>) {
653        self.emit_void(CraneliftInstr::Return(vals));
654    }
655    /// Emit the full module as textual IR.
656    pub fn emit_module(&self) -> String {
657        self.module.emit()
658    }
659}
660/// Stack slot allocator for a function.
661#[derive(Debug, Default)]
662#[allow(dead_code)]
663pub struct CraneliftStackAllocator {
664    pub(super) slots: Vec<CraneliftStackSlot>,
665    pub(super) next_id: u32,
666    pub(super) frame_size: u32,
667}
668impl CraneliftStackAllocator {
669    /// Create a new stack allocator.
670    #[allow(dead_code)]
671    pub fn new() -> Self {
672        CraneliftStackAllocator::default()
673    }
674    /// Allocate a new stack slot with the given size and alignment.
675    #[allow(dead_code)]
676    pub fn alloc(&mut self, size: u32, align: u32) -> &CraneliftStackSlot {
677        let aligned = (self.frame_size + align - 1) & !(align - 1);
678        self.frame_size = aligned + size;
679        let slot = CraneliftStackSlot::new(self.next_id, size, align);
680        self.next_id += 1;
681        self.slots.push(slot);
682        self.slots
683            .last()
684            .expect("slots is non-empty after push; invariant guaranteed by alloc")
685    }
686    /// Allocate a named stack slot.
687    #[allow(dead_code)]
688    pub fn alloc_named(
689        &mut self,
690        size: u32,
691        align: u32,
692        name: impl Into<String>,
693    ) -> &CraneliftStackSlot {
694        let aligned = (self.frame_size + align - 1) & !(align - 1);
695        self.frame_size = aligned + size;
696        let slot = CraneliftStackSlot::named(self.next_id, size, align, name);
697        self.next_id += 1;
698        self.slots.push(slot);
699        self.slots
700            .last()
701            .expect("slots is non-empty after push; invariant guaranteed by alloc_named")
702    }
703    /// Return all allocated slots.
704    #[allow(dead_code)]
705    pub fn slots(&self) -> &[CraneliftStackSlot] {
706        &self.slots
707    }
708    /// Return the total frame size.
709    #[allow(dead_code)]
710    pub fn frame_size(&self) -> u32 {
711        self.frame_size
712    }
713    /// Emit all slot declarations.
714    #[allow(dead_code)]
715    pub fn emit_decls(&self) -> String {
716        self.slots
717            .iter()
718            .map(|s| s.emit())
719            .collect::<Vec<_>>()
720            .join("\n")
721    }
722}
723/// A data object in the Cranelift module (global variable / constant).
724#[derive(Debug, Clone, PartialEq)]
725pub struct CraneliftDataObject {
726    /// Symbol name
727    pub name: String,
728    /// Whether the data is read-only
729    pub is_readonly: bool,
730    /// Data contents (raw bytes)
731    pub data: Vec<u8>,
732    /// Alignment in bytes
733    pub align: u32,
734}
735impl CraneliftDataObject {
736    /// Create a new read-only data object.
737    pub fn readonly(name: impl Into<String>, data: Vec<u8>, align: u32) -> Self {
738        CraneliftDataObject {
739            name: name.into(),
740            is_readonly: true,
741            data,
742            align,
743        }
744    }
745    /// Create a writable data object.
746    pub fn writable(name: impl Into<String>, data: Vec<u8>, align: u32) -> Self {
747        CraneliftDataObject {
748            name: name.into(),
749            is_readonly: false,
750            data,
751            align,
752        }
753    }
754    /// Emit this data object as textual IR.
755    pub fn emit(&self) -> String {
756        let rw = if self.is_readonly { "rodata" } else { "data" };
757        let hex: String = self.data.iter().map(|b| format!("\\{:02x}", b)).collect();
758        format!(
759            "{} %{} align={} {{\n    ascii \"{}\"\n}}\n",
760            rw, self.name, self.align, hex
761        )
762    }
763}
764/// ABI parameter classification.
765#[derive(Debug, Clone, PartialEq, Eq)]
766#[allow(dead_code)]
767pub enum CraneliftABIClass {
768    /// Passed in integer register.
769    Integer,
770    /// Passed in floating-point register.
771    Float,
772    /// Passed in SSE register (packed integers).
773    SSE,
774    /// Passed on the stack.
775    Memory,
776    /// Not passed (zero-size or erased).
777    NoValue,
778}
779/// ABI layout for a function parameter or return value.
780#[derive(Debug, Clone)]
781#[allow(dead_code)]
782pub struct CraneliftABIParam {
783    /// The IR type.
784    pub ty: CraneliftType,
785    /// How this parameter is classified.
786    pub class: CraneliftABIClass,
787    /// Stack offset (if passed on stack), or register index.
788    pub location: i32,
789}
790impl CraneliftABIParam {
791    /// Create a new ABI parameter.
792    #[allow(dead_code)]
793    pub fn new(ty: CraneliftType, class: CraneliftABIClass, location: i32) -> Self {
794        CraneliftABIParam {
795            ty,
796            class,
797            location,
798        }
799    }
800    /// Return true if this parameter is register-allocated.
801    #[allow(dead_code)]
802    pub fn is_register(&self) -> bool {
803        !matches!(
804            self.class,
805            CraneliftABIClass::Memory | CraneliftABIClass::NoValue
806        )
807    }
808}
809/// Which optimization passes to run on Cranelift IR.
810#[derive(Debug, Clone)]
811#[allow(dead_code)]
812pub struct CraneliftPassConfig {
813    /// Enable constant folding.
814    pub const_folding: bool,
815    /// Enable dead code elimination.
816    pub dce: bool,
817    /// Enable instruction combining (e.g., add + mul → madd).
818    pub inst_combine: bool,
819    /// Enable branch optimization.
820    pub branch_opt: bool,
821    /// Enable loop-invariant code motion.
822    pub licm: bool,
823    /// Enable register coalescing.
824    pub reg_coalescing: bool,
825    /// Enable redundant load elimination.
826    pub load_elim: bool,
827    /// Enable tail call optimization.
828    pub tail_call_opt: bool,
829    /// Maximum inlining depth.
830    pub inline_depth: u32,
831    /// Whether to emit debug information.
832    pub debug_info: bool,
833}
834impl CraneliftPassConfig {
835    /// Return a no-optimization configuration.
836    #[allow(dead_code)]
837    pub fn no_opt() -> Self {
838        CraneliftPassConfig {
839            const_folding: false,
840            dce: false,
841            inst_combine: false,
842            branch_opt: false,
843            licm: false,
844            reg_coalescing: false,
845            load_elim: false,
846            tail_call_opt: false,
847            inline_depth: 0,
848            debug_info: false,
849        }
850    }
851    /// Return a maximum optimization configuration.
852    #[allow(dead_code)]
853    pub fn max_opt() -> Self {
854        CraneliftPassConfig {
855            const_folding: true,
856            dce: true,
857            inst_combine: true,
858            branch_opt: true,
859            licm: true,
860            reg_coalescing: true,
861            load_elim: true,
862            tail_call_opt: true,
863            inline_depth: 10,
864            debug_info: false,
865        }
866    }
867}
868/// A block reference — corresponds to `block0`, `block1`, etc.
869#[derive(Debug, Clone, PartialEq, Eq, Hash)]
870pub struct BlockRef {
871    /// Numeric ID for this block
872    pub id: u32,
873}
874impl BlockRef {
875    /// Create a new block reference.
876    pub fn new(id: u32) -> Self {
877        BlockRef { id }
878    }
879}
880/// Memory access flags for load/store instructions.
881#[derive(Debug, Clone, PartialEq, Eq)]
882pub struct MemFlags {
883    /// True if the access is aligned (UB if not)
884    pub aligned: bool,
885    /// True if the access is volatile (not reordered)
886    pub notrap: bool,
887    /// True if the access does not alias any other access
888    pub readonly: bool,
889}
890impl MemFlags {
891    /// Create default (safe) memory flags.
892    pub fn new() -> Self {
893        MemFlags {
894            aligned: false,
895            notrap: false,
896            readonly: false,
897        }
898    }
899    /// Create trusted (notrap) memory flags.
900    pub fn trusted() -> Self {
901        MemFlags {
902            aligned: false,
903            notrap: true,
904            readonly: false,
905        }
906    }
907    /// Create aligned, notrap flags.
908    pub fn aligned_notrap() -> Self {
909        MemFlags {
910            aligned: true,
911            notrap: true,
912            readonly: false,
913        }
914    }
915}
916/// Known calling conventions for Cranelift.
917#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
918#[allow(dead_code)]
919pub enum CraneliftCallingConvention {
920    /// System V AMD64 ABI (Linux, macOS x86-64).
921    SystemV,
922    /// Windows x64 calling convention.
923    WindowsFastcall,
924    /// Wasmtime calling convention (WebAssembly).
925    WasmtimeSystem,
926    /// Cold (rarely-called) function convention.
927    Cold,
928    /// Tail-call optimized convention.
929    Tail,
930    /// Fast (internal) convention (no caller-saves).
931    Fast,
932}
933/// Debug information attached to a Cranelift function.
934#[derive(Debug, Clone, Default)]
935#[allow(dead_code)]
936pub struct CraneliftDebugInfo {
937    /// Source file name.
938    pub source_file: Option<String>,
939    /// Source function name (may differ from IR name).
940    pub source_function: Option<String>,
941    /// Mapping from instruction offset to (line, column) in source.
942    pub location_map: Vec<(usize, u32, u32)>,
943    /// Local variable names: (ir_value, source_name).
944    pub var_names: HashMap<String, String>,
945}
946impl CraneliftDebugInfo {
947    /// Create a new debug info record.
948    #[allow(dead_code)]
949    pub fn new(source_file: impl Into<String>, source_function: impl Into<String>) -> Self {
950        CraneliftDebugInfo {
951            source_file: Some(source_file.into()),
952            source_function: Some(source_function.into()),
953            location_map: Vec::new(),
954            var_names: HashMap::new(),
955        }
956    }
957    /// Record a source location for an instruction.
958    #[allow(dead_code)]
959    pub fn add_location(&mut self, offset: usize, line: u32, column: u32) {
960        self.location_map.push((offset, line, column));
961    }
962    /// Record a variable name mapping.
963    #[allow(dead_code)]
964    pub fn add_var_name(&mut self, ir_name: impl Into<String>, source_name: impl Into<String>) {
965        self.var_names.insert(ir_name.into(), source_name.into());
966    }
967    /// Emit debug info as comments.
968    #[allow(dead_code)]
969    pub fn emit_comments(&self) -> String {
970        let mut out = String::new();
971        if let Some(ref f) = self.source_file {
972            out.push_str(&format!("; source_file: {}\n", f));
973        }
974        if let Some(ref f) = self.source_function {
975            out.push_str(&format!("; source_function: {}\n", f));
976        }
977        for (offset, line, col) in &self.location_map {
978            out.push_str(&format!("; @{}: {}:{}\n", offset, line, col));
979        }
980        for (ir, src) in &self.var_names {
981            out.push_str(&format!("; var {} => {}\n", ir, src));
982        }
983        out
984    }
985}
986/// A Cranelift global value declaration.
987#[derive(Debug, Clone)]
988#[allow(dead_code)]
989pub struct CraneliftGlobalValue {
990    /// Global value ID.
991    pub id: u32,
992    /// The global value type.
993    pub ty: CraneliftType,
994    /// How the value is obtained.
995    pub def: CraneliftGlobalValueDef,
996}
997impl CraneliftGlobalValue {
998    /// Create a symbol global value.
999    #[allow(dead_code)]
1000    pub fn symbol(id: u32, name: impl Into<String>, colocated: bool) -> Self {
1001        CraneliftGlobalValue {
1002            id,
1003            ty: CraneliftType::I64,
1004            def: CraneliftGlobalValueDef::Symbol {
1005                name: name.into(),
1006                colocated,
1007            },
1008        }
1009    }
1010    /// Emit the global value declaration.
1011    #[allow(dead_code)]
1012    pub fn emit(&self) -> String {
1013        match &self.def {
1014            CraneliftGlobalValueDef::Symbol { name, colocated } => {
1015                format!(
1016                    "gv{} = symbol {}{}",
1017                    self.id,
1018                    if *colocated { "colocated " } else { "" },
1019                    name
1020                )
1021            }
1022            CraneliftGlobalValueDef::IAddImm { base, offset } => {
1023                format!("gv{} = iadd_imm gv{}, {}", self.id, base, offset)
1024            }
1025            CraneliftGlobalValueDef::Load {
1026                base,
1027                offset,
1028                global_type,
1029                readonly,
1030            } => {
1031                format!(
1032                    "gv{} = load.{} {}[{}]{}",
1033                    self.id,
1034                    global_type,
1035                    base,
1036                    offset,
1037                    if *readonly { " readonly" } else { "" }
1038                )
1039            }
1040        }
1041    }
1042}
1043/// WebAssembly-style heap (linear memory) configuration for Cranelift.
1044#[derive(Debug, Clone)]
1045#[allow(dead_code)]
1046pub struct CraneliftHeapConfig {
1047    /// Base global value (pointer to start of heap).
1048    pub base: u32,
1049    /// Minimum heap size in bytes.
1050    pub min_size: u64,
1051    /// Maximum heap size (None = unlimited).
1052    pub max_size: Option<u64>,
1053    /// Page size (typically 65536 for Wasm).
1054    pub page_size: u64,
1055    /// Whether bounds checking is needed.
1056    pub needs_bounds_check: bool,
1057    /// Guard size in bytes (0 = no guard pages).
1058    pub guard_size: u64,
1059}
1060impl CraneliftHeapConfig {
1061    /// Create a 4 GiB static heap (no guard needed in 64-bit mode).
1062    #[allow(dead_code)]
1063    pub fn static_4gib() -> Self {
1064        CraneliftHeapConfig {
1065            min_size: 65536,
1066            max_size: Some(4 * 1024 * 1024 * 1024),
1067            guard_size: 2 * 1024 * 1024 * 1024,
1068            needs_bounds_check: false,
1069            ..Default::default()
1070        }
1071    }
1072    /// Emit a comment describing the heap configuration.
1073    #[allow(dead_code)]
1074    pub fn emit_comment(&self) -> String {
1075        format!(
1076            "; heap base=gv{} min={} max={} page={} guard={} bounds_check={}",
1077            self.base,
1078            self.min_size,
1079            self.max_size
1080                .map(|m| m.to_string())
1081                .unwrap_or_else(|| "unlimited".to_string()),
1082            self.page_size,
1083            self.guard_size,
1084            self.needs_bounds_check,
1085        )
1086    }
1087}
1088/// A stack slot in a Cranelift function frame.
1089#[derive(Debug, Clone)]
1090#[allow(dead_code)]
1091pub struct CraneliftStackSlot {
1092    /// Slot identifier.
1093    pub id: u32,
1094    /// Size in bytes.
1095    pub size: u32,
1096    /// Alignment in bytes.
1097    pub align: u32,
1098    /// Optional debug name.
1099    pub name: Option<String>,
1100}
1101impl CraneliftStackSlot {
1102    /// Create a new stack slot.
1103    #[allow(dead_code)]
1104    pub fn new(id: u32, size: u32, align: u32) -> Self {
1105        CraneliftStackSlot {
1106            id,
1107            size,
1108            align,
1109            name: None,
1110        }
1111    }
1112    /// Create a named stack slot.
1113    #[allow(dead_code)]
1114    pub fn named(id: u32, size: u32, align: u32, name: impl Into<String>) -> Self {
1115        CraneliftStackSlot {
1116            id,
1117            size,
1118            align,
1119            name: Some(name.into()),
1120        }
1121    }
1122    /// Emit the stack slot declaration.
1123    #[allow(dead_code)]
1124    pub fn emit(&self) -> String {
1125        let name_comment = self
1126            .name
1127            .as_ref()
1128            .map(|n| format!(" ; {}", n))
1129            .unwrap_or_default();
1130        format!(
1131            "ss{} = explicit_slot {}, align = {}{}",
1132            self.id, self.size, self.align, name_comment
1133        )
1134    }
1135    /// Generate a `stack_addr` expression for this slot at the given offset.
1136    #[allow(dead_code)]
1137    pub fn addr_expr(&self, offset: i32) -> String {
1138        format!("stack_addr.i64 ss{}, {}", self.id, offset)
1139    }
1140}
1141/// A Cranelift IR instruction.
1142#[derive(Debug, Clone, PartialEq)]
1143pub enum CraneliftInstr {
1144    /// Integer constant: `iconst.i64 42`
1145    Iconst(CraneliftType, i64),
1146    /// Boolean constant: `bconst.b1 true`
1147    Bconst(bool),
1148    /// 32-bit float constant: `f32const 3.14`
1149    F32Const(f32),
1150    /// 64-bit float constant: `f64const 3.14`
1151    F64Const(f64),
1152    /// Add: `iadd v1, v2`
1153    Iadd(CraneliftValue, CraneliftValue),
1154    /// Subtract: `isub v1, v2`
1155    Isub(CraneliftValue, CraneliftValue),
1156    /// Multiply: `imul v1, v2`
1157    Imul(CraneliftValue, CraneliftValue),
1158    /// Signed divide: `sdiv v1, v2`
1159    Sdiv(CraneliftValue, CraneliftValue),
1160    /// Unsigned divide: `udiv v1, v2`
1161    Udiv(CraneliftValue, CraneliftValue),
1162    /// Signed remainder: `srem v1, v2`
1163    Srem(CraneliftValue, CraneliftValue),
1164    /// Unsigned remainder: `urem v1, v2`
1165    Urem(CraneliftValue, CraneliftValue),
1166    /// Negate: `ineg v1`
1167    Ineg(CraneliftValue),
1168    /// Absolute value: `iabs v1`
1169    Iabs(CraneliftValue),
1170    /// Add with immediate: `iadd_imm v1, 5`
1171    IaddImm(CraneliftValue, i64),
1172    /// Multiply with immediate: `imul_imm v1, 5`
1173    ImulImm(CraneliftValue, i64),
1174    /// Bitwise AND: `band v1, v2`
1175    Band(CraneliftValue, CraneliftValue),
1176    /// Bitwise OR: `bor v1, v2`
1177    Bor(CraneliftValue, CraneliftValue),
1178    /// Bitwise XOR: `bxor v1, v2`
1179    Bxor(CraneliftValue, CraneliftValue),
1180    /// Bitwise NOT: `bnot v1`
1181    Bnot(CraneliftValue),
1182    /// Shift left: `ishl v1, v2`
1183    Ishl(CraneliftValue, CraneliftValue),
1184    /// Arithmetic shift right: `sshr v1, v2`
1185    Sshr(CraneliftValue, CraneliftValue),
1186    /// Logical shift right: `ushr v1, v2`
1187    Ushr(CraneliftValue, CraneliftValue),
1188    /// Rotate left: `rotl v1, v2`
1189    Rotl(CraneliftValue, CraneliftValue),
1190    /// Rotate right: `rotr v1, v2`
1191    Rotr(CraneliftValue, CraneliftValue),
1192    /// Count leading zeros: `clz v1`
1193    Clz(CraneliftValue),
1194    /// Count trailing zeros: `ctz v1`
1195    Ctz(CraneliftValue),
1196    /// Population count: `popcnt v1`
1197    Popcnt(CraneliftValue),
1198    /// Float add: `fadd v1, v2`
1199    Fadd(CraneliftValue, CraneliftValue),
1200    /// Float subtract: `fsub v1, v2`
1201    Fsub(CraneliftValue, CraneliftValue),
1202    /// Float multiply: `fmul v1, v2`
1203    Fmul(CraneliftValue, CraneliftValue),
1204    /// Float divide: `fdiv v1, v2`
1205    Fdiv(CraneliftValue, CraneliftValue),
1206    /// Float negate: `fneg v1`
1207    Fneg(CraneliftValue),
1208    /// Float absolute value: `fabs v1`
1209    Fabs(CraneliftValue),
1210    /// Float square root: `sqrt v1`
1211    Sqrt(CraneliftValue),
1212    /// Fused multiply-add: `fma v1, v2, v3`
1213    Fma(CraneliftValue, CraneliftValue, CraneliftValue),
1214    /// Float minimum: `fmin v1, v2`
1215    Fmin(CraneliftValue, CraneliftValue),
1216    /// Float maximum: `fmax v1, v2`
1217    Fmax(CraneliftValue, CraneliftValue),
1218    /// Float floor: `floor v1`
1219    Floor(CraneliftValue),
1220    /// Float ceiling: `ceil v1`
1221    Ceil(CraneliftValue),
1222    /// Float truncate toward zero: `trunc v1`
1223    FTrunc(CraneliftValue),
1224    /// Float round to nearest: `nearest v1`
1225    Nearest(CraneliftValue),
1226    /// Integer compare: `icmp eq v1, v2`
1227    Icmp(IntCC, CraneliftValue, CraneliftValue),
1228    /// Float compare: `fcmp lt v1, v2`
1229    Fcmp(FloatCC, CraneliftValue, CraneliftValue),
1230    /// Select: `select v_cond, v_true, v_false`
1231    Select(CraneliftValue, CraneliftValue, CraneliftValue),
1232    /// Sign-extend: `sextend.i64 v1`
1233    Sextend(CraneliftType, CraneliftValue),
1234    /// Zero-extend: `uextend.i64 v1`
1235    Uextend(CraneliftType, CraneliftValue),
1236    /// Truncate: `ireduce.i32 v1`
1237    Ireduce(CraneliftType, CraneliftValue),
1238    /// Float convert: `fpromote.f64 v1`
1239    Fpromote(CraneliftType, CraneliftValue),
1240    /// Float demote: `fdemote.f32 v1`
1241    Fdemote(CraneliftType, CraneliftValue),
1242    /// Float to int (trunc): `fcvt_to_sint.i64 v1`
1243    FcvtToSint(CraneliftType, CraneliftValue),
1244    /// Float to unsigned int (trunc): `fcvt_to_uint.i64 v1`
1245    FcvtToUint(CraneliftType, CraneliftValue),
1246    /// Signed int to float: `fcvt_from_sint.f64 v1`
1247    FcvtFromSint(CraneliftType, CraneliftValue),
1248    /// Unsigned int to float: `fcvt_from_uint.f64 v1`
1249    FcvtFromUint(CraneliftType, CraneliftValue),
1250    /// Bitcast: `bitcast.f64 v1`
1251    Bitcast(CraneliftType, CraneliftValue),
1252    /// Load: `load.i64 notrap aligned v_addr+offset`
1253    Load(CraneliftType, MemFlags, CraneliftValue, i32),
1254    /// Store: `store notrap aligned v_val, v_addr+offset`
1255    Store(MemFlags, CraneliftValue, CraneliftValue, i32),
1256    /// Stack slot address: `stack_addr.i64 ss0`
1257    StackAddr(CraneliftType, u32),
1258    /// Global value address: `global_value.i64 gv0`
1259    GlobalValue(CraneliftType, u32),
1260    /// Unconditional jump: `jump block1(v1, v2)`
1261    Jump(BlockRef, Vec<CraneliftValue>),
1262    /// Conditional branch: `brif v_cond, block1(args), block2(args)`
1263    Brif(
1264        CraneliftValue,
1265        BlockRef,
1266        Vec<CraneliftValue>,
1267        BlockRef,
1268        Vec<CraneliftValue>,
1269    ),
1270    /// Branch table (indirect jump): `br_table v, block_default, jt0`
1271    BrTable(CraneliftValue, BlockRef, Vec<BlockRef>),
1272    /// Return: `return v1, v2`
1273    Return(Vec<CraneliftValue>),
1274    /// Trap: `trap user1`
1275    Trap(String),
1276    /// Trap if condition: `trapif eq v1, user1`
1277    Trapif(IntCC, CraneliftValue, String),
1278    /// Unreachable trap
1279    Unreachable,
1280    /// Direct call: `call func(args)`
1281    Call(String, Vec<CraneliftValue>),
1282    /// Indirect call: `call_indirect sig0, v_callee(args)`
1283    CallIndirect(u32, CraneliftValue, Vec<CraneliftValue>),
1284    /// Return call (tail call): `return_call func(args)`
1285    ReturnCall(String, Vec<CraneliftValue>),
1286    /// Function argument: `func_addr.i64 func_name`
1287    FuncAddr(CraneliftType, String),
1288    /// Null reference constant: `null.r64`
1289    Null(CraneliftType),
1290    /// Vector splat: `splat.i32x4 v1`
1291    Splat(CraneliftType, CraneliftValue),
1292    /// Vector extract lane: `extractlane v1, 0`
1293    ExtractLane(CraneliftValue, u8),
1294    /// Vector insert lane: `insertlane v1, 0, v2`
1295    InsertLane(CraneliftValue, u8, CraneliftValue),
1296    /// Copy / identity: `copy v1` (used for renames)
1297    Copy(CraneliftValue),
1298    /// Nop
1299    Nop,
1300}
1301/// Float comparison condition codes for `fcmp`.
1302#[derive(Debug, Clone, PartialEq, Eq)]
1303pub enum FloatCC {
1304    /// Ordered and equal
1305    Equal,
1306    /// Ordered and not equal
1307    NotEqual,
1308    /// Ordered and less than
1309    LessThan,
1310    /// Ordered and less than or equal
1311    LessThanOrEqual,
1312    /// Ordered and greater than
1313    GreaterThan,
1314    /// Ordered and greater than or equal
1315    GreaterThanOrEqual,
1316    /// Ordered (neither is NaN)
1317    Ordered,
1318    /// Unordered (at least one is NaN)
1319    Unordered,
1320    /// Unordered or equal
1321    UnorderedOrEqual,
1322    /// Unordered or less than
1323    UnorderedOrLessThan,
1324    /// Unordered or greater than
1325    UnorderedOrGreaterThan,
1326}
1327/// Integer comparison condition codes for `icmp`.
1328#[derive(Debug, Clone, PartialEq, Eq)]
1329pub enum IntCC {
1330    /// Equal (`==`)
1331    Equal,
1332    /// Not equal (`!=`)
1333    NotEqual,
1334    /// Signed less than (`<`)
1335    SignedLessThan,
1336    /// Signed less than or equal (`<=`)
1337    SignedLessThanOrEqual,
1338    /// Signed greater than (`>`)
1339    SignedGreaterThan,
1340    /// Signed greater than or equal (`>=`)
1341    SignedGreaterThanOrEqual,
1342    /// Unsigned less than
1343    UnsignedLessThan,
1344    /// Unsigned less than or equal
1345    UnsignedLessThanOrEqual,
1346    /// Unsigned greater than
1347    UnsignedGreaterThan,
1348    /// Unsigned greater than or equal
1349    UnsignedGreaterThanOrEqual,
1350    /// Overflow: signed add overflows
1351    Overflow,
1352    /// No overflow
1353    NotOverflow,
1354}
1355/// An SSA value reference in Cranelift IR — corresponds to `v0`, `v1`, etc.
1356#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1357pub struct CraneliftValue {
1358    /// Numeric ID for this SSA value
1359    pub id: u32,
1360    /// The type of this value
1361    pub ty: CraneliftType,
1362}
1363impl CraneliftValue {
1364    /// Create a new SSA value.
1365    pub fn new(id: u32, ty: CraneliftType) -> Self {
1366        CraneliftValue { id, ty }
1367    }
1368}
1369/// Calling convention.
1370#[derive(Debug, Clone, PartialEq, Eq)]
1371pub enum CallConv {
1372    /// Fast calling convention (Cranelift internal)
1373    Fast,
1374    /// Cold calling convention (infrequently called)
1375    Cold,
1376    /// System V AMD64 ABI
1377    SystemV,
1378    /// Windows x64 ABI
1379    WindowsFastcall,
1380    /// WebAssembly calling convention
1381    WasmtimeSystemV,
1382}
1383/// Static metrics about a Cranelift function.
1384#[derive(Debug, Clone, Default)]
1385#[allow(dead_code)]
1386pub struct CraneliftCodeMetrics {
1387    /// Number of basic blocks.
1388    pub num_blocks: usize,
1389    /// Total number of instructions.
1390    pub total_instructions: usize,
1391    /// Number of value-producing instructions.
1392    pub num_value_instructions: usize,
1393    /// Number of void (side-effecting) instructions.
1394    pub num_void_instructions: usize,
1395    /// Number of block parameters across all blocks.
1396    pub total_block_params: usize,
1397    /// Number of call instructions.
1398    pub num_calls: usize,
1399    /// Number of load instructions.
1400    pub num_loads: usize,
1401    /// Number of store instructions.
1402    pub num_stores: usize,
1403    /// Number of branch instructions.
1404    pub num_branches: usize,
1405}
1406impl CraneliftCodeMetrics {
1407    /// Compute metrics for a function.
1408    #[allow(dead_code)]
1409    pub fn compute(func: &CraneliftFunction) -> Self {
1410        let mut m = CraneliftCodeMetrics {
1411            num_blocks: func.blocks.len(),
1412            ..Default::default()
1413        };
1414        for block in &func.blocks {
1415            m.total_block_params += block.params.len();
1416            for inst in &block.instrs {
1417                m.total_instructions += 1;
1418                if inst.result.is_some() {
1419                    m.num_value_instructions += 1;
1420                } else {
1421                    m.num_void_instructions += 1;
1422                }
1423                match &inst.instr {
1424                    CraneliftInstr::Call(..) => {
1425                        m.num_calls += 1;
1426                    }
1427                    CraneliftInstr::Load(..) => {
1428                        m.num_loads += 1;
1429                    }
1430                    CraneliftInstr::Store(..) => {
1431                        m.num_stores += 1;
1432                    }
1433                    CraneliftInstr::Brif(..)
1434                    | CraneliftInstr::BrTable(..)
1435                    | CraneliftInstr::Jump(..) => {
1436                        m.num_branches += 1;
1437                    }
1438                    _ => {}
1439                }
1440            }
1441        }
1442        m
1443    }
1444    /// Return a summary string.
1445    #[allow(dead_code)]
1446    pub fn summary(&self) -> String {
1447        format!(
1448            "blocks={} total_instrs={} values={} voids={} params={} calls={} loads={} stores={} branches={}",
1449            self.num_blocks, self.total_instructions, self.num_value_instructions, self
1450            .num_void_instructions, self.total_block_params, self.num_calls, self
1451            .num_loads, self.num_stores, self.num_branches,
1452        )
1453    }
1454}
1455/// An inline assembly fragment that can be embedded in a function.
1456#[derive(Debug, Clone)]
1457#[allow(dead_code)]
1458pub struct CraneliftInlineAsm {
1459    /// The assembly template string.
1460    pub template: String,
1461    /// Input operands: (constraint, value).
1462    pub inputs: Vec<(String, CraneliftValue)>,
1463    /// Output operands: (constraint, result_value).
1464    pub outputs: Vec<(String, CraneliftValue)>,
1465    /// Whether the assembly has side effects (prevents reordering).
1466    pub volatile: bool,
1467    /// Whether the assembly can trap.
1468    pub can_trap: bool,
1469}
1470impl CraneliftInlineAsm {
1471    /// Create a new inline assembly fragment.
1472    #[allow(dead_code)]
1473    pub fn new(template: impl Into<String>) -> Self {
1474        CraneliftInlineAsm {
1475            template: template.into(),
1476            inputs: Vec::new(),
1477            outputs: Vec::new(),
1478            volatile: true,
1479            can_trap: false,
1480        }
1481    }
1482    /// Add an input operand.
1483    #[allow(dead_code)]
1484    pub fn add_input(&mut self, constraint: impl Into<String>, val: CraneliftValue) {
1485        self.inputs.push((constraint.into(), val));
1486    }
1487    /// Add an output operand.
1488    #[allow(dead_code)]
1489    pub fn add_output(&mut self, constraint: impl Into<String>, val: CraneliftValue) {
1490        self.outputs.push((constraint.into(), val));
1491    }
1492    /// Emit a comment describing this inline asm fragment.
1493    #[allow(dead_code)]
1494    pub fn emit_comment(&self) -> String {
1495        format!(
1496            "; inline_asm template={:?} inputs={} outputs={} volatile={}",
1497            self.template,
1498            self.inputs.len(),
1499            self.outputs.len(),
1500            self.volatile,
1501        )
1502    }
1503}
1504/// A Cranelift function definition.
1505#[derive(Debug, Clone, PartialEq)]
1506pub struct CraneliftFunction {
1507    /// Function name
1508    pub name: String,
1509    /// Function signature
1510    pub sig: Signature,
1511    /// Stack slots: (slot_id, size_bytes)
1512    pub stack_slots: Vec<(u32, u32)>,
1513    /// Global values referenced: (gv_id, name)
1514    pub global_values: Vec<(u32, String)>,
1515    /// Signature references for indirect calls: (sig_id, signature)
1516    pub sig_refs: Vec<(u32, Signature)>,
1517    /// Function references for direct calls: (fn_ref_id, name, sig_id)
1518    pub func_refs: Vec<(u32, String, u32)>,
1519    /// Basic blocks (first block is the entry block)
1520    pub blocks: Vec<CraneliftBlock>,
1521    /// Next available SSA value id
1522    pub(super) next_value: u32,
1523    /// Next available block id
1524    pub(super) next_block: u32,
1525}
1526impl CraneliftFunction {
1527    /// Create a new function.
1528    pub fn new(name: impl Into<String>, sig: Signature) -> Self {
1529        CraneliftFunction {
1530            name: name.into(),
1531            sig,
1532            stack_slots: vec![],
1533            global_values: vec![],
1534            sig_refs: vec![],
1535            func_refs: vec![],
1536            blocks: vec![],
1537            next_value: 0,
1538            next_block: 0,
1539        }
1540    }
1541    /// Allocate a fresh SSA value with the given type.
1542    pub fn fresh_value(&mut self, ty: CraneliftType) -> CraneliftValue {
1543        let v = CraneliftValue::new(self.next_value, ty);
1544        self.next_value += 1;
1545        v
1546    }
1547    /// Create a new block and return its block reference.
1548    pub fn new_block(&mut self) -> u32 {
1549        let id = self.next_block;
1550        self.next_block += 1;
1551        self.blocks.push(CraneliftBlock::new(id));
1552        id
1553    }
1554    /// Create a new block with parameters.
1555    pub fn new_block_with_params(&mut self, param_types: &[CraneliftType]) -> u32 {
1556        let id = self.next_block;
1557        self.next_block += 1;
1558        let params = param_types
1559            .iter()
1560            .map(|ty| {
1561                let v = CraneliftValue::new(self.next_value, ty.clone());
1562                self.next_value += 1;
1563                v
1564            })
1565            .collect();
1566        self.blocks.push(CraneliftBlock::with_params(id, params));
1567        id
1568    }
1569    /// Get a mutable reference to a block by id.
1570    pub fn block_mut(&mut self, id: u32) -> Option<&mut CraneliftBlock> {
1571        self.blocks.iter_mut().find(|b| b.id == id)
1572    }
1573    /// Add a stack slot.
1574    pub fn add_stack_slot(&mut self, size_bytes: u32) -> u32 {
1575        let id = self.stack_slots.len() as u32;
1576        self.stack_slots.push((id, size_bytes));
1577        id
1578    }
1579    /// Emit this function as textual IR.
1580    pub fn emit(&self) -> String {
1581        let mut s = String::new();
1582        s.push_str(&format!("function %{}(", self.name));
1583        for (i, ty) in self.sig.params.iter().enumerate() {
1584            if i > 0 {
1585                s.push_str(", ");
1586            }
1587            s.push_str(&ty.to_string());
1588        }
1589        s.push_str(") -> ");
1590        for (i, ty) in self.sig.returns.iter().enumerate() {
1591            if i > 0 {
1592                s.push_str(", ");
1593            }
1594            s.push_str(&ty.to_string());
1595        }
1596        s.push_str(" system_v {\n");
1597        for (id, size) in &self.stack_slots {
1598            s.push_str(&format!("    ss{} = explicit_slot {}\n", id, size));
1599        }
1600        for (id, name) in &self.global_values {
1601            s.push_str(&format!("    gv{} = symbol colocated %{}\n", id, name));
1602        }
1603        for (id, sig) in &self.sig_refs {
1604            s.push_str(&format!("    sig{} = {}\n", id, sig));
1605        }
1606        for (id, name, sig_id) in &self.func_refs {
1607            s.push_str(&format!(
1608                "    fn{} = colocated %{} sig{}\n",
1609                id, name, sig_id
1610            ));
1611        }
1612        if !self.stack_slots.is_empty()
1613            || !self.global_values.is_empty()
1614            || !self.func_refs.is_empty()
1615        {
1616            s.push('\n');
1617        }
1618        for block in &self.blocks {
1619            s.push_str(&block.emit());
1620        }
1621        s.push_str("}\n");
1622        s
1623    }
1624}
1625/// A Cranelift module — the top-level compilation unit.
1626#[derive(Debug, Clone)]
1627pub struct CraneliftModule {
1628    /// Module name (for display purposes)
1629    pub name: String,
1630    /// Target triple (e.g. "x86_64-unknown-linux-gnu")
1631    pub target: String,
1632    /// Function definitions
1633    pub functions: Vec<CraneliftFunction>,
1634    /// Function declarations (external references)
1635    pub func_decls: Vec<(String, Signature)>,
1636    /// Data objects
1637    pub data_objects: Vec<CraneliftDataObject>,
1638    /// Global value map: name → gv_id
1639    pub global_values: HashMap<String, u32>,
1640}
1641impl CraneliftModule {
1642    /// Create a new module.
1643    pub fn new(name: impl Into<String>) -> Self {
1644        CraneliftModule {
1645            name: name.into(),
1646            target: "x86_64-unknown-linux-gnu".to_string(),
1647            functions: vec![],
1648            func_decls: vec![],
1649            data_objects: vec![],
1650            global_values: HashMap::new(),
1651        }
1652    }
1653    /// Add a function definition.
1654    pub fn add_function(&mut self, func: CraneliftFunction) {
1655        self.functions.push(func);
1656    }
1657    /// Add a function declaration (external).
1658    pub fn add_func_decl(&mut self, name: impl Into<String>, sig: Signature) {
1659        self.func_decls.push((name.into(), sig));
1660    }
1661    /// Add a data object.
1662    pub fn add_data_object(&mut self, obj: CraneliftDataObject) {
1663        self.data_objects.push(obj);
1664    }
1665    /// Emit the full module as textual IR.
1666    pub fn emit(&self) -> String {
1667        let mut s = String::new();
1668        s.push_str(&format!("; target = \"{}\"\n\n", self.target));
1669        for (name, sig) in &self.func_decls {
1670            s.push_str(&format!("declare %{}{};\n", name, sig));
1671        }
1672        if !self.func_decls.is_empty() {
1673            s.push('\n');
1674        }
1675        for obj in &self.data_objects {
1676            s.push_str(&obj.emit());
1677            s.push('\n');
1678        }
1679        for func in &self.functions {
1680            s.push_str(&func.emit());
1681            s.push('\n');
1682        }
1683        s
1684    }
1685}