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 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 Eq for Opcode

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.