Sign in

    milkir

    Reusable Cranelift-like SSA intermediate representation

    compiler
    ir
    ssa
    optimization
    Download zip
    Author
    Version
    0.1.1
    License
    Apache-2.0
    Last updated
    3 months ago
    Downloads
    362

    #milkir

    Reusable Cranelift-like SSA intermediate representation.

    milkir provides compiler IR data structures, builders, verification, CFG helpers, printing, and optimization drivers. It is intended as a reusable middle-end layer for MoonBit compiler projects.

    #Package

    • Milky2018/milkir: SSA values, blocks, instructions, terminators, signatures, FunctionBuilder, verification, CFG utilities, and optimization drivers.

    #When to use it

    Use MilkIR when a frontend needs a target-independent SSA form before instruction selection. A typical pipeline builds a Function, verifies it, runs one or more optimization passes, then lowers it through milkir_machv into MachV.

    #Example: build and verify SSA

    FunctionBuilder owns the common workflow: declare parameters/results, emit the entry block, create additional blocks when control flow needs them, switch to the block being translated, and finish each block with a terminator. A new builder starts with an entry block as the current block, so simple straight-line functions can emit instructions immediately.

    ///|
    test "build an add function with FunctionBuilder" {
    let builder = FunctionBuilder::FunctionBuilder("add_i32")
    let lhs = builder.add_param(I32)
    let rhs = builder.add_param(I32)
    builder.add_result(I32)
    let sum = builder.iadd(lhs, rhs)
    builder.return_([sum])
    let func = builder.finalize()
    inspect(func.verify(), content="()")
    inspect(func.blocks.length(), content="1")
    inspect(instruction_count(func), content="1")
    }

    #Example: run a small optimization pass

    The public optimization drivers mutate the function and report whether they changed it. This example folds two constants and then verifies the optimized function.

    ///|
    test "fold constants in a MilkIR function" {
    let builder = FunctionBuilder::FunctionBuilder("const_add")
    builder.add_result(I32)
    let lhs = builder.iconst_i32(10)
    let rhs = builder.iconst_i32(20)
    let sum = builder.iadd(lhs, rhs)
    builder.return_([sum])
    let func = builder.finalize()
    let before = instruction_count(func)
    let result = optimize_with_level(func, OptLevel::from_int(1))
    inspect(result.changed, content="true")
    inspect(instruction_count(func) <= before, content="true")
    inspect(func.verify(), content="()")
    }

    #Boundary

    milkir is generic compiler infrastructure. It should not depend on Wasmoon runtime concepts, embedding context layouts, WASI, or machine-code emission.

    Dialect-specific operations should travel through the generic ExtOp extension hook. The WebAssembly dialect is owned by Milky2018/wasm_milkir, not by MilkIR core.

    VerifyError

    pub suberror VerifyError {
    MissingTerminator(block_id~ : Int)
    EmptyFunction
    UndefinedValue(value_id~ : Int)
    ArityMismatch(message~ : String)
    TypeMismatch(message~ : String)
    } derive(Eq,
    Debug
    )

    impl Show for VerifyError

    Block

    pub struct Block {
    id : Int
    params : Array[(Value, Type)]
    instructions : Array[Inst]
    terminator : Terminator?
    } derive(
    Debug
    )

    Block - represents a basic block in the control flow graph A basic block is a sequence of instructions with:
    • One entry point (the first instruction)
    • One exit point (the last instruction, a terminator)

    Block::append_inst

    fn Block::append_inst(self : Block, inst : Inst) -> Unit

    Block::set_terminator

    fn Block::set_terminator(self : Block, term : Terminator) -> Unit

    Set the terminator for this block

    CFG

    pub struct CFG {
    size : Int
    num_blocks : Int
    successors : Array[Array[Int]]
    predecessors : Array[Array[Int]]
    valid : Array[Bool]
    } derive(
    Debug
    )

    CFG::build

    fn CFG::build(func : Function) -> CFG

    CFG::compute_dominators

    fn CFG::compute_dominators(self : CFG) -> Array[Int]

    CFG::dominates

    fn CFG::dominates(self : CFG, a : Int, b : Int) -> Bool

    CFG::find_back_edges

    fn CFG::find_back_edges(self : CFG) -> Array[(Int, Int)]

    CFG::find_loops

    fn CFG::find_loops(self : CFG) -> Array[Loop]

    CFG::get_loop_preheader

    fn CFG::get_loop_preheader(self : CFG, loop_ : Loop) -> Int?

    CFG::get_predecessors

    fn CFG::get_predecessors(self : CFG, block_id : Int) -> Array[Int]

    CFG::get_successors

    fn CFG::get_successors(self : CFG, block_id : Int) -> Array[Int]

    CFG::is_entry_or_unreachable

    fn CFG::is_entry_or_unreachable(self : CFG, block_id : Int) -> Bool

    CFG::is_exit_block

    fn CFG::is_exit_block(self : CFG, block_id : Int) -> Bool

    CFG::is_valid

    fn CFG::is_valid(self : CFG, block_id : Int) -> Bool

    CFG::postorder

    fn CFG::postorder(self : CFG) -> Array[Int]

    CFG::reverse_postorder

    fn CFG::reverse_postorder(self : CFG) -> Array[Int]

    CFG::to_dot

    fn CFG::to_dot(self : CFG, func_name : String) -> String

    ExtOp

    pub struct ExtOp {
    dialect : String
    opcode : String
    immediates : FixedArray[Int]
    } derive(
    Debug
    )

    impl Eq for ExtOp
    impl Hash for ExtOp

    ExtOp::ExtOp

    fn ExtOp::ExtOp(dialect : String, opcode : String, immediates : FixedArray[Int]) -> ExtOp

    ExternalSymbol

    pub struct ExternalSymbol {
    name : String
    } derive(Eq, Hash,
    Debug
    )

    ExternalSymbol::ExternalSymbol

    fn ExternalSymbol::ExternalSymbol(name : String) -> ExternalSymbol

    FloatCC

    pub(all) enum FloatCC {
    Eq
    Ne
    Lt
    Le
    Gt
    Ge
    } derive(Eq, Hash,
    Debug
    )

    Floating point comparison condition codes

    Function

    pub struct Function {
    name : String
    signature : Signature
    params : Array[(Value, Type)]
    results : Array[Type]
    blocks : Array[Block]
    stack_slots : Array[StackSlot]
    external_symbols : Array[ExternalSymbol]
    next_value_id : Int
    next_inst_id : Int
    next_block_id : Int
    next_stack_slot_id : Int
    } derive(
    Debug
    )

    Function - a complete IR function

    Function::Function

    fn Function::Function(name : String, signature : Signature) -> Function

    Function::add_param

    fn Function::add_param(self : Function, ty : Type) -> Value

    Add a parameter to the function

    Function::add_result

    fn Function::add_result(self : Function, ty : Type) -> Unit

    Add a result type to the function

    Function::declare_external_symbol

    fn Function::declare_external_symbol(self : Function, name : String) -> ExternalSymbol

    Function::new_block

    fn Function::new_block(self : Function, params : Array[Value]) -> Block

    Create a new basic block

    Function::new_block0

    fn Function::new_block0(self : Function) -> Block

    Function::new_empty

    fn Function::new_empty(name : String) -> Function

    Function::new_inst

    fn Function::new_inst(self : Function, opcode : Opcode, args : Array[Value], results : Array[Value]) -> Inst

    Function::new_stack_slot

    fn Function::new_stack_slot(self : Function, size : Int, align : Int) -> StackSlot

    Function::new_value

    fn Function::new_value(self : Function, ty : Type) -> Value

    Create a new value with a unique ID

    Function::print

    fn Function::print(self : Function) -> String

    Print a function

    Function::verify

    fn Function::verify(self : Function) -> Unit raise VerifyError

    FunctionBuilder

    type FunctionBuilder

    FunctionBuilder - helps construct IR functions Tracks the current block and provides methods for emitting instructions

    FunctionBuilder::FunctionBuilder

    fn FunctionBuilder::FunctionBuilder(name : String) -> FunctionBuilder

    FunctionBuilder::add_block_param

    fn FunctionBuilder::add_block_param(self : FunctionBuilder, block : Block, ty : Type) -> Value

    Add a block parameter (for SSA phi nodes)

    FunctionBuilder::add_param

    fn FunctionBuilder::add_param(self : FunctionBuilder, ty : Type) -> Value

    Add a parameter to the function

    FunctionBuilder::add_result

    fn FunctionBuilder::add_result(self : FunctionBuilder, ty : Type) -> Unit

    Add a result type to the function

    FunctionBuilder::append_block_params_for_function_params

    fn FunctionBuilder::append_block_params_for_function_params(self : FunctionBuilder, block : Block) -> Unit

    Append block parameters matching the function parameter types.

    FunctionBuilder::append_block_params_for_function_returns

    fn FunctionBuilder::append_block_params_for_function_returns(self : FunctionBuilder, block : Block) -> Unit

    Append block parameters matching the function result types.

    FunctionBuilder::band

    fn FunctionBuilder::band(self : FunctionBuilder, a : Value, b : Value) -> Value

    Bitwise and

    FunctionBuilder::bitcast

    fn FunctionBuilder::bitcast(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Bitcast (reinterpret bits)

    FunctionBuilder::block_params

    fn FunctionBuilder::block_params(_self : FunctionBuilder, block : Block) -> Array[Value]

    Return the SSA values used as block parameters.

    FunctionBuilder::bnot

    fn FunctionBuilder::bnot(self : FunctionBuilder, a : Value) -> Value

    Bitwise not

    FunctionBuilder::bor

    fn FunctionBuilder::bor(self : FunctionBuilder, a : Value, b : Value) -> Value

    Bitwise or

    FunctionBuilder::br_table

    fn FunctionBuilder::br_table(self : FunctionBuilder, index : Value, targets : Array[Block], default_target : Block) -> Unit

    Branch table (switch)

    FunctionBuilder::brnz

    fn FunctionBuilder::brnz(self : FunctionBuilder, cond : Value, then_block : Block, else_block : Block) -> Unit

    Conditional branch (branch if non-zero)

    FunctionBuilder::brz

    fn FunctionBuilder::brz(self : FunctionBuilder, cond : Value, then_block : Block, else_block : Block) -> Unit

    Conditional branch (branch if zero)

    FunctionBuilder::bxor

    fn FunctionBuilder::bxor(self : FunctionBuilder, a : Value, b : Value) -> Value

    Bitwise xor

    FunctionBuilder::call_ptr

    fn FunctionBuilder::call_ptr(self : FunctionBuilder, func_ptr : Value, callee_env : Value, args : Array[Value], result_types : Array[Type]) -> Array[Value]

    Call via function pointer with multiple return values For calls through an indirect callee address.

    Design: a callee environment operand is passed explicitly before user arguments; callers can provide a null/sentinel value when their convention does not use an environment.

    Operand layout: [func_ptr, callee_env, user_args...]

    FunctionBuilder::call_symbol

    fn FunctionBuilder::call_symbol(self : FunctionBuilder, symbol : ExternalSymbol, result_ty : Type?, args : Array[Value]) -> Value?

    FunctionBuilder::call_symbol_multi

    fn FunctionBuilder::call_symbol_multi(self : FunctionBuilder, symbol : ExternalSymbol, result_types : Array[Type], args : Array[Value]) -> Array[Value]

    FunctionBuilder::clz

    fn FunctionBuilder::clz(self : FunctionBuilder, a : Value) -> Value

    Count leading zeros

    FunctionBuilder::copy

    fn FunctionBuilder::copy(self : FunctionBuilder, a : Value) -> Value

    Copy value (for register allocation)

    FunctionBuilder::create_block

    fn FunctionBuilder::create_block(self : FunctionBuilder) -> Block

    Create a new block.

    FunctionBuilder::ctz

    fn FunctionBuilder::ctz(self : FunctionBuilder, a : Value) -> Value

    Count trailing zeros

    FunctionBuilder::current_block

    fn FunctionBuilder::current_block(self : FunctionBuilder) -> Block

    Get the current block

    FunctionBuilder::emit_ext_inst

    fn FunctionBuilder::emit_ext_inst(self : FunctionBuilder, ty : Type, opcode : ExtOp, operands : Array[Value]) -> Value

    FunctionBuilder::emit_inst

    fn FunctionBuilder::emit_inst(self : FunctionBuilder, ty : Type, opcode : Opcode, operands : Array[Value]) -> Value

    Emit an instruction that produces a result

    FunctionBuilder::emit_multi_ext_inst

    fn FunctionBuilder::emit_multi_ext_inst(self : FunctionBuilder, result_types : Array[Type], opcode : ExtOp, operands : Array[Value]) -> Array[Value]

    FunctionBuilder::emit_multi_inst

    fn FunctionBuilder::emit_multi_inst(self : FunctionBuilder, result_types : Array[Type], opcode : Opcode, operands : Array[Value]) -> Array[Value]

    Emit an instruction with multiple results.

    FunctionBuilder::emit_void_ext_inst

    fn FunctionBuilder::emit_void_ext_inst(self : FunctionBuilder, opcode : ExtOp, operands : Array[Value]) -> Unit

    FunctionBuilder::emit_void_inst

    fn FunctionBuilder::emit_void_inst(self : FunctionBuilder, opcode : Opcode, operands : Array[Value]) -> Unit

    Emit an instruction without a result

    FunctionBuilder::fabs

    fn FunctionBuilder::fabs(self : FunctionBuilder, a : Value) -> Value

    Float absolute value

    FunctionBuilder::fadd

    fn FunctionBuilder::fadd(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float add

    FunctionBuilder::fceil

    fn FunctionBuilder::fceil(self : FunctionBuilder, a : Value) -> Value

    Float ceiling

    FunctionBuilder::fcmp

    fn FunctionBuilder::fcmp(self : FunctionBuilder, cc : FloatCC, a : Value, b : Value) -> Value

    Float comparison (returns i32 0 or 1)

    FunctionBuilder::fconst

    fn FunctionBuilder::fconst(self : FunctionBuilder, ty : Type, value : Double) -> Value

    Emit a float constant

    FunctionBuilder::fconst_f32

    fn FunctionBuilder::fconst_f32(self : FunctionBuilder, value : Float) -> Value

    Emit an f32 constant Note: We pack the f32 bits into the Double's bit representation to preserve NaN payloads. Using value.to_double() would go through the FPU and convert signaling NaNs to quiet NaNs.

    FunctionBuilder::fconst_f64

    fn FunctionBuilder::fconst_f64(self : FunctionBuilder, value : Double) -> Value

    Emit an f64 constant

    FunctionBuilder::fcvt_to_sint

    fn FunctionBuilder::fcvt_to_sint(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Float to signed int

    FunctionBuilder::fcvt_to_sint_sat

    fn FunctionBuilder::fcvt_to_sint_sat(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Float to signed int (saturating - NaN->0, overflow->max/min)

    FunctionBuilder::fcvt_to_uint

    fn FunctionBuilder::fcvt_to_uint(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Float to unsigned int

    FunctionBuilder::fcvt_to_uint_sat

    fn FunctionBuilder::fcvt_to_uint_sat(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Float to unsigned int (saturating - NaN->0, overflow->max, negative->0)

    FunctionBuilder::fdemote

    fn FunctionBuilder::fdemote(self : FunctionBuilder, a : Value) -> Value

    Demote float (f64 -> f32)

    FunctionBuilder::fdiv

    fn FunctionBuilder::fdiv(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float divide

    FunctionBuilder::ffloor

    fn FunctionBuilder::ffloor(self : FunctionBuilder, a : Value) -> Value

    Float floor

    FunctionBuilder::finalize

    fn FunctionBuilder::finalize(self : FunctionBuilder) -> Function

    Finish building and return the constructed function.

    FunctionBuilder::fmax

    fn FunctionBuilder::fmax(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float maximum

    FunctionBuilder::fmin

    fn FunctionBuilder::fmin(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float minimum

    FunctionBuilder::fmul

    fn FunctionBuilder::fmul(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float multiply

    FunctionBuilder::fnearest

    fn FunctionBuilder::fnearest(self : FunctionBuilder, a : Value) -> Value

    Float nearest (round to nearest even)

    FunctionBuilder::fneg

    fn FunctionBuilder::fneg(self : FunctionBuilder, a : Value) -> Value

    Float negate

    FunctionBuilder::fpromote

    fn FunctionBuilder::fpromote(self : FunctionBuilder, a : Value) -> Value

    Promote float (f32 -> f64)

    FunctionBuilder::fsqrt

    fn FunctionBuilder::fsqrt(self : FunctionBuilder, a : Value) -> Value

    Float square root

    FunctionBuilder::fsub

    fn FunctionBuilder::fsub(self : FunctionBuilder, a : Value, b : Value) -> Value

    Float subtract

    FunctionBuilder::ftrunc

    fn FunctionBuilder::ftrunc(self : FunctionBuilder, a : Value) -> Value

    Float truncate

    FunctionBuilder::get_const_value

    fn FunctionBuilder::get_const_value(self : FunctionBuilder, v : Value) -> Int64?

    Get the constant value if a Value was defined by an Iconst instruction. Searches all blocks in the function to find the defining instruction. Returns None if the value is not a constant or not found.

    FunctionBuilder::get_function

    fn FunctionBuilder::get_function(self : FunctionBuilder) -> Function

    Get the function being built

    FunctionBuilder::iadd

    fn FunctionBuilder::iadd(self : FunctionBuilder, a : Value, b : Value) -> Value

    Integer add

    FunctionBuilder::icmp

    fn FunctionBuilder::icmp(self : FunctionBuilder, cc : IntCC, a : Value, b : Value) -> Value

    Integer comparison (returns i32 0 or 1)

    FunctionBuilder::icmp_eq

    fn FunctionBuilder::icmp_eq(self : FunctionBuilder, a : Value, b : Value) -> Value

    Integer equal

    FunctionBuilder::icmp_ne

    fn FunctionBuilder::icmp_ne(self : FunctionBuilder, a : Value, b : Value) -> Value

    Integer not equal

    FunctionBuilder::icmp_sge

    fn FunctionBuilder::icmp_sge(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed greater than or equal

    FunctionBuilder::icmp_sgt

    fn FunctionBuilder::icmp_sgt(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed greater than

    FunctionBuilder::icmp_sle

    fn FunctionBuilder::icmp_sle(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed less than or equal

    FunctionBuilder::icmp_slt

    fn FunctionBuilder::icmp_slt(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed less than

    FunctionBuilder::icmp_uge

    fn FunctionBuilder::icmp_uge(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned greater than or equal

    FunctionBuilder::icmp_ugt

    fn FunctionBuilder::icmp_ugt(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned greater than

    FunctionBuilder::icmp_ule

    fn FunctionBuilder::icmp_ule(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned less than or equal

    FunctionBuilder::icmp_ult

    fn FunctionBuilder::icmp_ult(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned less than

    FunctionBuilder::iconst

    fn FunctionBuilder::iconst(self : FunctionBuilder, ty : Type, value : Int64) -> Value

    Emit an integer constant

    FunctionBuilder::iconst_i32

    fn FunctionBuilder::iconst_i32(self : FunctionBuilder, value : Int) -> Value

    Emit an i32 constant

    FunctionBuilder::iconst_i64

    fn FunctionBuilder::iconst_i64(self : FunctionBuilder, value : Int64) -> Value

    Emit an i64 constant

    FunctionBuilder::imul

    fn FunctionBuilder::imul(self : FunctionBuilder, a : Value, b : Value) -> Value

    Integer multiply

    FunctionBuilder::ireduce

    fn FunctionBuilder::ireduce(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Reduce integer width (e.g., i64 -> i32)

    FunctionBuilder::ishl

    fn FunctionBuilder::ishl(self : FunctionBuilder, a : Value, b : Value) -> Value

    Shift left

    FunctionBuilder::isub

    fn FunctionBuilder::isub(self : FunctionBuilder, a : Value, b : Value) -> Value

    Integer subtract

    FunctionBuilder::jump

    fn FunctionBuilder::jump(self : FunctionBuilder, target : Block, args : Array[Value]) -> Unit

    Unconditional jump

    FunctionBuilder::load_ptr

    fn FunctionBuilder::load_ptr(self : FunctionBuilder, ty : Type, base : Value, offset : Value) -> Value

    Load from raw pointer (no bounds checking) For trampoline code that operates on host memory

    FunctionBuilder::load_ptr_narrow

    fn FunctionBuilder::load_ptr_narrow(self : FunctionBuilder, result_ty : Type, bits : Int, signed : Bool, base : Value, offset : Value) -> Value

    Load narrow value from raw pointer (no bounds checking) Loads 'bits' bits from memory and extends to result_ty

    FunctionBuilder::popcnt

    fn FunctionBuilder::popcnt(self : FunctionBuilder, a : Value) -> Value

    Population count (count number of 1 bits)

    FunctionBuilder::print

    fn FunctionBuilder::print(self : FunctionBuilder) -> String

    Print using FunctionBuilder

    FunctionBuilder::return_

    fn FunctionBuilder::return_(self : FunctionBuilder, values : Array[Value]) -> Unit

    Return from function

    FunctionBuilder::rotl

    fn FunctionBuilder::rotl(self : FunctionBuilder, a : Value, b : Value) -> Value

    Rotate left

    FunctionBuilder::rotr

    fn FunctionBuilder::rotr(self : FunctionBuilder, a : Value, b : Value) -> Value

    Rotate right

    FunctionBuilder::sdiv

    fn FunctionBuilder::sdiv(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed integer divide

    FunctionBuilder::select

    fn FunctionBuilder::select(self : FunctionBuilder, cond : Value, a : Value, b : Value) -> Value

    Conditional select: cond ? a : b

    FunctionBuilder::sextend

    fn FunctionBuilder::sextend(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Sign extend (e.g., i32 -> i64)

    FunctionBuilder::sextend16

    fn FunctionBuilder::sextend16(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Sign extend from 16 bits (in-place, keeps the same type) Similar to ireduce(I16) + sextend(ty)

    FunctionBuilder::sextend32

    fn FunctionBuilder::sextend32(self : FunctionBuilder, a : Value) -> Value

    Sign extend from 32 bits to 64 bits Similar to ireduce(I32) + sextend(I64)

    FunctionBuilder::sextend8

    fn FunctionBuilder::sextend8(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Sign extend from 8 bits (in-place, keeps the same type) Similar to ireduce(I8) + sextend(ty)

    FunctionBuilder::sint_to_fcvt

    fn FunctionBuilder::sint_to_fcvt(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Signed int to float

    FunctionBuilder::smulh

    fn FunctionBuilder::smulh(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed multiply high (i64 only)

    FunctionBuilder::srem

    fn FunctionBuilder::srem(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed integer remainder

    FunctionBuilder::sshr

    fn FunctionBuilder::sshr(self : FunctionBuilder, a : Value, b : Value) -> Value

    Signed shift right

    FunctionBuilder::store_ptr

    fn FunctionBuilder::store_ptr(self : FunctionBuilder, ty : Type, base : Value, value : Value, offset : Value) -> Unit

    Store to raw pointer (no bounds checking) For trampoline code that operates on host memory

    FunctionBuilder::store_ptr_narrow

    fn FunctionBuilder::store_ptr_narrow(self : FunctionBuilder, bits : Int, base : Value, value : Value, offset : Value) -> Unit

    Store narrow value to raw pointer (no bounds checking) Stores the low 'bits' bits of value to memory

    FunctionBuilder::switch_to_block

    fn FunctionBuilder::switch_to_block(self : FunctionBuilder, block : Block) -> Unit

    Switch to a different block for emitting instructions

    FunctionBuilder::trap

    fn FunctionBuilder::trap(self : FunctionBuilder, reason : String) -> Unit

    Trap/unreachable

    FunctionBuilder::udiv

    fn FunctionBuilder::udiv(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned integer divide

    FunctionBuilder::uextend

    fn FunctionBuilder::uextend(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Zero extend (e.g., i32 -> i64)

    FunctionBuilder::uint_to_fcvt

    fn FunctionBuilder::uint_to_fcvt(self : FunctionBuilder, ty : Type, a : Value) -> Value

    Unsigned int to float

    FunctionBuilder::umulh

    fn FunctionBuilder::umulh(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned multiply high (i64 only)

    FunctionBuilder::urem

    fn FunctionBuilder::urem(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned integer remainder

    FunctionBuilder::ushr

    fn FunctionBuilder::ushr(self : FunctionBuilder, a : Value, b : Value) -> Value

    Unsigned shift right

    FunctionBuilder::v128_and

    fn FunctionBuilder::v128_and(self : FunctionBuilder, a : Value, b : Value) -> Value

    FunctionBuilder::v128_andnot

    fn FunctionBuilder::v128_andnot(self : FunctionBuilder, a : Value, b : Value) -> Value

    FunctionBuilder::v128_anytrue

    fn FunctionBuilder::v128_anytrue(self : FunctionBuilder, a : Value) -> Value

    FunctionBuilder::v128_binary

    fn FunctionBuilder::v128_binary(self : FunctionBuilder, opcode : Opcode, a : Value, b : Value) -> Value

    FunctionBuilder::v128_bitselect

    fn FunctionBuilder::v128_bitselect(self : FunctionBuilder, a : Value, b : Value, c : Value) -> Value

    FunctionBuilder::v128_const

    fn FunctionBuilder::v128_const(self : FunctionBuilder, bytes : Bytes) -> Value

    v128_const - emit a V128 constant

    FunctionBuilder::v128_extract16s

    fn FunctionBuilder::v128_extract16s(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract16u

    fn FunctionBuilder::v128_extract16u(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract32

    fn FunctionBuilder::v128_extract32(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract64

    fn FunctionBuilder::v128_extract64(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract8s

    fn FunctionBuilder::v128_extract8s(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    Extract a lane from a v128 value

    FunctionBuilder::v128_extract8u

    fn FunctionBuilder::v128_extract8u(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract_f32

    fn FunctionBuilder::v128_extract_f32(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_extract_f64

    fn FunctionBuilder::v128_extract_f64(self : FunctionBuilder, vec : Value, lane : Int) -> Value

    FunctionBuilder::v128_load_lane_with_addr

    fn FunctionBuilder::v128_load_lane_with_addr(self : FunctionBuilder, opcode : Opcode, effective_addr : Value, vec : Value) -> Value

    SIMD load lane with effective address and existing vector

    FunctionBuilder::v128_load_with_addr

    fn FunctionBuilder::v128_load_with_addr(self : FunctionBuilder, opcode : Opcode, effective_addr : Value) -> Value

    SIMD load with effective address (for complex SIMD loads)

    FunctionBuilder::v128_not

    fn FunctionBuilder::v128_not(self : FunctionBuilder, a : Value) -> Value

    Bitwise operations on v128

    FunctionBuilder::v128_or

    fn FunctionBuilder::v128_or(self : FunctionBuilder, a : Value, b : Value) -> Value

    FunctionBuilder::v128_replace16

    fn FunctionBuilder::v128_replace16(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    FunctionBuilder::v128_replace32

    fn FunctionBuilder::v128_replace32(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    FunctionBuilder::v128_replace64

    fn FunctionBuilder::v128_replace64(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    FunctionBuilder::v128_replace8

    fn FunctionBuilder::v128_replace8(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    Replace a lane in a v128 value

    FunctionBuilder::v128_replace_f32

    fn FunctionBuilder::v128_replace_f32(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    FunctionBuilder::v128_replace_f64

    fn FunctionBuilder::v128_replace_f64(self : FunctionBuilder, vec : Value, val : Value, lane : Int) -> Value

    FunctionBuilder::v128_shift

    fn FunctionBuilder::v128_shift(self : FunctionBuilder, opcode : Opcode, vec : Value, shift : Value) -> Value

    FunctionBuilder::v128_shuffle

    fn FunctionBuilder::v128_shuffle(self : FunctionBuilder, a : Value, b : Value, lanes : FixedArray[Int]) -> Value

    Shuffle lanes from two v128 values

    FunctionBuilder::v128_splat16

    fn FunctionBuilder::v128_splat16(self : FunctionBuilder, val : Value) -> Value

    FunctionBuilder::v128_splat32

    fn FunctionBuilder::v128_splat32(self : FunctionBuilder, val : Value) -> Value

    FunctionBuilder::v128_splat64

    fn FunctionBuilder::v128_splat64(self : FunctionBuilder, val : Value) -> Value

    FunctionBuilder::v128_splat8

    fn FunctionBuilder::v128_splat8(self : FunctionBuilder, val : Value) -> Value

    v128_splat - broadcast a scalar to all lanes

    FunctionBuilder::v128_splat_f32

    fn FunctionBuilder::v128_splat_f32(self : FunctionBuilder, val : Value) -> Value

    FunctionBuilder::v128_splat_f64

    fn FunctionBuilder::v128_splat_f64(self : FunctionBuilder, val : Value) -> Value

    FunctionBuilder::v128_store_lane_with_addr

    fn FunctionBuilder::v128_store_lane_with_addr(self : FunctionBuilder, opcode : Opcode, effective_addr : Value, vec : Value) -> Unit

    SIMD store lane with effective address and vector (void)

    FunctionBuilder::v128_swizzle

    fn FunctionBuilder::v128_swizzle(self : FunctionBuilder, a : Value, b : Value) -> Value

    Swizzle lanes using indices from another v128

    FunctionBuilder::v128_to_i32

    fn FunctionBuilder::v128_to_i32(self : FunctionBuilder, opcode : Opcode, a : Value) -> Value

    FunctionBuilder::v128_unary

    fn FunctionBuilder::v128_unary(self : FunctionBuilder, opcode : Opcode, a : Value) -> Value

    Generic SIMD instruction emitter Use this for operations that follow the pattern: opcode, operands -> V128/I32

    FunctionBuilder::v128_xor

    fn FunctionBuilder::v128_xor(self : FunctionBuilder, a : Value, b : Value) -> Value

    Inst

    pub struct Inst {
    id : Int
    results : Array[Value]
    opcode : Opcode
    args : Array[Value]
    operands : Array[Value]
    metadata : Array[Metadata]
    } derive(
    Debug
    )

    Instruction - an SSA instruction that produces a value
    impl Eq for Inst
    impl Hash for Inst

    Inst::add_metadata

    fn Inst::add_metadata(self : Inst, metadata : Metadata) -> Unit

    Inst::all_results

    fn Inst::all_results(self : Inst) -> Array[Value]

    Get all results of this instruction

    Inst::first_result

    fn Inst::first_result(self : Inst) -> Value?

    Get primary result of this instruction (first result or None)

    IntCC

    pub(all) enum IntCC {
    Eq
    Ne
    Slt
    Sle
    Sgt
    Sge
    Ult
    Ule
    Ugt
    Uge
    } derive(Eq, Hash,
    Debug
    )

    Integer comparison condition codes

    Loop

    pub struct Loop {
    header : Int
    blocks : Array[Int]
    back_edges : Array[(Int, Int)]
    } derive(
    Debug
    )

    Loop::contains

    fn Loop::contains(self : Loop, block_id : Int) -> Bool

    Metadata

    pub(all) enum Metadata {
    SourceLoc(String)
    Comment(String)
    } derive(Eq,
    Debug
    )

    Opcode

    pub(all) enum Opcode {
    Iconst(Int64)
    Fconst(Double)
    Iadd
    Isub
    Imul
    Umulh
    Smulh
    Sdiv
    Udiv
    Srem
    Urem
    Band
    Bor
    Bxor
    Bnot
    Ishl
    Sshr
    Ushr
    Rotl
    Rotr
    Clz
    Ctz
    Popcnt
    Icmp(IntCC)
    IcmpEq
    Fadd
    Fsub
    Fmul
    Fdiv
    Fmin
    Fmax
    Fcmp(FloatCC)
    Fneg
    Fabs
    Fsqrt
    Fceil
    Ffloor
    Ftrunc
    Fnearest
    Ireduce
    Sextend
    Uextend
    Fpromote
    Fdemote
    FcvtToSint
    FcvtToUint
    FcvtToSintSat
    FcvtToUintSat
    SintToFcvt
    UintToFcvt
    Bitcast
    Sextend8
    Sextend16
    Sextend32
    Select
    Copy
    Load
    Store
    StackAddr(StackSlot)
    Call(ExternalSymbol)
    CallIndirect(Signature)
    LoadPtr(Type)
    StorePtr(Type)
    LoadPtrNarrow(Type, Int, Bool)
    StorePtrNarrow(Int)
    CallPtr(Int, Int)
    Trap(String)
    Custom(String)
    Ext(ExtOp)
    V128Const(Bytes)
    V128Splat8
    V128Splat16
    V128Splat32
    V128Splat64
    V128SplatF32
    V128SplatF64
    V128ExtractLane8S(Int)
    V128ExtractLane8U(Int)
    V128ExtractLane16S(Int)
    V128ExtractLane16U(Int)
    V128ExtractLane32(Int)
    V128ExtractLane64(Int)
    V128ExtractLaneF32(Int)
    V128ExtractLaneF64(Int)
    V128ReplaceLane8(Int)
    V128ReplaceLane16(Int)
    V128ReplaceLane32(Int)
    V128ReplaceLane64(Int)
    V128ReplaceLaneF32(Int)
    V128ReplaceLaneF64(Int)
    V128Shuffle(FixedArray[Int])
    V128Swizzle
    V128Not
    V128And
    V128AndNot
    V128Or
    V128Xor
    V128Bitselect
    V128AnyTrue
    V128AllTrue8
    V128AllTrue16
    V128AllTrue32
    V128AllTrue64
    V128Bitmask8
    V128Bitmask16
    V128Bitmask32
    V128Bitmask64
    V128Add8
    V128Add16
    V128Add32
    V128Add64
    V128Sub8
    V128Sub16
    V128Sub32
    V128Sub64
    V128Mul16
    V128Mul32
    V128Mul64
    V128AddSat8S
    V128AddSat8U
    V128AddSat16S
    V128AddSat16U
    V128SubSat8S
    V128SubSat8U
    V128SubSat16S
    V128SubSat16U
    V128Min8S
    V128Min8U
    V128Min16S
    V128Min16U
    V128Min32S
    V128Min32U
    V128Max8S
    V128Max8U
    V128Max16S
    V128Max16U
    V128Max32S
    V128Max32U
    V128Avgr8U
    V128Avgr16U
    V128Abs8
    V128Abs16
    V128Abs32
    V128Abs64
    V128Neg8
    V128Neg16
    V128Neg32
    V128Neg64
    V128Popcnt8
    V128Shl8
    V128Shl16
    V128Shl32
    V128Shl64
    V128Shr8S
    V128Shr8U
    V128Shr16S
    V128Shr16U
    V128Shr32S
    V128Shr32U
    V128Shr64S
    V128Shr64U
    V128Eq8
    V128Eq16
    V128Eq32
    V128Eq64
    V128Ne8
    V128Ne16
    V128Ne32
    V128Ne64
    V128Lt8S
    V128Lt8U
    V128Lt16S
    V128Lt16U
    V128Lt32S
    V128Lt32U
    V128Lt64S
    V128Gt8S
    V128Gt8U
    V128Gt16S
    V128Gt16U
    V128Gt32S
    V128Gt32U
    V128Gt64S
    V128Le8S
    V128Le8U
    V128Le16S
    V128Le16U
    V128Le32S
    V128Le32U
    V128Le64S
    V128Ge8S
    V128Ge8U
    V128Ge16S
    V128Ge16U
    V128Ge32S
    V128Ge32U
    V128Ge64S
    V128Narrow16to8S
    V128Narrow16to8U
    V128Narrow32to16S
    V128Narrow32to16U
    V128ExtendLow8to16S
    V128ExtendHigh8to16S
    V128ExtendLow8to16U
    V128ExtendHigh8to16U
    V128ExtendLow16to32S
    V128ExtendHigh16to32S
    V128ExtendLow16to32U
    V128ExtendHigh16to32U
    V128ExtendLow32to64S
    V128ExtendHigh32to64S
    V128ExtendLow32to64U
    V128ExtendHigh32to64U
    V128ExtMulLow8to16S
    V128ExtMulHigh8to16S
    V128ExtMulLow8to16U
    V128ExtMulHigh8to16U
    V128ExtMulLow16to32S
    V128ExtMulHigh16to32S
    V128ExtMulLow16to32U
    V128ExtMulHigh16to32U
    V128ExtMulLow32to64S
    V128ExtMulHigh32to64S
    V128ExtMulLow32to64U
    V128ExtMulHigh32to64U
    V128ExtAddPairwise8to16S
    V128ExtAddPairwise8to16U
    V128ExtAddPairwise16to32S
    V128ExtAddPairwise16to32U
    V128Dot16to32S
    V128Q15MulrSat16S
    V128AddF32
    V128AddF64
    V128SubF32
    V128SubF64
    V128MulF32
    V128MulF64
    V128DivF32
    V128DivF64
    V128MinF32
    V128MinF64
    V128MaxF32
    V128MaxF64
    V128PMinF32
    V128PMinF64
    V128PMaxF32
    V128PMaxF64
    V128AbsF32
    V128AbsF64
    V128NegF32
    V128NegF64
    V128SqrtF32
    V128SqrtF64
    V128CeilF32
    V128CeilF64
    V128FloorF32
    V128FloorF64
    V128TruncF32
    V128TruncF64
    V128NearestF32
    V128NearestF64
    V128EqF32
    V128EqF64
    V128NeF32
    V128NeF64
    V128LtF32
    V128LtF64
    V128GtF32
    V128GtF64
    V128LeF32
    V128LeF64
    V128GeF32
    V128GeF64
    V128TruncSatF32toI32S
    V128TruncSatF32toI32U
    V128TruncSatF64toI32SZero
    V128TruncSatF64toI32UZero
    V128ConvertI32toF32S
    V128ConvertI32toF32U
    V128ConvertLowI32toF64S
    V128ConvertLowI32toF64U
    V128DemoteF64toF32Zero
    V128PromoteLowF32toF64
    V128Load8x8S(Int, Int, Int64)
    V128Load8x8U(Int, Int, Int64)
    V128Load16x4S(Int, Int, Int64)
    V128Load16x4U(Int, Int, Int64)
    V128Load32x2S(Int, Int, Int64)
    V128Load32x2U(Int, Int, Int64)
    V128Load8Splat(Int, Int, Int64)
    V128Load16Splat(Int, Int, Int64)
    V128Load32Splat(Int, Int, Int64)
    V128Load64Splat(Int, Int, Int64)
    V128Load32Zero(Int, Int, Int64)
    V128Load64Zero(Int, Int, Int64)
    V128Load8Lane(Int, Int, Int64, Int)
    V128Load16Lane(Int, Int, Int64, Int)
    V128Load32Lane(Int, Int, Int64, Int)
    V128Load64Lane(Int, Int, Int64, Int)
    V128Store8Lane(Int, Int, Int64, Int)
    V128Store16Lane(Int, Int, Int64, Int)
    V128Store32Lane(Int, Int, Int64, Int)
    V128Store64Lane(Int, Int, Int64, Int)
    V128RelaxedSwizzle
    V128RelaxedTruncF32toI32S
    V128RelaxedTruncF32toI32U
    V128RelaxedTruncF64toI32SZero
    V128RelaxedTruncF64toI32UZero
    V128RelaxedMaddF32
    V128RelaxedNmaddF32
    V128RelaxedMaddF64
    V128RelaxedNmaddF64
    V128RelaxedLaneselect8
    V128RelaxedLaneselect16
    V128RelaxedLaneselect32
    V128RelaxedLaneselect64
    V128RelaxedMinF32
    V128RelaxedMaxF32
    V128RelaxedMinF64
    V128RelaxedMaxF64
    V128RelaxedQ15MulrS
    V128RelaxedDot8to16S
    V128RelaxedDot8to32AddS
    } derive(Eq, Hash,
    Debug
    )

    Opcode - the operation performed by an instruction
    impl Show for Opcode

    OptLevel

    pub(all) enum OptLevel {
    O0
    O1
    O2
    O3
    }

    Optimization level
    • 0: No optimization
    • 1: Basic optimizations (constant folding, copy propagation, CSE, DCE)
    • 2: Default optimizations (includes control flow optimizations)
    • 3: Aggressive optimizations (includes loop optimizations)

    OptLevel::from_int

    fn OptLevel::from_int(n : Int) -> OptLevel

    Parse optimization level from integer

    OptResult

    pub struct OptResult {
    changed : Bool
    } derive(Eq)

    Result of an optimization pass

    Signature

    pub struct Signature {
    params : Array[Type]
    results : Array[Type]
    } derive(Eq, Hash,
    Debug
    )

    Signature::Signature

    fn Signature::Signature(params : Array[Type], results : Array[Type]) -> Signature

    StackSlot

    pub struct StackSlot {
    id : Int
    size : Int
    align : Int
    } derive(Eq, Hash,
    Debug
    )

    Terminator

    pub(all) enum Terminator {
    Jump(Int, Array[Value])
    Branch(Value, Int, Array[Value], Int, Array[Value])
    Brz(Value, Int, Int)
    Brnz(Value, Int, Int)
    BrTable(Value, Array[Int], Int)
    Return(Array[Value])
    Trap(String)
    TrapExit(String)
    } derive(
    Debug
    )

    Terminator - how a basic block ends

    Type

    pub(all) enum Type {
    I32
    I64
    F32
    F64
    V128
    Ptr
    Ref
    CallableRef
    OpaqueRef
    } derive(Eq, Hash,
    Debug
    )

    IR type system for scalar, vector, pointer, and reference-typed values.
    impl Show for Type

    Value

    pub struct Value {
    id : Int
    ty : Type
    } derive(Eq, Hash,
    Debug
    )

    IR Value - represents a virtual register in SSA form Each value is defined exactly once and can be used multiple times

    Value::Value

    fn Value::Value(id : Int, ty : Type) -> Value

    instruction_count

    fn instruction_count(func : Function) -> Int

    Count IR instructions in a function.

    optimize

    fn optimize(func : Function) -> OptResult

    Run default optimizations (Cranelift-aligned O2 path).

    optimize_with_level

    fn optimize_with_level(func : Function, level : OptLevel) -> OptResult

    Run optimizations based on level