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