proj-plbook-plChSingleIntermedLangs3

Zig stage1 compiler IR

Zig stage1 compiler: where the core is written in C++. See also Zig "stage2" compiler implemented entirely in Zig.

https://github.com/mikdusan/zig.internals/blob/master/internals.rst#common-ir-instruction-set discussion: https://lobste.rs/s/rpfhhs/zig_compiler_internals_2020

IrInstructionBinOp?:

<BinOp?> ::= <op1> <op_id> <op1> op_id one of: BoolOr?, BoolAnd?, CmpEq?, CmpNotEq?, CmpLessThan?, CmpGreaterThan?, CmpLessOrEq?, CmpGreaterOrEq?, BinOr?, BinXor?, BinAnd?, BitShiftLeftLossy?, BitShiftLeftExact?, BitShiftRightLossy?, BitShiftRightExact?, Add, AddWrap?, Sub, SubWrap?, Mult, MultWrap?, DivUnspecified?, DivExact?, DivTrunc?, DivFloor?, RemUnspecified?, RemRem?, RemMod?, ArrayCat?, ArrayMult?, MergeErrorSets?

IrInstructionConst?: <Const> ::= <value> value comptime value

IrInstructionConst? is a compile-time instruction.

terminators: Br
::= "goto" "$"<dest_block>

CondBr? <CondBr?> ::= "if" "(" <condition> ")" "$"<then_block> "else" "$"<else_block>

condition is evaluated as a bool then_block branch taken if condition == true else_block branch taken if condition == false

IrInstructionReturn? IrInstructionReturn? unconditionally transfers control flow back to the caller basic-block.

syntax:

    <Return> ::= "return" "{}"

Zig stage1 compiler ZIR

