pub enum Inst {
Show 200 variants
Nop {},
Mov {
dst: Reg,
src: Reg,
},
LoadConst {
dst: Reg,
k: ConstId,
},
DLoadConst {
dst: Reg,
k: ConstId,
},
LoadInt {
dst: Reg,
val: i32,
ty: IntTy,
},
DLoadInt {
dst: Reg,
val: i32,
},
LoadBool {
dst: Reg,
val: bool,
},
LoadNil {
dst: Reg,
},
LoadImport {
dst: Reg,
import: ImportId,
},
GetGlobal {
dst: Reg,
global: GlobalId,
},
SetGlobal {
global: GlobalId,
src: Reg,
},
IAdd {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
ISub {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IMul {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IDiv {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IRem {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IFloorDiv {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IFloorMod {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IAnd {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IOr {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IXor {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IShl {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IShr {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IMin {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IMax {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
INeg {
dst: Reg,
src: Reg,
op: IntOp,
},
IBitNot {
dst: Reg,
src: Reg,
op: IntOp,
},
IAbs {
dst: Reg,
src: Reg,
op: IntOp,
},
IPow {
dst: Reg,
lhs: Reg,
rhs: Reg,
op: IntOp,
},
IEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
INe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
ILt {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
ILe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
IGt {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
IGe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: IntTy,
},
FAdd {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FSub {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FMul {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FDiv {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FRem {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FIeeeRem {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FMin {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FMax {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FFma {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FNeg {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FAbs {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FSqrt {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FFloor {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FCeil {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FTrunc {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FRound {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FRoundEven {
dst: Reg,
src: Reg,
ty: FloatTy,
},
FEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FNe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FLt {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FLe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FGt {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FGe {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FPow {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
FTotalCmp {
dst: Reg,
lhs: Reg,
rhs: Reg,
ty: FloatTy,
},
BNot {
dst: Reg,
src: Reg,
},
BAnd {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
BOr {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
BXor {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CNe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CLt {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CLe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CGt {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
CGe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
RefEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
IntCast {
dst: Reg,
src: Reg,
conv: IntConv,
},
Zext {
dst: Reg,
src: Reg,
pair: IntPair,
},
Sext {
dst: Reg,
src: Reg,
pair: IntPair,
},
Trunc {
dst: Reg,
src: Reg,
pair: IntPair,
},
IntToF32 {
dst: Reg,
src: Reg,
ty: IntTy,
},
IntToF64 {
dst: Reg,
src: Reg,
ty: IntTy,
},
F32ToInt {
dst: Reg,
src: Reg,
conv: FloatConv,
},
F64ToInt {
dst: Reg,
src: Reg,
conv: FloatConv,
},
F32ToF64 {
dst: Reg,
src: Reg,
},
F64ToF32 {
dst: Reg,
src: Reg,
},
FloatToBits {
dst: Reg,
src: Reg,
ty: IntTy,
},
BitsToFloat {
dst: Reg,
src: Reg,
ty: IntTy,
},
CharFromU32 {
dst: Reg,
src: Reg,
},
CharToU32 {
dst: Reg,
src: Reg,
},
BoolToInt {
dst: Reg,
src: Reg,
ty: IntTy,
},
DAdd {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DSub {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DMul {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DDiv {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DRem {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DFloorDiv {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DFloorMod {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DAnd {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DOr {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DXor {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DShl {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DShr {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DNeg {
dst: Reg,
src: Reg,
pol: Policy,
},
DBitNot {
dst: Reg,
src: Reg,
pol: Policy,
},
DEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DNe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DLt {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DLe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DGt {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DGe {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
DTruthy {
dst: Reg,
src: Reg,
},
DConcat {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
ToDyn {
dst: Reg,
src: Reg,
from: Prim,
},
FromDyn {
dst: Reg,
src: Reg,
to: Prim,
},
TypeOf {
dst: Reg,
src: Reg,
},
IsKind {
dst: Reg,
src: Reg,
kind: Kind,
},
IsType {
dst: Reg,
src: Reg,
ty: TypeRef,
},
Cast {
dst: Reg,
src: Reg,
ty: TypeRef,
},
DGetIndex {
dst: Reg,
obj: Reg,
key: Reg,
},
DSetIndex {
obj: Reg,
key: Reg,
src: Reg,
},
GetProp {
dst: Reg,
obj: Reg,
name: NameRef,
},
SetProp {
obj: Reg,
name: NameRef,
src: Reg,
},
HasProp {
dst: Reg,
obj: Reg,
name: NameRef,
},
DCall {
dst: Reg,
callee: Reg,
argc: u8,
},
DIterNew {
dst: Reg,
src: Reg,
},
DLen {
dst: Reg,
src: Reg,
},
DNot {
dst: Reg,
src: Reg,
},
DPow {
dst: Reg,
lhs: Reg,
rhs: Reg,
pol: Policy,
},
DAbs {
dst: Reg,
src: Reg,
pol: Policy,
},
DSepIndex {
dst: Reg,
obj: Reg,
key: Reg,
},
DSepProp {
dst: Reg,
obj: Reg,
name: NameRef,
},
DCallShape {
dst: Reg,
callee: Reg,
shape: ShapeId,
},
DParamRef {
dst: Reg,
callee: Reg,
pos: Reg,
},
DParamRefNamed {
dst: Reg,
callee: Reg,
name: NameRef,
},
ErrPayload {
dst: Reg,
src: Reg,
},
Jmp {
target: Target,
},
JmpIf {
cond: Reg,
target: Target,
},
JmpIfNot {
cond: Reg,
target: Target,
},
Switch {
src: Reg,
table: TableId,
ty: IntTy,
},
Call {
dst: Reg,
func: FuncId,
argc: u8,
},
CallIndirect {
dst: Reg,
callee: Reg,
argc: u8,
},
CallImport {
dst: Reg,
import: ImportId,
argc: u8,
},
TailCall {
func: FuncId,
args: Reg,
argc: u8,
},
TailCallIndirect {
callee: Reg,
args: Reg,
argc: u8,
},
Ret {
src: Reg,
},
RetVoid {},
Throw {
src: Reg,
},
ErrCode {
dst: Reg,
src: Reg,
},
Safepoint {},
Unreachable {},
Raise {
src: Reg,
kind: ErrorKind,
},
MakeClosure {
dst: Reg,
func: FuncId,
},
GetUpval {
dst: Reg,
idx: UpvalIdx,
},
NewCell {
dst: Reg,
src: Reg,
ty: TypeRef,
},
CellGet {
dst: Reg,
cell: Reg,
},
CellSet {
cell: Reg,
src: Reg,
},
NewRef {
dst: Reg,
src: Reg,
},
DRefIndex {
dst: Reg,
obj: Reg,
key: Reg,
},
DRefProp {
dst: Reg,
obj: Reg,
name: NameRef,
},
DBindIndex {
obj: Reg,
key: Reg,
src: Reg,
},
DBindProp {
obj: Reg,
name: NameRef,
src: Reg,
},
DUnrefIndex {
obj: Reg,
key: Reg,
},
DUnrefProp {
obj: Reg,
name: NameRef,
},
NewStruct {
dst: Reg,
ty: TypeRef,
},
GetField {
dst: Reg,
obj: Reg,
field: FieldIdx,
},
SetField {
obj: Reg,
field: FieldIdx,
src: Reg,
},
NewArray {
dst: Reg,
len: Reg,
ty: TypeRef,
},
ArrayLen {
dst: Reg,
arr: Reg,
},
ArrayGet {
dst: Reg,
arr: Reg,
idx: Reg,
},
ArraySet {
arr: Reg,
idx: Reg,
src: Reg,
},
ArrayPush {
arr: Reg,
src: Reg,
},
ArrayPop {
dst: Reg,
arr: Reg,
},
NewMap {
dst: Reg,
ty: TypeRef,
},
MapLen {
dst: Reg,
map: Reg,
},
MapGet {
dst: Reg,
map: Reg,
key: Reg,
},
MapFind {
dst: Reg,
map: Reg,
key: Reg,
},
MapHas {
dst: Reg,
map: Reg,
key: Reg,
},
MapSet {
map: Reg,
key: Reg,
src: Reg,
},
MapDel {
map: Reg,
key: Reg,
},
MapPush {
map: Reg,
src: Reg,
},
IterNew {
dst: Reg,
src: Reg,
},
IterNext {
has: Reg,
iter: Reg,
val: Reg,
},
IterKey {
dst: Reg,
iter: Reg,
},
Dup {
dst: Reg,
src: Reg,
},
StrLen {
dst: Reg,
s: Reg,
},
StrConcat {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
StrConcatN {
dst: Reg,
first: Reg,
count: u8,
},
StrEq {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
StrCmp {
dst: Reg,
lhs: Reg,
rhs: Reg,
},
StrSlice {
dst: Reg,
s: Reg,
range: Reg,
utf8: bool,
},
StrByte {
dst: Reg,
s: Reg,
idx: Reg,
},
CoroNew {
dst: Reg,
func: FuncId,
argc: u8,
},
CoroNewIndirect {
dst: Reg,
callee: Reg,
argc: u8,
},
Yield {
dst: Reg,
src: Reg,
},
Await {
dst: Reg,
src: Reg,
},
Resume {
dst: Reg,
coro: Reg,
src: Reg,
},
ResumeThrow {
dst: Reg,
coro: Reg,
src: Reg,
},
CoroStatus {
dst: Reg,
coro: Reg,
},
CoroCurrent {
dst: Reg,
},
YieldKv {
dst: Reg,
key: Reg,
src: Reg,
},
CoroClose {
dst: Reg,
coro: Reg,
src: Reg,
},
CoroKey {
dst: Reg,
coro: Reg,
},
CoroResult {
dst: Reg,
coro: Reg,
},
Spawn {
dst: Reg,
callee: Reg,
argc: u8,
},
}Expand description
One LSB instruction, decoded.
Every variant is eight bytes and Copy. Field order is display
order; Opcode::fields gives each field’s slot in the encoded
word. The normative semantics of every instruction, every operand
type rule, and every error it can raise are in specs/LSB.md;
each variant’s documentation summarizes them.
Window operands. Instructions that need more registers than
eight bytes hold read them from consecutive registers: a call’s
arguments are dst+1 ..= dst+argc, a closure’s captures follow
its destination, str_slice reads its end index from range+1.
The enum is deliberately exhaustive: every execution tier must implement every instruction, and a new one is a format change.
§Examples
use bytecode_lang::{Inst, IntOp, IntTy, Opcode, Reg};
let add = Inst::IAdd { op: IntOp::new(IntTy::I64), dst: Reg(2), lhs: Reg(0), rhs: Reg(1) };
assert_eq!(add.opcode(), Opcode::IAdd);
assert_eq!(add.to_string(), "iadd.i64 r2, r0, r1");
assert_eq!(Inst::from_bytes(add.to_bytes()), Ok(add));
assert_eq!(core::mem::size_of::<Inst>(), 8);Variants§
Nop
Does nothing.
Mov
dst = src. Both registers have the same declared type; the 64-bit
slot is copied as is.
LoadConst
dst = constants[k] in the destination’s typed representation (an
int constant into an integer register it fits, a str or bytes
constant into a str register, an aggregate into a matching ref).
DLoadConst
dst = constants[k] boxed as a dyn value (integers become dynamic
ints and must fit i64; floats become dynamic floats; aggregates
become dynamic arrays and maps).
LoadInt
dst = val as an integer of type ty; the immediate is
sign-extended and must be representable in ty.
Fields
DLoadInt
dst = val as a dynamic integer.
LoadBool
dst = val.
LoadNil
dst = nil: the dynamic nil, or the null str/ref.
LoadImport
dst = a callable reference to a host function: a first-class value
every dynamic call form accepts, bound by the import’s parameter
list if it has one.
GetGlobal
dst = globals[global].
SetGlobal
globals[global] = src; the global must be mutable.
IAdd
dst = lhs + rhs; overflow per op.policy().overflow().
Fields
ISub
dst = lhs - rhs; overflow per policy.
Fields
IMul
dst = lhs * rhs; overflow per policy.
Fields
IDiv
dst = lhs / rhs, truncating toward zero; rhs == 0 per div_zero,
signed MIN / -1 per overflow (wrap gives MIN).
Fields
IRem
dst = lhs rem rhs, the sign following the dividend; rhs == 0 per
div_zero; signed MIN rem -1 is 0, never an error.
Fields
IFloorDiv
dst = floor(lhs / rhs) (Python //); zero and overflow rules as
idiv.
Fields
IFloorMod
dst = lhs - rhs * floor_div(lhs, rhs), the sign following the
divisor; rhs == 0 per div_zero; signed MIN floor_mod -1 is 0.
Fields
IAnd
dst = lhs & rhs.
Fields
IOr
dst = lhs | rhs.
Fields
IXor
dst = lhs ^ rhs.
Fields
IShl
dst = lhs << rhs; bits shifted out are discarded; an amount at least
the width (or negative, for a signed type) per shift.
Fields
IShr
dst = lhs >> rhs, arithmetic for signed types and logical for
unsigned; amount rule as ishl.
Fields
IMin
dst = min(lhs, rhs).
Fields
IMax
dst = max(lhs, rhs).
Fields
INeg
dst = 0 - src; neg(MIN) per overflow.
IBitNot
dst = !src (bitwise complement; HIR’s bit_not on integers).
IAbs
dst = |src|; abs(MIN) per overflow.
IPow
dst = lhs ** rhs (OPS v2 pow): the exact power by repeated
squaring, 0 ** 0 = 1; a result that does not fit per overflow
(wrap keeps the low bits); a negative exponent of a signed type
raises NegativeExponent (E0006) under every policy (promote is
never valid here). The exponent has the operand type.
Fields
IEq
dst = lhs == rhs (bool).
Fields
INe
dst = lhs != rhs (bool).
Fields
ILt
dst = lhs < rhs (bool), signed or unsigned per ty.
Fields
ILe
dst = lhs <= rhs (bool).
Fields
IGt
dst = lhs > rhs (bool).
Fields
IGe
dst = lhs >= rhs (bool).
Fields
FAdd
dst = lhs + rhs (round to nearest, ties to even).
Fields
FSub
dst = lhs - rhs.
Fields
FMul
dst = lhs * rhs.
Fields
FDiv
dst = lhs / rhs; division by zero gives ±inf or NaN.
FRem
dst = fmod(lhs, rhs): the truncated remainder, sign of the dividend.
FIeeeRem
dst = remainder(lhs, rhs): IEEE 754 remainder (nearest quotient).
FMin
dst = min(lhs, rhs); NaN if either is NaN; min(-0, +0) = -0.
Fields
FMax
dst = max(lhs, rhs); NaN if either is NaN; max(-0, +0) = +0.
Fields
FFma
dst = fma(lhs, rhs, dst): fused multiply-add, correctly rounded.
dst is both the addend and the result.
Fields
FNeg
dst = -src (sign flip; payload preserved).
FAbs
dst = |src| (sign clear; payload preserved).
FSqrt
dst = sqrt(src), correctly rounded.
FFloor
dst = floor(src).
FCeil
dst = ceil(src).
FTrunc
dst = trunc(src) (toward zero).
FRound
dst = round(src), ties away from zero.
FRoundEven
dst = round(src), ties to even.
FEq
dst = lhs == rhs (bool); false if either is NaN.
Fields
FNe
dst = lhs != rhs (bool); true if either is NaN.
Fields
FLt
dst = lhs < rhs (bool); false if either is NaN.
Fields
FLe
dst = lhs <= rhs (bool); false if either is NaN.
Fields
FGt
dst = lhs > rhs (bool); false if either is NaN.
Fields
FGe
dst = lhs >= rhs (bool); false if either is NaN.
Fields
FPow
dst = pow(lhs, rhs) (OPS v2 float pow): C99 Annex F special
cases, finite results by the family’s shared ls_pow routine so every
tier is bit-identical; f32 computes ls_pow on the operands widened
to f64 and rounds once. Never an error.
FTotalCmp
dst = totalOrder(lhs, rhs) as an i8 of -1, 0, or 1 (IEEE 754
total order: -NaN < -inf < ... < -0 < +0 < ... < +inf < +NaN).
Fields
BNot
dst = !src (logical).
BAnd
dst = lhs & rhs (both evaluated; short-circuit is control flow).
BOr
dst = lhs | rhs.
BXor
dst = lhs ^ rhs (also boolean inequality).
CEq
dst = lhs == rhs on char scalar values.
CNe
dst = lhs != rhs on char scalar values.
CLt
dst = lhs < rhs on char scalar values.
CLe
dst = lhs <= rhs on char scalar values.
CGt
dst = lhs > rhs on char scalar values.
CGe
dst = lhs >= rhs on char scalar values.
RefEq
dst = lhs and rhs are the same object (or both nil). Operands
are str or ref; string contents are not compared.
IntCast
dst = src converted between integer types: exact if it fits, else
per the conversion’s overflow (wrap truncates or sign-extends).
Fields
Zext
Zero-extends a narrower integer to a wider one; never an error.
Fields
Sext
Sign-extends a narrower integer to a wider one; never an error.
Fields
Trunc
Keeps the low bits of a wider integer; never an error.
Fields
IntToF32
dst = src as f32, rounded to nearest, ties to even.
Fields
IntToF64
dst = src as f64, rounded to nearest, ties to even.
Fields
F32ToInt
dst = src truncated toward zero to the integer type conv.ty();
NaN or out of range per conv.float_to_int().
Fields
F64ToInt
dst = src truncated toward zero to the integer type conv.ty();
NaN or out of range per conv.float_to_int().
Fields
F32ToF64
dst = src widened to f64 (exact).
F64ToF32
dst = src narrowed to f32, rounded to nearest, ties to even.
FloatToBits
dst = the IEEE bits of src as an integer of the same width
(ty is a 32- or 64-bit integer type).
Fields
BitsToFloat
dst = the float whose IEEE bits are src (ty is a 32- or 64-bit
integer type; the float has the same width).
Fields
CharFromU32
dst = char(src); InvalidChar (E0005) if src (a u32) is not a
Unicode scalar value.
CharToU32
dst = src as its u32 scalar value. Total; an LSB addition to OPS.
BoolToInt
dst = 1 if src is true, else 0.
Fields
DAdd
Dynamic +.
Fields
DSub
Dynamic -.
Fields
DMul
Dynamic *.
Fields
DDiv
Dynamic division: truncating for two ints, IEEE otherwise.
Fields
DRem
Dynamic remainder: irem for two ints, frem otherwise.
Fields
DFloorDiv
Dynamic floor division (Python //).
Fields
DFloorMod
Dynamic floor modulo (Python %).
Fields
DAnd
Dynamic bitwise and (ints only, else hook).
Fields
DOr
Dynamic bitwise or.
Fields
DXor
Dynamic bitwise xor.
Fields
DShl
Dynamic shift left (64-bit; amount rule per shift, saturate for
PHP).
Fields
DShr
Dynamic arithmetic shift right.
Fields
DNeg
Dynamic negation.
DBitNot
Dynamic bitwise complement (PHP/Python ~; HIR’s bit_not): ints
only, else the bit_not hook.
DEq
Dynamic equality into a bool register (numbers exactly, strings by
content, other kinds through the eq hook or by identity).
DNe
Dynamic inequality: the negation of deq.
DLt
Dynamic < into a bool register (numbers, strings bytewise, chars;
else the lt hook or TypeError).
DLe
Dynamic <=.
DGt
Dynamic > (lt with the operands swapped).
DGe
Dynamic >= (le with the operands swapped).
DTruthy
dst = the truthiness of src as a bool: nil is false, bools are
themselves, numbers are true unless zero; other kinds go to the
truthy hook, or are true unless an empty string, array, or map.
DConcat
Dynamic string concatenation (two strings, else the concat hook).
ToDyn
dst = src boxed into a dyn (from names src’s static type;
u64 above i64::MAX raises ArithOverflow; str/ref are a no-op).
Fields
FromDyn
dst = src unboxed to the static type to; TypeError if the kind
does not match, ArithOverflow if an int does not fit. (ref targets
use cast.)
Fields
TypeOf
dst = the Kind code of src, as a u8.
IsKind
dst = whether src is of kind kind.
Fields
IsType
dst = whether src is a non-nil instance of struct type ty or of
a type that has it as an ancestor.
Fields
Cast
dst = src as ref ty; TypeError if src is not nil and not an
instance of ty (or a descendant).
Fields
DGetIndex
Dynamic indexing dst = obj[key]: arrays by int, maps by key, strings
by int (the byte); misses and other kinds go to the get_index hook.
A reference slot reads as its reference’s value.
DSetIndex
Dynamic indexed store obj[key] = src; a reference slot is written
through, and a reference src stores its value.
GetProp
Dynamic property read dst = obj.name: a struct field or method by
name, a map entry with a string key, else the get_prop hook.
SetProp
Dynamic property write obj.name = src.
HasProp
dst = whether obj has property name.
DCall
Dynamic call: dst = callee(dst+1, ..., dst+argc) with positional
dyn arguments, bound to the callee’s parameter list (exactly
dcall_shape with an all-positional shape): ArgumentError (E0114)
when they do not bind, TypeError when one does not convert to its
parameter’s type; non-callables go to the call hook.
Fields
DIterNew
dst = a dynamic iterator over src (array or map; else the iter
hook).
DLen
dst = the length of src as an i64 (string bytes, array or map
entries; else the len hook).
DNot
Dynamic logical not (PHP !, Python not; HIR’s not): dst = !truthy(src) as a bool, with exactly the truthiness rules of
dtruthy (the truthy hook included). dbit_not is the bitwise ~.
DPow
Dynamic ** (OPS v2 pow): two ints → integer pow at i64 under
pol (promote gives the nearest f64 of the exact power, and the
f64 power for a negative exponent; other policies raise
NegativeExponent for one); numbers with a float → fpow in f64;
else the pow hook, else TypeError.
Fields
DAbs
Dynamic absolute value: an int → abs at i64 (abs(MIN) per
overflow; promote gives 9.223372036854775808e18); a float →
fabs; else the abs hook, else TypeError.
DSepIndex
Separate an element for a nested write (PHP $a[k][] = v): obj
(an array or map) is written, so its own copy-on-write store is made
unique first; then if obj[key] is an array or map that another
container may share, it is replaced by a copy (O(1), copy-on-write);
dst = the element, safe to write in place. A reference slot
separates the container inside the reference. An absent key gives
nil (nothing is stored); other kinds of obj behave exactly as
dget_index.
DSepProp
dsep_index for a property (PHP $o->items[] = v): a struct field
of type dyn or a map entry with that string key; an absent map
entry gives nil; other cases behave exactly as get_prop.
DCallShape
Dynamic call with a call shape: dst = callee(...) with the window
dst+1 ..= dst+n laid out by shapes[shape] (positional, named,
spread, named spread), bound to the callee’s parameter list
(ArgumentError E0114 when they do not bind); non-callables go to
the call_shape hook, or to call when no argument is named.
Fields
DParamRef
dst = whether a positional argument at position pos (an i64)
would be taken by reference by callee, so a code generator can
send a reference or a value (PHP decides per argument at run time).
False for non-callables, callees without a parameter list, and
negative positions. Never raises.
Fields
DParamRefNamed
dst = whether a named argument name would be taken by reference
by callee. Never raises.
Fields
ErrPayload
dst = the payload of a runtime error value (what raise gave it;
nil for errors raised by instructions), or nil for any other value.
Jmp
Continue at target.
JmpIf
Continue at target if cond is true, else fall through.
JmpIfNot
Continue at target if cond is false, else fall through.
Switch
Continue at tables[table].targets[src] if 0 <= src < len, else at
the table’s default.
Call
dst = func(dst+1, ..., dst+argc); a call to a function with no
result leaves dst untouched.
Fields
CallIndirect
dst = callee(dst+1, ..., dst+argc) through a typed function
reference (ref of a function type).
Fields
CallImport
dst = import(dst+1, ..., dst+argc): a host call.
Fields
TailCall
Replaces the running frame with a call to func(args, ..., args+argc-1); the callee’s results equal the caller’s.
TailCallIndirect
Tail call through a typed function reference.
Fields
Ret
Return src to the caller.
RetVoid
Return with no result.
Throw
Raise src as an error: control moves to the innermost covering
handler, in this frame or a caller’s.
ErrCode
dst = the numeric ErrorKind code of a caught
runtime error, or 0 for any other value.
Safepoint
A point where the garbage collector may run and fuel is charged. Calls and allocations are safepoints too; every loop must pass one.
Unreachable
Abort the run with Unreachable (E0109).
Raise
Raise the runtime error kind (any catchable kind) with src as its
payload, at this pc: how a code generator raises HIR’s NoMatch
(E0200) with the scrutinee, or an ArgumentError from a prologue.
MakeClosure
dst = a closure of func capturing, by value, the registers
dst+1 ..= dst+n (n = the function’s capture count).
GetUpval
dst = the running closure’s captured value idx.
NewCell
dst = a new cell of type ty holding src.
CellGet
dst = the value in cell (a ref to a cell type, or a dyn
holding a cell or a reference; TypeError otherwise).
CellSet
Store src into cell (operand rules as cell_get).
NewRef
dst = a new reference holding src (a variable taken by reference,
PHP $r = &$x when $x is not yet one). (A)
DRefIndex
dst = a reference to the slot obj[key] (PHP &$a[k]): the slot’s
reference if it holds one; else the slot (created with nil if
absent in a map) is separated as by dsep_index and replaced by a
new reference holding its value. (A)
Fields
DRefProp
dst = a reference to the property obj.name (PHP &$o->p): a
struct field of type dyn, or a map entry with that string key
(created with nil if absent). (A)
Fields
DBindIndex
Make the slot obj[key] the reference src (PHP $a[k] = &$x),
replacing what the slot held (a previous reference is unbound, not
written through). TypeError if src is not a reference. (A)
DBindProp
Make the property obj.name the reference src (PHP $o->p = &$x). (A)
DUnrefIndex
If the slot obj[key] holds a reference, replace it by the
reference’s current value (a container value separated as by dup);
else nothing. Lets a code generator end a reference’s hold on a slot
it can prove no other holder uses (PHP drops such references when it
copies the array).
DUnrefProp
dunref_index for a property.
NewStruct
dst = a new instance of struct type ty, every field at its
type’s default.
GetField
dst = obj.field.
Fields
SetField
obj.field = src.
NewArray
dst = a new array of type ty with len (an i64, at least 0)
default elements.
ArrayLen
dst = the array’s length (i64).
ArrayGet
dst = arr[idx]; IndexOutOfBounds unless 0 <= idx < len.
Fields
ArraySet
arr[idx] = src; IndexOutOfBounds unless 0 <= idx < len.
ArrayPush
Append src to the array.
ArrayPop
dst = the removed last element; IndexOutOfBounds if empty.
NewMap
dst = a new, empty map of type ty.
MapLen
dst = the number of entries (i64).
MapGet
dst = map[key]; KeyNotFound if absent.
MapFind
dst = map[key], or nil if absent (value type dyn, str, or
ref).
MapHas
dst = whether key is present.
MapSet
map[key] = src: a new key goes last; an existing key keeps its
position.
MapDel
Remove key if present; the other entries keep their order.
MapPush
Append src under the next integer key (PHP $a[] = v): one more
than the largest integer key ever inserted, or 0.
IterNew
dst = a typed iterator over the array or map src.
IterNext
Advance: if another element exists, val = its value and has =
true; else has = false and val is untouched.
Fields
IterKey
dst = the key of the element the last iter_next produced.
Dup
dst = a shallow copy of src (array, map, struct, or cell; a new
identity, so value semantics such as PHP’s array assignment are
explicit; O(1), the contents copied on the first write). Reference
slots stay shared between the copies. Strings and callables are
returned as is; iterators, coroutines, and references raise
TypeError.
StrLen
dst = the length in bytes (i64).
StrConcat
dst = lhs ++ rhs.
StrConcatN
dst = the concatenation of the count strings in first .. first+count (the empty string if count is 0).
StrEq
dst = whether the strings have equal bytes.
StrCmp
dst = -1, 0, or 1 (i8) by bytewise lexicographic order.
StrSlice
dst = s[start..end] by byte offset, start in range and end in
range+1 (both i64); IndexOutOfBounds unless 0 <= start <= end <= len; with utf8, InvalidStrIndex if a bound splits a character.
Fields
StrByte
dst = the byte at idx (u8); IndexOutOfBounds unless 0 <= idx < len.
CoroNew
dst = a new coroutine, state created, that will run
func(dst+1, ..., dst+argc) when first resumed. The arguments are
copied now. (A)
Fields
CoroNewIndirect
dst = a new coroutine running the closure or function reference
callee with the arguments dst+1 ..= dst+argc (converted from
dyn as dcall does when callee is dyn). (A)
Fields
Yield
Suspend the running coroutine in state yielded, handing src to
its resumer under the next automatic key (PHP’s generator rule: one
more than the largest integer key yielded so far, never below 0, so
after only yield -5 => x it is 0); when resumed,
dst = the value sent. The yield is an unwind point: resume_throw
and coro_close raise here. CannotSuspend (E0111) outside a
coroutine or across a host frame.
Await
Suspend the running coroutine in state awaiting, handing the
awaitable src to its resumer (the scheduler); when resumed, dst =
the value sent (the awaited result), or the error sent by
resume_throw is raised here. CannotSuspend as yield.
Resume
Resume coro (state created, yielded, or awaiting), sending
src; when it next suspends or finishes, dst = the value it
yielded, the awaitable it awaits, or its return value (nil for a void
body). An error escaping its body marks it failed and is raised
here. InvalidCoroState (E0110) for any other state.
Fields
ResumeThrow
Resume coro by raising src at its suspension point (in a
created coroutine: before its first instruction, where no handler
covers it). Otherwise as resume.
Fields
CoroStatus
dst = the CoroState code of coro, as a
u8.
CoroCurrent
dst = the running coroutine, or nil on the main stack.
YieldKv
As yield, with an explicit key (PHP yield $k => $v); an integer
key larger than any before it moves the automatic-key counter.
Fields
CoroClose
Close coro (Python close()/aclose(), PHP generator
destruction): created → returned without running; returned or
failed → nothing. A suspended coroutine is marked closing and
src (the close signal, e.g. GeneratorExit) is raised at its
suspension point, so its finally blocks run. If the body then
returns, or the error escaping it is src itself, the close
succeeds (returned; dst = the return value or nil). Another
error marks it failed and is raised here. An await while closing
suspends normally (dst = the awaitable; drive it with resume); a
yield while closing leaves it suspended there and raises
CloseIgnored (E0113) here.
Fields
CoroKey
dst = the key of the value coro most recently yielded, or nil
before its first yield (PHP Generator::key()).
CoroResult
dst = the return value of a returned coroutine (Python’s
StopIteration.value, PHP Generator::getReturn()), nil for a void
body. InvalidCoroState (E0110) in any other state.
Spawn
Start a task: make a coroutine as coro_new_indirect does and pass
it to the module’s spawn hook (the host scheduler); dst = the
hook’s result (a task handle). NoScheduler (E0112) without the hook.
(A)
Implementations§
Source§impl Inst
impl Inst
Sourcepub const fn opcode(&self) -> Opcode
pub const fn opcode(&self) -> Opcode
The instruction’s opcode.
§Examples
use bytecode_lang::{Inst, Opcode};
assert_eq!(Inst::RetVoid {}.opcode(), Opcode::RetVoid);Sourcepub fn to_bytes(&self) -> [u8; 8]
pub fn to_bytes(&self) -> [u8; 8]
The canonical eight-byte encoding.
§Examples
use bytecode_lang::{Inst, Reg};
let mov = Inst::Mov { dst: Reg(1), src: Reg(2) };
assert_eq!(mov.to_bytes(), [0x01, 0, 1, 0, 2, 0, 0, 0]);Sourcepub fn from_bytes(bytes: [u8; 8]) -> Result<Inst, InstError>
pub fn from_bytes(bytes: [u8; 8]) -> Result<Inst, InstError>
Decodes eight bytes. Fails on an unknown opcode, on a modifier value its type does not define, and on non-zero bytes in unused slots, so every instruction has exactly one encoding.
§Errors
InstError says which of the three applies.
§Examples
use bytecode_lang::{Inst, InstError, Opcode};
assert_eq!(Inst::from_bytes([0, 0, 0, 0, 0, 0, 0, 0]), Ok(Inst::Nop {}));
// `load_bool` with 2 in its boolean slot.
assert_eq!(
Inst::from_bytes([0x06, 2, 0, 0, 0, 0, 0, 0]),
Err(InstError::InvalidOperand { opcode: Opcode::LoadBool, field: "val" }),
);Sourcepub fn overflow(&self) -> Option<Overflow>
pub fn overflow(&self) -> Option<Overflow>
The overflow policy the instruction carries (in an
IntOp, Policy, or IntConv modifier), or None for
instructions that carry none.
§Examples
use bytecode_lang::{Inst, Overflow, Policy, Reg};
let p = Policy::new().with_overflow(Overflow::Promote);
let add = Inst::DAdd { dst: Reg(0), lhs: Reg(1), rhs: Reg(2), pol: p };
assert_eq!(add.overflow(), Some(Overflow::Promote));
assert_eq!(Inst::Nop {}.overflow(), None);Source§impl Inst
impl Inst
Sourcepub const fn branch_target(&self) -> Option<Target>
pub const fn branch_target(&self) -> Option<Target>
The branch target of jmp, jmp_if, or jmp_if_not, if this is
one. (Switch targets live in the function’s jump tables.)
§Examples
use bytecode_lang::{Inst, Reg, Target};
assert_eq!(Inst::Jmp { target: Target(4) }.branch_target(), Some(Target(4)));
assert_eq!(Inst::Mov { dst: Reg(0), src: Reg(1) }.branch_target(), None);