package core:rexcode/ir/wasm
Overview
rexcode/ir/wasm -- the WebAssembly intermediate representation.
WASM is a stack bytecode: a byte stream with LEB128 immediates, one encoding
form per opcode, over an implicit value stack with a minimal type system.
On the two axes that sort the IR family (docs/ir_design.md §2) it is
table-driven on encoding -- a static opcode -> operand-layout table,
exactly the ISA ENCODING_TABLE shape -- and STACK on dataflow (the one
outlier among the modelled IRs; SPIR-V/LLVM are SSA).
So this package is a sibling of the SPIR-V package under ir/: it re-exports
the shared ir vocabulary (Module / Function / Block / Operation / Operand /
Type / Id / ...), owns a u16 Opcode (the WASM opcode set, with the 0xFC/
0xFD/0xFE prefix groups folded in), a static ENCODING_TABLE that drives a
byte/LEB codec, the three Module-based verbs (encode / decode / print),
a Relocation for object-file index fixups, and the WASM value-type model.
This is the migration anticipated by docs/ir_design.md §4: WASM was shaped as
an ISA arch package (core:rexcode/wasm); its real encode/decode already
dropped the ISA verbs' label_defs/resolve/base_address (WASM has no
PC-relative pass -- branches carry structured label depths), so moving it onto
the ir Module/Operation/Operand model is a change of leaf shape, not of
codec. The table-driven codec below is carried over intact; what changed is
the leaf (ir.Operation in place of the old fixed-operand Instruction), the
operand model (ir.Operand, with WASM memarg/blocktype/lane riding in aux),
and the unit of work (an ir.Module of functions->blocks->operations).
Index
Types (54)
- Attr
- Block
- Block_Type
- Builder
- Custom_Section
- Custom_Section_Name
- Custom_Section_Name_Function
- Custom_Section_Name_Function_Locals
- Custom_Section_Name_Local
- Custom_Section_Target_Feature
- Custom_Section_Target_Feature_Prefix
- Custom_Section_Target_Features
- Dataflow
- Encoding
- Encoding_Flags
- Error
- Error_Code
- Export
- External_Kind
- Func_Type
- Function
- Global
- Id
- Imm_Kind
- Import
- Index_Kind
- Memarg
- Module
- Opcode
- Operand
- Operand_Kind
- Operation
- Operation_Flags
- Parse_Error
- Print_Options
- Print_Result
- Reader
- Reader_Error
- Ref
- Ref_Space
- Reloc_Group
- Relocation
- Relocation_Type
- Result
- Section
- Section_Id
- Symbol_Table
- Token
- Token_Kind
- Type
- Type_Kind
- Type_Ref
- Value_Type
- WAT_Options
Variables (6)
Procedures (128)
- append_uleb
- append_uleb_name
- aprint
- aprint_wat
- builder_make
- count_import_kind
- decode
- decode_expr
- decode_one
- decode_ops
- emit
- emit_block
- emit_br
- emit_br_if
- emit_br_table
- emit_call
- emit_call_indirect
- emit_else
- emit_end
- emit_f32
- emit_f64
- emit_global_get
- emit_global_set
- emit_i32
- emit_i64
- emit_if
- emit_load
- emit_local_get
- emit_local_set
- emit_local_tee
- emit_loop
- emit_none
- emit_return
- emit_shuffle
- emit_store
- emit_unreachable
- emit_v128_const
- encode
- encode_max_code_size
- encode_max_relocation_count
- encode_operation
- encode_ops
- encode_size
- external_kind_name
- fprint_wat
- make_module
- memarg
- mnemonic_to_string
- module_name
- no_result
- op_block_typeidx
- op_blocktype
- op_data
- op_elem
- op_f32
- op_f64
- op_flags_for
- op_func
- op_global
- op_i32
- op_i64
- op_label
- op_labelidx
- op_lane
- op_local
- op_memarg
- op_memory
- op_reftype
- op_table
- op_typeidx
- op_v128
- op_wasm_index
- opbuf
- operand_attr
- operand_index
- operand_index_kind
- operand_memarg
- operand_symbolic
- operand_v128
- operation
- parse_container
- print_wat
- read_sleb
- read_u32_block
- read_u64_block
- read_uleb
- ref_space_for
- reloc_field_size
- reloc_has_addend
- reloc_type_from_wire
- relocations_for_section
- sbprint
- sbprint_wat
- section_name
- sleb_size
- take_block
- tprint
- tprint_wat
- uleb_size
- valtype_name
- value_type_is_num
- value_type_is_ref
- wat_write_const_expr
- wat_write_data
- wat_write_elements
- wat_write_function
- wat_write_functype
- wat_write_globals
- wat_write_imports
- wat_write_memories
- wat_write_quoted_string
- wat_write_tables
- write_attribute
- write_block_type
- write_float
- write_heap_type
- write_id_or_comment
- write_label
- write_mnemonic
- write_name_or_id
- write_operand
- write_operation
- write_sleb
- write_u32_block
- write_u64_block
- write_uleb
- write_uleb_padded5
Procedure Groups (0)
This section is empty.
Types
Attr ¶
Attr :: enum u16 { NONE, BLOCKTYPE, MEMARG, REFTYPE, LANE, V128_LO, // low 8 bytes of a v128 literal / shuffle mask V128_HI, // high 8 bytes }
The ir.Operand.aux tag for the ATTRIBUTE-kind WASM immediates. (REF operands
instead put an Index_Kind in aux; the opcode's ENCODING_TABLE form always
says which of the two an operand slot is, so the two uses never collide.)
Related Procedures With Returns
Block_Type ¶
Block_Type :: enum i64 { EMPTY = -46, // 0x40 I32 = -1, // 0x7F I64 = -2, // 0x7E F32 = -3, // 0x7D F64 = -4, // 0x7C V128 = -5, // 0x7B FUNCREF = -61, // 0x70 EXTERNREF = -71, // 0x6F }
Block signature. Negative sentinels are the s33 single-byte forms; a non-negative value is a type index encoded as a positive signed LEB128.
Related Procedures With Parameters
Builder ¶
Related Procedures With Parameters
- emit
- emit_block
- emit_br
- emit_br_if
- emit_br_table
- emit_call
- emit_call_indirect
- emit_else
- emit_end
- emit_f32
- emit_f64
- emit_global_get
- emit_global_set
- emit_i32
- emit_i64
- emit_if
- emit_load
- emit_local_get
- emit_local_set
- emit_local_tee
- emit_loop
- emit_none
- emit_return
- emit_shuffle
- emit_store
- emit_unreachable
- emit_v128_const
- opbuf
- take_block
Related Procedures With Returns
Custom_Section ¶
Custom_Section :: struct { section: Section, payload: []u8, // borrowed, m.data[section.offset:][:section.size] variant: union { Custom_Section_Name, Custom_Section_Target_Features, }, }
Custom_Section_Name ¶
Custom_Section_Name :: struct { module_name: string, functions: []Custom_Section_Name_Function, locals: []Custom_Section_Name_Function_Locals, }
Custom_Section_Name_Function_Locals ¶
Custom_Section_Name_Function_Locals :: struct { func_idx: u32, locals: []Custom_Section_Name_Local, }
Custom_Section_Target_Feature ¶
Custom_Section_Target_Feature :: struct { prefix: Custom_Section_Target_Feature_Prefix, feature: string, }
Custom_Section_Target_Feature_Prefix ¶
Custom_Section_Target_Feature_Prefix :: enum u8 { Used = 43, Disallowed = 45, Required = 61, }
Custom_Section_Target_Features ¶
Custom_Section_Target_Features :: struct { features: []Custom_Section_Target_Feature, }
Dataflow ¶
Dataflow :: rexcode_ir.Dataflow
Encoding ¶
Encoding :: struct #packed { mnemonic: Opcode, // 2 -- redundant w/ table index, kept for parity prefix: u8, // 1 -- PREFIX_NONE / PREFIX_MISC / PREFIX_SIMD / PREFIX_ATOM opcode: u16, // 2 -- primary opcode, or sub-opcode within a prefix group imm: [2]Imm_Kind, // 2 -- immediate layout, walked in order flags: Encoding_Flags, // 1 inputs: i8, // 1 -- stack operands consumed; -1 when it varies outputs: i8, }
Error_Code ¶
Error_Code :: rexcode_ir.Error_Code
Export ¶
Export :: struct { kind: External_Kind, name: string, index: u32, }
External_Kind ¶
External_Kind :: enum u8 { FUNC = 0, TABLE = 1, MEMORY = 2, GLOBAL = 3, }
Related Procedures With Parameters
Func_Type ¶
Func_Type :: struct { params: []Value_Type, results: []Value_Type, }
A WASM function signature: value-typed params and results.
Related Procedures With Parameters
Imm_Kind ¶
Imm_Kind :: enum u8 { NONE, BLOCKTYPE, // signed LEB128 s33 (negative valtype byte, or type index) I32, // signed LEB128 (i32.const) I64, // signed LEB128 (i64.const) F32, // 4 little-endian bytes F64, // 8 little-endian bytes IDX, // unsigned LEB128 index (space comes from the operand) MEMARG, // unsigned LEB128 align, then unsigned LEB128 offset REFTYPE, // single value-type byte (ref.null) BR_TABLE, // unsigned LEB128 count, that many label depths, default depth ZERO_BYTE, // a single reserved 0x00 byte (memidx placeholders) LANE, // single byte lane index (SIMD extract/replace/load/store lane) LANES16, // sixteen raw bytes (v128.const value / i8x16.shuffle mask) }
How one immediate field is laid down after the opcode.
Import ¶
Import :: struct { kind: External_Kind, module_name: string, field_name: string, index: u32, }
Index_Kind ¶
Index_Kind :: enum u16 { NONE, LOCAL, GLOBAL, FUNC, TYPE, TABLE, MEMORY, LABEL, // br / br_if / br_table relative depth DATA, ELEM, }
Which WASM index space an index immediate addresses. Drives the on-wire
encoding, relocation-type selection, and printer annotation. Kept in
ir.Operand.aux for every REF operand so the exact space always round-trips,
even where the shared ir.Ref_Space has no dedicated member (TABLE/DATA/ELEM).
Related Procedures With Parameters
Related Procedures With Returns
Memarg ¶
Load/store immediate: alignment hint (log2 bytes) + static offset.
Related Procedures With Parameters
Related Procedures With Returns
Module ¶
Module :: struct { using base: rexcode_ir.Module, // functions, globals, symbols, dataflow (= .STACK), target version: u32, // --- container sections (the WASM-specific data the ir core has no slot for) --- func_types: []Func_Type, // the type section; ir.Function.signature indexes here imports: []Import, exports: []Export, start: i64, // -1 if absent, else the start funcidx customs: []Custom_Section, // --- side tables parallel to the ir core arrays --- // A WASM function's declared locals (the code section's local groups), kept // parallel to base.functions since ir.Function has no locals slot. function_locals: [][]Value_Type, // --- preserved binary framing (so nothing decoded is lost / is re-readable) --- sections: []Section, // every section header, in file order relocations: []Reloc_Group, // object-file relocations, grouped by target section data: []u8, }
The WASM module -- the unit the verbs operate on. Embeds the ir core; adds the container metadata parsed from / emitted to the binary sections.
After decode, base.functions spans the whole WASM function index space:
imported functions occupy the low indices (their blocks are empty -- an
import has no body) followed by the module-defined functions (each a single
ir.Block whose ops are the decoded body). ir.Function.signature is the
function's typeidx (an index into func_types, by convention), and its
name is resolved from the export and "name" custom sections.
Related Procedures With Parameters
Related Procedures With Returns
Opcode ¶
Opcode :: enum u16 { INVALID = 0, // ------------------------------------------------------------------ control UNREACHABLE, NOP, BLOCK, LOOP, IF, ELSE, END, BR, BR_IF, BR_TABLE, RETURN, CALL, CALL_INDIRECT, RETURN_CALL, RETURN_CALL_INDIRECT, // -------------------------------------------------------------- parametric DROP, SELECT, // ---------------------------------------------------------------- variable LOCAL_GET, LOCAL_SET, LOCAL_TEE, GLOBAL_GET, GLOBAL_SET, // ------------------------------------------------------------------- memory I32_LOAD, I64_LOAD, F32_LOAD, F64_LOAD, I32_LOAD8_S, I32_LOAD8_U, I32_LOAD16_S, I32_LOAD16_U, I64_LOAD8_S, I64_LOAD8_U, I64_LOAD16_S, I64_LOAD16_U, I64_LOAD32_S, I64_LOAD32_U, I32_STORE, I64_STORE, F32_STORE, F64_STORE, I32_STORE8, I32_STORE16, I64_STORE8, I64_STORE16, I64_STORE32, MEMORY_SIZE, MEMORY_GROW, // ----------------------------------------------------------------- numeric I32_CONST, I64_CONST, F32_CONST, F64_CONST, // i32 comparison I32_EQZ, I32_EQ, I32_NE, I32_LT_S, I32_LT_U, I32_GT_S, I32_GT_U, I32_LE_S, I32_LE_U, I32_GE_S, I32_GE_U, // i64 comparison I64_EQZ, I64_EQ, I64_NE, I64_LT_S, I64_LT_U, I64_GT_S, I64_GT_U, I64_LE_S, I64_LE_U, I64_GE_S, I64_GE_U, // f32 comparison F32_EQ, F32_NE, F32_LT, F32_GT, F32_LE, F32_GE, // f64 comparison F64_EQ, F64_NE, F64_LT, F64_GT, F64_LE, F64_GE, // i32 arithmetic I32_CLZ, I32_CTZ, I32_POPCNT, I32_ADD, I32_SUB, I32_MUL, I32_DIV_S, I32_DIV_U, I32_REM_S, I32_REM_U, I32_AND, I32_OR, I32_XOR, I32_SHL, I32_SHR_S, I32_SHR_U, I32_ROTL, I32_ROTR, // i64 arithmetic I64_CLZ, I64_CTZ, I64_POPCNT, I64_ADD, I64_SUB, I64_MUL, I64_DIV_S, I64_DIV_U, I64_REM_S, I64_REM_U, I64_AND, I64_OR, I64_XOR, I64_SHL, I64_SHR_S, I64_SHR_U, I64_ROTL, I64_ROTR, // f32 arithmetic F32_ABS, F32_NEG, F32_CEIL, F32_FLOOR, F32_TRUNC, F32_NEAREST, F32_SQRT, F32_ADD, F32_SUB, F32_MUL, F32_DIV, F32_MIN, F32_MAX, F32_COPYSIGN, // f64 arithmetic F64_ABS, F64_NEG, F64_CEIL, F64_FLOOR, F64_TRUNC, F64_NEAREST, F64_SQRT, F64_ADD, F64_SUB, F64_MUL, F64_DIV, F64_MIN, F64_MAX, F64_COPYSIGN, // conversions I32_WRAP_I64, I32_TRUNC_F32_S, I32_TRUNC_F32_U, I32_TRUNC_F64_S, I32_TRUNC_F64_U, I64_EXTEND_I32_S, I64_EXTEND_I32_U, I64_TRUNC_F32_S, I64_TRUNC_F32_U, I64_TRUNC_F64_S, I64_TRUNC_F64_U, F32_CONVERT_I32_S, F32_CONVERT_I32_U, F32_CONVERT_I64_S, F32_CONVERT_I64_U, F32_DEMOTE_F64, F64_CONVERT_I32_S, F64_CONVERT_I32_U, F64_CONVERT_I64_S, F64_CONVERT_I64_U, F64_PROMOTE_F32, I32_REINTERPRET_F32, I64_REINTERPRET_F64, F32_REINTERPRET_I32, F64_REINTERPRET_I64, // sign-extension operators (0xC0..0xC4) I32_EXTEND8_S, I32_EXTEND16_S, I64_EXTEND8_S, I64_EXTEND16_S, I64_EXTEND32_S, // reference types REF_NULL, REF_IS_NULL, REF_FUNC, // ------------------------------------------------------- 0xFC misc prefix // saturating truncation I32_TRUNC_SAT_F32_S, I32_TRUNC_SAT_F32_U, I32_TRUNC_SAT_F64_S, I32_TRUNC_SAT_F64_U, I64_TRUNC_SAT_F32_S, I64_TRUNC_SAT_F32_U, I64_TRUNC_SAT_F64_S, I64_TRUNC_SAT_F64_U, // bulk memory & table MEMORY_INIT, DATA_DROP, MEMORY_COPY, MEMORY_FILL, TABLE_INIT, ELEM_DROP, TABLE_COPY, TABLE_GROW, TABLE_SIZE, TABLE_FILL, // ----------------------------------------------- 0xFD SIMD (v128) prefix V128_LOAD, V128_LOAD8X8_S, V128_LOAD8X8_U, V128_LOAD16X4_S, V128_LOAD16X4_U, V128_LOAD32X2_S, V128_LOAD32X2_U, V128_LOAD8_SPLAT, V128_LOAD16_SPLAT, V128_LOAD32_SPLAT, V128_LOAD64_SPLAT, V128_STORE, V128_CONST, I8X16_SHUFFLE, I8X16_SWIZZLE, I8X16_SPLAT, I16X8_SPLAT, I32X4_SPLAT, I64X2_SPLAT, F32X4_SPLAT, F64X2_SPLAT, I8X16_EXTRACT_LANE_S, I8X16_EXTRACT_LANE_U, I8X16_REPLACE_LANE, I16X8_EXTRACT_LANE_S, I16X8_EXTRACT_LANE_U, I16X8_REPLACE_LANE, I32X4_EXTRACT_LANE, I32X4_REPLACE_LANE, I64X2_EXTRACT_LANE, I64X2_REPLACE_LANE, F32X4_EXTRACT_LANE, F32X4_REPLACE_LANE, F64X2_EXTRACT_LANE, F64X2_REPLACE_LANE, I8X16_EQ, I8X16_NE, I8X16_LT_S, I8X16_LT_U, I8X16_GT_S, I8X16_GT_U, I8X16_LE_S, I8X16_LE_U, I8X16_GE_S, I8X16_GE_U, I16X8_EQ, I16X8_NE, I16X8_LT_S, I16X8_LT_U, I16X8_GT_S, I16X8_GT_U, I16X8_LE_S, I16X8_LE_U, I16X8_GE_S, I16X8_GE_U, I32X4_EQ, I32X4_NE, I32X4_LT_S, I32X4_LT_U, I32X4_GT_S, I32X4_GT_U, I32X4_LE_S, I32X4_LE_U, I32X4_GE_S, I32X4_GE_U, F32X4_EQ, F32X4_NE, F32X4_LT, F32X4_GT, F32X4_LE, F32X4_GE, F64X2_EQ, F64X2_NE, F64X2_LT, F64X2_GT, F64X2_LE, F64X2_GE, V128_NOT, V128_AND, V128_ANDNOT, V128_OR, V128_XOR, V128_BITSELECT, V128_ANY_TRUE, V128_LOAD8_LANE, V128_LOAD16_LANE, V128_LOAD32_LANE, V128_LOAD64_LANE, V128_STORE8_LANE, V128_STORE16_LANE, V128_STORE32_LANE, V128_STORE64_LANE, V128_LOAD32_ZERO, V128_LOAD64_ZERO, F32X4_DEMOTE_F64X2_ZERO, F64X2_PROMOTE_LOW_F32X4, I8X16_ABS, I8X16_NEG, I8X16_POPCNT, I8X16_ALL_TRUE, I8X16_BITMASK, I8X16_NARROW_I16X8_S, I8X16_NARROW_I16X8_U, F32X4_CEIL, F32X4_FLOOR, F32X4_TRUNC, F32X4_NEAREST, I8X16_SHL, I8X16_SHR_S, I8X16_SHR_U, I8X16_ADD, I8X16_ADD_SAT_S, I8X16_ADD_SAT_U, I8X16_SUB, I8X16_SUB_SAT_S, I8X16_SUB_SAT_U, F64X2_CEIL, F64X2_FLOOR, I8X16_MIN_S, I8X16_MIN_U, I8X16_MAX_S, I8X16_MAX_U, F64X2_TRUNC, I8X16_AVGR_U, I16X8_EXTADD_PAIRWISE_I8X16_S, I16X8_EXTADD_PAIRWISE_I8X16_U, I32X4_EXTADD_PAIRWISE_I16X8_S, I32X4_EXTADD_PAIRWISE_I16X8_U, I16X8_ABS, I16X8_NEG, I16X8_Q15MULR_SAT_S, I16X8_ALL_TRUE, I16X8_BITMASK, I16X8_NARROW_I32X4_S, I16X8_NARROW_I32X4_U, I16X8_EXTEND_LOW_I8X16_S, I16X8_EXTEND_HIGH_I8X16_S, I16X8_EXTEND_LOW_I8X16_U, I16X8_EXTEND_HIGH_I8X16_U, I16X8_SHL, I16X8_SHR_S, I16X8_SHR_U, I16X8_ADD, I16X8_ADD_SAT_S, I16X8_ADD_SAT_U, I16X8_SUB, I16X8_SUB_SAT_S, I16X8_SUB_SAT_U, F64X2_NEAREST, I16X8_MUL, I16X8_MIN_S, I16X8_MIN_U, I16X8_MAX_S, I16X8_MAX_U, I16X8_AVGR_U, I16X8_EXTMUL_LOW_I8X16_S, I16X8_EXTMUL_HIGH_I8X16_S, I16X8_EXTMUL_LOW_I8X16_U, I16X8_EXTMUL_HIGH_I8X16_U, I32X4_ABS, I32X4_NEG, I32X4_ALL_TRUE, I32X4_BITMASK, I32X4_EXTEND_LOW_I16X8_S, I32X4_EXTEND_HIGH_I16X8_S, I32X4_EXTEND_LOW_I16X8_U, I32X4_EXTEND_HIGH_I16X8_U, I32X4_SHL, I32X4_SHR_S, I32X4_SHR_U, I32X4_ADD, I32X4_SUB, I32X4_MUL, I32X4_MIN_S, I32X4_MIN_U, I32X4_MAX_S, I32X4_MAX_U, I32X4_DOT_I16X8_S, I32X4_EXTMUL_LOW_I16X8_S, I32X4_EXTMUL_HIGH_I16X8_S, I32X4_EXTMUL_LOW_I16X8_U, I32X4_EXTMUL_HIGH_I16X8_U, I64X2_ABS, I64X2_NEG, I64X2_ALL_TRUE, I64X2_BITMASK, I64X2_EXTEND_LOW_I32X4_S, I64X2_EXTEND_HIGH_I32X4_S, I64X2_EXTEND_LOW_I32X4_U, I64X2_EXTEND_HIGH_I32X4_U, I64X2_SHL, I64X2_SHR_S, I64X2_SHR_U, I64X2_ADD, I64X2_SUB, I64X2_MUL, I64X2_EQ, I64X2_NE, I64X2_LT_S, I64X2_GT_S, I64X2_LE_S, I64X2_GE_S, I64X2_EXTMUL_LOW_I32X4_S, I64X2_EXTMUL_HIGH_I32X4_S, I64X2_EXTMUL_LOW_I32X4_U, I64X2_EXTMUL_HIGH_I32X4_U, F32X4_ABS, F32X4_NEG, F32X4_SQRT, F32X4_ADD, F32X4_SUB, F32X4_MUL, F32X4_DIV, F32X4_MIN, F32X4_MAX, F32X4_PMIN, F32X4_PMAX, F64X2_ABS, F64X2_NEG, F64X2_SQRT, F64X2_ADD, F64X2_SUB, F64X2_MUL, F64X2_DIV, F64X2_MIN, F64X2_MAX, F64X2_PMIN, F64X2_PMAX, I32X4_TRUNC_SAT_F32X4_S, I32X4_TRUNC_SAT_F32X4_U, F32X4_CONVERT_I32X4_S, F32X4_CONVERT_I32X4_U, I32X4_TRUNC_SAT_F64X2_S_ZERO, I32X4_TRUNC_SAT_F64X2_U_ZERO, F64X2_CONVERT_LOW_I32X4_S, F64X2_CONVERT_LOW_I32X4_U, I8X16_RELAXED_SWIZZLE, I32X4_RELAXED_TRUNC_F32X4_S, I32X4_RELAXED_TRUNC_F32X4_U, I32X4_RELAXED_TRUNC_F64X2_S_ZERO, I32X4_RELAXED_TRUNC_F64X2_U_ZERO, F32X4_RELAXED_MADD, F32X4_RELAXED_NMADD, F64X2_RELAXED_MADD, F64X2_RELAXED_NMADD, I8X16_RELAXED_LANESELECT, I16X8_RELAXED_LANESELECT, I32X4_RELAXED_LANESELECT, I64X2_RELAXED_LANESELECT, F32X4_RELAXED_MIN, F32X4_RELAXED_MAX, F64X2_RELAXED_MIN, F64X2_RELAXED_MAX, I16X8_RELAXED_Q15MULR_S, I16X8_RELAXED_DOT_I8X16_I7X16_S, I32X4_RELAXED_DOT_I8X16_I7X16_ADD_S, // ------------------------------------------ 0xFE threads / atomics prefix MEMORY_ATOMIC_NOTIFY, MEMORY_ATOMIC_WAIT32, MEMORY_ATOMIC_WAIT64, ATOMIC_FENCE, I32_ATOMIC_LOAD, I64_ATOMIC_LOAD, I32_ATOMIC_LOAD8_U, I32_ATOMIC_LOAD16_U, I64_ATOMIC_LOAD8_U, I64_ATOMIC_LOAD16_U, I64_ATOMIC_LOAD32_U, I32_ATOMIC_STORE, I64_ATOMIC_STORE, I32_ATOMIC_STORE8, I32_ATOMIC_STORE16, I64_ATOMIC_STORE8, I64_ATOMIC_STORE16, I64_ATOMIC_STORE32, I32_ATOMIC_RMW_ADD, I64_ATOMIC_RMW_ADD, I32_ATOMIC_RMW8_ADD_U, I32_ATOMIC_RMW16_ADD_U, I64_ATOMIC_RMW8_ADD_U, I64_ATOMIC_RMW16_ADD_U, I64_ATOMIC_RMW32_ADD_U, I32_ATOMIC_RMW_SUB, I64_ATOMIC_RMW_SUB, I32_ATOMIC_RMW8_SUB_U, I32_ATOMIC_RMW16_SUB_U, I64_ATOMIC_RMW8_SUB_U, I64_ATOMIC_RMW16_SUB_U, I64_ATOMIC_RMW32_SUB_U, I32_ATOMIC_RMW_AND, I64_ATOMIC_RMW_AND, I32_ATOMIC_RMW8_AND_U, I32_ATOMIC_RMW16_AND_U, I64_ATOMIC_RMW8_AND_U, I64_ATOMIC_RMW16_AND_U, I64_ATOMIC_RMW32_AND_U, I32_ATOMIC_RMW_OR, I64_ATOMIC_RMW_OR, I32_ATOMIC_RMW8_OR_U, I32_ATOMIC_RMW16_OR_U, I64_ATOMIC_RMW8_OR_U, I64_ATOMIC_RMW16_OR_U, I64_ATOMIC_RMW32_OR_U, I32_ATOMIC_RMW_XOR, I64_ATOMIC_RMW_XOR, I32_ATOMIC_RMW8_XOR_U, I32_ATOMIC_RMW16_XOR_U, I64_ATOMIC_RMW8_XOR_U, I64_ATOMIC_RMW16_XOR_U, I64_ATOMIC_RMW32_XOR_U, I32_ATOMIC_RMW_XCHG, I64_ATOMIC_RMW_XCHG, I32_ATOMIC_RMW8_XCHG_U, I32_ATOMIC_RMW16_XCHG_U, I64_ATOMIC_RMW8_XCHG_U, I64_ATOMIC_RMW16_XCHG_U, I64_ATOMIC_RMW32_XCHG_U, I32_ATOMIC_RMW_CMPXCHG, I64_ATOMIC_RMW_CMPXCHG, I32_ATOMIC_RMW8_CMPXCHG_U, I32_ATOMIC_RMW16_CMPXCHG_U, I64_ATOMIC_RMW8_CMPXCHG_U, I64_ATOMIC_RMW16_CMPXCHG_U, I64_ATOMIC_RMW32_CMPXCHG_U, }
Related Procedures With Parameters
Operand ¶
Operand :: rexcode_ir.Operand
Related Procedures With Parameters
Related Procedures With Returns
Operand_Kind ¶
Operand_Kind :: rexcode_ir.Operand_Kind
Operation ¶
Operation :: rexcode_ir.Operation
Related Procedures With Parameters
Related Procedures With Returns
Parse_Error ¶
Parse_Error :: enum u8 { NONE = 0, TRUNCATED, // read past the end of the buffer BAD_MAGIC, // not a `\0asm` module BAD_TYPE_FORM, // a functype did not start with 0x60 BAD_SECTION, // section contents extend past the buffer BAD_ULEB, // a ULEB did not terminate within 10 bytes }
Related Procedures With Returns
Print_Options ¶
Print_Options :: rexcode_ir.Print_Options
Related Procedures With Parameters
Related Constants
Print_Result ¶
Print_Result :: rexcode_ir.Print_Result
Reader_Error ¶
Reader_Error :: union { Parse_Error, runtime.Allocator_Error, }
Related Procedures With Returns
Reloc_Group ¶
Reloc_Group :: struct { target_section: Section_Id, relocs: []Relocation, }
A set of relocations that apply to one section (parsed from a reloc.<name>
custom section). Grouped by the section they target so the decoder can hand
the CODE-section group to each function body it decodes.
Relocation_Type ¶
Relocation_Type :: enum u8 { NONE = 0, FUNCTION_INDEX_LEB, // funcidx, 5-byte ULEB (call, ref.func) TABLE_INDEX_SLEB, // 5-byte SLEB table element index TABLE_INDEX_I32, // 4-byte LE table element index MEMORY_ADDR_LEB, // linear-memory address, 5-byte ULEB MEMORY_ADDR_SLEB, // linear-memory address, 5-byte SLEB MEMORY_ADDR_I32, // linear-memory address, 4-byte LE TYPE_INDEX_LEB, // typeidx, 5-byte ULEB (call_indirect) GLOBAL_INDEX_LEB, // globalidx, 5-byte ULEB TABLE_NUMBER_LEB, // tableidx, 5-byte ULEB }
Related Procedures With Parameters
Related Procedures With Returns
Section ¶
Section :: struct { id: Section_Id, offset: u32, // file offset of the section contents size: u32, // contents length in bytes count: u32, // declared element count (0 for CUSTOM / START) name: string, }
A parsed binary section header: where its contents live in the file and how
many entries it declares. Kept so sections the ir core does not model
structurally (table/memory/global/element/data) stay re-readable from data.
Section_Id ¶
Section_Id :: enum u8 { // Binary section ids (WebAssembly core spec §5.5.2). CUSTOM = 0, TYPE = 1, IMPORT = 2, FUNCTION = 3, TABLE = 4, MEMORY = 5, GLOBAL = 6, EXPORT = 7, START = 8, ELEMENT = 9, CODE = 10, DATA = 11, DATA_COUNT = 12, }
Related Procedures With Parameters
Symbol_Table ¶
Symbol_Table :: rexcode_ir.Symbol_Table
Token_Kind ¶
Token_Kind :: rexcode_ir.Token_Kind
Type_Kind ¶
Type_Kind :: rexcode_ir.Type_Kind
Value_Type ¶
Value_Type :: enum u8 { I32 = 127, I64 = 126, F32 = 125, F64 = 124, V128 = 123, FUNCREF = 112, EXTERNREF = 111, }
Related Procedures With Parameters
WAT_Options ¶
WAT_Options :: struct { indent_unit: string, }
Related Procedures With Parameters
Related Constants
Constants
DEFAULT_PRINT_OPTIONS ¶
DEFAULT_PRINT_OPTIONS: rexcode_ir.Print_Options : ir.DEFAULT_PRINT_OPTIONS
DEFAULT_WAT_OPTIONS ¶
DEFAULT_WAT_OPTIONS :: WAT_Options{indent_unit = " "}
FLAG_SYMBOLIC ¶
FLAG_SYMBOLIC :: u32(1)
ir.Operand.flags bit: a REF whose index is a symbol id the linker fixes up
(emitted as a fixed-width 5-byte LEB placeholder plus a Relocation).
MAX_OPCODE_SIZE ¶
MAX_OPCODE_SIZE :: 3
prefix byte + two-byte unsigned-LEB sub-opcode (SIMD reaches 0x113)
PREFIX_NONE ¶
PREFIX_NONE :: u8(0x00)
Opcode-space prefix bytes. A prefixed opcode is prefix byte then an unsigned
LEB128 sub-opcode (SIMD reaches 0x113, so the sub-opcode can be two bytes).
TYPE_NONE ¶
TYPE_NONE: rexcode_ir.Type_Ref : ir.TYPE_NONE
WASM_MAGIC ¶
WASM_MAGIC :: u32(0x6d73_6100)
The four bytes that begin every module: "\0asm" as a little-endian u32.
WASM_VERSION ¶
WASM_VERSION :: u32(1)
Variables
DECODE_ATOMIC ¶
@(rodata) DECODE_ATOMIC: [79]Opcode = …
DECODE_MAIN ¶
@(rodata) DECODE_MAIN: [256]Opcode = …
DECODE_MISC ¶
@(rodata) DECODE_MISC: [32]Opcode = …
DECODE_SIMD ¶
@(rodata) DECODE_SIMD: [276]Opcode = …
Procedures
append_uleb ¶
Unsigned LEB128, appended to a [dynamic]u8
aprint ¶
aprint :: proc(ops: []rexcode_ir.Operation, options: ^rexcode_ir.Print_Options = nil, allocator := context.allocator) -> string {…}
aprint: caller-allocated string of an operation stream.
aprint_wat ¶
aprint_wat :: proc(m: Module, opts: WAT_Options = DEFAULT_WAT_OPTIONS, allocator := context.allocator) -> string {…}
Allocates the result with allocator (caller owns it).
builder_make ¶
builder_make :: proc(allocator := context.allocator) -> Builder {…}
count_import_kind ¶
count_import_kind :: proc "contextless" (m: Module, k: External_Kind) -> u32 {…}
decode ¶
decode :: proc(data: []u8, m: ^Module, errors: ^[dynamic]rexcode_ir.Error, allocator := context.allocator) -> (byte_count: u32, ok: bool) {…}
decode: parse a whole .wasm binary module into m. Returns the number of
bytes consumed (the file length on success) and whether it fully succeeded.
decode_expr ¶
decode_expr :: proc(data: []u8, m: ^Module, errors: ^[dynamic]rexcode_ir.Error, allocator := context.allocator) -> (byte_count: u32, ok: bool) {…}
decode_expr: parse a bare WASM expr byte stream (one instruction stream,
no container) into a single-function, single-block Module (dataflow = .STACK).
The full-container module verb is decode (parse.odin); the reusable
stream-level decoder both share is decode_ops.
decode_ops ¶
decode_ops :: proc(data: []u8, relocs: []Relocation, errors: ^[dynamic]rexcode_ir.Error, allocator := context.allocator) -> (ops: []rexcode_ir.Operation, byte_count: u32, ok: bool) {…}
decode_ops: the reusable instruction-stream decoder. relocs (may be nil) are
the input relocations to re-attach to symbolic index fields.
emit ¶
Append an operation with the given operands, allocating their backing.
emit_block ¶
emit_block :: proc(b: ^Builder, bt: Block_Type = .EMPTY) {…}
emit_br_table ¶
br_table: operands are [default, case0, case1, ...], every entry a label depth.
emit_else ¶
emit_else :: proc(b: ^Builder) {…}
emit_end ¶
emit_end :: proc(b: ^Builder) {…}
emit_if ¶
emit_if :: proc(b: ^Builder, bt: Block_Type = .EMPTY) {…}
emit_loop ¶
emit_loop :: proc(b: ^Builder, bt: Block_Type = .EMPTY) {…}
emit_return ¶
emit_return :: proc(b: ^Builder) {…}
emit_unreachable ¶
emit_unreachable :: proc(b: ^Builder) {…}
emit_v128_const ¶
v128.const / i8x16.shuffle: the 16-byte immediate as two ATTRIBUTE halves.
encode ¶
encode :: proc(m: Module, code: []u8, relocs: ^[dynamic]Relocation, errors: ^[dynamic]rexcode_ir.Error) -> (byte_count: u32, ok: bool) {…}
encode: serialize the module m into code, producing a complete .wasm
binary. Returns the number of bytes written and whether it fully succeeded.
Size code with encode_size(m) (or any larger buffer).
encode_ops ¶
encode_ops :: proc(ops: []rexcode_ir.Operation, code: []u8, relocs: ^[dynamic]Relocation, errors: ^[dynamic]rexcode_ir.Error) -> (byte_count: u32, ok: bool) {…}
encode_ops: the reusable instruction-stream encoder (a WASM expr).
encode_size ¶
encode_size: the exact byte length encode(m, ...) will produce (a dry run,
so callers can size the output buffer precisely). Uses the temp allocator.
external_kind_name ¶
external_kind_name :: proc "contextless" (k: External_Kind) -> string {…}
fprint_wat ¶
fprint_wat :: proc(w: io.Stream, m: Module, opts: WAT_Options = DEFAULT_WAT_OPTIONS) {…}
make_module ¶
make_module :: proc "contextless" () -> Module {…}
A freshly-made WASM module declares STACK dataflow so the shared verbs and the printer pick the stack-machine path (no SSA results, no value refs).
mnemonic_to_string ¶
mnemonic_to_string :: proc(op: Opcode, uppercase: bool = false, allocator := context.temp_allocator) -> string {…}
no_result ¶
no_result :: proc "contextless" () -> rexcode_ir.Result {…}
The stack-IR result: WASM defines no SSA value, so every operation's result is empty. (Kept as a helper so the intent is explicit at every call site.)
op_blocktype ¶
op_blocktype :: proc "contextless" (bt: Block_Type) -> rexcode_ir.Operand {…}
op_flags_for ¶
op_flags_for :: proc "contextless" (opcode: Opcode) -> rexcode_ir.Operation_Flags {…}
Operation flags derived from the opcode's ENCODING_TABLE form, plus the terminator bit for the ops that end a stack-IR region.
op_label ¶
Symbolic function reference: emitted as a relocatable funcidx placeholder.
op_labelidx ¶
Branch label depth (number of enclosing blocks to break out of).
op_reftype ¶
op_reftype :: proc "contextless" (t: Value_Type) -> rexcode_ir.Operand {…}
op_v128 ¶
A 16-byte v128 literal (v128.const) or shuffle mask (i8x16.shuffle), as two little-endian 64-bit ATTRIBUTE halves.
op_wasm_index ¶
op_wasm_index :: proc "contextless" (kind: Index_Kind, value: u32, symbolic: bool = false) -> rexcode_ir.Operand {…}
opbuf ¶
Stable per-operation operand backing.
operand_index_kind ¶
operand_index_kind :: proc "contextless" (o: rexcode_ir.Operand) -> Index_Kind {…}
operand_v128 ¶
v128 bytes from a lo/hi ATTRIBUTE pair.
operation ¶
operation :: proc "contextless" (opcode: Opcode, operands: []rexcode_ir.Operand = nil) -> rexcode_ir.Operation {…}
Build an Operation over an already-owned operand slice (no allocation).
parse_container ¶
parse_container :: proc(data: []u8, m: ^Module, errors: ^[dynamic]rexcode_ir.Error, allocator: runtime.Allocator) -> Reader_Error {…}
print ¶
print :: proc(m: Module, sb: ^strings.Builder, options: ^rexcode_ir.Print_Options = nil) {…}
print: disassemble m into the caller-owned builder sb. The canonical ir
print verb; sbprint / tprint below are thin convenience sinks over it.
print_wat ¶
print_wat :: proc(m: Module, file: ^os.File, opts: WAT_Options = DEFAULT_WAT_OPTIONS) {…}
read_sleb ¶
Read signed LEB128 starting at *offset; advances it.
read_uleb ¶
Read unsigned LEB128 starting at *offset; advances it. ok is false on
truncation. Reads at most max bytes (10 covers u64).
ref_space_for ¶
ref_space_for :: proc "contextless" (k: Index_Kind) -> rexcode_ir.Ref_Space {…}
Best-fit shared space for a WASM index space (used for printer annotation and
generic ir tooling). The exact Index_Kind still lives in aux, so spaces
the shared enum lacks (TABLE/DATA/ELEM) map to NONE here without loss.
reloc_field_size ¶
reloc_field_size :: proc "contextless" (t: Relocation_Type) -> u8 {…}
On-wire field width of a relocation, in bytes.
reloc_has_addend ¶
MEMORY_ADDR_ (3,4,5) and the _OFFSET_I32 forms (8,9) carry a trailing signed-LEB addend; the index-type relocations do not.
reloc_type_from_wire ¶
reloc_type_from_wire :: proc "contextless" (code: u8) -> (Relocation_Type, bool) {…}
Decode a relocation type byte from a reloc.* custom section. ok is false
for a type this codec does not model (the entry is then skipped).
relocations_for_section ¶
relocations_for_section :: proc "contextless" (groups: []Reloc_Group, id: Section_Id) -> []Relocation {…}
The relocations (if any) that patch fields in the given section.
sbprint ¶
sbprint :: proc(sb: ^strings.Builder, ops: []rexcode_ir.Operation, options: ^rexcode_ir.Print_Options = nil) {…}
sbprint: disassemble a bare operation stream (a WASM expr) -- the reusable
core that print runs per block, and the mirror of the encoder's
encode_ops / decoder's decode_ops.
sbprint_wat ¶
sbprint_wat :: proc(sb: ^strings.Builder, m: Module, opts: WAT_Options = DEFAULT_WAT_OPTIONS) {…}
section_name ¶
section_name :: proc "contextless" (id: Section_Id) -> string {…}
take_block ¶
Detach the accumulated operations as a block body (and reset for the next).
tprint ¶
tprint :: proc(ops: []rexcode_ir.Operation, options: ^rexcode_ir.Print_Options = nil) -> string {…}
tprint: temp-allocated string of an operation stream (spot-checks / debugging).
tprint_wat ¶
tprint_wat :: proc(m: Module, opts: WAT_Options = DEFAULT_WAT_OPTIONS) -> string {…}
Result lives in the temp allocator.
valtype_name ¶
valtype_name :: proc "contextless" (t: Value_Type) -> string {…}
value_type_is_num ¶
value_type_is_num :: proc "contextless" (t: Value_Type) -> bool {…}
value_type_is_ref ¶
value_type_is_ref :: proc "contextless" (t: Value_Type) -> bool {…}
wat_write_const_expr ¶
wat_write_const_expr :: proc( sb: ^strings.Builder, m: Module, relocs: []Relocation, data: []u8, off: ^u32, unit: string, allocator: runtime.Allocator, ) {…}
Decode and fold a constant expression at off^ (advancing past its end).
wat_write_data ¶
wat_write_data :: proc(sb: ^strings.Builder, m: Module, unit: string) -> Parse_Error {…}
wat_write_elements ¶
wat_write_elements :: proc(sb: ^strings.Builder, m: Module, unit: string) -> Parse_Error {…}
wat_write_function ¶
wat_write_function :: proc(sb: ^strings.Builder, m: Module, func_relocs: []Relocation, f: rexcode_ir.Function, unit: string) {…}
wat_write_imports ¶
wat_write_imports :: proc(sb: ^strings.Builder, m: Module, unit: string) -> Parse_Error {…}
write_attribute ¶
write_attribute :: proc(sb: ^strings.Builder, o: ^rexcode_ir.Operand, opts: ^rexcode_ir.Print_Options) {…}
write_block_type ¶
A blocktype annotation. Returns nothing meaningful; kept a proc for symmetry
with the old printer. EMPTY prints nothing (the common block/loop case).
write_operand ¶
write_operand :: proc(sb: ^strings.Builder, o: ^rexcode_ir.Operand, opcode: Opcode, opts: ^rexcode_ir.Print_Options) {…}
One ir.Operand, dispatched on its shared kind (then, for ATTRIBUTE, on the
WASM Attr tag in aux). A leading space separates it from the mnemonic /
previous operand -- matching the old ISA printer's spacing.
write_operation ¶
write_operation :: proc(sb: ^strings.Builder, op: ^rexcode_ir.Operation, opts: ^rexcode_ir.Print_Options, module: runtime.Maybe($T=^Module)) {…}
write_sleb ¶
Signed LEB128. Advances *offset.
write_uleb ¶
Unsigned LEB128. Advances *offset. Caller guarantees buffer space.
write_uleb_padded5 ¶
Fixed 5-byte unsigned LEB128 (relocatable placeholder for 32-bit indices).
Procedure Groups
This section is empty.
Source Files
- builder.odin
- decoder.odin
- decoding_tables.odin
- encoder.odin
- encoding.odin
- encoding_table.odin
- leb.odin
- module.odin
- opcodes.odin
- operands.odin
- parse.odin
- print_wat.odin
- printer.odin
- reloc.odin
- wasm.odin
- write.odin
Generation Information
Generated with odin version dev-2026-07 (vendor "odin") Windows_amd64 @ 2026-07-20 21:55:30.818753600 +0000 UTC