https://github.com/ziglang/zig/blob/57e1f6a89f044e731fe60ce15e98b496dcbaa74f/src/Zir.zig

    pub const Tag = enum(u8) {
        /// Arithmetic addition, asserts no integer overflow.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        add,
        /// Twos complement wrapping integer addition.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        addwrap,
        /// Saturating addition.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        add_sat,
        /// Arithmetic subtraction. Asserts no integer overflow.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        sub,
        /// Twos complement wrapping integer subtraction.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        subwrap,
        /// Saturating subtraction.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        sub_sat,
        /// Arithmetic multiplication. Asserts no integer overflow.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        mul,
        /// Twos complement wrapping integer multiplication.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        mulwrap,
        /// Saturating multiplication.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        mul_sat,
        /// Implements the `@divExact` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        div_exact,
        /// Implements the `@divFloor` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        div_floor,
        /// Implements the `@divTrunc` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        div_trunc,
        /// Implements the `@mod` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        mod,
        /// Implements the `@rem` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        rem,
        /// Ambiguously remainder division or modulus. If the computation would possibly have
        /// a different value depending on whether the operation is remainder division or modulus,
        /// a compile error is emitted. Otherwise the computation is performed.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        mod_rem,
        /// Integer shift-left. Zeroes are shifted in from the right hand side.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        shl,
        /// Implements the `@shlExact` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        shl_exact,
        /// Saturating shift-left.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        shl_sat,
        /// Integer shift-right. Arithmetic or logical depending on the signedness of
        /// the integer type.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        shr,
        /// Implements the `@shrExact` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        shr_exact,
        /// Declares a parameter of the current function. Used for:
        /// * debug info
        /// * checking shadowing against declarations in the current namespace
        /// * parameter type expressions referencing other parameters
        /// These occur in the block outside a function body (the same block as
        /// contains the func instruction).
        /// Uses the `pl_tok` field. Token is the parameter name, payload is a `Param`.
        param,
        /// Same as `param` except the parameter is marked comptime.
        param_comptime,
        /// Same as `param` except the parameter is marked anytype.
        /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name.
        param_anytype,
        /// Same as `param` except the parameter is marked both comptime and anytype.
        /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name.
        param_anytype_comptime,
        /// Array concatenation. `a ++ b`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        array_cat,
        /// Array multiplication `a ** b`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        array_mul,
        /// `[N]T` syntax. No source location provided.
        /// Uses the `bin` union field. lhs is length, rhs is element type.
        array_type,
        /// `[N:S]T` syntax. Source location is the array type expression node.
        /// Uses the `pl_node` union field. Payload is `ArrayTypeSentinel`.
        array_type_sentinel,
        /// `@Vector` builtin.
        /// Uses the `pl_node` union field with `Bin` payload.
        /// lhs is length, rhs is element type.
        vector_type,
        /// Given an array type, returns the element type.
        /// Uses the `un_node` union field.
        elem_type,
        /// Given a pointer to an indexable object, returns the len property. This is
        /// used by for loops. This instruction also emits a for-loop specific compile
        /// error if the indexable object is not indexable.
        /// Uses the `un_node` field. The AST node is the for loop node.
        indexable_ptr_len,
        /// Create a `anyframe->T` type.
        /// Uses the `un_node` field.
        anyframe_type,
        /// Type coercion. No source location attached.
        /// Uses the `bin` field.
        as,
        /// Type coercion to the function's return type.
        /// Uses the `pl_node` field. Payload is `As`. AST node could be many things.
        as_node,
        /// Bitwise AND. `&`
        bit_and,
        /// Reinterpret the memory representation of a value as a different type.
        /// Uses the pl_node field with payload `Bin`.
        bitcast,
        /// Bitwise NOT. `~`
        /// Uses `un_node`.
        bit_not,
        /// Bitwise OR. `|`
        bit_or,
        /// A labeled block of code, which can return a value.
        /// Uses the `pl_node` union field. Payload is `Block`.
        block,
        /// A list of instructions which are analyzed in the parent context, without
        /// generating a runtime block. Must terminate with an "inline" variant of
        /// a noreturn instruction.
        /// Uses the `pl_node` union field. Payload is `Block`.
        block_inline,
        /// Implements `suspend {...}`.
        /// Uses the `pl_node` union field. Payload is `Block`.
        suspend_block,
        /// Boolean NOT. See also `bit_not`.
        /// Uses the `un_node` field.
        bool_not,
        /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand
        /// is a block, which is evaluated if `lhs` is `true`.
        /// Uses the `bool_br` union field.
        bool_br_and,
        /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand
        /// is a block, which is evaluated if `lhs` is `false`.
        /// Uses the `bool_br` union field.
        bool_br_or,
        /// Return a value from a block.
        /// Uses the `break` union field.
        /// Uses the source information from previous instruction.
        @"break",
        /// Return a value from a block. This instruction is used as the terminator
        /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`.
        /// This instruction may also be used when it is known that there is only one
        /// break instruction in a block, and the target block is the parent.
        /// Uses the `break` union field.
        break_inline,
        /// Uses the `node` union field.
        breakpoint,
        /// Function call.
        /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
        call,
        /// `<`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_lt,
        /// `<=`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_lte,
        /// `==`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_eq,
        /// `>=`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_gte,
        /// `>`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_gt,
        /// `!=`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        cmp_neq,
        /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
        /// as type coercion from the new element type to the old element type.
        /// Uses the `bin` union field.
        /// LHS is destination element type, RHS is result pointer.
        coerce_result_ptr,
        /// Conditional branch. Splits control flow based on a boolean condition value.
        /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
        /// Payload is `CondBr`.
        condbr,
        /// Same as `condbr`, except the condition is coerced to a comptime value, and
        /// only the taken branch is analyzed. The then block and else block must
        /// terminate with an "inline" variant of a noreturn instruction.
        condbr_inline,
        /// An error set type definition. Contains a list of field names.
        /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
        error_set_decl,
        error_set_decl_anon,
        error_set_decl_func,
        /// Declares the beginning of a statement. Used for debug info.
        /// Uses the `dbg_stmt` union field. The line and column are offset
        /// from the parent declaration.
        dbg_stmt,
        /// Uses a name to identify a Decl and takes a pointer to it.
        /// Uses the `str_tok` union field.
        decl_ref,
        /// Uses a name to identify a Decl and uses it as a value.
        /// Uses the `str_tok` union field.
        decl_val,
        /// Load the value from a pointer. Assumes `x.*` syntax.
        /// Uses `un_node` field. AST node is the `x.*` syntax.
        load,
        /// Arithmetic division. Asserts no integer overflow.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        div,
        /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
        /// the provided index. Uses the `bin` union field. Source location is implied
        /// to be the same as the previous instruction.
        elem_ptr,
        /// Same as `elem_ptr` except also stores a source location node.
        /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
        elem_ptr_node,
        /// Same as `elem_ptr_node` except the index is stored immediately rather than
        /// as a reference to another ZIR instruction.
        /// Uses the `pl_node` union field. AST node is an element inside array initialization
        /// syntax. Payload is `ElemPtrImm`.
        elem_ptr_imm,
        /// Given an array, slice, or pointer, returns the element at the provided index.
        /// Uses the `bin` union field. Source location is implied to be the same
        /// as the previous instruction.
        elem_val,
        /// Same as `elem_val` except also stores a source location node.
        /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
        elem_val_node,
        /// Emits a compile error if the operand is not `void`.
        /// Uses the `un_node` field.
        ensure_result_used,
        /// Emits a compile error if an error is ignored.
        /// Uses the `un_node` field.
        ensure_result_non_error,
        /// Create a `E!T` type.
        /// Uses the `pl_node` field with `Bin` payload.
        error_union_type,
        /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
        error_value,
        /// Implements the `@export` builtin function, based on either an identifier to a Decl,
        /// or field access of a Decl. The thing being exported is the Decl.
        /// Uses the `pl_node` union field. Payload is `Export`.
        @"export",
        /// Implements the `@export` builtin function, based on a comptime-known value.
        /// The thing being exported is the comptime-known value which is the operand.
        /// Uses the `pl_node` union field. Payload is `ExportValue`.
        export_value,
        /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
        /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
        /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
        field_ptr,
        /// Given a struct or object that contains virtual fields, returns the named field.
        /// The field name is stored in string_bytes. Used by a.b syntax.
        /// This instruction also accepts a pointer.
        /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
        field_val,
        /// Given a pointer to a struct or object that contains virtual fields, returns the
        /// named field.  If there is no named field, searches in the type for a decl that
        /// matches the field name.  The decl is resolved and we ensure that it's a function
        /// which can accept the object as the first parameter, with one pointer fixup.  If
        /// all of that works, this instruction produces a special "bound function" value
        /// which contains both the function and the saved first parameter value.
        /// Bound functions may only be used as the function parameter to a `call` or
        /// `builtin_call` instruction.  Any other use is invalid zir and may crash the compiler.
        field_call_bind,
        /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
        /// to the named field. The field name is a comptime instruction. Used by @field.
        /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
        field_ptr_named,
        /// Given a struct or object that contains virtual fields, returns the named field.
        /// The field name is a comptime instruction. Used by @field.
        /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
        field_val_named,
        /// Given a pointer to a struct or object that contains virtual fields, returns the
        /// named field.  If there is no named field, searches in the type for a decl that
        /// matches the field name.  The decl is resolved and we ensure that it's a function
        /// which can accept the object as the first parameter, with one pointer fixup.  If
        /// all of that works, this instruction produces a special "bound function" value
        /// which contains both the function and the saved first parameter value.
        /// Bound functions may only be used as the function parameter to a `call` or
        /// `builtin_call` instruction.  Any other use is invalid zir and may crash the compiler.
        field_call_bind_named,
        /// Returns a function type, or a function instance, depending on whether
        /// the body_len is 0. Calling convention is auto.
        /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
        func,
        /// Same as `func` but has an inferred error set.
        func_inferred,
        /// Implements the `@import` builtin.
        /// Uses the `str_tok` field.
        import,
        /// Integer literal that fits in a u64. Uses the `int` union field.
        int,
        /// Arbitrary sized integer literal. Uses the `str` union field.
        int_big,
        /// A float literal that fits in a f64. Uses the float union value.
        float,
        /// A float literal that fits in a f128. Uses the `pl_node` union value.
        /// Payload is `Float128`.
        float128,
        /// Make an integer type out of signedness and bit count.
        /// Payload is `int_type`
        int_type,
        /// Return a boolean false if an optional is null. `x != null`
        /// Uses the `un_node` field.
        is_non_null,
        /// Return a boolean false if an optional is null. `x.* != null`
        /// Uses the `un_node` field.
        is_non_null_ptr,
        /// Return a boolean false if value is an error
        /// Uses the `un_node` field.
        is_non_err,
        /// Return a boolean false if dereferenced pointer is an error
        /// Uses the `un_node` field.
        is_non_err_ptr,
        /// A labeled block of code that loops forever. At the end of the body will have either
        /// a `repeat` instruction or a `repeat_inline` instruction.
        /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
        /// This ZIR instruction is needed because AIR does not (yet?) match ZIR, and Sema
        /// needs to emit more than 1 AIR block for this instruction.
        /// The payload is `Block`.
        loop,
        /// Sends runtime control flow back to the beginning of the current block.
        /// Uses the `node` field.
        repeat,
        /// Sends comptime control flow back to the beginning of the current block.
        /// Uses the `node` field.
        repeat_inline,
        /// Merge two error sets into one, `E1 || E2`.
        /// Uses the `pl_node` field with payload `Bin`.
        merge_error_sets,
        /// Turns an R-Value into a const L-Value. In other words, it takes a value,
        /// stores it in a memory location, and returns a const pointer to it. If the value
        /// is `comptime`, the memory location is global static constant data. Otherwise,
        /// the memory location is in the stack frame, local to the scope containing the
        /// instruction.
        /// Uses the `un_tok` union field.
        ref,
        /// Sends control flow back to the function's callee.
        /// Includes an operand as the return value.
        /// Includes an AST node source location.
        /// Uses the `un_node` union field.
        ret_node,
        /// Sends control flow back to the function's callee.
        /// The operand is a `ret_ptr` instruction, where the return value can be found.
        /// Includes an AST node source location.
        /// Uses the `un_node` union field.
        ret_load,
        /// Sends control flow back to the function's callee.
        /// Includes an operand as the return value.
        /// Includes a token source location.
        /// Uses the `un_tok` union field.
        /// The operand needs to get coerced to the function's return type.
        /// TODO rename this to `ret_tok` because coercion is now done unconditionally in Sema.
        ret_coerce,
        /// Sends control flow back to the function's callee.
        /// The return operand is `error.foo` where `foo` is given by the string.
        /// If the current function has an inferred error set, the error given by the
        /// name is added to it.
        /// Uses the `str_tok` union field.
        ret_err_value,
        /// A string name is provided which is an anonymous error set value.
        /// If the current function has an inferred error set, the error given by the
        /// name is added to it.
        /// Results in the error code. Note that control flow is not diverted with
        /// this instruction; a following 'ret' instruction will do the diversion.
        /// Uses the `str_tok` union field.
        ret_err_value_code,
        /// Create a pointer type that does not have a sentinel, alignment, address space, or bit range specified.
        /// Uses the `ptr_type_simple` union field.
        ptr_type_simple,
        /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range.
        /// Uses the `ptr_type` union field.
        ptr_type,
        /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
        /// Returns a pointer to the subslice.
        /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
        slice_start,
        /// Slice operation `array_ptr[start..end]`. No sentinel.
        /// Returns a pointer to the subslice.
        /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`.
        slice_end,
        /// Slice operation `array_ptr[start..end:sentinel]`.
        /// Returns a pointer to the subslice.
        /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`.
        slice_sentinel,
        /// Write a value to a pointer. For loading, see `load`.
        /// Source location is assumed to be same as previous instruction.
        /// Uses the `bin` union field.
        store,
        /// Same as `store` except provides a source location.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        store_node,
        /// Same as `store` but the type of the value being stored will be used to infer
        /// the block type. The LHS is the pointer to store to.
        /// Uses the `bin` union field.
        /// If the pointer is none, it means this instruction has been elided in
        /// AstGen, but AstGen was unable to actually omit it from the ZIR code.
        store_to_block_ptr,
        /// Same as `store` but the type of the value being stored will be used to infer
        /// the pointer type.
        /// Uses the `bin` union field - Astgen.zig depends on the ability to change
        /// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr`
        /// without changing the data.
        store_to_inferred_ptr,
        /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
        /// Uses the `str` union field.
        str,
        /// Arithmetic negation. Asserts no integer overflow.
        /// Same as sub with a lhs of 0, split into a separate instruction to save memory.
        /// Uses `un_node`.
        negate,
        /// Twos complement wrapping integer negation.
        /// Same as subwrap with a lhs of 0, split into a separate instruction to save memory.
        /// Uses `un_node`.
        negate_wrap,
        /// Returns the type of a value.
        /// Uses the `un_node` field.
        typeof,
        /// Given a value, look at the type of it, which must be an integer type.
        /// Returns the integer type for the RHS of a shift operation.
        /// Uses the `un_node` field.
        typeof_log2_int_type,
        /// Given an integer type, returns the integer type for the RHS of a shift operation.
        /// Uses the `un_node` field.
        log2_int_type,
        /// Asserts control-flow will not reach this instruction (`unreachable`).
        /// Uses the `unreachable` union field.
        @"unreachable",
        /// Bitwise XOR. `^`
        /// Uses the `pl_node` union field. Payload is `Bin`.
        xor,
        /// Create an optional type '?T'
        /// Uses the `un_node` field.
        optional_type,
        /// ?T => T with safety.
        /// Given an optional value, returns the payload value, with a safety check that
        /// the value is non-null. Used for `orelse`, `if` and `while`.
        /// Uses the `un_node` field.
        optional_payload_safe,
        /// ?T => T without safety.
        /// Given an optional value, returns the payload value. No safety checks.
        /// Uses the `un_node` field.
        optional_payload_unsafe,
        /// *?T => *T with safety.
        /// Given a pointer to an optional value, returns a pointer to the payload value,
        /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.
        /// Uses the `un_node` field.
        optional_payload_safe_ptr,
        /// *?T => *T without safety.
        /// Given a pointer to an optional value, returns a pointer to the payload value.
        /// No safety checks.
        /// Uses the `un_node` field.
        optional_payload_unsafe_ptr,
        /// E!T => T with safety.
        /// Given an error union value, returns the payload value, with a safety check
        /// that the value is not an error. Used for catch, if, and while.
        /// Uses the `un_node` field.
        err_union_payload_safe,
        /// E!T => T without safety.
        /// Given an error union value, returns the payload value. No safety checks.
        /// Uses the `un_node` field.
        err_union_payload_unsafe,
        /// *E!T => *T with safety.
        /// Given a pointer to an error union value, returns a pointer to the payload value,
        /// with a safety check that the value is not an error. Used for catch, if, and while.
        /// Uses the `un_node` field.
        err_union_payload_safe_ptr,
        /// *E!T => *T without safety.
        /// Given a pointer to a error union value, returns a pointer to the payload value.
        /// No safety checks.
        /// Uses the `un_node` field.
        err_union_payload_unsafe_ptr,
        /// E!T => E without safety.
        /// Given an error union value, returns the error code. No safety checks.
        /// Uses the `un_node` field.
        err_union_code,
        /// *E!T => E without safety.
        /// Given a pointer to an error union value, returns the error code. No safety checks.
        /// Uses the `un_node` field.
        err_union_code_ptr,
        /// Takes a *E!T and raises a compiler error if T != void
        /// Uses the `un_tok` field.
        ensure_err_payload_void,
        /// An enum literal. Uses the `str_tok` union field.
        enum_literal,
        /// A switch expression. Uses the `pl_node` union field.
        /// AST node is the switch, payload is `SwitchBlock`.
        switch_block,
        /// Produces the value that will be switched on. For example, for
        /// integers, it returns the integer with no modifications. For tagged unions, it
        /// returns the active enum tag.
        /// Uses the `un_node` union field.
        switch_cond,
        /// Same as `switch_cond`, except the input operand is a pointer to
        /// what will be switched on.
        /// Uses the `un_node` union field.
        switch_cond_ref,
        /// Produces the capture value for a switch prong.
        /// Uses the `switch_capture` field.
        switch_capture,
        /// Produces the capture value for a switch prong.
        /// Result is a pointer to the value.
        /// Uses the `switch_capture` field.
        switch_capture_ref,
        /// Produces the capture value for a switch prong.
        /// The prong is one of the multi cases.
        /// Uses the `switch_capture` field.
        switch_capture_multi,
        /// Produces the capture value for a switch prong.
        /// The prong is one of the multi cases.
        /// Result is a pointer to the value.
        /// Uses the `switch_capture` field.
        switch_capture_multi_ref,
        /// Produces the capture value for the else/'_' switch prong.
        /// Uses the `switch_capture` field.
        switch_capture_else,
        /// Produces the capture value for the else/'_' switch prong.
        /// Result is a pointer to the value.
        /// Uses the `switch_capture` field.
        switch_capture_else_ref,
        /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
        /// initialization expression, and emits compile errors for duplicate fields
        /// as well as missing fields, if applicable.
        /// This instruction asserts that there is at least one field_ptr instruction,
        /// because it must use one of them to find out the struct type.
        /// Uses the `pl_node` field. Payload is `Block`.
        validate_struct_init,
        /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an
        /// array initialization expression, and emits a compile error if the number of
        /// elements does not match the array type.
        /// This instruction asserts that there is at least one `elem_ptr_imm` instruction,
        /// because it must use one of them to find out the array type.
        /// Uses the `pl_node` field. Payload is `Block`.
        validate_array_init,
        /// A struct literal with a specified type, with no fields.
        /// Uses the `un_node` field.
        struct_init_empty,
        /// Given a struct or union, and a field name as a string index,
        /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.
        field_type,
        /// Given a struct or union, and a field name as a Ref,
        /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
        field_type_ref,
        /// Finalizes a typed struct or union initialization, performs validation, and returns the
        /// struct or union value.
        /// Uses the `pl_node` field. Payload is `StructInit`.
        struct_init,
        /// Struct initialization syntax, make the result a pointer.
        /// Uses the `pl_node` field. Payload is `StructInit`.
        struct_init_ref,
        /// Struct initialization without a type.
        /// Uses the `pl_node` field. Payload is `StructInitAnon`.
        struct_init_anon,
        /// Anonymous struct initialization syntax, make the result a pointer.
        /// Uses the `pl_node` field. Payload is `StructInitAnon`.
        struct_init_anon_ref,
        /// Array initialization syntax.
        /// Uses the `pl_node` field. Payload is `MultiOp`.
        array_init,
        /// Anonymous array initialization syntax.
        /// Uses the `pl_node` field. Payload is `MultiOp`.
        array_init_anon,
        /// Array initialization syntax, make the result a pointer.
        /// Uses the `pl_node` field. Payload is `MultiOp`.
        array_init_ref,
        /// Anonymous array initialization syntax, make the result a pointer.
        /// Uses the `pl_node` field. Payload is `MultiOp`.
        array_init_anon_ref,
        /// Given a pointer to a union and a comptime known field name, activates that field
        /// and returns a pointer to it.
        /// Uses the `pl_node` field. Payload is `UnionInitPtr`.
        union_init_ptr,
        /// Implements the `@typeInfo` builtin. Uses `un_node`.
        type_info,
        /// Implements the `@sizeOf` builtin. Uses `un_node`.
        size_of,
        /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
        bit_size_of,
        /// Implements the `@fence` builtin. Uses `un_node`.
        fence,
        /// Implement builtin `@ptrToInt`. Uses `un_node`.
        /// Convert a pointer to a `usize` integer.
        ptr_to_int,
        /// Implement builtin `@errToInt`. Uses `un_node`.
        error_to_int,
        /// Implement builtin `@intToError`. Uses `un_node`.
        int_to_error,
        /// Emit an error message and fail compilation.
        /// Uses the `un_node` field.
        compile_error,
        /// Changes the maximum number of backwards branches that compile-time
        /// code execution can use before giving up and making a compile error.
        /// Uses the `un_node` union field.
        set_eval_branch_quota,
        /// Converts an enum value into an integer. Resulting type will be the tag type
        /// of the enum. Uses `un_node`.
        enum_to_int,
        /// Implement builtin `@alignOf`. Uses `un_node`.
        align_of,
        /// Implement builtin `@boolToInt`. Uses `un_node`.
        bool_to_int,
        /// Implement builtin `@embedFile`. Uses `un_node`.
        embed_file,
        /// Implement builtin `@errorName`. Uses `un_node`.
        error_name,
        /// Implement builtin `@panic`. Uses `un_node`.
        panic,
        /// Implement builtin `@setAlignStack`. Uses `un_node`.
        set_align_stack,
        /// Implement builtin `@setCold`. Uses `un_node`.
        set_cold,
        /// Implement builtin `@setFloatMode`. Uses `un_node`.
        set_float_mode,
        /// Implement builtin `@setRuntimeSafety`. Uses `un_node`.
        set_runtime_safety,
        /// Implement builtin `@sqrt`. Uses `un_node`.
        sqrt,
        /// Implement builtin `@sin`. Uses `un_node`.
        sin,
        /// Implement builtin `@cos`. Uses `un_node`.
        cos,
        /// Implement builtin `@exp`. Uses `un_node`.
        exp,
        /// Implement builtin `@exp2`. Uses `un_node`.
        exp2,
        /// Implement builtin `@log`. Uses `un_node`.
        log,
        /// Implement builtin `@log2`. Uses `un_node`.
        log2,
        /// Implement builtin `@log10`. Uses `un_node`.
        log10,
        /// Implement builtin `@fabs`. Uses `un_node`.
        fabs,
        /// Implement builtin `@floor`. Uses `un_node`.
        floor,
        /// Implement builtin `@ceil`. Uses `un_node`.
        ceil,
        /// Implement builtin `@trunc`. Uses `un_node`.
        trunc,
        /// Implement builtin `@round`. Uses `un_node`.
        round,
        /// Implement builtin `@tagName`. Uses `un_node`.
        tag_name,
        /// Implement builtin `@Type`. Uses `un_node`.
        reify,
        /// Implement builtin `@typeName`. Uses `un_node`.
        type_name,
        /// Implement builtin `@Frame`. Uses `un_node`.
        frame_type,
        /// Implement builtin `@frameSize`. Uses `un_node`.
        frame_size,
        /// Implements the `@floatToInt` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        float_to_int,
        /// Implements the `@intToFloat` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        int_to_float,
        /// Implements the `@intToPtr` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        int_to_ptr,
        /// Converts an integer into an enum value.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        int_to_enum,
        /// Convert a larger float type to any other float type, possibly causing
        /// a loss of precision.
        /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
        /// Payload is `Bin` with lhs as the dest type, rhs the operand.
        float_cast,
        /// Implements the `@intCast` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        /// Convert an integer value to another integer type, asserting that the destination type
        /// can hold the same mathematical value.
        int_cast,
        /// Implements the `@errSetCast` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        err_set_cast,
        /// Implements the `@ptrCast` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        ptr_cast,
        /// Implements the `@truncate` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
        truncate,
        /// Implements the `@alignCast` builtin.
        /// Uses `pl_node` with payload `Bin`. `lhs` is dest alignment, `rhs` is operand.
        align_cast,
        /// Implements the `@hasDecl` builtin.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        has_decl,
        /// Implements the `@hasField` builtin.
        /// Uses the `pl_node` union field. Payload is `Bin`.
        has_field,
        /// Implements the `@clz` builtin. Uses the `un_node` union field.
        clz,
        /// Implements the `@ctz` builtin. Uses the `un_node` union field.
        ctz,
        /// Implements the `@popCount` builtin. Uses the `un_node` union field.
        pop_count,
        /// Implements the `@byteSwap` builtin. Uses the `un_node` union field.
        byte_swap,
        /// Implements the `@bitReverse` builtin. Uses the `un_node` union field.
        bit_reverse,
        /// Implements the `@bitOffsetOf` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        bit_offset_of,
        /// Implements the `@offsetOf` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        offset_of,
        /// Implements the `@cmpxchgStrong` builtin.
        /// Uses the `pl_node` union field with payload `Cmpxchg`.
        cmpxchg_strong,
        /// Implements the `@cmpxchgWeak` builtin.
        /// Uses the `pl_node` union field with payload `Cmpxchg`.
        cmpxchg_weak,
        /// Implements the `@splat` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        splat,
        /// Implements the `@reduce` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        reduce,
        /// Implements the `@shuffle` builtin.
        /// Uses the `pl_node` union field with payload `Shuffle`.
        shuffle,
        /// Implements the `@select` builtin.
        /// Uses the `pl_node` union field with payload `Select`.
        select,
        /// Implements the `@atomicLoad` builtin.
        /// Uses the `pl_node` union field with payload `Bin`.
        atomic_load,
        /// Implements the `@atomicRmw` builtin.
        /// Uses the `pl_node` union field with payload `AtomicRmw`.
        atomic_rmw,
        /// Implements the `@atomicStore` builtin.
        /// Uses the `pl_node` union field with payload `AtomicStore`.
        atomic_store,
        /// Implements the `@mulAdd` builtin.
        /// Uses the `pl_node` union field with payload `MulAdd`.
        mul_add,
        /// Implements the `@call` builtin.
        /// Uses the `pl_node` union field with payload `BuiltinCall`.
        builtin_call,
        /// Given a type and a field name, returns a pointer to the field type.
        /// Assumed to be part of a `@fieldParentPtr` builtin call.
        /// Uses the `bin` union field. LHS is type, RHS is field name.
        field_ptr_type,
        /// Implements the `@fieldParentPtr` builtin.
        /// Uses the `pl_node` union field with payload `FieldParentPtr`.
        field_parent_ptr,
        /// Implements the `@memcpy` builtin.
        /// Uses the `pl_node` union field with payload `Memcpy`.
        memcpy,
        /// Implements the `@memset` builtin.
        /// Uses the `pl_node` union field with payload `Memset`.
        memset,
        /// Implements the `@minimum` builtin.
        /// Uses the `pl_node` union field with payload `Bin`
        minimum,
        /// Implements the `@maximum` builtin.
        /// Uses the `pl_node` union field with payload `Bin`
        maximum,
        /// Implements the `@asyncCall` builtin.
        /// Uses the `pl_node` union field with payload `AsyncCall`.
        builtin_async_call,
        /// Implements the `@cImport` builtin.
        /// Uses the `pl_node` union field with payload `Block`.
        c_import,
        /// Allocates stack local memory.
        /// Uses the `un_node` union field. The operand is the type of the allocated object.
        /// The node source location points to a var decl node.
        alloc,
        /// Same as `alloc` except mutable.
        alloc_mut,
        /// Allocates comptime-mutable memory.
        /// Uses the `un_node` union field. The operand is the type of the allocated object.
        /// The node source location points to a var decl node.
        alloc_comptime,
        /// Same as `alloc` except the type is inferred.
        /// Uses the `node` union field.
        alloc_inferred,
        /// Same as `alloc_inferred` except mutable.
        alloc_inferred_mut,
        /// Same as `alloc_comptime` except the type is inferred.
        alloc_inferred_comptime,
        /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
        /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
        /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
        /// is the allocation that needs to have its type inferred.
        /// Uses the `un_node` field. The AST node is the var decl.
        resolve_inferred_alloc,
        /// Implements `resume` syntax. Uses `un_node` field.
        @"resume",
        @"await",
        await_nosuspend,
        /// When a type or function refers to a comptime value from an outer
        /// scope, that forms a closure over comptime value.  The outer scope
        /// will record a capture of that value, which encodes its current state
        /// and marks it to persist.  Uses `un_tok` field.  Operand is the
        /// instruction value to capture.
        closure_capture,
        /// The inner scope of a closure uses closure_get to retrieve the value
        /// stored by the outer scope.  Uses `inst_node` field.  Operand is the
        /// closure_capture instruction ref.
        closure_get,
        /// The ZIR instruction tag is one of the `Extended` ones.
        /// Uses the `extended` union field.
        extended,

See also https://media.handmade-seattle.com/practical-data-oriented-design/ , https://lobste.rs/s/vbiu6y/practical_guide_applying_data_oriented

---

Zig AST, ZIR, AIR

https://mitchellh.com/zig

---

Passerine VM

Opcodes:

" / Load a constant. Con = 0, / Load uninitialized Data. NotInit?, / Delete a value off the stack. Del, / Calls out to a Rust function via FFI FFICall, / Copies topmost value on the stack. Copy, / Moves a variable onto the heap. Capture, / Save a constant into a variable. Save, / Save a value to a captured variable. SaveCap?, / Push a copy of a variable onto the stack. Load, / Load a copy of a captured variable. LoadCap?, / Call a function. Call, / Return from a function. Return, / Creates a closure over the current local environment. Closure, / Prints a value. Print, / Constructs a label. Label, Constructs a tuple. Tuple, / Destructures atomic data by asserting it matches exactly. UnData?, / Destructures a label. UnLabel?, / Sestructures a tuple. UnTuple?, " -- https://github.com/vrtbl/passerine/blob/master/src/common/opcode.rs

---

Microvium IL

Links:

The "registers" mentioned below appear to be (from typedef struct vm_TsRegisters? in microvium_internals.h, which mentions that this occupies 20 bytes on a 32-bit machine): " uint16_t* pFrameBase; uint16_t* pStackPointer; LongPtr? lpProgramCounter; Note: I previously used to infer the location of the arguments based on the number of values PUSHed by a CALL instruction to preserve the activation state (i.e. 3 words). But now that distance is dynamic, so we need and explicit register. Value* pArgs; uint16_t argCountAndFlags; Lower 8 bits are argument count, upper 8 bits are vm_TeActivationFlags? Value scope; Closure scope "

There are actually two ILs, called "IL" (higher) and "Bytecode" (lower). The IL ops are (mostly quoted from https://github.com/coder-mike/microvium/blob/main/doc/internals/instruction-set/script/instruction-set.js ):

Array ops:

ArrayNew? (operands: [ ], stackChange: 1): Creates a new JavaScript? array; pushes a pointer to the new array

ArrayGet? (operands: [The index of the array slot to access ], stackChange: 0): Gets the item at the given index of a fixed-length array. Pops the array to read from, and pushes the value copied from the array element at the operand.

ArraySet? (operands: [The index of the array slot to access ], stackChange: -2): Sets the item at the given index of a fixed-length array. Pops the value to assign into the array slot, and the array to write to.

Unary and binary ops:

BinOp? (operands: [which_operation ], stackChange: -1): One of +, -, /, DIVIDE_AND_TRUNC, %, *, , &,

, >>, >>>, <<, ^, ===, !==, >, <, >=, <=. These operations have the same meaning as the corresponding operation in JavaScript?, except DIVIDE_AND_TRUNC, which is equivalent to the JavaScript? `left / right 0` and is used to represent integer division. Pops the two operands and pushes the result.

The following op is listed in the built il-opcodes.ts but not in instruction-set.js:

From il.ts, the unary operations appear to be one of: - + ! ~ typeof typeCodeOf

Control flow:

Branch (operands: [LabelOperand?, LabelOperand?], stackChange: -1): Jumps the program counter to one of two target labels (blocks) depending on the truthiness of the condition value. Pops the condition. Note: the bytecode representations of the branch instruction only have a single target, corresponding to the \`true\` path. If the label is false, control falls through to the next instruction. A full IL branch instruction can be implemented by a Branch bytecode instruction followed by a Jump bytecode instruction. Note: target labels must reference blocks in the same function as the branch instruction

Call (operands: ['CountOperand?' ], stackChange: variadic): Function call. For the basic function call, the callee must push the function reference and each of the arguments onto the stack in order. The CALL operation pushes 3-4 words to the stack to save the current registers, and then passes control to the given function. The CALL operation also sets flags in the VM state to indicate what dynamic elements were pushed onto the stack. When the matching RETURN operation is later executed, it will consult these flags to decide what to pop off the stack (so far, this is only the \`scope\` register).

Control flow IL ops listed in the built il-opcodes.ts but not in instruction-set.js:

Creating and deleting scopes and closures:

ScopePush? (operands: [The number of variable slots to allocate in the scope ], stackChange: 0): Push a new closure scope (environment record) to the scope stack. Creates a new closure scope with the given number of slots and with its \`outerScope\` set to the current \`scope\` register value. The scope register is then set to point to the newly-created scope so that future [LoadScoped?](#LoadScoped?) or [StoreScoped?](#StoreScoped?) will implicitly access the new scope. Closure scopes are internally just fixed-length arrays and take \`4 + 2 × slotCount\` bytes of space on the heap in total. Note: this pushes the scope to the closure scope chain/stack, not the VM call-stack stack. Note: the \`scope\` VM register is saved across function calls. A called function does not inherit the \`scope\` of its caller, it gets the scope of its [Closure](#ClosureNew?), or \`undefined\` if the function is not called via a closure. See also: [ClosureNew?](#ClosureNew?), [ScopePop?](#ScopePop?), [ScopeClone?](#ScopeClone?).

ClosureNew? (operands: [ ], stackChange: 0): Creates a new closure object. A Closure in Microvium is a callable type which internally references a target function, a scope (See TsClosure? structure) Calling the closure is effectively calling the given target function, except that the scope register of the VM will adopt the scope value from the closure. A new scope can be created using [ScopePush?](#ScopePush?). A closure takes 6 bytes on the runtime heap, including the allocation header. Closures are logically immutable, in the sense that there are no operators that can change one of the 2 internal fields of a closure (scope, target). Closure equality is compared by reference equality. Pops the function target to bind the current scope to, pushes the new closure.

ScopePop? (operands: [ ], stackChange: 0): Pops the top closure scope off the scope stack. This is the inverse of [ScopePush?](#ScopePush?). It removes the top scope from the closure scope chain and sets the \`scope\` register to instead point to its \`outerScope\`. Note: when an IL function [Return](#Return) to its caller, the caller's scope is recovered along with the other saved registers, so you do not need to \`ScopePop?\` at the end of a function. This instruction is intended for the context of loops with nested closures, since each iteration of the loop requires a fresh closure scope for the variables in the loop body, and the previous one must be popped off the closure scope stack. Note: It is illegal to invoke this instruction when there is no closure scope on the scope stack. See also [ScopePush?](#ScopePush?), [ScopeClone?](#ScopeClone?)

ScopeClone? (operands: [ ], stackChange: 0): Clones the top closure scope and sets it as the active scope. This is really just to implement \`let\` bindings in for loops that contain closures. See [CreatePerIterationEnvironment?](https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-createperiterationenvironment) Note: It is illegal to invoke this instruction when there is no closure scope on the scope stack. See also [ScopePush?](#ScopePush?), [ScopePop?](#ScopePop?)

Accessing variables in scopes:

StoreScoped? (operands: [index of the closure-scoped slot to access ], stackChange: -1): Pops the top value off the stack and stores it in the given closure scope slot. This is similar to [StoreVar?](#StoreVar?) except instead of storing the value in the current stack frame, it stores it in the current closure \`scope\` (see [ScopePush?](#ScopePush?)). The index is permitted to "overflow" the current closure scope into the next outer scope, repeatedly. For example, if the current scope has 5 slots (created with \`ScopePush?(5)\`) then \`StoreScoped?(4)\` accesses the 5th variable slot in the current scope but \`StoreScoped?(5)\` accesses the first slot of the parent scope, etc. See also [ScopePush?](#ScopePush?), [LoadScoped?](#LoadScoped?). Pops the value to store in the closure scope slot.

LoadScoped? (operands: [index of the closure-scoped slot to access ], stackChange: 1): Fetches the value from the given closure scope slot and pushes it onto the stack. Pushes the Value loaded from the closure scope slot.

Data IL ops Data IL ops listed in the built il-opcodes.ts but not in instruction-set.js: