Skip to main content

Opcode

Enum Opcode 

Source
pub enum Opcode {
Show 88 variants Nop, Add { dest: Reg, src1: Reg, src2: Reg, }, Sub { dest: Reg, src1: Reg, src2: Reg, }, Mul { dest: Reg, src1: Reg, src2: Reg, }, DivS { dest: Reg, src1: Reg, src2: Reg, }, DivU { dest: Reg, src1: Reg, src2: Reg, }, RemS { dest: Reg, src1: Reg, src2: Reg, }, RemU { dest: Reg, src1: Reg, src2: Reg, }, And { dest: Reg, src1: Reg, src2: Reg, }, Or { dest: Reg, src1: Reg, src2: Reg, }, Xor { dest: Reg, src1: Reg, src2: Reg, }, Shl { dest: Reg, src1: Reg, src2: Reg, }, ShrS { dest: Reg, src1: Reg, src2: Reg, }, ShrU { dest: Reg, src1: Reg, src2: Reg, }, Rotl { dest: Reg, src1: Reg, src2: Reg, }, Rotr { dest: Reg, src1: Reg, src2: Reg, }, Clz { dest: Reg, src: Reg, }, Ctz { dest: Reg, src: Reg, }, Popcnt { dest: Reg, src: Reg, }, Extend8S { dest: Reg, src: Reg, }, Extend16S { dest: Reg, src: Reg, }, Eqz { dest: Reg, src: Reg, }, Eq { dest: Reg, src1: Reg, src2: Reg, }, Ne { dest: Reg, src1: Reg, src2: Reg, }, LtS { dest: Reg, src1: Reg, src2: Reg, }, LtU { dest: Reg, src1: Reg, src2: Reg, }, LeS { dest: Reg, src1: Reg, src2: Reg, }, LeU { dest: Reg, src1: Reg, src2: Reg, }, GtS { dest: Reg, src1: Reg, src2: Reg, }, GtU { dest: Reg, src1: Reg, src2: Reg, }, GeS { dest: Reg, src1: Reg, src2: Reg, }, GeU { dest: Reg, src1: Reg, src2: Reg, }, Load { dest: Reg, addr: u32, }, Store { src: Reg, addr: u32, }, I64Load { dest_lo: Reg, dest_hi: Reg, addr: u32, }, MemLoad { dest: Reg, addr: Reg, offset: u32, }, MemStore { src: Reg, addr: Reg, offset: u32, }, MemLoadSubword { dest: Reg, addr: Reg, offset: u32, width: u32, signed: bool, }, MemStoreSubword { src: Reg, addr: Reg, offset: u32, width: u32, }, GlobalGet { dest: Reg, idx: u32, }, GlobalSet { src: Reg, idx: u32, }, MemorySize { dest: Reg, }, MemoryGrow { dest: Reg, delta: Reg, }, Branch { target: BlockId, }, CondBranch { cond: Reg, target: BlockId, }, Call { dest: Reg, func_idx: u32, }, Return { value: Option<Reg>, }, Label { id: BlockId, }, Copy { dest: Reg, src: Reg, }, TeeStore { dest: Reg, src: Reg, addr: u32, }, Select { dest: Reg, val_true: Reg, val_false: Reg, cond: Reg, }, Const { dest: Reg, value: i32, }, I64Add { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Sub { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64And { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Or { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Xor { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Const { dest_lo: Reg, dest_hi: Reg, value: i64, }, I64Eq { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Ne { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64LtS { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64GtS { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64LeS { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64GeS { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64LtU { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64GtU { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64LeU { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64GeU { dest: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Eqz { dest: Reg, src_lo: Reg, src_hi: Reg, }, I64Clz { dest: Reg, src_lo: Reg, src_hi: Reg, }, I64Ctz { dest: Reg, src_lo: Reg, src_hi: Reg, }, I64Popcnt { dest: Reg, src_lo: Reg, src_hi: Reg, }, I64Extend8S { dest_lo: Reg, dest_hi: Reg, src_lo: Reg, }, I64Extend16S { dest_lo: Reg, dest_hi: Reg, src_lo: Reg, }, I64Extend32S { dest_lo: Reg, dest_hi: Reg, src_lo: Reg, }, I64ExtendI32U { dest_lo: Reg, dest_hi: Reg, src: Reg, }, I64ExtendI32S { dest_lo: Reg, dest_hi: Reg, src: Reg, }, I32WrapI64 { dest: Reg, src_lo: Reg, }, I64Mul { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64DivS { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64DivU { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64RemS { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64RemU { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Shl { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64ShrS { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64ShrU { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Rotl { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, }, I64Rotr { dest_lo: Reg, dest_hi: Reg, src1_lo: Reg, src1_hi: Reg, src2_lo: Reg, src2_hi: Reg, },
}

Variants§

§

Nop

§

Add

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Sub

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Mul

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

DivS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

DivU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

RemS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

RemU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

And

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Or

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Xor

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Shl

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

ShrS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

ShrU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Rotl

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Rotr

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Clz

Fields

§dest: Reg
§src: Reg
§

Ctz

Fields

§dest: Reg
§src: Reg
§

Popcnt

Fields

§dest: Reg
§src: Reg
§

Extend8S

Fields

§dest: Reg
§src: Reg
§

Extend16S

Fields

§dest: Reg
§src: Reg
§

Eqz

Fields

§dest: Reg
§src: Reg
§

Eq

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Ne

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

LtS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

LtU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

LeS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

LeU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

GtS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

GtU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

GeS

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

GeU

Fields

§dest: Reg
§src1: Reg
§src2: Reg
§

Load

Fields

§dest: Reg
§addr: u32
§

Store

Fields

§src: Reg
§addr: u32
§

I64Load

Load 64-bit value from local into register pair (for i64 on 32-bit ARM)

Fields

§dest_lo: Reg
§dest_hi: Reg
§addr: u32
§

MemLoad

Load 32-bit value from linear memory: dest = mem[addr + offset]

Fields

§dest: Reg
§addr: Reg
§offset: u32
§

MemStore

Store 32-bit value to linear memory: mem[addr + offset] = src

Fields

§src: Reg
§addr: Reg
§offset: u32
§

MemLoadSubword

Sub-word load: i32.load8_s/u, i32.load16_s/u and the i64 equivalents after extension. width is 1 or 2 bytes; signed is true for the _s variants. The dest is a single i32 register (sub-word loads on ARM expand to a single LDRB/LDRH ± an SXTB/SXTH).

Fields

§dest: Reg
§addr: Reg
§offset: u32
§width: u32
§signed: bool
§

MemStoreSubword

Sub-word store: i32.store8 / i32.store16 / i64.store8/16/32. width is 1, 2, or 4. For 4-byte store of an i64’s low word we just take the lo register.

Fields

§src: Reg
§addr: Reg
§offset: u32
§width: u32
§

GlobalGet

global.get — load a global into a fresh vreg. The actual ARM lowering is LDR rd, [R9, #offset] (R9 is the globals base, by convention). The vreg MUST be allocated to a non-AAPCS-param register at lowering time — otherwise the LDR would clobber a live caller arg.

Fields

§dest: Reg
§idx: u32
§

GlobalSet

global.set — store a vreg to a global slot. Emits STR src, [R9, #offset]. No vreg is written.

Fields

§src: Reg
§idx: u32
§

MemorySize

memory.size — returns the current memory size in pages as an i32. By convention R10 holds the memory-size word; we emit MOV dest, R10. dest must be allocated to a non-param scratch.

Fields

§dest: Reg
§

MemoryGrow

memory.grow — pops the grow-by amount, pushes the previous page count (or -1 on failure). Embedded targets generally have fixed memory, so this is a stub returning -1 in dest.

Fields

§dest: Reg
§delta: Reg
§

Branch

Fields

§target: BlockId
§

CondBranch

Fields

§cond: Reg
§target: BlockId
§

Call

Direct function call. Lowered to BL func_<func_idx> (or to an import dispatch for func_idx < num_imports). The AAPCS return value lands in R0, so ir_to_arm binds dest to R0 after the BL.

Prior to this opcode, WasmOp::Call fell through to Opcode::Nop in wasm_to_ir, leaving the call result’s vreg unmapped. Any downstream consumer (e.g., i32.add of two call results, as in the recursive fib example) then triggered the PR #101 defensive panic — or, with the silent R0 fallback, silently miscompiled. See the issue-#93 family of bugs.

NOTE: this opcode does NOT model the call’s clobber of R0..R3 — that’s a separate (deeper) issue around correct AAPCS lowering of calls in the optimized path. This fix only closes the unmapped-vreg gap so the compiler stops panicking on lawful WASM modules.

Fields

§dest: Reg
§func_idx: u32
§

Return

Fields

§value: Option<Reg>
§

Label

Label marker for branch targets (loop start, block end)

Fields

§

Copy

Copy a value (for local.tee semantics: store value and keep it on stack)

Fields

§dest: Reg
§src: Reg
§

TeeStore

TeeStore: Store to local AND keep value on stack (local.tee) Combines Store + Copy: stores src to local addr, dest gets same value

Fields

§dest: Reg
§src: Reg
§addr: u32
§

Select

Fields

§dest: Reg
§val_true: Reg
§val_false: Reg
§cond: Reg
§

Const

Fields

§dest: Reg
§value: i32
§

I64Add

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Sub

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64And

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Or

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Xor

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Const

Fields

§dest_lo: Reg
§dest_hi: Reg
§value: i64
§

I64Eq

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Ne

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64LtS

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64GtS

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64LeS

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64GeS

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64LtU

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64GtU

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64LeU

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64GeU

Fields

§dest: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Eqz

Fields

§dest: Reg
§src_lo: Reg
§src_hi: Reg
§

I64Clz

Fields

§dest: Reg
§src_lo: Reg
§src_hi: Reg
§

I64Ctz

Fields

§dest: Reg
§src_lo: Reg
§src_hi: Reg
§

I64Popcnt

Fields

§dest: Reg
§src_lo: Reg
§src_hi: Reg
§

I64Extend8S

Fields

§dest_lo: Reg
§dest_hi: Reg
§src_lo: Reg
§

I64Extend16S

Fields

§dest_lo: Reg
§dest_hi: Reg
§src_lo: Reg
§

I64Extend32S

Fields

§dest_lo: Reg
§dest_hi: Reg
§src_lo: Reg
§

I64ExtendI32U

i32 -> i64 zero-extension. dest_lo aliases src (same vreg by IR convention — see wasm_to_ir); dest_hi is freshly allocated and holds the constant 0. Lowering MUST move src’s ARM reg into a non-AAPCS-param register before treating it as the i64 lo half — the downstream I64Shl/ShrU/ShrS emitters use rm_lo/rm_hi as scratch and clobber them, so we must not place a live param register there. This was the proximate cause of issue #93 (memset infinite loop on silicon) before this opcode existed and the bridge silently fell through to Opcode::Nop + R0-fallback in get_arm_reg.

Fields

§dest_lo: Reg
§dest_hi: Reg
§src: Reg
§

I64ExtendI32S

i32 -> i64 sign-extension. Same constraints as I64ExtendI32U; the dest_hi is filled by an arithmetic shift right by 31 of the src.

Fields

§dest_lo: Reg
§dest_hi: Reg
§src: Reg
§

I32WrapI64

i64 -> i32 wrap (truncate to low 32 bits). dest aliases the i64’s src_lo vreg (same value); the high half is simply discarded.

Fields

§dest: Reg
§src_lo: Reg
§

I64Mul

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64DivS

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64DivU

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64RemS

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64RemU

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Shl

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64ShrS

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64ShrU

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Rotl

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg
§

I64Rotr

Fields

§dest_lo: Reg
§dest_hi: Reg
§src1_lo: Reg
§src1_hi: Reg
§src2_lo: Reg
§src2_hi: Reg

Trait Implementations§

Source§

impl Clone for Opcode

Source§

fn clone(&self) -> Opcode

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Opcode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Opcode

Source§

impl PartialEq for Opcode

Source§

fn eq(&self, other: &Opcode) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for Opcode

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.