xref: /wasmtime-44.0.1/pulley/src/lib.rs (revision bacc2dc3)
1 //! The pulley bytecode for fast interpreters.
2 
3 #![cfg_attr(docsrs, feature(doc_cfg))]
4 #![cfg_attr(pulley_tail_calls, feature(explicit_tail_calls))]
5 #![cfg_attr(pulley_tail_calls, allow(incomplete_features, unstable_features))]
6 #![deny(missing_docs)]
7 #![no_std]
8 
9 #[cfg(feature = "std")]
10 #[macro_use]
11 extern crate std;
12 
13 #[cfg(feature = "decode")]
14 extern crate alloc;
15 
16 /// Calls the given macro with each opcode.
17 ///
18 /// # Instruction Guidelines
19 ///
20 /// We're inventing an instruction set here which naturally brings a whole set
21 /// of design questions. Note that this is explicitly intended to be only ever
22 /// used for Pulley where there are a different set of design constraints than
23 /// other instruction sets (e.g. general-purpose CPU ISAs). Some examples of
24 /// constraints for Pulley are:
25 ///
26 /// * Instructions must be portable to many architectures.
27 /// * The Pulley ISA is mostly target-independent as the compilation target is
28 ///   currently only parameterized on pointer width and endianness.
29 /// * Pulley instructions should be balance of time-to-decode and code size. For
30 ///   example super fancy bit-packing tricks might be tough to decode in
31 ///   software but might be worthwhile if it's quite common and greatly reduces
32 ///   the size of bytecode. There's not a hard-and-fast answer here, but a
33 ///   balance to be made.
34 /// * Many "macro ops" are present to reduce the size of compiled bytecode so
35 ///   there is a wide set of duplicate functionality between opcodes (and this
36 ///   is expected).
37 ///
38 /// Given all this it's also useful to have a set of guidelines used to name and
39 /// develop Pulley instructions. As of the time of this writing it's still
40 /// pretty early days for Pulley so some of these guidelines may change over
41 /// time. Additionally instructions don't necessarily all follow these
42 /// conventions and that may also change over time. With that in mind, here's a
43 /// rough set of guidelines:
44 ///
45 /// * Most instructions are prefixed with `x`, `f`, or `v`, indicating which
46 ///   type of register they're operating on. (e.g. `xadd32` operates on the `x`
47 ///   integer registers and `fadd32` operates on the `f` float registers).
48 ///
49 /// * Most instructions are suffixed or otherwise contain the bit width they're
50 ///   operating on. For example `xadd32` is a 32-bit addition.
51 ///
52 /// * If an instruction operates on signed or unsigned data (such as division
53 ///   and remainder), then the instruction is suffixed with `_s` or `_u`.
54 ///
55 /// * Instructions operate on either 32 or 64-bit parts of a register.
56 ///   Instructions modifying only 32-bits of a register always modify the "low"
57 ///   part of a register and leave the upper part unmodified. This is intended
58 ///   to help 32-bit platforms where if most operations are 32-bit there's no
59 ///   need for extra instructions to sign or zero extend and modify the upper
60 ///   half of the register.
61 ///
62 /// * Binops use `BinaryOperands<T>` for the destination and argument registers.
63 ///
64 /// * Instructions operating on memory contain a few pieces of information:
65 ///
66 ///   ```text
67 ///   xload16le_u32_o32
68 ///   │└─┬┘└┤└┤ └┬┘ └┬┘
69 ///   │  │  │ │  │   ▼
70 ///   │  │  │ │  │   addressing mode
71 ///   │  │  │ │  ▼
72 ///   │  │  │ │  width of register modified + sign-extension (optional)
73 ///   │  │  │ ▼
74 ///   │  │  │ endianness of the operation (le/be)
75 ///   │  │  ▼
76 ///   │  │  bit-width of the operation
77 ///   │  ▼
78 ///   │  what's happening (load/store)
79 ///   ▼
80 ///   register being operated on (x/f/z)
81 ///   ```
82 ///
83 /// More guidelines might get added here over time, and if you have any
84 /// questions feel free to raise them and we can try to add them here as well!
85 #[macro_export]
86 macro_rules! for_each_op {
87     ( $macro:ident ) => {
88         $macro! {
89             /// Transfer control the address in the `lr` register.
90             ret = Ret;
91 
92             /// Transfer control to the PC at the given offset and set the `lr`
93             /// register to the PC just after this instruction.
94             ///
95             /// This instruction generally assumes that the Pulley ABI is being
96             /// respected where arguments are in argument registers (starting at
97             /// x0 for integer arguments) and results are in result registers.
98             /// This instruction itself assume that all arguments are already in
99             /// their registers. Subsequent instructions below enable moving
100             /// arguments into the correct registers as part of the same call
101             /// instruction.
102             call = Call { offset: PcRelOffset };
103             /// Like `call`, but also `x0 = arg1`
104             call1 = Call1 { arg1: XReg, offset: PcRelOffset };
105             /// Like `call`, but also `x0, x1 = arg1, arg2`
106             call2 = Call2 { arg1: XReg, arg2: XReg, offset: PcRelOffset };
107             /// Like `call`, but also `x0, x1, x2 = arg1, arg2, arg3`
108             call3 = Call3 { arg1: XReg, arg2: XReg, arg3: XReg, offset: PcRelOffset };
109             /// Like `call`, but also `x0, x1, x2, x3 = arg1, arg2, arg3, arg4`
110             call4 = Call4 { arg1: XReg, arg2: XReg, arg3: XReg, arg4: XReg, offset: PcRelOffset };
111 
112             /// Transfer control to the PC in `reg` and set `lr` to the PC just
113             /// after this instruction.
114             call_indirect = CallIndirect { reg: XReg };
115 
116             /// Unconditionally transfer control to the PC at the given offset.
117             jump = Jump { offset: PcRelOffset };
118 
119             /// Unconditionally transfer control to the PC at specified
120             /// register.
121             xjump = XJump { reg: XReg };
122 
123             /// Conditionally transfer control to the given PC offset if
124             /// `low32(cond)` contains a non-zero value.
125             br_if32 = BrIf { cond: XReg, offset: PcRelOffset };
126 
127             /// Conditionally transfer control to the given PC offset if
128             /// `low32(cond)` contains a zero value.
129             br_if_not32 = BrIfNot { cond: XReg, offset: PcRelOffset };
130 
131             /// Branch if `a == b`.
132             br_if_xeq32 = BrIfXeq32 { a: XReg, b: XReg, offset: PcRelOffset };
133             /// Branch if `a != `b.
134             br_if_xneq32 = BrIfXneq32 { a: XReg, b: XReg, offset: PcRelOffset };
135             /// Branch if signed `a < b`.
136             br_if_xslt32 = BrIfXslt32 { a: XReg, b: XReg, offset: PcRelOffset };
137             /// Branch if signed `a <= b`.
138             br_if_xslteq32 = BrIfXslteq32 { a: XReg, b: XReg, offset: PcRelOffset };
139             /// Branch if unsigned `a < b`.
140             br_if_xult32 = BrIfXult32 { a: XReg, b: XReg, offset: PcRelOffset };
141             /// Branch if unsigned `a <= b`.
142             br_if_xulteq32 = BrIfXulteq32 { a: XReg, b: XReg, offset: PcRelOffset };
143             /// Branch if `a == b`.
144             br_if_xeq64 = BrIfXeq64 { a: XReg, b: XReg, offset: PcRelOffset };
145             /// Branch if `a != `b.
146             br_if_xneq64 = BrIfXneq64 { a: XReg, b: XReg, offset: PcRelOffset };
147             /// Branch if signed `a < b`.
148             br_if_xslt64 = BrIfXslt64 { a: XReg, b: XReg, offset: PcRelOffset };
149             /// Branch if signed `a <= b`.
150             br_if_xslteq64 = BrIfXslteq64 { a: XReg, b: XReg, offset: PcRelOffset };
151             /// Branch if unsigned `a < b`.
152             br_if_xult64 = BrIfXult64 { a: XReg, b: XReg, offset: PcRelOffset };
153             /// Branch if unsigned `a <= b`.
154             br_if_xulteq64 = BrIfXulteq64 { a: XReg, b: XReg, offset: PcRelOffset };
155 
156             /// Branch if `a == b`.
157             br_if_xeq32_i8 = BrIfXeq32I8 { a: XReg, b: i8, offset: PcRelOffset };
158             /// Branch if `a == b`.
159             br_if_xeq32_i32 = BrIfXeq32I32 { a: XReg, b: i32, offset: PcRelOffset };
160             /// Branch if `a != `b.
161             br_if_xneq32_i8 = BrIfXneq32I8 { a: XReg, b: i8, offset: PcRelOffset };
162             /// Branch if `a != `b.
163             br_if_xneq32_i32 = BrIfXneq32I32 { a: XReg, b: i32, offset: PcRelOffset };
164             /// Branch if signed `a < b`.
165             br_if_xslt32_i8 = BrIfXslt32I8 { a: XReg, b: i8, offset: PcRelOffset };
166             /// Branch if signed `a < b`.
167             br_if_xslt32_i32 = BrIfXslt32I32 { a: XReg, b: i32, offset: PcRelOffset };
168             /// Branch if signed `a > b`.
169             br_if_xsgt32_i8 = BrIfXsgt32I8 { a: XReg, b: i8, offset: PcRelOffset };
170             /// Branch if signed `a > b`.
171             br_if_xsgt32_i32 = BrIfXsgt32I32 { a: XReg, b: i32, offset: PcRelOffset };
172             /// Branch if signed `a <= b`.
173             br_if_xslteq32_i8 = BrIfXslteq32I8 { a: XReg, b: i8, offset: PcRelOffset };
174             /// Branch if signed `a <= b`.
175             br_if_xslteq32_i32 = BrIfXslteq32I32 { a: XReg, b: i32, offset: PcRelOffset };
176             /// Branch if signed `a >= b`.
177             br_if_xsgteq32_i8 = BrIfXsgteq32I8 { a: XReg, b: i8, offset: PcRelOffset };
178             /// Branch if signed `a >= b`.
179             br_if_xsgteq32_i32 = BrIfXsgteq32I32 { a: XReg, b: i32, offset: PcRelOffset };
180             /// Branch if unsigned `a < b`.
181             br_if_xult32_u8 = BrIfXult32U8 { a: XReg, b: u8, offset: PcRelOffset };
182             /// Branch if unsigned `a < b`.
183             br_if_xult32_u32 = BrIfXult32U32 { a: XReg, b: u32, offset: PcRelOffset };
184             /// Branch if unsigned `a <= b`.
185             br_if_xulteq32_u8 = BrIfXulteq32U8 { a: XReg, b: u8, offset: PcRelOffset };
186             /// Branch if unsigned `a <= b`.
187             br_if_xulteq32_u32 = BrIfXulteq32U32 { a: XReg, b: u32, offset: PcRelOffset };
188             /// Branch if unsigned `a > b`.
189             br_if_xugt32_u8 = BrIfXugt32U8 { a: XReg, b: u8, offset: PcRelOffset };
190             /// Branch if unsigned `a > b`.
191             br_if_xugt32_u32 = BrIfXugt32U32 { a: XReg, b: u32, offset: PcRelOffset };
192             /// Branch if unsigned `a >= b`.
193             br_if_xugteq32_u8 = BrIfXugteq32U8 { a: XReg, b: u8, offset: PcRelOffset };
194             /// Branch if unsigned `a >= b`.
195             br_if_xugteq32_u32 = BrIfXugteq32U32 { a: XReg, b: u32, offset: PcRelOffset };
196 
197             /// Branch if `a == b`.
198             br_if_xeq64_i8 = BrIfXeq64I8 { a: XReg, b: i8, offset: PcRelOffset };
199             /// Branch if `a == b`.
200             br_if_xeq64_i32 = BrIfXeq64I32 { a: XReg, b: i32, offset: PcRelOffset };
201             /// Branch if `a != `b.
202             br_if_xneq64_i8 = BrIfXneq64I8 { a: XReg, b: i8, offset: PcRelOffset };
203             /// Branch if `a != `b.
204             br_if_xneq64_i32 = BrIfXneq64I32 { a: XReg, b: i32, offset: PcRelOffset };
205             /// Branch if signed `a < b`.
206             br_if_xslt64_i8 = BrIfXslt64I8 { a: XReg, b: i8, offset: PcRelOffset };
207             /// Branch if signed `a < b`.
208             br_if_xslt64_i32 = BrIfXslt64I32 { a: XReg, b: i32, offset: PcRelOffset };
209             /// Branch if signed `a > b`.
210             br_if_xsgt64_i8 = BrIfXsgt64I8 { a: XReg, b: i8, offset: PcRelOffset };
211             /// Branch if signed `a > b`.
212             br_if_xsgt64_i32 = BrIfXsgt64I32 { a: XReg, b: i32, offset: PcRelOffset };
213             /// Branch if signed `a <= b`.
214             br_if_xslteq64_i8 = BrIfXslteq64I8 { a: XReg, b: i8, offset: PcRelOffset };
215             /// Branch if signed `a <= b`.
216             br_if_xslteq64_i32 = BrIfXslteq64I32 { a: XReg, b: i32, offset: PcRelOffset };
217             /// Branch if signed `a >= b`.
218             br_if_xsgteq64_i8 = BrIfXsgteq64I8 { a: XReg, b: i8, offset: PcRelOffset };
219             /// Branch if signed `a >= b`.
220             br_if_xsgteq64_i32 = BrIfXsgteq64I32 { a: XReg, b: i32, offset: PcRelOffset };
221             /// Branch if unsigned `a < b`.
222             br_if_xult64_u8 = BrIfXult64U8 { a: XReg, b: u8, offset: PcRelOffset };
223             /// Branch if unsigned `a < b`.
224             br_if_xult64_u32 = BrIfXult64U32 { a: XReg, b: u32, offset: PcRelOffset };
225             /// Branch if unsigned `a <= b`.
226             br_if_xulteq64_u8 = BrIfXulteq64U8 { a: XReg, b: u8, offset: PcRelOffset };
227             /// Branch if unsigned `a <= b`.
228             br_if_xulteq64_u32 = BrIfXulteq64U32 { a: XReg, b: u32, offset: PcRelOffset };
229             /// Branch if unsigned `a > b`.
230             br_if_xugt64_u8 = BrIfXugt64U8 { a: XReg, b: u8, offset: PcRelOffset };
231             /// Branch if unsigned `a > b`.
232             br_if_xugt64_u32 = BrIfXugt64U32 { a: XReg, b: u32, offset: PcRelOffset };
233             /// Branch if unsigned `a >= b`.
234             br_if_xugteq64_u8 = BrIfXugteq64U8 { a: XReg, b: u8, offset: PcRelOffset };
235             /// Branch if unsigned `a >= b`.
236             br_if_xugteq64_u32 = BrIfXugteq64U32 { a: XReg, b: u32, offset: PcRelOffset };
237 
238             /// Branch to the label indicated by `low32(idx)`.
239             ///
240             /// After this instruction are `amt` instances of `PcRelOffset`
241             /// and the `idx` selects which one will be branched to. The value
242             /// of `idx` is clamped to `amt - 1` (e.g. the last offset is the
243             /// "default" one.
244             br_table32 = BrTable32 { idx: XReg, amt: u32 };
245 
246             /// Move between `x` registers.
247             xmov = Xmov { dst: XReg, src: XReg };
248 
249             /// Set `dst = 0`
250             xzero = Xzero { dst: XReg };
251             /// Set `dst = 1`
252             xone = Xone { dst: XReg };
253             /// Set `dst = sign_extend(imm8)`.
254             xconst8 = Xconst8 { dst: XReg, imm: i8 };
255             /// Set `dst = sign_extend(imm16)`.
256             xconst16 = Xconst16 { dst: XReg, imm: i16 };
257             /// Set `dst = sign_extend(imm32)`.
258             xconst32 = Xconst32 { dst: XReg, imm: i32 };
259             /// Set `dst = imm64`.
260             xconst64 = Xconst64 { dst: XReg, imm: i64 };
261 
262             /// 32-bit wrapping addition: `low32(dst) = low32(src1) + low32(src2)`.
263             ///
264             /// The upper 32-bits of `dst` are unmodified.
265             xadd32 = Xadd32 { operands: BinaryOperands<XReg> };
266             /// Same as `xadd32` but `src2` is a zero-extended 8-bit immediate.
267             xadd32_u8 = Xadd32U8 { dst: XReg, src1: XReg, src2: u8 };
268             /// Same as `xadd32` but `src2` is a 32-bit immediate.
269             xadd32_u32 = Xadd32U32 { dst: XReg, src1: XReg, src2: u32 };
270 
271             /// 64-bit wrapping addition: `dst = src1 + src2`.
272             xadd64 = Xadd64 { operands: BinaryOperands<XReg> };
273             /// Same as `xadd64` but `src2` is a zero-extended 8-bit immediate.
274             xadd64_u8 = Xadd64U8 { dst: XReg, src1: XReg, src2: u8 };
275             /// Same as `xadd64` but `src2` is a zero-extended 32-bit immediate.
276             xadd64_u32 = Xadd64U32 { dst: XReg, src1: XReg, src2: u32 };
277 
278             /// `low32(dst) = low32(src1) * low32(src2) + low32(src3)`
279             xmadd32 = Xmadd32 { dst: XReg, src1: XReg, src2: XReg, src3: XReg };
280             /// `dst = src1 * src2 + src3`
281             xmadd64 = Xmadd64 { dst: XReg, src1: XReg, src2: XReg, src3: XReg };
282 
283             /// 32-bit wrapping subtraction: `low32(dst) = low32(src1) - low32(src2)`.
284             ///
285             /// The upper 32-bits of `dst` are unmodified.
286             xsub32 = Xsub32 { operands: BinaryOperands<XReg> };
287             /// Same as `xsub32` but `src2` is a zero-extended 8-bit immediate.
288             xsub32_u8 = Xsub32U8 { dst: XReg, src1: XReg, src2: u8 };
289             /// Same as `xsub32` but `src2` is a 32-bit immediate.
290             xsub32_u32 = Xsub32U32 { dst: XReg, src1: XReg, src2: u32 };
291 
292             /// 64-bit wrapping subtraction: `dst = src1 - src2`.
293             xsub64 = Xsub64 { operands: BinaryOperands<XReg> };
294             /// Same as `xsub64` but `src2` is a zero-extended 8-bit immediate.
295             xsub64_u8 = Xsub64U8 { dst: XReg, src1: XReg, src2: u8 };
296             /// Same as `xsub64` but `src2` is a zero-extended 32-bit immediate.
297             xsub64_u32 = Xsub64U32 { dst: XReg, src1: XReg, src2: u32 };
298 
299             /// `low32(dst) = low32(src1) * low32(src2)`
300             xmul32 = XMul32 { operands: BinaryOperands<XReg> };
301             /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate.
302             xmul32_s8 = Xmul32S8 { dst: XReg, src1: XReg, src2: i8 };
303             /// Same as `xmul32` but `src2` is a sign-extended 32-bit immediate.
304             xmul32_s32 = Xmul32S32 { dst: XReg, src1: XReg, src2: i32 };
305 
306             /// `dst = src1 * src2`
307             xmul64 = XMul64 { operands: BinaryOperands<XReg> };
308             /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate.
309             xmul64_s8 = Xmul64S8 { dst: XReg, src1: XReg, src2: i8 };
310             /// Same as `xmul64` but `src2` is a sign-extended 64-bit immediate.
311             xmul64_s32 = Xmul64S32 { dst: XReg, src1: XReg, src2: i32 };
312 
313             /// `low32(dst) = trailing_zeros(low32(src))`
314             xctz32 = Xctz32 { dst: XReg, src: XReg };
315             /// `dst = trailing_zeros(src)`
316             xctz64 = Xctz64 { dst: XReg, src: XReg };
317 
318             /// `low32(dst) = leading_zeros(low32(src))`
319             xclz32 = Xclz32 { dst: XReg, src: XReg };
320             /// `dst = leading_zeros(src)`
321             xclz64 = Xclz64 { dst: XReg, src: XReg };
322 
323             /// `low32(dst) = count_ones(low32(src))`
324             xpopcnt32 = Xpopcnt32 { dst: XReg, src: XReg };
325             /// `dst = count_ones(src)`
326             xpopcnt64 = Xpopcnt64 { dst: XReg, src: XReg };
327 
328             /// `low32(dst) = rotate_left(low32(src1), low32(src2))`
329             xrotl32 = Xrotl32 { operands: BinaryOperands<XReg> };
330             /// `dst = rotate_left(src1, src2)`
331             xrotl64 = Xrotl64 { operands: BinaryOperands<XReg> };
332 
333             /// `low32(dst) = rotate_right(low32(src1), low32(src2))`
334             xrotr32 = Xrotr32 { operands: BinaryOperands<XReg> };
335             /// `dst = rotate_right(src1, src2)`
336             xrotr64 = Xrotr64 { operands: BinaryOperands<XReg> };
337 
338             /// `low32(dst) = low32(src1) << low5(src2)`
339             xshl32 = Xshl32 { operands: BinaryOperands<XReg> };
340             /// `low32(dst) = low32(src1) >> low5(src2)`
341             xshr32_s = Xshr32S { operands: BinaryOperands<XReg> };
342             /// `low32(dst) = low32(src1) >> low5(src2)`
343             xshr32_u = Xshr32U { operands: BinaryOperands<XReg> };
344             /// `dst = src1 << low5(src2)`
345             xshl64 = Xshl64 { operands: BinaryOperands<XReg> };
346             /// `dst = src1 >> low6(src2)`
347             xshr64_s = Xshr64S { operands: BinaryOperands<XReg> };
348             /// `dst = src1 >> low6(src2)`
349             xshr64_u = Xshr64U { operands: BinaryOperands<XReg> };
350 
351             /// `low32(dst) = low32(src1) << low5(src2)`
352             xshl32_u6 = Xshl32U6 { operands: BinaryOperands<XReg, XReg, U6> };
353             /// `low32(dst) = low32(src1) >> low5(src2)`
354             xshr32_s_u6 = Xshr32SU6 { operands: BinaryOperands<XReg, XReg, U6> };
355             /// `low32(dst) = low32(src1) >> low5(src2)`
356             xshr32_u_u6 = Xshr32UU6 { operands: BinaryOperands<XReg, XReg, U6> };
357             /// `dst = src1 << low5(src2)`
358             xshl64_u6 = Xshl64U6 { operands: BinaryOperands<XReg, XReg, U6> };
359             /// `dst = src1 >> low6(src2)`
360             xshr64_s_u6 = Xshr64SU6 { operands: BinaryOperands<XReg, XReg, U6> };
361             /// `dst = src1 >> low6(src2)`
362             xshr64_u_u6 = Xshr64UU6 { operands: BinaryOperands<XReg, XReg, U6> };
363 
364             /// `low32(dst) = -low32(src)`
365             xneg32 = Xneg32 { dst: XReg, src: XReg };
366             /// `dst = -src`
367             xneg64 = Xneg64 { dst: XReg, src: XReg };
368 
369             /// `low32(dst) = src1 == src2`
370             xeq64 = Xeq64 { operands: BinaryOperands<XReg> };
371             /// `low32(dst) = src1 != src2`
372             xneq64 = Xneq64 { operands: BinaryOperands<XReg> };
373             /// `low32(dst) = src1 < src2` (signed)
374             xslt64 = Xslt64 { operands: BinaryOperands<XReg> };
375             /// `low32(dst) = src1 <= src2` (signed)
376             xslteq64 = Xslteq64 { operands: BinaryOperands<XReg> };
377             /// `low32(dst) = src1 < src2` (unsigned)
378             xult64 = Xult64 { operands: BinaryOperands<XReg> };
379             /// `low32(dst) = src1 <= src2` (unsigned)
380             xulteq64 = Xulteq64 { operands: BinaryOperands<XReg> };
381             /// `low32(dst) = low32(src1) == low32(src2)`
382             xeq32 = Xeq32 { operands: BinaryOperands<XReg> };
383             /// `low32(dst) = low32(src1) != low32(src2)`
384             xneq32 = Xneq32 { operands: BinaryOperands<XReg> };
385             /// `low32(dst) = low32(src1) < low32(src2)` (signed)
386             xslt32 = Xslt32 { operands: BinaryOperands<XReg> };
387             /// `low32(dst) = low32(src1) <= low32(src2)` (signed)
388             xslteq32 = Xslteq32 { operands: BinaryOperands<XReg> };
389             /// `low32(dst) = low32(src1) < low32(src2)` (unsigned)
390             xult32 = Xult32 { operands: BinaryOperands<XReg> };
391             /// `low32(dst) = low32(src1) <= low32(src2)` (unsigned)
392             xulteq32 = Xulteq32 { operands: BinaryOperands<XReg> };
393 
394             // Loads/stores with various addressing modes. Note that each style
395             // of addressing mode is split to its own suite of instructions to
396             // simplify the implementation of each opcode and avoid internal
397             // branching when using one addressing mode vs another.
398             //
399             // Note that big-endian, float, and vector loads are deferred to
400             // the "extended" opcode set below.
401 
402             /// `low32(dst) = zext_8_32(*addr)`
403             xload8_u32_o32 = XLoad8U32O32 { dst: XReg, addr: AddrO32 };
404             /// `low32(dst) = sext_8_32(*addr)`
405             xload8_s32_o32 = XLoad8S32O32 { dst: XReg, addr: AddrO32 };
406             /// `low32(dst) = o32ext_16_32(*addr)`
407             xload16le_u32_o32 = XLoad16LeU32O32 { dst: XReg, addr: AddrO32 };
408             /// `low32(dst) = sext_16_32(*addr)`
409             xload16le_s32_o32 = XLoad16LeS32O32 { dst: XReg, addr: AddrO32 };
410             /// `low32(dst) = *addr`
411             xload32le_o32 = XLoad32LeO32 { dst: XReg, addr: AddrO32 };
412             /// `dst = *addr`
413             xload64le_o32 = XLoad64LeO32 { dst: XReg, addr: AddrO32 };
414             /// `*addr = low8(src)`
415             xstore8_o32 = XStore8O32 { addr: AddrO32, src: XReg };
416             /// `*addr = low16(src)`
417             xstore16le_o32 = XStore16LeO32 { addr: AddrO32, src: XReg };
418             /// `*addr = low32(src)`
419             xstore32le_o32 = XStore32LeO32 { addr: AddrO32, src: XReg };
420             /// `*addr = src`
421             xstore64le_o32 = XStore64LeO32 { addr: AddrO32, src: XReg };
422 
423             /// `low32(dst) = zext_8_32(*addr)`
424             xload8_u32_z = XLoad8U32Z { dst: XReg, addr: AddrZ };
425             /// `low32(dst) = sext_8_32(*addr)`
426             xload8_s32_z = XLoad8S32Z { dst: XReg, addr: AddrZ };
427             /// `low32(dst) = zext_16_32(*addr)`
428             xload16le_u32_z = XLoad16LeU32Z { dst: XReg, addr: AddrZ };
429             /// `low32(dst) = sext_16_32(*addr)`
430             xload16le_s32_z = XLoad16LeS32Z { dst: XReg, addr: AddrZ };
431             /// `low32(dst) = *addr`
432             xload32le_z = XLoad32LeZ { dst: XReg, addr: AddrZ };
433             /// `dst = *addr`
434             xload64le_z = XLoad64LeZ { dst: XReg, addr: AddrZ };
435             /// `*addr = low8(src)`
436             xstore8_z = XStore8Z { addr: AddrZ, src: XReg };
437             /// `*addr = low16(src)`
438             xstore16le_z = XStore16LeZ { addr: AddrZ, src: XReg };
439             /// `*addr = low32(src)`
440             xstore32le_z = XStore32LeZ { addr: AddrZ, src: XReg };
441             /// `*addr = src`
442             xstore64le_z = XStore64LeZ { addr: AddrZ, src: XReg };
443 
444             /// `low32(dst) = zext_8_32(*addr)`
445             xload8_u32_g32 = XLoad8U32G32 { dst: XReg, addr: AddrG32 };
446             /// `low32(dst) = sext_8_32(*addr)`
447             xload8_s32_g32 = XLoad8S32G32 { dst: XReg, addr: AddrG32 };
448             /// `low32(dst) = zext_16_32(*addr)`
449             xload16le_u32_g32 = XLoad16LeU32G32 { dst: XReg, addr: AddrG32 };
450             /// `low32(dst) = sext_16_32(*addr)`
451             xload16le_s32_g32 = XLoad16LeS32G32 { dst: XReg, addr: AddrG32 };
452             /// `low32(dst) = *addr`
453             xload32le_g32 = XLoad32LeG32 { dst: XReg, addr: AddrG32 };
454             /// `dst = *addr`
455             xload64le_g32 = XLoad64LeG32 { dst: XReg, addr: AddrG32 };
456             /// `*addr = low8(src)`
457             xstore8_g32 = XStore8G32 { addr: AddrG32, src: XReg };
458             /// `*addr = low16(src)`
459             xstore16le_g32 = XStore16LeG32 { addr: AddrG32, src: XReg };
460             /// `*addr = low32(src)`
461             xstore32le_g32 = XStore32LeG32 { addr: AddrG32, src: XReg };
462             /// `*addr = src`
463             xstore64le_g32 = XStore64LeG32 { addr: AddrG32, src: XReg };
464 
465             /// `low32(dst) = zext_8_32(*addr)`
466             xload8_u32_g32bne = XLoad8U32G32Bne { dst: XReg, addr: AddrG32Bne };
467             /// `low32(dst) = sext_8_32(*addr)`
468             xload8_s32_g32bne = XLoad8S32G32Bne { dst: XReg, addr: AddrG32Bne };
469             /// `low32(dst) = zext_16_32(*addr)`
470             xload16le_u32_g32bne = XLoad16LeU32G32Bne { dst: XReg, addr: AddrG32Bne };
471             /// `low32(dst) = sext_16_32(*addr)`
472             xload16le_s32_g32bne = XLoad16LeS32G32Bne { dst: XReg, addr: AddrG32Bne };
473             /// `low32(dst) = *addr`
474             xload32le_g32bne = XLoad32LeG32Bne { dst: XReg, addr: AddrG32Bne };
475             /// `dst = *addr`
476             xload64le_g32bne = XLoad64LeG32Bne { dst: XReg, addr: AddrG32Bne };
477             /// `*addr = low8(src)`
478             xstore8_g32bne = XStore8G32Bne { addr: AddrG32Bne, src: XReg };
479             /// `*addr = low16(src)`
480             xstore16le_g32bne = XStore16LeG32Bne { addr: AddrG32Bne, src: XReg };
481             /// `*addr = low32(src)`
482             xstore32le_g32bne = XStore32LeG32Bne { addr: AddrG32Bne, src: XReg };
483             /// `*addr = src`
484             xstore64le_g32bne = XStore64LeG32Bne { addr: AddrG32Bne, src: XReg };
485 
486 
487             /// `push lr; push fp; fp = sp`
488             push_frame = PushFrame ;
489             /// `sp = fp; pop fp; pop lr`
490             pop_frame = PopFrame ;
491 
492             /// Macro-instruction to enter a function, allocate some stack, and
493             /// then save some registers.
494             ///
495             /// This is equivalent to `push_frame`, `stack_alloc32 amt`, then
496             /// saving all of `regs` to the top of the stack just allocated.
497             push_frame_save = PushFrameSave { amt: u16, regs: UpperRegSet<XReg> };
498             /// Inverse of `push_frame_save`. Restores `regs` from the top of
499             /// the stack, then runs `stack_free32 amt`, then runs `pop_frame`.
500             pop_frame_restore = PopFrameRestore { amt: u16, regs: UpperRegSet<XReg> };
501 
502             /// `sp = sp.checked_sub(amt)`
503             stack_alloc32 = StackAlloc32 { amt: u32 };
504 
505             /// `sp = sp + amt`
506             stack_free32 = StackFree32 { amt: u32 };
507 
508             /// `dst = zext(low8(src))`
509             zext8 = Zext8 { dst: XReg, src: XReg };
510             /// `dst = zext(low16(src))`
511             zext16 = Zext16 { dst: XReg, src: XReg };
512             /// `dst = zext(low32(src))`
513             zext32 = Zext32 { dst: XReg, src: XReg };
514             /// `dst = sext(low8(src))`
515             sext8 = Sext8 { dst: XReg, src: XReg };
516             /// `dst = sext(low16(src))`
517             sext16 = Sext16 { dst: XReg, src: XReg };
518             /// `dst = sext(low32(src))`
519             sext32 = Sext32 { dst: XReg, src: XReg };
520 
521             /// `low32(dst) = |low32(src)|`
522             xabs32 = XAbs32 { dst: XReg, src: XReg };
523             /// `dst = |src|`
524             xabs64 = XAbs64 { dst: XReg, src: XReg };
525 
526             /// `low32(dst) = low32(src1) / low32(src2)` (signed)
527             xdiv32_s = XDiv32S { operands: BinaryOperands<XReg> };
528 
529             /// `dst = src1 / src2` (signed)
530             xdiv64_s = XDiv64S { operands: BinaryOperands<XReg> };
531 
532             /// `low32(dst) = low32(src1) / low32(src2)` (unsigned)
533             xdiv32_u = XDiv32U { operands: BinaryOperands<XReg> };
534 
535             /// `dst = src1 / src2` (unsigned)
536             xdiv64_u = XDiv64U { operands: BinaryOperands<XReg> };
537 
538             /// `low32(dst) = low32(src1) % low32(src2)` (signed)
539             xrem32_s = XRem32S { operands: BinaryOperands<XReg> };
540 
541             /// `dst = src1 / src2` (signed)
542             xrem64_s = XRem64S { operands: BinaryOperands<XReg> };
543 
544             /// `low32(dst) = low32(src1) % low32(src2)` (unsigned)
545             xrem32_u = XRem32U { operands: BinaryOperands<XReg> };
546 
547             /// `dst = src1 / src2` (unsigned)
548             xrem64_u = XRem64U { operands: BinaryOperands<XReg> };
549 
550             /// `low32(dst) = low32(src1) & low32(src2)`
551             xband32 = XBand32 { operands: BinaryOperands<XReg> };
552             /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate.
553             xband32_s8 = Xband32S8 { dst: XReg, src1: XReg, src2: i8 };
554             /// Same as `xband32` but `src2` is a sign-extended 32-bit immediate.
555             xband32_s32 = Xband32S32 { dst: XReg, src1: XReg, src2: i32 };
556             /// `dst = src1 & src2`
557             xband64 = XBand64 { operands: BinaryOperands<XReg> };
558             /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate.
559             xband64_s8 = Xband64S8 { dst: XReg, src1: XReg, src2: i8 };
560             /// Same as `xband64` but `src2` is a sign-extended 32-bit immediate.
561             xband64_s32 = Xband64S32 { dst: XReg, src1: XReg, src2: i32 };
562             /// `low32(dst) = low32(src1) | low32(src2)`
563             xbor32 = XBor32 { operands: BinaryOperands<XReg> };
564             /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate.
565             xbor32_s8 = Xbor32S8 { dst: XReg, src1: XReg, src2: i8 };
566             /// Same as `xbor32` but `src2` is a sign-extended 32-bit immediate.
567             xbor32_s32 = Xbor32S32 { dst: XReg, src1: XReg, src2: i32 };
568             /// `dst = src1 | src2`
569             xbor64 = XBor64 { operands: BinaryOperands<XReg> };
570             /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate.
571             xbor64_s8 = Xbor64S8 { dst: XReg, src1: XReg, src2: i8 };
572             /// Same as `xbor64` but `src2` is a sign-extended 32-bit immediate.
573             xbor64_s32 = Xbor64S32 { dst: XReg, src1: XReg, src2: i32 };
574 
575             /// `low32(dst) = low32(src1) ^ low32(src2)`
576             xbxor32 = XBxor32 { operands: BinaryOperands<XReg> };
577             /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate.
578             xbxor32_s8 = Xbxor32S8 { dst: XReg, src1: XReg, src2: i8 };
579             /// Same as `xbxor32` but `src2` is a sign-extended 32-bit immediate.
580             xbxor32_s32 = Xbxor32S32 { dst: XReg, src1: XReg, src2: i32 };
581             /// `dst = src1 ^ src2`
582             xbxor64 = XBxor64 { operands: BinaryOperands<XReg> };
583             /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate.
584             xbxor64_s8 = Xbxor64S8 { dst: XReg, src1: XReg, src2: i8 };
585             /// Same as `xbxor64` but `src2` is a sign-extended 32-bit immediate.
586             xbxor64_s32 = Xbxor64S32 { dst: XReg, src1: XReg, src2: i32 };
587 
588             /// `low32(dst) = !low32(src1)`
589             xbnot32 = XBnot32 { dst: XReg, src: XReg };
590             /// `dst = !src1`
591             xbnot64 = XBnot64 { dst: XReg, src: XReg };
592 
593             /// `low32(dst) = min(low32(src1), low32(src2))` (unsigned)
594             xmin32_u = Xmin32U { operands: BinaryOperands<XReg> };
595             /// `low32(dst) = min(low32(src1), low32(src2))` (signed)
596             xmin32_s = Xmin32S { operands: BinaryOperands<XReg> };
597             /// `low32(dst) = max(low32(src1), low32(src2))` (unsigned)
598             xmax32_u = Xmax32U { operands: BinaryOperands<XReg> };
599             /// `low32(dst) = max(low32(src1), low32(src2))` (signed)
600             xmax32_s = Xmax32S { operands: BinaryOperands<XReg> };
601             /// `dst = min(src1, src2)` (unsigned)
602             xmin64_u = Xmin64U { operands: BinaryOperands<XReg> };
603             /// `dst = min(src1, src2)` (signed)
604             xmin64_s = Xmin64S { operands: BinaryOperands<XReg> };
605             /// `dst = max(src1, src2)` (unsigned)
606             xmax64_u = Xmax64U { operands: BinaryOperands<XReg> };
607             /// `dst = max(src1, src2)` (signed)
608             xmax64_s = Xmax64S { operands: BinaryOperands<XReg> };
609 
610             /// `low32(dst) = low32(cond) ? low32(if_nonzero) : low32(if_zero)`
611             xselect32 = XSelect32 { dst: XReg, cond: XReg, if_nonzero: XReg, if_zero: XReg };
612             /// `dst = low32(cond) ? if_nonzero : if_zero`
613             xselect64 = XSelect64 { dst: XReg, cond: XReg, if_nonzero: XReg, if_zero: XReg };
614         }
615     };
616 }
617 
618 /// Calls the given macro with each extended opcode.
619 #[macro_export]
620 macro_rules! for_each_extended_op {
621     ( $macro:ident ) => {
622         $macro! {
623             /// Raise a trap.
624             trap = Trap;
625 
626             /// Do nothing.
627             nop = Nop;
628 
629             /// A special opcode to halt interpreter execution and yield control
630             /// back to the host.
631             ///
632             /// This opcode results in `DoneReason::CallIndirectHost` where the
633             /// `id` here is shepherded along to the embedder. It's up to the
634             /// embedder to determine what to do with the `id` and the current
635             /// state of registers and the stack.
636             ///
637             /// In Wasmtime this is used to implement interpreter-to-host calls.
638             /// This is modeled as a `call` instruction where the first
639             /// parameter is the native function pointer to invoke and all
640             /// remaining parameters for the native function are in following
641             /// parameter positions (e.g. `x1`, `x2`, ...). The results of the
642             /// host call are then store in `x0`.
643             ///
644             /// Handling this in Wasmtime is done through a "relocation" which
645             /// is resolved at link-time when raw bytecode from Cranelift is
646             /// assembled into the final object that Wasmtime will interpret.
647             call_indirect_host = CallIndirectHost { id: u8 };
648 
649             /// Adds `offset` to the pc of this instruction and stores it in
650             /// `dst`.
651             xpcadd = Xpcadd { dst: XReg, offset: PcRelOffset };
652 
653             /// Gets the special "fp" register and moves it into `dst`.
654             xmov_fp = XmovFp { dst: XReg };
655 
656             /// Gets the special "lr" register and moves it into `dst`.
657             xmov_lr = XmovLr { dst: XReg };
658 
659             /// `dst = byteswap(low32(src))`
660             bswap32 = Bswap32 { dst: XReg, src: XReg };
661             /// `dst = byteswap(src)`
662             bswap64 = Bswap64 { dst: XReg, src: XReg };
663 
664             /// 32-bit checked unsigned addition: `low32(dst) = low32(src1) +
665             /// low32(src2)`.
666             ///
667             /// The upper 32-bits of `dst` are unmodified. Traps if the addition
668             /// overflows.
669             xadd32_uoverflow_trap = Xadd32UoverflowTrap { operands: BinaryOperands<XReg> };
670 
671             /// 64-bit checked unsigned addition: `dst = src1 + src2`.
672             xadd64_uoverflow_trap = Xadd64UoverflowTrap { operands: BinaryOperands<XReg> };
673 
674             /// `dst = high64(src1 * src2)` (signed)
675             xmulhi64_s = XMulHi64S { operands: BinaryOperands<XReg> };
676             /// `dst = high64(src1 * src2)` (unsigned)
677             xmulhi64_u = XMulHi64U { operands: BinaryOperands<XReg> };
678 
679             /// low32(dst) = if low32(src) == 0 { 0 } else { -1 }
680             xbmask32 = Xbmask32 { dst: XReg, src: XReg };
681             /// dst = if src == 0 { 0 } else { -1 }
682             xbmask64 = Xbmask64 { dst: XReg, src: XReg };
683 
684             // Big-endian loads/stores of X-registers using the "o32"
685             // addressing mode
686 
687             /// `low32(dst) = zext(*addr)`
688             xload16be_u32_o32 = XLoad16BeU32O32 { dst: XReg, addr: AddrO32 };
689             /// `low32(dst) = sext(*addr)`
690             xload16be_s32_o32 = XLoad16BeS32O32 { dst: XReg, addr: AddrO32 };
691             /// `low32(dst) = zext(*addr)`
692             xload32be_o32 = XLoad32BeO32 { dst: XReg, addr: AddrO32 };
693             /// `dst = *addr`
694             xload64be_o32 = XLoad64BeO32 { dst: XReg, addr: AddrO32 };
695             /// `*addr = low16(src)`
696             xstore16be_o32 = XStore16BeO32 { addr: AddrO32, src: XReg };
697             /// `*addr = low32(src)`
698             xstore32be_o32 = XStore32BeO32 { addr: AddrO32, src: XReg };
699             /// `*addr = low64(src)`
700             xstore64be_o32 = XStore64BeO32 { addr: AddrO32, src: XReg };
701 
702             // Big and little endian float loads/stores. Note that the "Z"
703             // addressing mode only has little-endian variants.
704 
705             /// `low32(dst) = zext(*addr)`
706             fload32be_o32 = Fload32BeO32 { dst: FReg, addr: AddrO32 };
707             /// `dst = *addr`
708             fload64be_o32 = Fload64BeO32 { dst: FReg, addr: AddrO32 };
709             /// `*addr = low32(src)`
710             fstore32be_o32 = Fstore32BeO32 { addr: AddrO32, src: FReg };
711             /// `*addr = src`
712             fstore64be_o32 = Fstore64BeO32 { addr: AddrO32, src: FReg };
713 
714             /// `low32(dst) = zext(*addr)`
715             fload32le_o32 = Fload32LeO32 { dst: FReg, addr: AddrO32 };
716             /// `dst = *addr`
717             fload64le_o32 = Fload64LeO32 { dst: FReg, addr: AddrO32 };
718             /// `*addr = low32(src)`
719             fstore32le_o32 = Fstore32LeO32 { addr: AddrO32, src: FReg };
720             /// `*addr = src`
721             fstore64le_o32 = Fstore64LeO32 { addr: AddrO32, src: FReg };
722 
723             /// `low32(dst) = zext(*addr)`
724             fload32le_z = Fload32LeZ { dst: FReg, addr: AddrZ };
725             /// `dst = *addr`
726             fload64le_z = Fload64LeZ { dst: FReg, addr: AddrZ };
727             /// `*addr = low32(src)`
728             fstore32le_z = Fstore32LeZ { addr: AddrZ, src: FReg };
729             /// `*addr = src`
730             fstore64le_z = Fstore64LeZ { addr: AddrZ, src: FReg };
731 
732             /// `low32(dst) = zext(*addr)`
733             fload32le_g32 = Fload32LeG32 { dst: FReg, addr: AddrG32 };
734             /// `dst = *addr`
735             fload64le_g32 = Fload64LeG32 { dst: FReg, addr: AddrG32 };
736             /// `*addr = low32(src)`
737             fstore32le_g32 = Fstore32LeG32 { addr: AddrG32, src: FReg };
738             /// `*addr = src`
739             fstore64le_g32 = Fstore64LeG32 { addr: AddrG32, src: FReg };
740 
741             // Vector loads/stores. Note that big-endian variants are all
742             // omitted.
743 
744             /// `dst = *addr`
745             vload128le_o32 = VLoad128O32 { dst: VReg, addr: AddrO32 };
746             /// `*addr = src`
747             vstore128le_o32 = Vstore128LeO32 { addr: AddrO32, src: VReg };
748             /// `dst = *(ptr + offset)`
749             vload128le_z = VLoad128Z { dst: VReg, addr: AddrZ };
750             /// `*(ptr + offset) = src`
751             vstore128le_z = Vstore128LeZ { addr: AddrZ, src: VReg };
752             /// `dst = *(ptr + offset)`
753             vload128le_g32 = VLoad128G32 { dst: VReg, addr: AddrG32 };
754             /// `*(ptr + offset) = src`
755             vstore128le_g32 = Vstore128LeG32 { addr: AddrG32, src: VReg };
756 
757             /// Move between `f` registers.
758             fmov = Fmov { dst: FReg, src: FReg };
759             /// Move between `v` registers.
760             vmov = Vmov { dst: VReg, src: VReg };
761 
762             /// `low32(dst) = bitcast low32(src) as i32`
763             bitcast_int_from_float_32 = BitcastIntFromFloat32 { dst: XReg, src: FReg };
764             /// `dst = bitcast src as i64`
765             bitcast_int_from_float_64 = BitcastIntFromFloat64 { dst: XReg, src: FReg };
766             /// `low32(dst) = bitcast low32(src) as f32`
767             bitcast_float_from_int_32 = BitcastFloatFromInt32 { dst: FReg, src: XReg };
768             /// `dst = bitcast src as f64`
769             bitcast_float_from_int_64 = BitcastFloatFromInt64 { dst: FReg, src: XReg };
770 
771             /// `low32(dst) = bits`
772             fconst32 = FConst32 { dst: FReg, bits: u32 };
773             /// `dst = bits`
774             fconst64 = FConst64 { dst: FReg, bits: u64 };
775 
776             /// `low32(dst) = zext(src1 == src2)`
777             feq32 = Feq32 { dst: XReg, src1: FReg, src2: FReg };
778             /// `low32(dst) = zext(src1 != src2)`
779             fneq32 = Fneq32 { dst: XReg, src1: FReg, src2: FReg };
780             /// `low32(dst) = zext(src1 < src2)`
781             flt32 = Flt32 { dst: XReg, src1: FReg, src2: FReg };
782             /// `low32(dst) = zext(src1 <= src2)`
783             flteq32 = Flteq32 { dst: XReg, src1: FReg, src2: FReg };
784             /// `low32(dst) = zext(src1 == src2)`
785             feq64 = Feq64 { dst: XReg, src1: FReg, src2: FReg };
786             /// `low32(dst) = zext(src1 != src2)`
787             fneq64 = Fneq64 { dst: XReg, src1: FReg, src2: FReg };
788             /// `low32(dst) = zext(src1 < src2)`
789             flt64 = Flt64 { dst: XReg, src1: FReg, src2: FReg };
790             /// `low32(dst) = zext(src1 <= src2)`
791             flteq64 = Flteq64 { dst: XReg, src1: FReg, src2: FReg };
792 
793             /// `low32(dst) = low32(cond) ? low32(if_nonzero) : low32(if_zero)`
794             fselect32 = FSelect32 { dst: FReg, cond: XReg, if_nonzero: FReg, if_zero: FReg };
795             /// `dst = low32(cond) ? if_nonzero : if_zero`
796             fselect64 = FSelect64 { dst: FReg, cond: XReg, if_nonzero: FReg, if_zero: FReg };
797 
798             /// `low32(dst) = demote(src)`
799             f32_from_f64 = F32FromF64 { dst: FReg, src: FReg };
800             /// `(st) = promote(low32(src))`
801             f64_from_f32 = F64FromF32 { dst: FReg, src: FReg };
802 
803             /// `low32(dst) = checked_f32_from_signed(low32(src))`
804             f32_from_x32_s = F32FromX32S { dst: FReg, src: XReg };
805             /// `low32(dst) = checked_f32_from_unsigned(low32(src))`
806             f32_from_x32_u = F32FromX32U { dst: FReg, src: XReg };
807             /// `low32(dst) = checked_f32_from_signed(src)`
808             f32_from_x64_s = F32FromX64S { dst: FReg, src: XReg };
809             /// `low32(dst) = checked_f32_from_unsigned(src)`
810             f32_from_x64_u = F32FromX64U { dst: FReg, src: XReg };
811             /// `dst = checked_f64_from_signed(low32(src))`
812             f64_from_x32_s = F64FromX32S { dst: FReg, src: XReg };
813             /// `dst = checked_f64_from_unsigned(low32(src))`
814             f64_from_x32_u = F64FromX32U { dst: FReg, src: XReg };
815             /// `dst = checked_f64_from_signed(src)`
816             f64_from_x64_s = F64FromX64S { dst: FReg, src: XReg };
817             /// `dst = checked_f64_from_unsigned(src)`
818             f64_from_x64_u = F64FromX64U { dst: FReg, src: XReg };
819 
820             /// `low32(dst) = checked_signed_from_f32(low32(src))`
821             x32_from_f32_s = X32FromF32S { dst: XReg, src: FReg };
822             /// `low32(dst) = checked_unsigned_from_f32(low32(src))`
823             x32_from_f32_u = X32FromF32U { dst: XReg, src: FReg };
824             /// `low32(dst) = checked_signed_from_f64(src)`
825             x32_from_f64_s = X32FromF64S { dst: XReg, src: FReg };
826             /// `low32(dst) = checked_unsigned_from_f64(src)`
827             x32_from_f64_u = X32FromF64U { dst: XReg, src: FReg };
828             /// `dst = checked_signed_from_f32(low32(src))`
829             x64_from_f32_s = X64FromF32S { dst: XReg, src: FReg };
830             /// `dst = checked_unsigned_from_f32(low32(src))`
831             x64_from_f32_u = X64FromF32U { dst: XReg, src: FReg };
832             /// `dst = checked_signed_from_f64(src)`
833             x64_from_f64_s = X64FromF64S { dst: XReg, src: FReg };
834             /// `dst = checked_unsigned_from_f64(src)`
835             x64_from_f64_u = X64FromF64U { dst: XReg, src: FReg };
836 
837             /// `low32(dst) = saturating_signed_from_f32(low32(src))`
838             x32_from_f32_s_sat = X32FromF32SSat { dst: XReg, src: FReg };
839             /// `low32(dst) = saturating_unsigned_from_f32(low32(src))`
840             x32_from_f32_u_sat = X32FromF32USat { dst: XReg, src: FReg };
841             /// `low32(dst) = saturating_signed_from_f64(src)`
842             x32_from_f64_s_sat = X32FromF64SSat { dst: XReg, src: FReg };
843             /// `low32(dst) = saturating_unsigned_from_f64(src)`
844             x32_from_f64_u_sat = X32FromF64USat { dst: XReg, src: FReg };
845             /// `dst = saturating_signed_from_f32(low32(src))`
846             x64_from_f32_s_sat = X64FromF32SSat { dst: XReg, src: FReg };
847             /// `dst = saturating_unsigned_from_f32(low32(src))`
848             x64_from_f32_u_sat = X64FromF32USat { dst: XReg, src: FReg };
849             /// `dst = saturating_signed_from_f64(src)`
850             x64_from_f64_s_sat = X64FromF64SSat { dst: XReg, src: FReg };
851             /// `dst = saturating_unsigned_from_f64(src)`
852             x64_from_f64_u_sat = X64FromF64USat { dst: XReg, src: FReg };
853 
854             /// `low32(dst) = copysign(low32(src1), low32(src2))`
855             fcopysign32 = FCopySign32 { operands: BinaryOperands<FReg> };
856             /// `dst = copysign(src1, src2)`
857             fcopysign64 = FCopySign64 { operands: BinaryOperands<FReg> };
858 
859             /// `low32(dst) = low32(src1) + low32(src2)`
860             fadd32 = Fadd32 { operands: BinaryOperands<FReg> };
861             /// `low32(dst) = low32(src1) - low32(src2)`
862             fsub32 = Fsub32 { operands: BinaryOperands<FReg> };
863             /// `low128(dst) = low128(src1) - low128(src2)`
864             vsubf32x4 = Vsubf32x4 { operands: BinaryOperands<VReg> };
865             /// `low32(dst) = low32(src1) * low32(src2)`
866             fmul32 = Fmul32 { operands: BinaryOperands<FReg> };
867             /// `low128(dst) = low128(src1) * low128(src2)`
868             vmulf32x4 = Vmulf32x4 { operands: BinaryOperands<VReg> };
869             /// `low32(dst) = low32(src1) / low32(src2)`
870             fdiv32 = Fdiv32 { operands: BinaryOperands<FReg> };
871             /// `low128(dst) = low128(src1) / low128(src2)`
872             vdivf32x4 = Vdivf32x4 { operands: BinaryOperands<VReg> };
873             /// `low32(dst) = ieee_maximum(low32(src1), low32(src2))`
874             fmaximum32 = Fmaximum32 { operands: BinaryOperands<FReg> };
875             /// `low32(dst) = ieee_minimum(low32(src1), low32(src2))`
876             fminimum32 = Fminimum32 { operands: BinaryOperands<FReg> };
877             /// `low32(dst) = ieee_trunc(low32(src))`
878             ftrunc32 = Ftrunc32 { dst: FReg, src: FReg };
879             /// `low128(dst) = ieee_trunc(low128(src))`
880             vtrunc32x4 = Vtrunc32x4 { dst: VReg, src: VReg };
881             /// `low128(dst) = ieee_trunc(low128(src))`
882             vtrunc64x2 = Vtrunc64x2 { dst: VReg, src: VReg };
883             /// `low32(dst) = ieee_floor(low32(src))`
884             ffloor32 = Ffloor32 { dst: FReg, src: FReg };
885             /// `low128(dst) = ieee_floor(low128(src))`
886             vfloor32x4 = Vfloor32x4 { dst: VReg, src: VReg };
887             /// `low128(dst) = ieee_floor(low128(src))`
888             vfloor64x2 = Vfloor64x2 { dst: VReg, src: VReg };
889             /// `low32(dst) = ieee_ceil(low32(src))`
890             fceil32 = Fceil32 { dst: FReg, src: FReg };
891             /// `low128(dst) = ieee_ceil(low128(src))`
892             vceil32x4 = Vceil32x4 { dst: VReg, src: VReg };
893             /// `low128(dst) = ieee_ceil(low128(src))`
894             vceil64x2 = Vceil64x2 { dst: VReg, src: VReg };
895             /// `low32(dst) = ieee_nearest(low32(src))`
896             fnearest32 = Fnearest32 { dst: FReg, src: FReg };
897             /// `low32(dst) = ieee_sqrt(low32(src))`
898             fsqrt32 = Fsqrt32 { dst: FReg, src: FReg };
899             /// `low32(dst) = ieee_sqrt(low32(src))`
900             vsqrt32x4 = Vsqrt32x4 { dst: VReg, src: VReg };
901             /// `low32(dst) = ieee_sqrt(low32(src))`
902             vsqrt64x2 = Vsqrt64x2 { dst: VReg, src: VReg };
903             /// `low32(dst) = -low32(src)`
904             fneg32 = Fneg32 { dst: FReg, src: FReg };
905             /// `low128(dst) = -low128(src)`
906             vnegf32x4 = Vnegf32x4 { dst: VReg, src: VReg };
907             /// `low32(dst) = |low32(src)|`
908             fabs32 = Fabs32 { dst: FReg, src: FReg };
909 
910             /// `dst = src1 + src2`
911             fadd64 = Fadd64 { operands: BinaryOperands<FReg> };
912             /// `dst = src1 - src2`
913             fsub64 = Fsub64 { operands: BinaryOperands<FReg> };
914             /// `dst = src1 * src2`
915             fmul64 = Fmul64 { operands: BinaryOperands<FReg> };
916             /// `dst = src1 / src2`
917             fdiv64 = Fdiv64 { operands: BinaryOperands<FReg> };
918             /// `dst = src1 / src2`
919             vdivf64x2 = VDivF64x2 { operands: BinaryOperands<VReg> };
920             /// `dst = ieee_maximum(src1, src2)`
921             fmaximum64 = Fmaximum64 { operands: BinaryOperands<FReg> };
922             /// `dst = ieee_minimum(src1, src2)`
923             fminimum64 = Fminimum64 { operands: BinaryOperands<FReg> };
924             /// `dst = ieee_trunc(src)`
925             ftrunc64 = Ftrunc64 { dst: FReg, src: FReg };
926             /// `dst = ieee_floor(src)`
927             ffloor64 = Ffloor64 { dst: FReg, src: FReg };
928             /// `dst = ieee_ceil(src)`
929             fceil64 = Fceil64 { dst: FReg, src: FReg };
930             /// `dst = ieee_nearest(src)`
931             fnearest64 = Fnearest64 { dst: FReg, src: FReg };
932             /// `low128(dst) = ieee_nearest(low128(src))`
933             vnearest32x4 = Vnearest32x4 { dst: VReg, src: VReg };
934             /// `low128(dst) = ieee_nearest(low128(src))`
935             vnearest64x2 = Vnearest64x2 { dst: VReg, src: VReg };
936             /// `dst = ieee_sqrt(src)`
937             fsqrt64 = Fsqrt64 { dst: FReg, src: FReg };
938             /// `dst = -src`
939             fneg64 = Fneg64 { dst: FReg, src: FReg };
940             /// `dst = |src|`
941             fabs64 = Fabs64 { dst: FReg, src: FReg };
942 
943             /// `dst = imm`
944             vconst128 = Vconst128 { dst: VReg, imm: u128 };
945 
946             /// `dst = src1 + src2`
947             vaddi8x16 = VAddI8x16 { operands: BinaryOperands<VReg> };
948             /// `dst = src1 + src2`
949             vaddi16x8 = VAddI16x8 { operands: BinaryOperands<VReg> };
950             /// `dst = src1 + src2`
951             vaddi32x4 = VAddI32x4 { operands: BinaryOperands<VReg> };
952             /// `dst = src1 + src2`
953             vaddi64x2 = VAddI64x2 { operands: BinaryOperands<VReg> };
954             /// `dst = src1 + src2`
955             vaddf32x4 = VAddF32x4 { operands: BinaryOperands<VReg> };
956             /// `dst = src1 + src2`
957             vaddf64x2 = VAddF64x2 { operands: BinaryOperands<VReg> };
958 
959             /// `dst = satruating_add(src1, src2)`
960             vaddi8x16_sat = VAddI8x16Sat { operands: BinaryOperands<VReg> };
961             /// `dst = satruating_add(src1, src2)`
962             vaddu8x16_sat = VAddU8x16Sat { operands: BinaryOperands<VReg> };
963             /// `dst = satruating_add(src1, src2)`
964             vaddi16x8_sat = VAddI16x8Sat { operands: BinaryOperands<VReg> };
965             /// `dst = satruating_add(src1, src2)`
966             vaddu16x8_sat = VAddU16x8Sat { operands: BinaryOperands<VReg> };
967 
968             /// `dst = [src1[0] + src1[1], ..., src2[6] + src2[7]]`
969             vaddpairwisei16x8_s = VAddpairwiseI16x8S { operands: BinaryOperands<VReg> };
970             /// `dst = [src1[0] + src1[1], ..., src2[2] + src2[3]]`
971             vaddpairwisei32x4_s = VAddpairwiseI32x4S { operands: BinaryOperands<VReg> };
972 
973             /// `dst = src1 << src2`
974             vshli8x16 = VShlI8x16 { operands: BinaryOperands<VReg, VReg, XReg> };
975             /// `dst = src1 << src2`
976             vshli16x8 = VShlI16x8 { operands: BinaryOperands<VReg, VReg, XReg> };
977             /// `dst = src1 << src2`
978             vshli32x4 = VShlI32x4 { operands: BinaryOperands<VReg, VReg, XReg> };
979             /// `dst = src1 << src2`
980             vshli64x2 = VShlI64x2 { operands: BinaryOperands<VReg, VReg, XReg> };
981             /// `dst = src1 >> src2` (signed)
982             vshri8x16_s = VShrI8x16S { operands: BinaryOperands<VReg, VReg, XReg> };
983             /// `dst = src1 >> src2` (signed)
984             vshri16x8_s = VShrI16x8S { operands: BinaryOperands<VReg, VReg, XReg> };
985             /// `dst = src1 >> src2` (signed)
986             vshri32x4_s = VShrI32x4S { operands: BinaryOperands<VReg, VReg, XReg> };
987             /// `dst = src1 >> src2` (signed)
988             vshri64x2_s = VShrI64x2S { operands: BinaryOperands<VReg, VReg, XReg> };
989             /// `dst = src1 >> src2` (unsigned)
990             vshri8x16_u = VShrI8x16U { operands: BinaryOperands<VReg, VReg, XReg> };
991             /// `dst = src1 >> src2` (unsigned)
992             vshri16x8_u = VShrI16x8U { operands: BinaryOperands<VReg, VReg, XReg> };
993             /// `dst = src1 >> src2` (unsigned)
994             vshri32x4_u = VShrI32x4U { operands: BinaryOperands<VReg, VReg, XReg> };
995             /// `dst = src1 >> src2` (unsigned)
996             vshri64x2_u = VShrI64x2U { operands: BinaryOperands<VReg, VReg, XReg> };
997 
998             /// `dst = splat(low8(src))`
999             vsplatx8 = VSplatX8 { dst: VReg, src: XReg };
1000             /// `dst = splat(low16(src))`
1001             vsplatx16 = VSplatX16 { dst: VReg, src: XReg };
1002             /// `dst = splat(low32(src))`
1003             vsplatx32 = VSplatX32 { dst: VReg, src: XReg };
1004             /// `dst = splat(src)`
1005             vsplatx64 = VSplatX64 { dst: VReg, src: XReg };
1006             /// `dst = splat(low32(src))`
1007             vsplatf32 = VSplatF32 { dst: VReg, src: FReg };
1008             /// `dst = splat(src)`
1009             vsplatf64 = VSplatF64 { dst: VReg, src: FReg };
1010 
1011             /// Load the 64-bit source as i8x8 and sign-extend to i16x8.
1012             vload8x8_s_z = VLoad8x8SZ { dst: VReg, addr: AddrZ };
1013             /// Load the 64-bit source as u8x8 and zero-extend to i16x8.
1014             vload8x8_u_z = VLoad8x8UZ { dst: VReg, addr: AddrZ };
1015             /// Load the 64-bit source as i16x4 and sign-extend to i32x4.
1016             vload16x4le_s_z = VLoad16x4LeSZ { dst: VReg, addr: AddrZ };
1017             /// Load the 64-bit source as u16x4 and zero-extend to i32x4.
1018             vload16x4le_u_z = VLoad16x4LeUZ { dst: VReg, addr: AddrZ };
1019             /// Load the 64-bit source as i32x2 and sign-extend to i64x2.
1020             vload32x2le_s_z = VLoad32x2LeSZ { dst: VReg, addr: AddrZ };
1021             /// Load the 64-bit source as u32x2 and zero-extend to i64x2.
1022             vload32x2le_u_z = VLoad32x2LeUZ { dst: VReg, addr: AddrZ };
1023 
1024             /// `dst = src1 & src2`
1025             vband128 = VBand128 { operands: BinaryOperands<VReg> };
1026             /// `dst = src1 | src2`
1027             vbor128 = VBor128 { operands: BinaryOperands<VReg> };
1028             /// `dst = src1 ^ src2`
1029             vbxor128 = VBxor128 { operands: BinaryOperands<VReg> };
1030             /// `dst = !src1`
1031             vbnot128 = VBnot128 { dst: VReg, src: VReg };
1032             /// `dst = (c & x) | (!c & y)`
1033             vbitselect128 = VBitselect128 { dst: VReg, c: VReg, x: VReg, y: VReg };
1034             /// Collect high bits of each lane into the low 32-bits of the
1035             /// destination.
1036             vbitmask8x16 = Vbitmask8x16 { dst: XReg, src: VReg };
1037             /// Collect high bits of each lane into the low 32-bits of the
1038             /// destination.
1039             vbitmask16x8 = Vbitmask16x8 { dst: XReg, src: VReg };
1040             /// Collect high bits of each lane into the low 32-bits of the
1041             /// destination.
1042             vbitmask32x4 = Vbitmask32x4 { dst: XReg, src: VReg };
1043             /// Collect high bits of each lane into the low 32-bits of the
1044             /// destination.
1045             vbitmask64x2 = Vbitmask64x2 { dst: XReg, src: VReg };
1046             /// Store whether all lanes are nonzero in `dst`.
1047             valltrue8x16 = Valltrue8x16 { dst: XReg, src: VReg };
1048             /// Store whether all lanes are nonzero in `dst`.
1049             valltrue16x8 = Valltrue16x8 { dst: XReg, src: VReg };
1050             /// Store whether all lanes are nonzero in `dst`.
1051             valltrue32x4 = Valltrue32x4 { dst: XReg, src: VReg };
1052             /// Store whether any lanes are nonzero in `dst`.
1053             valltrue64x2 = Valltrue64x2 { dst: XReg, src: VReg };
1054             /// Store whether any lanes are nonzero in `dst`.
1055             vanytrue8x16 = Vanytrue8x16 { dst: XReg, src: VReg };
1056             /// Store whether any lanes are nonzero in `dst`.
1057             vanytrue16x8 = Vanytrue16x8 { dst: XReg, src: VReg };
1058             /// Store whether any lanes are nonzero in `dst`.
1059             vanytrue32x4 = Vanytrue32x4 { dst: XReg, src: VReg };
1060             /// Store whether any lanes are nonzero in `dst`.
1061             vanytrue64x2 = Vanytrue64x2 { dst: XReg, src: VReg };
1062 
1063             /// Int-to-float conversion (same as `f32_from_x32_s`)
1064             vf32x4_from_i32x4_s = VF32x4FromI32x4S { dst: VReg, src: VReg };
1065             /// Int-to-float conversion (same as `f32_from_x32_u`)
1066             vf32x4_from_i32x4_u = VF32x4FromI32x4U { dst: VReg, src: VReg };
1067             /// Int-to-float conversion (same as `f64_from_x64_s`)
1068             vf64x2_from_i64x2_s = VF64x2FromI64x2S { dst: VReg, src: VReg };
1069             /// Int-to-float conversion (same as `f64_from_x64_u`)
1070             vf64x2_from_i64x2_u = VF64x2FromI64x2U { dst: VReg, src: VReg };
1071             /// Float-to-int conversion (same as `x32_from_f32_s`
1072             vi32x4_from_f32x4_s = VI32x4FromF32x4S { dst: VReg, src: VReg };
1073             /// Float-to-int conversion (same as `x32_from_f32_u`
1074             vi32x4_from_f32x4_u = VI32x4FromF32x4U { dst: VReg, src: VReg };
1075             /// Float-to-int conversion (same as `x64_from_f64_s`
1076             vi64x2_from_f64x2_s = VI64x2FromF64x2S { dst: VReg, src: VReg };
1077             /// Float-to-int conversion (same as `x64_from_f64_u`
1078             vi64x2_from_f64x2_u = VI64x2FromF64x2U { dst: VReg, src: VReg };
1079 
1080             /// Widens the low lanes of the input vector, as signed, to twice
1081             /// the width.
1082             vwidenlow8x16_s = VWidenLow8x16S { dst: VReg, src: VReg };
1083             /// Widens the low lanes of the input vector, as unsigned, to twice
1084             /// the width.
1085             vwidenlow8x16_u = VWidenLow8x16U { dst: VReg, src: VReg };
1086             /// Widens the low lanes of the input vector, as signed, to twice
1087             /// the width.
1088             vwidenlow16x8_s = VWidenLow16x8S { dst: VReg, src: VReg };
1089             /// Widens the low lanes of the input vector, as unsigned, to twice
1090             /// the width.
1091             vwidenlow16x8_u = VWidenLow16x8U { dst: VReg, src: VReg };
1092             /// Widens the low lanes of the input vector, as signed, to twice
1093             /// the width.
1094             vwidenlow32x4_s = VWidenLow32x4S { dst: VReg, src: VReg };
1095             /// Widens the low lanes of the input vector, as unsigned, to twice
1096             /// the width.
1097             vwidenlow32x4_u = VWidenLow32x4U { dst: VReg, src: VReg };
1098             /// Widens the high lanes of the input vector, as signed, to twice
1099             /// the width.
1100             vwidenhigh8x16_s = VWidenHigh8x16S { dst: VReg, src: VReg };
1101             /// Widens the high lanes of the input vector, as unsigned, to twice
1102             /// the width.
1103             vwidenhigh8x16_u = VWidenHigh8x16U { dst: VReg, src: VReg };
1104             /// Widens the high lanes of the input vector, as signed, to twice
1105             /// the width.
1106             vwidenhigh16x8_s = VWidenHigh16x8S { dst: VReg, src: VReg };
1107             /// Widens the high lanes of the input vector, as unsigned, to twice
1108             /// the width.
1109             vwidenhigh16x8_u = VWidenHigh16x8U { dst: VReg, src: VReg };
1110             /// Widens the high lanes of the input vector, as signed, to twice
1111             /// the width.
1112             vwidenhigh32x4_s = VWidenHigh32x4S { dst: VReg, src: VReg };
1113             /// Widens the high lanes of the input vector, as unsigned, to twice
1114             /// the width.
1115             vwidenhigh32x4_u = VWidenHigh32x4U { dst: VReg, src: VReg };
1116 
1117             /// Narrows the two 16x8 vectors, assuming all input lanes are
1118             /// signed, to half the width. Narrowing is signed and saturating.
1119             vnarrow16x8_s = Vnarrow16x8S { operands: BinaryOperands<VReg> };
1120             /// Narrows the two 16x8 vectors, assuming all input lanes are
1121             /// signed, to half the width. Narrowing is unsigned and saturating.
1122             vnarrow16x8_u = Vnarrow16x8U { operands: BinaryOperands<VReg> };
1123             /// Narrows the two 32x4 vectors, assuming all input lanes are
1124             /// signed, to half the width. Narrowing is signed and saturating.
1125             vnarrow32x4_s = Vnarrow32x4S { operands: BinaryOperands<VReg> };
1126             /// Narrows the two 32x4 vectors, assuming all input lanes are
1127             /// signed, to half the width. Narrowing is unsigned and saturating.
1128             vnarrow32x4_u = Vnarrow32x4U { operands: BinaryOperands<VReg> };
1129             /// Narrows the two 64x2 vectors, assuming all input lanes are
1130             /// signed, to half the width. Narrowing is signed and saturating.
1131             vnarrow64x2_s = Vnarrow64x2S { operands: BinaryOperands<VReg> };
1132             /// Narrows the two 64x2 vectors, assuming all input lanes are
1133             /// signed, to half the width. Narrowing is unsigned and saturating.
1134             vnarrow64x2_u = Vnarrow64x2U { operands: BinaryOperands<VReg> };
1135             /// Narrows the two 64x2 vectors, assuming all input lanes are
1136             /// unsigned, to half the width. Narrowing is unsigned and saturating.
1137             vunarrow64x2_u = Vunarrow64x2U { operands: BinaryOperands<VReg> };
1138             /// Promotes the low two lanes of the f32x4 input to f64x2.
1139             vfpromotelow = VFpromoteLow { dst: VReg, src: VReg };
1140             /// Demotes the two f64x2 lanes to f32x2 and then extends with two
1141             /// more zero lanes.
1142             vfdemote = VFdemote { dst: VReg, src: VReg };
1143 
1144             /// `dst = src1 - src2`
1145             vsubi8x16 = VSubI8x16 { operands: BinaryOperands<VReg> };
1146             /// `dst = src1 - src2`
1147             vsubi16x8 = VSubI16x8 { operands: BinaryOperands<VReg> };
1148             /// `dst = src1 - src2`
1149             vsubi32x4 = VSubI32x4 { operands: BinaryOperands<VReg> };
1150             /// `dst = src1 - src2`
1151             vsubi64x2 = VSubI64x2 { operands: BinaryOperands<VReg> };
1152             /// `dst = src1 - src2`
1153             vsubf64x2 = VSubF64x2 { operands: BinaryOperands<VReg> };
1154 
1155             /// `dst = saturating_sub(src1, src2)`
1156             vsubi8x16_sat = VSubI8x16Sat { operands: BinaryOperands<VReg> };
1157             /// `dst = saturating_sub(src1, src2)`
1158             vsubu8x16_sat = VSubU8x16Sat { operands: BinaryOperands<VReg> };
1159             /// `dst = saturating_sub(src1, src2)`
1160             vsubi16x8_sat = VSubI16x8Sat { operands: BinaryOperands<VReg> };
1161             /// `dst = saturating_sub(src1, src2)`
1162             vsubu16x8_sat = VSubU16x8Sat { operands: BinaryOperands<VReg> };
1163 
1164             /// `dst = src1 * src2`
1165             vmuli8x16 = VMulI8x16 { operands: BinaryOperands<VReg> };
1166             /// `dst = src1 * src2`
1167             vmuli16x8 = VMulI16x8 { operands: BinaryOperands<VReg> };
1168             /// `dst = src1 * src2`
1169             vmuli32x4 = VMulI32x4 { operands: BinaryOperands<VReg> };
1170             /// `dst = src1 * src2`
1171             vmuli64x2 = VMulI64x2 { operands: BinaryOperands<VReg> };
1172             /// `dst = src1 * src2`
1173             vmulf64x2 = VMulF64x2 { operands: BinaryOperands<VReg> };
1174 
1175             /// `dst = signed_saturate(src1 * src2 + (1 << (Q - 1)) >> Q)`
1176             vqmulrsi16x8 = VQmulrsI16x8 { operands: BinaryOperands<VReg> };
1177 
1178             /// `dst = count_ones(src)`
1179             vpopcnt8x16 = VPopcnt8x16 { dst: VReg, src: VReg };
1180 
1181             /// `low32(dst) = zext(src[lane])`
1182             xextractv8x16 = XExtractV8x16 { dst: XReg, src: VReg, lane: u8 };
1183             /// `low32(dst) = zext(src[lane])`
1184             xextractv16x8 = XExtractV16x8 { dst: XReg, src: VReg, lane: u8 };
1185             /// `low32(dst) = src[lane]`
1186             xextractv32x4 = XExtractV32x4 { dst: XReg, src: VReg, lane: u8 };
1187             /// `dst = src[lane]`
1188             xextractv64x2 = XExtractV64x2 { dst: XReg, src: VReg, lane: u8 };
1189             /// `low32(dst) = src[lane]`
1190             fextractv32x4 = FExtractV32x4 { dst: FReg, src: VReg, lane: u8 };
1191             /// `dst = src[lane]`
1192             fextractv64x2 = FExtractV64x2 { dst: FReg, src: VReg, lane: u8 };
1193 
1194             /// `dst = src1; dst[lane] = src2`
1195             vinsertx8 = VInsertX8 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 };
1196             /// `dst = src1; dst[lane] = src2`
1197             vinsertx16 = VInsertX16 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 };
1198             /// `dst = src1; dst[lane] = src2`
1199             vinsertx32 = VInsertX32 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 };
1200             /// `dst = src1; dst[lane] = src2`
1201             vinsertx64 = VInsertX64 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 };
1202             /// `dst = src1; dst[lane] = src2`
1203             vinsertf32 = VInsertF32 { operands: BinaryOperands<VReg, VReg, FReg>, lane: u8 };
1204             /// `dst = src1; dst[lane] = src2`
1205             vinsertf64 = VInsertF64 { operands: BinaryOperands<VReg, VReg, FReg>, lane: u8 };
1206 
1207             /// `dst = src == dst`
1208             veq8x16 = Veq8x16 { operands: BinaryOperands<VReg> };
1209             /// `dst = src != dst`
1210             vneq8x16 = Vneq8x16 { operands: BinaryOperands<VReg> };
1211             /// `dst = src < dst` (signed)
1212             vslt8x16 = Vslt8x16 { operands: BinaryOperands<VReg> };
1213             /// `dst = src <= dst` (signed)
1214             vslteq8x16 = Vslteq8x16 { operands: BinaryOperands<VReg> };
1215             /// `dst = src < dst` (unsigned)
1216             vult8x16 = Vult8x16 { operands: BinaryOperands<VReg> };
1217             /// `dst = src <= dst` (unsigned)
1218             vulteq8x16 = Vulteq8x16 { operands: BinaryOperands<VReg> };
1219             /// `dst = src == dst`
1220             veq16x8 = Veq16x8 { operands: BinaryOperands<VReg> };
1221             /// `dst = src != dst`
1222             vneq16x8 = Vneq16x8 { operands: BinaryOperands<VReg> };
1223             /// `dst = src < dst` (signed)
1224             vslt16x8 = Vslt16x8 { operands: BinaryOperands<VReg> };
1225             /// `dst = src <= dst` (signed)
1226             vslteq16x8 = Vslteq16x8 { operands: BinaryOperands<VReg> };
1227             /// `dst = src < dst` (unsigned)
1228             vult16x8 = Vult16x8 { operands: BinaryOperands<VReg> };
1229             /// `dst = src <= dst` (unsigned)
1230             vulteq16x8 = Vulteq16x8 { operands: BinaryOperands<VReg> };
1231             /// `dst = src == dst`
1232             veq32x4 = Veq32x4 { operands: BinaryOperands<VReg> };
1233             /// `dst = src != dst`
1234             vneq32x4 = Vneq32x4 { operands: BinaryOperands<VReg> };
1235             /// `dst = src < dst` (signed)
1236             vslt32x4 = Vslt32x4 { operands: BinaryOperands<VReg> };
1237             /// `dst = src <= dst` (signed)
1238             vslteq32x4 = Vslteq32x4 { operands: BinaryOperands<VReg> };
1239             /// `dst = src < dst` (unsigned)
1240             vult32x4 = Vult32x4 { operands: BinaryOperands<VReg> };
1241             /// `dst = src <= dst` (unsigned)
1242             vulteq32x4 = Vulteq32x4 { operands: BinaryOperands<VReg> };
1243             /// `dst = src == dst`
1244             veq64x2 = Veq64x2 { operands: BinaryOperands<VReg> };
1245             /// `dst = src != dst`
1246             vneq64x2 = Vneq64x2 { operands: BinaryOperands<VReg> };
1247             /// `dst = src < dst` (signed)
1248             vslt64x2 = Vslt64x2 { operands: BinaryOperands<VReg> };
1249             /// `dst = src <= dst` (signed)
1250             vslteq64x2 = Vslteq64x2 { operands: BinaryOperands<VReg> };
1251             /// `dst = src < dst` (unsigned)
1252             vult64x2 = Vult64x2 { operands: BinaryOperands<VReg> };
1253             /// `dst = src <= dst` (unsigned)
1254             vulteq64x2 = Vulteq64x2 { operands: BinaryOperands<VReg> };
1255 
1256             /// `dst = -src`
1257             vneg8x16 = Vneg8x16 { dst: VReg, src: VReg };
1258             /// `dst = -src`
1259             vneg16x8 = Vneg16x8 { dst: VReg, src: VReg };
1260             /// `dst = -src`
1261             vneg32x4 = Vneg32x4 { dst: VReg, src: VReg };
1262             /// `dst = -src`
1263             vneg64x2 = Vneg64x2 { dst: VReg, src: VReg };
1264             /// `dst = -src`
1265             vnegf64x2 = VnegF64x2 { dst: VReg, src: VReg };
1266 
1267             /// `dst = min(src1, src2)` (signed)
1268             vmin8x16_s = Vmin8x16S { operands: BinaryOperands<VReg> };
1269             /// `dst = min(src1, src2)` (unsigned)
1270             vmin8x16_u = Vmin8x16U { operands: BinaryOperands<VReg> };
1271             /// `dst = min(src1, src2)` (signed)
1272             vmin16x8_s = Vmin16x8S { operands: BinaryOperands<VReg> };
1273             /// `dst = min(src1, src2)` (unsigned)
1274             vmin16x8_u = Vmin16x8U { operands: BinaryOperands<VReg> };
1275             /// `dst = max(src1, src2)` (signed)
1276             vmax8x16_s = Vmax8x16S { operands: BinaryOperands<VReg> };
1277             /// `dst = max(src1, src2)` (unsigned)
1278             vmax8x16_u = Vmax8x16U { operands: BinaryOperands<VReg> };
1279             /// `dst = max(src1, src2)` (signed)
1280             vmax16x8_s = Vmax16x8S { operands: BinaryOperands<VReg> };
1281             /// `dst = max(src1, src2)` (unsigned)
1282             vmax16x8_u = Vmax16x8U { operands: BinaryOperands<VReg> };
1283 
1284             /// `dst = min(src1, src2)` (signed)
1285             vmin32x4_s = Vmin32x4S { operands: BinaryOperands<VReg> };
1286             /// `dst = min(src1, src2)` (unsigned)
1287             vmin32x4_u = Vmin32x4U { operands: BinaryOperands<VReg> };
1288             /// `dst = max(src1, src2)` (signed)
1289             vmax32x4_s = Vmax32x4S { operands: BinaryOperands<VReg> };
1290             /// `dst = max(src1, src2)` (unsigned)
1291             vmax32x4_u = Vmax32x4U { operands: BinaryOperands<VReg> };
1292 
1293             /// `dst = |src|`
1294             vabs8x16 = Vabs8x16 { dst: VReg, src: VReg };
1295             /// `dst = |src|`
1296             vabs16x8 = Vabs16x8 { dst: VReg, src: VReg };
1297             /// `dst = |src|`
1298             vabs32x4 = Vabs32x4 { dst: VReg, src: VReg };
1299             /// `dst = |src|`
1300             vabs64x2 = Vabs64x2 { dst: VReg, src: VReg };
1301 
1302             /// `dst = |src|`
1303             vabsf32x4 = Vabsf32x4 { dst: VReg, src: VReg };
1304             /// `dst = |src|`
1305             vabsf64x2 = Vabsf64x2 { dst: VReg, src: VReg };
1306             /// `dst = ieee_maximum(src1, src2)`
1307             vmaximumf32x4 = Vmaximumf32x4 { operands: BinaryOperands<VReg> };
1308             /// `dst = ieee_maximum(src1, src2)`
1309             vmaximumf64x2 = Vmaximumf64x2 { operands: BinaryOperands<VReg> };
1310             /// `dst = ieee_minimum(src1, src2)`
1311             vminimumf32x4 = Vminimumf32x4 { operands: BinaryOperands<VReg> };
1312             /// `dst = ieee_minimum(src1, src2)`
1313             vminimumf64x2 = Vminimumf64x2 { operands: BinaryOperands<VReg> };
1314 
1315             /// `dst = shuffle(src1, src2, mask)`
1316             vshuffle = VShuffle { dst: VReg, src1: VReg, src2: VReg, mask: u128 };
1317 
1318             /// `dst = swizzle(src1, src2)`
1319             vswizzlei8x16 = Vswizzlei8x16 { operands: BinaryOperands<VReg> };
1320 
1321             /// `dst = (src1 + src2 + 1) // 2`
1322             vavground8x16 = Vavground8x16 { operands: BinaryOperands<VReg> };
1323             /// `dst = (src1 + src2 + 1) // 2`
1324             vavground16x8 = Vavground16x8 { operands: BinaryOperands<VReg> };
1325 
1326             /// `dst = src == dst`
1327             veqf32x4 = VeqF32x4 { operands: BinaryOperands<VReg> };
1328             /// `dst = src != dst`
1329             vneqf32x4 = VneqF32x4 { operands: BinaryOperands<VReg> };
1330             /// `dst = src < dst`
1331             vltf32x4 = VltF32x4 { operands: BinaryOperands<VReg> };
1332             /// `dst = src <= dst`
1333             vlteqf32x4 = VlteqF32x4 { operands: BinaryOperands<VReg> };
1334             /// `dst = src == dst`
1335             veqf64x2 = VeqF64x2 { operands: BinaryOperands<VReg> };
1336             /// `dst = src != dst`
1337             vneqf64x2 = VneqF64x2 { operands: BinaryOperands<VReg> };
1338             /// `dst = src < dst`
1339             vltf64x2 = VltF64x2 { operands: BinaryOperands<VReg> };
1340             /// `dst = src <= dst`
1341             vlteqf64x2 = VlteqF64x2 { operands: BinaryOperands<VReg> };
1342 
1343             /// `dst = ieee_fma(a, b, c)`
1344             vfma32x4 = Vfma32x4 { dst: VReg, a: VReg, b: VReg, c: VReg };
1345             /// `dst = ieee_fma(a, b, c)`
1346             vfma64x2 = Vfma64x2 { dst: VReg, a: VReg, b: VReg, c: VReg };
1347 
1348             /// `dst = low32(cond) ? if_nonzero : if_zero`
1349             vselect = Vselect { dst: VReg, cond: XReg, if_nonzero: VReg, if_zero: VReg };
1350 
1351             /// `dst_hi:dst_lo = lhs_hi:lhs_lo + rhs_hi:rhs_lo`
1352             xadd128 = Xadd128 {
1353                 dst_lo: XReg,
1354                 dst_hi: XReg,
1355                 lhs_lo: XReg,
1356                 lhs_hi: XReg,
1357                 rhs_lo: XReg,
1358                 rhs_hi: XReg
1359             };
1360             /// `dst_hi:dst_lo = lhs_hi:lhs_lo - rhs_hi:rhs_lo`
1361             xsub128 = Xsub128 {
1362                 dst_lo: XReg,
1363                 dst_hi: XReg,
1364                 lhs_lo: XReg,
1365                 lhs_hi: XReg,
1366                 rhs_lo: XReg,
1367                 rhs_hi: XReg
1368             };
1369             /// `dst_hi:dst_lo = sext(lhs) * sext(rhs)`
1370             xwidemul64_s = Xwidemul64S {
1371                 dst_lo: XReg,
1372                 dst_hi: XReg,
1373                 lhs: XReg,
1374                 rhs: XReg
1375             };
1376             /// `dst_hi:dst_lo = zext(lhs) * zext(rhs)`
1377             xwidemul64_u = Xwidemul64U {
1378                 dst_lo: XReg,
1379                 dst_hi: XReg,
1380                 lhs: XReg,
1381                 rhs: XReg
1382             };
1383         }
1384     };
1385 }
1386 
1387 #[cfg(feature = "decode")]
1388 pub mod decode;
1389 #[cfg(feature = "disas")]
1390 pub mod disas;
1391 #[cfg(feature = "encode")]
1392 pub mod encode;
1393 #[cfg(feature = "interp")]
1394 pub mod interp;
1395 #[cfg(feature = "profile")]
1396 pub mod profile;
1397 #[cfg(all(not(feature = "profile"), feature = "interp"))]
1398 mod profile_disabled;
1399 #[cfg(all(not(feature = "profile"), feature = "interp"))]
1400 use profile_disabled as profile;
1401 
1402 pub mod regs;
1403 pub use regs::*;
1404 
1405 pub mod imms;
1406 pub use imms::*;
1407 
1408 pub mod op;
1409 pub use op::*;
1410 
1411 pub mod opcode;
1412 pub use opcode::*;
1413 
1414 #[cfg(any(feature = "encode", feature = "decode"))]
1415 pub(crate) unsafe fn unreachable_unchecked<T>() -> T {
1416     #[cfg(debug_assertions)]
1417     unreachable!();
1418 
1419     #[cfg(not(debug_assertions))]
1420     unsafe {
1421         core::hint::unreachable_unchecked()
1422     }
1423 }
1424