Skip to main content

winch_codegen/
visitor.rs

1//! This module is the central place for machine code emission.
2//! It defines an implementation of wasmparser's Visitor trait
3//! for `CodeGen`; which defines a visitor per op-code,
4//! which validates and dispatches to the corresponding
5//! machine code emitter.
6
7use crate::abi::RetArea;
8use crate::codegen::{
9    Callee, CodeGen, CodeGenError, ConditionalBranch, ControlStackFrame, Emission, FnCall,
10    UnconditionalBranch, control_index,
11};
12use crate::masm::{
13    AtomicWaitKind, DivKind, Extend, ExtractLaneKind, FloatCmpKind, IntCmpKind, LoadKind,
14    MacroAssembler, MulWideKind, OperandSize, RegImm, RemKind, ReplaceLaneKind, RmwOp,
15    RoundingMode, SPOffset, ShiftKind, Signed, SplatKind, SplatLoadKind, StoreKind, TruncKind,
16    V128AbsKind, V128AddKind, V128ConvertKind, V128ExtAddKind, V128ExtMulKind, V128ExtendKind,
17    V128LoadExtendKind, V128MaxKind, V128MinKind, V128MulKind, V128NarrowKind, V128NegKind,
18    V128SubKind, V128TruncKind, VectorCompareKind, VectorEqualityKind, Zero,
19};
20use crate::reg::{Reg, writable};
21use crate::stack::{TypedReg, Val};
22use crate::{Result, bail, format_err};
23use regalloc2::RegClass;
24use smallvec::{SmallVec, smallvec};
25use wasmparser::{
26    BlockType, BrTable, HeapType, Ieee32, Ieee64, MemArg, V128, ValType, VisitOperator,
27    VisitSimdOperator,
28};
29use wasmtime_cranelift::TRAP_INDIRECT_CALL_TO_NULL;
30use wasmtime_environ::{
31    DataIndex, ElemIndex, FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex, WasmHeapType,
32    WasmValType,
33};
34
35/// A macro to define unsupported WebAssembly operators.
36///
37/// This macro calls itself recursively;
38/// 1. It no-ops when matching a supported operator.
39/// 2. Defines the visitor function and panics when
40///    matching an unsupported operator.
41macro_rules! def_unsupported {
42    ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $ann:tt)*) => {
43        $(
44            def_unsupported!(
45                emit
46                    $op
47
48                fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
49                    $($(let _ = $arg;)*)?
50
51                    Err(format_err!(CodeGenError::unimplemented_wasm_instruction()))
52                }
53            );
54        )*
55    };
56
57    (emit I32Const $($rest:tt)*) => {};
58    (emit I64Const $($rest:tt)*) => {};
59    (emit F32Const $($rest:tt)*) => {};
60    (emit F64Const $($rest:tt)*) => {};
61    (emit V128Const $($rest:tt)*) => {};
62    (emit F32Add $($rest:tt)*) => {};
63    (emit F64Add $($rest:tt)*) => {};
64    (emit F32Sub $($rest:tt)*) => {};
65    (emit F64Sub $($rest:tt)*) => {};
66    (emit F32Mul $($rest:tt)*) => {};
67    (emit F64Mul $($rest:tt)*) => {};
68    (emit F32Div $($rest:tt)*) => {};
69    (emit F64Div $($rest:tt)*) => {};
70    (emit F32Min $($rest:tt)*) => {};
71    (emit F64Min $($rest:tt)*) => {};
72    (emit F32Max $($rest:tt)*) => {};
73    (emit F64Max $($rest:tt)*) => {};
74    (emit F32Copysign $($rest:tt)*) => {};
75    (emit F64Copysign $($rest:tt)*) => {};
76    (emit F32Abs $($rest:tt)*) => {};
77    (emit F64Abs $($rest:tt)*) => {};
78    (emit F32Neg $($rest:tt)*) => {};
79    (emit F64Neg $($rest:tt)*) => {};
80    (emit F32Floor $($rest:tt)*) => {};
81    (emit F64Floor $($rest:tt)*) => {};
82    (emit F32Ceil $($rest:tt)*) => {};
83    (emit F64Ceil $($rest:tt)*) => {};
84    (emit F32Nearest $($rest:tt)*) => {};
85    (emit F64Nearest $($rest:tt)*) => {};
86    (emit F32Trunc $($rest:tt)*) => {};
87    (emit F64Trunc $($rest:tt)*) => {};
88    (emit F32Sqrt $($rest:tt)*) => {};
89    (emit F64Sqrt $($rest:tt)*) => {};
90    (emit F32Eq $($rest:tt)*) => {};
91    (emit F64Eq $($rest:tt)*) => {};
92    (emit F32Ne $($rest:tt)*) => {};
93    (emit F64Ne $($rest:tt)*) => {};
94    (emit F32Lt $($rest:tt)*) => {};
95    (emit F64Lt $($rest:tt)*) => {};
96    (emit F32Gt $($rest:tt)*) => {};
97    (emit F64Gt $($rest:tt)*) => {};
98    (emit F32Le $($rest:tt)*) => {};
99    (emit F64Le $($rest:tt)*) => {};
100    (emit F32Ge $($rest:tt)*) => {};
101    (emit F64Ge $($rest:tt)*) => {};
102    (emit F32ConvertI32S $($rest:tt)*) => {};
103    (emit F32ConvertI32U $($rest:tt)*) => {};
104    (emit F32ConvertI64S $($rest:tt)*) => {};
105    (emit F32ConvertI64U $($rest:tt)*) => {};
106    (emit F64ConvertI32S $($rest:tt)*) => {};
107    (emit F64ConvertI32U $($rest:tt)*) => {};
108    (emit F64ConvertI64S $($rest:tt)*) => {};
109    (emit F64ConvertI64U $($rest:tt)*) => {};
110    (emit F32ReinterpretI32 $($rest:tt)*) => {};
111    (emit F64ReinterpretI64 $($rest:tt)*) => {};
112    (emit F32DemoteF64 $($rest:tt)*) => {};
113    (emit F64PromoteF32 $($rest:tt)*) => {};
114    (emit I32Add $($rest:tt)*) => {};
115    (emit I64Add $($rest:tt)*) => {};
116    (emit I32Sub $($rest:tt)*) => {};
117    (emit I32Mul $($rest:tt)*) => {};
118    (emit I32DivS $($rest:tt)*) => {};
119    (emit I32DivU $($rest:tt)*) => {};
120    (emit I64DivS $($rest:tt)*) => {};
121    (emit I64DivU $($rest:tt)*) => {};
122    (emit I64RemU $($rest:tt)*) => {};
123    (emit I64RemS $($rest:tt)*) => {};
124    (emit I32RemU $($rest:tt)*) => {};
125    (emit I32RemS $($rest:tt)*) => {};
126    (emit I64Mul $($rest:tt)*) => {};
127    (emit I64Sub $($rest:tt)*) => {};
128    (emit I32Eq $($rest:tt)*) => {};
129    (emit I64Eq $($rest:tt)*) => {};
130    (emit I32Ne $($rest:tt)*) => {};
131    (emit I64Ne $($rest:tt)*) => {};
132    (emit I32LtS $($rest:tt)*) => {};
133    (emit I64LtS $($rest:tt)*) => {};
134    (emit I32LtU $($rest:tt)*) => {};
135    (emit I64LtU $($rest:tt)*) => {};
136    (emit I32LeS $($rest:tt)*) => {};
137    (emit I64LeS $($rest:tt)*) => {};
138    (emit I32LeU $($rest:tt)*) => {};
139    (emit I64LeU $($rest:tt)*) => {};
140    (emit I32GtS $($rest:tt)*) => {};
141    (emit I64GtS $($rest:tt)*) => {};
142    (emit I32GtU $($rest:tt)*) => {};
143    (emit I64GtU $($rest:tt)*) => {};
144    (emit I32GeS $($rest:tt)*) => {};
145    (emit I64GeS $($rest:tt)*) => {};
146    (emit I32GeU $($rest:tt)*) => {};
147    (emit I64GeU $($rest:tt)*) => {};
148    (emit I32Eqz $($rest:tt)*) => {};
149    (emit I64Eqz $($rest:tt)*) => {};
150    (emit I32And $($rest:tt)*) => {};
151    (emit I64And $($rest:tt)*) => {};
152    (emit I32Or $($rest:tt)*) => {};
153    (emit I64Or $($rest:tt)*) => {};
154    (emit I32Xor $($rest:tt)*) => {};
155    (emit I64Xor $($rest:tt)*) => {};
156    (emit I32Shl $($rest:tt)*) => {};
157    (emit I64Shl $($rest:tt)*) => {};
158    (emit I32ShrS $($rest:tt)*) => {};
159    (emit I64ShrS $($rest:tt)*) => {};
160    (emit I32ShrU $($rest:tt)*) => {};
161    (emit I64ShrU $($rest:tt)*) => {};
162    (emit I32Rotl $($rest:tt)*) => {};
163    (emit I64Rotl $($rest:tt)*) => {};
164    (emit I32Rotr $($rest:tt)*) => {};
165    (emit I64Rotr $($rest:tt)*) => {};
166    (emit I32Clz $($rest:tt)*) => {};
167    (emit I64Clz $($rest:tt)*) => {};
168    (emit I32Ctz $($rest:tt)*) => {};
169    (emit I64Ctz $($rest:tt)*) => {};
170    (emit I32Popcnt $($rest:tt)*) => {};
171    (emit I64Popcnt $($rest:tt)*) => {};
172    (emit I32WrapI64 $($rest:tt)*) => {};
173    (emit I64ExtendI32S $($rest:tt)*) => {};
174    (emit I64ExtendI32U $($rest:tt)*) => {};
175    (emit I32Extend8S $($rest:tt)*) => {};
176    (emit I32Extend16S $($rest:tt)*) => {};
177    (emit I64Extend8S $($rest:tt)*) => {};
178    (emit I64Extend16S $($rest:tt)*) => {};
179    (emit I64Extend32S $($rest:tt)*) => {};
180    (emit I32TruncF32S $($rest:tt)*) => {};
181    (emit I32TruncF32U $($rest:tt)*) => {};
182    (emit I32TruncF64S $($rest:tt)*) => {};
183    (emit I32TruncF64U $($rest:tt)*) => {};
184    (emit I64TruncF32S $($rest:tt)*) => {};
185    (emit I64TruncF32U $($rest:tt)*) => {};
186    (emit I64TruncF64S $($rest:tt)*) => {};
187    (emit I64TruncF64U $($rest:tt)*) => {};
188    (emit I32ReinterpretF32 $($rest:tt)*) => {};
189    (emit I64ReinterpretF64 $($rest:tt)*) => {};
190    (emit LocalGet $($rest:tt)*) => {};
191    (emit LocalSet $($rest:tt)*) => {};
192    (emit Call $($rest:tt)*) => {};
193    (emit End $($rest:tt)*) => {};
194    (emit Nop $($rest:tt)*) => {};
195    (emit If $($rest:tt)*) => {};
196    (emit Else $($rest:tt)*) => {};
197    (emit Block $($rest:tt)*) => {};
198    (emit Loop $($rest:tt)*) => {};
199    (emit Br $($rest:tt)*) => {};
200    (emit BrIf $($rest:tt)*) => {};
201    (emit Return $($rest:tt)*) => {};
202    (emit Unreachable $($rest:tt)*) => {};
203    (emit LocalTee $($rest:tt)*) => {};
204    (emit GlobalGet $($rest:tt)*) => {};
205    (emit GlobalSet $($rest:tt)*) => {};
206    (emit Select $($rest:tt)*) => {};
207    (emit TypedSelect $($rest:tt)*) => {};
208    (emit RefNull $($rest:tt)*) => {};
209    (emit RefIsNull $($rest:tt)*) => {};
210    (emit RefFunc $($rest:tt)*) => {};
211    (emit Drop $($rest:tt)*) => {};
212    (emit BrTable $($rest:tt)*) => {};
213    (emit CallIndirect $($rest:tt)*) => {};
214    (emit TableInit $($rest:tt)*) => {};
215    (emit TableCopy $($rest:tt)*) => {};
216    (emit TableGet $($rest:tt)*) => {};
217    (emit TableSet $($rest:tt)*) => {};
218    (emit TableGrow $($rest:tt)*) => {};
219    (emit TableSize $($rest:tt)*) => {};
220    (emit TableFill $($rest:tt)*) => {};
221    (emit ElemDrop $($rest:tt)*) => {};
222    (emit MemoryInit $($rest:tt)*) => {};
223    (emit MemoryCopy $($rest:tt)*) => {};
224    (emit DataDrop $($rest:tt)*) => {};
225    (emit MemoryFill $($rest:tt)*) => {};
226    (emit MemorySize $($rest:tt)*) => {};
227    (emit MemoryGrow $($rest:tt)*) => {};
228    (emit I32Load $($rest:tt)*) => {};
229    (emit I32Load8S $($rest:tt)*) => {};
230    (emit I32Load8U $($rest:tt)*) => {};
231    (emit I32Load16S $($rest:tt)*) => {};
232    (emit I32Load16U $($rest:tt)*) => {};
233    (emit I64Load8S $($rest:tt)*) => {};
234    (emit I64Load8U $($rest:tt)*) => {};
235    (emit I64Load16S $($rest:tt)*) => {};
236    (emit I64Load16U $($rest:tt)*) => {};
237    (emit I64Load32S $($rest:tt)*) => {};
238    (emit I64Load32U $($rest:tt)*) => {};
239    (emit I64Load $($rest:tt)*) => {};
240    (emit I32Store $($rest:tt)*) => {};
241    (emit I32Store8 $($rest:tt)*) => {};
242    (emit I32Store16 $($rest:tt)*) => {};
243    (emit I64Store $($rest:tt)*) => {};
244    (emit I64Store8 $($rest:tt)*) => {};
245    (emit I64Store16 $($rest:tt)*) => {};
246    (emit I64Store32 $($rest:tt)*) => {};
247    (emit F32Load $($rest:tt)*) => {};
248    (emit F32Store $($rest:tt)*) => {};
249    (emit F64Load $($rest:tt)*) => {};
250    (emit F64Store $($rest:tt)*) => {};
251    (emit I32TruncSatF32S $($rest:tt)*) => {};
252    (emit I32TruncSatF32U $($rest:tt)*) => {};
253    (emit I32TruncSatF64S $($rest:tt)*) => {};
254    (emit I32TruncSatF64U $($rest:tt)*) => {};
255    (emit I64TruncSatF32S $($rest:tt)*) => {};
256    (emit I64TruncSatF32U $($rest:tt)*) => {};
257    (emit I64TruncSatF64S $($rest:tt)*) => {};
258    (emit I64TruncSatF64U $($rest:tt)*) => {};
259    (emit V128Load $($rest:tt)*) => {};
260    (emit V128Store $($rest:tt)*) => {};
261    (emit I64Add128 $($rest:tt)*) => {};
262    (emit I64Sub128 $($rest:tt)*) => {};
263    (emit I64MulWideS $($rest:tt)*) => {};
264    (emit I64MulWideU $($rest:tt)*) => {};
265    (emit I32AtomicLoad8U $($rest:tt)*) => {};
266    (emit I32AtomicLoad16U $($rest:tt)*) => {};
267    (emit I32AtomicLoad $($rest:tt)*) => {};
268    (emit I64AtomicLoad8U $($rest:tt)*) => {};
269    (emit I64AtomicLoad16U $($rest:tt)*) => {};
270    (emit I64AtomicLoad32U $($rest:tt)*) => {};
271    (emit I64AtomicLoad $($rest:tt)*) => {};
272    (emit V128Load8x8S $($rest:tt)*) => {};
273    (emit V128Load8x8U $($rest:tt)*) => {};
274    (emit V128Load16x4S $($rest:tt)*) => {};
275    (emit V128Load16x4U $($rest:tt)*) => {};
276    (emit V128Load32x2S $($rest:tt)*) => {};
277    (emit V128Load32x2U $($rest:tt)*) => {};
278    (emit V128Load8Splat $($rest:tt)*) => {};
279    (emit V128Load16Splat $($rest:tt)*) => {};
280    (emit V128Load32Splat $($rest:tt)*) => {};
281    (emit V128Load64Splat $($rest:tt)*) => {};
282    (emit I8x16Splat $($rest:tt)*) => {};
283    (emit I16x8Splat $($rest:tt)*) => {};
284    (emit I32x4Splat $($rest:tt)*) => {};
285    (emit I64x2Splat $($rest:tt)*) => {};
286    (emit F32x4Splat $($rest:tt)*) => {};
287    (emit F64x2Splat $($rest:tt)*) => {};
288    (emit I32AtomicStore8 $($rest:tt)*) => {};
289    (emit I32AtomicStore16 $($rest:tt)*) => {};
290    (emit I32AtomicStore $($rest:tt)*) => {};
291    (emit I64AtomicStore8 $($rest:tt)*) => {};
292    (emit I64AtomicStore16 $($rest:tt)*) => {};
293    (emit I64AtomicStore32 $($rest:tt)*) => {};
294    (emit I64AtomicStore $($rest:tt)*) => {};
295    (emit I32AtomicRmw8AddU $($rest:tt)*) => {};
296    (emit I32AtomicRmw16AddU $($rest:tt)*) => {};
297    (emit I32AtomicRmwAdd $($rest:tt)*) => {};
298    (emit I64AtomicRmw8AddU $($rest:tt)*) => {};
299    (emit I64AtomicRmw16AddU $($rest:tt)*) => {};
300    (emit I64AtomicRmw32AddU $($rest:tt)*) => {};
301    (emit I64AtomicRmwAdd $($rest:tt)*) => {};
302    (emit I8x16Shuffle $($rest:tt)*) => {};
303    (emit I8x16Swizzle $($rest:tt)*) => {};
304    (emit I32AtomicRmw8SubU $($rest:tt)*) => {};
305    (emit I32AtomicRmw16SubU $($rest:tt)*) => {};
306    (emit I32AtomicRmwSub $($rest:tt)*) => {};
307    (emit I64AtomicRmw8SubU $($rest:tt)*) => {};
308    (emit I64AtomicRmw16SubU $($rest:tt)*) => {};
309    (emit I64AtomicRmw32SubU $($rest:tt)*) => {};
310    (emit I64AtomicRmwSub $($rest:tt)*) => {};
311    (emit I32AtomicRmw8XchgU $($rest:tt)*) => {};
312    (emit I32AtomicRmw16XchgU $($rest:tt)*) => {};
313    (emit I32AtomicRmwXchg $($rest:tt)*) => {};
314    (emit I64AtomicRmw8XchgU $($rest:tt)*) => {};
315    (emit I64AtomicRmw16XchgU $($rest:tt)*) => {};
316    (emit I64AtomicRmw32XchgU $($rest:tt)*) => {};
317    (emit I64AtomicRmwXchg $($rest:tt)*) => {};
318    (emit I8x16ExtractLaneS $($rest:tt)*) => {};
319    (emit I8x16ExtractLaneU $($rest:tt)*) => {};
320    (emit I16x8ExtractLaneS $($rest:tt)*) => {};
321    (emit I16x8ExtractLaneU $($rest:tt)*) => {};
322    (emit I32x4ExtractLane $($rest:tt)*) => {};
323    (emit I64x2ExtractLane $($rest:tt)*) => {};
324    (emit F32x4ExtractLane $($rest:tt)*) => {};
325    (emit F64x2ExtractLane $($rest:tt)*) => {};
326    (emit I32AtomicRmw8AndU $($rest:tt)*) => {};
327    (emit I32AtomicRmw16AndU $($rest:tt)*) => {};
328    (emit I32AtomicRmwAnd $($rest:tt)*) => {};
329    (emit I64AtomicRmw8AndU $($rest:tt)*) => {};
330    (emit I64AtomicRmw16AndU $($rest:tt)*) => {};
331    (emit I64AtomicRmw32AndU $($rest:tt)*) => {};
332    (emit I64AtomicRmwAnd $($rest:tt)*) => {};
333    (emit I32AtomicRmw8OrU $($rest:tt)*) => {};
334    (emit I32AtomicRmw16OrU $($rest:tt)*) => {};
335    (emit I32AtomicRmwOr $($rest:tt)*) => {};
336    (emit I64AtomicRmw8OrU $($rest:tt)*) => {};
337    (emit I64AtomicRmw16OrU $($rest:tt)*) => {};
338    (emit I64AtomicRmw32OrU $($rest:tt)*) => {};
339    (emit I64AtomicRmwOr $($rest:tt)*) => {};
340    (emit I32AtomicRmw8XorU $($rest:tt)*) => {};
341    (emit I32AtomicRmw16XorU $($rest:tt)*) => {};
342    (emit I32AtomicRmwXor $($rest:tt)*) => {};
343    (emit I64AtomicRmw8XorU $($rest:tt)*) => {};
344    (emit I64AtomicRmw16XorU $($rest:tt)*) => {};
345    (emit I64AtomicRmw32XorU $($rest:tt)*) => {};
346    (emit I64AtomicRmwXor $($rest:tt)*) => {};
347    (emit I8x16ReplaceLane $($rest:tt)*) => {};
348    (emit I16x8ReplaceLane $($rest:tt)*) => {};
349    (emit I32x4ReplaceLane $($rest:tt)*) => {};
350    (emit I64x2ReplaceLane $($rest:tt)*) => {};
351    (emit F32x4ReplaceLane $($rest:tt)*) => {};
352    (emit F64x2ReplaceLane $($rest:tt)*) => {};
353    (emit I32AtomicRmw8CmpxchgU $($rest:tt)*) => {};
354    (emit I32AtomicRmw16CmpxchgU $($rest:tt)*) => {};
355    (emit I32AtomicRmwCmpxchg $($rest:tt)*) => {};
356    (emit I64AtomicRmw8CmpxchgU $($rest:tt)*) => {};
357    (emit I64AtomicRmw16CmpxchgU $($rest:tt)*) => {};
358    (emit I64AtomicRmw32CmpxchgU $($rest:tt)*) => {};
359    (emit I64AtomicRmwCmpxchg $($rest:tt)*) => {};
360    (emit I8x16Eq $($rest:tt)*) => {};
361    (emit I16x8Eq $($rest:tt)*) => {};
362    (emit I32x4Eq $($rest:tt)*) => {};
363    (emit I64x2Eq $($rest:tt)*) => {};
364    (emit F32x4Eq $($rest:tt)*) => {};
365    (emit F64x2Eq $($rest:tt)*) => {};
366    (emit I8x16Ne $($rest:tt)*) => {};
367    (emit I16x8Ne $($rest:tt)*) => {};
368    (emit I32x4Ne $($rest:tt)*) => {};
369    (emit I64x2Ne $($rest:tt)*) => {};
370    (emit F32x4Ne $($rest:tt)*) => {};
371    (emit F64x2Ne $($rest:tt)*) => {};
372    (emit I8x16LtS $($rest:tt)*) => {};
373    (emit I8x16LtU $($rest:tt)*) => {};
374    (emit I16x8LtS $($rest:tt)*) => {};
375    (emit I16x8LtU $($rest:tt)*) => {};
376    (emit I32x4LtS $($rest:tt)*) => {};
377    (emit I32x4LtU $($rest:tt)*) => {};
378    (emit I64x2LtS $($rest:tt)*) => {};
379    (emit F32x4Lt $($rest:tt)*) => {};
380    (emit F64x2Lt $($rest:tt)*) => {};
381    (emit I8x16LeS $($rest:tt)*) => {};
382    (emit I8x16LeU $($rest:tt)*) => {};
383    (emit I16x8LeS $($rest:tt)*) => {};
384    (emit I16x8LeU $($rest:tt)*) => {};
385    (emit I32x4LeS $($rest:tt)*) => {};
386    (emit I32x4LeU $($rest:tt)*) => {};
387    (emit I64x2LeS $($rest:tt)*) => {};
388    (emit F32x4Le $($rest:tt)*) => {};
389    (emit F64x2Le $($rest:tt)*) => {};
390    (emit I8x16GtS $($rest:tt)*) => {};
391    (emit I8x16GtU $($rest:tt)*) => {};
392    (emit I16x8GtS $($rest:tt)*) => {};
393    (emit I16x8GtU $($rest:tt)*) => {};
394    (emit I32x4GtS $($rest:tt)*) => {};
395    (emit I32x4GtU $($rest:tt)*) => {};
396    (emit I64x2GtS $($rest:tt)*) => {};
397    (emit F32x4Gt $($rest:tt)*) => {};
398    (emit F64x2Gt $($rest:tt)*) => {};
399    (emit I8x16GeS $($rest:tt)*) => {};
400    (emit I8x16GeU $($rest:tt)*) => {};
401    (emit I16x8GeS $($rest:tt)*) => {};
402    (emit I16x8GeU $($rest:tt)*) => {};
403    (emit I32x4GeS $($rest:tt)*) => {};
404    (emit I32x4GeU $($rest:tt)*) => {};
405    (emit I64x2GeS $($rest:tt)*) => {};
406    (emit F32x4Ge $($rest:tt)*) => {};
407    (emit F64x2Ge $($rest:tt)*) => {};
408    (emit MemoryAtomicWait32 $($rest:tt)*) => {};
409    (emit MemoryAtomicWait64 $($rest:tt)*) => {};
410    (emit MemoryAtomicNotify $($rest:tt)*) => {};
411    (emit AtomicFence $($rest:tt)*) => {};
412    (emit V128Not $($rest:tt)*) => {};
413    (emit V128And $($rest:tt)*) => {};
414    (emit V128AndNot $($rest:tt)*) => {};
415    (emit V128Or $($rest:tt)*) => {};
416    (emit V128Xor $($rest:tt)*) => {};
417    (emit V128Bitselect $($rest:tt)*) => {};
418    (emit V128AnyTrue $($rest:tt)*) => {};
419    (emit V128Load8Lane $($rest:tt)*) => {};
420    (emit V128Load16Lane $($rest:tt)*) => {};
421    (emit V128Load32Lane $($rest:tt)*) => {};
422    (emit V128Load64Lane $($rest:tt)*) => {};
423    (emit V128Store8Lane $($rest:tt)*) => {};
424    (emit V128Store16Lane $($rest:tt)*) => {};
425    (emit V128Store32Lane $($rest:tt)*) => {};
426    (emit V128Store64Lane $($rest:tt)*) => {};
427    (emit F32x4ConvertI32x4S $($rest:tt)*) => {};
428    (emit F32x4ConvertI32x4U $($rest:tt)*) => {};
429    (emit F64x2ConvertLowI32x4S $($rest:tt)*) => {};
430    (emit F64x2ConvertLowI32x4U $($rest:tt)*) => {};
431    (emit I8x16NarrowI16x8S $($rest:tt)*) => {};
432    (emit I8x16NarrowI16x8U $($rest:tt)*) => {};
433    (emit I16x8NarrowI32x4S $($rest:tt)*) => {};
434    (emit I16x8NarrowI32x4U $($rest:tt)*) => {};
435    (emit F32x4DemoteF64x2Zero $($rest:tt)*) => {};
436    (emit F64x2PromoteLowF32x4 $($rest:tt)*) => {};
437    (emit I16x8ExtendLowI8x16S $($rest:tt)*) => {};
438    (emit I16x8ExtendHighI8x16S $($rest:tt)*) => {};
439    (emit I16x8ExtendLowI8x16U $($rest:tt)*) => {};
440    (emit I16x8ExtendHighI8x16U $($rest:tt)*) => {};
441    (emit I32x4ExtendLowI16x8S $($rest:tt)*) => {};
442    (emit I32x4ExtendHighI16x8S $($rest:tt)*) => {};
443    (emit I32x4ExtendLowI16x8U $($rest:tt)*) => {};
444    (emit I32x4ExtendHighI16x8U $($rest:tt)*) => {};
445    (emit I64x2ExtendLowI32x4S $($rest:tt)*) => {};
446    (emit I64x2ExtendHighI32x4S $($rest:tt)*) => {};
447    (emit I64x2ExtendLowI32x4U $($rest:tt)*) => {};
448    (emit I64x2ExtendHighI32x4U $($rest:tt)*) => {};
449    (emit I8x16Add $($rest:tt)*) => {};
450    (emit I16x8Add $($rest:tt)*) => {};
451    (emit I32x4Add $($rest:tt)*) => {};
452    (emit I64x2Add $($rest:tt)*) => {};
453    (emit I8x16Sub $($rest:tt)*) => {};
454    (emit I16x8Sub $($rest:tt)*) => {};
455    (emit I32x4Sub $($rest:tt)*) => {};
456    (emit I64x2Sub $($rest:tt)*) => {};
457    (emit I16x8Mul $($rest:tt)*) => {};
458    (emit I32x4Mul $($rest:tt)*) => {};
459    (emit I64x2Mul $($rest:tt)*) => {};
460    (emit I8x16AddSatS $($rest:tt)*) => {};
461    (emit I16x8AddSatS $($rest:tt)*) => {};
462    (emit I8x16AddSatU $($rest:tt)*) => {};
463    (emit I16x8AddSatU $($rest:tt)*) => {};
464    (emit I8x16SubSatS $($rest:tt)*) => {};
465    (emit I16x8SubSatS $($rest:tt)*) => {};
466    (emit I8x16SubSatU $($rest:tt)*) => {};
467    (emit I16x8SubSatU $($rest:tt)*) => {};
468    (emit I8x16Abs $($rest:tt)*) => {};
469    (emit I16x8Abs $($rest:tt)*) => {};
470    (emit I32x4Abs $($rest:tt)*) => {};
471    (emit I64x2Abs $($rest:tt)*) => {};
472    (emit F32x4Abs $($rest:tt)*) => {};
473    (emit F64x2Abs $($rest:tt)*) => {};
474    (emit I8x16Neg $($rest:tt)*) => {};
475    (emit I16x8Neg $($rest:tt)*) => {};
476    (emit I32x4Neg $($rest:tt)*) => {};
477    (emit I64x2Neg $($rest:tt)*) => {};
478    (emit I8x16Shl $($rest:tt)*) => {};
479    (emit I16x8Shl $($rest:tt)*) => {};
480    (emit I32x4Shl $($rest:tt)*) => {};
481    (emit I64x2Shl $($rest:tt)*) => {};
482    (emit I8x16ShrU $($rest:tt)*) => {};
483    (emit I16x8ShrU $($rest:tt)*) => {};
484    (emit I32x4ShrU $($rest:tt)*) => {};
485    (emit I64x2ShrU $($rest:tt)*) => {};
486    (emit I8x16ShrS $($rest:tt)*) => {};
487    (emit I16x8ShrS $($rest:tt)*) => {};
488    (emit I32x4ShrS $($rest:tt)*) => {};
489    (emit I64x2ShrS $($rest:tt)*) => {};
490    (emit I16x8Q15MulrSatS $($rest:tt)*) => {};
491    (emit I8x16AllTrue $($rest:tt)*) => {};
492    (emit I16x8AllTrue $($rest:tt)*) => {};
493    (emit I32x4AllTrue $($rest:tt)*) => {};
494    (emit I64x2AllTrue $($rest:tt)*) => {};
495    (emit I8x16Bitmask $($rest:tt)*) => {};
496    (emit I16x8Bitmask $($rest:tt)*) => {};
497    (emit I32x4Bitmask $($rest:tt)*) => {};
498    (emit I64x2Bitmask $($rest:tt)*) => {};
499    (emit I32x4TruncSatF32x4S $($rest:tt)*) => {};
500    (emit I32x4TruncSatF32x4U $($rest:tt)*) => {};
501    (emit I32x4TruncSatF64x2SZero $($rest:tt)*) => {};
502    (emit I32x4TruncSatF64x2UZero $($rest:tt)*) => {};
503    (emit I8x16MinU $($rest:tt)*) => {};
504    (emit I16x8MinU $($rest:tt)*) => {};
505    (emit I32x4MinU $($rest:tt)*) => {};
506    (emit I8x16MinS $($rest:tt)*) => {};
507    (emit I16x8MinS $($rest:tt)*) => {};
508    (emit I32x4MinS $($rest:tt)*) => {};
509    (emit I8x16MaxU $($rest:tt)*) => {};
510    (emit I16x8MaxU $($rest:tt)*) => {};
511    (emit I32x4MaxU $($rest:tt)*) => {};
512    (emit I8x16MaxS $($rest:tt)*) => {};
513    (emit I16x8MaxS $($rest:tt)*) => {};
514    (emit I32x4MaxS $($rest:tt)*) => {};
515    (emit I16x8ExtMulLowI8x16S $($rest:tt)*) => {};
516    (emit I32x4ExtMulLowI16x8S $($rest:tt)*) => {};
517    (emit I64x2ExtMulLowI32x4S $($rest:tt)*) => {};
518    (emit I16x8ExtMulHighI8x16S $($rest:tt)*) => {};
519    (emit I32x4ExtMulHighI16x8S $($rest:tt)*) => {};
520    (emit I64x2ExtMulHighI32x4S $($rest:tt)*) => {};
521    (emit I16x8ExtMulLowI8x16U $($rest:tt)*) => {};
522    (emit I32x4ExtMulLowI16x8U $($rest:tt)*) => {};
523    (emit I64x2ExtMulLowI32x4U $($rest:tt)*) => {};
524    (emit I16x8ExtMulHighI8x16U $($rest:tt)*) => {};
525    (emit I32x4ExtMulHighI16x8U $($rest:tt)*) => {};
526    (emit I64x2ExtMulHighI32x4U $($rest:tt)*) => {};
527    (emit I16x8ExtAddPairwiseI8x16U $($rest:tt)*) => {};
528    (emit I16x8ExtAddPairwiseI8x16S $($rest:tt)*) => {};
529    (emit I32x4ExtAddPairwiseI16x8U $($rest:tt)*) => {};
530    (emit I32x4ExtAddPairwiseI16x8S $($rest:tt)*) => {};
531    (emit I32x4DotI16x8S $($rest:tt)*) => {};
532    (emit I8x16Popcnt $($rest:tt)*) => {};
533    (emit I8x16AvgrU $($rest:tt)*) => {};
534    (emit I16x8AvgrU $($rest:tt)*) => {};
535    (emit F32x4Add $($rest:tt)*) => {};
536    (emit F64x2Add $($rest:tt)*) => {};
537    (emit F32x4Sub $($rest:tt)*) => {};
538    (emit F64x2Sub $($rest:tt)*) => {};
539    (emit F32x4Mul $($rest:tt)*) => {};
540    (emit F64x2Mul $($rest:tt)*) => {};
541    (emit F32x4Div $($rest:tt)*) => {};
542    (emit F64x2Div $($rest:tt)*) => {};
543    (emit F32x4Neg $($rest:tt)*) => {};
544    (emit F64x2Neg $($rest:tt)*) => {};
545    (emit F32x4Sqrt $($rest:tt)*) => {};
546    (emit F64x2Sqrt $($rest:tt)*) => {};
547    (emit F32x4Ceil $($rest:tt)*) => {};
548    (emit F64x2Ceil $($rest:tt)*) => {};
549    (emit F32x4Floor $($rest:tt)*) => {};
550    (emit F64x2Floor $($rest:tt)*) => {};
551    (emit F32x4Nearest $($rest:tt)*) => {};
552    (emit F64x2Nearest $($rest:tt)*) => {};
553    (emit F32x4Trunc $($rest:tt)*) => {};
554    (emit F64x2Trunc $($rest:tt)*) => {};
555    (emit V128Load32Zero $($rest:tt)*) => {};
556    (emit V128Load64Zero $($rest:tt)*) => {};
557    (emit F32x4PMin $($rest:tt)*) => {};
558    (emit F64x2PMin $($rest:tt)*) => {};
559    (emit F32x4PMax $($rest:tt)*) => {};
560    (emit F64x2PMax $($rest:tt)*) => {};
561    (emit F32x4Min $($rest:tt)*) => {};
562    (emit F64x2Min $($rest:tt)*) => {};
563    (emit F32x4Max $($rest:tt)*) => {};
564    (emit F64x2Max $($rest:tt)*) => {};
565
566    (emit $unsupported:tt $($rest:tt)*) => {$($rest)*};
567}
568
569impl<'a, 'translation, 'data, M> VisitOperator<'a> for CodeGen<'a, 'translation, 'data, M, Emission>
570where
571    M: MacroAssembler,
572{
573    type Output = Result<()>;
574
575    fn visit_i32_const(&mut self, val: i32) -> Self::Output {
576        self.context.stack.push(Val::i32(val));
577
578        Ok(())
579    }
580
581    fn visit_i64_const(&mut self, val: i64) -> Self::Output {
582        self.context.stack.push(Val::i64(val));
583        Ok(())
584    }
585
586    fn visit_f32_const(&mut self, val: Ieee32) -> Self::Output {
587        self.context.stack.push(Val::f32(val));
588        Ok(())
589    }
590
591    fn visit_f64_const(&mut self, val: Ieee64) -> Self::Output {
592        self.context.stack.push(Val::f64(val));
593        Ok(())
594    }
595
596    fn visit_f32_add(&mut self) -> Self::Output {
597        self.context.binop(
598            self.masm,
599            OperandSize::S32,
600            &mut |masm: &mut M, dst, src, size| {
601                masm.float_add(writable!(dst), dst, src, size)?;
602                masm.maybe_canonicalize_nan(writable!(dst), size)?;
603                Ok(TypedReg::f32(dst))
604            },
605        )
606    }
607
608    fn visit_f64_add(&mut self) -> Self::Output {
609        self.context.binop(
610            self.masm,
611            OperandSize::S64,
612            &mut |masm: &mut M, dst, src, size| {
613                masm.float_add(writable!(dst), dst, src, size)?;
614                masm.maybe_canonicalize_nan(writable!(dst), size)?;
615                Ok(TypedReg::f64(dst))
616            },
617        )
618    }
619
620    fn visit_f32_sub(&mut self) -> Self::Output {
621        self.context.binop(
622            self.masm,
623            OperandSize::S32,
624            &mut |masm: &mut M, dst, src, size| {
625                masm.float_sub(writable!(dst), dst, src, size)?;
626                masm.maybe_canonicalize_nan(writable!(dst), size)?;
627                Ok(TypedReg::f32(dst))
628            },
629        )
630    }
631
632    fn visit_f64_sub(&mut self) -> Self::Output {
633        self.context.binop(
634            self.masm,
635            OperandSize::S64,
636            &mut |masm: &mut M, dst, src, size| {
637                masm.float_sub(writable!(dst), dst, src, size)?;
638                masm.maybe_canonicalize_nan(writable!(dst), size)?;
639                Ok(TypedReg::f64(dst))
640            },
641        )
642    }
643
644    fn visit_f32_mul(&mut self) -> Self::Output {
645        self.context.binop(
646            self.masm,
647            OperandSize::S32,
648            &mut |masm: &mut M, dst, src, size| {
649                masm.float_mul(writable!(dst), dst, src, size)?;
650                masm.maybe_canonicalize_nan(writable!(dst), size)?;
651                Ok(TypedReg::f32(dst))
652            },
653        )
654    }
655
656    fn visit_f64_mul(&mut self) -> Self::Output {
657        self.context.binop(
658            self.masm,
659            OperandSize::S64,
660            &mut |masm: &mut M, dst, src, size| {
661                masm.float_mul(writable!(dst), dst, src, size)?;
662                masm.maybe_canonicalize_nan(writable!(dst), size)?;
663                Ok(TypedReg::f64(dst))
664            },
665        )
666    }
667
668    fn visit_f32_div(&mut self) -> Self::Output {
669        self.context.binop(
670            self.masm,
671            OperandSize::S32,
672            &mut |masm: &mut M, dst, src, size| {
673                masm.float_div(writable!(dst), dst, src, size)?;
674                masm.maybe_canonicalize_nan(writable!(dst), size)?;
675                Ok(TypedReg::f32(dst))
676            },
677        )
678    }
679
680    fn visit_f64_div(&mut self) -> Self::Output {
681        self.context.binop(
682            self.masm,
683            OperandSize::S64,
684            &mut |masm: &mut M, dst, src, size| {
685                masm.float_div(writable!(dst), dst, src, size)?;
686                masm.maybe_canonicalize_nan(writable!(dst), size)?;
687                Ok(TypedReg::f64(dst))
688            },
689        )
690    }
691
692    fn visit_f32_min(&mut self) -> Self::Output {
693        self.context.binop(
694            self.masm,
695            OperandSize::S32,
696            &mut |masm: &mut M, dst, src, size| {
697                masm.float_min(writable!(dst), dst, src, size)?;
698                masm.maybe_canonicalize_nan(writable!(dst), size)?;
699                Ok(TypedReg::f32(dst))
700            },
701        )
702    }
703
704    fn visit_f64_min(&mut self) -> Self::Output {
705        self.context.binop(
706            self.masm,
707            OperandSize::S64,
708            &mut |masm: &mut M, dst, src, size| {
709                masm.float_min(writable!(dst), dst, src, size)?;
710                masm.maybe_canonicalize_nan(writable!(dst), size)?;
711                Ok(TypedReg::f64(dst))
712            },
713        )
714    }
715
716    fn visit_f32_max(&mut self) -> Self::Output {
717        self.context.binop(
718            self.masm,
719            OperandSize::S32,
720            &mut |masm: &mut M, dst, src, size| {
721                masm.float_max(writable!(dst), dst, src, size)?;
722                masm.maybe_canonicalize_nan(writable!(dst), size)?;
723                Ok(TypedReg::f32(dst))
724            },
725        )
726    }
727
728    fn visit_f64_max(&mut self) -> Self::Output {
729        self.context.binop(
730            self.masm,
731            OperandSize::S64,
732            &mut |masm: &mut M, dst, src, size| {
733                masm.float_max(writable!(dst), dst, src, size)?;
734                masm.maybe_canonicalize_nan(writable!(dst), size)?;
735                Ok(TypedReg::f64(dst))
736            },
737        )
738    }
739
740    fn visit_f32_copysign(&mut self) -> Self::Output {
741        self.context.binop(
742            self.masm,
743            OperandSize::S32,
744            &mut |masm: &mut M, dst, src, size| {
745                masm.float_copysign(writable!(dst), dst, src, size)?;
746                Ok(TypedReg::f32(dst))
747            },
748        )
749    }
750
751    fn visit_f64_copysign(&mut self) -> Self::Output {
752        self.context.binop(
753            self.masm,
754            OperandSize::S64,
755            &mut |masm: &mut M, dst, src, size| {
756                masm.float_copysign(writable!(dst), dst, src, size)?;
757                Ok(TypedReg::f64(dst))
758            },
759        )
760    }
761
762    fn visit_f32_abs(&mut self) -> Self::Output {
763        self.context.unop(self.masm, |masm, reg| {
764            masm.float_abs(writable!(reg), OperandSize::S32)?;
765            Ok(TypedReg::f32(reg))
766        })
767    }
768
769    fn visit_f64_abs(&mut self) -> Self::Output {
770        self.context.unop(self.masm, |masm, reg| {
771            masm.float_abs(writable!(reg), OperandSize::S64)?;
772            Ok(TypedReg::f64(reg))
773        })
774    }
775
776    fn visit_f32_neg(&mut self) -> Self::Output {
777        self.context.unop(self.masm, |masm, reg| {
778            masm.float_neg(writable!(reg), OperandSize::S32)?;
779            Ok(TypedReg::f32(reg))
780        })
781    }
782
783    fn visit_f64_neg(&mut self) -> Self::Output {
784        self.context.unop(self.masm, |masm, reg| {
785            masm.float_neg(writable!(reg), OperandSize::S64)?;
786            Ok(TypedReg::f64(reg))
787        })
788    }
789
790    fn visit_f32_floor(&mut self) -> Self::Output {
791        self.masm.float_round(
792            RoundingMode::Down,
793            &mut self.env,
794            &mut self.context,
795            OperandSize::S32,
796            |env, cx, masm| {
797                let builtin = env.builtins.floor_f32::<M::ABI>()?;
798                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
799            },
800        )?;
801        let result = self.context.pop_to_reg(self.masm, None)?;
802        self.masm
803            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S32)?;
804        self.context.stack.push(result.into());
805        Ok(())
806    }
807
808    fn visit_f64_floor(&mut self) -> Self::Output {
809        self.masm.float_round(
810            RoundingMode::Down,
811            &mut self.env,
812            &mut self.context,
813            OperandSize::S64,
814            |env, cx, masm| {
815                let builtin = env.builtins.floor_f64::<M::ABI>()?;
816                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
817            },
818        )?;
819        let result = self.context.pop_to_reg(self.masm, None)?;
820        self.masm
821            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S64)?;
822        self.context.stack.push(result.into());
823        Ok(())
824    }
825
826    fn visit_f32_ceil(&mut self) -> Self::Output {
827        self.masm.float_round(
828            RoundingMode::Up,
829            &mut self.env,
830            &mut self.context,
831            OperandSize::S32,
832            |env, cx, masm| {
833                let builtin = env.builtins.ceil_f32::<M::ABI>()?;
834                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
835            },
836        )?;
837        let result = self.context.pop_to_reg(self.masm, None)?;
838        self.masm
839            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S32)?;
840        self.context.stack.push(result.into());
841        Ok(())
842    }
843
844    fn visit_f64_ceil(&mut self) -> Self::Output {
845        self.masm.float_round(
846            RoundingMode::Up,
847            &mut self.env,
848            &mut self.context,
849            OperandSize::S64,
850            |env, cx, masm| {
851                let builtin = env.builtins.ceil_f64::<M::ABI>()?;
852                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
853            },
854        )?;
855        let result = self.context.pop_to_reg(self.masm, None)?;
856        self.masm
857            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S64)?;
858        self.context.stack.push(result.into());
859        Ok(())
860    }
861
862    fn visit_f32_nearest(&mut self) -> Self::Output {
863        self.masm.float_round(
864            RoundingMode::Nearest,
865            &mut self.env,
866            &mut self.context,
867            OperandSize::S32,
868            |env, cx, masm| {
869                let builtin = env.builtins.nearest_f32::<M::ABI>()?;
870                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
871            },
872        )?;
873        let result = self.context.pop_to_reg(self.masm, None)?;
874        self.masm
875            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S32)?;
876        self.context.stack.push(result.into());
877        Ok(())
878    }
879
880    fn visit_f64_nearest(&mut self) -> Self::Output {
881        self.masm.float_round(
882            RoundingMode::Nearest,
883            &mut self.env,
884            &mut self.context,
885            OperandSize::S64,
886            |env, cx, masm| {
887                let builtin = env.builtins.nearest_f64::<M::ABI>()?;
888                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
889            },
890        )?;
891        let result = self.context.pop_to_reg(self.masm, None)?;
892        self.masm
893            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S64)?;
894        self.context.stack.push(result.into());
895        Ok(())
896    }
897
898    fn visit_f32_trunc(&mut self) -> Self::Output {
899        self.masm.float_round(
900            RoundingMode::Zero,
901            &mut self.env,
902            &mut self.context,
903            OperandSize::S32,
904            |env, cx, masm| {
905                let builtin = env.builtins.trunc_f32::<M::ABI>()?;
906                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
907            },
908        )?;
909        let result = self.context.pop_to_reg(self.masm, None)?;
910        self.masm
911            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S32)?;
912        self.context.stack.push(result.into());
913        Ok(())
914    }
915
916    fn visit_f64_trunc(&mut self) -> Self::Output {
917        self.masm.float_round(
918            RoundingMode::Zero,
919            &mut self.env,
920            &mut self.context,
921            OperandSize::S64,
922            |env, cx, masm| {
923                let builtin = env.builtins.trunc_f64::<M::ABI>()?;
924                FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin))
925            },
926        )?;
927        let result = self.context.pop_to_reg(self.masm, None)?;
928        self.masm
929            .maybe_canonicalize_nan(writable!(result.into()), OperandSize::S64)?;
930        self.context.stack.push(result.into());
931        Ok(())
932    }
933
934    fn visit_f32_sqrt(&mut self) -> Self::Output {
935        self.context.unop(self.masm, |masm, reg| {
936            masm.float_sqrt(writable!(reg), reg, OperandSize::S32)?;
937            masm.maybe_canonicalize_nan(writable!(reg), OperandSize::S32)?;
938            Ok(TypedReg::f32(reg))
939        })
940    }
941
942    fn visit_f64_sqrt(&mut self) -> Self::Output {
943        self.context.unop(self.masm, |masm, reg| {
944            masm.float_sqrt(writable!(reg), reg, OperandSize::S64)?;
945            masm.maybe_canonicalize_nan(writable!(reg), OperandSize::S64)?;
946            Ok(TypedReg::f64(reg))
947        })
948    }
949
950    fn visit_f32_eq(&mut self) -> Self::Output {
951        self.context.float_cmp_op(
952            self.masm,
953            OperandSize::S32,
954            &mut |masm: &mut M, dst, src1, src2, size| {
955                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Eq, size)
956            },
957        )
958    }
959
960    fn visit_f64_eq(&mut self) -> Self::Output {
961        self.context.float_cmp_op(
962            self.masm,
963            OperandSize::S64,
964            &mut |masm: &mut M, dst, src1, src2, size| {
965                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Eq, size)
966            },
967        )
968    }
969
970    fn visit_f32_ne(&mut self) -> Self::Output {
971        self.context.float_cmp_op(
972            self.masm,
973            OperandSize::S32,
974            &mut |masm: &mut M, dst, src1, src2, size| {
975                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ne, size)
976            },
977        )
978    }
979
980    fn visit_f64_ne(&mut self) -> Self::Output {
981        self.context.float_cmp_op(
982            self.masm,
983            OperandSize::S64,
984            &mut |masm: &mut M, dst, src1, src2, size| {
985                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ne, size)
986            },
987        )
988    }
989
990    fn visit_f32_lt(&mut self) -> Self::Output {
991        self.context.float_cmp_op(
992            self.masm,
993            OperandSize::S32,
994            &mut |masm: &mut M, dst, src1, src2, size| {
995                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Lt, size)
996            },
997        )
998    }
999
1000    fn visit_f64_lt(&mut self) -> Self::Output {
1001        self.context.float_cmp_op(
1002            self.masm,
1003            OperandSize::S64,
1004            &mut |masm: &mut M, dst, src1, src2, size| {
1005                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Lt, size)
1006            },
1007        )
1008    }
1009
1010    fn visit_f32_gt(&mut self) -> Self::Output {
1011        self.context.float_cmp_op(
1012            self.masm,
1013            OperandSize::S32,
1014            &mut |masm: &mut M, dst, src1, src2, size| {
1015                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Gt, size)
1016            },
1017        )
1018    }
1019
1020    fn visit_f64_gt(&mut self) -> Self::Output {
1021        self.context.float_cmp_op(
1022            self.masm,
1023            OperandSize::S64,
1024            &mut |masm: &mut M, dst, src1, src2, size| {
1025                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Gt, size)
1026            },
1027        )
1028    }
1029
1030    fn visit_f32_le(&mut self) -> Self::Output {
1031        self.context.float_cmp_op(
1032            self.masm,
1033            OperandSize::S32,
1034            &mut |masm: &mut M, dst, src1, src2, size| {
1035                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Le, size)
1036            },
1037        )
1038    }
1039
1040    fn visit_f64_le(&mut self) -> Self::Output {
1041        self.context.float_cmp_op(
1042            self.masm,
1043            OperandSize::S64,
1044            &mut |masm: &mut M, dst, src1, src2, size| {
1045                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Le, size)
1046            },
1047        )
1048    }
1049
1050    fn visit_f32_ge(&mut self) -> Self::Output {
1051        self.context.float_cmp_op(
1052            self.masm,
1053            OperandSize::S32,
1054            &mut |masm: &mut M, dst, src1, src2, size| {
1055                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ge, size)
1056            },
1057        )
1058    }
1059
1060    fn visit_f64_ge(&mut self) -> Self::Output {
1061        self.context.float_cmp_op(
1062            self.masm,
1063            OperandSize::S64,
1064            &mut |masm: &mut M, dst, src1, src2, size| {
1065                masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ge, size)
1066            },
1067        )
1068    }
1069
1070    fn visit_f32_convert_i32_s(&mut self) -> Self::Output {
1071        self.context
1072            .convert_op(self.masm, WasmValType::F32, |masm, dst, src, dst_size| {
1073                masm.signed_convert(writable!(dst), src, OperandSize::S32, dst_size)
1074            })
1075    }
1076
1077    fn visit_f32_convert_i32_u(&mut self) -> Self::Output {
1078        self.context.convert_op_with_tmp_reg(
1079            self.masm,
1080            WasmValType::F32,
1081            RegClass::Int,
1082            |masm, dst, src, tmp_gpr, dst_size| {
1083                masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S32, dst_size)
1084            },
1085        )
1086    }
1087
1088    fn visit_f32_convert_i64_s(&mut self) -> Self::Output {
1089        self.context
1090            .convert_op(self.masm, WasmValType::F32, |masm, dst, src, dst_size| {
1091                masm.signed_convert(writable!(dst), src, OperandSize::S64, dst_size)
1092            })
1093    }
1094
1095    fn visit_f32_convert_i64_u(&mut self) -> Self::Output {
1096        self.context.convert_op_with_tmp_reg(
1097            self.masm,
1098            WasmValType::F32,
1099            RegClass::Int,
1100            |masm, dst, src, tmp_gpr, dst_size| {
1101                masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S64, dst_size)
1102            },
1103        )
1104    }
1105
1106    fn visit_f64_convert_i32_s(&mut self) -> Self::Output {
1107        self.context
1108            .convert_op(self.masm, WasmValType::F64, |masm, dst, src, dst_size| {
1109                masm.signed_convert(writable!(dst), src, OperandSize::S32, dst_size)
1110            })
1111    }
1112
1113    fn visit_f64_convert_i32_u(&mut self) -> Self::Output {
1114        self.context.convert_op_with_tmp_reg(
1115            self.masm,
1116            WasmValType::F64,
1117            RegClass::Int,
1118            |masm, dst, src, tmp_gpr, dst_size| {
1119                masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S32, dst_size)
1120            },
1121        )
1122    }
1123
1124    fn visit_f64_convert_i64_s(&mut self) -> Self::Output {
1125        self.context
1126            .convert_op(self.masm, WasmValType::F64, |masm, dst, src, dst_size| {
1127                masm.signed_convert(writable!(dst), src, OperandSize::S64, dst_size)
1128            })
1129    }
1130
1131    fn visit_f64_convert_i64_u(&mut self) -> Self::Output {
1132        self.context.convert_op_with_tmp_reg(
1133            self.masm,
1134            WasmValType::F64,
1135            RegClass::Int,
1136            |masm, dst, src, tmp_gpr, dst_size| {
1137                masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S64, dst_size)
1138            },
1139        )
1140    }
1141
1142    fn visit_f32_reinterpret_i32(&mut self) -> Self::Output {
1143        self.context
1144            .convert_op(self.masm, WasmValType::F32, |masm, dst, src, size| {
1145                masm.reinterpret_int_as_float(writable!(dst), src, size)
1146            })
1147    }
1148
1149    fn visit_f64_reinterpret_i64(&mut self) -> Self::Output {
1150        self.context
1151            .convert_op(self.masm, WasmValType::F64, |masm, dst, src, size| {
1152                masm.reinterpret_int_as_float(writable!(dst), src, size)
1153            })
1154    }
1155
1156    fn visit_f32_demote_f64(&mut self) -> Self::Output {
1157        self.context.unop(self.masm, |masm, reg| {
1158            masm.demote(writable!(reg), reg)?;
1159            masm.maybe_canonicalize_nan(writable!(reg), OperandSize::S32)?;
1160            Ok(TypedReg::f32(reg))
1161        })
1162    }
1163
1164    fn visit_f64_promote_f32(&mut self) -> Self::Output {
1165        self.context.unop(self.masm, |masm, reg| {
1166            masm.promote(writable!(reg), reg)?;
1167            masm.maybe_canonicalize_nan(writable!(reg), OperandSize::S64)?;
1168            Ok(TypedReg::f64(reg))
1169        })
1170    }
1171
1172    fn visit_i32_add(&mut self) -> Self::Output {
1173        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1174            masm.add(writable!(dst), dst, src, size)?;
1175            Ok(TypedReg::i32(dst))
1176        })
1177    }
1178
1179    fn visit_i64_add(&mut self) -> Self::Output {
1180        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1181            masm.add(writable!(dst), dst, src, size)?;
1182            Ok(TypedReg::i64(dst))
1183        })
1184    }
1185
1186    fn visit_i32_sub(&mut self) -> Self::Output {
1187        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1188            masm.sub(writable!(dst), dst, src, size)?;
1189            Ok(TypedReg::i32(dst))
1190        })
1191    }
1192
1193    fn visit_i64_sub(&mut self) -> Self::Output {
1194        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1195            masm.sub(writable!(dst), dst, src, size)?;
1196            Ok(TypedReg::i64(dst))
1197        })
1198    }
1199
1200    fn visit_i32_mul(&mut self) -> Self::Output {
1201        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1202            masm.mul(writable!(dst), dst, src, size)?;
1203            Ok(TypedReg::i32(dst))
1204        })
1205    }
1206
1207    fn visit_i64_mul(&mut self) -> Self::Output {
1208        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1209            masm.mul(writable!(dst), dst, src, size)?;
1210            Ok(TypedReg::i64(dst))
1211        })
1212    }
1213
1214    fn visit_i32_div_s(&mut self) -> Self::Output {
1215        use DivKind::*;
1216        use OperandSize::*;
1217
1218        self.masm.div(&mut self.context, Signed, S32)
1219    }
1220
1221    fn visit_i32_div_u(&mut self) -> Self::Output {
1222        use DivKind::*;
1223        use OperandSize::*;
1224
1225        self.masm.div(&mut self.context, Unsigned, S32)
1226    }
1227
1228    fn visit_i64_div_s(&mut self) -> Self::Output {
1229        use DivKind::*;
1230        use OperandSize::*;
1231
1232        self.masm.div(&mut self.context, Signed, S64)
1233    }
1234
1235    fn visit_i64_div_u(&mut self) -> Self::Output {
1236        use DivKind::*;
1237        use OperandSize::*;
1238
1239        self.masm.div(&mut self.context, Unsigned, S64)
1240    }
1241
1242    fn visit_i32_rem_s(&mut self) -> Self::Output {
1243        use OperandSize::*;
1244        use RemKind::*;
1245
1246        self.masm.rem(&mut self.context, Signed, S32)
1247    }
1248
1249    fn visit_i32_rem_u(&mut self) -> Self::Output {
1250        use OperandSize::*;
1251        use RemKind::*;
1252
1253        self.masm.rem(&mut self.context, Unsigned, S32)
1254    }
1255
1256    fn visit_i64_rem_s(&mut self) -> Self::Output {
1257        use OperandSize::*;
1258        use RemKind::*;
1259
1260        self.masm.rem(&mut self.context, Signed, S64)
1261    }
1262
1263    fn visit_i64_rem_u(&mut self) -> Self::Output {
1264        use OperandSize::*;
1265        use RemKind::*;
1266
1267        self.masm.rem(&mut self.context, Unsigned, S64)
1268    }
1269
1270    fn visit_i32_eq(&mut self) -> Self::Output {
1271        self.cmp_i32s(IntCmpKind::Eq)
1272    }
1273
1274    fn visit_i64_eq(&mut self) -> Self::Output {
1275        self.cmp_i64s(IntCmpKind::Eq)
1276    }
1277
1278    fn visit_i32_ne(&mut self) -> Self::Output {
1279        self.cmp_i32s(IntCmpKind::Ne)
1280    }
1281
1282    fn visit_i64_ne(&mut self) -> Self::Output {
1283        self.cmp_i64s(IntCmpKind::Ne)
1284    }
1285
1286    fn visit_i32_lt_s(&mut self) -> Self::Output {
1287        self.cmp_i32s(IntCmpKind::LtS)
1288    }
1289
1290    fn visit_i64_lt_s(&mut self) -> Self::Output {
1291        self.cmp_i64s(IntCmpKind::LtS)
1292    }
1293
1294    fn visit_i32_lt_u(&mut self) -> Self::Output {
1295        self.cmp_i32s(IntCmpKind::LtU)
1296    }
1297
1298    fn visit_i64_lt_u(&mut self) -> Self::Output {
1299        self.cmp_i64s(IntCmpKind::LtU)
1300    }
1301
1302    fn visit_i32_le_s(&mut self) -> Self::Output {
1303        self.cmp_i32s(IntCmpKind::LeS)
1304    }
1305
1306    fn visit_i64_le_s(&mut self) -> Self::Output {
1307        self.cmp_i64s(IntCmpKind::LeS)
1308    }
1309
1310    fn visit_i32_le_u(&mut self) -> Self::Output {
1311        self.cmp_i32s(IntCmpKind::LeU)
1312    }
1313
1314    fn visit_i64_le_u(&mut self) -> Self::Output {
1315        self.cmp_i64s(IntCmpKind::LeU)
1316    }
1317
1318    fn visit_i32_gt_s(&mut self) -> Self::Output {
1319        self.cmp_i32s(IntCmpKind::GtS)
1320    }
1321
1322    fn visit_i64_gt_s(&mut self) -> Self::Output {
1323        self.cmp_i64s(IntCmpKind::GtS)
1324    }
1325
1326    fn visit_i32_gt_u(&mut self) -> Self::Output {
1327        self.cmp_i32s(IntCmpKind::GtU)
1328    }
1329
1330    fn visit_i64_gt_u(&mut self) -> Self::Output {
1331        self.cmp_i64s(IntCmpKind::GtU)
1332    }
1333
1334    fn visit_i32_ge_s(&mut self) -> Self::Output {
1335        self.cmp_i32s(IntCmpKind::GeS)
1336    }
1337
1338    fn visit_i64_ge_s(&mut self) -> Self::Output {
1339        self.cmp_i64s(IntCmpKind::GeS)
1340    }
1341
1342    fn visit_i32_ge_u(&mut self) -> Self::Output {
1343        self.cmp_i32s(IntCmpKind::GeU)
1344    }
1345
1346    fn visit_i64_ge_u(&mut self) -> Self::Output {
1347        self.cmp_i64s(IntCmpKind::GeU)
1348    }
1349
1350    fn visit_i32_eqz(&mut self) -> Self::Output {
1351        use OperandSize::*;
1352
1353        self.context.unop(self.masm, |masm, reg| {
1354            masm.cmp_with_set(writable!(reg), RegImm::i32(0), IntCmpKind::Eq, S32)?;
1355            Ok(TypedReg::i32(reg))
1356        })
1357    }
1358
1359    fn visit_i64_eqz(&mut self) -> Self::Output {
1360        use OperandSize::*;
1361
1362        self.context.unop(self.masm, |masm, reg| {
1363            masm.cmp_with_set(writable!(reg), RegImm::i64(0), IntCmpKind::Eq, S64)?;
1364            Ok(TypedReg::i32(reg)) // Return value for `i64.eqz` is an `i32`.
1365        })
1366    }
1367
1368    fn visit_i32_clz(&mut self) -> Self::Output {
1369        use OperandSize::*;
1370
1371        self.context.unop(self.masm, |masm, reg| {
1372            masm.clz(writable!(reg), reg, S32)?;
1373            Ok(TypedReg::i32(reg))
1374        })
1375    }
1376
1377    fn visit_i64_clz(&mut self) -> Self::Output {
1378        use OperandSize::*;
1379
1380        self.context.unop(self.masm, |masm, reg| {
1381            masm.clz(writable!(reg), reg, S64)?;
1382            Ok(TypedReg::i64(reg))
1383        })
1384    }
1385
1386    fn visit_i32_ctz(&mut self) -> Self::Output {
1387        use OperandSize::*;
1388
1389        self.context.unop(self.masm, |masm, reg| {
1390            masm.ctz(writable!(reg), reg, S32)?;
1391            Ok(TypedReg::i32(reg))
1392        })
1393    }
1394
1395    fn visit_i64_ctz(&mut self) -> Self::Output {
1396        use OperandSize::*;
1397
1398        self.context.unop(self.masm, |masm, reg| {
1399            masm.ctz(writable!(reg), reg, S64)?;
1400            Ok(TypedReg::i64(reg))
1401        })
1402    }
1403
1404    fn visit_i32_and(&mut self) -> Self::Output {
1405        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1406            masm.and(writable!(dst), dst, src, size)?;
1407            Ok(TypedReg::i32(dst))
1408        })
1409    }
1410
1411    fn visit_i64_and(&mut self) -> Self::Output {
1412        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1413            masm.and(writable!(dst), dst, src, size)?;
1414            Ok(TypedReg::i64(dst))
1415        })
1416    }
1417
1418    fn visit_i32_or(&mut self) -> Self::Output {
1419        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1420            masm.or(writable!(dst), dst, src, size)?;
1421            Ok(TypedReg::i32(dst))
1422        })
1423    }
1424
1425    fn visit_i64_or(&mut self) -> Self::Output {
1426        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1427            masm.or(writable!(dst), dst, src, size)?;
1428            Ok(TypedReg::i64(dst))
1429        })
1430    }
1431
1432    fn visit_i32_xor(&mut self) -> Self::Output {
1433        self.context.i32_binop(self.masm, |masm, dst, src, size| {
1434            masm.xor(writable!(dst), dst, src, size)?;
1435            Ok(TypedReg::i32(dst))
1436        })
1437    }
1438
1439    fn visit_i64_xor(&mut self) -> Self::Output {
1440        self.context.i64_binop(self.masm, |masm, dst, src, size| {
1441            masm.xor(writable!(dst), dst, src, size)?;
1442            Ok(TypedReg::i64(dst))
1443        })
1444    }
1445
1446    fn visit_i32_shl(&mut self) -> Self::Output {
1447        use ShiftKind::*;
1448
1449        self.context.i32_shift(self.masm, Shl)
1450    }
1451
1452    fn visit_i64_shl(&mut self) -> Self::Output {
1453        use ShiftKind::*;
1454
1455        self.context.i64_shift(self.masm, Shl)
1456    }
1457
1458    fn visit_i32_shr_s(&mut self) -> Self::Output {
1459        use ShiftKind::*;
1460
1461        self.context.i32_shift(self.masm, ShrS)
1462    }
1463
1464    fn visit_i64_shr_s(&mut self) -> Self::Output {
1465        use ShiftKind::*;
1466
1467        self.context.i64_shift(self.masm, ShrS)
1468    }
1469
1470    fn visit_i32_shr_u(&mut self) -> Self::Output {
1471        use ShiftKind::*;
1472
1473        self.context.i32_shift(self.masm, ShrU)
1474    }
1475
1476    fn visit_i64_shr_u(&mut self) -> Self::Output {
1477        use ShiftKind::*;
1478
1479        self.context.i64_shift(self.masm, ShrU)
1480    }
1481
1482    fn visit_i32_rotl(&mut self) -> Self::Output {
1483        use ShiftKind::*;
1484
1485        self.context.i32_shift(self.masm, Rotl)
1486    }
1487
1488    fn visit_i64_rotl(&mut self) -> Self::Output {
1489        use ShiftKind::*;
1490
1491        self.context.i64_shift(self.masm, Rotl)
1492    }
1493
1494    fn visit_i32_rotr(&mut self) -> Self::Output {
1495        use ShiftKind::*;
1496
1497        self.context.i32_shift(self.masm, Rotr)
1498    }
1499
1500    fn visit_i64_rotr(&mut self) -> Self::Output {
1501        use ShiftKind::*;
1502
1503        self.context.i64_shift(self.masm, Rotr)
1504    }
1505
1506    fn visit_end(&mut self) -> Self::Output {
1507        if !self.context.reachable {
1508            self.handle_unreachable_end()
1509        } else {
1510            let mut control = self.pop_control_frame()?;
1511            control.emit_end(self.masm, &mut self.context)
1512        }
1513    }
1514
1515    fn visit_i32_popcnt(&mut self) -> Self::Output {
1516        use OperandSize::*;
1517        self.masm.popcnt(&mut self.context, S32)
1518    }
1519
1520    fn visit_i64_popcnt(&mut self) -> Self::Output {
1521        use OperandSize::*;
1522
1523        self.masm.popcnt(&mut self.context, S64)
1524    }
1525
1526    fn visit_i32_wrap_i64(&mut self) -> Self::Output {
1527        self.context.unop(self.masm, |masm, reg| {
1528            masm.wrap(writable!(reg), reg)?;
1529            Ok(TypedReg::i32(reg))
1530        })
1531    }
1532
1533    fn visit_i64_extend_i32_s(&mut self) -> Self::Output {
1534        self.context.unop(self.masm, |masm, reg| {
1535            masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend32.into())?;
1536            Ok(TypedReg::i64(reg))
1537        })
1538    }
1539
1540    fn visit_i64_extend_i32_u(&mut self) -> Self::Output {
1541        self.context.unop(self.masm, |masm, reg| {
1542            masm.extend(writable!(reg), reg, Extend::<Zero>::I64Extend32.into())?;
1543            Ok(TypedReg::i64(reg))
1544        })
1545    }
1546
1547    fn visit_i32_extend8_s(&mut self) -> Self::Output {
1548        self.context.unop(self.masm, |masm, reg| {
1549            masm.extend(writable!(reg), reg, Extend::<Signed>::I32Extend8.into())?;
1550            Ok(TypedReg::i32(reg))
1551        })
1552    }
1553
1554    fn visit_i32_extend16_s(&mut self) -> Self::Output {
1555        self.context.unop(self.masm, |masm, reg| {
1556            masm.extend(writable!(reg), reg, Extend::<Signed>::I32Extend16.into())?;
1557            Ok(TypedReg::i32(reg))
1558        })
1559    }
1560
1561    fn visit_i64_extend8_s(&mut self) -> Self::Output {
1562        self.context.unop(self.masm, |masm, reg| {
1563            masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend8.into())?;
1564            Ok(TypedReg::i64(reg))
1565        })
1566    }
1567
1568    fn visit_i64_extend16_s(&mut self) -> Self::Output {
1569        self.context.unop(self.masm, |masm, reg| {
1570            masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend16.into())?;
1571            Ok(TypedReg::i64(reg))
1572        })
1573    }
1574
1575    fn visit_i64_extend32_s(&mut self) -> Self::Output {
1576        self.context.unop(self.masm, |masm, reg| {
1577            masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend32.into())?;
1578            Ok(TypedReg::i64(reg))
1579        })
1580    }
1581
1582    fn visit_i32_trunc_f32_s(&mut self) -> Self::Output {
1583        use OperandSize::*;
1584
1585        self.context
1586            .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
1587                masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Unchecked)
1588            })
1589    }
1590
1591    fn visit_i32_trunc_f32_u(&mut self) -> Self::Output {
1592        use OperandSize::*;
1593
1594        self.masm
1595            .unsigned_truncate(&mut self.context, S32, S32, TruncKind::Unchecked)
1596    }
1597
1598    fn visit_i32_trunc_f64_s(&mut self) -> Self::Output {
1599        use OperandSize::*;
1600
1601        self.context
1602            .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
1603                masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Unchecked)
1604            })
1605    }
1606
1607    fn visit_i32_trunc_f64_u(&mut self) -> Self::Output {
1608        use OperandSize::*;
1609        self.masm
1610            .unsigned_truncate(&mut self.context, S64, S32, TruncKind::Unchecked)
1611    }
1612
1613    fn visit_i64_trunc_f32_s(&mut self) -> Self::Output {
1614        use OperandSize::*;
1615
1616        self.context
1617            .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
1618                masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Unchecked)
1619            })
1620    }
1621
1622    fn visit_i64_trunc_f32_u(&mut self) -> Self::Output {
1623        use OperandSize::*;
1624
1625        self.masm
1626            .unsigned_truncate(&mut self.context, S32, S64, TruncKind::Unchecked)
1627    }
1628
1629    fn visit_i64_trunc_f64_s(&mut self) -> Self::Output {
1630        use OperandSize::*;
1631
1632        self.context
1633            .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
1634                masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Unchecked)
1635            })
1636    }
1637
1638    fn visit_i64_trunc_f64_u(&mut self) -> Self::Output {
1639        use OperandSize::*;
1640
1641        self.masm
1642            .unsigned_truncate(&mut self.context, S64, S64, TruncKind::Unchecked)
1643    }
1644
1645    fn visit_i32_reinterpret_f32(&mut self) -> Self::Output {
1646        self.context
1647            .convert_op(self.masm, WasmValType::I32, |masm, dst, src, size| {
1648                masm.reinterpret_float_as_int(writable!(dst), src, size)
1649            })
1650    }
1651
1652    fn visit_i64_reinterpret_f64(&mut self) -> Self::Output {
1653        self.context
1654            .convert_op(self.masm, WasmValType::I64, |masm, dst, src, size| {
1655                masm.reinterpret_float_as_int(writable!(dst), src, size)
1656            })
1657    }
1658
1659    fn visit_local_get(&mut self, index: u32) -> Self::Output {
1660        use WasmValType::*;
1661        let context = &mut self.context;
1662        let slot = context.frame.get_wasm_local(index);
1663        match slot.ty {
1664            I32 | I64 | F32 | F64 | V128 => context.stack.push(Val::local(index, slot.ty)),
1665            Ref(rt) => match rt.heap_type {
1666                WasmHeapType::Func => context.stack.push(Val::local(index, slot.ty)),
1667                _ => bail!(CodeGenError::unsupported_wasm_type()),
1668            },
1669        }
1670
1671        Ok(())
1672    }
1673
1674    fn visit_local_set(&mut self, index: u32) -> Self::Output {
1675        let src = self.emit_set_local(index)?;
1676        self.context.free_reg(src);
1677        Ok(())
1678    }
1679
1680    fn visit_call(&mut self, index: u32) -> Self::Output {
1681        let callee = self.env.callee_from_index(FuncIndex::from_u32(index));
1682        FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, callee)?;
1683        Ok(())
1684    }
1685
1686    fn visit_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output {
1687        // Spill now because `emit_table_get` and the `FnCall::emit`
1688        // invocations will both trigger spills since they both call functions.
1689        // However, the machine instructions for the spill emitted by
1690        // `emit_lazy_funcref` will be jumped over if the funcref was previously
1691        // initialized which may result in the machine stack becoming
1692        // unbalanced.
1693        self.context.spill(self.masm)?;
1694
1695        let type_index = TypeIndex::from_u32(type_index);
1696        let table_index = TableIndex::from_u32(table_index);
1697
1698        self.emit_table_get(table_index)?;
1699
1700        // Perform the indirect call.
1701        // This code assumes that [`Self::emit_table_get`] will
1702        // push the funcref to the value stack.
1703        let funcref_ptr = self
1704            .context
1705            .stack
1706            .peek()
1707            .map(|v| v.unwrap_reg())
1708            .ok_or_else(|| CodeGenError::missing_values_in_stack())?;
1709        self.masm
1710            .trapz(funcref_ptr.into(), TRAP_INDIRECT_CALL_TO_NULL)?;
1711        self.emit_typecheck_funcref(funcref_ptr.into(), type_index)?;
1712
1713        let callee = self.env.funcref(type_index);
1714        FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, callee)?;
1715        Ok(())
1716    }
1717
1718    fn visit_table_init(&mut self, elem: u32, table: u32) -> Self::Output {
1719        self.emit_table_init(ElemIndex::from_u32(elem), TableIndex::from_u32(table))
1720    }
1721
1722    fn visit_table_copy(&mut self, dst: u32, src: u32) -> Self::Output {
1723        self.emit_table_copy(TableIndex::from_u32(dst), TableIndex::from_u32(src))
1724    }
1725
1726    fn visit_table_get(&mut self, table: u32) -> Self::Output {
1727        let table_index = TableIndex::from_u32(table);
1728        self.emit_table_get(table_index)
1729    }
1730
1731    fn visit_table_grow(&mut self, table: u32) -> Self::Output {
1732        let table_index = TableIndex::from_u32(table);
1733        self.emit_table_grow(table_index)
1734    }
1735
1736    fn visit_table_size(&mut self, table: u32) -> Self::Output {
1737        let table_index = TableIndex::from_u32(table);
1738        let table_data = self.env.resolve_table_data(table_index);
1739        self.emit_compute_table_size(&table_data)
1740    }
1741
1742    fn visit_table_fill(&mut self, table: u32) -> Self::Output {
1743        let table_index = TableIndex::from_u32(table);
1744        self.emit_table_fill(table_index)
1745    }
1746
1747    fn visit_table_set(&mut self, table: u32) -> Self::Output {
1748        let table_index = TableIndex::from_u32(table);
1749        self.emit_table_set(table_index)
1750    }
1751
1752    fn visit_elem_drop(&mut self, index: u32) -> Self::Output {
1753        let index = ElemIndex::from_u32(index);
1754        self.emit_elem_drop(index)
1755    }
1756
1757    fn visit_memory_init(&mut self, data_index: u32, mem: u32) -> Self::Output {
1758        self.emit_memory_init(DataIndex::from_u32(data_index), MemoryIndex::from_u32(mem))
1759    }
1760
1761    fn visit_memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> Self::Output {
1762        self.emit_memory_copy(
1763            MemoryIndex::from_u32(dst_mem),
1764            MemoryIndex::from_u32(src_mem),
1765        )
1766    }
1767
1768    fn visit_memory_fill(&mut self, mem: u32) -> Self::Output {
1769        self.emit_memory_fill(MemoryIndex::from_u32(mem))
1770    }
1771
1772    fn visit_memory_size(&mut self, mem: u32) -> Self::Output {
1773        let heap = self.env.resolve_heap(MemoryIndex::from_u32(mem));
1774        self.emit_compute_memory_size(&heap)
1775    }
1776
1777    fn visit_memory_grow(&mut self, mem: u32) -> Self::Output {
1778        let at = self.context.stack.ensure_index_at(1)?;
1779        let mem = MemoryIndex::from_u32(mem);
1780        // The stack at this point contains: [ delta ]
1781        // The desired state is
1782        //   [ vmctx, delta, index ]
1783        let builtin = self.env.builtins.memory_grow::<M::ABI>()?;
1784        let builtin = self.prepare_builtin_defined_memory_arg(mem, at + 1, builtin)?;
1785
1786        let heap = self.env.resolve_heap(mem);
1787        FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, builtin)?;
1788
1789        // The memory32_grow builtin returns a pointer type, therefore we must
1790        // ensure that the return type is representative of the address space of
1791        // the heap type.
1792        match (self.env.ptr_type(), heap.index_type()) {
1793            (WasmValType::I64, WasmValType::I64) => Ok(()),
1794            // When the heap type is smaller than the pointer type, we adjust
1795            // the result of the memory32_grow builtin.
1796            (WasmValType::I64, WasmValType::I32) => {
1797                let top: Reg = self.context.pop_to_reg(self.masm, None)?.into();
1798                self.masm.wrap(writable!(top), top)?;
1799                self.context.stack.push(TypedReg::i32(top).into());
1800                Ok(())
1801            }
1802            _ => Err(format_err!(CodeGenError::unsupported_32_bit_platform())),
1803        }
1804    }
1805
1806    fn visit_data_drop(&mut self, data_index: u32) -> Self::Output {
1807        self.emit_data_drop(DataIndex::from_u32(data_index))
1808    }
1809
1810    fn visit_nop(&mut self) -> Self::Output {
1811        Ok(())
1812    }
1813
1814    fn visit_if(&mut self, blockty: BlockType) -> Self::Output {
1815        self.control_frames.push(ControlStackFrame::r#if(
1816            self.env.resolve_block_sig(blockty)?,
1817            self.masm,
1818            &mut self.context,
1819        )?);
1820
1821        Ok(())
1822    }
1823
1824    fn visit_else(&mut self) -> Self::Output {
1825        if !self.context.reachable {
1826            self.handle_unreachable_else()
1827        } else {
1828            let control = self
1829                .control_frames
1830                .last_mut()
1831                .ok_or_else(|| CodeGenError::control_frame_expected())?;
1832            control.emit_else(self.masm, &mut self.context)
1833        }
1834    }
1835
1836    fn visit_block(&mut self, blockty: BlockType) -> Self::Output {
1837        self.control_frames.push(ControlStackFrame::block(
1838            self.env.resolve_block_sig(blockty)?,
1839            self.masm,
1840            &mut self.context,
1841        )?);
1842
1843        Ok(())
1844    }
1845
1846    fn visit_loop(&mut self, blockty: BlockType) -> Self::Output {
1847        self.control_frames.push(ControlStackFrame::r#loop(
1848            self.env.resolve_block_sig(blockty)?,
1849            self.masm,
1850            &mut self.context,
1851        )?);
1852
1853        self.maybe_emit_epoch_check()?;
1854        self.maybe_emit_fuel_check()
1855    }
1856
1857    fn visit_br(&mut self, depth: u32) -> Self::Output {
1858        let index = control_index(depth, self.control_frames.len())?;
1859        let frame = &mut self.control_frames[index];
1860        self.context
1861            .br::<_, _, UnconditionalBranch>(frame, self.masm, |masm, cx, frame| {
1862                frame.pop_abi_results::<M, _>(cx, masm, |results, _, _| {
1863                    Ok(results.ret_area().copied())
1864                })
1865            })
1866    }
1867
1868    fn visit_br_if(&mut self, depth: u32) -> Self::Output {
1869        let index = control_index(depth, self.control_frames.len())?;
1870        let frame = &mut self.control_frames[index];
1871        frame.set_as_target();
1872
1873        let top = {
1874            let top = self.context.without::<Result<TypedReg>, M, _>(
1875                frame.results::<M>()?.regs(),
1876                self.masm,
1877                |ctx, masm| ctx.pop_to_reg(masm, None),
1878            )??;
1879            // Explicitly save any live registers and locals before setting up
1880            // the branch state.
1881            // In some cases, calculating the `top` value above, will result in
1882            // a spill, thus the following one will result in a no-op.
1883            self.context.spill(self.masm)?;
1884            frame.top_abi_results::<M, _>(
1885                &mut self.context,
1886                self.masm,
1887                |results, context, masm| {
1888                    // In the case of `br_if` there's a possibility that we'll
1889                    // exit early from the block or fallthrough, for
1890                    // a fallthrough, we cannot rely on the pre-computed return area;
1891                    // it must be recalculated so that any values that are
1892                    // generated are correctly placed near the current stack
1893                    // pointer.
1894                    if results.on_stack() {
1895                        let stack_consumed = context.stack.sizeof(results.stack_operands_len());
1896                        let base = masm.sp_offset()?.as_u32() - stack_consumed;
1897                        let offs = base + results.size();
1898                        Ok(Some(RetArea::sp(SPOffset::from_u32(offs))))
1899                    } else {
1900                        Ok(None)
1901                    }
1902                },
1903            )?;
1904            top
1905        };
1906
1907        // Emit instructions to balance the machine stack.
1908        let current_sp_offset = self.masm.sp_offset()?;
1909        let unbalanced = frame.unbalanced(self.masm)?;
1910        let (label, cmp) = if unbalanced {
1911            (self.masm.get_label()?, IntCmpKind::Eq)
1912        } else {
1913            (*frame.label(), IntCmpKind::Ne)
1914        };
1915
1916        self.masm
1917            .branch(cmp, top.reg, top.reg.into(), label, OperandSize::S32)?;
1918        self.context.free_reg(top);
1919
1920        if unbalanced {
1921            self.context
1922                .br::<_, _, ConditionalBranch>(frame, self.masm, |_, _, _| Ok(()))?;
1923
1924            // Restore sp_offset to what it was for falling through and emit
1925            // fallthrough label.
1926            self.masm.reset_stack_pointer(current_sp_offset)?;
1927            self.masm.bind(label)?;
1928        }
1929
1930        Ok(())
1931    }
1932
1933    fn visit_br_table(&mut self, targets: BrTable<'a>) -> Self::Output {
1934        // +1 to account for the default target.
1935        let len = targets.len() + 1;
1936        // SmallVec<[_; 5]> to match the binary emission layer (e.g
1937        // see `JmpTableSeq'), but here we use 5 instead since we
1938        // bundle the default target as the last element in the array.
1939        let mut labels: SmallVec<[_; 5]> = smallvec![];
1940        for _ in 0..len {
1941            labels.push(self.masm.get_label()?);
1942        }
1943
1944        // Find the innermost target and use it as the relative frame
1945        // for result handling below.
1946        //
1947        // This approach ensures that
1948        // 1. The stack pointer offset is correctly positioned
1949        //    according to the expectations of the innermost block end
1950        //    sequence.
1951        // 2. We meet the jump site invariants introduced by
1952        //    `CodegenContext::br`, which take advantage of Wasm
1953        //    semantics given that all jumps are "outward".
1954        let mut innermost = targets.default();
1955        for target in targets.targets() {
1956            let target = target?;
1957            if target < innermost {
1958                innermost = target;
1959            }
1960        }
1961
1962        let innermost_index = control_index(innermost, self.control_frames.len())?;
1963        let innermost_frame = &mut self.control_frames[innermost_index];
1964        let innermost_result = innermost_frame.results::<M>()?;
1965
1966        let (index, tmp) = {
1967            let index_and_tmp = self.context.without::<Result<(TypedReg, _)>, M, _>(
1968                innermost_result.regs(),
1969                self.masm,
1970                |cx, masm| Ok((cx.pop_to_reg(masm, None)?, cx.any_gpr(masm)?)),
1971            )??;
1972
1973            // Materialize any constants or locals into their result
1974            // representation, so that when reachability is restored,
1975            // they are correctly located.  NB: the results are popped
1976            // in function of the innermost branch specified for
1977            // `br_table`, which implies that the machine stack will
1978            // be correctly balanced, by virtue of calling
1979            // `pop_abi_results`.
1980
1981            // It's possible that we need to balance the stack for the
1982            // rest of the targets, which will be done before emitting
1983            // the unconditional jump below.
1984            innermost_frame.pop_abi_results::<M, _>(
1985                &mut self.context,
1986                self.masm,
1987                |results, _, _| Ok(results.ret_area().copied()),
1988            )?;
1989            index_and_tmp
1990        };
1991
1992        self.masm.jmp_table(&labels, index.into(), tmp)?;
1993        // Save the original stack pointer offset; we will reset the stack
1994        // pointer to this offset after jumping to each of the targets. Each
1995        // jump might adjust the stack according to the base offset of the
1996        // target.
1997        let current_sp = self.masm.sp_offset()?;
1998
1999        for (t, l) in targets
2000            .targets()
2001            .chain(std::iter::once(Ok(targets.default())))
2002            .zip(labels.iter())
2003        {
2004            let control_index = control_index(t?, self.control_frames.len())?;
2005            let frame = &mut self.control_frames[control_index];
2006            // Reset the stack pointer to its original offset. This is needed
2007            // because each jump will potentially adjust the stack pointer
2008            // according to the base offset of the target.
2009            self.masm.reset_stack_pointer(current_sp)?;
2010
2011            // NB: We don't perform any result handling as it was
2012            // already taken care of above before jumping to the
2013            // jump table.
2014            self.masm.bind(*l)?;
2015            // Ensure that the stack pointer is correctly positioned before
2016            // jumping to the jump table code.
2017            self.context
2018                .br::<_, _, UnconditionalBranch>(frame, self.masm, |_, _, _| Ok(()))?;
2019        }
2020        // Finally reset the stack pointer to the original location.
2021        // The reachability analysis, will ensure it's correctly located
2022        // once reachability is restored.
2023        self.masm.reset_stack_pointer(current_sp)?;
2024        self.context.reachable = false;
2025        self.context.free_reg(index.reg);
2026        self.context.free_reg(tmp);
2027
2028        Ok(())
2029    }
2030
2031    fn visit_return(&mut self) -> Self::Output {
2032        // Grab the outermost frame, which is the function's body
2033        // frame. We don't rely on [`codegen::control_index`] since
2034        // this frame is implicit and we know that it should exist at
2035        // index 0.
2036        let outermost = &mut self.control_frames[0];
2037        self.context
2038            .br::<_, _, UnconditionalBranch>(outermost, self.masm, |masm, cx, frame| {
2039                frame.pop_abi_results::<M, _>(cx, masm, |results, _, _| {
2040                    Ok(results.ret_area().copied())
2041                })
2042            })
2043    }
2044
2045    fn visit_unreachable(&mut self) -> Self::Output {
2046        self.masm.unreachable()?;
2047        self.context.reachable = false;
2048        // Set the implicit outermost frame as target to perform the necessary
2049        // stack clean up.
2050        let outermost = &mut self.control_frames[0];
2051        outermost.set_as_target();
2052
2053        Ok(())
2054    }
2055
2056    fn visit_local_tee(&mut self, index: u32) -> Self::Output {
2057        let typed_reg = self.emit_set_local(index)?;
2058        self.context.stack.push(typed_reg.into());
2059
2060        Ok(())
2061    }
2062
2063    fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
2064        let index = GlobalIndex::from_u32(global_index);
2065        let (ty, base, offset) = self.emit_get_global_addr(index)?;
2066        let addr = self.masm.address_at_reg(base, offset)?;
2067        let dst = self.context.reg_for_type(ty, self.masm)?;
2068        self.masm.load(addr, writable!(dst), ty.try_into()?)?;
2069        self.context.stack.push(Val::reg(dst, ty));
2070
2071        self.context.free_reg(base);
2072
2073        Ok(())
2074    }
2075
2076    fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
2077        let index = GlobalIndex::from_u32(global_index);
2078        let (ty, base, offset) = self.emit_get_global_addr(index)?;
2079        let addr = self.masm.address_at_reg(base, offset)?;
2080
2081        let typed_reg = self.context.pop_to_reg(self.masm, None)?;
2082        self.masm
2083            .store(typed_reg.reg.into(), addr, ty.try_into()?)?;
2084        self.context.free_reg(typed_reg.reg);
2085        self.context.free_reg(base);
2086
2087        Ok(())
2088    }
2089
2090    fn visit_drop(&mut self) -> Self::Output {
2091        self.context.drop_last(1, |regalloc, val| match val {
2092            Val::Reg(tr) => Ok(regalloc.free(tr.reg)),
2093            Val::Memory(m) => self.masm.free_stack(m.slot.size),
2094            _ => Ok(()),
2095        })
2096    }
2097
2098    fn visit_select(&mut self) -> Self::Output {
2099        let cond = self.context.pop_to_reg(self.masm, None)?;
2100        let val2 = self.context.pop_to_reg(self.masm, None)?;
2101        let val1 = self.context.pop_to_reg(self.masm, None)?;
2102        self.masm.cmp(cond.reg, RegImm::i32(0), OperandSize::S32)?;
2103        // Conditionally move val1 to val2 if the comparison is
2104        // not zero.
2105        self.masm.cmov(
2106            writable!(val2.into()),
2107            val1.into(),
2108            IntCmpKind::Ne,
2109            val1.ty.try_into()?,
2110        )?;
2111        self.context.stack.push(val2.into());
2112        self.context.free_reg(val1.reg);
2113        self.context.free_reg(cond);
2114
2115        Ok(())
2116    }
2117
2118    fn visit_typed_select(&mut self, _ty: ValType) -> Self::Output {
2119        self.visit_select()
2120    }
2121
2122    fn visit_ref_null(&mut self, hty: HeapType) -> Self::Output {
2123        match hty {
2124            HeapType::FUNC => {
2125                let ptr_type = self.env.ptr_type();
2126                match ptr_type {
2127                    WasmValType::I64 => self.context.stack.push(Val::i64(0)),
2128                    WasmValType::I32 => self.context.stack.push(Val::i32(0)),
2129                    _ => bail!(CodeGenError::unsupported_wasm_type()),
2130                }
2131                Ok(())
2132            }
2133            _ => Err(format_err!(CodeGenError::unsupported_wasm_type())),
2134        }
2135    }
2136
2137    fn visit_ref_is_null(&mut self) -> Self::Output {
2138        let (zero, size) = match self.env.ptr_type() {
2139            WasmValType::I64 => (RegImm::i64(0), OperandSize::S64),
2140            WasmValType::I32 => (RegImm::i32(0), OperandSize::S32),
2141            _ => bail!(CodeGenError::unsupported_wasm_type()),
2142        };
2143        self.context.unop(self.masm, |masm, reg| {
2144            masm.cmp_with_set(writable!(reg), zero, IntCmpKind::Eq, size)?;
2145            Ok(TypedReg::i32(reg))
2146        })
2147    }
2148
2149    fn visit_ref_func(&mut self, function_index: u32) -> Self::Output {
2150        let ref_func = self.env.builtins.ref_func::<M::ABI>()?;
2151        self.context.stack.extend([function_index.try_into()?]);
2152        FnCall::emit::<M>(
2153            &mut self.env,
2154            self.masm,
2155            &mut self.context,
2156            Callee::Builtin(ref_func),
2157        )
2158    }
2159
2160    fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
2161        self.emit_wasm_load(
2162            &memarg,
2163            WasmValType::I32,
2164            LoadKind::Operand(OperandSize::S32),
2165        )
2166    }
2167
2168    fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output {
2169        self.emit_wasm_load(
2170            &memarg,
2171            WasmValType::I32,
2172            LoadKind::ScalarExtend(Extend::<Signed>::I32Extend8.into()),
2173        )
2174    }
2175
2176    fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2177        self.emit_wasm_load(
2178            &memarg,
2179            WasmValType::I32,
2180            LoadKind::ScalarExtend(Extend::<Zero>::I32Extend8.into()),
2181        )
2182    }
2183
2184    fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output {
2185        self.emit_wasm_load(
2186            &memarg,
2187            WasmValType::I32,
2188            LoadKind::ScalarExtend(Extend::<Signed>::I32Extend16.into()),
2189        )
2190    }
2191
2192    fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2193        self.emit_wasm_load(
2194            &memarg,
2195            WasmValType::I32,
2196            LoadKind::ScalarExtend(Extend::<Zero>::I32Extend16.into()),
2197        )
2198    }
2199
2200    fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output {
2201        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32))
2202    }
2203
2204    fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output {
2205        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S8))
2206    }
2207
2208    fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output {
2209        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S16))
2210    }
2211
2212    fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output {
2213        self.emit_wasm_load(
2214            &memarg,
2215            WasmValType::I64,
2216            LoadKind::ScalarExtend(Extend::<Signed>::I64Extend8.into()),
2217        )
2218    }
2219
2220    fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2221        self.emit_wasm_load(
2222            &memarg,
2223            WasmValType::I64,
2224            LoadKind::ScalarExtend(Extend::<Zero>::I64Extend8.into()),
2225        )
2226    }
2227
2228    fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2229        self.emit_wasm_load(
2230            &memarg,
2231            WasmValType::I64,
2232            LoadKind::ScalarExtend(Extend::<Zero>::I64Extend16.into()),
2233        )
2234    }
2235
2236    fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output {
2237        self.emit_wasm_load(
2238            &memarg,
2239            WasmValType::I64,
2240            LoadKind::ScalarExtend(Extend::<Signed>::I64Extend16.into()),
2241        )
2242    }
2243
2244    fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output {
2245        self.emit_wasm_load(
2246            &memarg,
2247            WasmValType::I64,
2248            LoadKind::ScalarExtend(Extend::<Zero>::I64Extend32.into()),
2249        )
2250    }
2251
2252    fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output {
2253        self.emit_wasm_load(
2254            &memarg,
2255            WasmValType::I64,
2256            LoadKind::ScalarExtend(Extend::<Signed>::I64Extend32.into()),
2257        )
2258    }
2259
2260    fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output {
2261        self.emit_wasm_load(
2262            &memarg,
2263            WasmValType::I64,
2264            LoadKind::Operand(OperandSize::S64),
2265        )
2266    }
2267
2268    fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output {
2269        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S64))
2270    }
2271
2272    fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output {
2273        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S8))
2274    }
2275
2276    fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output {
2277        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S16))
2278    }
2279
2280    fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output {
2281        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32))
2282    }
2283
2284    fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output {
2285        self.emit_wasm_load(
2286            &memarg,
2287            WasmValType::F32,
2288            LoadKind::Operand(OperandSize::S32),
2289        )
2290    }
2291
2292    fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output {
2293        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32))
2294    }
2295
2296    fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output {
2297        self.emit_wasm_load(
2298            &memarg,
2299            WasmValType::F64,
2300            LoadKind::Operand(OperandSize::S64),
2301        )
2302    }
2303
2304    fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output {
2305        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S64))
2306    }
2307
2308    fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output {
2309        use OperandSize::*;
2310
2311        self.context
2312            .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
2313                masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Checked)
2314            })
2315    }
2316
2317    fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output {
2318        use OperandSize::*;
2319
2320        self.masm
2321            .unsigned_truncate(&mut self.context, S32, S32, TruncKind::Checked)
2322    }
2323
2324    fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output {
2325        use OperandSize::*;
2326
2327        self.context
2328            .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| {
2329                masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Checked)
2330            })
2331    }
2332
2333    fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output {
2334        use OperandSize::*;
2335
2336        self.masm
2337            .unsigned_truncate(&mut self.context, S64, S32, TruncKind::Checked)
2338    }
2339
2340    fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output {
2341        use OperandSize::*;
2342
2343        self.context
2344            .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
2345                masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Checked)
2346            })
2347    }
2348
2349    fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output {
2350        use OperandSize::*;
2351
2352        self.masm
2353            .unsigned_truncate(&mut self.context, S32, S64, TruncKind::Checked)
2354    }
2355
2356    fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output {
2357        use OperandSize::*;
2358
2359        self.context
2360            .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| {
2361                masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Checked)
2362            })
2363    }
2364
2365    fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output {
2366        use OperandSize::*;
2367
2368        self.masm
2369            .unsigned_truncate(&mut self.context, S64, S64, TruncKind::Checked)
2370    }
2371
2372    fn visit_i64_add128(&mut self) -> Self::Output {
2373        self.context
2374            .binop128(self.masm, |masm, lhs_lo, lhs_hi, rhs_lo, rhs_hi| {
2375                masm.add128(
2376                    writable!(lhs_lo),
2377                    writable!(lhs_hi),
2378                    lhs_lo,
2379                    lhs_hi,
2380                    rhs_lo,
2381                    rhs_hi,
2382                )?;
2383                Ok((TypedReg::i64(lhs_lo), TypedReg::i64(lhs_hi)))
2384            })
2385    }
2386
2387    fn visit_i64_sub128(&mut self) -> Self::Output {
2388        self.context
2389            .binop128(self.masm, |masm, lhs_lo, lhs_hi, rhs_lo, rhs_hi| {
2390                masm.sub128(
2391                    writable!(lhs_lo),
2392                    writable!(lhs_hi),
2393                    lhs_lo,
2394                    lhs_hi,
2395                    rhs_lo,
2396                    rhs_hi,
2397                )?;
2398                Ok((TypedReg::i64(lhs_lo), TypedReg::i64(lhs_hi)))
2399            })
2400    }
2401
2402    fn visit_i64_mul_wide_s(&mut self) -> Self::Output {
2403        self.masm.mul_wide(&mut self.context, MulWideKind::Signed)
2404    }
2405
2406    fn visit_i64_mul_wide_u(&mut self) -> Self::Output {
2407        self.masm.mul_wide(&mut self.context, MulWideKind::Unsigned)
2408    }
2409
2410    fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2411        self.emit_wasm_load(
2412            &memarg,
2413            WasmValType::I32,
2414            LoadKind::Atomic(OperandSize::S8, Some(Extend::<Zero>::I32Extend8.into())),
2415        )
2416    }
2417
2418    fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2419        self.emit_wasm_load(
2420            &memarg,
2421            WasmValType::I32,
2422            LoadKind::Atomic(OperandSize::S16, Some(Extend::<Zero>::I32Extend16.into())),
2423        )
2424    }
2425
2426    fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
2427        self.emit_wasm_load(
2428            &memarg,
2429            WasmValType::I32,
2430            LoadKind::Atomic(OperandSize::S32, None),
2431        )
2432    }
2433
2434    fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output {
2435        self.emit_wasm_load(
2436            &memarg,
2437            WasmValType::I64,
2438            LoadKind::Atomic(OperandSize::S8, Some(Extend::<Zero>::I64Extend8.into())),
2439        )
2440    }
2441
2442    fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output {
2443        self.emit_wasm_load(
2444            &memarg,
2445            WasmValType::I64,
2446            LoadKind::Atomic(OperandSize::S16, Some(Extend::<Zero>::I64Extend16.into())),
2447        )
2448    }
2449
2450    fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output {
2451        self.emit_wasm_load(
2452            &memarg,
2453            WasmValType::I64,
2454            LoadKind::Atomic(OperandSize::S32, Some(Extend::<Zero>::I64Extend32.into())),
2455        )
2456    }
2457
2458    fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output {
2459        self.emit_wasm_load(
2460            &memarg,
2461            WasmValType::I64,
2462            LoadKind::Atomic(OperandSize::S64, None),
2463        )
2464    }
2465
2466    fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
2467        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S32))
2468    }
2469
2470    fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output {
2471        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S64))
2472    }
2473
2474    fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
2475        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S8))
2476    }
2477
2478    fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
2479        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S16))
2480    }
2481
2482    fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output {
2483        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S8))
2484    }
2485
2486    fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output {
2487        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S16))
2488    }
2489
2490    fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output {
2491        self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S32))
2492    }
2493
2494    fn visit_i32_atomic_rmw8_add_u(&mut self, arg: MemArg) -> Self::Output {
2495        self.emit_atomic_rmw(
2496            &arg,
2497            RmwOp::Add,
2498            OperandSize::S8,
2499            Some(Extend::<Zero>::I32Extend8),
2500        )
2501    }
2502
2503    fn visit_i32_atomic_rmw16_add_u(&mut self, arg: MemArg) -> Self::Output {
2504        self.emit_atomic_rmw(
2505            &arg,
2506            RmwOp::Add,
2507            OperandSize::S16,
2508            Some(Extend::<Zero>::I32Extend16),
2509        )
2510    }
2511
2512    fn visit_i32_atomic_rmw_add(&mut self, arg: MemArg) -> Self::Output {
2513        self.emit_atomic_rmw(&arg, RmwOp::Add, OperandSize::S32, None)
2514    }
2515
2516    fn visit_i64_atomic_rmw8_add_u(&mut self, arg: MemArg) -> Self::Output {
2517        self.emit_atomic_rmw(
2518            &arg,
2519            RmwOp::Add,
2520            OperandSize::S8,
2521            Some(Extend::<Zero>::I64Extend8),
2522        )
2523    }
2524
2525    fn visit_i64_atomic_rmw16_add_u(&mut self, arg: MemArg) -> Self::Output {
2526        self.emit_atomic_rmw(
2527            &arg,
2528            RmwOp::Add,
2529            OperandSize::S16,
2530            Some(Extend::<Zero>::I64Extend16),
2531        )
2532    }
2533
2534    fn visit_i64_atomic_rmw32_add_u(&mut self, arg: MemArg) -> Self::Output {
2535        self.emit_atomic_rmw(
2536            &arg,
2537            RmwOp::Add,
2538            OperandSize::S32,
2539            Some(Extend::<Zero>::I64Extend32),
2540        )
2541    }
2542
2543    fn visit_i64_atomic_rmw_add(&mut self, arg: MemArg) -> Self::Output {
2544        self.emit_atomic_rmw(&arg, RmwOp::Add, OperandSize::S64, None)
2545    }
2546
2547    fn visit_i32_atomic_rmw8_sub_u(&mut self, arg: MemArg) -> Self::Output {
2548        self.emit_atomic_rmw(
2549            &arg,
2550            RmwOp::Sub,
2551            OperandSize::S8,
2552            Some(Extend::<Zero>::I32Extend8),
2553        )
2554    }
2555    fn visit_i32_atomic_rmw16_sub_u(&mut self, arg: MemArg) -> Self::Output {
2556        self.emit_atomic_rmw(
2557            &arg,
2558            RmwOp::Sub,
2559            OperandSize::S16,
2560            Some(Extend::<Zero>::I32Extend16),
2561        )
2562    }
2563
2564    fn visit_i32_atomic_rmw_sub(&mut self, arg: MemArg) -> Self::Output {
2565        self.emit_atomic_rmw(&arg, RmwOp::Sub, OperandSize::S32, None)
2566    }
2567
2568    fn visit_i64_atomic_rmw8_sub_u(&mut self, arg: MemArg) -> Self::Output {
2569        self.emit_atomic_rmw(
2570            &arg,
2571            RmwOp::Sub,
2572            OperandSize::S8,
2573            Some(Extend::<Zero>::I64Extend8),
2574        )
2575    }
2576
2577    fn visit_i64_atomic_rmw16_sub_u(&mut self, arg: MemArg) -> Self::Output {
2578        self.emit_atomic_rmw(
2579            &arg,
2580            RmwOp::Sub,
2581            OperandSize::S16,
2582            Some(Extend::<Zero>::I64Extend16),
2583        )
2584    }
2585
2586    fn visit_i64_atomic_rmw32_sub_u(&mut self, arg: MemArg) -> Self::Output {
2587        self.emit_atomic_rmw(
2588            &arg,
2589            RmwOp::Sub,
2590            OperandSize::S32,
2591            Some(Extend::<Zero>::I64Extend32),
2592        )
2593    }
2594
2595    fn visit_i64_atomic_rmw_sub(&mut self, arg: MemArg) -> Self::Output {
2596        self.emit_atomic_rmw(&arg, RmwOp::Sub, OperandSize::S64, None)
2597    }
2598
2599    fn visit_i32_atomic_rmw8_xchg_u(&mut self, arg: MemArg) -> Self::Output {
2600        self.emit_atomic_rmw(
2601            &arg,
2602            RmwOp::Xchg,
2603            OperandSize::S8,
2604            Some(Extend::<Zero>::I32Extend8),
2605        )
2606    }
2607
2608    fn visit_i32_atomic_rmw16_xchg_u(&mut self, arg: MemArg) -> Self::Output {
2609        self.emit_atomic_rmw(
2610            &arg,
2611            RmwOp::Xchg,
2612            OperandSize::S16,
2613            Some(Extend::<Zero>::I32Extend16),
2614        )
2615    }
2616
2617    fn visit_i32_atomic_rmw_xchg(&mut self, arg: MemArg) -> Self::Output {
2618        self.emit_atomic_rmw(&arg, RmwOp::Xchg, OperandSize::S32, None)
2619    }
2620
2621    fn visit_i64_atomic_rmw8_xchg_u(&mut self, arg: MemArg) -> Self::Output {
2622        self.emit_atomic_rmw(
2623            &arg,
2624            RmwOp::Xchg,
2625            OperandSize::S8,
2626            Some(Extend::<Zero>::I64Extend8),
2627        )
2628    }
2629
2630    fn visit_i64_atomic_rmw16_xchg_u(&mut self, arg: MemArg) -> Self::Output {
2631        self.emit_atomic_rmw(
2632            &arg,
2633            RmwOp::Xchg,
2634            OperandSize::S16,
2635            Some(Extend::<Zero>::I64Extend16),
2636        )
2637    }
2638
2639    fn visit_i64_atomic_rmw32_xchg_u(&mut self, arg: MemArg) -> Self::Output {
2640        self.emit_atomic_rmw(
2641            &arg,
2642            RmwOp::Xchg,
2643            OperandSize::S32,
2644            Some(Extend::<Zero>::I64Extend32),
2645        )
2646    }
2647
2648    fn visit_i64_atomic_rmw_xchg(&mut self, arg: MemArg) -> Self::Output {
2649        self.emit_atomic_rmw(&arg, RmwOp::Xchg, OperandSize::S64, None)
2650    }
2651
2652    fn visit_i32_atomic_rmw8_and_u(&mut self, arg: MemArg) -> Self::Output {
2653        self.emit_atomic_rmw(
2654            &arg,
2655            RmwOp::And,
2656            OperandSize::S8,
2657            Some(Extend::<Zero>::I32Extend8),
2658        )
2659    }
2660
2661    fn visit_i32_atomic_rmw16_and_u(&mut self, arg: MemArg) -> Self::Output {
2662        self.emit_atomic_rmw(
2663            &arg,
2664            RmwOp::And,
2665            OperandSize::S16,
2666            Some(Extend::<Zero>::I32Extend16),
2667        )
2668    }
2669
2670    fn visit_i32_atomic_rmw_and(&mut self, arg: MemArg) -> Self::Output {
2671        self.emit_atomic_rmw(&arg, RmwOp::And, OperandSize::S32, None)
2672    }
2673
2674    fn visit_i64_atomic_rmw8_and_u(&mut self, arg: MemArg) -> Self::Output {
2675        self.emit_atomic_rmw(
2676            &arg,
2677            RmwOp::And,
2678            OperandSize::S8,
2679            Some(Extend::<Zero>::I64Extend8),
2680        )
2681    }
2682
2683    fn visit_i64_atomic_rmw16_and_u(&mut self, arg: MemArg) -> Self::Output {
2684        self.emit_atomic_rmw(
2685            &arg,
2686            RmwOp::And,
2687            OperandSize::S16,
2688            Some(Extend::<Zero>::I64Extend16),
2689        )
2690    }
2691
2692    fn visit_i64_atomic_rmw32_and_u(&mut self, arg: MemArg) -> Self::Output {
2693        self.emit_atomic_rmw(
2694            &arg,
2695            RmwOp::And,
2696            OperandSize::S32,
2697            Some(Extend::<Zero>::I64Extend32),
2698        )
2699    }
2700
2701    fn visit_i64_atomic_rmw_and(&mut self, arg: MemArg) -> Self::Output {
2702        self.emit_atomic_rmw(&arg, RmwOp::And, OperandSize::S64, None)
2703    }
2704
2705    fn visit_i32_atomic_rmw8_or_u(&mut self, arg: MemArg) -> Self::Output {
2706        self.emit_atomic_rmw(
2707            &arg,
2708            RmwOp::Or,
2709            OperandSize::S8,
2710            Some(Extend::<Zero>::I32Extend8),
2711        )
2712    }
2713
2714    fn visit_i32_atomic_rmw16_or_u(&mut self, arg: MemArg) -> Self::Output {
2715        self.emit_atomic_rmw(
2716            &arg,
2717            RmwOp::Or,
2718            OperandSize::S16,
2719            Some(Extend::<Zero>::I32Extend16),
2720        )
2721    }
2722
2723    fn visit_i32_atomic_rmw_or(&mut self, arg: MemArg) -> Self::Output {
2724        self.emit_atomic_rmw(&arg, RmwOp::Or, OperandSize::S32, None)
2725    }
2726
2727    fn visit_i64_atomic_rmw8_or_u(&mut self, arg: MemArg) -> Self::Output {
2728        self.emit_atomic_rmw(
2729            &arg,
2730            RmwOp::Or,
2731            OperandSize::S8,
2732            Some(Extend::<Zero>::I64Extend8),
2733        )
2734    }
2735
2736    fn visit_i64_atomic_rmw16_or_u(&mut self, arg: MemArg) -> Self::Output {
2737        self.emit_atomic_rmw(
2738            &arg,
2739            RmwOp::Or,
2740            OperandSize::S16,
2741            Some(Extend::<Zero>::I64Extend16),
2742        )
2743    }
2744
2745    fn visit_i64_atomic_rmw32_or_u(&mut self, arg: MemArg) -> Self::Output {
2746        self.emit_atomic_rmw(
2747            &arg,
2748            RmwOp::Or,
2749            OperandSize::S32,
2750            Some(Extend::<Zero>::I64Extend32),
2751        )
2752    }
2753
2754    fn visit_i64_atomic_rmw_or(&mut self, arg: MemArg) -> Self::Output {
2755        self.emit_atomic_rmw(&arg, RmwOp::Or, OperandSize::S64, None)
2756    }
2757
2758    fn visit_i32_atomic_rmw8_xor_u(&mut self, arg: MemArg) -> Self::Output {
2759        self.emit_atomic_rmw(
2760            &arg,
2761            RmwOp::Xor,
2762            OperandSize::S8,
2763            Some(Extend::<Zero>::I32Extend8),
2764        )
2765    }
2766
2767    fn visit_i32_atomic_rmw16_xor_u(&mut self, arg: MemArg) -> Self::Output {
2768        self.emit_atomic_rmw(
2769            &arg,
2770            RmwOp::Xor,
2771            OperandSize::S16,
2772            Some(Extend::<Zero>::I32Extend16),
2773        )
2774    }
2775
2776    fn visit_i32_atomic_rmw_xor(&mut self, arg: MemArg) -> Self::Output {
2777        self.emit_atomic_rmw(&arg, RmwOp::Xor, OperandSize::S32, None)
2778    }
2779
2780    fn visit_i64_atomic_rmw8_xor_u(&mut self, arg: MemArg) -> Self::Output {
2781        self.emit_atomic_rmw(
2782            &arg,
2783            RmwOp::Xor,
2784            OperandSize::S8,
2785            Some(Extend::<Zero>::I64Extend8),
2786        )
2787    }
2788
2789    fn visit_i64_atomic_rmw16_xor_u(&mut self, arg: MemArg) -> Self::Output {
2790        self.emit_atomic_rmw(
2791            &arg,
2792            RmwOp::Xor,
2793            OperandSize::S16,
2794            Some(Extend::<Zero>::I64Extend16),
2795        )
2796    }
2797
2798    fn visit_i64_atomic_rmw32_xor_u(&mut self, arg: MemArg) -> Self::Output {
2799        self.emit_atomic_rmw(
2800            &arg,
2801            RmwOp::Xor,
2802            OperandSize::S32,
2803            Some(Extend::<Zero>::I64Extend32),
2804        )
2805    }
2806
2807    fn visit_i64_atomic_rmw_xor(&mut self, arg: MemArg) -> Self::Output {
2808        self.emit_atomic_rmw(&arg, RmwOp::Xor, OperandSize::S64, None)
2809    }
2810
2811    fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output {
2812        self.emit_atomic_cmpxchg(&arg, OperandSize::S8, Some(Extend::I32Extend8))
2813    }
2814
2815    fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output {
2816        self.emit_atomic_cmpxchg(&arg, OperandSize::S16, Some(Extend::I32Extend16))
2817    }
2818
2819    fn visit_i32_atomic_rmw_cmpxchg(&mut self, arg: MemArg) -> Self::Output {
2820        self.emit_atomic_cmpxchg(&arg, OperandSize::S32, None)
2821    }
2822
2823    fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output {
2824        self.emit_atomic_cmpxchg(&arg, OperandSize::S8, Some(Extend::I64Extend8))
2825    }
2826
2827    fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output {
2828        self.emit_atomic_cmpxchg(&arg, OperandSize::S16, Some(Extend::I64Extend16))
2829    }
2830
2831    fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output {
2832        self.emit_atomic_cmpxchg(&arg, OperandSize::S32, Some(Extend::I64Extend32))
2833    }
2834
2835    fn visit_i64_atomic_rmw_cmpxchg(&mut self, arg: MemArg) -> Self::Output {
2836        self.emit_atomic_cmpxchg(&arg, OperandSize::S64, None)
2837    }
2838
2839    fn visit_memory_atomic_wait32(&mut self, arg: MemArg) -> Self::Output {
2840        self.emit_atomic_wait(&arg, AtomicWaitKind::Wait32)
2841    }
2842
2843    fn visit_memory_atomic_wait64(&mut self, arg: MemArg) -> Self::Output {
2844        self.emit_atomic_wait(&arg, AtomicWaitKind::Wait64)
2845    }
2846
2847    fn visit_memory_atomic_notify(&mut self, arg: MemArg) -> Self::Output {
2848        self.emit_atomic_notify(&arg)
2849    }
2850
2851    fn visit_atomic_fence(&mut self) -> Self::Output {
2852        self.masm.fence()
2853    }
2854
2855    wasmparser::for_each_visit_operator!(def_unsupported);
2856}
2857
2858impl<'a, 'translation, 'data, M> VisitSimdOperator<'a>
2859    for CodeGen<'a, 'translation, 'data, M, Emission>
2860where
2861    M: MacroAssembler,
2862{
2863    fn visit_v128_const(&mut self, val: V128) -> Self::Output {
2864        self.context.stack.push(Val::v128(val.i128()));
2865        Ok(())
2866    }
2867
2868    fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output {
2869        self.emit_wasm_load(
2870            &memarg,
2871            WasmValType::V128,
2872            LoadKind::Operand(OperandSize::S128),
2873        )
2874    }
2875
2876    fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output {
2877        self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S128))
2878    }
2879
2880    fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output {
2881        self.emit_wasm_load(
2882            &memarg,
2883            WasmValType::V128,
2884            LoadKind::VectorExtend(V128LoadExtendKind::E8x8S),
2885        )
2886    }
2887
2888    fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output {
2889        self.emit_wasm_load(
2890            &memarg,
2891            WasmValType::V128,
2892            LoadKind::VectorExtend(V128LoadExtendKind::E8x8U),
2893        )
2894    }
2895
2896    fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output {
2897        self.emit_wasm_load(
2898            &memarg,
2899            WasmValType::V128,
2900            LoadKind::VectorExtend(V128LoadExtendKind::E16x4S),
2901        )
2902    }
2903
2904    fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output {
2905        self.emit_wasm_load(
2906            &memarg,
2907            WasmValType::V128,
2908            LoadKind::VectorExtend(V128LoadExtendKind::E16x4U),
2909        )
2910    }
2911
2912    fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output {
2913        self.emit_wasm_load(
2914            &memarg,
2915            WasmValType::V128,
2916            LoadKind::VectorExtend(V128LoadExtendKind::E32x2S),
2917        )
2918    }
2919
2920    fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output {
2921        self.emit_wasm_load(
2922            &memarg,
2923            WasmValType::V128,
2924            LoadKind::VectorExtend(V128LoadExtendKind::E32x2U),
2925        )
2926    }
2927
2928    fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output {
2929        self.emit_wasm_load(
2930            &memarg,
2931            WasmValType::V128,
2932            LoadKind::Splat(SplatLoadKind::S8),
2933        )
2934    }
2935
2936    fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output {
2937        self.emit_wasm_load(
2938            &memarg,
2939            WasmValType::V128,
2940            LoadKind::Splat(SplatLoadKind::S16),
2941        )
2942    }
2943
2944    fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output {
2945        self.emit_wasm_load(
2946            &memarg,
2947            WasmValType::V128,
2948            LoadKind::Splat(SplatLoadKind::S32),
2949        )
2950    }
2951
2952    fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output {
2953        self.emit_wasm_load(
2954            &memarg,
2955            WasmValType::V128,
2956            LoadKind::Splat(SplatLoadKind::S64),
2957        )
2958    }
2959
2960    fn visit_i8x16_splat(&mut self) -> Self::Output {
2961        self.masm.splat(&mut self.context, SplatKind::I8x16)
2962    }
2963
2964    fn visit_i16x8_splat(&mut self) -> Self::Output {
2965        self.masm.splat(&mut self.context, SplatKind::I16x8)
2966    }
2967
2968    fn visit_i32x4_splat(&mut self) -> Self::Output {
2969        self.masm.splat(&mut self.context, SplatKind::I32x4)
2970    }
2971
2972    fn visit_i64x2_splat(&mut self) -> Self::Output {
2973        self.masm.splat(&mut self.context, SplatKind::I64x2)
2974    }
2975
2976    fn visit_f32x4_splat(&mut self) -> Self::Output {
2977        self.masm.splat(&mut self.context, SplatKind::F32x4)
2978    }
2979
2980    fn visit_f64x2_splat(&mut self) -> Self::Output {
2981        self.masm.splat(&mut self.context, SplatKind::F64x2)
2982    }
2983
2984    fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output {
2985        let rhs = self.context.pop_to_reg(self.masm, None)?;
2986        let lhs = self.context.pop_to_reg(self.masm, None)?;
2987        self.masm
2988            .shuffle(writable!(lhs.into()), lhs.into(), rhs.into(), lanes)?;
2989        self.context.stack.push(TypedReg::v128(lhs.into()).into());
2990        self.context.free_reg(rhs);
2991        Ok(())
2992    }
2993
2994    fn visit_i8x16_swizzle(&mut self) -> Self::Output {
2995        let rhs = self.context.pop_to_reg(self.masm, None)?;
2996        let lhs = self.context.pop_to_reg(self.masm, None)?;
2997        self.masm
2998            .swizzle(writable!(lhs.into()), lhs.into(), rhs.into())?;
2999        self.context.stack.push(TypedReg::v128(lhs.into()).into());
3000        self.context.free_reg(rhs);
3001        Ok(())
3002    }
3003
3004    fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output {
3005        self.context.extract_lane_op(
3006            self.masm,
3007            ExtractLaneKind::I8x16S,
3008            |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind),
3009        )
3010    }
3011
3012    fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output {
3013        self.context.extract_lane_op(
3014            self.masm,
3015            ExtractLaneKind::I8x16U,
3016            |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind),
3017        )
3018    }
3019
3020    fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output {
3021        self.context.extract_lane_op(
3022            self.masm,
3023            ExtractLaneKind::I16x8S,
3024            |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind),
3025        )
3026    }
3027
3028    fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output {
3029        self.context.extract_lane_op(
3030            self.masm,
3031            ExtractLaneKind::I16x8U,
3032            |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind),
3033        )
3034    }
3035
3036    fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
3037        self.context
3038            .extract_lane_op(self.masm, ExtractLaneKind::I32x4, |masm, src, dst, kind| {
3039                masm.extract_lane(src, dst, lane, kind)
3040            })
3041    }
3042
3043    fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
3044        self.context
3045            .extract_lane_op(self.masm, ExtractLaneKind::I64x2, |masm, src, dst, kind| {
3046                masm.extract_lane(src, dst, lane, kind)
3047            })
3048    }
3049
3050    fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output {
3051        self.context
3052            .extract_lane_op(self.masm, ExtractLaneKind::F32x4, |masm, src, dst, kind| {
3053                masm.extract_lane(src, dst, lane, kind)
3054            })
3055    }
3056
3057    fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output {
3058        self.context
3059            .extract_lane_op(self.masm, ExtractLaneKind::F64x2, |masm, src, dst, kind| {
3060                masm.extract_lane(src, dst, lane, kind)
3061            })
3062    }
3063
3064    fn visit_i8x16_eq(&mut self) -> Self::Output {
3065        self.context
3066            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3067                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I8x16)?;
3068                Ok(TypedReg::v128(dst))
3069            })
3070    }
3071
3072    fn visit_i16x8_eq(&mut self) -> Self::Output {
3073        self.context
3074            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3075                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I16x8)?;
3076                Ok(TypedReg::v128(dst))
3077            })
3078    }
3079
3080    fn visit_i32x4_eq(&mut self) -> Self::Output {
3081        self.context
3082            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3083                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I32x4)?;
3084                Ok(TypedReg::v128(dst))
3085            })
3086    }
3087
3088    fn visit_i64x2_eq(&mut self) -> Self::Output {
3089        self.context
3090            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3091                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I64x2)?;
3092                Ok(TypedReg::v128(dst))
3093            })
3094    }
3095
3096    fn visit_f32x4_eq(&mut self) -> Self::Output {
3097        self.context
3098            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3099                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::F32x4)?;
3100                Ok(TypedReg::v128(dst))
3101            })
3102    }
3103
3104    fn visit_f64x2_eq(&mut self) -> Self::Output {
3105        self.context
3106            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3107                masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::F64x2)?;
3108                Ok(TypedReg::v128(dst))
3109            })
3110    }
3111
3112    fn visit_i8x16_ne(&mut self) -> Self::Output {
3113        self.context
3114            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3115                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I8x16)?;
3116                Ok(TypedReg::v128(dst))
3117            })
3118    }
3119
3120    fn visit_i16x8_ne(&mut self) -> Self::Output {
3121        self.context
3122            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3123                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I16x8)?;
3124                Ok(TypedReg::v128(dst))
3125            })
3126    }
3127
3128    fn visit_i32x4_ne(&mut self) -> Self::Output {
3129        self.context
3130            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3131                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I32x4)?;
3132                Ok(TypedReg::v128(dst))
3133            })
3134    }
3135
3136    fn visit_i64x2_ne(&mut self) -> Self::Output {
3137        self.context
3138            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3139                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I64x2)?;
3140                Ok(TypedReg::v128(dst))
3141            })
3142    }
3143
3144    fn visit_f32x4_ne(&mut self) -> Self::Output {
3145        self.context
3146            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3147                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::F32x4)?;
3148                Ok(TypedReg::v128(dst))
3149            })
3150    }
3151
3152    fn visit_f64x2_ne(&mut self) -> Self::Output {
3153        self.context
3154            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3155                masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::F64x2)?;
3156                Ok(TypedReg::v128(dst))
3157            })
3158    }
3159
3160    fn visit_i8x16_lt_s(&mut self) -> Self::Output {
3161        self.context
3162            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3163                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I8x16S)?;
3164                Ok(TypedReg::v128(dst))
3165            })
3166    }
3167
3168    fn visit_i8x16_lt_u(&mut self) -> Self::Output {
3169        self.context
3170            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3171                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I8x16U)?;
3172                Ok(TypedReg::v128(dst))
3173            })
3174    }
3175
3176    fn visit_i16x8_lt_s(&mut self) -> Self::Output {
3177        self.context
3178            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3179                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I16x8S)?;
3180                Ok(TypedReg::v128(dst))
3181            })
3182    }
3183
3184    fn visit_i16x8_lt_u(&mut self) -> Self::Output {
3185        self.context
3186            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3187                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I16x8U)?;
3188                Ok(TypedReg::v128(dst))
3189            })
3190    }
3191
3192    fn visit_i32x4_lt_s(&mut self) -> Self::Output {
3193        self.context
3194            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3195                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I32x4S)?;
3196                Ok(TypedReg::v128(dst))
3197            })
3198    }
3199
3200    fn visit_i32x4_lt_u(&mut self) -> Self::Output {
3201        self.context
3202            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3203                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I32x4U)?;
3204                Ok(TypedReg::v128(dst))
3205            })
3206    }
3207
3208    fn visit_i64x2_lt_s(&mut self) -> Self::Output {
3209        self.context
3210            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3211                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I64x2S)?;
3212                Ok(TypedReg::v128(dst))
3213            })
3214    }
3215
3216    fn visit_f32x4_lt(&mut self) -> Self::Output {
3217        self.context
3218            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3219                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::F32x4)?;
3220                Ok(TypedReg::v128(dst))
3221            })
3222    }
3223
3224    fn visit_f64x2_lt(&mut self) -> Self::Output {
3225        self.context
3226            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3227                masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::F64x2)?;
3228                Ok(TypedReg::v128(dst))
3229            })
3230    }
3231
3232    fn visit_i8x16_le_s(&mut self) -> Self::Output {
3233        self.context
3234            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3235                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I8x16S)?;
3236                Ok(TypedReg::v128(dst))
3237            })
3238    }
3239
3240    fn visit_i8x16_le_u(&mut self) -> Self::Output {
3241        self.context
3242            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3243                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I8x16U)?;
3244                Ok(TypedReg::v128(dst))
3245            })
3246    }
3247
3248    fn visit_i16x8_le_s(&mut self) -> Self::Output {
3249        self.context
3250            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3251                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I16x8S)?;
3252                Ok(TypedReg::v128(dst))
3253            })
3254    }
3255
3256    fn visit_i16x8_le_u(&mut self) -> Self::Output {
3257        self.context
3258            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3259                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I16x8U)?;
3260                Ok(TypedReg::v128(dst))
3261            })
3262    }
3263
3264    fn visit_i32x4_le_s(&mut self) -> Self::Output {
3265        self.context
3266            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3267                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I32x4S)?;
3268                Ok(TypedReg::v128(dst))
3269            })
3270    }
3271
3272    fn visit_i32x4_le_u(&mut self) -> Self::Output {
3273        self.context
3274            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3275                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I32x4U)?;
3276                Ok(TypedReg::v128(dst))
3277            })
3278    }
3279
3280    fn visit_i64x2_le_s(&mut self) -> Self::Output {
3281        self.context
3282            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3283                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I64x2S)?;
3284                Ok(TypedReg::v128(dst))
3285            })
3286    }
3287
3288    fn visit_f32x4_le(&mut self) -> Self::Output {
3289        self.context
3290            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3291                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::F32x4)?;
3292                Ok(TypedReg::v128(dst))
3293            })
3294    }
3295
3296    fn visit_f64x2_le(&mut self) -> Self::Output {
3297        self.context
3298            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3299                masm.v128_le(writable!(dst), dst, src, VectorCompareKind::F64x2)?;
3300                Ok(TypedReg::v128(dst))
3301            })
3302    }
3303
3304    fn visit_i8x16_gt_s(&mut self) -> Self::Output {
3305        self.context
3306            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3307                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I8x16S)?;
3308                Ok(TypedReg::v128(dst))
3309            })
3310    }
3311
3312    fn visit_i8x16_gt_u(&mut self) -> Self::Output {
3313        self.context
3314            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3315                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I8x16U)?;
3316                Ok(TypedReg::v128(dst))
3317            })
3318    }
3319
3320    fn visit_i16x8_gt_s(&mut self) -> Self::Output {
3321        self.context
3322            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3323                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I16x8S)?;
3324                Ok(TypedReg::v128(dst))
3325            })
3326    }
3327
3328    fn visit_i16x8_gt_u(&mut self) -> Self::Output {
3329        self.context
3330            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3331                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I16x8U)?;
3332                Ok(TypedReg::v128(dst))
3333            })
3334    }
3335
3336    fn visit_i32x4_gt_s(&mut self) -> Self::Output {
3337        self.context
3338            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3339                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I32x4S)?;
3340                Ok(TypedReg::v128(dst))
3341            })
3342    }
3343
3344    fn visit_i32x4_gt_u(&mut self) -> Self::Output {
3345        self.context
3346            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3347                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I32x4U)?;
3348                Ok(TypedReg::v128(dst))
3349            })
3350    }
3351
3352    fn visit_i64x2_gt_s(&mut self) -> Self::Output {
3353        self.context
3354            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3355                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I64x2S)?;
3356                Ok(TypedReg::v128(dst))
3357            })
3358    }
3359
3360    fn visit_f32x4_gt(&mut self) -> Self::Output {
3361        self.context
3362            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3363                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::F32x4)?;
3364                Ok(TypedReg::v128(dst))
3365            })
3366    }
3367
3368    fn visit_f64x2_gt(&mut self) -> Self::Output {
3369        self.context
3370            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3371                masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::F64x2)?;
3372                Ok(TypedReg::v128(dst))
3373            })
3374    }
3375
3376    fn visit_i8x16_ge_s(&mut self) -> Self::Output {
3377        self.context
3378            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3379                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I8x16S)?;
3380                Ok(TypedReg::v128(dst))
3381            })
3382    }
3383
3384    fn visit_i8x16_ge_u(&mut self) -> Self::Output {
3385        self.context
3386            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3387                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I8x16U)?;
3388                Ok(TypedReg::v128(dst))
3389            })
3390    }
3391
3392    fn visit_i16x8_ge_s(&mut self) -> Self::Output {
3393        self.context
3394            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3395                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I16x8S)?;
3396                Ok(TypedReg::v128(dst))
3397            })
3398    }
3399
3400    fn visit_i16x8_ge_u(&mut self) -> Self::Output {
3401        self.context
3402            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3403                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I16x8U)?;
3404                Ok(TypedReg::v128(dst))
3405            })
3406    }
3407
3408    fn visit_i32x4_ge_s(&mut self) -> Self::Output {
3409        self.context
3410            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3411                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I32x4S)?;
3412                Ok(TypedReg::v128(dst))
3413            })
3414    }
3415
3416    fn visit_i32x4_ge_u(&mut self) -> Self::Output {
3417        self.context
3418            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3419                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I32x4U)?;
3420                Ok(TypedReg::v128(dst))
3421            })
3422    }
3423
3424    fn visit_i64x2_ge_s(&mut self) -> Self::Output {
3425        self.context
3426            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3427                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I64x2S)?;
3428                Ok(TypedReg::v128(dst))
3429            })
3430    }
3431
3432    fn visit_f32x4_ge(&mut self) -> Self::Output {
3433        self.context
3434            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3435                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::F32x4)?;
3436                Ok(TypedReg::v128(dst))
3437            })
3438    }
3439
3440    fn visit_f64x2_ge(&mut self) -> Self::Output {
3441        self.context
3442            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3443                masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::F64x2)?;
3444                Ok(TypedReg::v128(dst))
3445            })
3446    }
3447
3448    fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output {
3449        self.context
3450            .replace_lane_op(self.masm, ReplaceLaneKind::I8x16, |masm, src, dst, kind| {
3451                masm.replace_lane(src, dst, lane, kind)
3452            })
3453    }
3454
3455    fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output {
3456        self.context
3457            .replace_lane_op(self.masm, ReplaceLaneKind::I16x8, |masm, src, dst, kind| {
3458                masm.replace_lane(src, dst, lane, kind)
3459            })
3460    }
3461
3462    fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
3463        self.context
3464            .replace_lane_op(self.masm, ReplaceLaneKind::I32x4, |masm, src, dst, kind| {
3465                masm.replace_lane(src, dst, lane, kind)
3466            })
3467    }
3468
3469    fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
3470        self.context
3471            .replace_lane_op(self.masm, ReplaceLaneKind::I64x2, |masm, src, dst, kind| {
3472                masm.replace_lane(src, dst, lane, kind)
3473            })
3474    }
3475
3476    fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output {
3477        self.context
3478            .replace_lane_op(self.masm, ReplaceLaneKind::F32x4, |masm, src, dst, kind| {
3479                masm.replace_lane(src, dst, lane, kind)
3480            })
3481    }
3482
3483    fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output {
3484        self.context
3485            .replace_lane_op(self.masm, ReplaceLaneKind::F64x2, |masm, src, dst, kind| {
3486                masm.replace_lane(src, dst, lane, kind)
3487            })
3488    }
3489
3490    fn visit_v128_not(&mut self) -> Self::Output {
3491        self.context.unop(self.masm, |masm, reg| {
3492            masm.v128_not(writable!(reg))?;
3493            Ok(TypedReg::new(WasmValType::V128, reg))
3494        })
3495    }
3496
3497    fn visit_v128_and(&mut self) -> Self::Output {
3498        self.context
3499            .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| {
3500                masm.v128_and(dst, src, writable!(dst))?;
3501                Ok(TypedReg::new(WasmValType::V128, dst))
3502            })
3503    }
3504
3505    fn visit_v128_andnot(&mut self) -> Self::Output {
3506        self.context
3507            .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| {
3508                // careful here: and_not is *not* commutative: dst = !src1 & src2
3509                masm.v128_and_not(src, dst, writable!(dst))?;
3510                Ok(TypedReg::new(WasmValType::V128, dst))
3511            })
3512    }
3513
3514    fn visit_v128_or(&mut self) -> Self::Output {
3515        self.context
3516            .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| {
3517                // careful here: and_not is *not* commutative: dst = !src1 & src2
3518                masm.v128_or(src, dst, writable!(dst))?;
3519                Ok(TypedReg::new(WasmValType::V128, dst))
3520            })
3521    }
3522
3523    fn visit_v128_xor(&mut self) -> Self::Output {
3524        self.context
3525            .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| {
3526                // careful here: and_not is *not* commutative: dst = !src1 & src2
3527                masm.v128_xor(src, dst, writable!(dst))?;
3528                Ok(TypedReg::new(WasmValType::V128, dst))
3529            })
3530    }
3531
3532    fn visit_v128_bitselect(&mut self) -> Self::Output {
3533        let mask = self.context.pop_to_reg(self.masm, None)?;
3534        let op2 = self.context.pop_to_reg(self.masm, None)?;
3535        let op1 = self.context.pop_to_reg(self.masm, None)?;
3536        let dst = self.context.any_fpr(self.masm)?;
3537
3538        // careful here: bitselect is *not* commutative.
3539        self.masm
3540            .v128_bitselect(op1.reg, op2.reg, mask.reg, writable!(dst))?;
3541
3542        self.context
3543            .stack
3544            .push(TypedReg::new(WasmValType::V128, dst).into());
3545        self.context.free_reg(op1);
3546        self.context.free_reg(op2);
3547        self.context.free_reg(mask);
3548
3549        Ok(())
3550    }
3551
3552    fn visit_v128_any_true(&mut self) -> Self::Output {
3553        let src = self.context.pop_to_reg(self.masm, None)?;
3554        let dst = self.context.any_gpr(self.masm)?;
3555
3556        self.masm.v128_any_true(src.reg, writable!(dst))?;
3557
3558        self.context
3559            .stack
3560            .push(TypedReg::new(WasmValType::I32, dst).into());
3561        self.context.free_reg(src);
3562
3563        Ok(())
3564    }
3565
3566    fn visit_v128_load8_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3567        self.emit_wasm_load(
3568            &arg,
3569            WasmValType::V128,
3570            LoadKind::vector_lane(lane, OperandSize::S8),
3571        )
3572    }
3573
3574    fn visit_v128_load16_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3575        self.emit_wasm_load(
3576            &arg,
3577            WasmValType::V128,
3578            LoadKind::vector_lane(lane, OperandSize::S16),
3579        )
3580    }
3581
3582    fn visit_v128_load32_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3583        self.emit_wasm_load(
3584            &arg,
3585            WasmValType::V128,
3586            LoadKind::vector_lane(lane, OperandSize::S32),
3587        )
3588    }
3589
3590    fn visit_v128_load64_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3591        self.emit_wasm_load(
3592            &arg,
3593            WasmValType::V128,
3594            LoadKind::vector_lane(lane, OperandSize::S64),
3595        )
3596    }
3597
3598    fn visit_v128_store8_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3599        self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S8))
3600    }
3601
3602    fn visit_v128_store16_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3603        self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S16))
3604    }
3605
3606    fn visit_v128_store32_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3607        self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S32))
3608    }
3609
3610    fn visit_v128_store64_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output {
3611        self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S64))
3612    }
3613
3614    fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output {
3615        self.context.unop(self.masm, |masm, reg| {
3616            masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4S)?;
3617            Ok(TypedReg::v128(reg))
3618        })
3619    }
3620
3621    fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output {
3622        self.context.unop(self.masm, |masm, reg| {
3623            masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4U)?;
3624            Ok(TypedReg::v128(reg))
3625        })
3626    }
3627
3628    fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output {
3629        self.context.unop(self.masm, |masm, reg| {
3630            masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4LowS)?;
3631            Ok(TypedReg::v128(reg))
3632        })
3633    }
3634
3635    fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output {
3636        self.context.unop(self.masm, |masm, reg| {
3637            masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4LowU)?;
3638            Ok(TypedReg::v128(reg))
3639        })
3640    }
3641
3642    fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output {
3643        self.context
3644            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3645                masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I16x8S)?;
3646                Ok(TypedReg::v128(dst))
3647            })
3648    }
3649
3650    fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output {
3651        self.context
3652            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3653                masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I16x8U)?;
3654                Ok(TypedReg::v128(dst))
3655            })
3656    }
3657
3658    fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output {
3659        self.context
3660            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3661                masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I32x4S)?;
3662                Ok(TypedReg::v128(dst))
3663            })
3664    }
3665
3666    fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output {
3667        self.context
3668            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3669                masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I32x4U)?;
3670                Ok(TypedReg::v128(dst))
3671            })
3672    }
3673
3674    fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output {
3675        self.context.unop(self.masm, |masm, reg| {
3676            masm.v128_demote(reg, writable!(reg))?;
3677            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S32)?;
3678            Ok(TypedReg::v128(reg))
3679        })
3680    }
3681
3682    fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output {
3683        self.context.unop(self.masm, |masm, reg| {
3684            masm.v128_promote(reg, writable!(reg))?;
3685            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S64)?;
3686            Ok(TypedReg::v128(reg))
3687        })
3688    }
3689
3690    fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output {
3691        self.context.unop(self.masm, |masm, reg| {
3692            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI8x16S)?;
3693            Ok(TypedReg::v128(reg))
3694        })
3695    }
3696
3697    fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output {
3698        self.context.unop(self.masm, |masm, reg| {
3699            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI8x16S)?;
3700            Ok(TypedReg::v128(reg))
3701        })
3702    }
3703
3704    fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output {
3705        self.context.unop(self.masm, |masm, reg| {
3706            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI8x16U)?;
3707            Ok(TypedReg::v128(reg))
3708        })
3709    }
3710
3711    fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output {
3712        self.context.unop(self.masm, |masm, reg| {
3713            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI8x16U)?;
3714            Ok(TypedReg::v128(reg))
3715        })
3716    }
3717
3718    fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output {
3719        self.context.unop(self.masm, |masm, reg| {
3720            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI16x8S)?;
3721            Ok(TypedReg::v128(reg))
3722        })
3723    }
3724
3725    fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output {
3726        self.context.unop(self.masm, |masm, reg| {
3727            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI16x8S)?;
3728            Ok(TypedReg::v128(reg))
3729        })
3730    }
3731
3732    fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output {
3733        self.context.unop(self.masm, |masm, reg| {
3734            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI16x8U)?;
3735            Ok(TypedReg::v128(reg))
3736        })
3737    }
3738
3739    fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output {
3740        self.context.unop(self.masm, |masm, reg| {
3741            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI16x8U)?;
3742            Ok(TypedReg::v128(reg))
3743        })
3744    }
3745
3746    fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output {
3747        self.context.unop(self.masm, |masm, reg| {
3748            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI32x4S)?;
3749            Ok(TypedReg::v128(reg))
3750        })
3751    }
3752
3753    fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output {
3754        self.context.unop(self.masm, |masm, reg| {
3755            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI32x4S)?;
3756            Ok(TypedReg::v128(reg))
3757        })
3758    }
3759
3760    fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output {
3761        self.context.unop(self.masm, |masm, reg| {
3762            masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI32x4U)?;
3763            Ok(TypedReg::v128(reg))
3764        })
3765    }
3766
3767    fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output {
3768        self.context.unop(self.masm, |masm, reg| {
3769            masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI32x4U)?;
3770            Ok(TypedReg::v128(reg))
3771        })
3772    }
3773
3774    fn visit_i8x16_add(&mut self) -> Self::Output {
3775        self.context
3776            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3777                masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16)?;
3778                Ok(TypedReg::new(WasmValType::V128, dst))
3779            })
3780    }
3781
3782    fn visit_i16x8_add(&mut self) -> Self::Output {
3783        self.context
3784            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3785                masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8)?;
3786                Ok(TypedReg::new(WasmValType::V128, dst))
3787            })
3788    }
3789
3790    fn visit_i32x4_add(&mut self) -> Self::Output {
3791        self.context
3792            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3793                masm.v128_add(dst, src, writable!(dst), V128AddKind::I32x4)?;
3794                Ok(TypedReg::new(WasmValType::V128, dst))
3795            })
3796    }
3797
3798    fn visit_i64x2_add(&mut self) -> Self::Output {
3799        self.context
3800            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3801                masm.v128_add(dst, src, writable!(dst), V128AddKind::I64x2)?;
3802                Ok(TypedReg::new(WasmValType::V128, dst))
3803            })
3804    }
3805
3806    fn visit_i8x16_sub(&mut self) -> Self::Output {
3807        self.context
3808            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3809                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16)?;
3810                Ok(TypedReg::new(WasmValType::V128, dst))
3811            })
3812    }
3813
3814    fn visit_i16x8_sub(&mut self) -> Self::Output {
3815        self.context
3816            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3817                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8)?;
3818                Ok(TypedReg::new(WasmValType::V128, dst))
3819            })
3820    }
3821
3822    fn visit_i32x4_sub(&mut self) -> Self::Output {
3823        self.context
3824            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
3825                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I32x4)?;
3826                Ok(TypedReg::new(WasmValType::V128, dst))
3827            })
3828    }
3829
3830    fn visit_i64x2_sub(&mut self) -> Self::Output {
3831        self.context
3832            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
3833                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I64x2)?;
3834                Ok(TypedReg::new(WasmValType::V128, dst))
3835            })
3836    }
3837
3838    fn visit_i16x8_mul(&mut self) -> Self::Output {
3839        self.masm.v128_mul(&mut self.context, V128MulKind::I16x8)
3840    }
3841
3842    fn visit_i32x4_mul(&mut self) -> Self::Output {
3843        self.masm.v128_mul(&mut self.context, V128MulKind::I32x4)
3844    }
3845
3846    fn visit_i64x2_mul(&mut self) -> Self::Output {
3847        self.masm.v128_mul(&mut self.context, V128MulKind::I64x2)
3848    }
3849
3850    fn visit_i8x16_add_sat_s(&mut self) -> Self::Output {
3851        self.context
3852            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3853                masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16SatS)?;
3854                Ok(TypedReg::new(WasmValType::V128, dst))
3855            })
3856    }
3857
3858    fn visit_i16x8_add_sat_s(&mut self) -> Self::Output {
3859        self.context
3860            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3861                masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8SatS)?;
3862                Ok(TypedReg::new(WasmValType::V128, dst))
3863            })
3864    }
3865
3866    fn visit_i8x16_add_sat_u(&mut self) -> Self::Output {
3867        self.context
3868            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3869                masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16SatU)?;
3870                Ok(TypedReg::new(WasmValType::V128, dst))
3871            })
3872    }
3873
3874    fn visit_i16x8_add_sat_u(&mut self) -> Self::Output {
3875        self.context
3876            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3877                masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8SatU)?;
3878                Ok(TypedReg::new(WasmValType::V128, dst))
3879            })
3880    }
3881
3882    fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output {
3883        self.context
3884            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3885                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16SatS)?;
3886                Ok(TypedReg::new(WasmValType::V128, dst))
3887            })
3888    }
3889
3890    fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output {
3891        self.context
3892            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3893                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8SatS)?;
3894                Ok(TypedReg::new(WasmValType::V128, dst))
3895            })
3896    }
3897
3898    fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output {
3899        self.context
3900            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
3901                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16SatU)?;
3902                Ok(TypedReg::new(WasmValType::V128, dst))
3903            })
3904    }
3905
3906    fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output {
3907        self.context
3908            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
3909                masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8SatU)?;
3910                Ok(TypedReg::new(WasmValType::V128, dst))
3911            })
3912    }
3913
3914    fn visit_i8x16_abs(&mut self) -> Self::Output {
3915        self.context.unop(self.masm, |masm, reg| {
3916            masm.v128_abs(reg, writable!(reg), V128AbsKind::I8x16)?;
3917            Ok(TypedReg::new(WasmValType::V128, reg))
3918        })
3919    }
3920
3921    fn visit_i16x8_abs(&mut self) -> Self::Output {
3922        self.context.unop(self.masm, |masm, reg| {
3923            masm.v128_abs(reg, writable!(reg), V128AbsKind::I16x8)?;
3924            Ok(TypedReg::new(WasmValType::V128, reg))
3925        })
3926    }
3927
3928    fn visit_i32x4_abs(&mut self) -> Self::Output {
3929        self.context.unop(self.masm, |masm, reg| {
3930            masm.v128_abs(reg, writable!(reg), V128AbsKind::I32x4)?;
3931            Ok(TypedReg::new(WasmValType::V128, reg))
3932        })
3933    }
3934
3935    fn visit_i64x2_abs(&mut self) -> Self::Output {
3936        self.context.unop(self.masm, |masm, reg| {
3937            masm.v128_abs(reg, writable!(reg), V128AbsKind::I64x2)?;
3938            Ok(TypedReg::new(WasmValType::V128, reg))
3939        })
3940    }
3941
3942    fn visit_f32x4_abs(&mut self) -> Self::Output {
3943        self.context.unop(self.masm, |masm, reg| {
3944            masm.v128_abs(reg, writable!(reg), V128AbsKind::F32x4)?;
3945            Ok(TypedReg::new(WasmValType::V128, reg))
3946        })
3947    }
3948
3949    fn visit_f64x2_abs(&mut self) -> Self::Output {
3950        self.context.unop(self.masm, |masm, reg| {
3951            masm.v128_abs(reg, writable!(reg), V128AbsKind::F64x2)?;
3952            Ok(TypedReg::new(WasmValType::V128, reg))
3953        })
3954    }
3955
3956    fn visit_i8x16_neg(&mut self) -> Self::Output {
3957        self.context.unop(self.masm, |masm, op| {
3958            masm.v128_neg(writable!(op), V128NegKind::I8x16)?;
3959            Ok(TypedReg::new(WasmValType::V128, op))
3960        })
3961    }
3962
3963    fn visit_i16x8_neg(&mut self) -> Self::Output {
3964        self.context.unop(self.masm, |masm, op| {
3965            masm.v128_neg(writable!(op), V128NegKind::I16x8)?;
3966            Ok(TypedReg::new(WasmValType::V128, op))
3967        })
3968    }
3969
3970    fn visit_i32x4_neg(&mut self) -> Self::Output {
3971        self.context.unop(self.masm, |masm, op| {
3972            masm.v128_neg(writable!(op), V128NegKind::I32x4)?;
3973            Ok(TypedReg::new(WasmValType::V128, op))
3974        })
3975    }
3976
3977    fn visit_i64x2_neg(&mut self) -> Self::Output {
3978        self.context.unop(self.masm, |masm, op| {
3979            masm.v128_neg(writable!(op), V128NegKind::I64x2)?;
3980            Ok(TypedReg::new(WasmValType::V128, op))
3981        })
3982    }
3983
3984    fn visit_i8x16_shl(&mut self) -> Self::Output {
3985        self.masm
3986            .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::Shl)
3987    }
3988
3989    fn visit_i16x8_shl(&mut self) -> Self::Output {
3990        self.masm
3991            .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::Shl)
3992    }
3993
3994    fn visit_i32x4_shl(&mut self) -> Self::Output {
3995        self.masm
3996            .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::Shl)
3997    }
3998
3999    fn visit_i64x2_shl(&mut self) -> Self::Output {
4000        self.masm
4001            .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::Shl)
4002    }
4003
4004    fn visit_i8x16_shr_u(&mut self) -> Self::Output {
4005        self.masm
4006            .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::ShrU)
4007    }
4008
4009    fn visit_i16x8_shr_u(&mut self) -> Self::Output {
4010        self.masm
4011            .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::ShrU)
4012    }
4013
4014    fn visit_i32x4_shr_u(&mut self) -> Self::Output {
4015        self.masm
4016            .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::ShrU)
4017    }
4018
4019    fn visit_i64x2_shr_u(&mut self) -> Self::Output {
4020        self.masm
4021            .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::ShrU)
4022    }
4023
4024    fn visit_i8x16_shr_s(&mut self) -> Self::Output {
4025        self.masm
4026            .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::ShrS)
4027    }
4028
4029    fn visit_i16x8_shr_s(&mut self) -> Self::Output {
4030        self.masm
4031            .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::ShrS)
4032    }
4033
4034    fn visit_i32x4_shr_s(&mut self) -> Self::Output {
4035        self.masm
4036            .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::ShrS)
4037    }
4038
4039    fn visit_i64x2_shr_s(&mut self) -> Self::Output {
4040        self.masm
4041            .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::ShrS)
4042    }
4043
4044    fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output {
4045        self.context
4046            .binop(self.masm, OperandSize::S16, |masm, dst, src, size| {
4047                masm.v128_q15mulr_sat_s(dst, src, writable!(dst), size)?;
4048                Ok(TypedReg::v128(dst))
4049            })
4050    }
4051
4052    fn visit_i8x16_min_s(&mut self) -> Self::Output {
4053        self.context
4054            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
4055                masm.v128_min(src, dst, writable!(dst), V128MinKind::I8x16S)?;
4056                Ok(TypedReg::v128(dst))
4057            })
4058    }
4059
4060    fn visit_i8x16_all_true(&mut self) -> Self::Output {
4061        self.context.v128_all_true_op(self.masm, |masm, src, dst| {
4062            masm.v128_all_true(src, writable!(dst), OperandSize::S8)
4063        })
4064    }
4065
4066    fn visit_i16x8_all_true(&mut self) -> Self::Output {
4067        self.context.v128_all_true_op(self.masm, |masm, src, dst| {
4068            masm.v128_all_true(src, writable!(dst), OperandSize::S16)
4069        })
4070    }
4071
4072    fn visit_i32x4_all_true(&mut self) -> Self::Output {
4073        self.context.v128_all_true_op(self.masm, |masm, src, dst| {
4074            masm.v128_all_true(src, writable!(dst), OperandSize::S32)
4075        })
4076    }
4077
4078    fn visit_i64x2_all_true(&mut self) -> Self::Output {
4079        self.context.v128_all_true_op(self.masm, |masm, src, dst| {
4080            masm.v128_all_true(src, writable!(dst), OperandSize::S64)
4081        })
4082    }
4083
4084    fn visit_i8x16_bitmask(&mut self) -> Self::Output {
4085        self.context.v128_bitmask_op(self.masm, |masm, src, dst| {
4086            masm.v128_bitmask(src, writable!(dst), OperandSize::S8)
4087        })
4088    }
4089
4090    fn visit_i16x8_bitmask(&mut self) -> Self::Output {
4091        self.context.v128_bitmask_op(self.masm, |masm, src, dst| {
4092            masm.v128_bitmask(src, writable!(dst), OperandSize::S16)
4093        })
4094    }
4095
4096    fn visit_i32x4_bitmask(&mut self) -> Self::Output {
4097        self.context.v128_bitmask_op(self.masm, |masm, src, dst| {
4098            masm.v128_bitmask(src, writable!(dst), OperandSize::S32)
4099        })
4100    }
4101
4102    fn visit_i64x2_bitmask(&mut self) -> Self::Output {
4103        self.context.v128_bitmask_op(self.masm, |masm, src, dst| {
4104            masm.v128_bitmask(src, writable!(dst), OperandSize::S64)
4105        })
4106    }
4107
4108    fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output {
4109        self.masm
4110            .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF32x4S)
4111    }
4112
4113    fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output {
4114        self.masm
4115            .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF32x4U)
4116    }
4117
4118    fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output {
4119        self.masm
4120            .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF64x2SZero)
4121    }
4122
4123    fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output {
4124        self.masm
4125            .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF64x2UZero)
4126    }
4127
4128    fn visit_i16x8_min_s(&mut self) -> Self::Output {
4129        self.context
4130            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
4131                masm.v128_min(src, dst, writable!(dst), V128MinKind::I16x8S)?;
4132                Ok(TypedReg::v128(dst))
4133            })
4134    }
4135
4136    fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output {
4137        self.context
4138            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4139                masm.v128_dot(dst, src, writable!(dst))?;
4140                Ok(TypedReg::v128(dst))
4141            })
4142    }
4143
4144    fn visit_i8x16_popcnt(&mut self) -> Self::Output {
4145        self.masm.v128_popcnt(&mut self.context)
4146    }
4147
4148    fn visit_i8x16_avgr_u(&mut self) -> Self::Output {
4149        self.context
4150            .binop(self.masm, OperandSize::S8, |masm, dst, src, size| {
4151                masm.v128_avgr(dst, src, writable!(dst), size)?;
4152                Ok(TypedReg::v128(dst))
4153            })
4154    }
4155
4156    fn visit_i32x4_min_s(&mut self) -> Self::Output {
4157        self.context
4158            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4159                masm.v128_min(src, dst, writable!(dst), V128MinKind::I32x4S)?;
4160                Ok(TypedReg::v128(dst))
4161            })
4162    }
4163
4164    fn visit_i8x16_min_u(&mut self) -> Self::Output {
4165        self.context
4166            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
4167                masm.v128_min(src, dst, writable!(dst), V128MinKind::I8x16U)?;
4168                Ok(TypedReg::v128(dst))
4169            })
4170    }
4171
4172    fn visit_i16x8_avgr_u(&mut self) -> Self::Output {
4173        self.context
4174            .binop(self.masm, OperandSize::S16, |masm, dst, src, size| {
4175                masm.v128_avgr(dst, src, writable!(dst), size)?;
4176                Ok(TypedReg::v128(dst))
4177            })
4178    }
4179
4180    fn visit_i16x8_min_u(&mut self) -> Self::Output {
4181        self.context
4182            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
4183                masm.v128_min(src, dst, writable!(dst), V128MinKind::I16x8U)?;
4184                Ok(TypedReg::v128(dst))
4185            })
4186    }
4187
4188    fn visit_i32x4_min_u(&mut self) -> Self::Output {
4189        self.context
4190            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4191                masm.v128_min(src, dst, writable!(dst), V128MinKind::I32x4U)?;
4192                Ok(TypedReg::v128(dst))
4193            })
4194    }
4195
4196    fn visit_i8x16_max_s(&mut self) -> Self::Output {
4197        self.context
4198            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
4199                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I8x16S)?;
4200                Ok(TypedReg::v128(dst))
4201            })
4202    }
4203
4204    fn visit_i16x8_max_s(&mut self) -> Self::Output {
4205        self.context
4206            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
4207                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I16x8S)?;
4208                Ok(TypedReg::v128(dst))
4209            })
4210    }
4211
4212    fn visit_i32x4_max_s(&mut self) -> Self::Output {
4213        self.context
4214            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4215                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I32x4S)?;
4216                Ok(TypedReg::v128(dst))
4217            })
4218    }
4219
4220    fn visit_i8x16_max_u(&mut self) -> Self::Output {
4221        self.context
4222            .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| {
4223                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I8x16U)?;
4224                Ok(TypedReg::v128(dst))
4225            })
4226    }
4227
4228    fn visit_i16x8_max_u(&mut self) -> Self::Output {
4229        self.context
4230            .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| {
4231                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I16x8U)?;
4232                Ok(TypedReg::v128(dst))
4233            })
4234    }
4235
4236    fn visit_i32x4_max_u(&mut self) -> Self::Output {
4237        self.context
4238            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4239                masm.v128_max(src, dst, writable!(dst), V128MaxKind::I32x4U)?;
4240                Ok(TypedReg::v128(dst))
4241            })
4242    }
4243
4244    fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output {
4245        self.masm
4246            .v128_extmul(&mut self.context, V128ExtMulKind::LowI8x16S)
4247    }
4248
4249    fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output {
4250        self.masm
4251            .v128_extmul(&mut self.context, V128ExtMulKind::LowI16x8S)
4252    }
4253
4254    fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output {
4255        self.masm
4256            .v128_extmul(&mut self.context, V128ExtMulKind::LowI32x4S)
4257    }
4258
4259    fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output {
4260        self.masm
4261            .v128_extmul(&mut self.context, V128ExtMulKind::LowI8x16U)
4262    }
4263
4264    fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output {
4265        self.masm
4266            .v128_extmul(&mut self.context, V128ExtMulKind::LowI16x8U)
4267    }
4268
4269    fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output {
4270        self.masm
4271            .v128_extmul(&mut self.context, V128ExtMulKind::LowI32x4U)
4272    }
4273
4274    fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output {
4275        self.masm
4276            .v128_extmul(&mut self.context, V128ExtMulKind::HighI8x16U)
4277    }
4278
4279    fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output {
4280        self.masm
4281            .v128_extmul(&mut self.context, V128ExtMulKind::HighI16x8U)
4282    }
4283
4284    fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output {
4285        self.masm
4286            .v128_extmul(&mut self.context, V128ExtMulKind::HighI32x4U)
4287    }
4288
4289    fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output {
4290        self.masm
4291            .v128_extmul(&mut self.context, V128ExtMulKind::HighI8x16S)
4292    }
4293
4294    fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output {
4295        self.masm
4296            .v128_extmul(&mut self.context, V128ExtMulKind::HighI16x8S)
4297    }
4298
4299    fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output {
4300        self.masm
4301            .v128_extmul(&mut self.context, V128ExtMulKind::HighI32x4S)
4302    }
4303
4304    fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output {
4305        self.context.unop(self.masm, |masm, op| {
4306            masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I8x16S)?;
4307            Ok(TypedReg::v128(op))
4308        })
4309    }
4310
4311    fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output {
4312        self.context.unop(self.masm, |masm, op| {
4313            masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I8x16U)?;
4314            Ok(TypedReg::v128(op))
4315        })
4316    }
4317
4318    fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output {
4319        self.context.unop(self.masm, |masm, op| {
4320            masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I16x8S)?;
4321            Ok(TypedReg::v128(op))
4322        })
4323    }
4324
4325    fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output {
4326        self.context.unop(self.masm, |masm, op| {
4327            masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I16x8U)?;
4328            Ok(TypedReg::v128(op))
4329        })
4330    }
4331
4332    fn visit_f32x4_add(&mut self) -> Self::Output {
4333        self.context
4334            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4335                masm.v128_add(dst, src, writable!(dst), V128AddKind::F32x4)?;
4336                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S32)?;
4337                Ok(TypedReg::v128(dst))
4338            })
4339    }
4340
4341    fn visit_f64x2_add(&mut self) -> Self::Output {
4342        self.context
4343            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
4344                masm.v128_add(dst, src, writable!(dst), V128AddKind::F64x2)?;
4345                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S64)?;
4346                Ok(TypedReg::v128(dst))
4347            })
4348    }
4349
4350    fn visit_f32x4_sub(&mut self) -> Self::Output {
4351        self.context
4352            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4353                masm.v128_sub(dst, src, writable!(dst), V128SubKind::F32x4)?;
4354                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S32)?;
4355                Ok(TypedReg::v128(dst))
4356            })
4357    }
4358
4359    fn visit_f64x2_sub(&mut self) -> Self::Output {
4360        self.context
4361            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
4362                masm.v128_sub(dst, src, writable!(dst), V128SubKind::F64x2)?;
4363                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S64)?;
4364                Ok(TypedReg::v128(dst))
4365            })
4366    }
4367
4368    fn visit_f32x4_mul(&mut self) -> Self::Output {
4369        self.masm.v128_mul(&mut self.context, V128MulKind::F32x4)?;
4370        let result = self.context.pop_to_reg(self.masm, None)?;
4371        self.masm
4372            .maybe_canonicalize_v128_nan(writable!(result.into()), OperandSize::S32)?;
4373        self.context.stack.push(result.into());
4374        Ok(())
4375    }
4376
4377    fn visit_f64x2_mul(&mut self) -> Self::Output {
4378        self.masm.v128_mul(&mut self.context, V128MulKind::F64x2)?;
4379        let result = self.context.pop_to_reg(self.masm, None)?;
4380        self.masm
4381            .maybe_canonicalize_v128_nan(writable!(result.into()), OperandSize::S64)?;
4382        self.context.stack.push(result.into());
4383        Ok(())
4384    }
4385
4386    fn visit_f32x4_div(&mut self) -> Self::Output {
4387        self.context
4388            .binop(self.masm, OperandSize::S32, |masm, dst, src, size| {
4389                masm.v128_div(dst, src, writable!(dst), size)?;
4390                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S32)?;
4391                Ok(TypedReg::v128(dst))
4392            })
4393    }
4394
4395    fn visit_f64x2_div(&mut self) -> Self::Output {
4396        self.context
4397            .binop(self.masm, OperandSize::S64, |masm, dst, src, size| {
4398                masm.v128_div(dst, src, writable!(dst), size)?;
4399                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S64)?;
4400                Ok(TypedReg::v128(dst))
4401            })
4402    }
4403
4404    fn visit_f32x4_neg(&mut self) -> Self::Output {
4405        self.context.unop(self.masm, |masm, reg| {
4406            masm.v128_neg(writable!(reg), V128NegKind::F32x4)?;
4407            Ok(TypedReg::v128(reg))
4408        })
4409    }
4410
4411    fn visit_f32x4_ceil(&mut self) -> Self::Output {
4412        self.context.unop(self.masm, |masm, reg| {
4413            masm.v128_ceil(reg, writable!(reg), OperandSize::S32)?;
4414            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S32)?;
4415            Ok(TypedReg::v128(reg))
4416        })
4417    }
4418
4419    fn visit_f64x2_neg(&mut self) -> Self::Output {
4420        self.context.unop(self.masm, |masm, reg| {
4421            masm.v128_neg(writable!(reg), V128NegKind::F64x2)?;
4422            Ok(TypedReg::v128(reg))
4423        })
4424    }
4425
4426    fn visit_f64x2_ceil(&mut self) -> Self::Output {
4427        self.context.unop(self.masm, |masm, reg| {
4428            masm.v128_ceil(reg, writable!(reg), OperandSize::S64)?;
4429            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S64)?;
4430            Ok(TypedReg::v128(reg))
4431        })
4432    }
4433
4434    fn visit_f32x4_sqrt(&mut self) -> Self::Output {
4435        self.context.unop(self.masm, |masm, reg| {
4436            masm.v128_sqrt(reg, writable!(reg), OperandSize::S32)?;
4437            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S32)?;
4438            Ok(TypedReg::v128(reg))
4439        })
4440    }
4441
4442    fn visit_f32x4_floor(&mut self) -> Self::Output {
4443        self.context.unop(self.masm, |masm, reg| {
4444            masm.v128_floor(reg, writable!(reg), OperandSize::S32)?;
4445            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S32)?;
4446            Ok(TypedReg::v128(reg))
4447        })
4448    }
4449
4450    fn visit_f64x2_sqrt(&mut self) -> Self::Output {
4451        self.context.unop(self.masm, |masm, reg| {
4452            masm.v128_sqrt(reg, writable!(reg), OperandSize::S64)?;
4453            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S64)?;
4454            Ok(TypedReg::v128(reg))
4455        })
4456    }
4457
4458    fn visit_f64x2_floor(&mut self) -> Self::Output {
4459        self.context.unop(self.masm, |masm, reg| {
4460            masm.v128_floor(reg, writable!(reg), OperandSize::S64)?;
4461            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S64)?;
4462            Ok(TypedReg::v128(reg))
4463        })
4464    }
4465
4466    fn visit_f32x4_nearest(&mut self) -> Self::Output {
4467        self.context.unop(self.masm, |masm, reg| {
4468            masm.v128_nearest(reg, writable!(reg), OperandSize::S32)?;
4469            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S32)?;
4470            Ok(TypedReg::v128(reg))
4471        })
4472    }
4473
4474    fn visit_f64x2_nearest(&mut self) -> Self::Output {
4475        self.context.unop(self.masm, |masm, reg| {
4476            masm.v128_nearest(reg, writable!(reg), OperandSize::S64)?;
4477            masm.maybe_canonicalize_v128_nan(writable!(reg), OperandSize::S64)?;
4478            Ok(TypedReg::v128(reg))
4479        })
4480    }
4481
4482    fn visit_f32x4_trunc(&mut self) -> Self::Output {
4483        self.masm
4484            .v128_trunc(&mut self.context, V128TruncKind::F32x4)?;
4485        let result = self.context.pop_to_reg(self.masm, None)?;
4486        self.masm
4487            .maybe_canonicalize_v128_nan(writable!(result.into()), OperandSize::S32)?;
4488        self.context.stack.push(result.into());
4489        Ok(())
4490    }
4491
4492    fn visit_f64x2_trunc(&mut self) -> Self::Output {
4493        self.masm
4494            .v128_trunc(&mut self.context, V128TruncKind::F64x2)?;
4495        let result = self.context.pop_to_reg(self.masm, None)?;
4496        self.masm
4497            .maybe_canonicalize_v128_nan(writable!(result.into()), OperandSize::S64)?;
4498        self.context.stack.push(result.into());
4499        Ok(())
4500    }
4501
4502    fn visit_v128_load32_zero(&mut self, memarg: MemArg) -> Self::Output {
4503        self.emit_wasm_load(
4504            &memarg,
4505            WasmValType::V128,
4506            LoadKind::VectorZero(OperandSize::S32),
4507        )
4508    }
4509
4510    fn visit_v128_load64_zero(&mut self, memarg: MemArg) -> Self::Output {
4511        self.emit_wasm_load(
4512            &memarg,
4513            WasmValType::V128,
4514            LoadKind::VectorZero(OperandSize::S64),
4515        )
4516    }
4517
4518    fn visit_f32x4_pmin(&mut self) -> Self::Output {
4519        self.context
4520            .binop(self.masm, OperandSize::S32, |masm, dst, src, size| {
4521                masm.v128_pmin(dst, src, writable!(dst), size)?;
4522                Ok(TypedReg::v128(dst))
4523            })
4524    }
4525
4526    fn visit_f64x2_pmin(&mut self) -> Self::Output {
4527        self.context
4528            .binop(self.masm, OperandSize::S64, |masm, dst, src, size| {
4529                masm.v128_pmin(dst, src, writable!(dst), size)?;
4530                Ok(TypedReg::v128(dst))
4531            })
4532    }
4533
4534    fn visit_f32x4_pmax(&mut self) -> Self::Output {
4535        self.context
4536            .binop(self.masm, OperandSize::S32, |masm, dst, src, size| {
4537                masm.v128_pmax(dst, src, writable!(dst), size)?;
4538                Ok(TypedReg::v128(dst))
4539            })
4540    }
4541
4542    fn visit_f64x2_pmax(&mut self) -> Self::Output {
4543        self.context
4544            .binop(self.masm, OperandSize::S64, |masm, dst, src, size| {
4545                masm.v128_pmax(dst, src, writable!(dst), size)?;
4546                Ok(TypedReg::v128(dst))
4547            })
4548    }
4549
4550    fn visit_f32x4_min(&mut self) -> Self::Output {
4551        self.context
4552            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4553                masm.v128_min(dst, src, writable!(dst), V128MinKind::F32x4)?;
4554                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S32)?;
4555                Ok(TypedReg::v128(dst))
4556            })
4557    }
4558
4559    fn visit_f64x2_min(&mut self) -> Self::Output {
4560        self.context
4561            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
4562                masm.v128_min(dst, src, writable!(dst), V128MinKind::F64x2)?;
4563                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S64)?;
4564                Ok(TypedReg::v128(dst))
4565            })
4566    }
4567
4568    fn visit_f32x4_max(&mut self) -> Self::Output {
4569        self.context
4570            .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| {
4571                masm.v128_max(dst, src, writable!(dst), V128MaxKind::F32x4)?;
4572                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S32)?;
4573                Ok(TypedReg::v128(dst))
4574            })
4575    }
4576
4577    fn visit_f64x2_max(&mut self) -> Self::Output {
4578        self.context
4579            .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| {
4580                masm.v128_max(dst, src, writable!(dst), V128MaxKind::F64x2)?;
4581                masm.maybe_canonicalize_v128_nan(writable!(dst), OperandSize::S64)?;
4582                Ok(TypedReg::v128(dst))
4583            })
4584    }
4585
4586    wasmparser::for_each_visit_simd_operator!(def_unsupported);
4587}
4588
4589impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M, Emission>
4590where
4591    M: MacroAssembler,
4592{
4593    fn cmp_i32s(&mut self, kind: IntCmpKind) -> Result<()> {
4594        self.context.i32_binop(self.masm, |masm, dst, src, size| {
4595            masm.cmp_with_set(writable!(dst), src, kind, size)?;
4596            Ok(TypedReg::i32(dst))
4597        })
4598    }
4599
4600    fn cmp_i64s(&mut self, kind: IntCmpKind) -> Result<()> {
4601        self.context
4602            .i64_binop(self.masm, move |masm, dst, src, size| {
4603                masm.cmp_with_set(writable!(dst), src, kind, size)?;
4604                Ok(TypedReg::i32(dst)) // Return value for comparisons is an `i32`.
4605            })
4606    }
4607}
4608
4609impl TryFrom<WasmValType> for OperandSize {
4610    type Error = crate::Error;
4611    fn try_from(ty: WasmValType) -> Result<OperandSize> {
4612        let ty = match ty {
4613            WasmValType::I32 | WasmValType::F32 => OperandSize::S32,
4614            WasmValType::I64 | WasmValType::F64 => OperandSize::S64,
4615            WasmValType::V128 => OperandSize::S128,
4616            WasmValType::Ref(rt) => {
4617                match rt.heap_type {
4618                    // TODO: Hardcoded size, assuming 64-bit support only. Once
4619                    // Wasmtime supports 32-bit architectures, this will need
4620                    // to be updated in such a way that the calculation of the
4621                    // OperandSize will depend on the target's  pointer size.
4622                    WasmHeapType::Func => OperandSize::S64,
4623                    WasmHeapType::Extern => OperandSize::S64,
4624                    _ => bail!(CodeGenError::unsupported_wasm_type()),
4625                }
4626            }
4627        };
4628        Ok(ty)
4629    }
4630}