1use alloc::boxed::Box;
2
3use super::{FuncAddr, GlobalAddr, LocalAddr, TableAddr, TagAddr, TypeAddr, ValueCounts};
4use crate::operands::{read_field, write_field};
5use crate::{
6 DataAddr, ElemAddr, MemAddr, ModuleFuncIdx, Operand64, Operand64Idx, Operand128, Operand128Idx, OperandIdx, RefType,
7};
8
9pub enum MemoryOperand {}
11
12pub enum CompactMemoryOperand {}
14
15pub enum BranchTableOperand {}
17
18pub enum MemoryFillOperand {}
20
21pub enum LocalUpdateOperand {}
23
24pub enum GlobalUpdateOperand {}
26
27pub enum LocalUpdateCmpOperand {}
29
30#[derive(Copy, Clone, PartialEq, Eq)]
35#[cfg_attr(feature = "debug", derive(Debug))]
36#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
37#[repr(Rust, packed)]
38pub struct CompactMemoryArg {
39 offset: u32,
40 mem_addr: u16,
41}
42
43#[derive(Copy, Clone, PartialEq, Eq)]
45#[cfg_attr(feature = "debug", derive(Debug))]
46#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
47#[repr(Rust, packed)]
48pub struct MemoryLocalArg {
49 pub memory_arg_idx: Operand64Idx<CompactMemoryOperand>,
50 pub local1: u8,
51 pub local2: u8,
52}
53
54#[derive(Copy, Clone, PartialEq, Eq)]
56#[cfg_attr(feature = "debug", derive(Debug))]
57#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
58#[repr(Rust, packed)]
59pub struct MemoryLaneArg {
60 pub memory_arg_idx: Operand128Idx<MemoryOperand>,
61 pub lane: u8,
62}
63
64#[derive(Copy, Clone, PartialEq, Eq)]
66#[cfg_attr(feature = "debug", derive(Debug))]
67#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
68#[repr(Rust, packed)]
69pub struct I32LocalArg {
70 pub value: i32,
71 pub local: LocalAddr,
72}
73
74#[derive(Copy, Clone, PartialEq, Eq)]
76#[cfg_attr(feature = "debug", derive(Debug))]
77#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
78pub struct LocalTripleArg {
79 pub left: LocalAddr,
80 pub right: LocalAddr,
81 pub dst: LocalAddr,
82}
83
84#[derive(Copy, Clone, PartialEq, Eq)]
86#[cfg_attr(feature = "debug", derive(Debug))]
87#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
88#[repr(Rust, packed)]
89pub struct TargetLocalArg {
90 pub target_ip: u32,
91 pub local: LocalAddr,
92}
93
94#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
96#[cfg_attr(
97 feature = "archive",
98 serde(bound(serialize = "Op: Copy + serde::Serialize", deserialize = "Op: Copy + serde::de::DeserializeOwned",))
99)]
100#[repr(Rust, packed)]
101pub struct PackedOp<Op, T, const WIDTH: usize> {
102 pub op: Op,
103 pub index: OperandIdx<T, WIDTH>,
104}
105
106pub type PackedOp64<Op, T> = PackedOp<Op, T, 8>;
108
109pub type PackedOp128<Op, T> = PackedOp<Op, T, 16>;
111
112impl<Op: Copy, T, const WIDTH: usize> Copy for PackedOp<Op, T, WIDTH> {}
113
114impl<Op: Copy, T, const WIDTH: usize> Clone for PackedOp<Op, T, WIDTH> {
115 fn clone(&self) -> Self {
116 *self
117 }
118}
119
120impl<Op: Copy + PartialEq, T, const WIDTH: usize> PartialEq for PackedOp<Op, T, WIDTH> {
121 fn eq(&self, other: &Self) -> bool {
122 let (op, index) = (self.op, self.index);
123 let (other_op, other_index) = (other.op, other.index);
124 op == other_op && index == other_index
125 }
126}
127
128impl<Op: Copy + Eq, T, const WIDTH: usize> Eq for PackedOp<Op, T, WIDTH> {}
129
130#[cfg(feature = "debug")]
131impl<Op: Copy + core::fmt::Debug, T, const WIDTH: usize> core::fmt::Debug for PackedOp<Op, T, WIDTH> {
132 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
133 let (op, index) = (self.op, self.index);
134 formatter.debug_struct("PackedOp").field("op", &op).field("index", &index).finish()
135 }
136}
137
138impl<Op, T, const WIDTH: usize> PackedOp<Op, T, WIDTH> {
139 #[inline]
141 pub const fn new(op: Op, index: OperandIdx<T, WIDTH>) -> Self {
142 Self { op, index }
143 }
144}
145
146#[derive(Clone, Copy, PartialEq, Eq)]
148#[cfg_attr(feature = "debug", derive(Debug))]
149#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
150pub enum ExceptionCatch {
151 Tag { tag: TagAddr, landing_pad: u32, base: ValueCounts, with_ref: bool },
153 All { landing_pad: u32, base: ValueCounts, with_ref: bool },
155}
156
157impl ExceptionCatch {
158 pub const fn landing_pad(self) -> u32 {
160 match self {
161 Self::Tag { landing_pad, .. } | Self::All { landing_pad, .. } => landing_pad,
162 }
163 }
164
165 pub const fn with_ref(self) -> bool {
167 match self {
168 Self::Tag { with_ref, .. } | Self::All { with_ref, .. } => with_ref,
169 }
170 }
171}
172
173#[derive(Clone, PartialEq, Eq)]
175#[cfg_attr(feature = "debug", derive(Debug))]
176#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
177pub struct ExceptionHandler {
178 pub start_ip: u32,
180 pub end_ip: u32,
182 pub catches: Box<[ExceptionCatch]>,
184}
185
186impl Operand128<MemoryOperand> {
187 #[inline]
189 pub fn new(offset: u64, memory: MemAddr) -> Self {
190 let mut operand = Self::default();
191 write_field!(operand, u64, 0, offset);
192 write_field!(operand, u32, 8, memory);
193 operand
194 }
195
196 #[inline(always)]
198 pub fn offset(&self) -> u64 {
199 read_field!(self, u64, 0)
200 }
201
202 #[inline(always)]
204 pub fn memory(&self) -> MemAddr {
205 read_field!(self, u32, 8)
206 }
207}
208
209impl Operand64<CompactMemoryOperand> {
210 #[inline]
212 pub fn new(offset: u32, memory: u16) -> Self {
213 let mut operand = Self::default();
214 write_field!(operand, u32, 0, offset);
215 write_field!(operand, u16, 4, memory);
216 operand
217 }
218
219 #[inline(always)]
221 pub fn offset(&self) -> u32 {
222 read_field!(self, u32, 0)
223 }
224
225 #[inline(always)]
227 pub fn memory(&self) -> u16 {
228 read_field!(self, u16, 4)
229 }
230}
231
232impl Operand128<BranchTableOperand> {
233 #[inline]
234 pub fn new(target: u32, start: u32, len: u32) -> Self {
235 let mut operand = Self::default();
236 write_field!(operand, u32, 0, target);
237 write_field!(operand, u32, 4, start);
238 write_field!(operand, u32, 8, len);
239 operand
240 }
241 #[inline(always)]
242 pub fn start(&self) -> u32 {
243 read_field!(self, u32, 4)
244 }
245 #[inline(always)]
246 pub fn size(&self) -> u32 {
247 read_field!(self, u32, 8)
248 }
249}
250
251impl Operand128<MemoryFillOperand> {
252 #[inline]
253 pub fn new(memory: MemAddr, byte: u8, value: i32) -> Self {
254 let mut operand = Self::default();
255 write_field!(operand, u32, 0, memory);
256 write_field!(operand, u8, 4, byte);
257 write_field!(operand, i32, 5, value);
258 operand
259 }
260 #[inline(always)]
261 pub fn memory(&self) -> MemAddr {
262 read_field!(self, u32, 0)
263 }
264 #[inline(always)]
265 pub fn byte(&self) -> u8 {
266 read_field!(self, u8, 4)
267 }
268 #[inline(always)]
269 pub fn value(&self) -> i32 {
270 read_field!(self, i32, 5)
271 }
272}
273
274impl Operand128<LocalUpdateOperand> {
275 #[inline]
276 pub fn new(target: u32, value: i32, local: LocalAddr, on_zero: bool) -> Self {
277 let mut operand = Self::default();
278 write_field!(operand, u32, 0, target);
279 write_field!(operand, i32, 4, value);
280 write_field!(operand, u16, 8, local);
281 write_field!(operand, u8, 10, u8::from(on_zero));
282 operand
283 }
284 #[inline(always)]
285 pub fn value(&self) -> i32 {
286 read_field!(self, i32, 4)
287 }
288 #[inline(always)]
289 pub fn local(&self) -> LocalAddr {
290 read_field!(self, u16, 8)
291 }
292 #[inline(always)]
293 pub fn on_zero(&self) -> bool {
294 read_field!(self, u8, 10) != 0
295 }
296}
297
298impl Operand128<GlobalUpdateOperand> {
299 #[inline]
300 pub fn new(target: u32, value: i32, global: GlobalAddr, on_zero: bool) -> Self {
301 let mut operand = Self::default();
302 write_field!(operand, u32, 0, target);
303 write_field!(operand, i32, 4, value);
304 write_field!(operand, u32, 8, global);
305 write_field!(operand, u8, 12, u8::from(on_zero));
306 operand
307 }
308 #[inline(always)]
309 pub fn value(&self) -> i32 {
310 read_field!(self, i32, 4)
311 }
312 #[inline(always)]
313 pub fn global(&self) -> GlobalAddr {
314 read_field!(self, u32, 8)
315 }
316 #[inline(always)]
317 pub fn on_zero(&self) -> bool {
318 read_field!(self, u8, 12) != 0
319 }
320}
321
322impl Operand128<LocalUpdateCmpOperand> {
323 #[inline]
324 pub fn new(target: u32, value: i32, local: LocalAddr, right: LocalAddr) -> Self {
325 let mut operand = Self::default();
326 write_field!(operand, u32, 0, target);
327 write_field!(operand, i32, 4, value);
328 write_field!(operand, u16, 8, local);
329 write_field!(operand, u16, 10, right);
330 operand
331 }
332 #[inline(always)]
333 pub fn value(&self) -> i32 {
334 read_field!(self, i32, 4)
335 }
336 #[inline(always)]
337 pub fn local(&self) -> LocalAddr {
338 read_field!(self, u16, 8)
339 }
340 #[inline(always)]
341 pub fn right(&self) -> LocalAddr {
342 read_field!(self, u16, 10)
343 }
344}
345
346impl CompactMemoryArg {
347 #[inline]
349 pub const fn offset(self) -> u64 {
350 self.offset as u64
351 }
352
353 #[inline]
355 pub const fn mem_addr(self) -> MemAddr {
356 self.mem_addr as MemAddr
357 }
358}
359
360impl TryFrom<Operand128<MemoryOperand>> for CompactMemoryArg {
361 type Error = ();
362
363 #[inline]
364 fn try_from(arg: Operand128<MemoryOperand>) -> Result<Self, Self::Error> {
365 Ok(Self {
366 offset: u32::try_from(arg.offset()).map_err(|_| ())?,
367 mem_addr: u16::try_from(arg.memory()).map_err(|_| ())?,
368 })
369 }
370}
371
372impl From<CompactMemoryArg> for Operand64<CompactMemoryOperand> {
373 #[inline]
374 fn from(arg: CompactMemoryArg) -> Self {
375 Self::new(arg.offset, arg.mem_addr)
376 }
377}
378
379const _: () = {
380 assert!(core::mem::size_of::<Operand64Idx<i64>>() == 4);
381 assert!(core::mem::size_of::<Operand64>() == 8);
382 assert!(core::mem::size_of::<Operand128>() == 16);
383 assert!(core::mem::size_of::<CompactMemoryArg>() == 6);
384 assert!(core::mem::size_of::<MemoryLocalArg>() == 6);
385 assert!(core::mem::size_of::<LocalTripleArg>() == 6);
386};
387
388#[derive(Clone, Copy, PartialEq)]
389#[cfg_attr(feature = "debug", derive(Debug))]
390#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
391pub enum ConstInstruction {
392 I32Const(i32),
393 I64Const(i64),
394 F32Const(f32),
395 F64Const(f64),
396 V128Const([u8; 16]),
397 GlobalGet32(GlobalAddr),
398 GlobalGet64(GlobalAddr),
399 GlobalGet128(GlobalAddr),
400 GlobalGetRef(GlobalAddr),
401 RefNull(RefType),
402 RefFunc(ModuleFuncIdx),
403 RefI31,
404 AnyConvertExtern,
405 ExternConvertAny,
406 StructNew(TypeAddr),
407 StructNewDefault(TypeAddr),
408 ArrayNew(TypeAddr),
409 ArrayNewDefault(TypeAddr),
410 ArrayNewFixed(TypeAddr, u32),
411 I32Add,
412 I32Sub,
413 I32Mul,
414 I64Add,
415 I64Sub,
416 I64Mul,
417}
418
419#[derive(Clone, Copy, PartialEq, Eq)]
421#[cfg_attr(feature = "debug", derive(Debug))]
422#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
423pub enum CmpOp {
424 Eq,
425 Ne,
426 LtS,
427 LtU,
428 GtS,
429 GtU,
430 LeS,
431 LeU,
432 GeS,
433 GeU,
434}
435
436impl CmpOp {
437 #[inline]
439 pub const fn inverse(self) -> Self {
440 match self {
441 Self::Eq => Self::Ne,
442 Self::Ne => Self::Eq,
443 Self::LtS => Self::GeS,
444 Self::LtU => Self::GeU,
445 Self::GtS => Self::LeS,
446 Self::GtU => Self::LeU,
447 Self::LeS => Self::GtS,
448 Self::LeU => Self::GtU,
449 Self::GeS => Self::LtS,
450 Self::GeU => Self::LtU,
451 }
452 }
453}
454
455#[derive(Clone, Copy, PartialEq, Eq)]
456#[cfg_attr(feature = "debug", derive(Debug))]
457#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
458pub enum BinOp {
459 IAdd,
460 ISub,
461 IMul,
462 IAnd,
463 IOr,
464 IXor,
465 IShl,
466 IShrS,
467 IShrU,
468 IRotl,
469 IRotr,
470 FAdd,
471 FSub,
472 FMul,
473 FDiv,
474 FMin,
475 FMax,
476 FCopysign,
477}
478
479impl BinOp {
480 #[inline]
482 pub const fn inc_delta(self, immediate: i32) -> Option<i32> {
483 match self {
484 Self::IAdd => Some(immediate),
485 Self::ISub => Some(immediate.wrapping_neg()),
486 _ => None,
487 }
488 }
489}
490
491#[derive(Clone, Copy, PartialEq, Eq)]
492#[cfg_attr(feature = "debug", derive(Debug))]
493#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
494pub enum BinOp128 {
495 And,
496 AndNot,
497 Or,
498 Xor,
499 I64x2Add,
500 I64x2Mul,
501}
502
503macro_rules! define_instructions {
504 ($($variant:ident $(($($field:ty),* $(,)?))? $({ $($name:ident: $named_field:ty),* $(,)? })?),* $(,)?) => {
505 #[derive(Clone, Copy, PartialEq)]
511 #[cfg_attr(feature = "debug", derive(Debug))]
512 #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
513 pub enum Instruction {
514 $($variant $(($($field),*))? $({ $($name: $named_field),* })?),*
515 }
516
517 #[doc(hidden)]
518 #[repr(u16)]
519 #[derive(Clone, Copy)]
520 pub enum InstructionOpcode {
521 $($variant,)*
522 }
523
524 impl InstructionOpcode {
525 #[doc(hidden)]
526 pub const COUNT: usize = [$(Self::$variant),*].len();
527 }
528
529 impl Instruction {
530 #[inline(always)]
532 pub const fn opcode(&self) -> InstructionOpcode {
533 match self {
534 $(Self::$variant { .. } => InstructionOpcode::$variant,)*
535 }
536 }
537 }
538 };
539}
540
541define_instructions! {
542 LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr),
543 AddConst32(i32), AndConst32(i32), XorConst32(i32), ShrUConst32(i32), AddConst64(Operand64Idx<i64>),
544 IncLocal32(I32LocalArg), IncLocal64(PackedOp64<LocalAddr, i64>),
545
546 BinOpLocalLocal32(BinOp, LocalAddr, LocalAddr), BinOpLocalLocal64(BinOp, LocalAddr, LocalAddr),
548 BinOpLocalLocal128(BinOp128, LocalAddr, LocalAddr),
549 CmpLocalLocal32(CmpOp, LocalAddr, LocalAddr), CmpLocalLocal64(CmpOp, LocalAddr, LocalAddr),
550 AddLocalLocalSet32(LocalTripleArg), AddLocalLocalTee32(LocalTripleArg),
551 BinOpLocalLocalSet32(PackedOp64<BinOp, (u16, u16, u16)>), BinOpLocalLocalSet64(PackedOp64<BinOp, (u16, u16, u16)>), BinOpLocalLocalSet128(PackedOp64<BinOp128, (u16, u16, u16)>),
552 BinOpLocalLocalTee32(PackedOp64<BinOp, (u16, u16, u16)>), BinOpLocalLocalTee64(PackedOp64<BinOp, (u16, u16, u16)>), BinOpLocalLocalTee128(PackedOp64<BinOp128, (u16, u16, u16)>),
553
554 AddLocalConst32(I32LocalArg), SubLocalConst32(I32LocalArg), MulLocalConst32(I32LocalArg),
555 AndLocalConst32(I32LocalArg), ShrULocalConst32(I32LocalArg),
556 BinOpLocalConst32(PackedOp64<BinOp, (u16, u32)>), BinOpLocalConst64(PackedOp128<BinOp, (u16, u64)>),
557 BinOpLocalConst128(PackedOp64<BinOp128, (u16, Operand128Idx<[u8; 16]>)>),
558 BinOpLocalConstSet32(PackedOp64<BinOp, (u16, u16, u32)>), BinOpLocalConstSet64(PackedOp128<BinOp, (u16, u16, u64)>), BinOpLocalConstSet128(PackedOp64<BinOp128, (u16, u16, Operand128Idx<[u8; 16]>)>),
559 BinOpLocalConstTee32(PackedOp64<BinOp, (u16, u16, u32)>), BinOpLocalConstTee64(PackedOp128<BinOp, (u16, u16, u64)>), BinOpLocalConstTee128(PackedOp64<BinOp128, (u16, u16, Operand128Idx<[u8; 16]>)>),
560
561 BinOpStackConst32(BinOp, i32), BinOpStackConst64(PackedOp64<BinOp, i64>),
562
563 BinOpStackLocal32(BinOp, LocalAddr),
564 BinOpStackLocalSet32(BinOp, LocalAddr, LocalAddr),
565 BinOpStackLocalTee32(BinOp, LocalAddr, LocalAddr),
566 BinOpStackLocal128(BinOp128, LocalAddr),
567 BinOpStackGlobal32(BinOp, u32),
568 BinOpStackGlobal64(BinOp, u32),
569 BinOpGlobalConst32(PackedOp64<BinOp, (u32, u32)>), BinOpGlobalConst64(PackedOp128<BinOp, (u32, u64)>),
570 BinOpGlobalConst128(PackedOp64<BinOp128, (u32, Operand128Idx<[u8; 16]>)>),
571
572 SetLocalConst32(I32LocalArg), SetLocalConst64(PackedOp64<LocalAddr, i64>), SetLocalConst128(PackedOp128<LocalAddr, [u8; 16]>),
573 IncMemoryLocal32(MemoryLocalArg), IncMemoryLocal64(MemoryLocalArg),
574 StoreLocalLocal32(MemoryLocalArg), StoreLocalLocal64(MemoryLocalArg), StoreLocalLocal128(MemoryLocalArg),
575 LoadLocal32(MemoryLocalArg), LoadLocal64(MemoryLocalArg),
576 LoadLocal8S32(MemoryLocalArg), LoadLocal8U32(MemoryLocalArg),
577 LoadLocal16S32(MemoryLocalArg), LoadLocal16U32(MemoryLocalArg),
578 LoadLocalTee32(MemoryLocalArg), LoadLocalSet32(MemoryLocalArg),
579 LoadLocalTee8S32(MemoryLocalArg), LoadLocalTee8U32(MemoryLocalArg),
580 LoadLocalTee16S32(MemoryLocalArg), LoadLocalTee16U32(MemoryLocalArg),
581 LoadLocalSet8S32(MemoryLocalArg), LoadLocalSet8U32(MemoryLocalArg),
582 LoadLocalSet16S32(MemoryLocalArg), LoadLocalSet16U32(MemoryLocalArg),
583 LoadLocalTee128(MemoryLocalArg), LoadLocalSet128(MemoryLocalArg),
584 AndConstTee32(I32LocalArg), SubConstTee32(I32LocalArg),
585 AndConstTee64(PackedOp64<LocalAddr, i64>), SubConstTee64(PackedOp64<LocalAddr, i64>),
586 MulAccLocal32(LocalAddr), MulAccLocal64(LocalAddr),
587 FMulAccLocal32(LocalAddr), FMulAccLocal64(LocalAddr),
588 I32Add3,
589 I64Add3,
590 FMaStoreF32(CompactMemoryArg),
591 FMaStoreF64(CompactMemoryArg),
592
593 Unreachable,
596 Jump(u32),
597 JumpIfZero32(u32),
598 JumpIfNonZero32(u32),
599 JumpIfZero64(u32),
600 JumpIfNonZero64(u32),
601 JumpIfRefNull(u32),
602 JumpIfRefNonNull(u32),
603 JumpIfLocalZero32(TargetLocalArg), JumpIfLocalNonZero32(TargetLocalArg),
604 JumpIfLocalZero64(TargetLocalArg), JumpIfLocalNonZero64(TargetLocalArg),
605 JumpCmpStackConst32(PackedOp64<CmpOp, (u32, i32)>), JumpCmpStackConst64(PackedOp128<CmpOp, (u32, i64)>),
606 JumpCmpStackLocal32(PackedOp64<CmpOp, (u32, u16)>), JumpCmpStackLocal64(PackedOp64<CmpOp, (u32, u16)>),
607 BinOpLocalConstJump32(PackedOp128<BinOp, LocalUpdateOperand>), BinOpLocalConstJumpCmpLocal32(PackedOp128<(BinOp, CmpOp), LocalUpdateCmpOperand>),
608 BinOpStackConstTeeLocalJump32(PackedOp128<BinOp, LocalUpdateOperand>), BinOpGlobalConstJump32(PackedOp128<BinOp, GlobalUpdateOperand>),
609 IncLocalJump32(Operand128Idx<LocalUpdateOperand>), IncStackTeeLocalJump32(Operand128Idx<LocalUpdateOperand>), IncGlobalJump32(Operand128Idx<GlobalUpdateOperand>),
610 IncLocalJumpCmpLocal32(PackedOp128<CmpOp, LocalUpdateCmpOperand>), JumpCmpLocalConst32(PackedOp128<CmpOp, (u32, i32, u16)>), JumpCmpLocalConst64(PackedOp128<CmpOp, (u32, i32, u16)>),
611 JumpCmpLocalLocal32(PackedOp64<CmpOp, (u32, u16, u16)>), JumpCmpLocalLocal64(PackedOp64<CmpOp, (u32, u16, u16)>),
612 DropKeep32 { base: u16, keep: u16 }, DropKeep64 { base: u16, keep: u16 }, DropKeep128 { base: u16, keep: u16 }, BranchTable(Operand128Idx<BranchTableOperand>),
613 Return,
614 ReturnVoid,
615 Return32,
616 Return64,
617 Return128,
618 Call(FuncAddr),
619 CallSelf,
620 CallIndirect(Operand64Idx<(u32, u32)>),
621 CallRef(TypeAddr),
622 ReturnCall(FuncAddr),
623 ReturnCallSelf,
624 ReturnCallIndirect(Operand64Idx<(u32, u32)>),
625 ReturnCallRef(TypeAddr),
626 Throw(TagAddr),
627 ThrowRef,
628
629 Drop32, Select32,
632 Drop64, Select64,
633 Drop128, Select128,
634 SelectMulti(ValueCounts),
635
636 GlobalGet32(GlobalAddr), GlobalSet32(GlobalAddr), GlobalTee32(GlobalAddr), LocalGet32(LocalAddr), LocalSet32(LocalAddr), LocalTee32(LocalAddr),
639 GlobalGet64(GlobalAddr), GlobalSet64(GlobalAddr), GlobalTee64(GlobalAddr), LocalGet64(LocalAddr), LocalSet64(LocalAddr), LocalTee64(LocalAddr),
640 GlobalGet128(GlobalAddr), GlobalSet128(GlobalAddr), GlobalTee128(GlobalAddr), LocalGet128(LocalAddr), LocalSet128(LocalAddr), LocalTee128(LocalAddr),
641
642 I32Load(Operand128Idx<MemoryOperand>), I64Load(Operand128Idx<MemoryOperand>), F32Load(Operand128Idx<MemoryOperand>), F64Load(Operand128Idx<MemoryOperand>),
644 I32Load8S(Operand128Idx<MemoryOperand>), I32Load8U(Operand128Idx<MemoryOperand>), I32Load16S(Operand128Idx<MemoryOperand>), I32Load16U(Operand128Idx<MemoryOperand>),
645 I64Load8S(Operand128Idx<MemoryOperand>), I64Load8U(Operand128Idx<MemoryOperand>), I64Load16S(Operand128Idx<MemoryOperand>), I64Load16U(Operand128Idx<MemoryOperand>), I64Load32S(Operand128Idx<MemoryOperand>), I64Load32U(Operand128Idx<MemoryOperand>),
646 I32Store(Operand128Idx<MemoryOperand>), I64Store(Operand128Idx<MemoryOperand>), F32Store(Operand128Idx<MemoryOperand>), F64Store(Operand128Idx<MemoryOperand>),
647 I32Store8(Operand128Idx<MemoryOperand>), I32Store16(Operand128Idx<MemoryOperand>), I64Store8(Operand128Idx<MemoryOperand>), I64Store16(Operand128Idx<MemoryOperand>), I64Store32(Operand128Idx<MemoryOperand>),
648 MemorySize(MemAddr),
649 MemoryGrow(MemAddr),
650
651 Const32(i32),
653 Const64Imm(i32),
654 Const64(Operand64Idx<i64>),
655
656 RefNull(RefType),
658 RefFunc(FuncAddr),
659 RefIsNull,
660 RefAsNonNull,
661 RefI31,
662 I31GetS,
663 I31GetU,
664 RefEq,
665 RefTest(RefType),
666 RefCast(RefType),
667 BrOnCast(Operand64Idx<(u32, u32)>),
668 BrOnCastFail(Operand64Idx<(u32, u32)>),
669
670 StructNew(TypeAddr),
672 StructNewDefault(TypeAddr),
673 StructGet(Operand64Idx<(u32, u32)>), StructGetS(Operand64Idx<(u32, u32)>), StructGetU(Operand64Idx<(u32, u32)>), StructSet(Operand64Idx<(u32, u32)>),
674 ArrayNew(TypeAddr),
675 ArrayNewDefault(TypeAddr),
676 ArrayNewFixed(Operand64Idx<(u32, u32)>),
677 ArrayNewData(Operand64Idx<(u32, u32)>), ArrayNewElem(Operand64Idx<(u32, u32)>),
678 ArrayGet(TypeAddr),
679 ArrayGetS(TypeAddr),
680 ArrayGetU(TypeAddr),
681 ArraySet(TypeAddr),
682 ArrayLen,
683 ArrayFill(TypeAddr),
684 ArrayCopy(Operand64Idx<(u32, u32)>), ArrayInitData(Operand64Idx<(u32, u32)>), ArrayInitElem(Operand64Idx<(u32, u32)>),
685
686 I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU,
689 I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU,
690
691 F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge,
693 F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge,
694 I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU,
695 I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU,
696
697 I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr,
699 I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr,
700
701 F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign,
703 F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign,
704 I32WrapI64, I32TruncF32S, I32TruncF32U, I32TruncF64S, I32TruncF64U, I32Extend8S, I32Extend16S,
705 I64Extend8S, I64Extend16S, I64Extend32S, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U,
706 F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64,
707 F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32,
708
709 I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U,
711 I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U,
712
713 TableInit(Operand64Idx<(u32, u32)>),
715 TableGet(TableAddr),
716 TableSet(TableAddr),
717 TableCopy(Operand64Idx<(u32, u32)>),
718 TableGrow(TableAddr),
719 TableSize(TableAddr),
720 TableFill(TableAddr),
721
722 MemoryInit(Operand64Idx<(u32, u32)>), MemoryCopy(Operand64Idx<(u32, u32)>),
724 MemoryFill(MemAddr),
725 MemoryFillConst(Operand128Idx<MemoryFillOperand>),
726 DataDrop(DataAddr),
727 ElemDrop(ElemAddr),
728
729 I64Add128, I64Sub128, I64MulWideS, I64MulWideU,
731
732 V128Load(Operand128Idx<MemoryOperand>), V128Load8x8S(Operand128Idx<MemoryOperand>), V128Load8x8U(Operand128Idx<MemoryOperand>),
734 V128Load16x4S(Operand128Idx<MemoryOperand>), V128Load16x4U(Operand128Idx<MemoryOperand>), V128Load32x2S(Operand128Idx<MemoryOperand>), V128Load32x2U(Operand128Idx<MemoryOperand>),
735
736 V128Load8Splat(Operand128Idx<MemoryOperand>), V128Load16Splat(Operand128Idx<MemoryOperand>), V128Load32Splat(Operand128Idx<MemoryOperand>), V128Load64Splat(Operand128Idx<MemoryOperand>),
737 V128Load8Lane(MemoryLaneArg), V128Load16Lane(MemoryLaneArg), V128Load32Lane(MemoryLaneArg), V128Load64Lane(MemoryLaneArg),
738
739 V128Load32Zero(Operand128Idx<MemoryOperand>), V128Load64Zero(Operand128Idx<MemoryOperand>),
740
741 V128Store(Operand128Idx<MemoryOperand>), V128Store8Lane(MemoryLaneArg), V128Store16Lane(MemoryLaneArg), V128Store32Lane(MemoryLaneArg), V128Store64Lane(MemoryLaneArg),
742
743 I8x16Shuffle(Operand128Idx<[u8; 16]>),
744 Const128Imm(u32), Const128(Operand128Idx<[u8; 16]>),
745
746 I8x16ExtractLaneS(u8), I8x16ExtractLaneU(u8), I8x16ReplaceLane(u8),
747 I16x8ExtractLaneS(u8), I16x8ExtractLaneU(u8), I16x8ReplaceLane(u8),
748 I32x4ExtractLane(u8), I32x4ReplaceLane(u8),
749 I64x2ExtractLane(u8), I64x2ReplaceLane(u8),
750 F32x4ExtractLane(u8), F32x4ReplaceLane(u8),
751 F64x2ExtractLane(u8), F64x2ReplaceLane(u8),
752
753 V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, I8x16Swizzle,
754 I8x16Splat, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU,
755 I16x8Splat, I16x8Eq, I16x8Ne, I16x8LtS, I16x8LtU, I16x8GtS, I16x8GtU, I16x8LeS, I16x8LeU, I16x8GeS, I16x8GeU,
756 I32x4Splat, I32x4Eq, I32x4Ne, I32x4LtS, I32x4LtU, I32x4GtS, I32x4GtU, I32x4LeS, I32x4LeU, I32x4GeS, I32x4GeU,
757 I64x2Splat, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS,
758 F32x4Splat, F32x4Eq, F32x4Ne, F32x4Lt, F32x4Gt, F32x4Le, F32x4Ge,
759 F64x2Splat, F64x2Eq, F64x2Ne, F64x2Lt, F64x2Gt, F64x2Le, F64x2Ge,
760
761 I8x16Abs, I8x16Neg, I8x16AllTrue, I8x16Bitmask, I8x16Shl, I8x16ShrS, I8x16ShrU, I8x16Add, I8x16Sub, I8x16MinS, I8x16MinU, I8x16MaxS, I8x16MaxU,
762 I16x8Abs, I16x8Neg, I16x8AllTrue, I16x8Bitmask, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, I16x8Sub, I16x8MinS, I16x8MinU, I16x8MaxS, I16x8MaxU,
763 I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU,
764 I64x2Abs, I64x2Neg, I64x2AllTrue, I64x2Bitmask, I64x2Shl, I64x2ShrS, I64x2ShrU, I64x2Add, I64x2Sub, I64x2Mul,
765
766 I8x16NarrowI16x8S, I8x16NarrowI16x8U, I8x16AddSatS, I8x16AddSatU, I8x16SubSatS, I8x16SubSatU, I8x16AvgrU,
767 I16x8NarrowI32x4S, I16x8NarrowI32x4U, I16x8AddSatS, I16x8AddSatU, I16x8SubSatS, I16x8SubSatU, I16x8AvgrU,
768
769 I16x8ExtAddPairwiseI8x16S, I16x8ExtAddPairwiseI8x16U, I16x8Mul,
770 I32x4ExtAddPairwiseI16x8S, I32x4ExtAddPairwiseI16x8U, I32x4Mul,
771
772 I16x8ExtMulLowI8x16S, I16x8ExtMulLowI8x16U, I16x8ExtMulHighI8x16S, I16x8ExtMulHighI8x16U,
773 I32x4ExtMulLowI16x8S, I32x4ExtMulLowI16x8U, I32x4ExtMulHighI16x8S, I32x4ExtMulHighI16x8U,
774 I64x2ExtMulLowI32x4S, I64x2ExtMulLowI32x4U, I64x2ExtMulHighI32x4S, I64x2ExtMulHighI32x4U,
775
776 I16x8ExtendLowI8x16S, I16x8ExtendLowI8x16U, I16x8ExtendHighI8x16S, I16x8ExtendHighI8x16U,
777 I32x4ExtendLowI16x8S, I32x4ExtendLowI16x8U, I32x4ExtendHighI16x8S, I32x4ExtendHighI16x8U,
778 I64x2ExtendLowI32x4S, I64x2ExtendLowI32x4U, I64x2ExtendHighI32x4S, I64x2ExtendHighI32x4U,
779
780 I8x16Popcnt, I16x8Q15MulrSatS, I32x4DotI16x8S,
781
782 F32x4Ceil, F32x4Floor, F32x4Trunc, F32x4Nearest, F32x4Abs, F32x4Neg, F32x4Sqrt, F32x4Add, F32x4Sub, F32x4Mul, F32x4Div, F32x4Min, F32x4Max, F32x4PMin, F32x4PMax,
783 F64x2Ceil, F64x2Floor, F64x2Trunc, F64x2Nearest, F64x2Abs, F64x2Neg, F64x2Sqrt, F64x2Add, F64x2Sub, F64x2Mul, F64x2Div, F64x2Min, F64x2Max, F64x2PMin, F64x2PMax,
784 I32x4TruncSatF32x4S, I32x4TruncSatF32x4U,
785 F32x4ConvertI32x4S, F32x4ConvertI32x4U,
786 I32x4TruncSatF64x2SZero, I32x4TruncSatF64x2UZero,
787 F64x2ConvertLowI32x4S, F64x2ConvertLowI32x4U,
788 F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4,
789
790 I8x16RelaxedSwizzle,
792 I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U,
793 I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero,
794 F32x4RelaxedMadd, F32x4RelaxedNmadd,
795 F64x2RelaxedMadd, F64x2RelaxedNmadd,
796 I8x16RelaxedLaneselect, I16x8RelaxedLaneselect,
797 I32x4RelaxedLaneselect, I64x2RelaxedLaneselect,
798 F32x4RelaxedMin, F32x4RelaxedMax,
799 F64x2RelaxedMin, F64x2RelaxedMax,
800 I16x8RelaxedQ15mulrS,
801 I16x8RelaxedDotI8x16I7x16S,
802 I32x4RelaxedDotI8x16I7x16AddS,
803
804 SelectStore32(Operand128Idx<MemoryOperand>), SelectStore64(Operand128Idx<MemoryOperand>),
805}
806
807const _: () = assert!(core::mem::size_of::<Instruction>() == 8);
808
809#[cfg(test)]
810mod tests {
811 use super::*;
812
813 #[test]
814 fn compact_instruction_layout_is_exact() {
815 assert_eq!(core::mem::size_of::<Instruction>(), 8);
816 assert_eq!(core::mem::size_of::<CompactMemoryArg>(), 6);
817 assert_eq!(core::mem::size_of::<MemoryLocalArg>(), 6);
818 assert_eq!(core::mem::size_of::<LocalTripleArg>(), 6);
819 }
820
821 #[test]
822 fn operand_lanes_round_trip_max_values() {
823 let memory = Operand128::<MemoryOperand>::new(u64::MAX, u32::MAX);
824 assert_eq!(memory.offset(), u64::MAX);
825 assert_eq!(memory.memory(), u32::MAX);
826
827 let value = Operand128::<LocalUpdateOperand>::new(u32::MAX, i32::MIN, u16::MAX, true);
828 assert_eq!(value.target(), u32::MAX);
829 assert_eq!(value.value(), i32::MIN);
830 assert_eq!(value.local(), u16::MAX);
831 assert!(value.on_zero());
832 }
833}