Skip to main content

tinywasm_types/
instructions.rs

1use super::{FuncAddr, GlobalAddr, LocalAddr, TableAddr, TypeAddr, ValueCounts, WasmType};
2use crate::{ConstIdx, DataAddr, ElemAddr, ExternAddr, MemAddr};
3
4/// Represents a memory immediate in a WebAssembly memory instruction.
5#[derive(Copy, Clone, PartialEq, Eq)]
6#[cfg_attr(feature = "debug", derive(Debug))]
7#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
8#[repr(Rust, packed)]
9pub struct MemoryArg {
10    offset: u64,
11    mem_addr: MemAddr,
12}
13
14impl MemoryArg {
15    #[inline]
16    pub const fn new(offset: u64, mem_addr: MemAddr) -> Self {
17        Self { offset, mem_addr }
18    }
19
20    #[inline]
21    pub const fn offset(self) -> u64 {
22        self.offset
23    }
24
25    #[inline]
26    pub const fn mem_addr(self) -> MemAddr {
27        self.mem_addr
28    }
29}
30
31#[derive(Clone, Copy, PartialEq)]
32#[cfg_attr(feature = "debug", derive(Debug))]
33#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
34pub enum ConstInstruction {
35    I32Const(i32),
36    I64Const(i64),
37    F32Const(f32),
38    F64Const(f64),
39    V128Const(i128),
40    GlobalGet(GlobalAddr),
41    RefFunc(Option<FuncAddr>),
42    RefExtern(Option<ExternAddr>),
43    I32Add,
44    I32Sub,
45    I32Mul,
46    I64Add,
47    I64Sub,
48    I64Mul,
49}
50
51/// An integer comparison operator, currently only used for conditional jumps.
52#[derive(Clone, Copy, PartialEq, Eq)]
53#[cfg_attr(feature = "debug", derive(Debug))]
54#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
55pub enum CmpOp {
56    Eq,
57    Ne,
58    LtS,
59    LtU,
60    GtS,
61    GtU,
62    LeS,
63    LeU,
64    GeS,
65    GeU,
66}
67
68#[derive(Clone, Copy, PartialEq, Eq)]
69#[cfg_attr(feature = "debug", derive(Debug))]
70#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
71pub enum BinOp {
72    IAdd,
73    ISub,
74    IMul,
75    IAnd,
76    IOr,
77    IXor,
78    IShl,
79    IShrS,
80    IShrU,
81    IRotl,
82    IRotr,
83    FAdd,
84    FSub,
85    FMul,
86    FDiv,
87    FMin,
88    FMax,
89    FCopysign,
90}
91
92#[derive(Clone, Copy, PartialEq, Eq)]
93#[cfg_attr(feature = "debug", derive(Debug))]
94#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
95pub enum BinOp128 {
96    And,
97    AndNot,
98    Or,
99    Xor,
100    I64x2Add,
101    I64x2Mul,
102}
103
104/// A WebAssembly Instruction
105///
106/// These are our own internal bytecode instructions so they may not match the spec exactly.
107/// Wasm Bytecode can map to multiple of these instructions.
108///
109/// See <https://webassembly.github.io/spec/core/binary/instructions.html>
110#[rustfmt::skip]
111#[derive(Clone, Copy, PartialEq)]
112#[cfg_attr(feature = "debug", derive(Debug))]
113#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
114pub enum Instruction {
115    LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr),
116    AddConst32(i32), AddConst64(i64),
117    IncLocal32(LocalAddr, i32), IncLocal64(LocalAddr, i64),
118    // The 32/64 suffix describes the operand width. Future compare-style ops may still yield i32 results.
119    BinOpLocalLocal32(BinOp, LocalAddr, LocalAddr), BinOpLocalLocal64(BinOp, LocalAddr, LocalAddr),
120    BinOpLocalLocal128(BinOp128, LocalAddr, LocalAddr),
121    BinOpLocalLocalSet32(BinOp, LocalAddr, LocalAddr, LocalAddr),
122    BinOpLocalLocalSet64(BinOp, LocalAddr, LocalAddr, LocalAddr),
123    BinOpLocalLocalSet128(BinOp128, LocalAddr, LocalAddr, LocalAddr),
124    BinOpLocalLocalTee32(BinOp, LocalAddr, LocalAddr, LocalAddr),
125    BinOpLocalLocalTee64(BinOp, LocalAddr, LocalAddr, LocalAddr),
126    BinOpLocalLocalTee128(BinOp128, LocalAddr, LocalAddr, LocalAddr),
127    BinOpLocalConst32(BinOp, LocalAddr, i32), BinOpLocalConst64(BinOp, LocalAddr, i64),
128    BinOpLocalConst128(BinOp128, LocalAddr, ConstIdx),
129    BinOpLocalConstSet32(BinOp, LocalAddr, i32, LocalAddr),
130    BinOpLocalConstSet64(BinOp, LocalAddr, i64, LocalAddr),
131    BinOpLocalConstSet128(BinOp128, LocalAddr, ConstIdx, LocalAddr),
132    BinOpLocalConstTee32(BinOp, LocalAddr, i32, LocalAddr),
133    BinOpLocalConstTee64(BinOp, LocalAddr, i64, LocalAddr),
134    BinOpLocalConstTee128(BinOp128, LocalAddr, ConstIdx, LocalAddr),
135    BinOpStackGlobal32(BinOp, u32),
136    BinOpStackGlobal64(BinOp, u32),
137    SetLocalConst32(LocalAddr, i32), SetLocalConst64(LocalAddr, i64), SetLocalConst128(LocalAddr, ConstIdx),
138    StoreLocalLocal32(MemoryArg, u8, u8),
139    StoreLocalLocal64(MemoryArg, u8, u8),
140    StoreLocalLocal128(MemoryArg, u8, u8),
141    LoadLocal32(MemoryArg, u8),
142    LoadLocalTee32(MemoryArg, u8, u8),
143    LoadLocalSet32(MemoryArg, u8, u8),
144    LoadLocalTee128(MemoryArg, u8, u8),
145    LoadLocalSet128(MemoryArg, u8, u8),
146    AndConstTee32(i32, LocalAddr),
147    SubConstTee32(i32, LocalAddr),
148    AndConstTee64(i64, LocalAddr),
149    SubConstTee64(i64, LocalAddr),
150    MulAccLocal32(LocalAddr),
151    MulAccLocal64(LocalAddr),
152    FMulAccLocal32(LocalAddr),
153    FMulAccLocal64(LocalAddr),
154    I32Add3,
155    I64Add3,
156    FMaStoreF32(MemoryArg),
157    FMaStoreF64(MemoryArg),
158
159    // > Control Instructions (jump-oriented, lowered from structured control during parsing)
160    // See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
161    Unreachable,
162    Nop,
163    MergeBarrier,
164    Jump(u32),
165    JumpIfZero32(u32),
166    JumpIfNonZero32(u32),
167    JumpIfZero64(u32),
168    JumpIfNonZero64(u32),
169    JumpIfLocalZero32 { target_ip: u32, local: LocalAddr },
170    JumpIfLocalNonZero32 { target_ip: u32, local: LocalAddr },
171    JumpIfLocalZero64 { target_ip: u32, local: LocalAddr },
172    JumpIfLocalNonZero64 { target_ip: u32, local: LocalAddr },
173    JumpCmpStackConst32 { target_ip: u32, imm: i32, op: CmpOp },
174    JumpCmpStackConst64 { target_ip: u32, imm: i64, op: CmpOp },
175    JumpCmpLocalConst32 { target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp },
176    JumpCmpLocalConst64 { target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp },
177    JumpCmpLocalLocal32 { target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp },
178    JumpCmpLocalLocal64 { target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp },
179    DropKeep { base32: u16, keep32: u8, base64: u16, keep64: u8, base128: u16, keep128: u8 },
180    DropKeep32(u16, u16),
181    DropKeep64(u16, u16),
182    DropKeep128(u16, u16),
183    BranchTable(u32, u32, u32),  // (default_landing_pad_ip, branch_table_start, target_count)
184    Return,
185    ReturnVoid,
186    Return32,
187    Return64,
188    Return128,
189    Call(FuncAddr),
190    CallSelf,
191    CallIndirect(TypeAddr, TableAddr),
192    ReturnCall(FuncAddr),
193    ReturnCallSelf,
194    ReturnCallIndirect(TypeAddr, TableAddr),
195
196    // > Parametric Instructions
197    // See <https://webassembly.github.io/spec/core/binary/instructions.html#parametric-instructions>
198    Drop32, Select32,
199    Drop64, Select64,
200    Drop128, Select128,
201    SelectMulti(ValueCounts),
202
203    // > Variable Instructions
204    // See <https://webassembly.github.io/spec/core/binary/instructions.html#variable-instructions>
205    GlobalGet(GlobalAddr),
206    LocalGet32(LocalAddr), LocalSet32(LocalAddr), LocalTee32(LocalAddr), GlobalSet32(GlobalAddr),
207    LocalGet64(LocalAddr), LocalSet64(LocalAddr), LocalTee64(LocalAddr), GlobalSet64(GlobalAddr),
208    LocalGet128(LocalAddr), LocalSet128(LocalAddr), LocalTee128(LocalAddr), GlobalSet128(GlobalAddr),
209
210    // > Memory Instructions
211    I32Load(MemoryArg),
212    I64Load(MemoryArg),
213    F32Load(MemoryArg),
214    F64Load(MemoryArg),
215    I32Load8S(MemoryArg),
216    I32Load8U(MemoryArg),
217    I32Load16S(MemoryArg),
218    I32Load16U(MemoryArg),
219    I64Load8S(MemoryArg),
220    I64Load8U(MemoryArg),
221    I64Load16S(MemoryArg),
222    I64Load16U(MemoryArg),
223    I64Load32S(MemoryArg),
224    I64Load32U(MemoryArg),
225    I32Store(MemoryArg),
226    I64Store(MemoryArg),
227    F32Store(MemoryArg),
228    F64Store(MemoryArg),
229    I32Store8(MemoryArg),
230    I32Store16(MemoryArg),
231    I64Store8(MemoryArg),
232    I64Store16(MemoryArg),
233    I64Store32(MemoryArg),
234    MemorySize(MemAddr),
235    MemoryGrow(MemAddr),
236
237    // > Constants
238    Const32(i32),
239    Const64(i64),
240
241    // > Reference Types
242    RefNull(WasmType),
243    RefFunc(FuncAddr),
244    RefIsNull,
245
246    // > Numeric Instructions
247    // See <https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions>
248    I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU,
249    I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU,
250
251    // Comparisons
252    F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge,
253    F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge,
254    I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU,
255    I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU,
256
257    // Bitwise
258    I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr,
259    I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr,
260
261    // Floating Point
262    F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign,
263    F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign,
264    I32WrapI64, I32TruncF32S, I32TruncF32U, I32TruncF64S, I32TruncF64U, I32Extend8S, I32Extend16S,
265    I64Extend8S, I64Extend16S, I64Extend32S, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U,
266    F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64,
267    F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32,
268
269    // Saturating Float-to-Int Conversions
270    I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U,
271    I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U,
272
273    // > Table Instructions
274    TableInit(ElemAddr, TableAddr),
275    TableGet(TableAddr),
276    TableSet(TableAddr),
277    TableCopy { dst_table: TableAddr, src_table: TableAddr },
278    TableGrow(TableAddr),
279    TableSize(TableAddr),
280    TableFill(TableAddr),
281
282    // > Bulk Memory Instructions
283    MemoryInit(MemAddr, DataAddr),
284    MemoryCopy { dst_mem: MemAddr, src_mem: MemAddr },
285    MemoryFill(MemAddr),
286    MemoryFillImm(MemAddr, u8, i32),
287    DataDrop(DataAddr),
288    ElemDrop(ElemAddr),
289
290    // > Wide Arithmetic
291    I64Add128, I64Sub128, I64MulWideS, I64MulWideU,
292
293    // > SIMD
294    V128Load(MemoryArg),
295    V128Load8x8S(MemoryArg), V128Load8x8U(MemoryArg),
296    V128Load16x4S(MemoryArg), V128Load16x4U(MemoryArg),
297    V128Load32x2S(MemoryArg), V128Load32x2U(MemoryArg),
298
299    V128Load8Splat(MemoryArg), V128Load16Splat(MemoryArg), V128Load32Splat(MemoryArg), V128Load64Splat(MemoryArg),
300    V128Load8Lane(MemoryArg, u8), V128Load16Lane(MemoryArg, u8), V128Load32Lane(MemoryArg, u8), V128Load64Lane(MemoryArg, u8),
301
302    V128Load32Zero(MemoryArg), V128Load64Zero(MemoryArg),
303
304    V128Store(MemoryArg), V128Store8Lane(MemoryArg, u8), V128Store16Lane(MemoryArg, u8), V128Store32Lane(MemoryArg, u8), V128Store64Lane(MemoryArg, u8),
305
306    I8x16Shuffle(ConstIdx),
307    Const128(ConstIdx),
308
309    I8x16ExtractLaneS(u8), I8x16ExtractLaneU(u8), I8x16ReplaceLane(u8),
310    I16x8ExtractLaneS(u8), I16x8ExtractLaneU(u8), I16x8ReplaceLane(u8),
311    I32x4ExtractLane(u8), I32x4ReplaceLane(u8),
312    I64x2ExtractLane(u8), I64x2ReplaceLane(u8),
313    F32x4ExtractLane(u8), F32x4ReplaceLane(u8),
314    F64x2ExtractLane(u8), F64x2ReplaceLane(u8),
315
316    V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, I8x16Swizzle,
317    I8x16Splat, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU,
318    I16x8Splat, I16x8Eq, I16x8Ne, I16x8LtS, I16x8LtU, I16x8GtS, I16x8GtU, I16x8LeS, I16x8LeU, I16x8GeS, I16x8GeU,
319    I32x4Splat, I32x4Eq, I32x4Ne, I32x4LtS, I32x4LtU, I32x4GtS, I32x4GtU, I32x4LeS, I32x4LeU, I32x4GeS, I32x4GeU,
320    I64x2Splat, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS,
321    F32x4Splat, F32x4Eq, F32x4Ne, F32x4Lt, F32x4Gt, F32x4Le, F32x4Ge,
322    F64x2Splat, F64x2Eq, F64x2Ne, F64x2Lt, F64x2Gt, F64x2Le, F64x2Ge,
323
324    I8x16Abs, I8x16Neg, I8x16AllTrue, I8x16Bitmask, I8x16Shl, I8x16ShrS, I8x16ShrU, I8x16Add, I8x16Sub, I8x16MinS, I8x16MinU, I8x16MaxS, I8x16MaxU,
325    I16x8Abs, I16x8Neg, I16x8AllTrue, I16x8Bitmask, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, I16x8Sub, I16x8MinS, I16x8MinU, I16x8MaxS, I16x8MaxU,
326    I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU,
327    I64x2Abs, I64x2Neg, I64x2AllTrue, I64x2Bitmask, I64x2Shl, I64x2ShrS, I64x2ShrU, I64x2Add, I64x2Sub, I64x2Mul,
328
329    I8x16NarrowI16x8S, I8x16NarrowI16x8U, I8x16AddSatS, I8x16AddSatU, I8x16SubSatS, I8x16SubSatU, I8x16AvgrU,
330    I16x8NarrowI32x4S, I16x8NarrowI32x4U, I16x8AddSatS, I16x8AddSatU, I16x8SubSatS, I16x8SubSatU, I16x8AvgrU,
331
332    I16x8ExtAddPairwiseI8x16S, I16x8ExtAddPairwiseI8x16U, I16x8Mul,
333    I32x4ExtAddPairwiseI16x8S, I32x4ExtAddPairwiseI16x8U, I32x4Mul,
334
335    I16x8ExtMulLowI8x16S, I16x8ExtMulLowI8x16U, I16x8ExtMulHighI8x16S, I16x8ExtMulHighI8x16U,
336    I32x4ExtMulLowI16x8S, I32x4ExtMulLowI16x8U, I32x4ExtMulHighI16x8S, I32x4ExtMulHighI16x8U,
337    I64x2ExtMulLowI32x4S, I64x2ExtMulLowI32x4U, I64x2ExtMulHighI32x4S, I64x2ExtMulHighI32x4U,
338
339    I16x8ExtendLowI8x16S, I16x8ExtendLowI8x16U, I16x8ExtendHighI8x16S, I16x8ExtendHighI8x16U,
340    I32x4ExtendLowI16x8S, I32x4ExtendLowI16x8U, I32x4ExtendHighI16x8S, I32x4ExtendHighI16x8U,
341    I64x2ExtendLowI32x4S, I64x2ExtendLowI32x4U, I64x2ExtendHighI32x4S, I64x2ExtendHighI32x4U,
342
343    I8x16Popcnt, I16x8Q15MulrSatS, I32x4DotI16x8S,
344
345    F32x4Ceil, F32x4Floor, F32x4Trunc, F32x4Nearest, F32x4Abs, F32x4Neg, F32x4Sqrt, F32x4Add, F32x4Sub, F32x4Mul, F32x4Div, F32x4Min, F32x4Max, F32x4PMin, F32x4PMax,
346    F64x2Ceil, F64x2Floor, F64x2Trunc, F64x2Nearest, F64x2Abs, F64x2Neg, F64x2Sqrt, F64x2Add, F64x2Sub, F64x2Mul, F64x2Div, F64x2Min, F64x2Max, F64x2PMin, F64x2PMax,
347    I32x4TruncSatF32x4S, I32x4TruncSatF32x4U,
348    F32x4ConvertI32x4S, F32x4ConvertI32x4U,
349    I32x4TruncSatF64x2SZero, I32x4TruncSatF64x2UZero,
350    F64x2ConvertLowI32x4S, F64x2ConvertLowI32x4U,
351    F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4,
352
353    // > Relaxed SIMD
354    I8x16RelaxedSwizzle,
355    I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U,
356    I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero,
357    F32x4RelaxedMadd, F32x4RelaxedNmadd,
358    F64x2RelaxedMadd, F64x2RelaxedNmadd,
359    I8x16RelaxedLaneselect,
360    I16x8RelaxedLaneselect,
361    I32x4RelaxedLaneselect,
362    I64x2RelaxedLaneselect,
363    F32x4RelaxedMin, F32x4RelaxedMax,
364    F64x2RelaxedMin, F64x2RelaxedMax,
365    I16x8RelaxedQ15mulrS,
366    I16x8RelaxedDotI8x16I7x16S,
367    I32x4RelaxedDotI8x16I7x16AddS
368}
369
370impl Instruction {
371    #[inline]
372    pub const fn memory_addr(&self) -> Option<MemAddr> {
373        match self {
374            Self::StoreLocalLocal32(arg, ..)
375            | Self::StoreLocalLocal64(arg, ..)
376            | Self::StoreLocalLocal128(arg, ..)
377            | Self::LoadLocal32(arg, ..)
378            | Self::LoadLocalTee32(arg, ..)
379            | Self::LoadLocalSet32(arg, ..)
380            | Self::LoadLocalTee128(arg, ..)
381            | Self::LoadLocalSet128(arg, ..)
382            | Self::I32Load(arg)
383            | Self::I64Load(arg)
384            | Self::F32Load(arg)
385            | Self::F64Load(arg)
386            | Self::I32Load8S(arg)
387            | Self::I32Load8U(arg)
388            | Self::I32Load16S(arg)
389            | Self::I32Load16U(arg)
390            | Self::I64Load8S(arg)
391            | Self::I64Load8U(arg)
392            | Self::I64Load16S(arg)
393            | Self::I64Load16U(arg)
394            | Self::I64Load32S(arg)
395            | Self::I64Load32U(arg)
396            | Self::I32Store(arg)
397            | Self::I64Store(arg)
398            | Self::F32Store(arg)
399            | Self::F64Store(arg)
400            | Self::FMaStoreF32(arg)
401            | Self::FMaStoreF64(arg)
402            | Self::I32Store8(arg)
403            | Self::I32Store16(arg)
404            | Self::I64Store8(arg)
405            | Self::I64Store16(arg)
406            | Self::I64Store32(arg)
407            | Self::V128Load(arg)
408            | Self::V128Load8x8S(arg)
409            | Self::V128Load8x8U(arg)
410            | Self::V128Load16x4S(arg)
411            | Self::V128Load16x4U(arg)
412            | Self::V128Load32x2S(arg)
413            | Self::V128Load32x2U(arg)
414            | Self::V128Load8Splat(arg)
415            | Self::V128Load16Splat(arg)
416            | Self::V128Load32Splat(arg)
417            | Self::V128Load64Splat(arg)
418            | Self::V128Load8Lane(arg, ..)
419            | Self::V128Load16Lane(arg, ..)
420            | Self::V128Load32Lane(arg, ..)
421            | Self::V128Load64Lane(arg, ..)
422            | Self::V128Load32Zero(arg)
423            | Self::V128Load64Zero(arg)
424            | Self::V128Store(arg)
425            | Self::V128Store8Lane(arg, ..)
426            | Self::V128Store16Lane(arg, ..)
427            | Self::V128Store32Lane(arg, ..)
428            | Self::V128Store64Lane(arg, ..) => Some(arg.mem_addr()),
429            Self::MemorySize(mem)
430            | Self::MemoryGrow(mem)
431            | Self::MemoryInit(mem, ..)
432            | Self::MemoryFill(mem)
433            | Self::MemoryFillImm(mem, ..) => Some(*mem),
434            Self::MemoryCopy { dst_mem, src_mem } => Some(if *dst_mem >= *src_mem { *dst_mem } else { *src_mem }),
435            _ => None,
436        }
437    }
438}
439
440#[cfg(test)]
441mod tests {
442    use super::Instruction;
443
444    #[test]
445    fn instruction_layout_size_is_stable() {
446        assert_eq!(core::mem::size_of::<Instruction>(), 16);
447    }
448}