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