Skip to main content

pulley_interpreter/
interp.rs

1//! Interpretation of pulley bytecode.
2
3use crate::decode::*;
4use crate::encode::Encode;
5use crate::imms::*;
6use crate::profile::{ExecutingPc, ExecutingPcRef};
7use crate::regs::*;
8use alloc::string::ToString;
9use core::fmt;
10use core::mem;
11use core::ops::ControlFlow;
12use core::ops::{Index, IndexMut};
13use core::ptr::NonNull;
14use pulley_macros::interp_disable_if_cfg;
15use wasmtime_core::alloc::TryVec;
16use wasmtime_core::error::OutOfMemory;
17use wasmtime_core::math::{WasmFloat, f32_cvt_to_int_bounds, f64_cvt_to_int_bounds};
18
19mod debug;
20#[cfg(all(not(pulley_tail_calls), not(pulley_assume_llvm_makes_tail_calls)))]
21mod match_loop;
22#[cfg(any(pulley_tail_calls, pulley_assume_llvm_makes_tail_calls))]
23mod tail_loop;
24
25const DEFAULT_STACK_SIZE: usize = 1 << 20; // 1 MiB
26
27/// A virtual machine for interpreting Pulley bytecode.
28pub struct Vm {
29    state: MachineState,
30    executing_pc: ExecutingPc,
31}
32
33impl Vm {
34    /// Create a new virtual machine with the default stack size.
35    pub fn new() -> Result<Self, OutOfMemory> {
36        Self::with_stack(DEFAULT_STACK_SIZE)
37    }
38
39    /// Create a new virtual machine with the given stack.
40    pub fn with_stack(stack_size: usize) -> Result<Self, OutOfMemory> {
41        Ok(Self {
42            state: MachineState::with_stack(stack_size)?,
43            executing_pc: ExecutingPc::default(),
44        })
45    }
46
47    /// Get a shared reference to this VM's machine state.
48    pub fn state(&self) -> &MachineState {
49        &self.state
50    }
51
52    /// Get an exclusive reference to this VM's machine state.
53    pub fn state_mut(&mut self) -> &mut MachineState {
54        &mut self.state
55    }
56
57    /// Call a bytecode function.
58    ///
59    /// The given `func` must point to the beginning of a valid Pulley bytecode
60    /// function.
61    ///
62    /// The given `args` must match the number and type of arguments that
63    /// function expects.
64    ///
65    /// The given `rets` must match the function's actual return types.
66    ///
67    /// Returns either the resulting values, or the PC at which a trap was
68    /// raised.
69    pub unsafe fn call<'a, T>(
70        &'a mut self,
71        func: NonNull<u8>,
72        args: &[Val],
73        rets: T,
74    ) -> DoneReason<impl Iterator<Item = Val> + use<'a, T>>
75    where
76        T: IntoIterator<Item = RegType> + 'a,
77    {
78        unsafe {
79            let lr = self.call_start(args);
80
81            match self.call_run(func) {
82                DoneReason::ReturnToHost(()) => DoneReason::ReturnToHost(self.call_end(lr, rets)),
83                DoneReason::Trap { pc, kind } => DoneReason::Trap { pc, kind },
84                DoneReason::CallIndirectHost { id, resume } => {
85                    DoneReason::CallIndirectHost { id, resume }
86                }
87            }
88        }
89    }
90
91    /// Performs the initial part of [`Vm::call`] in setting up the `args`
92    /// provided in registers according to Pulley's ABI.
93    ///
94    /// # Return
95    ///
96    /// Returns the old `lr` register value. The current `lr` value is replaced
97    /// with a sentinel that triggers a return to the host when returned-to.
98    ///
99    /// # Unsafety
100    ///
101    /// All the same unsafety as `call` and additionally, you must
102    /// invoke `call_run` and then `call_end` after calling `call_start`.
103    /// If you don't want to wrangle these invocations, use `call` instead
104    /// of `call_{start,run,end}`.
105    pub unsafe fn call_start<'a>(&'a mut self, args: &[Val]) -> *mut u8 {
106        // NB: make sure this method stays in sync with
107        // `PulleyMachineDeps::compute_arg_locs`!
108
109        let mut x_args = (0..15).map(|x| unsafe { XReg::new_unchecked(x) });
110        let mut f_args = (0..16).map(|f| unsafe { FReg::new_unchecked(f) });
111        #[cfg(not(pulley_disable_interp_simd))]
112        let mut v_args = (0..16).map(|v| unsafe { VReg::new_unchecked(v) });
113
114        for arg in args {
115            match arg {
116                Val::XReg(val) => match x_args.next() {
117                    Some(reg) => self.state[reg] = *val,
118                    None => todo!("stack slots"),
119                },
120                Val::FReg(val) => match f_args.next() {
121                    Some(reg) => self.state[reg] = *val,
122                    None => todo!("stack slots"),
123                },
124                #[cfg(not(pulley_disable_interp_simd))]
125                Val::VReg(val) => match v_args.next() {
126                    Some(reg) => self.state[reg] = *val,
127                    None => todo!("stack slots"),
128                },
129            }
130        }
131
132        mem::replace(&mut self.state.lr, HOST_RETURN_ADDR)
133    }
134
135    /// Performs the internal part of [`Vm::call`] where bytecode is actually
136    /// executed.
137    ///
138    /// # Unsafety
139    ///
140    /// In addition to all the invariants documented for `call`, you
141    /// may only invoke `call_run` after invoking `call_start` to
142    /// initialize this call's arguments.
143    pub unsafe fn call_run(&mut self, pc: NonNull<u8>) -> DoneReason<()> {
144        self.state.debug_assert_done_reason_none();
145        let interpreter = Interpreter {
146            state: &mut self.state,
147            pc: unsafe { UnsafeBytecodeStream::new(pc) },
148            executing_pc: self.executing_pc.as_ref(),
149        };
150        let done = interpreter.run();
151        self.state.done_decode(done)
152    }
153
154    /// Performs the tail end of [`Vm::call`] by returning the values as
155    /// determined by `rets` according to Pulley's ABI.
156    ///
157    /// The `old_ret` value should have been provided from `call_start`
158    /// previously.
159    ///
160    /// # Unsafety
161    ///
162    /// In addition to the invariants documented for `call`, this may
163    /// only be called after `call_run`.
164    pub unsafe fn call_end<'a>(
165        &'a mut self,
166        old_ret: *mut u8,
167        rets: impl IntoIterator<Item = RegType> + 'a,
168    ) -> impl Iterator<Item = Val> + 'a {
169        self.state.lr = old_ret;
170        // NB: make sure this method stays in sync with
171        // `PulleyMachineDeps::compute_arg_locs`!
172
173        let mut x_rets = (0..15).map(|x| unsafe { XReg::new_unchecked(x) });
174        let mut f_rets = (0..16).map(|f| unsafe { FReg::new_unchecked(f) });
175        #[cfg(not(pulley_disable_interp_simd))]
176        let mut v_rets = (0..16).map(|v| unsafe { VReg::new_unchecked(v) });
177
178        rets.into_iter().map(move |ty| match ty {
179            RegType::XReg => match x_rets.next() {
180                Some(reg) => Val::XReg(self.state[reg]),
181                None => todo!("stack slots"),
182            },
183            RegType::FReg => match f_rets.next() {
184                Some(reg) => Val::FReg(self.state[reg]),
185                None => todo!("stack slots"),
186            },
187            #[cfg(not(pulley_disable_interp_simd))]
188            RegType::VReg => match v_rets.next() {
189                Some(reg) => Val::VReg(self.state[reg]),
190                None => todo!("stack slots"),
191            },
192            #[cfg(pulley_disable_interp_simd)]
193            RegType::VReg => panic!("simd support disabled at compile time"),
194        })
195    }
196
197    /// Returns the current `fp` register value.
198    pub fn fp(&self) -> *mut u8 {
199        self.state.fp
200    }
201
202    /// Returns the current `lr` register value.
203    pub fn lr(&self) -> *mut u8 {
204        self.state.lr
205    }
206
207    /// Returns whether the current `lr` register value is the return address
208    /// to the host that [`Vm::call_start`] installs.
209    pub fn lr_is_host_return(&self) -> bool {
210        self.state.lr == HOST_RETURN_ADDR
211    }
212
213    /// Sets the current `fp` register value.
214    pub unsafe fn set_fp(&mut self, fp: *mut u8) {
215        self.state.fp = fp;
216    }
217
218    /// Sets the current `lr` register value.
219    pub unsafe fn set_lr(&mut self, lr: *mut u8) {
220        self.state.lr = lr;
221    }
222
223    /// Gets a handle to the currently executing program counter for this
224    /// interpreter which can be read from other threads.
225    //
226    // Note that despite this field still existing with `not(feature =
227    // "profile")` it's hidden from the public API in that scenario as it has no
228    // methods anyway.
229    #[cfg(feature = "profile")]
230    pub fn executing_pc(&self) -> &ExecutingPc {
231        &self.executing_pc
232    }
233}
234
235impl Drop for Vm {
236    fn drop(&mut self) {
237        self.executing_pc.set_done();
238    }
239}
240
241/// The type of a register in the Pulley machine state.
242#[derive(Clone, Copy, Debug)]
243pub enum RegType {
244    /// An `x` register: integers.
245    XReg,
246
247    /// An `f` register: floats.
248    FReg,
249
250    /// A `v` register: vectors.
251    VReg,
252}
253
254/// A value that can be stored in a register.
255#[derive(Clone, Copy, Debug)]
256pub enum Val {
257    /// An `x` register value: integers.
258    XReg(XRegVal),
259
260    /// An `f` register value: floats.
261    FReg(FRegVal),
262
263    /// A `v` register value: vectors.
264    #[cfg(not(pulley_disable_interp_simd))]
265    VReg(VRegVal),
266}
267
268impl fmt::LowerHex for Val {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        match self {
271            Val::XReg(v) => fmt::LowerHex::fmt(v, f),
272            Val::FReg(v) => fmt::LowerHex::fmt(v, f),
273            #[cfg(not(pulley_disable_interp_simd))]
274            Val::VReg(v) => fmt::LowerHex::fmt(v, f),
275        }
276    }
277}
278
279impl From<XRegVal> for Val {
280    fn from(value: XRegVal) -> Self {
281        Val::XReg(value)
282    }
283}
284
285impl From<u64> for Val {
286    fn from(value: u64) -> Self {
287        XRegVal::new_u64(value).into()
288    }
289}
290
291impl From<u32> for Val {
292    fn from(value: u32) -> Self {
293        XRegVal::new_u32(value).into()
294    }
295}
296
297impl From<i64> for Val {
298    fn from(value: i64) -> Self {
299        XRegVal::new_i64(value).into()
300    }
301}
302
303impl From<i32> for Val {
304    fn from(value: i32) -> Self {
305        XRegVal::new_i32(value).into()
306    }
307}
308
309impl<T> From<*mut T> for Val {
310    fn from(value: *mut T) -> Self {
311        XRegVal::new_ptr(value).into()
312    }
313}
314
315impl From<FRegVal> for Val {
316    fn from(value: FRegVal) -> Self {
317        Val::FReg(value)
318    }
319}
320
321impl From<f64> for Val {
322    fn from(value: f64) -> Self {
323        FRegVal::new_f64(value).into()
324    }
325}
326
327impl From<f32> for Val {
328    fn from(value: f32) -> Self {
329        FRegVal::new_f32(value).into()
330    }
331}
332
333#[cfg(not(pulley_disable_interp_simd))]
334impl From<VRegVal> for Val {
335    fn from(value: VRegVal) -> Self {
336        Val::VReg(value)
337    }
338}
339
340/// An `x` register value: integers.
341#[derive(Copy, Clone)]
342pub struct XRegVal(XRegUnion);
343
344impl PartialEq for XRegVal {
345    fn eq(&self, other: &Self) -> bool {
346        self.get_u64() == other.get_u64()
347    }
348}
349
350impl Eq for XRegVal {}
351
352impl fmt::Debug for XRegVal {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        f.debug_struct("XRegVal")
355            .field("as_u64", &self.get_u64())
356            .finish()
357    }
358}
359
360impl fmt::LowerHex for XRegVal {
361    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362        fmt::LowerHex::fmt(&self.get_u64(), f)
363    }
364}
365
366/// Contents of an "x" register, or a general-purpose register.
367///
368/// This is represented as a Rust `union` to make it easier to access typed
369/// views of this, notably the `ptr` field which enables preserving a bit of
370/// provenance for Rust for values stored as a pointer and read as a pointer.
371///
372/// Note that the actual in-memory representation of this value is handled
373/// carefully at this time. Pulley bytecode exposes the ability to store a
374/// 32-bit result into a register and then read the 64-bit contents of the
375/// register. This leaves us with the question of what to do with the upper bits
376/// of the register when the 32-bit result is generated. Possibilities for
377/// handling this are:
378///
379/// 1. Do nothing, just store the 32-bit value. The problem with this approach
380///    means that the "upper bits" are now endianness-dependent. That means that
381///    the state of the register is now platform-dependent.
382/// 2. Sign or zero-extend. This restores platform-independent behavior but
383///    requires an extra store on 32-bit platforms because they can probably
384///    only store 32-bits at a time.
385/// 3. Always store the values in this union as little-endian. This means that
386///    big-endian platforms have to do a byte-swap but otherwise it has
387///    platform-independent behavior.
388///
389/// This union chooses route (3) at this time where the values here are always
390/// stored in little-endian form (even the `ptr` field). That guarantees
391/// cross-platform behavior while also minimizing the amount of data stored on
392/// writes.
393///
394/// In the future we may wish to benchmark this and possibly change this.
395/// Technically Cranelift-generated bytecode should never rely on the upper bits
396/// of a register if it didn't previously write them so this in theory doesn't
397/// actually matter for Cranelift or wasm semantics. The only cost right now is
398/// to big-endian platforms though and it's not certain how crucial performance
399/// will be there.
400///
401/// One final note is that this notably contrasts with native CPUs where
402/// native ISAs like RISC-V specifically define the entire register on every
403/// instruction, even if only the low half contains a significant result. Pulley
404/// is unlikely to become out-of-order within the CPU itself as it's interpreted
405/// meaning that severing data-dependencies with previous operations is
406/// hypothesized to not be too important. If this is ever a problem though it
407/// could increase the likelihood we go for route (2) above instead (or maybe
408/// even (1)).
409#[derive(Copy, Clone)]
410union XRegUnion {
411    i32: i32,
412    u32: u32,
413    i64: i64,
414    u64: u64,
415
416    // Note that this is intentionally `usize` and not an actual pointer like
417    // `*mut u8`. The reason for this is that provenance is required in Rust for
418    // pointers but Cranelift has no pointer type and thus no concept of
419    // provenance. That means that at-rest it's not known whether the value has
420    // provenance or not and basically means that Pulley is required to use
421    // "permissive provenance" in Rust as opposed to strict provenance.
422    //
423    // That's more-or-less a long-winded way of saying that storage of a pointer
424    // in this value is done with `.expose_provenance()` and reading a pointer
425    // uses `with_exposed_provenance_mut(..)`.
426    ptr: usize,
427}
428
429impl Default for XRegVal {
430    fn default() -> Self {
431        Self(unsafe { mem::zeroed() })
432    }
433}
434
435#[expect(missing_docs, reason = "self-describing methods")]
436impl XRegVal {
437    pub fn new_i32(x: i32) -> Self {
438        let mut val = XRegVal::default();
439        val.set_i32(x);
440        val
441    }
442
443    pub fn new_u32(x: u32) -> Self {
444        let mut val = XRegVal::default();
445        val.set_u32(x);
446        val
447    }
448
449    pub fn new_i64(x: i64) -> Self {
450        let mut val = XRegVal::default();
451        val.set_i64(x);
452        val
453    }
454
455    pub fn new_u64(x: u64) -> Self {
456        let mut val = XRegVal::default();
457        val.set_u64(x);
458        val
459    }
460
461    pub fn new_ptr<T>(ptr: *mut T) -> Self {
462        let mut val = XRegVal::default();
463        val.set_ptr(ptr);
464        val
465    }
466
467    pub fn get_i32(&self) -> i32 {
468        let x = unsafe { self.0.i32 };
469        i32::from_le(x)
470    }
471
472    pub fn get_u32(&self) -> u32 {
473        let x = unsafe { self.0.u32 };
474        u32::from_le(x)
475    }
476
477    pub fn get_i64(&self) -> i64 {
478        let x = unsafe { self.0.i64 };
479        i64::from_le(x)
480    }
481
482    pub fn get_u64(&self) -> u64 {
483        let x = unsafe { self.0.u64 };
484        u64::from_le(x)
485    }
486
487    pub fn get_ptr<T>(&self) -> *mut T {
488        let ptr = unsafe { self.0.ptr };
489        core::ptr::with_exposed_provenance_mut(usize::from_le(ptr))
490    }
491
492    pub fn set_i32(&mut self, x: i32) {
493        self.0.i32 = x.to_le();
494    }
495
496    pub fn set_u32(&mut self, x: u32) {
497        self.0.u32 = x.to_le();
498    }
499
500    pub fn set_i64(&mut self, x: i64) {
501        self.0.i64 = x.to_le();
502    }
503
504    pub fn set_u64(&mut self, x: u64) {
505        self.0.u64 = x.to_le();
506    }
507
508    pub fn set_ptr<T>(&mut self, ptr: *mut T) {
509        self.0.ptr = ptr.expose_provenance().to_le();
510    }
511}
512
513/// An `f` register value: floats.
514#[derive(Copy, Clone)]
515pub struct FRegVal(FRegUnion);
516
517impl fmt::Debug for FRegVal {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        f.debug_struct("FRegVal")
520            .field("as_f32", &self.get_f32())
521            .field("as_f64", &self.get_f64())
522            .finish()
523    }
524}
525
526impl fmt::LowerHex for FRegVal {
527    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528        fmt::LowerHex::fmt(&self.get_f64().to_bits(), f)
529    }
530}
531
532// NB: like `XRegUnion` values here are always little-endian, see the
533// documentation above for more details.
534#[derive(Copy, Clone)]
535union FRegUnion {
536    f32: u32,
537    f64: u64,
538}
539
540impl Default for FRegVal {
541    fn default() -> Self {
542        Self(unsafe { mem::zeroed() })
543    }
544}
545
546#[expect(missing_docs, reason = "self-describing methods")]
547impl FRegVal {
548    pub fn new_f32(f: f32) -> Self {
549        let mut val = Self::default();
550        val.set_f32(f);
551        val
552    }
553
554    pub fn new_f64(f: f64) -> Self {
555        let mut val = Self::default();
556        val.set_f64(f);
557        val
558    }
559
560    pub fn get_f32(&self) -> f32 {
561        let val = unsafe { self.0.f32 };
562        f32::from_le_bytes(val.to_ne_bytes())
563    }
564
565    pub fn get_f64(&self) -> f64 {
566        let val = unsafe { self.0.f64 };
567        f64::from_le_bytes(val.to_ne_bytes())
568    }
569
570    pub fn set_f32(&mut self, val: f32) {
571        self.0.f32 = u32::from_ne_bytes(val.to_le_bytes());
572    }
573
574    pub fn set_f64(&mut self, val: f64) {
575        self.0.f64 = u64::from_ne_bytes(val.to_le_bytes());
576    }
577}
578
579/// A `v` register value: vectors.
580#[derive(Copy, Clone)]
581#[cfg(not(pulley_disable_interp_simd))]
582pub struct VRegVal(VRegUnion);
583
584#[cfg(not(pulley_disable_interp_simd))]
585impl fmt::Debug for VRegVal {
586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587        f.debug_struct("VRegVal")
588            .field("as_u128", &unsafe { self.0.u128 })
589            .finish()
590    }
591}
592
593#[cfg(not(pulley_disable_interp_simd))]
594impl fmt::LowerHex for VRegVal {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        fmt::LowerHex::fmt(unsafe { &self.0.u128 }, f)
597    }
598}
599
600/// 128-bit vector registers.
601///
602/// This register is always stored in little-endian order and has different
603/// constraints than `XRegVal` and `FRegVal` above. Notably all fields of this
604/// union are the same width so all bits are always defined. Note that
605/// little-endian is required though so bitcasts between different shapes of
606/// vectors works. This union cannot be stored in big-endian.
607#[derive(Copy, Clone)]
608#[repr(align(16))]
609#[cfg(not(pulley_disable_interp_simd))]
610union VRegUnion {
611    u128: u128,
612    i8x16: [i8; 16],
613    i16x8: [i16; 8],
614    i32x4: [i32; 4],
615    i64x2: [i64; 2],
616    u8x16: [u8; 16],
617    u16x8: [u16; 8],
618    u32x4: [u32; 4],
619    u64x2: [u64; 2],
620    // Note that these are `u32` and `u64`, not f32/f64. That's only because
621    // f32/f64 don't have `.to_le()` and `::from_le()` so need to go through the
622    // bits anyway.
623    f32x4: [u32; 4],
624    f64x2: [u64; 2],
625}
626
627#[cfg(not(pulley_disable_interp_simd))]
628impl Default for VRegVal {
629    fn default() -> Self {
630        Self(unsafe { mem::zeroed() })
631    }
632}
633
634#[expect(missing_docs, reason = "self-describing methods")]
635#[cfg(not(pulley_disable_interp_simd))]
636impl VRegVal {
637    pub fn new_u128(i: u128) -> Self {
638        let mut val = Self::default();
639        val.set_u128(i);
640        val
641    }
642
643    pub fn get_u128(&self) -> u128 {
644        let val = unsafe { self.0.u128 };
645        u128::from_le(val)
646    }
647
648    pub fn set_u128(&mut self, val: u128) {
649        self.0.u128 = val.to_le();
650    }
651
652    fn get_i8x16(&self) -> [i8; 16] {
653        let val = unsafe { self.0.i8x16 };
654        val.map(|e| i8::from_le(e))
655    }
656
657    fn set_i8x16(&mut self, val: [i8; 16]) {
658        self.0.i8x16 = val.map(|e| e.to_le());
659    }
660
661    fn get_u8x16(&self) -> [u8; 16] {
662        let val = unsafe { self.0.u8x16 };
663        val.map(|e| u8::from_le(e))
664    }
665
666    fn set_u8x16(&mut self, val: [u8; 16]) {
667        self.0.u8x16 = val.map(|e| e.to_le());
668    }
669
670    fn get_i16x8(&self) -> [i16; 8] {
671        let val = unsafe { self.0.i16x8 };
672        val.map(|e| i16::from_le(e))
673    }
674
675    fn set_i16x8(&mut self, val: [i16; 8]) {
676        self.0.i16x8 = val.map(|e| e.to_le());
677    }
678
679    fn get_u16x8(&self) -> [u16; 8] {
680        let val = unsafe { self.0.u16x8 };
681        val.map(|e| u16::from_le(e))
682    }
683
684    fn set_u16x8(&mut self, val: [u16; 8]) {
685        self.0.u16x8 = val.map(|e| e.to_le());
686    }
687
688    fn get_i32x4(&self) -> [i32; 4] {
689        let val = unsafe { self.0.i32x4 };
690        val.map(|e| i32::from_le(e))
691    }
692
693    fn set_i32x4(&mut self, val: [i32; 4]) {
694        self.0.i32x4 = val.map(|e| e.to_le());
695    }
696
697    fn get_u32x4(&self) -> [u32; 4] {
698        let val = unsafe { self.0.u32x4 };
699        val.map(|e| u32::from_le(e))
700    }
701
702    fn set_u32x4(&mut self, val: [u32; 4]) {
703        self.0.u32x4 = val.map(|e| e.to_le());
704    }
705
706    fn get_i64x2(&self) -> [i64; 2] {
707        let val = unsafe { self.0.i64x2 };
708        val.map(|e| i64::from_le(e))
709    }
710
711    fn set_i64x2(&mut self, val: [i64; 2]) {
712        self.0.i64x2 = val.map(|e| e.to_le());
713    }
714
715    fn get_u64x2(&self) -> [u64; 2] {
716        let val = unsafe { self.0.u64x2 };
717        val.map(|e| u64::from_le(e))
718    }
719
720    fn set_u64x2(&mut self, val: [u64; 2]) {
721        self.0.u64x2 = val.map(|e| e.to_le());
722    }
723
724    fn get_f64x2(&self) -> [f64; 2] {
725        let val = unsafe { self.0.f64x2 };
726        val.map(|e| f64::from_bits(u64::from_le(e)))
727    }
728
729    fn set_f64x2(&mut self, val: [f64; 2]) {
730        self.0.f64x2 = val.map(|e| e.to_bits().to_le());
731    }
732
733    fn get_f32x4(&self) -> [f32; 4] {
734        let val = unsafe { self.0.f32x4 };
735        val.map(|e| f32::from_bits(u32::from_le(e)))
736    }
737
738    fn set_f32x4(&mut self, val: [f32; 4]) {
739        self.0.f32x4 = val.map(|e| e.to_bits().to_le());
740    }
741}
742
743/// The machine state for a Pulley virtual machine: the various registers and
744/// stack.
745pub struct MachineState {
746    x_regs: [XRegVal; XReg::RANGE.end as usize],
747    f_regs: [FRegVal; FReg::RANGE.end as usize],
748    #[cfg(not(pulley_disable_interp_simd))]
749    v_regs: [VRegVal; VReg::RANGE.end as usize],
750    fp: *mut u8,
751    lr: *mut u8,
752    stack: Stack,
753    done_reason: Option<DoneReason<()>>,
754}
755
756unsafe impl Send for MachineState {}
757unsafe impl Sync for MachineState {}
758
759/// Helper structure to store the state of the Pulley stack.
760///
761/// The Pulley stack notably needs to be a 16-byte aligned allocation on the
762/// host to ensure that addresses handed out are indeed 16-byte aligned. This is
763/// done with a custom `Vec<T>` internally where `T` has size and align of 16.
764/// This is manually done with a helper `Align16` type below.
765struct Stack {
766    storage: TryVec<Align16>,
767}
768
769/// Helper type used with `Stack` above.
770#[derive(Copy, Clone)]
771#[repr(align(16))]
772struct Align16 {
773    // Just here to give the structure a size of 16. The alignment is always 16
774    // regardless of what the host platform's alignment of u128 is.
775    _unused: u128,
776}
777
778impl Stack {
779    /// Creates a new stack which will have a byte size of at least `size`.
780    ///
781    /// The allocated stack might be slightly larger due to rounding necessary.
782    fn new(size: usize) -> Result<Stack, OutOfMemory> {
783        let mut storage = TryVec::new();
784        // Round up `size` to the nearest multiple of 16. Note that the
785        // stack is also allocated here but not initialized, and that's
786        // intentional as pulley bytecode should always initialize the stack
787        // before use.
788        storage.reserve_exact(size.checked_next_multiple_of(16).unwrap_or(usize::MAX) / 16)?;
789        Ok(Stack { storage })
790    }
791
792    /// Returns a pointer to the top of the stack (the highest address).
793    ///
794    /// Note that the returned pointer has provenance for the entire stack
795    /// allocation, however, not just the top.
796    fn top(&mut self) -> *mut u8 {
797        let len = self.len();
798        unsafe { self.base().add(len) }
799    }
800
801    /// Returns a pointer to the base of the stack (the lowest address).
802    ///
803    /// Note that the returned pointer has provenance for the entire stack
804    /// allocation, however, not just the top.
805    fn base(&mut self) -> *mut u8 {
806        self.storage.as_mut_ptr().cast::<u8>()
807    }
808
809    /// Returns the length, in bytes, of this stack allocation.
810    fn len(&self) -> usize {
811        self.storage.capacity() * mem::size_of::<Align16>()
812    }
813}
814
815impl fmt::Debug for MachineState {
816    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
817        let MachineState {
818            x_regs,
819            f_regs,
820            #[cfg(not(pulley_disable_interp_simd))]
821            v_regs,
822            stack: _,
823            done_reason: _,
824            fp: _,
825            lr: _,
826        } = self;
827
828        struct RegMap<'a, R>(&'a [R], fn(u8) -> alloc::string::String);
829
830        impl<R: fmt::Debug> fmt::Debug for RegMap<'_, R> {
831            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
832                let mut f = f.debug_map();
833                for (i, r) in self.0.iter().enumerate() {
834                    f.entry(&(self.1)(i as u8), r);
835                }
836                f.finish()
837            }
838        }
839
840        let mut f = f.debug_struct("MachineState");
841
842        f.field(
843            "x_regs",
844            &RegMap(x_regs, |i| XReg::new(i).unwrap().to_string()),
845        )
846        .field(
847            "f_regs",
848            &RegMap(f_regs, |i| FReg::new(i).unwrap().to_string()),
849        );
850        #[cfg(not(pulley_disable_interp_simd))]
851        f.field(
852            "v_regs",
853            &RegMap(v_regs, |i| VReg::new(i).unwrap().to_string()),
854        );
855        f.finish_non_exhaustive()
856    }
857}
858
859macro_rules! index_reg {
860    ($reg_ty:ty,$value_ty:ty,$field:ident) => {
861        impl Index<$reg_ty> for Vm {
862            type Output = $value_ty;
863
864            fn index(&self, reg: $reg_ty) -> &Self::Output {
865                &self.state[reg]
866            }
867        }
868
869        impl IndexMut<$reg_ty> for Vm {
870            fn index_mut(&mut self, reg: $reg_ty) -> &mut Self::Output {
871                &mut self.state[reg]
872            }
873        }
874
875        impl Index<$reg_ty> for MachineState {
876            type Output = $value_ty;
877
878            fn index(&self, reg: $reg_ty) -> &Self::Output {
879                &self.$field[reg.index()]
880            }
881        }
882
883        impl IndexMut<$reg_ty> for MachineState {
884            fn index_mut(&mut self, reg: $reg_ty) -> &mut Self::Output {
885                &mut self.$field[reg.index()]
886            }
887        }
888    };
889}
890
891index_reg!(XReg, XRegVal, x_regs);
892index_reg!(FReg, FRegVal, f_regs);
893#[cfg(not(pulley_disable_interp_simd))]
894index_reg!(VReg, VRegVal, v_regs);
895
896/// Sentinel return address that signals the end of the call stack.
897const HOST_RETURN_ADDR: *mut u8 = usize::MAX as *mut u8;
898
899impl MachineState {
900    fn with_stack(stack_size: usize) -> Result<Self, OutOfMemory> {
901        let mut state = Self {
902            x_regs: [Default::default(); XReg::RANGE.end as usize],
903            f_regs: Default::default(),
904            #[cfg(not(pulley_disable_interp_simd))]
905            v_regs: Default::default(),
906            stack: Stack::new(stack_size)?,
907            done_reason: None,
908            fp: HOST_RETURN_ADDR,
909            lr: HOST_RETURN_ADDR,
910        };
911
912        let sp = state.stack.top();
913        state[XReg::sp] = XRegVal::new_ptr(sp);
914
915        Ok(state)
916    }
917}
918
919/// Inner private module to prevent creation of the `Done` structure outside of
920/// this module.
921mod done {
922    use super::{Encode, Interpreter, MachineState};
923    use core::ops::ControlFlow;
924    use core::ptr::NonNull;
925
926    /// Zero-sized sentinel indicating that pulley execution has halted.
927    ///
928    /// The reason for halting is stored in `MachineState`.
929    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
930    pub struct Done {
931        _priv: (),
932    }
933
934    /// Reason that the pulley interpreter has ceased execution.
935    pub enum DoneReason<T> {
936        /// A trap happened at this bytecode instruction.
937        Trap {
938            /// Which instruction is raising this trap.
939            pc: NonNull<u8>,
940            /// The kind of trap being raised, if known.
941            kind: Option<TrapKind>,
942        },
943        /// The `call_indirect_host` instruction was executed.
944        CallIndirectHost {
945            /// The payload of `call_indirect_host`.
946            id: u8,
947            /// Where to resume execution after the host has finished.
948            resume: NonNull<u8>,
949        },
950        /// Pulley has finished and the provided value is being returned.
951        ReturnToHost(T),
952    }
953
954    /// Stored within `DoneReason::Trap`.
955    #[expect(missing_docs, reason = "self-describing variants")]
956    pub enum TrapKind {
957        DivideByZero,
958        IntegerOverflow,
959        BadConversionToInteger,
960        MemoryOutOfBounds,
961        DisabledOpcode,
962        StackOverflow,
963    }
964
965    impl MachineState {
966        pub(super) fn debug_assert_done_reason_none(&mut self) {
967            debug_assert!(self.done_reason.is_none());
968        }
969
970        pub(super) fn done_decode(&mut self, Done { _priv }: Done) -> DoneReason<()> {
971            self.done_reason.take().unwrap()
972        }
973    }
974
975    impl Interpreter<'_> {
976        /// Finishes execution by recording `DoneReason::Trap`.
977        ///
978        /// This method takes an `I` generic parameter indicating which
979        /// instruction is executing this function and generating a trap. That's
980        /// used to go backwards from the current `pc` which is just beyond the
981        /// instruction to point to the instruction itself in the trap metadata
982        /// returned from the interpreter.
983        #[cold]
984        pub fn done_trap<I: Encode>(&mut self) -> ControlFlow<Done> {
985            self.done_trap_kind::<I>(None)
986        }
987
988        /// Same as `done_trap` but with an explicit `TrapKind`.
989        #[cold]
990        pub fn done_trap_kind<I: Encode>(&mut self, kind: Option<TrapKind>) -> ControlFlow<Done> {
991            let pc = self.current_pc::<I>();
992            self.state.done_reason = Some(DoneReason::Trap { pc, kind });
993            ControlFlow::Break(Done { _priv: () })
994        }
995
996        /// Finishes execution by recording `DoneReason::CallIndirectHost`.
997        #[cold]
998        pub fn done_call_indirect_host(&mut self, id: u8) -> ControlFlow<Done> {
999            self.state.done_reason = Some(DoneReason::CallIndirectHost {
1000                id,
1001                resume: self.pc.as_ptr(),
1002            });
1003            ControlFlow::Break(Done { _priv: () })
1004        }
1005
1006        /// Finishes execution by recording `DoneReason::ReturnToHost`.
1007        #[cold]
1008        pub fn done_return_to_host(&mut self) -> ControlFlow<Done> {
1009            self.state.done_reason = Some(DoneReason::ReturnToHost(()));
1010            ControlFlow::Break(Done { _priv: () })
1011        }
1012    }
1013}
1014
1015use done::Done;
1016pub use done::{DoneReason, TrapKind};
1017
1018struct Interpreter<'a> {
1019    state: &'a mut MachineState,
1020    pc: UnsafeBytecodeStream,
1021    executing_pc: ExecutingPcRef<'a>,
1022}
1023
1024impl Interpreter<'_> {
1025    /// Calculates the `offset` for the current instruction `I`.
1026    #[inline]
1027    fn pc_rel<I: Encode>(&mut self, offset: PcRelOffset) -> NonNull<u8> {
1028        let offset = isize::try_from(i32::from(offset)).unwrap();
1029        unsafe { self.current_pc::<I>().offset(offset) }
1030    }
1031
1032    /// Performs a relative jump of `offset` bytes from the current instruction.
1033    ///
1034    /// This will jump from the start of the current instruction, identified by
1035    /// `I`, `offset` bytes away. Note that the `self.pc` at the start of this
1036    /// function actually points to the instruction after this one so `I` is
1037    /// necessary to go back to ourselves after which we then go `offset` away.
1038    #[inline]
1039    fn pc_rel_jump<I: Encode>(&mut self, offset: PcRelOffset) -> ControlFlow<Done> {
1040        let new_pc = self.pc_rel::<I>(offset);
1041        self.pc = unsafe { UnsafeBytecodeStream::new(new_pc) };
1042        ControlFlow::Continue(())
1043    }
1044
1045    /// Returns the PC of the current instruction where `I` is the static type
1046    /// representing the current instruction.
1047    fn current_pc<I: Encode>(&self) -> NonNull<u8> {
1048        unsafe { self.pc.offset(-isize::from(I::WIDTH)).as_ptr() }
1049    }
1050
1051    /// `sp -= size_of::<T>(); *sp = val;`
1052    ///
1053    /// Note that `I` is the instruction which is pushing data to use if a trap
1054    /// is generated.
1055    #[must_use]
1056    fn push<I: Encode, T>(&mut self, val: T) -> ControlFlow<Done> {
1057        let new_sp = self.state[XReg::sp].get_ptr::<T>().wrapping_sub(1);
1058        self.set_sp::<I>(new_sp.cast())?;
1059        unsafe {
1060            new_sp.write_unaligned(val);
1061        }
1062        ControlFlow::Continue(())
1063    }
1064
1065    /// `ret = *sp; sp -= size_of::<T>()`
1066    fn pop<T>(&mut self) -> T {
1067        let sp = self.state[XReg::sp].get_ptr::<T>();
1068        let val = unsafe { sp.read_unaligned() };
1069        self.set_sp_unchecked(sp.wrapping_add(1));
1070        val
1071    }
1072
1073    /// Sets the stack pointer to the `sp` provided.
1074    ///
1075    /// Returns a trap if this would result in stack overflow, or if `sp` is
1076    /// beneath the base pointer of `self.state.stack`.
1077    ///
1078    /// The `I` parameter here is the instruction that is setting the stack
1079    /// pointer and is used to calculate this instruction's own `pc` if this
1080    /// instruction traps.
1081    #[must_use]
1082    fn set_sp<I: Encode>(&mut self, sp: *mut u8) -> ControlFlow<Done> {
1083        let sp_raw = sp as usize;
1084        let base_raw = self.state.stack.base() as usize;
1085        if sp_raw < base_raw {
1086            return self.done_trap_kind::<I>(Some(TrapKind::StackOverflow));
1087        }
1088        self.set_sp_unchecked(sp);
1089        ControlFlow::Continue(())
1090    }
1091
1092    /// Same as `set_sp` but does not check to see if `sp` is in-bounds. Should
1093    /// only be used with stack increment operations such as `pop`.
1094    fn set_sp_unchecked<T>(&mut self, sp: *mut T) {
1095        if cfg!(debug_assertions) {
1096            let sp_raw = sp as usize;
1097            let base = self.state.stack.base() as usize;
1098            let end = base + self.state.stack.len();
1099            assert!(base <= sp_raw && sp_raw <= end);
1100        }
1101        self.state[XReg::sp].set_ptr(sp);
1102    }
1103
1104    /// Loads a value of `T` using native-endian byte ordering from the `addr`
1105    /// specified.
1106    ///
1107    /// The `I` type parameter is the instruction issuing this load which is
1108    /// used in case of traps to calculate the trapping pc.
1109    ///
1110    /// Returns `ControlFlow::Break` if a trap happens or
1111    /// `ControlFlow::Continue` if the value was loaded successfully.
1112    ///
1113    /// # Unsafety
1114    ///
1115    /// Safety of this method relies on the safety of the original bytecode
1116    /// itself and correctly annotating both `T` and `I`.
1117    #[must_use]
1118    unsafe fn load_ne<T, I: Encode>(&mut self, addr: impl AddressingMode) -> ControlFlow<Done, T> {
1119        unsafe { addr.load_ne::<T, I>(self) }
1120    }
1121
1122    /// Stores a `val` to the `addr` specified.
1123    ///
1124    /// The `I` type parameter is the instruction issuing this store which is
1125    /// used in case of traps to calculate the trapping pc.
1126    ///
1127    /// Returns `ControlFlow::Break` if a trap happens or
1128    /// `ControlFlow::Continue` if the value was stored successfully.
1129    ///
1130    /// # Unsafety
1131    ///
1132    /// Safety of this method relies on the safety of the original bytecode
1133    /// itself and correctly annotating both `T` and `I`.
1134    #[must_use]
1135    unsafe fn store_ne<T, I: Encode>(
1136        &mut self,
1137        addr: impl AddressingMode,
1138        val: T,
1139    ) -> ControlFlow<Done> {
1140        unsafe { addr.store_ne::<T, I>(self, val) }
1141    }
1142
1143    fn check_xnn_from_f32<I: Encode>(
1144        &mut self,
1145        val: f32,
1146        (lo, hi): (f32, f32),
1147    ) -> ControlFlow<Done> {
1148        self.check_xnn_from_f64::<I>(val.into(), (lo.into(), hi.into()))
1149    }
1150
1151    fn check_xnn_from_f64<I: Encode>(
1152        &mut self,
1153        val: f64,
1154        (lo, hi): (f64, f64),
1155    ) -> ControlFlow<Done> {
1156        if val != val {
1157            return self.done_trap_kind::<I>(Some(TrapKind::BadConversionToInteger));
1158        }
1159        let val = val.wasm_trunc();
1160        if val <= lo || val >= hi {
1161            return self.done_trap_kind::<I>(Some(TrapKind::IntegerOverflow));
1162        }
1163        ControlFlow::Continue(())
1164    }
1165
1166    #[cfg(not(pulley_disable_interp_simd))]
1167    fn get_i128(&self, lo: XReg, hi: XReg) -> i128 {
1168        let lo = self.state[lo].get_u64();
1169        let hi = self.state[hi].get_i64();
1170        i128::from(lo) | (i128::from(hi) << 64)
1171    }
1172
1173    #[cfg(not(pulley_disable_interp_simd))]
1174    fn set_i128(&mut self, lo: XReg, hi: XReg, val: i128) {
1175        self.state[lo].set_u64(val as u64);
1176        self.state[hi].set_u64((val >> 64) as u64);
1177    }
1178
1179    fn record_executing_pc_for_profiling(&mut self) {
1180        // Note that this is a no-op if `feature = "profile"` is disabled.
1181        self.executing_pc.record(self.pc.as_ptr().as_ptr() as usize);
1182    }
1183}
1184
1185/// Helper trait to encompass the various addressing modes of Pulley.
1186trait AddressingMode: Sized {
1187    /// Calculates the native host address `*mut T` corresponding to this
1188    /// addressing mode.
1189    ///
1190    /// # Safety
1191    ///
1192    /// Relies on the original bytecode being safe to execute as this will
1193    /// otherwise perform unsafe byte offsets for example which requires the
1194    /// original bytecode to be correct.
1195    #[must_use]
1196    unsafe fn addr<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, *mut T>;
1197
1198    /// Loads a value of `T` from this address, using native-endian byte order.
1199    ///
1200    /// For more information see [`Interpreter::load_ne`].
1201    #[must_use]
1202    unsafe fn load_ne<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, T> {
1203        let ret = unsafe { self.addr::<T, I>(i)?.read_unaligned() };
1204        ControlFlow::Continue(ret)
1205    }
1206
1207    /// Stores a `val` to this address, using native-endian byte order.
1208    ///
1209    /// For more information see [`Interpreter::store_ne`].
1210    #[must_use]
1211    unsafe fn store_ne<T, I: Encode>(self, i: &mut Interpreter<'_>, val: T) -> ControlFlow<Done> {
1212        unsafe {
1213            self.addr::<T, I>(i)?.write_unaligned(val);
1214        }
1215        ControlFlow::Continue(())
1216    }
1217}
1218
1219impl AddressingMode for AddrO32 {
1220    unsafe fn addr<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, *mut T> {
1221        // Note that this addressing mode cannot return `ControlFlow::Break`
1222        // which is intentional. It's expected that LLVM optimizes away any
1223        // branches callers have.
1224        unsafe {
1225            ControlFlow::Continue(
1226                i.state[self.addr]
1227                    .get_ptr::<T>()
1228                    .byte_offset(self.offset as isize),
1229            )
1230        }
1231    }
1232}
1233
1234impl AddressingMode for AddrZ {
1235    unsafe fn addr<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, *mut T> {
1236        // This addressing mode defines loading/storing to the null address as
1237        // a trap, but all other addresses are allowed.
1238        let host_addr = i.state[self.addr].get_ptr::<T>();
1239        if host_addr.is_null() {
1240            i.done_trap_kind::<I>(None)?;
1241            unreachable!();
1242        }
1243        unsafe {
1244            let addr = host_addr.byte_offset(self.offset as isize);
1245            ControlFlow::Continue(addr)
1246        }
1247    }
1248}
1249
1250impl AddressingMode for AddrG32 {
1251    unsafe fn addr<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, *mut T> {
1252        // Test if `bound - offset - T` is less than the wasm address to
1253        // generate a trap. It's a guarantee of this instruction that these
1254        // subtractions don't overflow.
1255        let bound = i.state[self.host_heap_bound].get_u64() as usize;
1256        let offset = usize::from(self.offset);
1257        let wasm_addr = i.state[self.wasm_addr].get_u32() as usize;
1258        if wasm_addr > bound - offset - size_of::<T>() {
1259            i.done_trap_kind::<I>(Some(TrapKind::MemoryOutOfBounds))?;
1260            unreachable!();
1261        }
1262        unsafe {
1263            let addr = i.state[self.host_heap_base]
1264                .get_ptr::<T>()
1265                .byte_add(wasm_addr)
1266                .byte_add(offset);
1267            ControlFlow::Continue(addr)
1268        }
1269    }
1270}
1271
1272impl AddressingMode for AddrG32Bne {
1273    unsafe fn addr<T, I: Encode>(self, i: &mut Interpreter<'_>) -> ControlFlow<Done, *mut T> {
1274        // Same as `AddrG32` above except that the bound is loaded from memory.
1275        let bound = unsafe {
1276            *i.state[self.host_heap_bound_addr]
1277                .get_ptr::<usize>()
1278                .byte_add(usize::from(self.host_heap_bound_offset))
1279        };
1280        let wasm_addr = i.state[self.wasm_addr].get_u32() as usize;
1281        let offset = usize::from(self.offset);
1282        if wasm_addr > bound - offset - size_of::<T>() {
1283            i.done_trap_kind::<I>(Some(TrapKind::MemoryOutOfBounds))?;
1284            unreachable!();
1285        }
1286        unsafe {
1287            let addr = i.state[self.host_heap_base]
1288                .get_ptr::<T>()
1289                .byte_add(wasm_addr)
1290                .byte_add(offset);
1291            ControlFlow::Continue(addr)
1292        }
1293    }
1294}
1295
1296#[test]
1297fn simple_push_pop() {
1298    let mut state = MachineState::with_stack(16).unwrap();
1299    let pc = ExecutingPc::default();
1300    unsafe {
1301        let mut bytecode = [0; 10];
1302        let mut i = Interpreter {
1303            state: &mut state,
1304            // this isn't actually read so just manufacture a dummy one
1305            pc: UnsafeBytecodeStream::new(NonNull::new(bytecode.as_mut_ptr().offset(4)).unwrap()),
1306            executing_pc: pc.as_ref(),
1307        };
1308        assert!(i.push::<crate::Ret, _>(0_i32).is_continue());
1309        assert_eq!(i.pop::<i32>(), 0_i32);
1310        assert!(i.push::<crate::Ret, _>(1_i32).is_continue());
1311        assert!(i.push::<crate::Ret, _>(2_i32).is_continue());
1312        assert!(i.push::<crate::Ret, _>(3_i32).is_continue());
1313        assert!(i.push::<crate::Ret, _>(4_i32).is_continue());
1314        assert!(i.push::<crate::Ret, _>(5_i32).is_break());
1315        assert!(i.push::<crate::Ret, _>(6_i32).is_break());
1316        assert_eq!(i.pop::<i32>(), 4_i32);
1317        assert_eq!(i.pop::<i32>(), 3_i32);
1318        assert_eq!(i.pop::<i32>(), 2_i32);
1319        assert_eq!(i.pop::<i32>(), 1_i32);
1320    }
1321}
1322
1323macro_rules! br_if_imm {
1324    ($(
1325        fn $snake:ident(&mut self, a: XReg, b: $imm:ident, offset: PcRelOffset)
1326            = $camel:ident / $op:tt / $get:ident;
1327    )*) => {$(
1328        fn $snake(&mut self, a: XReg, b: $imm, offset: PcRelOffset) -> ControlFlow<Done> {
1329            let a = self.state[a].$get();
1330            if a $op b.into() {
1331                self.pc_rel_jump::<crate::$camel>(offset)
1332            } else {
1333                ControlFlow::Continue(())
1334            }
1335        }
1336    )*};
1337}
1338
1339impl OpVisitor for Interpreter<'_> {
1340    type BytecodeStream = UnsafeBytecodeStream;
1341    type Return = ControlFlow<Done>;
1342
1343    fn bytecode(&mut self) -> &mut UnsafeBytecodeStream {
1344        &mut self.pc
1345    }
1346
1347    fn nop(&mut self) -> ControlFlow<Done> {
1348        ControlFlow::Continue(())
1349    }
1350
1351    fn ret(&mut self) -> ControlFlow<Done> {
1352        let lr = self.state.lr;
1353        if lr == HOST_RETURN_ADDR {
1354            self.done_return_to_host()
1355        } else {
1356            self.pc = unsafe { UnsafeBytecodeStream::new(NonNull::new_unchecked(lr)) };
1357            ControlFlow::Continue(())
1358        }
1359    }
1360
1361    fn call(&mut self, offset: PcRelOffset) -> ControlFlow<Done> {
1362        let return_addr = self.pc.as_ptr();
1363        self.state.lr = return_addr.as_ptr();
1364        self.pc_rel_jump::<crate::Call>(offset)
1365    }
1366
1367    fn call1(&mut self, arg1: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1368        let return_addr = self.pc.as_ptr();
1369        self.state.lr = return_addr.as_ptr();
1370        self.state[XReg::x0] = self.state[arg1];
1371        self.pc_rel_jump::<crate::Call1>(offset)
1372    }
1373
1374    fn call2(&mut self, arg1: XReg, arg2: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1375        let return_addr = self.pc.as_ptr();
1376        self.state.lr = return_addr.as_ptr();
1377        let (x0, x1) = (self.state[arg1], self.state[arg2]);
1378        self.state[XReg::x0] = x0;
1379        self.state[XReg::x1] = x1;
1380        self.pc_rel_jump::<crate::Call2>(offset)
1381    }
1382
1383    fn call3(
1384        &mut self,
1385        arg1: XReg,
1386        arg2: XReg,
1387        arg3: XReg,
1388        offset: PcRelOffset,
1389    ) -> ControlFlow<Done> {
1390        let return_addr = self.pc.as_ptr();
1391        self.state.lr = return_addr.as_ptr();
1392        let (x0, x1, x2) = (self.state[arg1], self.state[arg2], self.state[arg3]);
1393        self.state[XReg::x0] = x0;
1394        self.state[XReg::x1] = x1;
1395        self.state[XReg::x2] = x2;
1396        self.pc_rel_jump::<crate::Call3>(offset)
1397    }
1398
1399    fn call4(
1400        &mut self,
1401        arg1: XReg,
1402        arg2: XReg,
1403        arg3: XReg,
1404        arg4: XReg,
1405        offset: PcRelOffset,
1406    ) -> ControlFlow<Done> {
1407        let return_addr = self.pc.as_ptr();
1408        self.state.lr = return_addr.as_ptr();
1409        let (x0, x1, x2, x3) = (
1410            self.state[arg1],
1411            self.state[arg2],
1412            self.state[arg3],
1413            self.state[arg4],
1414        );
1415        self.state[XReg::x0] = x0;
1416        self.state[XReg::x1] = x1;
1417        self.state[XReg::x2] = x2;
1418        self.state[XReg::x3] = x3;
1419        self.pc_rel_jump::<crate::Call4>(offset)
1420    }
1421
1422    fn call_indirect(&mut self, dst: XReg) -> ControlFlow<Done> {
1423        let return_addr = self.pc.as_ptr();
1424        self.state.lr = return_addr.as_ptr();
1425        // SAFETY: part of the unsafe contract of the interpreter is only valid
1426        // bytecode is interpreted, so the jump destination is part of the validity
1427        // of the bytecode itself.
1428        unsafe {
1429            self.pc = UnsafeBytecodeStream::new(NonNull::new_unchecked(self.state[dst].get_ptr()));
1430        }
1431        ControlFlow::Continue(())
1432    }
1433
1434    fn jump(&mut self, offset: PcRelOffset) -> ControlFlow<Done> {
1435        self.pc_rel_jump::<crate::Jump>(offset)
1436    }
1437
1438    fn xjump(&mut self, reg: XReg) -> ControlFlow<Done> {
1439        unsafe {
1440            self.pc = UnsafeBytecodeStream::new(NonNull::new_unchecked(self.state[reg].get_ptr()));
1441        }
1442        ControlFlow::Continue(())
1443    }
1444
1445    fn br_if32(&mut self, cond: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1446        let cond = self.state[cond].get_u32();
1447        if cond != 0 {
1448            self.pc_rel_jump::<crate::BrIf>(offset)
1449        } else {
1450            ControlFlow::Continue(())
1451        }
1452    }
1453
1454    fn br_if_not32(&mut self, cond: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1455        let cond = self.state[cond].get_u32();
1456        if cond == 0 {
1457            self.pc_rel_jump::<crate::BrIfNot>(offset)
1458        } else {
1459            ControlFlow::Continue(())
1460        }
1461    }
1462
1463    fn br_if_xeq32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1464        let a = self.state[a].get_u32();
1465        let b = self.state[b].get_u32();
1466        if a == b {
1467            self.pc_rel_jump::<crate::BrIfXeq32>(offset)
1468        } else {
1469            ControlFlow::Continue(())
1470        }
1471    }
1472
1473    fn br_if_xneq32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1474        let a = self.state[a].get_u32();
1475        let b = self.state[b].get_u32();
1476        if a != b {
1477            self.pc_rel_jump::<crate::BrIfXneq32>(offset)
1478        } else {
1479            ControlFlow::Continue(())
1480        }
1481    }
1482
1483    fn br_if_xslt32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1484        let a = self.state[a].get_i32();
1485        let b = self.state[b].get_i32();
1486        if a < b {
1487            self.pc_rel_jump::<crate::BrIfXslt32>(offset)
1488        } else {
1489            ControlFlow::Continue(())
1490        }
1491    }
1492
1493    fn br_if_xslteq32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1494        let a = self.state[a].get_i32();
1495        let b = self.state[b].get_i32();
1496        if a <= b {
1497            self.pc_rel_jump::<crate::BrIfXslteq32>(offset)
1498        } else {
1499            ControlFlow::Continue(())
1500        }
1501    }
1502
1503    fn br_if_xult32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1504        let a = self.state[a].get_u32();
1505        let b = self.state[b].get_u32();
1506        if a < b {
1507            self.pc_rel_jump::<crate::BrIfXult32>(offset)
1508        } else {
1509            ControlFlow::Continue(())
1510        }
1511    }
1512
1513    fn br_if_xulteq32(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1514        let a = self.state[a].get_u32();
1515        let b = self.state[b].get_u32();
1516        if a <= b {
1517            self.pc_rel_jump::<crate::BrIfXulteq32>(offset)
1518        } else {
1519            ControlFlow::Continue(())
1520        }
1521    }
1522
1523    fn br_if_xeq64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1524        let a = self.state[a].get_u64();
1525        let b = self.state[b].get_u64();
1526        if a == b {
1527            self.pc_rel_jump::<crate::BrIfXeq64>(offset)
1528        } else {
1529            ControlFlow::Continue(())
1530        }
1531    }
1532
1533    fn br_if_xneq64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1534        let a = self.state[a].get_u64();
1535        let b = self.state[b].get_u64();
1536        if a != b {
1537            self.pc_rel_jump::<crate::BrIfXneq64>(offset)
1538        } else {
1539            ControlFlow::Continue(())
1540        }
1541    }
1542
1543    fn br_if_xslt64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1544        let a = self.state[a].get_i64();
1545        let b = self.state[b].get_i64();
1546        if a < b {
1547            self.pc_rel_jump::<crate::BrIfXslt64>(offset)
1548        } else {
1549            ControlFlow::Continue(())
1550        }
1551    }
1552
1553    fn br_if_xslteq64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1554        let a = self.state[a].get_i64();
1555        let b = self.state[b].get_i64();
1556        if a <= b {
1557            self.pc_rel_jump::<crate::BrIfXslteq64>(offset)
1558        } else {
1559            ControlFlow::Continue(())
1560        }
1561    }
1562
1563    fn br_if_xult64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1564        let a = self.state[a].get_u64();
1565        let b = self.state[b].get_u64();
1566        if a < b {
1567            self.pc_rel_jump::<crate::BrIfXult64>(offset)
1568        } else {
1569            ControlFlow::Continue(())
1570        }
1571    }
1572
1573    fn br_if_xulteq64(&mut self, a: XReg, b: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
1574        let a = self.state[a].get_u64();
1575        let b = self.state[b].get_u64();
1576        if a <= b {
1577            self.pc_rel_jump::<crate::BrIfXulteq64>(offset)
1578        } else {
1579            ControlFlow::Continue(())
1580        }
1581    }
1582
1583    br_if_imm! {
1584        fn br_if_xeq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1585            = BrIfXeq32I8 / == / get_i32;
1586        fn br_if_xeq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1587            = BrIfXeq32I32 / == / get_i32;
1588        fn br_if_xneq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1589            = BrIfXneq32I8 / != / get_i32;
1590        fn br_if_xneq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1591            = BrIfXneq32I32 / != / get_i32;
1592
1593        fn br_if_xslt32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1594            = BrIfXslt32I8 / < / get_i32;
1595        fn br_if_xslt32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1596            = BrIfXslt32I32 / < / get_i32;
1597        fn br_if_xsgt32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1598            = BrIfXsgt32I8 / > / get_i32;
1599        fn br_if_xsgt32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1600            = BrIfXsgt32I32 / > / get_i32;
1601        fn br_if_xslteq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1602            = BrIfXslteq32I8 / <= / get_i32;
1603        fn br_if_xslteq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1604            = BrIfXslteq32I32 / <= / get_i32;
1605        fn br_if_xsgteq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1606            = BrIfXsgteq32I8 / >= / get_i32;
1607        fn br_if_xsgteq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1608            = BrIfXsgteq32I32 / >= / get_i32;
1609
1610        fn br_if_xult32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1611            = BrIfXult32U8 / < / get_u32;
1612        fn br_if_xult32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1613            = BrIfXult32U32 / < / get_u32;
1614        fn br_if_xugt32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1615            = BrIfXugt32U8 / > / get_u32;
1616        fn br_if_xugt32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1617            = BrIfXugt32U32 / > / get_u32;
1618        fn br_if_xulteq32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1619            = BrIfXulteq32U8 / <= / get_u32;
1620        fn br_if_xulteq32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1621            = BrIfXulteq32U32 / <= / get_u32;
1622        fn br_if_xugteq32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1623            = BrIfXugteq32U8 / >= / get_u32;
1624        fn br_if_xugteq32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1625            = BrIfXugteq32U32 / >= / get_u32;
1626
1627        fn br_if_xeq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1628            = BrIfXeq64I8 / == / get_i64;
1629        fn br_if_xeq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1630            = BrIfXeq64I32 / == / get_i64;
1631        fn br_if_xneq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1632            = BrIfXneq64I8 / != / get_i64;
1633        fn br_if_xneq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1634            = BrIfXneq64I32 / != / get_i64;
1635
1636        fn br_if_xslt64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1637            = BrIfXslt64I8 / < / get_i64;
1638        fn br_if_xslt64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1639            = BrIfXslt64I32 / < / get_i64;
1640        fn br_if_xsgt64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1641            = BrIfXsgt64I8 / > / get_i64;
1642        fn br_if_xsgt64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1643            = BrIfXsgt64I32 / > / get_i64;
1644        fn br_if_xslteq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1645            = BrIfXslteq64I8 / <= / get_i64;
1646        fn br_if_xslteq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1647            = BrIfXslteq64I32 / <= / get_i64;
1648        fn br_if_xsgteq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset)
1649            = BrIfXsgteq64I8 / >= / get_i64;
1650        fn br_if_xsgteq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset)
1651            = BrIfXsgteq64I32 / >= / get_i64;
1652
1653        fn br_if_xult64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1654            = BrIfXult64U8 / < / get_u64;
1655        fn br_if_xult64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1656            = BrIfXult64U32 / < / get_u64;
1657        fn br_if_xugt64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1658            = BrIfXugt64U8 / > / get_u64;
1659        fn br_if_xugt64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1660            = BrIfXugt64U32 / > / get_u64;
1661        fn br_if_xulteq64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1662            = BrIfXulteq64U8 / <= / get_u64;
1663        fn br_if_xulteq64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1664            = BrIfXulteq64U32 / <= / get_u64;
1665        fn br_if_xugteq64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset)
1666            = BrIfXugteq64U8 / >= / get_u64;
1667        fn br_if_xugteq64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset)
1668            = BrIfXugteq64U32 / >= / get_u64;
1669    }
1670
1671    fn xmov(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
1672        let val = self.state[src];
1673        self.state[dst] = val;
1674        ControlFlow::Continue(())
1675    }
1676
1677    fn xconst8(&mut self, dst: XReg, imm: i8) -> ControlFlow<Done> {
1678        self.state[dst].set_i64(i64::from(imm));
1679        ControlFlow::Continue(())
1680    }
1681
1682    fn xzero(&mut self, dst: XReg) -> ControlFlow<Done> {
1683        self.state[dst].set_i64(0);
1684        ControlFlow::Continue(())
1685    }
1686
1687    fn xone(&mut self, dst: XReg) -> ControlFlow<Done> {
1688        self.state[dst].set_i64(1);
1689        ControlFlow::Continue(())
1690    }
1691
1692    fn xconst16(&mut self, dst: XReg, imm: i16) -> ControlFlow<Done> {
1693        self.state[dst].set_i64(i64::from(imm));
1694        ControlFlow::Continue(())
1695    }
1696
1697    fn xconst32(&mut self, dst: XReg, imm: i32) -> ControlFlow<Done> {
1698        self.state[dst].set_i64(i64::from(imm));
1699        ControlFlow::Continue(())
1700    }
1701
1702    fn xconst64(&mut self, dst: XReg, imm: i64) -> ControlFlow<Done> {
1703        self.state[dst].set_i64(imm);
1704        ControlFlow::Continue(())
1705    }
1706
1707    fn xadd32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1708        let a = self.state[operands.src1].get_u32();
1709        let b = self.state[operands.src2].get_u32();
1710        self.state[operands.dst].set_u32(a.wrapping_add(b));
1711        ControlFlow::Continue(())
1712    }
1713
1714    fn xadd32_u8(&mut self, dst: XReg, src1: XReg, src2: u8) -> ControlFlow<Done> {
1715        self.xadd32_u32(dst, src1, src2.into())
1716    }
1717
1718    fn xadd32_u32(&mut self, dst: XReg, src1: XReg, src2: u32) -> ControlFlow<Done> {
1719        let a = self.state[src1].get_u32();
1720        self.state[dst].set_u32(a.wrapping_add(src2));
1721        ControlFlow::Continue(())
1722    }
1723
1724    fn xadd64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1725        let a = self.state[operands.src1].get_u64();
1726        let b = self.state[operands.src2].get_u64();
1727        self.state[operands.dst].set_u64(a.wrapping_add(b));
1728        ControlFlow::Continue(())
1729    }
1730
1731    fn xadd64_u8(&mut self, dst: XReg, src1: XReg, src2: u8) -> ControlFlow<Done> {
1732        self.xadd64_u32(dst, src1, src2.into())
1733    }
1734
1735    fn xadd64_u32(&mut self, dst: XReg, src1: XReg, src2: u32) -> ControlFlow<Done> {
1736        let a = self.state[src1].get_u64();
1737        self.state[dst].set_u64(a.wrapping_add(src2.into()));
1738        ControlFlow::Continue(())
1739    }
1740
1741    fn xmadd32(&mut self, dst: XReg, src1: XReg, src2: XReg, src3: XReg) -> ControlFlow<Done> {
1742        let a = self.state[src1].get_u32();
1743        let b = self.state[src2].get_u32();
1744        let c = self.state[src3].get_u32();
1745        self.state[dst].set_u32(a.wrapping_mul(b).wrapping_add(c));
1746        ControlFlow::Continue(())
1747    }
1748
1749    fn xmadd64(&mut self, dst: XReg, src1: XReg, src2: XReg, src3: XReg) -> ControlFlow<Done> {
1750        let a = self.state[src1].get_u64();
1751        let b = self.state[src2].get_u64();
1752        let c = self.state[src3].get_u64();
1753        self.state[dst].set_u64(a.wrapping_mul(b).wrapping_add(c));
1754        ControlFlow::Continue(())
1755    }
1756
1757    fn xsub32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1758        let a = self.state[operands.src1].get_u32();
1759        let b = self.state[operands.src2].get_u32();
1760        self.state[operands.dst].set_u32(a.wrapping_sub(b));
1761        ControlFlow::Continue(())
1762    }
1763
1764    fn xsub32_u8(&mut self, dst: XReg, src1: XReg, src2: u8) -> ControlFlow<Done> {
1765        self.xsub32_u32(dst, src1, src2.into())
1766    }
1767
1768    fn xsub32_u32(&mut self, dst: XReg, src1: XReg, src2: u32) -> ControlFlow<Done> {
1769        let a = self.state[src1].get_u32();
1770        self.state[dst].set_u32(a.wrapping_sub(src2));
1771        ControlFlow::Continue(())
1772    }
1773
1774    fn xsub64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1775        let a = self.state[operands.src1].get_u64();
1776        let b = self.state[operands.src2].get_u64();
1777        self.state[operands.dst].set_u64(a.wrapping_sub(b));
1778        ControlFlow::Continue(())
1779    }
1780
1781    fn xsub64_u8(&mut self, dst: XReg, src1: XReg, src2: u8) -> ControlFlow<Done> {
1782        self.xsub64_u32(dst, src1, src2.into())
1783    }
1784
1785    fn xsub64_u32(&mut self, dst: XReg, src1: XReg, src2: u32) -> ControlFlow<Done> {
1786        let a = self.state[src1].get_u64();
1787        self.state[dst].set_u64(a.wrapping_sub(src2.into()));
1788        ControlFlow::Continue(())
1789    }
1790
1791    fn xmul32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1792        let a = self.state[operands.src1].get_u32();
1793        let b = self.state[operands.src2].get_u32();
1794        self.state[operands.dst].set_u32(a.wrapping_mul(b));
1795        ControlFlow::Continue(())
1796    }
1797
1798    fn xmul32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
1799        self.xmul32_s32(dst, src1, src2.into())
1800    }
1801
1802    fn xmul32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
1803        let a = self.state[src1].get_i32();
1804        self.state[dst].set_i32(a.wrapping_mul(src2));
1805        ControlFlow::Continue(())
1806    }
1807
1808    fn xmul64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1809        let a = self.state[operands.src1].get_u64();
1810        let b = self.state[operands.src2].get_u64();
1811        self.state[operands.dst].set_u64(a.wrapping_mul(b));
1812        ControlFlow::Continue(())
1813    }
1814
1815    fn xmul64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
1816        self.xmul64_s32(dst, src1, src2.into())
1817    }
1818
1819    fn xmul64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
1820        let a = self.state[src1].get_i64();
1821        self.state[dst].set_i64(a.wrapping_mul(src2.into()));
1822        ControlFlow::Continue(())
1823    }
1824
1825    fn xshl32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1826        let a = self.state[operands.src1].get_u32();
1827        let b = self.state[operands.src2].get_u32();
1828        self.state[operands.dst].set_u32(a.wrapping_shl(b));
1829        ControlFlow::Continue(())
1830    }
1831
1832    fn xshr32_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1833        let a = self.state[operands.src1].get_u32();
1834        let b = self.state[operands.src2].get_u32();
1835        self.state[operands.dst].set_u32(a.wrapping_shr(b));
1836        ControlFlow::Continue(())
1837    }
1838
1839    fn xshr32_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1840        let a = self.state[operands.src1].get_i32();
1841        let b = self.state[operands.src2].get_u32();
1842        self.state[operands.dst].set_i32(a.wrapping_shr(b));
1843        ControlFlow::Continue(())
1844    }
1845
1846    fn xshl64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1847        let a = self.state[operands.src1].get_u64();
1848        let b = self.state[operands.src2].get_u32();
1849        self.state[operands.dst].set_u64(a.wrapping_shl(b));
1850        ControlFlow::Continue(())
1851    }
1852
1853    fn xshr64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1854        let a = self.state[operands.src1].get_u64();
1855        let b = self.state[operands.src2].get_u32();
1856        self.state[operands.dst].set_u64(a.wrapping_shr(b));
1857        ControlFlow::Continue(())
1858    }
1859
1860    fn xshr64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1861        let a = self.state[operands.src1].get_i64();
1862        let b = self.state[operands.src2].get_u32();
1863        self.state[operands.dst].set_i64(a.wrapping_shr(b));
1864        ControlFlow::Continue(())
1865    }
1866
1867    fn xshl32_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1868        let a = self.state[operands.src1].get_u32();
1869        let b = u32::from(u8::from(operands.src2));
1870        self.state[operands.dst].set_u32(a.wrapping_shl(b));
1871        ControlFlow::Continue(())
1872    }
1873
1874    fn xshr32_u_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1875        let a = self.state[operands.src1].get_u32();
1876        let b = u32::from(u8::from(operands.src2));
1877        self.state[operands.dst].set_u32(a.wrapping_shr(b));
1878        ControlFlow::Continue(())
1879    }
1880
1881    fn xshr32_s_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1882        let a = self.state[operands.src1].get_i32();
1883        let b = u32::from(u8::from(operands.src2));
1884        self.state[operands.dst].set_i32(a.wrapping_shr(b));
1885        ControlFlow::Continue(())
1886    }
1887
1888    fn xshl64_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1889        let a = self.state[operands.src1].get_u64();
1890        let b = u32::from(u8::from(operands.src2));
1891        self.state[operands.dst].set_u64(a.wrapping_shl(b));
1892        ControlFlow::Continue(())
1893    }
1894
1895    fn xshr64_u_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1896        let a = self.state[operands.src1].get_u64();
1897        let b = u32::from(u8::from(operands.src2));
1898        self.state[operands.dst].set_u64(a.wrapping_shr(b));
1899        ControlFlow::Continue(())
1900    }
1901
1902    fn xshr64_s_u6(&mut self, operands: BinaryOperands<XReg, XReg, U6>) -> ControlFlow<Done> {
1903        let a = self.state[operands.src1].get_i64();
1904        let b = u32::from(u8::from(operands.src2));
1905        self.state[operands.dst].set_i64(a.wrapping_shr(b));
1906        ControlFlow::Continue(())
1907    }
1908
1909    fn xneg32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
1910        let a = self.state[src].get_i32();
1911        self.state[dst].set_i32(a.wrapping_neg());
1912        ControlFlow::Continue(())
1913    }
1914
1915    fn xneg64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
1916        let a = self.state[src].get_i64();
1917        self.state[dst].set_i64(a.wrapping_neg());
1918        ControlFlow::Continue(())
1919    }
1920
1921    fn xeq64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1922        let a = self.state[operands.src1].get_u64();
1923        let b = self.state[operands.src2].get_u64();
1924        self.state[operands.dst].set_u32(u32::from(a == b));
1925        ControlFlow::Continue(())
1926    }
1927
1928    fn xneq64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1929        let a = self.state[operands.src1].get_u64();
1930        let b = self.state[operands.src2].get_u64();
1931        self.state[operands.dst].set_u32(u32::from(a != b));
1932        ControlFlow::Continue(())
1933    }
1934
1935    fn xslt64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1936        let a = self.state[operands.src1].get_i64();
1937        let b = self.state[operands.src2].get_i64();
1938        self.state[operands.dst].set_u32(u32::from(a < b));
1939        ControlFlow::Continue(())
1940    }
1941
1942    fn xslteq64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1943        let a = self.state[operands.src1].get_i64();
1944        let b = self.state[operands.src2].get_i64();
1945        self.state[operands.dst].set_u32(u32::from(a <= b));
1946        ControlFlow::Continue(())
1947    }
1948
1949    fn xult64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1950        let a = self.state[operands.src1].get_u64();
1951        let b = self.state[operands.src2].get_u64();
1952        self.state[operands.dst].set_u32(u32::from(a < b));
1953        ControlFlow::Continue(())
1954    }
1955
1956    fn xulteq64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1957        let a = self.state[operands.src1].get_u64();
1958        let b = self.state[operands.src2].get_u64();
1959        self.state[operands.dst].set_u32(u32::from(a <= b));
1960        ControlFlow::Continue(())
1961    }
1962
1963    fn xeq32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1964        let a = self.state[operands.src1].get_u32();
1965        let b = self.state[operands.src2].get_u32();
1966        self.state[operands.dst].set_u32(u32::from(a == b));
1967        ControlFlow::Continue(())
1968    }
1969
1970    fn xneq32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1971        let a = self.state[operands.src1].get_u32();
1972        let b = self.state[operands.src2].get_u32();
1973        self.state[operands.dst].set_u32(u32::from(a != b));
1974        ControlFlow::Continue(())
1975    }
1976
1977    fn xslt32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1978        let a = self.state[operands.src1].get_i32();
1979        let b = self.state[operands.src2].get_i32();
1980        self.state[operands.dst].set_u32(u32::from(a < b));
1981        ControlFlow::Continue(())
1982    }
1983
1984    fn xslteq32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1985        let a = self.state[operands.src1].get_i32();
1986        let b = self.state[operands.src2].get_i32();
1987        self.state[operands.dst].set_u32(u32::from(a <= b));
1988        ControlFlow::Continue(())
1989    }
1990
1991    fn xult32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1992        let a = self.state[operands.src1].get_u32();
1993        let b = self.state[operands.src2].get_u32();
1994        self.state[operands.dst].set_u32(u32::from(a < b));
1995        ControlFlow::Continue(())
1996    }
1997
1998    fn xulteq32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
1999        let a = self.state[operands.src1].get_u32();
2000        let b = self.state[operands.src2].get_u32();
2001        self.state[operands.dst].set_u32(u32::from(a <= b));
2002        ControlFlow::Continue(())
2003    }
2004
2005    fn push_frame(&mut self) -> ControlFlow<Done> {
2006        self.push::<crate::PushFrame, _>(self.state.lr)?;
2007        self.push::<crate::PushFrame, _>(self.state.fp)?;
2008        self.state.fp = self.state[XReg::sp].get_ptr();
2009        ControlFlow::Continue(())
2010    }
2011
2012    #[inline]
2013    fn push_frame_save(&mut self, amt: u16, regs: UpperRegSet<XReg>) -> ControlFlow<Done> {
2014        // Decrement the stack pointer `amt` bytes plus 2 pointers more for
2015        // fp/lr.
2016        let ptr_size = size_of::<usize>();
2017        let full_amt = usize::from(amt) + 2 * ptr_size;
2018        let new_sp = self.state[XReg::sp].get_ptr::<u8>().wrapping_sub(full_amt);
2019        self.set_sp::<crate::PushFrameSave>(new_sp)?;
2020
2021        unsafe {
2022            // Emulate `push_frame` by placing `lr` and `fp` onto the stack, in
2023            // that order, at the top of the allocated area.
2024            self.store_ne::<_, crate::PushFrameSave>(
2025                AddrO32 {
2026                    addr: XReg::sp,
2027                    offset: (full_amt - 1 * ptr_size) as i32,
2028                },
2029                self.state.lr,
2030            )?;
2031            self.store_ne::<_, crate::PushFrameSave>(
2032                AddrO32 {
2033                    addr: XReg::sp,
2034                    offset: (full_amt - 2 * ptr_size) as i32,
2035                },
2036                self.state.fp,
2037            )?;
2038
2039            // Set `fp` to the top of our frame, where `fp` is stored.
2040            let mut offset = amt as i32;
2041            self.state.fp = self.state[XReg::sp]
2042                .get_ptr::<u8>()
2043                .byte_offset(offset as isize);
2044
2045            // Next save any registers in `regs` to the stack.
2046            for reg in regs {
2047                offset -= 8;
2048                self.store_ne::<_, crate::PushFrameSave>(
2049                    AddrO32 {
2050                        addr: XReg::sp,
2051                        offset,
2052                    },
2053                    self.state[reg].get_u64(),
2054                )?;
2055            }
2056        }
2057        ControlFlow::Continue(())
2058    }
2059
2060    fn pop_frame_restore(&mut self, amt: u16, regs: UpperRegSet<XReg>) -> ControlFlow<Done> {
2061        // Restore all registers in `regs`, followed by the normal `pop_frame`
2062        // opcode below to restore fp/lr.
2063        unsafe {
2064            let mut offset = i32::from(amt);
2065            for reg in regs {
2066                offset -= 8;
2067                let val = self.load_ne::<_, crate::PopFrameRestore>(AddrO32 {
2068                    addr: XReg::sp,
2069                    offset,
2070                })?;
2071                self.state[reg].set_u64(val);
2072            }
2073        }
2074        self.pop_frame()
2075    }
2076
2077    fn pop_frame(&mut self) -> ControlFlow<Done> {
2078        self.set_sp_unchecked(self.state.fp);
2079        let fp = self.pop();
2080        let lr = self.pop();
2081        self.state.fp = fp;
2082        self.state.lr = lr;
2083        ControlFlow::Continue(())
2084    }
2085
2086    fn br_table32(&mut self, idx: XReg, amt: u32) -> ControlFlow<Done> {
2087        let idx = self.state[idx].get_u32().min(amt - 1) as isize;
2088        // SAFETY: part of the contract of the interpreter is only dealing with
2089        // valid bytecode, so this offset should be safe.
2090        self.pc = unsafe { self.pc.offset(idx * 4) };
2091
2092        // Decode the `PcRelOffset` without tampering with `self.pc` as the
2093        // jump is relative to `self.pc`.
2094        let mut tmp = self.pc;
2095        let Ok(rel) = PcRelOffset::decode(&mut tmp);
2096        let offset = isize::try_from(i32::from(rel)).unwrap();
2097        self.pc = unsafe { self.pc.offset(offset) };
2098        ControlFlow::Continue(())
2099    }
2100
2101    fn stack_alloc32(&mut self, amt: u32) -> ControlFlow<Done> {
2102        let amt = usize::try_from(amt).unwrap();
2103        let new_sp = self.state[XReg::sp].get_ptr::<u8>().wrapping_sub(amt);
2104        self.set_sp::<crate::StackAlloc32>(new_sp)?;
2105        ControlFlow::Continue(())
2106    }
2107
2108    fn stack_free32(&mut self, amt: u32) -> ControlFlow<Done> {
2109        let amt = usize::try_from(amt).unwrap();
2110        let new_sp = self.state[XReg::sp].get_ptr::<u8>().wrapping_add(amt);
2111        self.set_sp_unchecked(new_sp);
2112        ControlFlow::Continue(())
2113    }
2114
2115    fn zext8(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2116        let src = self.state[src].get_u64() as u8;
2117        self.state[dst].set_u64(src.into());
2118        ControlFlow::Continue(())
2119    }
2120
2121    fn zext16(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2122        let src = self.state[src].get_u64() as u16;
2123        self.state[dst].set_u64(src.into());
2124        ControlFlow::Continue(())
2125    }
2126
2127    fn zext32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2128        let src = self.state[src].get_u64() as u32;
2129        self.state[dst].set_u64(src.into());
2130        ControlFlow::Continue(())
2131    }
2132
2133    fn sext8(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2134        let src = self.state[src].get_i64() as i8;
2135        self.state[dst].set_i64(src.into());
2136        ControlFlow::Continue(())
2137    }
2138
2139    fn sext16(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2140        let src = self.state[src].get_i64() as i16;
2141        self.state[dst].set_i64(src.into());
2142        ControlFlow::Continue(())
2143    }
2144
2145    fn sext32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2146        let src = self.state[src].get_i64() as i32;
2147        self.state[dst].set_i64(src.into());
2148        ControlFlow::Continue(())
2149    }
2150
2151    fn xdiv32_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2152        let a = self.state[operands.src1].get_i32();
2153        let b = self.state[operands.src2].get_i32();
2154        match a.checked_div(b) {
2155            Some(result) => {
2156                self.state[operands.dst].set_i32(result);
2157                ControlFlow::Continue(())
2158            }
2159            None => {
2160                let kind = if b == 0 {
2161                    TrapKind::DivideByZero
2162                } else {
2163                    TrapKind::IntegerOverflow
2164                };
2165                self.done_trap_kind::<crate::XDiv32S>(Some(kind))
2166            }
2167        }
2168    }
2169
2170    fn xdiv64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2171        let a = self.state[operands.src1].get_i64();
2172        let b = self.state[operands.src2].get_i64();
2173        match a.checked_div(b) {
2174            Some(result) => {
2175                self.state[operands.dst].set_i64(result);
2176                ControlFlow::Continue(())
2177            }
2178            None => {
2179                let kind = if b == 0 {
2180                    TrapKind::DivideByZero
2181                } else {
2182                    TrapKind::IntegerOverflow
2183                };
2184                self.done_trap_kind::<crate::XDiv64S>(Some(kind))
2185            }
2186        }
2187    }
2188
2189    fn xdiv32_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2190        let a = self.state[operands.src1].get_u32();
2191        let b = self.state[operands.src2].get_u32();
2192        match a.checked_div(b) {
2193            Some(result) => {
2194                self.state[operands.dst].set_u32(result);
2195                ControlFlow::Continue(())
2196            }
2197            None => self.done_trap_kind::<crate::XDiv32U>(Some(TrapKind::DivideByZero)),
2198        }
2199    }
2200
2201    fn xdiv64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2202        let a = self.state[operands.src1].get_u64();
2203        let b = self.state[operands.src2].get_u64();
2204        match a.checked_div(b) {
2205            Some(result) => {
2206                self.state[operands.dst].set_u64(result);
2207                ControlFlow::Continue(())
2208            }
2209            None => self.done_trap_kind::<crate::XDiv64U>(Some(TrapKind::DivideByZero)),
2210        }
2211    }
2212
2213    fn xrem32_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2214        let a = self.state[operands.src1].get_i32();
2215        let b = self.state[operands.src2].get_i32();
2216        let result = if a == i32::MIN && b == -1 {
2217            Some(0)
2218        } else {
2219            a.checked_rem(b)
2220        };
2221        match result {
2222            Some(result) => {
2223                self.state[operands.dst].set_i32(result);
2224                ControlFlow::Continue(())
2225            }
2226            None => self.done_trap_kind::<crate::XRem32S>(Some(TrapKind::DivideByZero)),
2227        }
2228    }
2229
2230    fn xrem64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2231        let a = self.state[operands.src1].get_i64();
2232        let b = self.state[operands.src2].get_i64();
2233        let result = if a == i64::MIN && b == -1 {
2234            Some(0)
2235        } else {
2236            a.checked_rem(b)
2237        };
2238        match result {
2239            Some(result) => {
2240                self.state[operands.dst].set_i64(result);
2241                ControlFlow::Continue(())
2242            }
2243            None => self.done_trap_kind::<crate::XRem64S>(Some(TrapKind::DivideByZero)),
2244        }
2245    }
2246
2247    fn xrem32_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2248        let a = self.state[operands.src1].get_u32();
2249        let b = self.state[operands.src2].get_u32();
2250        match a.checked_rem(b) {
2251            Some(result) => {
2252                self.state[operands.dst].set_u32(result);
2253                ControlFlow::Continue(())
2254            }
2255            None => self.done_trap_kind::<crate::XRem32U>(Some(TrapKind::DivideByZero)),
2256        }
2257    }
2258
2259    fn xrem64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2260        let a = self.state[operands.src1].get_u64();
2261        let b = self.state[operands.src2].get_u64();
2262        match a.checked_rem(b) {
2263            Some(result) => {
2264                self.state[operands.dst].set_u64(result);
2265                ControlFlow::Continue(())
2266            }
2267            None => self.done_trap_kind::<crate::XRem64U>(Some(TrapKind::DivideByZero)),
2268        }
2269    }
2270
2271    fn xband32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2272        let a = self.state[operands.src1].get_u32();
2273        let b = self.state[operands.src2].get_u32();
2274        self.state[operands.dst].set_u32(a & b);
2275        ControlFlow::Continue(())
2276    }
2277
2278    fn xband32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2279        self.xband32_s32(dst, src1, src2.into())
2280    }
2281
2282    fn xband32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2283        let a = self.state[src1].get_i32();
2284        self.state[dst].set_i32(a & src2);
2285        ControlFlow::Continue(())
2286    }
2287
2288    fn xband64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2289        let a = self.state[operands.src1].get_u64();
2290        let b = self.state[operands.src2].get_u64();
2291        self.state[operands.dst].set_u64(a & b);
2292        ControlFlow::Continue(())
2293    }
2294
2295    fn xband64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2296        self.xband64_s32(dst, src1, src2.into())
2297    }
2298
2299    fn xband64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2300        let a = self.state[src1].get_i64();
2301        self.state[dst].set_i64(a & i64::from(src2));
2302        ControlFlow::Continue(())
2303    }
2304
2305    fn xbor32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2306        let a = self.state[operands.src1].get_u32();
2307        let b = self.state[operands.src2].get_u32();
2308        self.state[operands.dst].set_u32(a | b);
2309        ControlFlow::Continue(())
2310    }
2311
2312    fn xbor32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2313        self.xbor32_s32(dst, src1, src2.into())
2314    }
2315
2316    fn xbor32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2317        let a = self.state[src1].get_i32();
2318        self.state[dst].set_i32(a | src2);
2319        ControlFlow::Continue(())
2320    }
2321
2322    fn xbor64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2323        let a = self.state[operands.src1].get_u64();
2324        let b = self.state[operands.src2].get_u64();
2325        self.state[operands.dst].set_u64(a | b);
2326        ControlFlow::Continue(())
2327    }
2328
2329    fn xbor64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2330        self.xbor64_s32(dst, src1, src2.into())
2331    }
2332
2333    fn xbor64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2334        let a = self.state[src1].get_i64();
2335        self.state[dst].set_i64(a | i64::from(src2));
2336        ControlFlow::Continue(())
2337    }
2338
2339    fn xbxor32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2340        let a = self.state[operands.src1].get_u32();
2341        let b = self.state[operands.src2].get_u32();
2342        self.state[operands.dst].set_u32(a ^ b);
2343        ControlFlow::Continue(())
2344    }
2345
2346    fn xbxor32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2347        self.xbxor32_s32(dst, src1, src2.into())
2348    }
2349
2350    fn xbxor32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2351        let a = self.state[src1].get_i32();
2352        self.state[dst].set_i32(a ^ src2);
2353        ControlFlow::Continue(())
2354    }
2355
2356    fn xbxor64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2357        let a = self.state[operands.src1].get_u64();
2358        let b = self.state[operands.src2].get_u64();
2359        self.state[operands.dst].set_u64(a ^ b);
2360        ControlFlow::Continue(())
2361    }
2362
2363    fn xbxor64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow<Done> {
2364        self.xbxor64_s32(dst, src1, src2.into())
2365    }
2366
2367    fn xbxor64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow<Done> {
2368        let a = self.state[src1].get_i64();
2369        self.state[dst].set_i64(a ^ i64::from(src2));
2370        ControlFlow::Continue(())
2371    }
2372
2373    fn xbnot32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2374        let a = self.state[src].get_u32();
2375        self.state[dst].set_u32(!a);
2376        ControlFlow::Continue(())
2377    }
2378
2379    fn xbnot64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2380        let a = self.state[src].get_u64();
2381        self.state[dst].set_u64(!a);
2382        ControlFlow::Continue(())
2383    }
2384
2385    fn xmin32_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2386        let a = self.state[operands.src1].get_u32();
2387        let b = self.state[operands.src2].get_u32();
2388        self.state[operands.dst].set_u32(a.min(b));
2389        ControlFlow::Continue(())
2390    }
2391
2392    fn xmin32_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2393        let a = self.state[operands.src1].get_i32();
2394        let b = self.state[operands.src2].get_i32();
2395        self.state[operands.dst].set_i32(a.min(b));
2396        ControlFlow::Continue(())
2397    }
2398
2399    fn xmax32_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2400        let a = self.state[operands.src1].get_u32();
2401        let b = self.state[operands.src2].get_u32();
2402        self.state[operands.dst].set_u32(a.max(b));
2403        ControlFlow::Continue(())
2404    }
2405
2406    fn xmax32_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2407        let a = self.state[operands.src1].get_i32();
2408        let b = self.state[operands.src2].get_i32();
2409        self.state[operands.dst].set_i32(a.max(b));
2410        ControlFlow::Continue(())
2411    }
2412
2413    fn xmin64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2414        let a = self.state[operands.src1].get_u64();
2415        let b = self.state[operands.src2].get_u64();
2416        self.state[operands.dst].set_u64(a.min(b));
2417        ControlFlow::Continue(())
2418    }
2419
2420    fn xmin64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2421        let a = self.state[operands.src1].get_i64();
2422        let b = self.state[operands.src2].get_i64();
2423        self.state[operands.dst].set_i64(a.min(b));
2424        ControlFlow::Continue(())
2425    }
2426
2427    fn xmax64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2428        let a = self.state[operands.src1].get_u64();
2429        let b = self.state[operands.src2].get_u64();
2430        self.state[operands.dst].set_u64(a.max(b));
2431        ControlFlow::Continue(())
2432    }
2433
2434    fn xmax64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2435        let a = self.state[operands.src1].get_i64();
2436        let b = self.state[operands.src2].get_i64();
2437        self.state[operands.dst].set_i64(a.max(b));
2438        ControlFlow::Continue(())
2439    }
2440
2441    fn xctz32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2442        let a = self.state[src].get_u32();
2443        self.state[dst].set_u32(a.trailing_zeros());
2444        ControlFlow::Continue(())
2445    }
2446
2447    fn xctz64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2448        let a = self.state[src].get_u64();
2449        self.state[dst].set_u64(a.trailing_zeros().into());
2450        ControlFlow::Continue(())
2451    }
2452
2453    fn xclz32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2454        let a = self.state[src].get_u32();
2455        self.state[dst].set_u32(a.leading_zeros());
2456        ControlFlow::Continue(())
2457    }
2458
2459    fn xclz64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2460        let a = self.state[src].get_u64();
2461        self.state[dst].set_u64(a.leading_zeros().into());
2462        ControlFlow::Continue(())
2463    }
2464
2465    fn xpopcnt32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2466        let a = self.state[src].get_u32();
2467        self.state[dst].set_u32(a.count_ones());
2468        ControlFlow::Continue(())
2469    }
2470
2471    fn xpopcnt64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2472        let a = self.state[src].get_u64();
2473        self.state[dst].set_u64(a.count_ones().into());
2474        ControlFlow::Continue(())
2475    }
2476
2477    fn xrotl32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2478        let a = self.state[operands.src1].get_u32();
2479        let b = self.state[operands.src2].get_u32();
2480        self.state[operands.dst].set_u32(a.rotate_left(b));
2481        ControlFlow::Continue(())
2482    }
2483
2484    fn xrotl64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2485        let a = self.state[operands.src1].get_u64();
2486        let b = self.state[operands.src2].get_u32();
2487        self.state[operands.dst].set_u64(a.rotate_left(b));
2488        ControlFlow::Continue(())
2489    }
2490
2491    fn xrotr32(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2492        let a = self.state[operands.src1].get_u32();
2493        let b = self.state[operands.src2].get_u32();
2494        self.state[operands.dst].set_u32(a.rotate_right(b));
2495        ControlFlow::Continue(())
2496    }
2497
2498    fn xrotr64(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2499        let a = self.state[operands.src1].get_u64();
2500        let b = self.state[operands.src2].get_u32();
2501        self.state[operands.dst].set_u64(a.rotate_right(b));
2502        ControlFlow::Continue(())
2503    }
2504
2505    fn xselect32(
2506        &mut self,
2507        dst: XReg,
2508        cond: XReg,
2509        if_nonzero: XReg,
2510        if_zero: XReg,
2511    ) -> ControlFlow<Done> {
2512        let result = if self.state[cond].get_u32() != 0 {
2513            self.state[if_nonzero].get_u32()
2514        } else {
2515            self.state[if_zero].get_u32()
2516        };
2517        self.state[dst].set_u32(result);
2518        ControlFlow::Continue(())
2519    }
2520
2521    fn xselect64(
2522        &mut self,
2523        dst: XReg,
2524        cond: XReg,
2525        if_nonzero: XReg,
2526        if_zero: XReg,
2527    ) -> ControlFlow<Done> {
2528        let result = if self.state[cond].get_u32() != 0 {
2529            self.state[if_nonzero].get_u64()
2530        } else {
2531            self.state[if_zero].get_u64()
2532        };
2533        self.state[dst].set_u64(result);
2534        ControlFlow::Continue(())
2535    }
2536
2537    fn xabs32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2538        let a = self.state[src].get_i32();
2539        self.state[dst].set_i32(a.wrapping_abs());
2540        ControlFlow::Continue(())
2541    }
2542
2543    fn xabs64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2544        let a = self.state[src].get_i64();
2545        self.state[dst].set_i64(a.wrapping_abs());
2546        ControlFlow::Continue(())
2547    }
2548
2549    // =========================================================================
2550    // o32 addressing modes
2551
2552    fn xload8_u32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2553        let result = unsafe { self.load_ne::<u8, crate::XLoad8U32O32>(addr)? };
2554        self.state[dst].set_u32(result.into());
2555        ControlFlow::Continue(())
2556    }
2557
2558    fn xload8_s32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2559        let result = unsafe { self.load_ne::<i8, crate::XLoad8S32O32>(addr)? };
2560        self.state[dst].set_i32(result.into());
2561        ControlFlow::Continue(())
2562    }
2563
2564    fn xload16le_u32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2565        let result = unsafe { self.load_ne::<u16, crate::XLoad16LeU32O32>(addr)? };
2566        self.state[dst].set_u32(u16::from_le(result).into());
2567        ControlFlow::Continue(())
2568    }
2569
2570    fn xload16le_s32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2571        let result = unsafe { self.load_ne::<i16, crate::XLoad16LeS32O32>(addr)? };
2572        self.state[dst].set_i32(i16::from_le(result).into());
2573        ControlFlow::Continue(())
2574    }
2575
2576    fn xload32le_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2577        let result = unsafe { self.load_ne::<i32, crate::XLoad32LeO32>(addr)? };
2578        self.state[dst].set_i32(i32::from_le(result));
2579        ControlFlow::Continue(())
2580    }
2581
2582    fn xload64le_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2583        let result = unsafe { self.load_ne::<i64, crate::XLoad64LeO32>(addr)? };
2584        self.state[dst].set_i64(i64::from_le(result));
2585        ControlFlow::Continue(())
2586    }
2587
2588    fn xstore8_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2589        let val = self.state[val].get_u32() as u8;
2590        unsafe {
2591            self.store_ne::<u8, crate::XStore8O32>(addr, val)?;
2592        }
2593        ControlFlow::Continue(())
2594    }
2595
2596    fn xstore16le_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2597        let val = self.state[val].get_u32() as u16;
2598        unsafe {
2599            self.store_ne::<u16, crate::XStore16LeO32>(addr, val.to_le())?;
2600        }
2601        ControlFlow::Continue(())
2602    }
2603
2604    fn xstore32le_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2605        let val = self.state[val].get_u32();
2606        unsafe {
2607            self.store_ne::<u32, crate::XStore32LeO32>(addr, val.to_le())?;
2608        }
2609        ControlFlow::Continue(())
2610    }
2611
2612    fn xstore64le_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2613        let val = self.state[val].get_u64();
2614        unsafe {
2615            self.store_ne::<u64, crate::XStore64LeO32>(addr, val.to_le())?;
2616        }
2617        ControlFlow::Continue(())
2618    }
2619
2620    // =========================================================================
2621    // g32 addressing modes
2622
2623    fn xload8_u32_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2624        let result = unsafe { self.load_ne::<u8, crate::XLoad8U32G32>(addr)? };
2625        self.state[dst].set_u32(result.into());
2626        ControlFlow::Continue(())
2627    }
2628
2629    fn xload8_s32_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2630        let result = unsafe { self.load_ne::<i8, crate::XLoad8S32G32>(addr)? };
2631        self.state[dst].set_i32(result.into());
2632        ControlFlow::Continue(())
2633    }
2634
2635    fn xload16le_u32_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2636        let result = unsafe { self.load_ne::<u16, crate::XLoad16LeU32G32>(addr)? };
2637        self.state[dst].set_u32(u16::from_le(result).into());
2638        ControlFlow::Continue(())
2639    }
2640
2641    fn xload16le_s32_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2642        let result = unsafe { self.load_ne::<i16, crate::XLoad16LeS32G32>(addr)? };
2643        self.state[dst].set_i32(i16::from_le(result).into());
2644        ControlFlow::Continue(())
2645    }
2646
2647    fn xload32le_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2648        let result = unsafe { self.load_ne::<i32, crate::XLoad32LeG32>(addr)? };
2649        self.state[dst].set_i32(i32::from_le(result));
2650        ControlFlow::Continue(())
2651    }
2652
2653    fn xload64le_g32(&mut self, dst: XReg, addr: AddrG32) -> ControlFlow<Done> {
2654        let result = unsafe { self.load_ne::<i64, crate::XLoad64LeG32>(addr)? };
2655        self.state[dst].set_i64(i64::from_le(result));
2656        ControlFlow::Continue(())
2657    }
2658
2659    fn xstore8_g32(&mut self, addr: AddrG32, val: XReg) -> ControlFlow<Done> {
2660        let val = self.state[val].get_u32() as u8;
2661        unsafe {
2662            self.store_ne::<u8, crate::XStore8G32>(addr, val)?;
2663        }
2664        ControlFlow::Continue(())
2665    }
2666
2667    fn xstore16le_g32(&mut self, addr: AddrG32, val: XReg) -> ControlFlow<Done> {
2668        let val = self.state[val].get_u32() as u16;
2669        unsafe {
2670            self.store_ne::<u16, crate::XStore16LeG32>(addr, val.to_le())?;
2671        }
2672        ControlFlow::Continue(())
2673    }
2674
2675    fn xstore32le_g32(&mut self, addr: AddrG32, val: XReg) -> ControlFlow<Done> {
2676        let val = self.state[val].get_u32();
2677        unsafe {
2678            self.store_ne::<u32, crate::XStore32LeG32>(addr, val.to_le())?;
2679        }
2680        ControlFlow::Continue(())
2681    }
2682
2683    fn xstore64le_g32(&mut self, addr: AddrG32, val: XReg) -> ControlFlow<Done> {
2684        let val = self.state[val].get_u64();
2685        unsafe {
2686            self.store_ne::<u64, crate::XStore64LeG32>(addr, val.to_le())?;
2687        }
2688        ControlFlow::Continue(())
2689    }
2690
2691    // =========================================================================
2692    // z addressing modes
2693
2694    fn xload8_u32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2695        let result = unsafe { self.load_ne::<u8, crate::XLoad8U32Z>(addr)? };
2696        self.state[dst].set_u32(result.into());
2697        ControlFlow::Continue(())
2698    }
2699
2700    fn xload8_s32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2701        let result = unsafe { self.load_ne::<i8, crate::XLoad8S32Z>(addr)? };
2702        self.state[dst].set_i32(result.into());
2703        ControlFlow::Continue(())
2704    }
2705
2706    fn xload16le_u32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2707        let result = unsafe { self.load_ne::<u16, crate::XLoad16LeU32Z>(addr)? };
2708        self.state[dst].set_u32(u16::from_le(result).into());
2709        ControlFlow::Continue(())
2710    }
2711
2712    fn xload16le_s32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2713        let result = unsafe { self.load_ne::<i16, crate::XLoad16LeS32Z>(addr)? };
2714        self.state[dst].set_i32(i16::from_le(result).into());
2715        ControlFlow::Continue(())
2716    }
2717
2718    fn xload32le_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2719        let result = unsafe { self.load_ne::<i32, crate::XLoad32LeZ>(addr)? };
2720        self.state[dst].set_i32(i32::from_le(result));
2721        ControlFlow::Continue(())
2722    }
2723
2724    fn xload64le_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
2725        let result = unsafe { self.load_ne::<i64, crate::XLoad64LeZ>(addr)? };
2726        self.state[dst].set_i64(i64::from_le(result));
2727        ControlFlow::Continue(())
2728    }
2729
2730    fn xstore8_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
2731        let val = self.state[val].get_u32() as u8;
2732        unsafe {
2733            self.store_ne::<u8, crate::XStore8Z>(addr, val)?;
2734        }
2735        ControlFlow::Continue(())
2736    }
2737
2738    fn xstore16le_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
2739        let val = self.state[val].get_u32() as u16;
2740        unsafe {
2741            self.store_ne::<u16, crate::XStore16LeZ>(addr, val.to_le())?;
2742        }
2743        ControlFlow::Continue(())
2744    }
2745
2746    fn xstore32le_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
2747        let val = self.state[val].get_u32();
2748        unsafe {
2749            self.store_ne::<u32, crate::XStore32LeZ>(addr, val.to_le())?;
2750        }
2751        ControlFlow::Continue(())
2752    }
2753
2754    fn xstore64le_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
2755        let val = self.state[val].get_u64();
2756        unsafe {
2757            self.store_ne::<u64, crate::XStore64LeZ>(addr, val.to_le())?;
2758        }
2759        ControlFlow::Continue(())
2760    }
2761
2762    // =========================================================================
2763    // g32bne addressing modes
2764
2765    fn xload8_u32_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2766        let result = unsafe { self.load_ne::<u8, crate::XLoad8U32G32Bne>(addr)? };
2767        self.state[dst].set_u32(result.into());
2768        ControlFlow::Continue(())
2769    }
2770
2771    fn xload8_s32_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2772        let result = unsafe { self.load_ne::<i8, crate::XLoad8S32G32Bne>(addr)? };
2773        self.state[dst].set_i32(result.into());
2774        ControlFlow::Continue(())
2775    }
2776
2777    fn xload16le_u32_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2778        let result = unsafe { self.load_ne::<u16, crate::XLoad16LeU32G32Bne>(addr)? };
2779        self.state[dst].set_u32(u16::from_le(result).into());
2780        ControlFlow::Continue(())
2781    }
2782
2783    fn xload16le_s32_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2784        let result = unsafe { self.load_ne::<i16, crate::XLoad16LeS32G32Bne>(addr)? };
2785        self.state[dst].set_i32(i16::from_le(result).into());
2786        ControlFlow::Continue(())
2787    }
2788
2789    fn xload32le_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2790        let result = unsafe { self.load_ne::<i32, crate::XLoad32LeG32Bne>(addr)? };
2791        self.state[dst].set_i32(i32::from_le(result));
2792        ControlFlow::Continue(())
2793    }
2794
2795    fn xload64le_g32bne(&mut self, dst: XReg, addr: AddrG32Bne) -> ControlFlow<Done> {
2796        let result = unsafe { self.load_ne::<i64, crate::XLoad64LeG32Bne>(addr)? };
2797        self.state[dst].set_i64(i64::from_le(result));
2798        ControlFlow::Continue(())
2799    }
2800
2801    fn xstore8_g32bne(&mut self, addr: AddrG32Bne, val: XReg) -> ControlFlow<Done> {
2802        let val = self.state[val].get_u32() as u8;
2803        unsafe {
2804            self.store_ne::<u8, crate::XStore8G32Bne>(addr, val)?;
2805        }
2806        ControlFlow::Continue(())
2807    }
2808
2809    fn xstore16le_g32bne(&mut self, addr: AddrG32Bne, val: XReg) -> ControlFlow<Done> {
2810        let val = self.state[val].get_u32() as u16;
2811        unsafe {
2812            self.store_ne::<u16, crate::XStore16LeG32Bne>(addr, val.to_le())?;
2813        }
2814        ControlFlow::Continue(())
2815    }
2816
2817    fn xstore32le_g32bne(&mut self, addr: AddrG32Bne, val: XReg) -> ControlFlow<Done> {
2818        let val = self.state[val].get_u32();
2819        unsafe {
2820            self.store_ne::<u32, crate::XStore32LeG32Bne>(addr, val.to_le())?;
2821        }
2822        ControlFlow::Continue(())
2823    }
2824
2825    fn xstore64le_g32bne(&mut self, addr: AddrG32Bne, val: XReg) -> ControlFlow<Done> {
2826        let val = self.state[val].get_u64();
2827        unsafe {
2828            self.store_ne::<u64, crate::XStore64LeG32Bne>(addr, val.to_le())?;
2829        }
2830        ControlFlow::Continue(())
2831    }
2832}
2833
2834impl ExtendedOpVisitor for Interpreter<'_> {
2835    fn trap(&mut self) -> ControlFlow<Done> {
2836        self.done_trap::<crate::Trap>()
2837    }
2838
2839    fn call_indirect_host(&mut self, id: u8) -> ControlFlow<Done> {
2840        self.done_call_indirect_host(id)
2841    }
2842
2843    fn xpcadd(&mut self, dst: XReg, offset: PcRelOffset) -> ControlFlow<Done> {
2844        let pc = self.pc_rel::<crate::Xpcadd>(offset);
2845        self.state[dst].set_ptr(pc.as_ptr());
2846        ControlFlow::Continue(())
2847    }
2848
2849    fn bswap32(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2850        let src = self.state[src].get_u32();
2851        self.state[dst].set_u32(src.swap_bytes());
2852        ControlFlow::Continue(())
2853    }
2854
2855    fn bswap64(&mut self, dst: XReg, src: XReg) -> ControlFlow<Done> {
2856        let src = self.state[src].get_u64();
2857        self.state[dst].set_u64(src.swap_bytes());
2858        ControlFlow::Continue(())
2859    }
2860
2861    fn xbmask32(&mut self, dst: XReg, src: XReg) -> Self::Return {
2862        let a = self.state[src].get_u32();
2863        if a == 0 {
2864            self.state[dst].set_u32(0);
2865        } else {
2866            self.state[dst].set_i32(-1);
2867        }
2868        ControlFlow::Continue(())
2869    }
2870
2871    fn xbmask64(&mut self, dst: XReg, src: XReg) -> Self::Return {
2872        let a = self.state[src].get_u64();
2873        if a == 0 {
2874            self.state[dst].set_u64(0);
2875        } else {
2876            self.state[dst].set_i64(-1);
2877        }
2878        ControlFlow::Continue(())
2879    }
2880
2881    fn xadd32_uoverflow_trap(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2882        let a = self.state[operands.src1].get_u32();
2883        let b = self.state[operands.src2].get_u32();
2884        match a.checked_add(b) {
2885            Some(c) => {
2886                self.state[operands.dst].set_u32(c);
2887                ControlFlow::Continue(())
2888            }
2889            None => self.done_trap::<crate::Xadd32UoverflowTrap>(),
2890        }
2891    }
2892
2893    fn xadd64_uoverflow_trap(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2894        let a = self.state[operands.src1].get_u64();
2895        let b = self.state[operands.src2].get_u64();
2896        match a.checked_add(b) {
2897            Some(c) => {
2898                self.state[operands.dst].set_u64(c);
2899                ControlFlow::Continue(())
2900            }
2901            None => self.done_trap::<crate::Xadd64UoverflowTrap>(),
2902        }
2903    }
2904
2905    fn xmulhi64_s(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2906        let a = self.state[operands.src1].get_i64();
2907        let b = self.state[operands.src2].get_i64();
2908        let result = ((i128::from(a) * i128::from(b)) >> 64) as i64;
2909        self.state[operands.dst].set_i64(result);
2910        ControlFlow::Continue(())
2911    }
2912
2913    fn xmulhi64_u(&mut self, operands: BinaryOperands<XReg>) -> ControlFlow<Done> {
2914        let a = self.state[operands.src1].get_u64();
2915        let b = self.state[operands.src2].get_u64();
2916        let result = ((u128::from(a) * u128::from(b)) >> 64) as u64;
2917        self.state[operands.dst].set_u64(result);
2918        ControlFlow::Continue(())
2919    }
2920
2921    // =========================================================================
2922    // o32 addressing modes for big-endian X-registers
2923
2924    fn xload16be_u32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2925        let result = unsafe { self.load_ne::<u16, crate::XLoad16BeU32O32>(addr)? };
2926        self.state[dst].set_u32(u16::from_be(result).into());
2927        ControlFlow::Continue(())
2928    }
2929
2930    fn xload16be_s32_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2931        let result = unsafe { self.load_ne::<i16, crate::XLoad16BeS32O32>(addr)? };
2932        self.state[dst].set_i32(i16::from_be(result).into());
2933        ControlFlow::Continue(())
2934    }
2935
2936    fn xload32be_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2937        let result = unsafe { self.load_ne::<i32, crate::XLoad32BeO32>(addr)? };
2938        self.state[dst].set_i32(i32::from_be(result));
2939        ControlFlow::Continue(())
2940    }
2941
2942    fn xload64be_o32(&mut self, dst: XReg, addr: AddrO32) -> ControlFlow<Done> {
2943        let result = unsafe { self.load_ne::<i64, crate::XLoad64BeO32>(addr)? };
2944        self.state[dst].set_i64(i64::from_be(result));
2945        ControlFlow::Continue(())
2946    }
2947
2948    fn xstore16be_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2949        let val = self.state[val].get_u32() as u16;
2950        unsafe {
2951            self.store_ne::<u16, crate::XStore16BeO32>(addr, val.to_be())?;
2952        }
2953        ControlFlow::Continue(())
2954    }
2955
2956    fn xstore32be_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2957        let val = self.state[val].get_u32();
2958        unsafe {
2959            self.store_ne::<u32, crate::XStore32BeO32>(addr, val.to_be())?;
2960        }
2961        ControlFlow::Continue(())
2962    }
2963
2964    fn xstore64be_o32(&mut self, addr: AddrO32, val: XReg) -> ControlFlow<Done> {
2965        let val = self.state[val].get_u64();
2966        unsafe {
2967            self.store_ne::<u64, crate::XStore64BeO32>(addr, val.to_be())?;
2968        }
2969        ControlFlow::Continue(())
2970    }
2971
2972    // =========================================================================
2973    // o32 addressing modes for little-endian F-registers
2974
2975    fn fload32le_o32(&mut self, dst: FReg, addr: AddrO32) -> ControlFlow<Done> {
2976        let val = unsafe { self.load_ne::<u32, crate::Fload32LeO32>(addr)? };
2977        self.state[dst].set_f32(f32::from_bits(u32::from_le(val)));
2978        ControlFlow::Continue(())
2979    }
2980
2981    fn fload64le_o32(&mut self, dst: FReg, addr: AddrO32) -> ControlFlow<Done> {
2982        let val = unsafe { self.load_ne::<u64, crate::Fload64LeO32>(addr)? };
2983        self.state[dst].set_f64(f64::from_bits(u64::from_le(val)));
2984        ControlFlow::Continue(())
2985    }
2986
2987    fn fstore32le_o32(&mut self, addr: AddrO32, src: FReg) -> ControlFlow<Done> {
2988        let val = self.state[src].get_f32();
2989        unsafe {
2990            self.store_ne::<u32, crate::Fstore32LeO32>(addr, val.to_bits().to_le())?;
2991        }
2992        ControlFlow::Continue(())
2993    }
2994
2995    fn fstore64le_o32(&mut self, addr: AddrO32, src: FReg) -> ControlFlow<Done> {
2996        let val = self.state[src].get_f64();
2997        unsafe {
2998            self.store_ne::<u64, crate::Fstore64LeO32>(addr, val.to_bits().to_le())?;
2999        }
3000        ControlFlow::Continue(())
3001    }
3002
3003    // =========================================================================
3004    // o32 addressing modes for big-endian F-registers
3005
3006    fn fload32be_o32(&mut self, dst: FReg, addr: AddrO32) -> ControlFlow<Done> {
3007        let val = unsafe { self.load_ne::<u32, crate::Fload32BeO32>(addr)? };
3008        self.state[dst].set_f32(f32::from_bits(u32::from_be(val)));
3009        ControlFlow::Continue(())
3010    }
3011
3012    fn fload64be_o32(&mut self, dst: FReg, addr: AddrO32) -> ControlFlow<Done> {
3013        let val = unsafe { self.load_ne::<u64, crate::Fload64BeO32>(addr)? };
3014        self.state[dst].set_f64(f64::from_bits(u64::from_be(val)));
3015        ControlFlow::Continue(())
3016    }
3017
3018    fn fstore32be_o32(&mut self, addr: AddrO32, src: FReg) -> ControlFlow<Done> {
3019        let val = self.state[src].get_f32();
3020        unsafe {
3021            self.store_ne::<u32, crate::Fstore32BeO32>(addr, val.to_bits().to_be())?;
3022        }
3023        ControlFlow::Continue(())
3024    }
3025
3026    fn fstore64be_o32(&mut self, addr: AddrO32, src: FReg) -> ControlFlow<Done> {
3027        let val = self.state[src].get_f64();
3028        unsafe {
3029            self.store_ne::<u64, crate::Fstore64BeO32>(addr, val.to_bits().to_be())?;
3030        }
3031        ControlFlow::Continue(())
3032    }
3033
3034    // =========================================================================
3035    // z addressing modes for little-endian F-registers
3036
3037    fn fload32le_z(&mut self, dst: FReg, addr: AddrZ) -> ControlFlow<Done> {
3038        let val = unsafe { self.load_ne::<u32, crate::Fload32LeZ>(addr)? };
3039        self.state[dst].set_f32(f32::from_bits(u32::from_le(val)));
3040        ControlFlow::Continue(())
3041    }
3042
3043    fn fload64le_z(&mut self, dst: FReg, addr: AddrZ) -> ControlFlow<Done> {
3044        let val = unsafe { self.load_ne::<u64, crate::Fload64LeZ>(addr)? };
3045        self.state[dst].set_f64(f64::from_bits(u64::from_le(val)));
3046        ControlFlow::Continue(())
3047    }
3048
3049    fn fstore32le_z(&mut self, addr: AddrZ, src: FReg) -> ControlFlow<Done> {
3050        let val = self.state[src].get_f32();
3051        unsafe {
3052            self.store_ne::<u32, crate::Fstore32LeZ>(addr, val.to_bits().to_le())?;
3053        }
3054        ControlFlow::Continue(())
3055    }
3056
3057    fn fstore64le_z(&mut self, addr: AddrZ, src: FReg) -> ControlFlow<Done> {
3058        let val = self.state[src].get_f64();
3059        unsafe {
3060            self.store_ne::<u64, crate::Fstore64LeZ>(addr, val.to_bits().to_le())?;
3061        }
3062        ControlFlow::Continue(())
3063    }
3064
3065    // =========================================================================
3066    // g32 addressing modes for little-endian F-registers
3067
3068    fn fload32le_g32(&mut self, dst: FReg, addr: AddrG32) -> ControlFlow<Done> {
3069        let val = unsafe { self.load_ne::<u32, crate::Fload32LeG32>(addr)? };
3070        self.state[dst].set_f32(f32::from_bits(u32::from_le(val)));
3071        ControlFlow::Continue(())
3072    }
3073
3074    fn fload64le_g32(&mut self, dst: FReg, addr: AddrG32) -> ControlFlow<Done> {
3075        let val = unsafe { self.load_ne::<u64, crate::Fload64LeG32>(addr)? };
3076        self.state[dst].set_f64(f64::from_bits(u64::from_le(val)));
3077        ControlFlow::Continue(())
3078    }
3079
3080    fn fstore32le_g32(&mut self, addr: AddrG32, src: FReg) -> ControlFlow<Done> {
3081        let val = self.state[src].get_f32();
3082        unsafe {
3083            self.store_ne::<u32, crate::Fstore32LeG32>(addr, val.to_bits().to_le())?;
3084        }
3085        ControlFlow::Continue(())
3086    }
3087
3088    fn fstore64le_g32(&mut self, addr: AddrG32, src: FReg) -> ControlFlow<Done> {
3089        let val = self.state[src].get_f64();
3090        unsafe {
3091            self.store_ne::<u64, crate::Fstore64LeG32>(addr, val.to_bits().to_le())?;
3092        }
3093        ControlFlow::Continue(())
3094    }
3095
3096    // =========================================================================
3097    // o32 addressing modes for little-endian V-registers
3098
3099    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3100    fn vload128le_o32(&mut self, dst: VReg, addr: AddrO32) -> ControlFlow<Done> {
3101        let val = unsafe { self.load_ne::<u128, crate::VLoad128O32>(addr)? };
3102        self.state[dst].set_u128(u128::from_le(val));
3103        ControlFlow::Continue(())
3104    }
3105
3106    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3107    fn vstore128le_o32(&mut self, addr: AddrO32, src: VReg) -> ControlFlow<Done> {
3108        let val = self.state[src].get_u128();
3109        unsafe {
3110            self.store_ne::<u128, crate::Vstore128LeO32>(addr, val.to_le())?;
3111        }
3112        ControlFlow::Continue(())
3113    }
3114
3115    // =========================================================================
3116    // z addressing modes for little-endian V-registers
3117
3118    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3119    fn vload128le_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
3120        let val = unsafe { self.load_ne::<u128, crate::VLoad128LeZ>(addr)? };
3121        self.state[dst].set_u128(u128::from_le(val));
3122        ControlFlow::Continue(())
3123    }
3124
3125    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3126    fn vstore128le_z(&mut self, addr: AddrZ, src: VReg) -> ControlFlow<Done> {
3127        let val = self.state[src].get_u128();
3128        unsafe {
3129            self.store_ne::<u128, crate::Vstore128LeZ>(addr, val.to_le())?;
3130        }
3131        ControlFlow::Continue(())
3132    }
3133
3134    // =========================================================================
3135    // g32 addressing modes for little-endian V-registers
3136
3137    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3138    fn vload128le_g32(&mut self, dst: VReg, addr: AddrG32) -> ControlFlow<Done> {
3139        let val = unsafe { self.load_ne::<u128, crate::VLoad128G32>(addr)? };
3140        self.state[dst].set_u128(u128::from_le(val));
3141        ControlFlow::Continue(())
3142    }
3143
3144    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3145    fn vstore128le_g32(&mut self, addr: AddrG32, src: VReg) -> ControlFlow<Done> {
3146        let val = self.state[src].get_u128();
3147        unsafe {
3148            self.store_ne::<u128, crate::Vstore128LeG32>(addr, val.to_le())?;
3149        }
3150        ControlFlow::Continue(())
3151    }
3152
3153    fn xmov_fp(&mut self, dst: XReg) -> ControlFlow<Done> {
3154        let fp = self.state.fp;
3155        self.state[dst].set_ptr(fp);
3156        ControlFlow::Continue(())
3157    }
3158
3159    fn xmov_lr(&mut self, dst: XReg) -> ControlFlow<Done> {
3160        let lr = self.state.lr;
3161        self.state[dst].set_ptr(lr);
3162        ControlFlow::Continue(())
3163    }
3164
3165    fn fmov(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3166        let val = self.state[src];
3167        self.state[dst] = val;
3168        ControlFlow::Continue(())
3169    }
3170
3171    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3172    fn vmov(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3173        let val = self.state[src];
3174        self.state[dst] = val;
3175        ControlFlow::Continue(())
3176    }
3177
3178    fn fconst32(&mut self, dst: FReg, bits: u32) -> ControlFlow<Done> {
3179        self.state[dst].set_f32(f32::from_bits(bits));
3180        ControlFlow::Continue(())
3181    }
3182
3183    fn fconst64(&mut self, dst: FReg, bits: u64) -> ControlFlow<Done> {
3184        self.state[dst].set_f64(f64::from_bits(bits));
3185        ControlFlow::Continue(())
3186    }
3187
3188    fn bitcast_int_from_float_32(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3189        let val = self.state[src].get_f32();
3190        self.state[dst].set_u32(val.to_bits());
3191        ControlFlow::Continue(())
3192    }
3193
3194    fn bitcast_int_from_float_64(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3195        let val = self.state[src].get_f64();
3196        self.state[dst].set_u64(val.to_bits());
3197        ControlFlow::Continue(())
3198    }
3199
3200    fn bitcast_float_from_int_32(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3201        let val = self.state[src].get_u32();
3202        self.state[dst].set_f32(f32::from_bits(val));
3203        ControlFlow::Continue(())
3204    }
3205
3206    fn bitcast_float_from_int_64(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3207        let val = self.state[src].get_u64();
3208        self.state[dst].set_f64(f64::from_bits(val));
3209        ControlFlow::Continue(())
3210    }
3211
3212    fn feq32(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3213        let a = self.state[src1].get_f32();
3214        let b = self.state[src2].get_f32();
3215        self.state[dst].set_u32(u32::from(a == b));
3216        ControlFlow::Continue(())
3217    }
3218
3219    fn fneq32(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3220        let a = self.state[src1].get_f32();
3221        let b = self.state[src2].get_f32();
3222        self.state[dst].set_u32(u32::from(a != b));
3223        ControlFlow::Continue(())
3224    }
3225
3226    fn flt32(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3227        let a = self.state[src1].get_f32();
3228        let b = self.state[src2].get_f32();
3229        self.state[dst].set_u32(u32::from(a < b));
3230        ControlFlow::Continue(())
3231    }
3232
3233    fn flteq32(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3234        let a = self.state[src1].get_f32();
3235        let b = self.state[src2].get_f32();
3236        self.state[dst].set_u32(u32::from(a <= b));
3237        ControlFlow::Continue(())
3238    }
3239
3240    fn feq64(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3241        let a = self.state[src1].get_f64();
3242        let b = self.state[src2].get_f64();
3243        self.state[dst].set_u32(u32::from(a == b));
3244        ControlFlow::Continue(())
3245    }
3246
3247    fn fneq64(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3248        let a = self.state[src1].get_f64();
3249        let b = self.state[src2].get_f64();
3250        self.state[dst].set_u32(u32::from(a != b));
3251        ControlFlow::Continue(())
3252    }
3253
3254    fn flt64(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3255        let a = self.state[src1].get_f64();
3256        let b = self.state[src2].get_f64();
3257        self.state[dst].set_u32(u32::from(a < b));
3258        ControlFlow::Continue(())
3259    }
3260
3261    fn flteq64(&mut self, dst: XReg, src1: FReg, src2: FReg) -> ControlFlow<Done> {
3262        let a = self.state[src1].get_f64();
3263        let b = self.state[src2].get_f64();
3264        self.state[dst].set_u32(u32::from(a <= b));
3265        ControlFlow::Continue(())
3266    }
3267
3268    fn fselect32(
3269        &mut self,
3270        dst: FReg,
3271        cond: XReg,
3272        if_nonzero: FReg,
3273        if_zero: FReg,
3274    ) -> ControlFlow<Done> {
3275        let result = if self.state[cond].get_u32() != 0 {
3276            self.state[if_nonzero].get_f32()
3277        } else {
3278            self.state[if_zero].get_f32()
3279        };
3280        self.state[dst].set_f32(result);
3281        ControlFlow::Continue(())
3282    }
3283
3284    fn fselect64(
3285        &mut self,
3286        dst: FReg,
3287        cond: XReg,
3288        if_nonzero: FReg,
3289        if_zero: FReg,
3290    ) -> ControlFlow<Done> {
3291        let result = if self.state[cond].get_u32() != 0 {
3292            self.state[if_nonzero].get_f64()
3293        } else {
3294            self.state[if_zero].get_f64()
3295        };
3296        self.state[dst].set_f64(result);
3297        ControlFlow::Continue(())
3298    }
3299
3300    fn f32_from_x32_s(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3301        let a = self.state[src].get_i32();
3302        self.state[dst].set_f32(a as f32);
3303        ControlFlow::Continue(())
3304    }
3305
3306    fn f32_from_x32_u(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3307        let a = self.state[src].get_u32();
3308        self.state[dst].set_f32(a as f32);
3309        ControlFlow::Continue(())
3310    }
3311
3312    fn f32_from_x64_s(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3313        let a = self.state[src].get_i64();
3314        self.state[dst].set_f32(a as f32);
3315        ControlFlow::Continue(())
3316    }
3317
3318    fn f32_from_x64_u(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3319        let a = self.state[src].get_u64();
3320        self.state[dst].set_f32(a as f32);
3321        ControlFlow::Continue(())
3322    }
3323
3324    fn f64_from_x32_s(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3325        let a = self.state[src].get_i32();
3326        self.state[dst].set_f64(a as f64);
3327        ControlFlow::Continue(())
3328    }
3329
3330    fn f64_from_x32_u(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3331        let a = self.state[src].get_u32();
3332        self.state[dst].set_f64(a as f64);
3333        ControlFlow::Continue(())
3334    }
3335
3336    fn f64_from_x64_s(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3337        let a = self.state[src].get_i64();
3338        self.state[dst].set_f64(a as f64);
3339        ControlFlow::Continue(())
3340    }
3341
3342    fn f64_from_x64_u(&mut self, dst: FReg, src: XReg) -> ControlFlow<Done> {
3343        let a = self.state[src].get_u64();
3344        self.state[dst].set_f64(a as f64);
3345        ControlFlow::Continue(())
3346    }
3347
3348    fn x32_from_f32_s(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3349        let a = self.state[src].get_f32();
3350        self.check_xnn_from_f32::<crate::X32FromF32S>(a, f32_cvt_to_int_bounds(true, 32))?;
3351        self.state[dst].set_i32(a as i32);
3352        ControlFlow::Continue(())
3353    }
3354
3355    fn x32_from_f32_u(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3356        let a = self.state[src].get_f32();
3357        self.check_xnn_from_f32::<crate::X32FromF32U>(a, f32_cvt_to_int_bounds(false, 32))?;
3358        self.state[dst].set_u32(a as u32);
3359        ControlFlow::Continue(())
3360    }
3361
3362    fn x64_from_f32_s(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3363        let a = self.state[src].get_f32();
3364        self.check_xnn_from_f32::<crate::X64FromF32S>(a, f32_cvt_to_int_bounds(true, 64))?;
3365        self.state[dst].set_i64(a as i64);
3366        ControlFlow::Continue(())
3367    }
3368
3369    fn x64_from_f32_u(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3370        let a = self.state[src].get_f32();
3371        self.check_xnn_from_f32::<crate::X64FromF32U>(a, f32_cvt_to_int_bounds(false, 64))?;
3372        self.state[dst].set_u64(a as u64);
3373        ControlFlow::Continue(())
3374    }
3375
3376    fn x32_from_f64_s(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3377        let a = self.state[src].get_f64();
3378        self.check_xnn_from_f64::<crate::X32FromF64S>(a, f64_cvt_to_int_bounds(true, 32))?;
3379        self.state[dst].set_i32(a as i32);
3380        ControlFlow::Continue(())
3381    }
3382
3383    fn x32_from_f64_u(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3384        let a = self.state[src].get_f64();
3385        self.check_xnn_from_f64::<crate::X32FromF64U>(a, f64_cvt_to_int_bounds(false, 32))?;
3386        self.state[dst].set_u32(a as u32);
3387        ControlFlow::Continue(())
3388    }
3389
3390    fn x64_from_f64_s(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3391        let a = self.state[src].get_f64();
3392        self.check_xnn_from_f64::<crate::X64FromF64S>(a, f64_cvt_to_int_bounds(true, 64))?;
3393        self.state[dst].set_i64(a as i64);
3394        ControlFlow::Continue(())
3395    }
3396
3397    fn x64_from_f64_u(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3398        let a = self.state[src].get_f64();
3399        self.check_xnn_from_f64::<crate::X64FromF64U>(a, f64_cvt_to_int_bounds(false, 64))?;
3400        self.state[dst].set_u64(a as u64);
3401        ControlFlow::Continue(())
3402    }
3403
3404    fn x32_from_f32_s_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3405        let a = self.state[src].get_f32();
3406        self.state[dst].set_i32(a as i32);
3407        ControlFlow::Continue(())
3408    }
3409
3410    fn x32_from_f32_u_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3411        let a = self.state[src].get_f32();
3412        self.state[dst].set_u32(a as u32);
3413        ControlFlow::Continue(())
3414    }
3415
3416    fn x64_from_f32_s_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3417        let a = self.state[src].get_f32();
3418        self.state[dst].set_i64(a as i64);
3419        ControlFlow::Continue(())
3420    }
3421
3422    fn x64_from_f32_u_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3423        let a = self.state[src].get_f32();
3424        self.state[dst].set_u64(a as u64);
3425        ControlFlow::Continue(())
3426    }
3427
3428    fn x32_from_f64_s_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3429        let a = self.state[src].get_f64();
3430        self.state[dst].set_i32(a as i32);
3431        ControlFlow::Continue(())
3432    }
3433
3434    fn x32_from_f64_u_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3435        let a = self.state[src].get_f64();
3436        self.state[dst].set_u32(a as u32);
3437        ControlFlow::Continue(())
3438    }
3439
3440    fn x64_from_f64_s_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3441        let a = self.state[src].get_f64();
3442        self.state[dst].set_i64(a as i64);
3443        ControlFlow::Continue(())
3444    }
3445
3446    fn x64_from_f64_u_sat(&mut self, dst: XReg, src: FReg) -> ControlFlow<Done> {
3447        let a = self.state[src].get_f64();
3448        self.state[dst].set_u64(a as u64);
3449        ControlFlow::Continue(())
3450    }
3451
3452    fn f32_from_f64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3453        let a = self.state[src].get_f64();
3454        self.state[dst].set_f32(a as f32);
3455        ControlFlow::Continue(())
3456    }
3457
3458    fn f64_from_f32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3459        let a = self.state[src].get_f32();
3460        self.state[dst].set_f64(a.into());
3461        ControlFlow::Continue(())
3462    }
3463
3464    fn fcopysign32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3465        let a = self.state[operands.src1].get_f32();
3466        let b = self.state[operands.src2].get_f32();
3467        self.state[operands.dst].set_f32(a.wasm_copysign(b));
3468        ControlFlow::Continue(())
3469    }
3470
3471    fn fcopysign64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3472        let a = self.state[operands.src1].get_f64();
3473        let b = self.state[operands.src2].get_f64();
3474        self.state[operands.dst].set_f64(a.wasm_copysign(b));
3475        ControlFlow::Continue(())
3476    }
3477
3478    fn fadd32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3479        let a = self.state[operands.src1].get_f32();
3480        let b = self.state[operands.src2].get_f32();
3481        self.state[operands.dst].set_f32(a + b);
3482        ControlFlow::Continue(())
3483    }
3484
3485    fn fsub32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3486        let a = self.state[operands.src1].get_f32();
3487        let b = self.state[operands.src2].get_f32();
3488        self.state[operands.dst].set_f32(a - b);
3489        ControlFlow::Continue(())
3490    }
3491
3492    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3493    fn vsubf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3494        let mut a = self.state[operands.src1].get_f32x4();
3495        let b = self.state[operands.src2].get_f32x4();
3496        for (a, b) in a.iter_mut().zip(b) {
3497            *a = *a - b;
3498        }
3499        self.state[operands.dst].set_f32x4(a);
3500        ControlFlow::Continue(())
3501    }
3502
3503    fn fmul32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3504        let a = self.state[operands.src1].get_f32();
3505        let b = self.state[operands.src2].get_f32();
3506        self.state[operands.dst].set_f32(a * b);
3507        ControlFlow::Continue(())
3508    }
3509
3510    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3511    fn vmulf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3512        let mut a = self.state[operands.src1].get_f32x4();
3513        let b = self.state[operands.src2].get_f32x4();
3514        for (a, b) in a.iter_mut().zip(b) {
3515            *a = *a * b;
3516        }
3517        self.state[operands.dst].set_f32x4(a);
3518        ControlFlow::Continue(())
3519    }
3520
3521    fn fdiv32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3522        let a = self.state[operands.src1].get_f32();
3523        let b = self.state[operands.src2].get_f32();
3524        self.state[operands.dst].set_f32(a / b);
3525        ControlFlow::Continue(())
3526    }
3527
3528    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3529    fn vdivf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3530        let a = self.state[operands.src1].get_f32x4();
3531        let b = self.state[operands.src2].get_f32x4();
3532        let mut result = [0.0f32; 4];
3533
3534        for i in 0..4 {
3535            result[i] = a[i] / b[i];
3536        }
3537
3538        self.state[operands.dst].set_f32x4(result);
3539        ControlFlow::Continue(())
3540    }
3541
3542    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3543    fn vdivf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3544        let a = self.state[operands.src1].get_f64x2();
3545        let b = self.state[operands.src2].get_f64x2();
3546        let mut result = [0.0f64; 2];
3547
3548        for i in 0..2 {
3549            result[i] = a[i] / b[i];
3550        }
3551
3552        self.state[operands.dst].set_f64x2(result);
3553        ControlFlow::Continue(())
3554    }
3555
3556    fn fmaximum32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3557        let a = self.state[operands.src1].get_f32();
3558        let b = self.state[operands.src2].get_f32();
3559        self.state[operands.dst].set_f32(a.wasm_maximum(b));
3560        ControlFlow::Continue(())
3561    }
3562
3563    fn fminimum32(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3564        let a = self.state[operands.src1].get_f32();
3565        let b = self.state[operands.src2].get_f32();
3566        self.state[operands.dst].set_f32(a.wasm_minimum(b));
3567        ControlFlow::Continue(())
3568    }
3569
3570    fn ftrunc32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3571        let a = self.state[src].get_f32();
3572        self.state[dst].set_f32(a.wasm_trunc());
3573        ControlFlow::Continue(())
3574    }
3575
3576    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3577    fn vtrunc32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3578        let mut a = self.state[src].get_f32x4();
3579        for elem in a.iter_mut() {
3580            *elem = elem.wasm_trunc();
3581        }
3582        self.state[dst].set_f32x4(a);
3583        ControlFlow::Continue(())
3584    }
3585
3586    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3587    fn vtrunc64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3588        let mut a = self.state[src].get_f64x2();
3589        for elem in a.iter_mut() {
3590            *elem = elem.wasm_trunc();
3591        }
3592        self.state[dst].set_f64x2(a);
3593        ControlFlow::Continue(())
3594    }
3595
3596    fn ffloor32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3597        let a = self.state[src].get_f32();
3598        self.state[dst].set_f32(a.wasm_floor());
3599        ControlFlow::Continue(())
3600    }
3601
3602    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3603    fn vfloor32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3604        let mut a = self.state[src].get_f32x4();
3605        for elem in a.iter_mut() {
3606            *elem = elem.wasm_floor();
3607        }
3608        self.state[dst].set_f32x4(a);
3609        ControlFlow::Continue(())
3610    }
3611
3612    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3613    fn vfloor64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3614        let mut a = self.state[src].get_f64x2();
3615        for elem in a.iter_mut() {
3616            *elem = elem.wasm_floor();
3617        }
3618        self.state[dst].set_f64x2(a);
3619        ControlFlow::Continue(())
3620    }
3621
3622    fn fceil32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3623        let a = self.state[src].get_f32();
3624        self.state[dst].set_f32(a.wasm_ceil());
3625        ControlFlow::Continue(())
3626    }
3627
3628    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3629    fn vceil32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3630        let mut a = self.state[src].get_f32x4();
3631        for elem in a.iter_mut() {
3632            *elem = elem.wasm_ceil();
3633        }
3634        self.state[dst].set_f32x4(a);
3635
3636        ControlFlow::Continue(())
3637    }
3638
3639    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3640    fn vceil64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3641        let mut a = self.state[src].get_f64x2();
3642        for elem in a.iter_mut() {
3643            *elem = elem.wasm_ceil();
3644        }
3645        self.state[dst].set_f64x2(a);
3646
3647        ControlFlow::Continue(())
3648    }
3649
3650    fn fnearest32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3651        let a = self.state[src].get_f32();
3652        self.state[dst].set_f32(a.wasm_nearest());
3653        ControlFlow::Continue(())
3654    }
3655
3656    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3657    fn vnearest32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3658        let mut a = self.state[src].get_f32x4();
3659        for elem in a.iter_mut() {
3660            *elem = elem.wasm_nearest();
3661        }
3662        self.state[dst].set_f32x4(a);
3663        ControlFlow::Continue(())
3664    }
3665
3666    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3667    fn vnearest64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3668        let mut a = self.state[src].get_f64x2();
3669        for elem in a.iter_mut() {
3670            *elem = elem.wasm_nearest();
3671        }
3672        self.state[dst].set_f64x2(a);
3673        ControlFlow::Continue(())
3674    }
3675
3676    fn fsqrt32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3677        let a = self.state[src].get_f32();
3678        self.state[dst].set_f32(a.wasm_sqrt());
3679        ControlFlow::Continue(())
3680    }
3681
3682    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3683    fn vsqrt32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3684        let mut a = self.state[src].get_f32x4();
3685        for elem in a.iter_mut() {
3686            *elem = elem.wasm_sqrt();
3687        }
3688        self.state[dst].set_f32x4(a);
3689        ControlFlow::Continue(())
3690    }
3691
3692    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3693    fn vsqrt64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3694        let mut a = self.state[src].get_f64x2();
3695        for elem in a.iter_mut() {
3696            *elem = elem.wasm_sqrt();
3697        }
3698        self.state[dst].set_f64x2(a);
3699        ControlFlow::Continue(())
3700    }
3701
3702    fn fneg32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3703        let a = self.state[src].get_f32();
3704        self.state[dst].set_f32(-a);
3705        ControlFlow::Continue(())
3706    }
3707
3708    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3709    fn vnegf32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
3710        let mut a = self.state[src].get_f32x4();
3711        for elem in a.iter_mut() {
3712            *elem = -*elem;
3713        }
3714        self.state[dst].set_f32x4(a);
3715        ControlFlow::Continue(())
3716    }
3717
3718    fn fabs32(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3719        let a = self.state[src].get_f32();
3720        self.state[dst].set_f32(a.wasm_abs());
3721        ControlFlow::Continue(())
3722    }
3723
3724    fn fadd64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3725        let a = self.state[operands.src1].get_f64();
3726        let b = self.state[operands.src2].get_f64();
3727        self.state[operands.dst].set_f64(a + b);
3728        ControlFlow::Continue(())
3729    }
3730
3731    fn fsub64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3732        let a = self.state[operands.src1].get_f64();
3733        let b = self.state[operands.src2].get_f64();
3734        self.state[operands.dst].set_f64(a - b);
3735        ControlFlow::Continue(())
3736    }
3737
3738    fn fmul64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3739        let a = self.state[operands.src1].get_f64();
3740        let b = self.state[operands.src2].get_f64();
3741        self.state[operands.dst].set_f64(a * b);
3742        ControlFlow::Continue(())
3743    }
3744
3745    fn fdiv64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3746        let a = self.state[operands.src1].get_f64();
3747        let b = self.state[operands.src2].get_f64();
3748        self.state[operands.dst].set_f64(a / b);
3749        ControlFlow::Continue(())
3750    }
3751
3752    fn fmaximum64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3753        let a = self.state[operands.src1].get_f64();
3754        let b = self.state[operands.src2].get_f64();
3755        self.state[operands.dst].set_f64(a.wasm_maximum(b));
3756        ControlFlow::Continue(())
3757    }
3758
3759    fn fminimum64(&mut self, operands: BinaryOperands<FReg>) -> ControlFlow<Done> {
3760        let a = self.state[operands.src1].get_f64();
3761        let b = self.state[operands.src2].get_f64();
3762        self.state[operands.dst].set_f64(a.wasm_minimum(b));
3763        ControlFlow::Continue(())
3764    }
3765
3766    fn ftrunc64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3767        let a = self.state[src].get_f64();
3768        self.state[dst].set_f64(a.wasm_trunc());
3769        ControlFlow::Continue(())
3770    }
3771
3772    fn ffloor64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3773        let a = self.state[src].get_f64();
3774        self.state[dst].set_f64(a.wasm_floor());
3775        ControlFlow::Continue(())
3776    }
3777
3778    fn fceil64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3779        let a = self.state[src].get_f64();
3780        self.state[dst].set_f64(a.wasm_ceil());
3781        ControlFlow::Continue(())
3782    }
3783
3784    fn fnearest64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3785        let a = self.state[src].get_f64();
3786        self.state[dst].set_f64(a.wasm_nearest());
3787        ControlFlow::Continue(())
3788    }
3789
3790    fn fsqrt64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3791        let a = self.state[src].get_f64();
3792        self.state[dst].set_f64(a.wasm_sqrt());
3793        ControlFlow::Continue(())
3794    }
3795
3796    fn fneg64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3797        let a = self.state[src].get_f64();
3798        self.state[dst].set_f64(-a);
3799        ControlFlow::Continue(())
3800    }
3801
3802    fn fabs64(&mut self, dst: FReg, src: FReg) -> ControlFlow<Done> {
3803        let a = self.state[src].get_f64();
3804        self.state[dst].set_f64(a.wasm_abs());
3805        ControlFlow::Continue(())
3806    }
3807
3808    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3809    fn vaddi8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3810        let mut a = self.state[operands.src1].get_i8x16();
3811        let b = self.state[operands.src2].get_i8x16();
3812        for (a, b) in a.iter_mut().zip(b) {
3813            *a = a.wrapping_add(b);
3814        }
3815        self.state[operands.dst].set_i8x16(a);
3816        ControlFlow::Continue(())
3817    }
3818
3819    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3820    fn vaddi16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3821        let mut a = self.state[operands.src1].get_i16x8();
3822        let b = self.state[operands.src2].get_i16x8();
3823        for (a, b) in a.iter_mut().zip(b) {
3824            *a = a.wrapping_add(b);
3825        }
3826        self.state[operands.dst].set_i16x8(a);
3827        ControlFlow::Continue(())
3828    }
3829
3830    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3831    fn vaddi32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3832        let mut a = self.state[operands.src1].get_i32x4();
3833        let b = self.state[operands.src2].get_i32x4();
3834        for (a, b) in a.iter_mut().zip(b) {
3835            *a = a.wrapping_add(b);
3836        }
3837        self.state[operands.dst].set_i32x4(a);
3838        ControlFlow::Continue(())
3839    }
3840
3841    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3842    fn vaddi64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3843        let mut a = self.state[operands.src1].get_i64x2();
3844        let b = self.state[operands.src2].get_i64x2();
3845        for (a, b) in a.iter_mut().zip(b) {
3846            *a = a.wrapping_add(b);
3847        }
3848        self.state[operands.dst].set_i64x2(a);
3849        ControlFlow::Continue(())
3850    }
3851
3852    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3853    fn vaddf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3854        let mut a = self.state[operands.src1].get_f32x4();
3855        let b = self.state[operands.src2].get_f32x4();
3856        for (a, b) in a.iter_mut().zip(b) {
3857            *a += b;
3858        }
3859        self.state[operands.dst].set_f32x4(a);
3860        ControlFlow::Continue(())
3861    }
3862
3863    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3864    fn vaddf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3865        let mut a = self.state[operands.src1].get_f64x2();
3866        let b = self.state[operands.src2].get_f64x2();
3867        for (a, b) in a.iter_mut().zip(b) {
3868            *a += b;
3869        }
3870        self.state[operands.dst].set_f64x2(a);
3871        ControlFlow::Continue(())
3872    }
3873
3874    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3875    fn vaddi8x16_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3876        let mut a = self.state[operands.src1].get_i8x16();
3877        let b = self.state[operands.src2].get_i8x16();
3878        for (a, b) in a.iter_mut().zip(b) {
3879            *a = (*a).saturating_add(b);
3880        }
3881        self.state[operands.dst].set_i8x16(a);
3882        ControlFlow::Continue(())
3883    }
3884
3885    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3886    fn vaddu8x16_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3887        let mut a = self.state[operands.src1].get_u8x16();
3888        let b = self.state[operands.src2].get_u8x16();
3889        for (a, b) in a.iter_mut().zip(b) {
3890            *a = (*a).saturating_add(b);
3891        }
3892        self.state[operands.dst].set_u8x16(a);
3893        ControlFlow::Continue(())
3894    }
3895
3896    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3897    fn vaddi16x8_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3898        let mut a = self.state[operands.src1].get_i16x8();
3899        let b = self.state[operands.src2].get_i16x8();
3900        for (a, b) in a.iter_mut().zip(b) {
3901            *a = (*a).saturating_add(b);
3902        }
3903        self.state[operands.dst].set_i16x8(a);
3904        ControlFlow::Continue(())
3905    }
3906
3907    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3908    fn vaddu16x8_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3909        let mut a = self.state[operands.src1].get_u16x8();
3910        let b = self.state[operands.src2].get_u16x8();
3911        for (a, b) in a.iter_mut().zip(b) {
3912            *a = (*a).saturating_add(b);
3913        }
3914        self.state[operands.dst].set_u16x8(a);
3915        ControlFlow::Continue(())
3916    }
3917
3918    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3919    fn vaddpairwisei16x8_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3920        let a = self.state[operands.src1].get_i16x8();
3921        let b = self.state[operands.src2].get_i16x8();
3922        let mut result = [0i16; 8];
3923        let half = result.len() / 2;
3924        for i in 0..half {
3925            result[i] = a[2 * i].wrapping_add(a[2 * i + 1]);
3926            result[i + half] = b[2 * i].wrapping_add(b[2 * i + 1]);
3927        }
3928        self.state[operands.dst].set_i16x8(result);
3929        ControlFlow::Continue(())
3930    }
3931
3932    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3933    fn vaddpairwisei32x4_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
3934        let a = self.state[operands.src1].get_i32x4();
3935        let b = self.state[operands.src2].get_i32x4();
3936        let mut result = [0i32; 4];
3937        result[0] = a[0].wrapping_add(a[1]);
3938        result[1] = a[2].wrapping_add(a[3]);
3939        result[2] = b[0].wrapping_add(b[1]);
3940        result[3] = b[2].wrapping_add(b[3]);
3941        self.state[operands.dst].set_i32x4(result);
3942        ControlFlow::Continue(())
3943    }
3944
3945    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3946    fn vshli8x16(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3947        let a = self.state[operands.src1].get_i8x16();
3948        let b = self.state[operands.src2].get_u32();
3949        self.state[operands.dst].set_i8x16(a.map(|a| a.wrapping_shl(b)));
3950        ControlFlow::Continue(())
3951    }
3952
3953    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3954    fn vshli16x8(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3955        let a = self.state[operands.src1].get_i16x8();
3956        let b = self.state[operands.src2].get_u32();
3957        self.state[operands.dst].set_i16x8(a.map(|a| a.wrapping_shl(b)));
3958        ControlFlow::Continue(())
3959    }
3960
3961    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3962    fn vshli32x4(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3963        let a = self.state[operands.src1].get_i32x4();
3964        let b = self.state[operands.src2].get_u32();
3965        self.state[operands.dst].set_i32x4(a.map(|a| a.wrapping_shl(b)));
3966        ControlFlow::Continue(())
3967    }
3968
3969    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3970    fn vshli64x2(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3971        let a = self.state[operands.src1].get_i64x2();
3972        let b = self.state[operands.src2].get_u32();
3973        self.state[operands.dst].set_i64x2(a.map(|a| a.wrapping_shl(b)));
3974        ControlFlow::Continue(())
3975    }
3976
3977    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3978    fn vshri8x16_s(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3979        let a = self.state[operands.src1].get_i8x16();
3980        let b = self.state[operands.src2].get_u32();
3981        self.state[operands.dst].set_i8x16(a.map(|a| a.wrapping_shr(b)));
3982        ControlFlow::Continue(())
3983    }
3984
3985    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3986    fn vshri16x8_s(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3987        let a = self.state[operands.src1].get_i16x8();
3988        let b = self.state[operands.src2].get_u32();
3989        self.state[operands.dst].set_i16x8(a.map(|a| a.wrapping_shr(b)));
3990        ControlFlow::Continue(())
3991    }
3992
3993    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
3994    fn vshri32x4_s(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
3995        let a = self.state[operands.src1].get_i32x4();
3996        let b = self.state[operands.src2].get_u32();
3997        self.state[operands.dst].set_i32x4(a.map(|a| a.wrapping_shr(b)));
3998        ControlFlow::Continue(())
3999    }
4000
4001    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4002    fn vshri64x2_s(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
4003        let a = self.state[operands.src1].get_i64x2();
4004        let b = self.state[operands.src2].get_u32();
4005        self.state[operands.dst].set_i64x2(a.map(|a| a.wrapping_shr(b)));
4006        ControlFlow::Continue(())
4007    }
4008
4009    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4010    fn vshri8x16_u(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
4011        let a = self.state[operands.src1].get_u8x16();
4012        let b = self.state[operands.src2].get_u32();
4013        self.state[operands.dst].set_u8x16(a.map(|a| a.wrapping_shr(b)));
4014        ControlFlow::Continue(())
4015    }
4016
4017    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4018    fn vshri16x8_u(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
4019        let a = self.state[operands.src1].get_u16x8();
4020        let b = self.state[operands.src2].get_u32();
4021        self.state[operands.dst].set_u16x8(a.map(|a| a.wrapping_shr(b)));
4022        ControlFlow::Continue(())
4023    }
4024
4025    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4026    fn vshri32x4_u(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
4027        let a = self.state[operands.src1].get_u32x4();
4028        let b = self.state[operands.src2].get_u32();
4029        self.state[operands.dst].set_u32x4(a.map(|a| a.wrapping_shr(b)));
4030        ControlFlow::Continue(())
4031    }
4032
4033    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4034    fn vshri64x2_u(&mut self, operands: BinaryOperands<VReg, VReg, XReg>) -> ControlFlow<Done> {
4035        let a = self.state[operands.src1].get_u64x2();
4036        let b = self.state[operands.src2].get_u32();
4037        self.state[operands.dst].set_u64x2(a.map(|a| a.wrapping_shr(b)));
4038        ControlFlow::Continue(())
4039    }
4040
4041    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4042    fn vconst128(&mut self, dst: VReg, val: u128) -> ControlFlow<Done> {
4043        self.state[dst].set_u128(val);
4044        ControlFlow::Continue(())
4045    }
4046
4047    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4048    fn vsplatx8(&mut self, dst: VReg, src: XReg) -> ControlFlow<Done> {
4049        let val = self.state[src].get_u32() as u8;
4050        self.state[dst].set_u8x16([val; 16]);
4051        ControlFlow::Continue(())
4052    }
4053
4054    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4055    fn vsplatx16(&mut self, dst: VReg, src: XReg) -> ControlFlow<Done> {
4056        let val = self.state[src].get_u32() as u16;
4057        self.state[dst].set_u16x8([val; 8]);
4058        ControlFlow::Continue(())
4059    }
4060
4061    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4062    fn vsplatx32(&mut self, dst: VReg, src: XReg) -> ControlFlow<Done> {
4063        let val = self.state[src].get_u32();
4064        self.state[dst].set_u32x4([val; 4]);
4065        ControlFlow::Continue(())
4066    }
4067
4068    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4069    fn vsplatx64(&mut self, dst: VReg, src: XReg) -> ControlFlow<Done> {
4070        let val = self.state[src].get_u64();
4071        self.state[dst].set_u64x2([val; 2]);
4072        ControlFlow::Continue(())
4073    }
4074
4075    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4076    fn vsplatf32(&mut self, dst: VReg, src: FReg) -> ControlFlow<Done> {
4077        let val = self.state[src].get_f32();
4078        self.state[dst].set_f32x4([val; 4]);
4079        ControlFlow::Continue(())
4080    }
4081
4082    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4083    fn vsplatf64(&mut self, dst: VReg, src: FReg) -> ControlFlow<Done> {
4084        let val = self.state[src].get_f64();
4085        self.state[dst].set_f64x2([val; 2]);
4086        ControlFlow::Continue(())
4087    }
4088
4089    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4090    fn vload8x8_s_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4091        let val = unsafe { self.load_ne::<[i8; 8], crate::VLoad8x8SZ>(addr)? };
4092        self.state[dst].set_i16x8(val.map(|i| i.into()));
4093        ControlFlow::Continue(())
4094    }
4095
4096    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4097    fn vload8x8_u_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4098        let val = unsafe { self.load_ne::<[u8; 8], crate::VLoad8x8UZ>(addr)? };
4099        self.state[dst].set_u16x8(val.map(|i| i.into()));
4100        ControlFlow::Continue(())
4101    }
4102
4103    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4104    fn vload16x4le_s_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4105        let val = unsafe { self.load_ne::<[i16; 4], crate::VLoad16x4LeSZ>(addr)? };
4106        self.state[dst].set_i32x4(val.map(|i| i16::from_le(i).into()));
4107        ControlFlow::Continue(())
4108    }
4109
4110    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4111    fn vload16x4le_u_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4112        let val = unsafe { self.load_ne::<[u16; 4], crate::VLoad16x4LeUZ>(addr)? };
4113        self.state[dst].set_u32x4(val.map(|i| u16::from_le(i).into()));
4114        ControlFlow::Continue(())
4115    }
4116
4117    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4118    fn vload32x2le_s_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4119        let val = unsafe { self.load_ne::<[i32; 2], crate::VLoad32x2LeSZ>(addr)? };
4120        self.state[dst].set_i64x2(val.map(|i| i32::from_le(i).into()));
4121        ControlFlow::Continue(())
4122    }
4123
4124    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4125    fn vload32x2le_u_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
4126        let val = unsafe { self.load_ne::<[u32; 2], crate::VLoad32x2LeUZ>(addr)? };
4127        self.state[dst].set_u64x2(val.map(|i| u32::from_le(i).into()));
4128        ControlFlow::Continue(())
4129    }
4130
4131    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4132    fn vband128(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4133        let a = self.state[operands.src1].get_u128();
4134        let b = self.state[operands.src2].get_u128();
4135        self.state[operands.dst].set_u128(a & b);
4136        ControlFlow::Continue(())
4137    }
4138
4139    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4140    fn vbor128(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4141        let a = self.state[operands.src1].get_u128();
4142        let b = self.state[operands.src2].get_u128();
4143        self.state[operands.dst].set_u128(a | b);
4144        ControlFlow::Continue(())
4145    }
4146
4147    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4148    fn vbxor128(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4149        let a = self.state[operands.src1].get_u128();
4150        let b = self.state[operands.src2].get_u128();
4151        self.state[operands.dst].set_u128(a ^ b);
4152        ControlFlow::Continue(())
4153    }
4154
4155    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4156    fn vbnot128(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4157        let a = self.state[src].get_u128();
4158        self.state[dst].set_u128(!a);
4159        ControlFlow::Continue(())
4160    }
4161
4162    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4163    fn vbitselect128(&mut self, dst: VReg, c: VReg, x: VReg, y: VReg) -> ControlFlow<Done> {
4164        let c = self.state[c].get_u128();
4165        let x = self.state[x].get_u128();
4166        let y = self.state[y].get_u128();
4167        self.state[dst].set_u128((c & x) | (!c & y));
4168        ControlFlow::Continue(())
4169    }
4170
4171    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4172    fn vbitmask8x16(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4173        let a = self.state[src].get_u8x16();
4174        let mut result = 0;
4175        for item in a.iter().rev() {
4176            result <<= 1;
4177            result |= (*item >> 7) as u32;
4178        }
4179        self.state[dst].set_u32(result);
4180        ControlFlow::Continue(())
4181    }
4182
4183    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4184    fn vbitmask16x8(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4185        let a = self.state[src].get_u16x8();
4186        let mut result = 0;
4187        for item in a.iter().rev() {
4188            result <<= 1;
4189            result |= (*item >> 15) as u32;
4190        }
4191        self.state[dst].set_u32(result);
4192        ControlFlow::Continue(())
4193    }
4194
4195    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4196    fn vbitmask32x4(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4197        let a = self.state[src].get_u32x4();
4198        let mut result = 0;
4199        for item in a.iter().rev() {
4200            result <<= 1;
4201            result |= *item >> 31;
4202        }
4203        self.state[dst].set_u32(result);
4204        ControlFlow::Continue(())
4205    }
4206
4207    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4208    fn vbitmask64x2(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4209        let a = self.state[src].get_u64x2();
4210        let mut result = 0;
4211        for item in a.iter().rev() {
4212            result <<= 1;
4213            result |= (*item >> 63) as u32;
4214        }
4215        self.state[dst].set_u32(result);
4216        ControlFlow::Continue(())
4217    }
4218
4219    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4220    fn valltrue8x16(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4221        let a = self.state[src].get_u8x16();
4222        let result = a.iter().all(|a| *a != 0);
4223        self.state[dst].set_u32(u32::from(result));
4224        ControlFlow::Continue(())
4225    }
4226
4227    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4228    fn valltrue16x8(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4229        let a = self.state[src].get_u16x8();
4230        let result = a.iter().all(|a| *a != 0);
4231        self.state[dst].set_u32(u32::from(result));
4232        ControlFlow::Continue(())
4233    }
4234
4235    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4236    fn valltrue32x4(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4237        let a = self.state[src].get_u32x4();
4238        let result = a.iter().all(|a| *a != 0);
4239        self.state[dst].set_u32(u32::from(result));
4240        ControlFlow::Continue(())
4241    }
4242
4243    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4244    fn valltrue64x2(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4245        let a = self.state[src].get_u64x2();
4246        let result = a.iter().all(|a| *a != 0);
4247        self.state[dst].set_u32(u32::from(result));
4248        ControlFlow::Continue(())
4249    }
4250
4251    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4252    fn vanytrue8x16(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4253        let a = self.state[src].get_u8x16();
4254        let result = a.iter().any(|a| *a != 0);
4255        self.state[dst].set_u32(u32::from(result));
4256        ControlFlow::Continue(())
4257    }
4258
4259    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4260    fn vanytrue16x8(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4261        let a = self.state[src].get_u16x8();
4262        let result = a.iter().any(|a| *a != 0);
4263        self.state[dst].set_u32(u32::from(result));
4264        ControlFlow::Continue(())
4265    }
4266
4267    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4268    fn vanytrue32x4(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4269        let a = self.state[src].get_u32x4();
4270        let result = a.iter().any(|a| *a != 0);
4271        self.state[dst].set_u32(u32::from(result));
4272        ControlFlow::Continue(())
4273    }
4274
4275    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4276    fn vanytrue64x2(&mut self, dst: XReg, src: VReg) -> ControlFlow<Done> {
4277        let a = self.state[src].get_u64x2();
4278        let result = a.iter().any(|a| *a != 0);
4279        self.state[dst].set_u32(u32::from(result));
4280        ControlFlow::Continue(())
4281    }
4282
4283    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4284    fn vf32x4_from_i32x4_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4285        let a = self.state[src].get_i32x4();
4286        self.state[dst].set_f32x4(a.map(|i| i as f32));
4287        ControlFlow::Continue(())
4288    }
4289
4290    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4291    fn vf32x4_from_i32x4_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4292        let a = self.state[src].get_u32x4();
4293        self.state[dst].set_f32x4(a.map(|i| i as f32));
4294        ControlFlow::Continue(())
4295    }
4296
4297    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4298    fn vf64x2_from_i64x2_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4299        let a = self.state[src].get_i64x2();
4300        self.state[dst].set_f64x2(a.map(|i| i as f64));
4301        ControlFlow::Continue(())
4302    }
4303
4304    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4305    fn vf64x2_from_i64x2_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4306        let a = self.state[src].get_u64x2();
4307        self.state[dst].set_f64x2(a.map(|i| i as f64));
4308        ControlFlow::Continue(())
4309    }
4310
4311    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4312    fn vi32x4_from_f32x4_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4313        let a = self.state[src].get_f32x4();
4314        self.state[dst].set_i32x4(a.map(|f| f as i32));
4315        ControlFlow::Continue(())
4316    }
4317
4318    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4319    fn vi32x4_from_f32x4_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4320        let a = self.state[src].get_f32x4();
4321        self.state[dst].set_u32x4(a.map(|f| f as u32));
4322        ControlFlow::Continue(())
4323    }
4324
4325    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4326    fn vi64x2_from_f64x2_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4327        let a = self.state[src].get_f64x2();
4328        self.state[dst].set_i64x2(a.map(|f| f as i64));
4329        ControlFlow::Continue(())
4330    }
4331
4332    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4333    fn vi64x2_from_f64x2_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4334        let a = self.state[src].get_f64x2();
4335        self.state[dst].set_u64x2(a.map(|f| f as u64));
4336        ControlFlow::Continue(())
4337    }
4338
4339    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4340    fn vwidenlow8x16_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4341        let a = *self.state[src].get_i8x16().first_chunk().unwrap();
4342        self.state[dst].set_i16x8(a.map(|i| i.into()));
4343        ControlFlow::Continue(())
4344    }
4345
4346    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4347    fn vwidenlow8x16_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4348        let a = *self.state[src].get_u8x16().first_chunk().unwrap();
4349        self.state[dst].set_u16x8(a.map(|i| i.into()));
4350        ControlFlow::Continue(())
4351    }
4352
4353    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4354    fn vwidenlow16x8_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4355        let a = *self.state[src].get_i16x8().first_chunk().unwrap();
4356        self.state[dst].set_i32x4(a.map(|i| i.into()));
4357        ControlFlow::Continue(())
4358    }
4359
4360    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4361    fn vwidenlow16x8_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4362        let a = *self.state[src].get_u16x8().first_chunk().unwrap();
4363        self.state[dst].set_u32x4(a.map(|i| i.into()));
4364        ControlFlow::Continue(())
4365    }
4366
4367    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4368    fn vwidenlow32x4_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4369        let a = *self.state[src].get_i32x4().first_chunk().unwrap();
4370        self.state[dst].set_i64x2(a.map(|i| i.into()));
4371        ControlFlow::Continue(())
4372    }
4373
4374    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4375    fn vwidenlow32x4_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4376        let a = *self.state[src].get_u32x4().first_chunk().unwrap();
4377        self.state[dst].set_u64x2(a.map(|i| i.into()));
4378        ControlFlow::Continue(())
4379    }
4380
4381    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4382    fn vwidenhigh8x16_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4383        let a = *self.state[src].get_i8x16().last_chunk().unwrap();
4384        self.state[dst].set_i16x8(a.map(|i| i.into()));
4385        ControlFlow::Continue(())
4386    }
4387
4388    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4389    fn vwidenhigh8x16_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4390        let a = *self.state[src].get_u8x16().last_chunk().unwrap();
4391        self.state[dst].set_u16x8(a.map(|i| i.into()));
4392        ControlFlow::Continue(())
4393    }
4394
4395    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4396    fn vwidenhigh16x8_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4397        let a = *self.state[src].get_i16x8().last_chunk().unwrap();
4398        self.state[dst].set_i32x4(a.map(|i| i.into()));
4399        ControlFlow::Continue(())
4400    }
4401
4402    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4403    fn vwidenhigh16x8_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4404        let a = *self.state[src].get_u16x8().last_chunk().unwrap();
4405        self.state[dst].set_u32x4(a.map(|i| i.into()));
4406        ControlFlow::Continue(())
4407    }
4408
4409    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4410    fn vwidenhigh32x4_s(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4411        let a = *self.state[src].get_i32x4().last_chunk().unwrap();
4412        self.state[dst].set_i64x2(a.map(|i| i.into()));
4413        ControlFlow::Continue(())
4414    }
4415
4416    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4417    fn vwidenhigh32x4_u(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4418        let a = *self.state[src].get_u32x4().last_chunk().unwrap();
4419        self.state[dst].set_u64x2(a.map(|i| i.into()));
4420        ControlFlow::Continue(())
4421    }
4422
4423    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4424    fn vnarrow16x8_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4425        let a = self.state[operands.src1].get_i16x8();
4426        let b = self.state[operands.src2].get_i16x8();
4427        let mut result = [0; 16];
4428        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4429            *d = (*i)
4430                .try_into()
4431                .unwrap_or(if *i < 0 { i8::MIN } else { i8::MAX });
4432        }
4433        self.state[operands.dst].set_i8x16(result);
4434        ControlFlow::Continue(())
4435    }
4436
4437    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4438    fn vnarrow16x8_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4439        let a = self.state[operands.src1].get_i16x8();
4440        let b = self.state[operands.src2].get_i16x8();
4441        let mut result = [0; 16];
4442        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4443            *d = (*i)
4444                .try_into()
4445                .unwrap_or(if *i < 0 { u8::MIN } else { u8::MAX });
4446        }
4447        self.state[operands.dst].set_u8x16(result);
4448        ControlFlow::Continue(())
4449    }
4450
4451    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4452    fn vnarrow32x4_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4453        let a = self.state[operands.src1].get_i32x4();
4454        let b = self.state[operands.src2].get_i32x4();
4455        let mut result = [0; 8];
4456        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4457            *d = (*i)
4458                .try_into()
4459                .unwrap_or(if *i < 0 { i16::MIN } else { i16::MAX });
4460        }
4461        self.state[operands.dst].set_i16x8(result);
4462        ControlFlow::Continue(())
4463    }
4464
4465    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4466    fn vnarrow32x4_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4467        let a = self.state[operands.src1].get_i32x4();
4468        let b = self.state[operands.src2].get_i32x4();
4469        let mut result = [0; 8];
4470        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4471            *d = (*i)
4472                .try_into()
4473                .unwrap_or(if *i < 0 { u16::MIN } else { u16::MAX });
4474        }
4475        self.state[operands.dst].set_u16x8(result);
4476        ControlFlow::Continue(())
4477    }
4478
4479    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4480    fn vnarrow64x2_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4481        let a = self.state[operands.src1].get_i64x2();
4482        let b = self.state[operands.src2].get_i64x2();
4483        let mut result = [0; 4];
4484        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4485            *d = (*i)
4486                .try_into()
4487                .unwrap_or(if *i < 0 { i32::MIN } else { i32::MAX });
4488        }
4489        self.state[operands.dst].set_i32x4(result);
4490        ControlFlow::Continue(())
4491    }
4492
4493    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4494    fn vnarrow64x2_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4495        let a = self.state[operands.src1].get_i64x2();
4496        let b = self.state[operands.src2].get_i64x2();
4497        let mut result = [0; 4];
4498        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4499            *d = (*i)
4500                .try_into()
4501                .unwrap_or(if *i < 0 { u32::MIN } else { u32::MAX });
4502        }
4503        self.state[operands.dst].set_u32x4(result);
4504        ControlFlow::Continue(())
4505    }
4506
4507    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4508    fn vunarrow64x2_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4509        let a = self.state[operands.src1].get_u64x2();
4510        let b = self.state[operands.src2].get_u64x2();
4511        let mut result = [0; 4];
4512        for (i, d) in a.iter().chain(&b).zip(&mut result) {
4513            *d = (*i).try_into().unwrap_or(u32::MAX);
4514        }
4515        self.state[operands.dst].set_u32x4(result);
4516        ControlFlow::Continue(())
4517    }
4518
4519    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4520    fn vfpromotelow(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4521        let a = self.state[src].get_f32x4();
4522        self.state[dst].set_f64x2([a[0].into(), a[1].into()]);
4523        ControlFlow::Continue(())
4524    }
4525
4526    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4527    fn vfdemote(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4528        let a = self.state[src].get_f64x2();
4529        self.state[dst].set_f32x4([a[0] as f32, a[1] as f32, 0.0, 0.0]);
4530        ControlFlow::Continue(())
4531    }
4532
4533    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4534    fn vsubi8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4535        let mut a = self.state[operands.src1].get_i8x16();
4536        let b = self.state[operands.src2].get_i8x16();
4537        for (a, b) in a.iter_mut().zip(b) {
4538            *a = a.wrapping_sub(b);
4539        }
4540        self.state[operands.dst].set_i8x16(a);
4541        ControlFlow::Continue(())
4542    }
4543
4544    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4545    fn vsubi16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4546        let mut a = self.state[operands.src1].get_i16x8();
4547        let b = self.state[operands.src2].get_i16x8();
4548        for (a, b) in a.iter_mut().zip(b) {
4549            *a = a.wrapping_sub(b);
4550        }
4551        self.state[operands.dst].set_i16x8(a);
4552        ControlFlow::Continue(())
4553    }
4554
4555    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4556    fn vsubi32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4557        let mut a = self.state[operands.src1].get_i32x4();
4558        let b = self.state[operands.src2].get_i32x4();
4559        for (a, b) in a.iter_mut().zip(b) {
4560            *a = a.wrapping_sub(b);
4561        }
4562        self.state[operands.dst].set_i32x4(a);
4563        ControlFlow::Continue(())
4564    }
4565
4566    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4567    fn vsubi64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4568        let mut a = self.state[operands.src1].get_i64x2();
4569        let b = self.state[operands.src2].get_i64x2();
4570        for (a, b) in a.iter_mut().zip(b) {
4571            *a = a.wrapping_sub(b);
4572        }
4573        self.state[operands.dst].set_i64x2(a);
4574        ControlFlow::Continue(())
4575    }
4576
4577    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4578    fn vsubi8x16_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4579        let mut a = self.state[operands.src1].get_i8x16();
4580        let b = self.state[operands.src2].get_i8x16();
4581        for (a, b) in a.iter_mut().zip(b) {
4582            *a = a.saturating_sub(b);
4583        }
4584        self.state[operands.dst].set_i8x16(a);
4585        ControlFlow::Continue(())
4586    }
4587
4588    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4589    fn vsubu8x16_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4590        let mut a = self.state[operands.src1].get_u8x16();
4591        let b = self.state[operands.src2].get_u8x16();
4592        for (a, b) in a.iter_mut().zip(b) {
4593            *a = a.saturating_sub(b);
4594        }
4595        self.state[operands.dst].set_u8x16(a);
4596        ControlFlow::Continue(())
4597    }
4598
4599    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4600    fn vsubi16x8_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4601        let mut a = self.state[operands.src1].get_i16x8();
4602        let b = self.state[operands.src2].get_i16x8();
4603        for (a, b) in a.iter_mut().zip(b) {
4604            *a = a.saturating_sub(b);
4605        }
4606        self.state[operands.dst].set_i16x8(a);
4607        ControlFlow::Continue(())
4608    }
4609
4610    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4611    fn vsubu16x8_sat(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4612        let mut a = self.state[operands.src1].get_u16x8();
4613        let b = self.state[operands.src2].get_u16x8();
4614        for (a, b) in a.iter_mut().zip(b) {
4615            *a = a.saturating_sub(b);
4616        }
4617        self.state[operands.dst].set_u16x8(a);
4618        ControlFlow::Continue(())
4619    }
4620
4621    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4622    fn vsubf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4623        let mut a = self.state[operands.src1].get_f64x2();
4624        let b = self.state[operands.src2].get_f64x2();
4625        for (a, b) in a.iter_mut().zip(b) {
4626            *a = *a - b;
4627        }
4628        self.state[operands.dst].set_f64x2(a);
4629        ControlFlow::Continue(())
4630    }
4631
4632    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4633    fn vmuli8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4634        let mut a = self.state[operands.src1].get_i8x16();
4635        let b = self.state[operands.src2].get_i8x16();
4636        for (a, b) in a.iter_mut().zip(b) {
4637            *a = a.wrapping_mul(b);
4638        }
4639        self.state[operands.dst].set_i8x16(a);
4640        ControlFlow::Continue(())
4641    }
4642
4643    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4644    fn vmuli16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4645        let mut a = self.state[operands.src1].get_i16x8();
4646        let b = self.state[operands.src2].get_i16x8();
4647        for (a, b) in a.iter_mut().zip(b) {
4648            *a = a.wrapping_mul(b);
4649        }
4650        self.state[operands.dst].set_i16x8(a);
4651        ControlFlow::Continue(())
4652    }
4653
4654    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4655    fn vmuli32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4656        let mut a = self.state[operands.src1].get_i32x4();
4657        let b = self.state[operands.src2].get_i32x4();
4658        for (a, b) in a.iter_mut().zip(b) {
4659            *a = a.wrapping_mul(b);
4660        }
4661        self.state[operands.dst].set_i32x4(a);
4662        ControlFlow::Continue(())
4663    }
4664
4665    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4666    fn vmuli64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4667        let mut a = self.state[operands.src1].get_i64x2();
4668        let b = self.state[operands.src2].get_i64x2();
4669        for (a, b) in a.iter_mut().zip(b) {
4670            *a = a.wrapping_mul(b);
4671        }
4672        self.state[operands.dst].set_i64x2(a);
4673        ControlFlow::Continue(())
4674    }
4675
4676    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4677    fn vmulf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4678        let mut a = self.state[operands.src1].get_f64x2();
4679        let b = self.state[operands.src2].get_f64x2();
4680        for (a, b) in a.iter_mut().zip(b) {
4681            *a = *a * b;
4682        }
4683        self.state[operands.dst].set_f64x2(a);
4684        ControlFlow::Continue(())
4685    }
4686
4687    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4688    fn vqmulrsi16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4689        let mut a = self.state[operands.src1].get_i16x8();
4690        let b = self.state[operands.src2].get_i16x8();
4691        const MIN: i32 = i16::MIN as i32;
4692        const MAX: i32 = i16::MAX as i32;
4693        for (a, b) in a.iter_mut().zip(b) {
4694            let r = (i32::from(*a) * i32::from(b) + (1 << 14)) >> 15;
4695            *a = r.clamp(MIN, MAX) as i16;
4696        }
4697        self.state[operands.dst].set_i16x8(a);
4698        ControlFlow::Continue(())
4699    }
4700
4701    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4702    fn vpopcnt8x16(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
4703        let a = self.state[src].get_u8x16();
4704        self.state[dst].set_u8x16(a.map(|i| i.count_ones() as u8));
4705        ControlFlow::Continue(())
4706    }
4707
4708    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4709    fn xextractv8x16(&mut self, dst: XReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4710        let a = unsafe { *self.state[src].get_u8x16().get_unchecked(usize::from(lane)) };
4711        self.state[dst].set_u32(u32::from(a));
4712        ControlFlow::Continue(())
4713    }
4714
4715    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4716    fn xextractv16x8(&mut self, dst: XReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4717        let a = unsafe { *self.state[src].get_u16x8().get_unchecked(usize::from(lane)) };
4718        self.state[dst].set_u32(u32::from(a));
4719        ControlFlow::Continue(())
4720    }
4721
4722    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4723    fn xextractv32x4(&mut self, dst: XReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4724        let a = unsafe { *self.state[src].get_u32x4().get_unchecked(usize::from(lane)) };
4725        self.state[dst].set_u32(a);
4726        ControlFlow::Continue(())
4727    }
4728
4729    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4730    fn xextractv64x2(&mut self, dst: XReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4731        let a = unsafe { *self.state[src].get_u64x2().get_unchecked(usize::from(lane)) };
4732        self.state[dst].set_u64(a);
4733        ControlFlow::Continue(())
4734    }
4735
4736    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4737    fn fextractv32x4(&mut self, dst: FReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4738        let a = unsafe { *self.state[src].get_f32x4().get_unchecked(usize::from(lane)) };
4739        self.state[dst].set_f32(a);
4740        ControlFlow::Continue(())
4741    }
4742
4743    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4744    fn fextractv64x2(&mut self, dst: FReg, src: VReg, lane: u8) -> ControlFlow<Done> {
4745        let a = unsafe { *self.state[src].get_f64x2().get_unchecked(usize::from(lane)) };
4746        self.state[dst].set_f64(a);
4747        ControlFlow::Continue(())
4748    }
4749
4750    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4751    fn vinsertx8(
4752        &mut self,
4753        operands: BinaryOperands<VReg, VReg, XReg>,
4754        lane: u8,
4755    ) -> ControlFlow<Done> {
4756        let mut a = self.state[operands.src1].get_u8x16();
4757        let b = self.state[operands.src2].get_u32() as u8;
4758        unsafe {
4759            *a.get_unchecked_mut(usize::from(lane)) = b;
4760        }
4761        self.state[operands.dst].set_u8x16(a);
4762        ControlFlow::Continue(())
4763    }
4764
4765    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4766    fn vinsertx16(
4767        &mut self,
4768        operands: BinaryOperands<VReg, VReg, XReg>,
4769        lane: u8,
4770    ) -> ControlFlow<Done> {
4771        let mut a = self.state[operands.src1].get_u16x8();
4772        let b = self.state[operands.src2].get_u32() as u16;
4773        unsafe {
4774            *a.get_unchecked_mut(usize::from(lane)) = b;
4775        }
4776        self.state[operands.dst].set_u16x8(a);
4777        ControlFlow::Continue(())
4778    }
4779
4780    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4781    fn vinsertx32(
4782        &mut self,
4783        operands: BinaryOperands<VReg, VReg, XReg>,
4784        lane: u8,
4785    ) -> ControlFlow<Done> {
4786        let mut a = self.state[operands.src1].get_u32x4();
4787        let b = self.state[operands.src2].get_u32();
4788        unsafe {
4789            *a.get_unchecked_mut(usize::from(lane)) = b;
4790        }
4791        self.state[operands.dst].set_u32x4(a);
4792        ControlFlow::Continue(())
4793    }
4794
4795    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4796    fn vinsertx64(
4797        &mut self,
4798        operands: BinaryOperands<VReg, VReg, XReg>,
4799        lane: u8,
4800    ) -> ControlFlow<Done> {
4801        let mut a = self.state[operands.src1].get_u64x2();
4802        let b = self.state[operands.src2].get_u64();
4803        unsafe {
4804            *a.get_unchecked_mut(usize::from(lane)) = b;
4805        }
4806        self.state[operands.dst].set_u64x2(a);
4807        ControlFlow::Continue(())
4808    }
4809
4810    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4811    fn vinsertf32(
4812        &mut self,
4813        operands: BinaryOperands<VReg, VReg, FReg>,
4814        lane: u8,
4815    ) -> ControlFlow<Done> {
4816        let mut a = self.state[operands.src1].get_f32x4();
4817        let b = self.state[operands.src2].get_f32();
4818        unsafe {
4819            *a.get_unchecked_mut(usize::from(lane)) = b;
4820        }
4821        self.state[operands.dst].set_f32x4(a);
4822        ControlFlow::Continue(())
4823    }
4824
4825    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4826    fn vinsertf64(
4827        &mut self,
4828        operands: BinaryOperands<VReg, VReg, FReg>,
4829        lane: u8,
4830    ) -> ControlFlow<Done> {
4831        let mut a = self.state[operands.src1].get_f64x2();
4832        let b = self.state[operands.src2].get_f64();
4833        unsafe {
4834            *a.get_unchecked_mut(usize::from(lane)) = b;
4835        }
4836        self.state[operands.dst].set_f64x2(a);
4837        ControlFlow::Continue(())
4838    }
4839
4840    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4841    fn veq8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4842        let a = self.state[operands.src1].get_u8x16();
4843        let b = self.state[operands.src2].get_u8x16();
4844        let mut c = [0; 16];
4845        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4846            *c = if a == b { u8::MAX } else { 0 };
4847        }
4848        self.state[operands.dst].set_u8x16(c);
4849        ControlFlow::Continue(())
4850    }
4851
4852    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4853    fn vneq8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4854        let a = self.state[operands.src1].get_u8x16();
4855        let b = self.state[operands.src2].get_u8x16();
4856        let mut c = [0; 16];
4857        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4858            *c = if a != b { u8::MAX } else { 0 };
4859        }
4860        self.state[operands.dst].set_u8x16(c);
4861        ControlFlow::Continue(())
4862    }
4863
4864    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4865    fn vslt8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4866        let a = self.state[operands.src1].get_i8x16();
4867        let b = self.state[operands.src2].get_i8x16();
4868        let mut c = [0; 16];
4869        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4870            *c = if a < b { u8::MAX } else { 0 };
4871        }
4872        self.state[operands.dst].set_u8x16(c);
4873        ControlFlow::Continue(())
4874    }
4875
4876    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4877    fn vslteq8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4878        let a = self.state[operands.src1].get_i8x16();
4879        let b = self.state[operands.src2].get_i8x16();
4880        let mut c = [0; 16];
4881        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4882            *c = if a <= b { u8::MAX } else { 0 };
4883        }
4884        self.state[operands.dst].set_u8x16(c);
4885        ControlFlow::Continue(())
4886    }
4887
4888    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4889    fn vult8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4890        let a = self.state[operands.src1].get_u8x16();
4891        let b = self.state[operands.src2].get_u8x16();
4892        let mut c = [0; 16];
4893        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4894            *c = if a < b { u8::MAX } else { 0 };
4895        }
4896        self.state[operands.dst].set_u8x16(c);
4897        ControlFlow::Continue(())
4898    }
4899
4900    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4901    fn vulteq8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4902        let a = self.state[operands.src1].get_u8x16();
4903        let b = self.state[operands.src2].get_u8x16();
4904        let mut c = [0; 16];
4905        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4906            *c = if a <= b { u8::MAX } else { 0 };
4907        }
4908        self.state[operands.dst].set_u8x16(c);
4909        ControlFlow::Continue(())
4910    }
4911
4912    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4913    fn veq16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4914        let a = self.state[operands.src1].get_u16x8();
4915        let b = self.state[operands.src2].get_u16x8();
4916        let mut c = [0; 8];
4917        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4918            *c = if a == b { u16::MAX } else { 0 };
4919        }
4920        self.state[operands.dst].set_u16x8(c);
4921        ControlFlow::Continue(())
4922    }
4923
4924    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4925    fn vneq16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4926        let a = self.state[operands.src1].get_u16x8();
4927        let b = self.state[operands.src2].get_u16x8();
4928        let mut c = [0; 8];
4929        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4930            *c = if a != b { u16::MAX } else { 0 };
4931        }
4932        self.state[operands.dst].set_u16x8(c);
4933        ControlFlow::Continue(())
4934    }
4935
4936    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4937    fn vslt16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4938        let a = self.state[operands.src1].get_i16x8();
4939        let b = self.state[operands.src2].get_i16x8();
4940        let mut c = [0; 8];
4941        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4942            *c = if a < b { u16::MAX } else { 0 };
4943        }
4944        self.state[operands.dst].set_u16x8(c);
4945        ControlFlow::Continue(())
4946    }
4947
4948    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4949    fn vslteq16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4950        let a = self.state[operands.src1].get_i16x8();
4951        let b = self.state[operands.src2].get_i16x8();
4952        let mut c = [0; 8];
4953        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4954            *c = if a <= b { u16::MAX } else { 0 };
4955        }
4956        self.state[operands.dst].set_u16x8(c);
4957        ControlFlow::Continue(())
4958    }
4959
4960    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4961    fn vult16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4962        let a = self.state[operands.src1].get_u16x8();
4963        let b = self.state[operands.src2].get_u16x8();
4964        let mut c = [0; 8];
4965        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4966            *c = if a < b { u16::MAX } else { 0 };
4967        }
4968        self.state[operands.dst].set_u16x8(c);
4969        ControlFlow::Continue(())
4970    }
4971
4972    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4973    fn vulteq16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4974        let a = self.state[operands.src1].get_u16x8();
4975        let b = self.state[operands.src2].get_u16x8();
4976        let mut c = [0; 8];
4977        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4978            *c = if a <= b { u16::MAX } else { 0 };
4979        }
4980        self.state[operands.dst].set_u16x8(c);
4981        ControlFlow::Continue(())
4982    }
4983
4984    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4985    fn veq32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4986        let a = self.state[operands.src1].get_u32x4();
4987        let b = self.state[operands.src2].get_u32x4();
4988        let mut c = [0; 4];
4989        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
4990            *c = if a == b { u32::MAX } else { 0 };
4991        }
4992        self.state[operands.dst].set_u32x4(c);
4993        ControlFlow::Continue(())
4994    }
4995
4996    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
4997    fn vneq32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
4998        let a = self.state[operands.src1].get_u32x4();
4999        let b = self.state[operands.src2].get_u32x4();
5000        let mut c = [0; 4];
5001        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5002            *c = if a != b { u32::MAX } else { 0 };
5003        }
5004        self.state[operands.dst].set_u32x4(c);
5005        ControlFlow::Continue(())
5006    }
5007
5008    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5009    fn vslt32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5010        let a = self.state[operands.src1].get_i32x4();
5011        let b = self.state[operands.src2].get_i32x4();
5012        let mut c = [0; 4];
5013        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5014            *c = if a < b { u32::MAX } else { 0 };
5015        }
5016        self.state[operands.dst].set_u32x4(c);
5017        ControlFlow::Continue(())
5018    }
5019
5020    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5021    fn vslteq32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5022        let a = self.state[operands.src1].get_i32x4();
5023        let b = self.state[operands.src2].get_i32x4();
5024        let mut c = [0; 4];
5025        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5026            *c = if a <= b { u32::MAX } else { 0 };
5027        }
5028        self.state[operands.dst].set_u32x4(c);
5029        ControlFlow::Continue(())
5030    }
5031
5032    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5033    fn vult32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5034        let a = self.state[operands.src1].get_u32x4();
5035        let b = self.state[operands.src2].get_u32x4();
5036        let mut c = [0; 4];
5037        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5038            *c = if a < b { u32::MAX } else { 0 };
5039        }
5040        self.state[operands.dst].set_u32x4(c);
5041        ControlFlow::Continue(())
5042    }
5043
5044    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5045    fn vulteq32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5046        let a = self.state[operands.src1].get_u32x4();
5047        let b = self.state[operands.src2].get_u32x4();
5048        let mut c = [0; 4];
5049        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5050            *c = if a <= b { u32::MAX } else { 0 };
5051        }
5052        self.state[operands.dst].set_u32x4(c);
5053        ControlFlow::Continue(())
5054    }
5055
5056    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5057    fn veq64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5058        let a = self.state[operands.src1].get_u64x2();
5059        let b = self.state[operands.src2].get_u64x2();
5060        let mut c = [0; 2];
5061        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5062            *c = if a == b { u64::MAX } else { 0 };
5063        }
5064        self.state[operands.dst].set_u64x2(c);
5065        ControlFlow::Continue(())
5066    }
5067
5068    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5069    fn vneq64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5070        let a = self.state[operands.src1].get_u64x2();
5071        let b = self.state[operands.src2].get_u64x2();
5072        let mut c = [0; 2];
5073        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5074            *c = if a != b { u64::MAX } else { 0 };
5075        }
5076        self.state[operands.dst].set_u64x2(c);
5077        ControlFlow::Continue(())
5078    }
5079
5080    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5081    fn vslt64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5082        let a = self.state[operands.src1].get_i64x2();
5083        let b = self.state[operands.src2].get_i64x2();
5084        let mut c = [0; 2];
5085        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5086            *c = if a < b { u64::MAX } else { 0 };
5087        }
5088        self.state[operands.dst].set_u64x2(c);
5089        ControlFlow::Continue(())
5090    }
5091
5092    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5093    fn vslteq64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5094        let a = self.state[operands.src1].get_i64x2();
5095        let b = self.state[operands.src2].get_i64x2();
5096        let mut c = [0; 2];
5097        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5098            *c = if a <= b { u64::MAX } else { 0 };
5099        }
5100        self.state[operands.dst].set_u64x2(c);
5101        ControlFlow::Continue(())
5102    }
5103
5104    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5105    fn vult64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5106        let a = self.state[operands.src1].get_u64x2();
5107        let b = self.state[operands.src2].get_u64x2();
5108        let mut c = [0; 2];
5109        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5110            *c = if a < b { u64::MAX } else { 0 };
5111        }
5112        self.state[operands.dst].set_u64x2(c);
5113        ControlFlow::Continue(())
5114    }
5115
5116    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5117    fn vulteq64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5118        let a = self.state[operands.src1].get_u64x2();
5119        let b = self.state[operands.src2].get_u64x2();
5120        let mut c = [0; 2];
5121        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5122            *c = if a <= b { u64::MAX } else { 0 };
5123        }
5124        self.state[operands.dst].set_u64x2(c);
5125        ControlFlow::Continue(())
5126    }
5127
5128    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5129    fn vneg8x16(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5130        let a = self.state[src].get_i8x16();
5131        self.state[dst].set_i8x16(a.map(|i| i.wrapping_neg()));
5132        ControlFlow::Continue(())
5133    }
5134
5135    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5136    fn vneg16x8(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5137        let a = self.state[src].get_i16x8();
5138        self.state[dst].set_i16x8(a.map(|i| i.wrapping_neg()));
5139        ControlFlow::Continue(())
5140    }
5141
5142    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5143    fn vneg32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5144        let a = self.state[src].get_i32x4();
5145        self.state[dst].set_i32x4(a.map(|i| i.wrapping_neg()));
5146        ControlFlow::Continue(())
5147    }
5148
5149    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5150    fn vneg64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5151        let a = self.state[src].get_i64x2();
5152        self.state[dst].set_i64x2(a.map(|i| i.wrapping_neg()));
5153        ControlFlow::Continue(())
5154    }
5155
5156    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5157    fn vnegf64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5158        let a = self.state[src].get_f64x2();
5159        self.state[dst].set_f64x2(a.map(|i| -i));
5160        ControlFlow::Continue(())
5161    }
5162
5163    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5164    fn vmin8x16_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5165        let mut a = self.state[operands.src1].get_i8x16();
5166        let b = self.state[operands.src2].get_i8x16();
5167        for (a, b) in a.iter_mut().zip(&b) {
5168            *a = (*a).min(*b);
5169        }
5170        self.state[operands.dst].set_i8x16(a);
5171        ControlFlow::Continue(())
5172    }
5173
5174    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5175    fn vmin8x16_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5176        let mut a = self.state[operands.src1].get_u8x16();
5177        let b = self.state[operands.src2].get_u8x16();
5178        for (a, b) in a.iter_mut().zip(&b) {
5179            *a = (*a).min(*b);
5180        }
5181        self.state[operands.dst].set_u8x16(a);
5182        ControlFlow::Continue(())
5183    }
5184
5185    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5186    fn vmin16x8_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5187        let mut a = self.state[operands.src1].get_i16x8();
5188        let b = self.state[operands.src2].get_i16x8();
5189        for (a, b) in a.iter_mut().zip(&b) {
5190            *a = (*a).min(*b);
5191        }
5192        self.state[operands.dst].set_i16x8(a);
5193        ControlFlow::Continue(())
5194    }
5195
5196    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5197    fn vmin16x8_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5198        let mut a = self.state[operands.src1].get_u16x8();
5199        let b = self.state[operands.src2].get_u16x8();
5200        for (a, b) in a.iter_mut().zip(&b) {
5201            *a = (*a).min(*b);
5202        }
5203        self.state[operands.dst].set_u16x8(a);
5204        ControlFlow::Continue(())
5205    }
5206
5207    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5208    fn vmin32x4_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5209        let mut a = self.state[operands.src1].get_i32x4();
5210        let b = self.state[operands.src2].get_i32x4();
5211        for (a, b) in a.iter_mut().zip(&b) {
5212            *a = (*a).min(*b);
5213        }
5214        self.state[operands.dst].set_i32x4(a);
5215        ControlFlow::Continue(())
5216    }
5217
5218    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5219    fn vmin32x4_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5220        let mut a = self.state[operands.src1].get_u32x4();
5221        let b = self.state[operands.src2].get_u32x4();
5222        for (a, b) in a.iter_mut().zip(&b) {
5223            *a = (*a).min(*b);
5224        }
5225        self.state[operands.dst].set_u32x4(a);
5226        ControlFlow::Continue(())
5227    }
5228
5229    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5230    fn vmax8x16_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5231        let mut a = self.state[operands.src1].get_i8x16();
5232        let b = self.state[operands.src2].get_i8x16();
5233        for (a, b) in a.iter_mut().zip(&b) {
5234            *a = (*a).max(*b);
5235        }
5236        self.state[operands.dst].set_i8x16(a);
5237        ControlFlow::Continue(())
5238    }
5239
5240    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5241    fn vmax8x16_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5242        let mut a = self.state[operands.src1].get_u8x16();
5243        let b = self.state[operands.src2].get_u8x16();
5244        for (a, b) in a.iter_mut().zip(&b) {
5245            *a = (*a).max(*b);
5246        }
5247        self.state[operands.dst].set_u8x16(a);
5248        ControlFlow::Continue(())
5249    }
5250
5251    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5252    fn vmax16x8_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5253        let mut a = self.state[operands.src1].get_i16x8();
5254        let b = self.state[operands.src2].get_i16x8();
5255        for (a, b) in a.iter_mut().zip(&b) {
5256            *a = (*a).max(*b);
5257        }
5258        self.state[operands.dst].set_i16x8(a);
5259        ControlFlow::Continue(())
5260    }
5261
5262    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5263    fn vmax16x8_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5264        let mut a = self.state[operands.src1].get_u16x8();
5265        let b = self.state[operands.src2].get_u16x8();
5266        for (a, b) in a.iter_mut().zip(&b) {
5267            *a = (*a).max(*b);
5268        }
5269        self.state[operands.dst].set_u16x8(a);
5270        ControlFlow::Continue(())
5271    }
5272
5273    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5274    fn vmax32x4_s(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5275        let mut a = self.state[operands.src1].get_i32x4();
5276        let b = self.state[operands.src2].get_i32x4();
5277        for (a, b) in a.iter_mut().zip(&b) {
5278            *a = (*a).max(*b);
5279        }
5280        self.state[operands.dst].set_i32x4(a);
5281        ControlFlow::Continue(())
5282    }
5283
5284    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5285    fn vmax32x4_u(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5286        let mut a = self.state[operands.src1].get_u32x4();
5287        let b = self.state[operands.src2].get_u32x4();
5288        for (a, b) in a.iter_mut().zip(&b) {
5289            *a = (*a).max(*b);
5290        }
5291        self.state[operands.dst].set_u32x4(a);
5292        ControlFlow::Continue(())
5293    }
5294
5295    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5296    fn vabs8x16(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5297        let a = self.state[src].get_i8x16();
5298        self.state[dst].set_i8x16(a.map(|i| i.wrapping_abs()));
5299        ControlFlow::Continue(())
5300    }
5301
5302    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5303    fn vabs16x8(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5304        let a = self.state[src].get_i16x8();
5305        self.state[dst].set_i16x8(a.map(|i| i.wrapping_abs()));
5306        ControlFlow::Continue(())
5307    }
5308
5309    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5310    fn vabs32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5311        let a = self.state[src].get_i32x4();
5312        self.state[dst].set_i32x4(a.map(|i| i.wrapping_abs()));
5313        ControlFlow::Continue(())
5314    }
5315
5316    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5317    fn vabs64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5318        let a = self.state[src].get_i64x2();
5319        self.state[dst].set_i64x2(a.map(|i| i.wrapping_abs()));
5320        ControlFlow::Continue(())
5321    }
5322
5323    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5324    fn vabsf32x4(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5325        let a = self.state[src].get_f32x4();
5326        self.state[dst].set_f32x4(a.map(|i| i.wasm_abs()));
5327        ControlFlow::Continue(())
5328    }
5329
5330    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5331    fn vabsf64x2(&mut self, dst: VReg, src: VReg) -> ControlFlow<Done> {
5332        let a = self.state[src].get_f64x2();
5333        self.state[dst].set_f64x2(a.map(|i| i.wasm_abs()));
5334        ControlFlow::Continue(())
5335    }
5336
5337    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5338    fn vmaximumf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5339        let mut a = self.state[operands.src1].get_f32x4();
5340        let b = self.state[operands.src2].get_f32x4();
5341        for (a, b) in a.iter_mut().zip(&b) {
5342            *a = a.wasm_maximum(*b);
5343        }
5344        self.state[operands.dst].set_f32x4(a);
5345        ControlFlow::Continue(())
5346    }
5347
5348    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5349    fn vmaximumf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5350        let mut a = self.state[operands.src1].get_f64x2();
5351        let b = self.state[operands.src2].get_f64x2();
5352        for (a, b) in a.iter_mut().zip(&b) {
5353            *a = a.wasm_maximum(*b);
5354        }
5355        self.state[operands.dst].set_f64x2(a);
5356        ControlFlow::Continue(())
5357    }
5358
5359    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5360    fn vminimumf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5361        let mut a = self.state[operands.src1].get_f32x4();
5362        let b = self.state[operands.src2].get_f32x4();
5363        for (a, b) in a.iter_mut().zip(&b) {
5364            *a = a.wasm_minimum(*b);
5365        }
5366        self.state[operands.dst].set_f32x4(a);
5367        ControlFlow::Continue(())
5368    }
5369
5370    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5371    fn vminimumf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5372        let mut a = self.state[operands.src1].get_f64x2();
5373        let b = self.state[operands.src2].get_f64x2();
5374        for (a, b) in a.iter_mut().zip(&b) {
5375            *a = a.wasm_minimum(*b);
5376        }
5377        self.state[operands.dst].set_f64x2(a);
5378        ControlFlow::Continue(())
5379    }
5380
5381    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5382    fn vshuffle(&mut self, dst: VReg, src1: VReg, src2: VReg, mask: u128) -> ControlFlow<Done> {
5383        let a = self.state[src1].get_u8x16();
5384        let b = self.state[src2].get_u8x16();
5385        let result = mask.to_le_bytes().map(|m| {
5386            if m < 16 {
5387                a[m as usize]
5388            } else {
5389                b[m as usize - 16]
5390            }
5391        });
5392        self.state[dst].set_u8x16(result);
5393        ControlFlow::Continue(())
5394    }
5395
5396    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5397    fn vswizzlei8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5398        let src1 = self.state[operands.src1].get_i8x16();
5399        let src2 = self.state[operands.src2].get_i8x16();
5400        let mut dst = [0i8; 16];
5401        for (i, &idx) in src2.iter().enumerate() {
5402            if (idx as usize) < 16 {
5403                dst[i] = src1[idx as usize];
5404            } else {
5405                dst[i] = 0
5406            }
5407        }
5408        self.state[operands.dst].set_i8x16(dst);
5409        ControlFlow::Continue(())
5410    }
5411
5412    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5413    fn vavground8x16(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5414        let mut a = self.state[operands.src1].get_u8x16();
5415        let b = self.state[operands.src2].get_u8x16();
5416        for (a, b) in a.iter_mut().zip(&b) {
5417            // use wider precision to avoid overflow
5418            *a = ((u32::from(*a) + u32::from(*b) + 1) / 2) as u8;
5419        }
5420        self.state[operands.dst].set_u8x16(a);
5421        ControlFlow::Continue(())
5422    }
5423
5424    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5425    fn vavground16x8(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5426        let mut a = self.state[operands.src1].get_u16x8();
5427        let b = self.state[operands.src2].get_u16x8();
5428        for (a, b) in a.iter_mut().zip(&b) {
5429            // use wider precision to avoid overflow
5430            *a = ((u32::from(*a) + u32::from(*b) + 1) / 2) as u16;
5431        }
5432        self.state[operands.dst].set_u16x8(a);
5433        ControlFlow::Continue(())
5434    }
5435
5436    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5437    fn veqf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5438        let a = self.state[operands.src1].get_f32x4();
5439        let b = self.state[operands.src2].get_f32x4();
5440        let mut c = [0; 4];
5441        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5442            *c = if a == b { u32::MAX } else { 0 };
5443        }
5444        self.state[operands.dst].set_u32x4(c);
5445        ControlFlow::Continue(())
5446    }
5447
5448    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5449    fn vneqf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5450        let a = self.state[operands.src1].get_f32x4();
5451        let b = self.state[operands.src2].get_f32x4();
5452        let mut c = [0; 4];
5453        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5454            *c = if a != b { u32::MAX } else { 0 };
5455        }
5456        self.state[operands.dst].set_u32x4(c);
5457        ControlFlow::Continue(())
5458    }
5459
5460    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5461    fn vltf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5462        let a = self.state[operands.src1].get_f32x4();
5463        let b = self.state[operands.src2].get_f32x4();
5464        let mut c = [0; 4];
5465        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5466            *c = if a < b { u32::MAX } else { 0 };
5467        }
5468        self.state[operands.dst].set_u32x4(c);
5469        ControlFlow::Continue(())
5470    }
5471
5472    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5473    fn vlteqf32x4(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5474        let a = self.state[operands.src1].get_f32x4();
5475        let b = self.state[operands.src2].get_f32x4();
5476        let mut c = [0; 4];
5477        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5478            *c = if a <= b { u32::MAX } else { 0 };
5479        }
5480        self.state[operands.dst].set_u32x4(c);
5481        ControlFlow::Continue(())
5482    }
5483
5484    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5485    fn veqf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5486        let a = self.state[operands.src1].get_f64x2();
5487        let b = self.state[operands.src2].get_f64x2();
5488        let mut c = [0; 2];
5489        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5490            *c = if a == b { u64::MAX } else { 0 };
5491        }
5492        self.state[operands.dst].set_u64x2(c);
5493        ControlFlow::Continue(())
5494    }
5495
5496    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5497    fn vneqf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5498        let a = self.state[operands.src1].get_f64x2();
5499        let b = self.state[operands.src2].get_f64x2();
5500        let mut c = [0; 2];
5501        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5502            *c = if a != b { u64::MAX } else { 0 };
5503        }
5504        self.state[operands.dst].set_u64x2(c);
5505        ControlFlow::Continue(())
5506    }
5507
5508    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5509    fn vltf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5510        let a = self.state[operands.src1].get_f64x2();
5511        let b = self.state[operands.src2].get_f64x2();
5512        let mut c = [0; 2];
5513        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5514            *c = if a < b { u64::MAX } else { 0 };
5515        }
5516        self.state[operands.dst].set_u64x2(c);
5517        ControlFlow::Continue(())
5518    }
5519
5520    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5521    fn vlteqf64x2(&mut self, operands: BinaryOperands<VReg>) -> ControlFlow<Done> {
5522        let a = self.state[operands.src1].get_f64x2();
5523        let b = self.state[operands.src2].get_f64x2();
5524        let mut c = [0; 2];
5525        for ((a, b), c) in a.iter().zip(&b).zip(&mut c) {
5526            *c = if a <= b { u64::MAX } else { 0 };
5527        }
5528        self.state[operands.dst].set_u64x2(c);
5529        ControlFlow::Continue(())
5530    }
5531
5532    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5533    fn vfma32x4(&mut self, dst: VReg, a: VReg, b: VReg, c: VReg) -> ControlFlow<Done> {
5534        let mut a = self.state[a].get_f32x4();
5535        let b = self.state[b].get_f32x4();
5536        let c = self.state[c].get_f32x4();
5537        for ((a, b), c) in a.iter_mut().zip(b).zip(c) {
5538            *a = a.wasm_mul_add(b, c);
5539        }
5540        self.state[dst].set_f32x4(a);
5541        ControlFlow::Continue(())
5542    }
5543
5544    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5545    fn vfma64x2(&mut self, dst: VReg, a: VReg, b: VReg, c: VReg) -> ControlFlow<Done> {
5546        let mut a = self.state[a].get_f64x2();
5547        let b = self.state[b].get_f64x2();
5548        let c = self.state[c].get_f64x2();
5549        for ((a, b), c) in a.iter_mut().zip(b).zip(c) {
5550            *a = a.wasm_mul_add(b, c);
5551        }
5552        self.state[dst].set_f64x2(a);
5553        ControlFlow::Continue(())
5554    }
5555
5556    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5557    fn vselect(
5558        &mut self,
5559        dst: VReg,
5560        cond: XReg,
5561        if_nonzero: VReg,
5562        if_zero: VReg,
5563    ) -> ControlFlow<Done> {
5564        let result = if self.state[cond].get_u32() != 0 {
5565            self.state[if_nonzero]
5566        } else {
5567            self.state[if_zero]
5568        };
5569        self.state[dst] = result;
5570        ControlFlow::Continue(())
5571    }
5572
5573    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5574    fn xadd128(
5575        &mut self,
5576        dst_lo: XReg,
5577        dst_hi: XReg,
5578        lhs_lo: XReg,
5579        lhs_hi: XReg,
5580        rhs_lo: XReg,
5581        rhs_hi: XReg,
5582    ) -> ControlFlow<Done> {
5583        let lhs = self.get_i128(lhs_lo, lhs_hi);
5584        let rhs = self.get_i128(rhs_lo, rhs_hi);
5585        let result = lhs.wrapping_add(rhs);
5586        self.set_i128(dst_lo, dst_hi, result);
5587        ControlFlow::Continue(())
5588    }
5589
5590    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5591    fn xsub128(
5592        &mut self,
5593        dst_lo: XReg,
5594        dst_hi: XReg,
5595        lhs_lo: XReg,
5596        lhs_hi: XReg,
5597        rhs_lo: XReg,
5598        rhs_hi: XReg,
5599    ) -> ControlFlow<Done> {
5600        let lhs = self.get_i128(lhs_lo, lhs_hi);
5601        let rhs = self.get_i128(rhs_lo, rhs_hi);
5602        let result = lhs.wrapping_sub(rhs);
5603        self.set_i128(dst_lo, dst_hi, result);
5604        ControlFlow::Continue(())
5605    }
5606
5607    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5608    fn xwidemul64_s(
5609        &mut self,
5610        dst_lo: XReg,
5611        dst_hi: XReg,
5612        lhs: XReg,
5613        rhs: XReg,
5614    ) -> ControlFlow<Done> {
5615        let lhs = self.state[lhs].get_i64();
5616        let rhs = self.state[rhs].get_i64();
5617        let result = i128::from(lhs).wrapping_mul(i128::from(rhs));
5618        self.set_i128(dst_lo, dst_hi, result);
5619        ControlFlow::Continue(())
5620    }
5621
5622    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5623    fn xwidemul64_u(
5624        &mut self,
5625        dst_lo: XReg,
5626        dst_hi: XReg,
5627        lhs: XReg,
5628        rhs: XReg,
5629    ) -> ControlFlow<Done> {
5630        let lhs = self.state[lhs].get_u64();
5631        let rhs = self.state[rhs].get_u64();
5632        let result = u128::from(lhs).wrapping_mul(u128::from(rhs));
5633        self.set_i128(dst_lo, dst_hi, result as i128);
5634        ControlFlow::Continue(())
5635    }
5636
5637    // =========================================================================
5638    // z addressing modes (big endian)
5639
5640    fn xload16be_u32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
5641        let result = unsafe { self.load_ne::<u16, crate::XLoad16BeU32Z>(addr)? };
5642        self.state[dst].set_u32(u16::from_be(result).into());
5643        ControlFlow::Continue(())
5644    }
5645
5646    fn xload16be_s32_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
5647        let result = unsafe { self.load_ne::<i16, crate::XLoad16BeS32Z>(addr)? };
5648        self.state[dst].set_i32(i16::from_be(result).into());
5649        ControlFlow::Continue(())
5650    }
5651
5652    fn xload32be_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
5653        let result = unsafe { self.load_ne::<i32, crate::XLoad32BeZ>(addr)? };
5654        self.state[dst].set_i32(i32::from_be(result));
5655        ControlFlow::Continue(())
5656    }
5657
5658    fn xload64be_z(&mut self, dst: XReg, addr: AddrZ) -> ControlFlow<Done> {
5659        let result = unsafe { self.load_ne::<i64, crate::XLoad64BeZ>(addr)? };
5660        self.state[dst].set_i64(i64::from_be(result));
5661        ControlFlow::Continue(())
5662    }
5663
5664    fn xstore16be_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
5665        let val = self.state[val].get_u32() as u16;
5666        unsafe {
5667            self.store_ne::<u16, crate::XStore16BeZ>(addr, val.to_be())?;
5668        }
5669        ControlFlow::Continue(())
5670    }
5671
5672    fn xstore32be_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
5673        let val = self.state[val].get_u32();
5674        unsafe {
5675            self.store_ne::<u32, crate::XStore32BeZ>(addr, val.to_be())?;
5676        }
5677        ControlFlow::Continue(())
5678    }
5679
5680    fn xstore64be_z(&mut self, addr: AddrZ, val: XReg) -> ControlFlow<Done> {
5681        let val = self.state[val].get_u64();
5682        unsafe {
5683            self.store_ne::<u64, crate::XStore64BeZ>(addr, val.to_be())?;
5684        }
5685        ControlFlow::Continue(())
5686    }
5687
5688    fn fload32be_z(&mut self, dst: FReg, addr: AddrZ) -> ControlFlow<Done> {
5689        let val = unsafe { self.load_ne::<u32, crate::Fload32BeZ>(addr)? };
5690        self.state[dst].set_f32(f32::from_bits(u32::from_be(val)));
5691        ControlFlow::Continue(())
5692    }
5693
5694    fn fload64be_z(&mut self, dst: FReg, addr: AddrZ) -> ControlFlow<Done> {
5695        let val = unsafe { self.load_ne::<u64, crate::Fload64BeZ>(addr)? };
5696        self.state[dst].set_f64(f64::from_bits(u64::from_be(val)));
5697        ControlFlow::Continue(())
5698    }
5699
5700    fn fstore32be_z(&mut self, addr: AddrZ, src: FReg) -> ControlFlow<Done> {
5701        let val = self.state[src].get_f32();
5702        unsafe {
5703            self.store_ne::<u32, crate::Fstore32BeZ>(addr, val.to_bits().to_be())?;
5704        }
5705        ControlFlow::Continue(())
5706    }
5707
5708    fn fstore64be_z(&mut self, addr: AddrZ, src: FReg) -> ControlFlow<Done> {
5709        let val = self.state[src].get_f64();
5710        unsafe {
5711            self.store_ne::<u64, crate::Fstore64BeZ>(addr, val.to_bits().to_be())?;
5712        }
5713        ControlFlow::Continue(())
5714    }
5715
5716    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5717    fn vload128be_z(&mut self, dst: VReg, addr: AddrZ) -> ControlFlow<Done> {
5718        let val = unsafe { self.load_ne::<u128, crate::VLoad128BeZ>(addr)? };
5719        self.state[dst].set_u128(u128::from_be(val));
5720        ControlFlow::Continue(())
5721    }
5722
5723    #[interp_disable_if_cfg(pulley_disable_interp_simd)]
5724    fn vstore128be_z(&mut self, addr: AddrZ, src: VReg) -> ControlFlow<Done> {
5725        let val = self.state[src].get_u128();
5726        unsafe {
5727            self.store_ne::<u128, crate::Vstore128BeZ>(addr, val.to_be())?;
5728        }
5729        ControlFlow::Continue(())
5730    }
5731}