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