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