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::ABI;
8 use crate::codegen::{control_index, Callee, CodeGen, ControlStackFrame, FnCall};
9 use crate::masm::{
10     DivKind, FloatCmpKind, IntCmpKind, MacroAssembler, OperandSize, RegImm, RemKind, RoundingMode,
11     ShiftKind,
12 };
13 use crate::stack::{TypedReg, Val};
14 use cranelift_codegen::ir::TrapCode;
15 use smallvec::SmallVec;
16 use wasmparser::BrTable;
17 use wasmparser::{BlockType, Ieee32, Ieee64, VisitOperator};
18 use wasmtime_environ::{
19     FuncIndex, GlobalIndex, TableIndex, TableStyle, TypeIndex, WasmHeapType, WasmType,
20     FUNCREF_INIT_BIT,
21 };
22 
23 /// A macro to define unsupported WebAssembly operators.
24 ///
25 /// This macro calls itself recursively;
26 /// 1. It no-ops when matching a supported operator.
27 /// 2. Defines the visitor function and panics when
28 /// matching an unsupported operator.
29 macro_rules! def_unsupported {
30     ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
31         $(
32             def_unsupported!(
33                 emit
34                     $op
35 
36                 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
37                     $($(let _ = $arg;)*)?
38                         todo!(stringify!($op))
39                 }
40             );
41         )*
42     };
43 
44     (emit I32Const $($rest:tt)*) => {};
45     (emit I64Const $($rest:tt)*) => {};
46     (emit F32Const $($rest:tt)*) => {};
47     (emit F64Const $($rest:tt)*) => {};
48     (emit F32Add $($rest:tt)*) => {};
49     (emit F64Add $($rest:tt)*) => {};
50     (emit F32Sub $($rest:tt)*) => {};
51     (emit F64Sub $($rest:tt)*) => {};
52     (emit F32Mul $($rest:tt)*) => {};
53     (emit F64Mul $($rest:tt)*) => {};
54     (emit F32Div $($rest:tt)*) => {};
55     (emit F64Div $($rest:tt)*) => {};
56     (emit F32Min $($rest:tt)*) => {};
57     (emit F64Min $($rest:tt)*) => {};
58     (emit F32Max $($rest:tt)*) => {};
59     (emit F64Max $($rest:tt)*) => {};
60     (emit F32Copysign $($rest:tt)*) => {};
61     (emit F64Copysign $($rest:tt)*) => {};
62     (emit F32Abs $($rest:tt)*) => {};
63     (emit F64Abs $($rest:tt)*) => {};
64     (emit F32Neg $($rest:tt)*) => {};
65     (emit F64Neg $($rest:tt)*) => {};
66     (emit F32Floor $($rest:tt)*) => {};
67     (emit F64Floor $($rest:tt)*) => {};
68     (emit F32Ceil $($rest:tt)*) => {};
69     (emit F64Ceil $($rest:tt)*) => {};
70     (emit F32Nearest $($rest:tt)*) => {};
71     (emit F64Nearest $($rest:tt)*) => {};
72     (emit F32Trunc $($rest:tt)*) => {};
73     (emit F64Trunc $($rest:tt)*) => {};
74     (emit F32Sqrt $($rest:tt)*) => {};
75     (emit F64Sqrt $($rest:tt)*) => {};
76     (emit F32Eq $($rest:tt)*) => {};
77     (emit F64Eq $($rest:tt)*) => {};
78     (emit F32Ne $($rest:tt)*) => {};
79     (emit F64Ne $($rest:tt)*) => {};
80     (emit F32Lt $($rest:tt)*) => {};
81     (emit F64Lt $($rest:tt)*) => {};
82     (emit F32Gt $($rest:tt)*) => {};
83     (emit F64Gt $($rest:tt)*) => {};
84     (emit F32Le $($rest:tt)*) => {};
85     (emit F64Le $($rest:tt)*) => {};
86     (emit F32Ge $($rest:tt)*) => {};
87     (emit F64Ge $($rest:tt)*) => {};
88     (emit I32Add $($rest:tt)*) => {};
89     (emit I64Add $($rest:tt)*) => {};
90     (emit I32Sub $($rest:tt)*) => {};
91     (emit I32Mul $($rest:tt)*) => {};
92     (emit I32DivS $($rest:tt)*) => {};
93     (emit I32DivU $($rest:tt)*) => {};
94     (emit I64DivS $($rest:tt)*) => {};
95     (emit I64DivU $($rest:tt)*) => {};
96     (emit I64RemU $($rest:tt)*) => {};
97     (emit I64RemS $($rest:tt)*) => {};
98     (emit I32RemU $($rest:tt)*) => {};
99     (emit I32RemS $($rest:tt)*) => {};
100     (emit I64Mul $($rest:tt)*) => {};
101     (emit I64Sub $($rest:tt)*) => {};
102     (emit I32Eq $($rest:tt)*) => {};
103     (emit I64Eq $($rest:tt)*) => {};
104     (emit I32Ne $($rest:tt)*) => {};
105     (emit I64Ne $($rest:tt)*) => {};
106     (emit I32LtS $($rest:tt)*) => {};
107     (emit I64LtS $($rest:tt)*) => {};
108     (emit I32LtU $($rest:tt)*) => {};
109     (emit I64LtU $($rest:tt)*) => {};
110     (emit I32LeS $($rest:tt)*) => {};
111     (emit I64LeS $($rest:tt)*) => {};
112     (emit I32LeU $($rest:tt)*) => {};
113     (emit I64LeU $($rest:tt)*) => {};
114     (emit I32GtS $($rest:tt)*) => {};
115     (emit I64GtS $($rest:tt)*) => {};
116     (emit I32GtU $($rest:tt)*) => {};
117     (emit I64GtU $($rest:tt)*) => {};
118     (emit I32GeS $($rest:tt)*) => {};
119     (emit I64GeS $($rest:tt)*) => {};
120     (emit I32GeU $($rest:tt)*) => {};
121     (emit I64GeU $($rest:tt)*) => {};
122     (emit I32Eqz $($rest:tt)*) => {};
123     (emit I64Eqz $($rest:tt)*) => {};
124     (emit I32And $($rest:tt)*) => {};
125     (emit I64And $($rest:tt)*) => {};
126     (emit I32Or $($rest:tt)*) => {};
127     (emit I64Or $($rest:tt)*) => {};
128     (emit I32Xor $($rest:tt)*) => {};
129     (emit I64Xor $($rest:tt)*) => {};
130     (emit I32Shl $($rest:tt)*) => {};
131     (emit I64Shl $($rest:tt)*) => {};
132     (emit I32ShrS $($rest:tt)*) => {};
133     (emit I64ShrS $($rest:tt)*) => {};
134     (emit I32ShrU $($rest:tt)*) => {};
135     (emit I64ShrU $($rest:tt)*) => {};
136     (emit I32Rotl $($rest:tt)*) => {};
137     (emit I64Rotl $($rest:tt)*) => {};
138     (emit I32Rotr $($rest:tt)*) => {};
139     (emit I64Rotr $($rest:tt)*) => {};
140     (emit I32Clz $($rest:tt)*) => {};
141     (emit I64Clz $($rest:tt)*) => {};
142     (emit I32Ctz $($rest:tt)*) => {};
143     (emit I64Ctz $($rest:tt)*) => {};
144     (emit I32Popcnt $($rest:tt)*) => {};
145     (emit I64Popcnt $($rest:tt)*) => {};
146     (emit LocalGet $($rest:tt)*) => {};
147     (emit LocalSet $($rest:tt)*) => {};
148     (emit Call $($rest:tt)*) => {};
149     (emit End $($rest:tt)*) => {};
150     (emit Nop $($rest:tt)*) => {};
151     (emit If $($rest:tt)*) => {};
152     (emit Else $($rest:tt)*) => {};
153     (emit Block $($rest:tt)*) => {};
154     (emit Loop $($rest:tt)*) => {};
155     (emit Br $($rest:tt)*) => {};
156     (emit BrIf $($rest:tt)*) => {};
157     (emit Return $($rest:tt)*) => {};
158     (emit Unreachable $($rest:tt)*) => {};
159     (emit LocalTee $($rest:tt)*) => {};
160     (emit GlobalGet $($rest:tt)*) => {};
161     (emit GlobalSet $($rest:tt)*) => {};
162     (emit Select $($rest:tt)*) => {};
163     (emit Drop $($rest:tt)*) => {};
164     (emit BrTable $($rest:tt)*) => {};
165     (emit CallIndirect $($rest:tt)*) => {};
166     (emit TableInit $($rest:tt)*) => {};
167     (emit TableCopy $($rest:tt)*) => {};
168     (emit TableGet $($rest:tt)*) => {};
169     (emit TableSet $($rest:tt)*) => {};
170     (emit TableGrow $($rest:tt)*) => {};
171     (emit TableSize $($rest:tt)*) => {};
172     (emit TableFill $($rest:tt)*) => {};
173     (emit ElemDrop $($rest:tt)*) => {};
174 
175     (emit $unsupported:tt $($rest:tt)*) => {$($rest)*};
176 }
177 
178 impl<'a, 'translation, 'data, M> VisitOperator<'a> for CodeGen<'a, 'translation, 'data, M>
179 where
180     M: MacroAssembler,
181 {
182     type Output = ();
183 
184     fn visit_i32_const(&mut self, val: i32) {
185         self.context.stack.push(Val::i32(val));
186     }
187 
188     fn visit_i64_const(&mut self, val: i64) {
189         self.context.stack.push(Val::i64(val));
190     }
191 
192     fn visit_f32_const(&mut self, val: Ieee32) {
193         self.context.stack.push(Val::f32(val));
194     }
195 
196     fn visit_f64_const(&mut self, val: Ieee64) {
197         self.context.stack.push(Val::f64(val));
198     }
199 
200     fn visit_f32_add(&mut self) {
201         self.context.binop(
202             self.masm,
203             OperandSize::S32,
204             &mut |masm: &mut M, dst, src, size| {
205                 masm.float_add(dst, dst, src, size);
206             },
207         );
208     }
209 
210     fn visit_f64_add(&mut self) {
211         self.context.binop(
212             self.masm,
213             OperandSize::S64,
214             &mut |masm: &mut M, dst, src, size| {
215                 masm.float_add(dst, dst, src, size);
216             },
217         );
218     }
219 
220     fn visit_f32_sub(&mut self) {
221         self.context.binop(
222             self.masm,
223             OperandSize::S32,
224             &mut |masm: &mut M, dst, src, size| {
225                 masm.float_sub(dst, dst, src, size);
226             },
227         );
228     }
229 
230     fn visit_f64_sub(&mut self) {
231         self.context.binop(
232             self.masm,
233             OperandSize::S64,
234             &mut |masm: &mut M, dst, src, size| {
235                 masm.float_sub(dst, dst, src, size);
236             },
237         );
238     }
239 
240     fn visit_f32_mul(&mut self) {
241         self.context.binop(
242             self.masm,
243             OperandSize::S32,
244             &mut |masm: &mut M, dst, src, size| {
245                 masm.float_mul(dst, dst, src, size);
246             },
247         );
248     }
249 
250     fn visit_f64_mul(&mut self) {
251         self.context.binop(
252             self.masm,
253             OperandSize::S64,
254             &mut |masm: &mut M, dst, src, size| {
255                 masm.float_mul(dst, dst, src, size);
256             },
257         );
258     }
259 
260     fn visit_f32_div(&mut self) {
261         self.context.binop(
262             self.masm,
263             OperandSize::S32,
264             &mut |masm: &mut M, dst, src, size| {
265                 masm.float_div(dst, dst, src, size);
266             },
267         );
268     }
269 
270     fn visit_f64_div(&mut self) {
271         self.context.binop(
272             self.masm,
273             OperandSize::S64,
274             &mut |masm: &mut M, dst, src, size| {
275                 masm.float_div(dst, dst, src, size);
276             },
277         );
278     }
279 
280     fn visit_f32_min(&mut self) {
281         self.context.binop(
282             self.masm,
283             OperandSize::S32,
284             &mut |masm: &mut M, dst, src, size| {
285                 masm.float_min(dst, dst, src, size);
286             },
287         );
288     }
289 
290     fn visit_f64_min(&mut self) {
291         self.context.binop(
292             self.masm,
293             OperandSize::S64,
294             &mut |masm: &mut M, dst, src, size| {
295                 masm.float_min(dst, dst, src, size);
296             },
297         );
298     }
299 
300     fn visit_f32_max(&mut self) {
301         self.context.binop(
302             self.masm,
303             OperandSize::S32,
304             &mut |masm: &mut M, dst, src, size| {
305                 masm.float_max(dst, dst, src, size);
306             },
307         );
308     }
309 
310     fn visit_f64_max(&mut self) {
311         self.context.binop(
312             self.masm,
313             OperandSize::S64,
314             &mut |masm: &mut M, dst, src, size| {
315                 masm.float_max(dst, dst, src, size);
316             },
317         );
318     }
319 
320     fn visit_f32_copysign(&mut self) {
321         self.context.binop(
322             self.masm,
323             OperandSize::S32,
324             &mut |masm: &mut M, dst, src, size| {
325                 masm.float_copysign(dst, dst, src, size);
326             },
327         );
328     }
329 
330     fn visit_f64_copysign(&mut self) {
331         self.context.binop(
332             self.masm,
333             OperandSize::S64,
334             &mut |masm: &mut M, dst, src, size| {
335                 masm.float_copysign(dst, dst, src, size);
336             },
337         );
338     }
339 
340     fn visit_f32_abs(&mut self) {
341         self.context
342             .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| {
343                 masm.float_abs(reg, size);
344             });
345     }
346 
347     fn visit_f64_abs(&mut self) {
348         self.context
349             .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| {
350                 masm.float_abs(reg, size);
351             });
352     }
353 
354     fn visit_f32_neg(&mut self) {
355         self.context
356             .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| {
357                 masm.float_neg(reg, size);
358             });
359     }
360 
361     fn visit_f64_neg(&mut self) {
362         self.context
363             .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| {
364                 masm.float_neg(reg, size);
365             });
366     }
367 
368     fn visit_f32_floor(&mut self) {
369         self.masm
370             .float_round(RoundingMode::Down, &mut self.context, OperandSize::S32);
371     }
372 
373     fn visit_f64_floor(&mut self) {
374         self.masm
375             .float_round(RoundingMode::Down, &mut self.context, OperandSize::S64);
376     }
377 
378     fn visit_f32_ceil(&mut self) {
379         self.masm
380             .float_round(RoundingMode::Up, &mut self.context, OperandSize::S32);
381     }
382 
383     fn visit_f64_ceil(&mut self) {
384         self.masm
385             .float_round(RoundingMode::Up, &mut self.context, OperandSize::S64);
386     }
387 
388     fn visit_f32_nearest(&mut self) {
389         self.masm
390             .float_round(RoundingMode::Nearest, &mut self.context, OperandSize::S32);
391     }
392 
393     fn visit_f64_nearest(&mut self) {
394         self.masm
395             .float_round(RoundingMode::Nearest, &mut self.context, OperandSize::S64);
396     }
397 
398     fn visit_f32_trunc(&mut self) {
399         self.masm
400             .float_round(RoundingMode::Zero, &mut self.context, OperandSize::S32);
401     }
402 
403     fn visit_f64_trunc(&mut self) {
404         self.masm
405             .float_round(RoundingMode::Zero, &mut self.context, OperandSize::S64);
406     }
407 
408     fn visit_f32_sqrt(&mut self) {
409         self.context
410             .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| {
411                 masm.float_sqrt(reg, reg, size);
412             });
413     }
414 
415     fn visit_f64_sqrt(&mut self) {
416         self.context
417             .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| {
418                 masm.float_sqrt(reg, reg, size);
419             });
420     }
421 
422     fn visit_f32_eq(&mut self) {
423         self.context.float_cmp_op(
424             self.masm,
425             OperandSize::S32,
426             &mut |masm: &mut M, dst, src1, src2, size| {
427                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Eq, size);
428             },
429         );
430     }
431 
432     fn visit_f64_eq(&mut self) {
433         self.context.float_cmp_op(
434             self.masm,
435             OperandSize::S64,
436             &mut |masm: &mut M, dst, src1, src2, size| {
437                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Eq, size);
438             },
439         );
440     }
441 
442     fn visit_f32_ne(&mut self) {
443         self.context.float_cmp_op(
444             self.masm,
445             OperandSize::S32,
446             &mut |masm: &mut M, dst, src1, src2, size| {
447                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Ne, size);
448             },
449         );
450     }
451 
452     fn visit_f64_ne(&mut self) {
453         self.context.float_cmp_op(
454             self.masm,
455             OperandSize::S64,
456             &mut |masm: &mut M, dst, src1, src2, size| {
457                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Ne, size);
458             },
459         );
460     }
461 
462     fn visit_f32_lt(&mut self) {
463         self.context.float_cmp_op(
464             self.masm,
465             OperandSize::S32,
466             &mut |masm: &mut M, dst, src1, src2, size| {
467                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Lt, size);
468             },
469         );
470     }
471 
472     fn visit_f64_lt(&mut self) {
473         self.context.float_cmp_op(
474             self.masm,
475             OperandSize::S64,
476             &mut |masm: &mut M, dst, src1, src2, size| {
477                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Lt, size);
478             },
479         );
480     }
481 
482     fn visit_f32_gt(&mut self) {
483         self.context.float_cmp_op(
484             self.masm,
485             OperandSize::S32,
486             &mut |masm: &mut M, dst, src1, src2, size| {
487                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Gt, size);
488             },
489         );
490     }
491 
492     fn visit_f64_gt(&mut self) {
493         self.context.float_cmp_op(
494             self.masm,
495             OperandSize::S64,
496             &mut |masm: &mut M, dst, src1, src2, size| {
497                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Gt, size);
498             },
499         );
500     }
501 
502     fn visit_f32_le(&mut self) {
503         self.context.float_cmp_op(
504             self.masm,
505             OperandSize::S32,
506             &mut |masm: &mut M, dst, src1, src2, size| {
507                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Le, size);
508             },
509         );
510     }
511 
512     fn visit_f64_le(&mut self) {
513         self.context.float_cmp_op(
514             self.masm,
515             OperandSize::S64,
516             &mut |masm: &mut M, dst, src1, src2, size| {
517                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Le, size);
518             },
519         );
520     }
521 
522     fn visit_f32_ge(&mut self) {
523         self.context.float_cmp_op(
524             self.masm,
525             OperandSize::S32,
526             &mut |masm: &mut M, dst, src1, src2, size| {
527                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Ge, size);
528             },
529         );
530     }
531 
532     fn visit_f64_ge(&mut self) {
533         self.context.float_cmp_op(
534             self.masm,
535             OperandSize::S64,
536             &mut |masm: &mut M, dst, src1, src2, size| {
537                 masm.float_cmp_with_set(src1, src2, dst, FloatCmpKind::Ge, size);
538             },
539         );
540     }
541 
542     fn visit_i32_add(&mut self) {
543         self.context.i32_binop(self.masm, |masm, dst, src, size| {
544             masm.add(dst, dst, src, size);
545         });
546     }
547 
548     fn visit_i64_add(&mut self) {
549         self.context.i64_binop(self.masm, |masm, dst, src, size| {
550             masm.add(dst, dst, src, size);
551         });
552     }
553 
554     fn visit_i32_sub(&mut self) {
555         self.context.i32_binop(self.masm, |masm, dst, src, size| {
556             masm.sub(dst, dst, src, size);
557         });
558     }
559 
560     fn visit_i64_sub(&mut self) {
561         self.context.i64_binop(self.masm, |masm, dst, src, size| {
562             masm.sub(dst, dst, src, size);
563         });
564     }
565 
566     fn visit_i32_mul(&mut self) {
567         self.context.i32_binop(self.masm, |masm, dst, src, size| {
568             masm.mul(dst, dst, src, size);
569         });
570     }
571 
572     fn visit_i64_mul(&mut self) {
573         self.context.i64_binop(self.masm, |masm, dst, src, size| {
574             masm.mul(dst, dst, src, size);
575         });
576     }
577 
578     fn visit_i32_div_s(&mut self) {
579         use DivKind::*;
580         use OperandSize::*;
581 
582         self.masm.div(&mut self.context, Signed, S32);
583     }
584 
585     fn visit_i32_div_u(&mut self) {
586         use DivKind::*;
587         use OperandSize::*;
588 
589         self.masm.div(&mut self.context, Unsigned, S32);
590     }
591 
592     fn visit_i64_div_s(&mut self) {
593         use DivKind::*;
594         use OperandSize::*;
595 
596         self.masm.div(&mut self.context, Signed, S64);
597     }
598 
599     fn visit_i64_div_u(&mut self) {
600         use DivKind::*;
601         use OperandSize::*;
602 
603         self.masm.div(&mut self.context, Unsigned, S64);
604     }
605 
606     fn visit_i32_rem_s(&mut self) {
607         use OperandSize::*;
608         use RemKind::*;
609 
610         self.masm.rem(&mut self.context, Signed, S32);
611     }
612 
613     fn visit_i32_rem_u(&mut self) {
614         use OperandSize::*;
615         use RemKind::*;
616 
617         self.masm.rem(&mut self.context, Unsigned, S32);
618     }
619 
620     fn visit_i64_rem_s(&mut self) {
621         use OperandSize::*;
622         use RemKind::*;
623 
624         self.masm.rem(&mut self.context, Signed, S64);
625     }
626 
627     fn visit_i64_rem_u(&mut self) {
628         use OperandSize::*;
629         use RemKind::*;
630 
631         self.masm.rem(&mut self.context, Unsigned, S64);
632     }
633 
634     fn visit_i32_eq(&mut self) {
635         self.cmp_i32s(IntCmpKind::Eq);
636     }
637 
638     fn visit_i64_eq(&mut self) {
639         self.cmp_i64s(IntCmpKind::Eq);
640     }
641 
642     fn visit_i32_ne(&mut self) {
643         self.cmp_i32s(IntCmpKind::Ne);
644     }
645 
646     fn visit_i64_ne(&mut self) {
647         self.cmp_i64s(IntCmpKind::Ne);
648     }
649 
650     fn visit_i32_lt_s(&mut self) {
651         self.cmp_i32s(IntCmpKind::LtS);
652     }
653 
654     fn visit_i64_lt_s(&mut self) {
655         self.cmp_i64s(IntCmpKind::LtS);
656     }
657 
658     fn visit_i32_lt_u(&mut self) {
659         self.cmp_i32s(IntCmpKind::LtU);
660     }
661 
662     fn visit_i64_lt_u(&mut self) {
663         self.cmp_i64s(IntCmpKind::LtU);
664     }
665 
666     fn visit_i32_le_s(&mut self) {
667         self.cmp_i32s(IntCmpKind::LeS);
668     }
669 
670     fn visit_i64_le_s(&mut self) {
671         self.cmp_i64s(IntCmpKind::LeS);
672     }
673 
674     fn visit_i32_le_u(&mut self) {
675         self.cmp_i32s(IntCmpKind::LeU);
676     }
677 
678     fn visit_i64_le_u(&mut self) {
679         self.cmp_i64s(IntCmpKind::LeU);
680     }
681 
682     fn visit_i32_gt_s(&mut self) {
683         self.cmp_i32s(IntCmpKind::GtS);
684     }
685 
686     fn visit_i64_gt_s(&mut self) {
687         self.cmp_i64s(IntCmpKind::GtS);
688     }
689 
690     fn visit_i32_gt_u(&mut self) {
691         self.cmp_i32s(IntCmpKind::GtU);
692     }
693 
694     fn visit_i64_gt_u(&mut self) {
695         self.cmp_i64s(IntCmpKind::GtU);
696     }
697 
698     fn visit_i32_ge_s(&mut self) {
699         self.cmp_i32s(IntCmpKind::GeS);
700     }
701 
702     fn visit_i64_ge_s(&mut self) {
703         self.cmp_i64s(IntCmpKind::GeS);
704     }
705 
706     fn visit_i32_ge_u(&mut self) {
707         self.cmp_i32s(IntCmpKind::GeU);
708     }
709 
710     fn visit_i64_ge_u(&mut self) {
711         self.cmp_i64s(IntCmpKind::GeU);
712     }
713 
714     fn visit_i32_eqz(&mut self) {
715         use OperandSize::*;
716 
717         self.context.unop(self.masm, S32, &mut |masm, reg, size| {
718             masm.cmp_with_set(RegImm::i32(0), reg.into(), IntCmpKind::Eq, size);
719         });
720     }
721 
722     fn visit_i64_eqz(&mut self) {
723         use OperandSize::*;
724 
725         self.context.unop(self.masm, S64, &mut |masm, reg, size| {
726             masm.cmp_with_set(RegImm::i64(0), reg.into(), IntCmpKind::Eq, size);
727         });
728     }
729 
730     fn visit_i32_clz(&mut self) {
731         use OperandSize::*;
732 
733         self.context.unop(self.masm, S32, &mut |masm, reg, size| {
734             masm.clz(reg, reg, size);
735         });
736     }
737 
738     fn visit_i64_clz(&mut self) {
739         use OperandSize::*;
740 
741         self.context.unop(self.masm, S64, &mut |masm, reg, size| {
742             masm.clz(reg, reg, size);
743         });
744     }
745 
746     fn visit_i32_ctz(&mut self) {
747         use OperandSize::*;
748 
749         self.context.unop(self.masm, S32, &mut |masm, reg, size| {
750             masm.ctz(reg, reg, size);
751         });
752     }
753 
754     fn visit_i64_ctz(&mut self) {
755         use OperandSize::*;
756 
757         self.context.unop(self.masm, S64, &mut |masm, reg, size| {
758             masm.ctz(reg, reg, size);
759         });
760     }
761 
762     fn visit_i32_and(&mut self) {
763         self.context.i32_binop(self.masm, |masm, dst, src, size| {
764             masm.and(dst, dst, src, size);
765         });
766     }
767 
768     fn visit_i64_and(&mut self) {
769         self.context.i64_binop(self.masm, |masm, dst, src, size| {
770             masm.and(dst, dst, src, size);
771         });
772     }
773 
774     fn visit_i32_or(&mut self) {
775         self.context.i32_binop(self.masm, |masm, dst, src, size| {
776             masm.or(dst, dst, src, size);
777         });
778     }
779 
780     fn visit_i64_or(&mut self) {
781         self.context.i64_binop(self.masm, |masm, dst, src, size| {
782             masm.or(dst, dst, src, size);
783         });
784     }
785 
786     fn visit_i32_xor(&mut self) {
787         self.context.i32_binop(self.masm, |masm, dst, src, size| {
788             masm.xor(dst, dst, src, size);
789         });
790     }
791 
792     fn visit_i64_xor(&mut self) {
793         self.context.i64_binop(self.masm, |masm, dst, src, size| {
794             masm.xor(dst, dst, src, size);
795         });
796     }
797 
798     fn visit_i32_shl(&mut self) {
799         use OperandSize::*;
800         use ShiftKind::*;
801 
802         self.masm.shift(&mut self.context, Shl, S32);
803     }
804 
805     fn visit_i64_shl(&mut self) {
806         use OperandSize::*;
807         use ShiftKind::*;
808 
809         self.masm.shift(&mut self.context, Shl, S64);
810     }
811 
812     fn visit_i32_shr_s(&mut self) {
813         use OperandSize::*;
814         use ShiftKind::*;
815 
816         self.masm.shift(&mut self.context, ShrS, S32);
817     }
818 
819     fn visit_i64_shr_s(&mut self) {
820         use OperandSize::*;
821         use ShiftKind::*;
822 
823         self.masm.shift(&mut self.context, ShrS, S64);
824     }
825 
826     fn visit_i32_shr_u(&mut self) {
827         use OperandSize::*;
828         use ShiftKind::*;
829 
830         self.masm.shift(&mut self.context, ShrU, S32);
831     }
832 
833     fn visit_i64_shr_u(&mut self) {
834         use OperandSize::*;
835         use ShiftKind::*;
836 
837         self.masm.shift(&mut self.context, ShrU, S64);
838     }
839 
840     fn visit_i32_rotl(&mut self) {
841         use OperandSize::*;
842         use ShiftKind::*;
843 
844         self.masm.shift(&mut self.context, Rotl, S32);
845     }
846 
847     fn visit_i64_rotl(&mut self) {
848         use OperandSize::*;
849         use ShiftKind::*;
850 
851         self.masm.shift(&mut self.context, Rotl, S64);
852     }
853 
854     fn visit_i32_rotr(&mut self) {
855         use OperandSize::*;
856         use ShiftKind::*;
857 
858         self.masm.shift(&mut self.context, Rotr, S32);
859     }
860 
861     fn visit_i64_rotr(&mut self) {
862         use OperandSize::*;
863         use ShiftKind::*;
864 
865         self.masm.shift(&mut self.context, Rotr, S64);
866     }
867 
868     fn visit_end(&mut self) {
869         if !self.context.reachable {
870             self.handle_unreachable_end();
871         } else {
872             let mut control = self.control_frames.pop().unwrap();
873             let is_outermost = self.control_frames.len() == 0;
874             // If it's not the outermost control stack frame, emit the the full "end" sequence,
875             // which involves, popping results from the value stack, pushing results back to the
876             // value stack and binding the exit label.
877             // Else, pop values from the value stack and bind the exit label.
878             if !is_outermost {
879                 control.emit_end(self.masm, &mut self.context);
880             } else {
881                 if let Some(data) = control.results() {
882                     self.context.pop_abi_results(data, self.masm);
883                 }
884                 control.bind_exit_label(self.masm);
885             }
886         }
887     }
888 
889     fn visit_i32_popcnt(&mut self) {
890         use OperandSize::*;
891         self.masm.popcnt(&mut self.context, S32);
892     }
893 
894     fn visit_i64_popcnt(&mut self) {
895         use OperandSize::*;
896 
897         self.masm.popcnt(&mut self.context, S64);
898     }
899 
900     fn visit_local_get(&mut self, index: u32) {
901         use WasmType::*;
902         let context = &mut self.context;
903         let slot = context
904             .frame
905             .get_local(index)
906             .unwrap_or_else(|| panic!("valid local at slot = {}", index));
907         match slot.ty {
908             I32 | I64 | F32 | F64 => context.stack.push(Val::local(index, slot.ty)),
909             Ref(rt) => match rt.heap_type {
910                 WasmHeapType::Func => context.stack.push(Val::local(index, slot.ty)),
911                 ht => unimplemented!("Support for WasmHeapType: {ht}"),
912             },
913             t => unimplemented!("Support local type: {t}"),
914         }
915     }
916 
917     fn visit_local_set(&mut self, index: u32) {
918         let src = self.emit_set_local(index);
919         self.context.free_reg(src);
920     }
921 
922     fn visit_call(&mut self, index: u32) {
923         let callee = self.env.callee_from_index(FuncIndex::from_u32(index));
924         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |_| callee.clone());
925     }
926 
927     fn visit_call_indirect(&mut self, type_index: u32, table_index: u32, _: u8) {
928         // Spill now because `emit_lazy_init_funcref` and the `FnCall::emit`
929         // invocations will both trigger spills since they both call functions.
930         // However, the machine instructions for the spill emitted by
931         // `emit_lazy_funcref` will be jumped over if the funcref was previously
932         // initialized which may result in the machine stack becoming
933         // unbalanced.
934         self.context.spill(self.masm);
935 
936         let type_index = TypeIndex::from_u32(type_index);
937         let table_index = TableIndex::from_u32(table_index);
938 
939         self.emit_lazy_init_funcref(table_index);
940 
941         // Perform the indirect call.
942         // This code assumes that [`Self::emit_lazy_init_funcref`] will
943         // push the funcref to the value stack.
944         match self.env.translation.module.table_plans[table_index].style {
945             TableStyle::CallerChecksSignature => {
946                 let funcref_ptr = self.context.stack.peek().map(|v| v.unwrap_reg()).unwrap();
947                 self.masm
948                     .trapz(funcref_ptr.into(), TrapCode::IndirectCallToNull);
949                 self.emit_typecheck_funcref(funcref_ptr.into(), type_index);
950             }
951         }
952 
953         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |_| {
954             self.env.funcref(type_index)
955         })
956     }
957 
958     fn visit_table_init(&mut self, elem: u32, table: u32) {
959         let ptr_type = self.env.ptr_type();
960         let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
961 
962         debug_assert!(self.context.stack.len() >= 3);
963         let at = self.context.stack.len() - 3;
964 
965         self.context.stack.insert_many(
966             at,
967             [
968                 vmctx.into(),
969                 table.try_into().unwrap(),
970                 elem.try_into().unwrap(),
971             ],
972         );
973         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
974             Callee::Builtin(cx.builtins.table_init::<M::ABI, M::Ptr>())
975         });
976     }
977 
978     fn visit_table_copy(&mut self, dst: u32, src: u32) {
979         let ptr_type = self.env.ptr_type();
980         let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
981         debug_assert!(self.context.stack.len() >= 3);
982         let at = self.context.stack.len() - 3;
983         self.context.stack.insert_many(
984             at,
985             [
986                 vmctx.into(),
987                 dst.try_into().unwrap(),
988                 src.try_into().unwrap(),
989             ],
990         );
991 
992         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |context| {
993             Callee::Builtin(context.builtins.table_copy::<M::ABI, M::Ptr>())
994         });
995     }
996 
997     fn visit_table_get(&mut self, table: u32) {
998         let table_index = TableIndex::from_u32(table);
999         let plan = self.env.table_plan(table_index);
1000         let heap_type = plan.table.wasm_ty.heap_type;
1001         let style = &plan.style;
1002 
1003         match heap_type {
1004             WasmHeapType::Func => match style {
1005                 TableStyle::CallerChecksSignature => self.emit_lazy_init_funcref(table_index),
1006             },
1007             t => unimplemented!("Support for WasmHeapType: {t}"),
1008         }
1009     }
1010 
1011     fn visit_table_grow(&mut self, table: u32) {
1012         let ptr_type = self.env.ptr_type();
1013         let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
1014         let table_index = TableIndex::from_u32(table);
1015         let table_plan = self.env.table_plan(table_index);
1016         let builtin = match table_plan.table.wasm_ty.heap_type {
1017             WasmHeapType::Func => self
1018                 .context
1019                 .builtins
1020                 .table_grow_func_ref::<M::ABI, M::Ptr>(),
1021             ty => unimplemented!("Support for HeapType: {ty}"),
1022         };
1023 
1024         let len = self.context.stack.len();
1025         // table.grow` requires at least 2 elements on the value stack.
1026         debug_assert!(len >= 2);
1027         let at = len - 2;
1028 
1029         // The table_grow builtin expects the parameters in a different
1030         // order.
1031         // The value stack at this point should contain:
1032         // [ init_value | delta ] (stack top)
1033         // but the builtin function expects the init value as the last
1034         // argument.
1035         self.context.stack.inner_mut().swap(len - 1, len - 2);
1036         self.context
1037             .stack
1038             .insert_many(at, [vmctx.into(), table.try_into().unwrap()]);
1039 
1040         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |_| {
1041             Callee::Builtin(builtin.clone())
1042         });
1043     }
1044 
1045     fn visit_table_size(&mut self, table: u32) {
1046         let table_index = TableIndex::from_u32(table);
1047         let table_data = self.env.resolve_table_data(table_index);
1048         self.masm.table_size(&table_data, &mut self.context);
1049     }
1050 
1051     fn visit_table_fill(&mut self, table: u32) {
1052         let ptr_type = self.env.ptr_type();
1053         let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
1054         let table_index = TableIndex::from_u32(table);
1055         let table_plan = self.env.table_plan(table_index);
1056         let builtin = match table_plan.table.wasm_ty.heap_type {
1057             WasmHeapType::Func => self
1058                 .context
1059                 .builtins
1060                 .table_fill_func_ref::<M::ABI, M::Ptr>(),
1061             ty => unimplemented!("Support for heap type: {ty}"),
1062         };
1063 
1064         let len = self.context.stack.len();
1065         debug_assert!(len >= 3);
1066         let at = len - 3;
1067         self.context
1068             .stack
1069             .insert_many(at, [vmctx.into(), table.try_into().unwrap()]);
1070         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |_| {
1071             Callee::Builtin(builtin.clone())
1072         })
1073     }
1074 
1075     fn visit_table_set(&mut self, table: u32) {
1076         let ptr_type = self.env.ptr_type();
1077         let table_index = TableIndex::from_u32(table);
1078         let table_data = self.env.resolve_table_data(table_index);
1079         let plan = self.env.table_plan(table_index);
1080         match plan.table.wasm_ty.heap_type {
1081             WasmHeapType::Func => match plan.style {
1082                 TableStyle::CallerChecksSignature => {
1083                     let value = self.context.pop_to_reg(self.masm, None);
1084                     let index = self.context.pop_to_reg(self.masm, None);
1085                     let base = self.context.any_gpr(self.masm);
1086                     let elem_addr = self.masm.table_elem_address(
1087                         index.into(),
1088                         base,
1089                         &table_data,
1090                         &mut self.context,
1091                     );
1092 
1093                     // Set the initialized bit.
1094                     self.masm.or(
1095                         value.into(),
1096                         value.into(),
1097                         RegImm::i64(FUNCREF_INIT_BIT as i64),
1098                         ptr_type.into(),
1099                     );
1100 
1101                     self.masm.store_ptr(value.into(), elem_addr);
1102 
1103                     self.context.free_reg(value);
1104                     self.context.free_reg(index);
1105                     self.context.free_reg(base);
1106                 }
1107             },
1108             ty => unimplemented!("Support for WasmHeapType: {ty}"),
1109         };
1110     }
1111 
1112     fn visit_elem_drop(&mut self, index: u32) {
1113         let ptr_type = self.env.ptr_type();
1114         let elem_drop = self.context.builtins.elem_drop::<M::ABI, M::Ptr>();
1115         let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
1116         self.context
1117             .stack
1118             .extend([vmctx.into(), index.try_into().unwrap()]);
1119         FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |_| {
1120             Callee::Builtin(elem_drop.clone())
1121         });
1122     }
1123 
1124     fn visit_nop(&mut self) {}
1125 
1126     fn visit_if(&mut self, blockty: BlockType) {
1127         self.control_frames.push(ControlStackFrame::r#if(
1128             self.env.resolve_block_results_data::<M::ABI>(blockty),
1129             self.env.resolve_block_type_info(blockty),
1130             self.masm,
1131             &mut self.context,
1132         ));
1133     }
1134 
1135     fn visit_else(&mut self) {
1136         if !self.context.reachable {
1137             self.handle_unreachable_else();
1138         } else {
1139             let control = self
1140                 .control_frames
1141                 .last_mut()
1142                 .unwrap_or_else(|| panic!("Expected active control stack frame for else"));
1143             control.emit_else(self.masm, &mut self.context);
1144         }
1145     }
1146 
1147     fn visit_block(&mut self, blockty: BlockType) {
1148         self.control_frames.push(ControlStackFrame::block(
1149             self.env.resolve_block_results_data::<M::ABI>(blockty),
1150             self.env.resolve_block_type_info(blockty),
1151             self.masm,
1152             &mut self.context,
1153         ));
1154     }
1155 
1156     fn visit_loop(&mut self, blockty: BlockType) {
1157         self.control_frames.push(ControlStackFrame::r#loop(
1158             self.env.resolve_block_type_info(blockty),
1159             self.masm,
1160             &mut self.context,
1161         ));
1162     }
1163 
1164     fn visit_br(&mut self, depth: u32) {
1165         let index = control_index(depth, self.control_frames.len());
1166         let frame = &mut self.control_frames[index];
1167         self.context
1168             .unconditional_jump(frame, self.masm, |masm, cx, frame| {
1169                 if let Some(r) = frame.as_target_results() {
1170                     cx.pop_abi_results(r, masm);
1171                 }
1172             });
1173     }
1174 
1175     fn visit_br_if(&mut self, depth: u32) {
1176         let index = control_index(depth, self.control_frames.len());
1177         let frame = &mut self.control_frames[index];
1178         frame.set_as_target();
1179 
1180         let top = if let Some(data) = frame.as_target_results() {
1181             let top = self.context.without::<TypedReg, M, _>(
1182                 data.results.regs(),
1183                 self.masm,
1184                 |ctx, masm| ctx.pop_to_reg(masm, None),
1185             );
1186             self.context.top_abi_results(data, self.masm);
1187             top
1188         } else {
1189             self.context.pop_to_reg(self.masm, None)
1190         };
1191 
1192         // Emit instructions to balance the machine stack if the frame has
1193         // a different offset.
1194         let current_sp_offset = self.masm.sp_offset();
1195         let (_, frame_sp_offset) = frame.base_stack_len_and_sp();
1196         let (label, cmp, needs_cleanup) = if current_sp_offset > frame_sp_offset {
1197             (self.masm.get_label(), IntCmpKind::Eq, true)
1198         } else {
1199             (*frame.label(), IntCmpKind::Ne, false)
1200         };
1201 
1202         self.masm
1203             .branch(cmp, top.reg.into(), top.reg.into(), label, OperandSize::S32);
1204         self.context.free_reg(top);
1205 
1206         if needs_cleanup {
1207             // Emit instructions to balance the stack and jump if not falling
1208             // through.
1209             self.masm.ensure_sp_for_jump(frame_sp_offset);
1210             self.masm.jmp(*frame.label());
1211 
1212             // Restore sp_offset to what it was for falling through and emit
1213             // fallthrough label.
1214             self.masm.reset_stack_pointer(current_sp_offset);
1215             self.masm.bind(label);
1216         }
1217     }
1218 
1219     fn visit_br_table(&mut self, targets: BrTable<'a>) {
1220         // +1 to account for the default target.
1221         let len = targets.len() + 1;
1222         // SmallVec<[_; 5]> to match the binary emission layer (e.g
1223         // see `JmpTableSeq'), but here we use 5 instead since we
1224         // bundle the default target as the last element in the array.
1225         let labels: SmallVec<[_; 5]> = (0..len).map(|_| self.masm.get_label()).collect();
1226 
1227         let default_index = control_index(targets.default(), self.control_frames.len());
1228         let default_result = self.control_frames[default_index].as_target_results();
1229 
1230         let (index, tmp) = if let Some(data) = default_result {
1231             let index_and_tmp = self.context.without::<(TypedReg, _), M, _>(
1232                 data.results.regs(),
1233                 self.masm,
1234                 |cx, masm| (cx.pop_to_reg(masm, None), cx.any_gpr(masm)),
1235             );
1236 
1237             // Materialize any constants or locals into their result representation,
1238             // so that when reachability is restored, they are correctly located.
1239             self.context.top_abi_results(data, self.masm);
1240             index_and_tmp
1241         } else {
1242             (
1243                 self.context.pop_to_reg(self.masm, None),
1244                 self.context.any_gpr(self.masm),
1245             )
1246         };
1247 
1248         self.masm.jmp_table(&labels, index.into(), tmp);
1249         // Save the original stack pointer offset; we will reset the stack
1250         // pointer to this offset after jumping to each of the targets. Each
1251         // jump might adjust the stack according to the base offset of the
1252         // target.
1253         let current_sp = self.masm.sp_offset();
1254 
1255         for (t, l) in targets
1256             .targets()
1257             .into_iter()
1258             .chain(std::iter::once(Ok(targets.default())))
1259             .zip(labels.iter())
1260         {
1261             let control_index = control_index(t.unwrap(), self.control_frames.len());
1262             let frame = &mut self.control_frames[control_index];
1263             // Reset the stack pointer to its original offset. This is needed
1264             // because each jump will potentially adjust the stack pointer
1265             // according to the base offset of the target.
1266             self.masm.reset_stack_pointer(current_sp);
1267 
1268             // NB: We don't perform any result handling as it was
1269             // already taken care of above before jumping to the
1270             // jump table.
1271             self.masm.bind(*l);
1272             // Ensure that the stack pointer is correctly positioned before
1273             // jumping to the jump table code.
1274             let (_, offset) = frame.base_stack_len_and_sp();
1275             self.masm.ensure_sp_for_jump(offset);
1276             self.masm.jmp(*frame.label());
1277             frame.set_as_target();
1278         }
1279         // Finally reset the stack pointer to the original location.
1280         // The reachability analysis, will ensure it's correctly located
1281         // once reachability is restored.
1282         self.masm.reset_stack_pointer(current_sp);
1283         self.context.reachable = false;
1284         self.context.free_reg(index.reg);
1285         self.context.free_reg(tmp);
1286     }
1287 
1288     fn visit_return(&mut self) {
1289         // Grab the outermost frame, which is the function's body
1290         // frame. We don't rely on [`codegen::control_index`] since
1291         // this frame is implicit and we know that it should exist at
1292         // index 0.
1293         let outermost = &mut self.control_frames[0];
1294         self.context
1295             .unconditional_jump(outermost, self.masm, |masm, cx, frame| {
1296                 if let Some(data) = frame.as_target_results() {
1297                     cx.pop_abi_results(data, masm);
1298                 }
1299             });
1300     }
1301 
1302     fn visit_unreachable(&mut self) {
1303         self.masm.unreachable();
1304         self.context.reachable = false;
1305         // Set the implicit outermost frame as target to perform the necessary
1306         // stack clean up.
1307         let outermost = &mut self.control_frames[0];
1308         outermost.set_as_target();
1309     }
1310 
1311     fn visit_local_tee(&mut self, index: u32) {
1312         let typed_reg = self.emit_set_local(index);
1313         self.context.stack.push(typed_reg.into());
1314     }
1315 
1316     fn visit_global_get(&mut self, global_index: u32) {
1317         let index = GlobalIndex::from_u32(global_index);
1318         let (ty, offset) = self.env.resolve_global_type_and_offset(index);
1319         let addr = self
1320             .masm
1321             .address_at_reg(<M::ABI as ABI>::vmctx_reg(), offset);
1322         let dst = self.context.reg_for_type(ty, self.masm);
1323         self.masm.load(addr, dst, ty.into());
1324         self.context.stack.push(Val::reg(dst, ty));
1325     }
1326 
1327     fn visit_global_set(&mut self, global_index: u32) {
1328         let index = GlobalIndex::from_u32(global_index);
1329         let (ty, offset) = self.env.resolve_global_type_and_offset(index);
1330         let addr = self
1331             .masm
1332             .address_at_reg(<M::ABI as ABI>::vmctx_reg(), offset);
1333         let typed_reg = self.context.pop_to_reg(self.masm, None);
1334         self.context.free_reg(typed_reg.reg);
1335         self.masm.store(typed_reg.reg.into(), addr, ty.into());
1336     }
1337 
1338     fn visit_drop(&mut self) {
1339         self.context.drop_last(1, |regalloc, val| match val {
1340             Val::Reg(tr) => regalloc.free(tr.reg.into()),
1341             Val::Memory(m) => self.masm.free_stack(m.slot.size),
1342             _ => {}
1343         });
1344     }
1345 
1346     fn visit_select(&mut self) {
1347         let cond = self.context.pop_to_reg(self.masm, None);
1348         let val2 = self.context.pop_to_reg(self.masm, None);
1349         let val1 = self.context.pop_to_reg(self.masm, None);
1350         self.masm
1351             .cmp(RegImm::i32(0), cond.reg.into(), OperandSize::S32);
1352         // Conditionally move val1 to val2 if the the comparision is
1353         // not zero.
1354         self.masm
1355             .cmov(val1.into(), val2.into(), IntCmpKind::Ne, val1.ty.into());
1356         self.context.stack.push(val2.into());
1357         self.context.free_reg(val1.reg);
1358         self.context.free_reg(cond);
1359     }
1360 
1361     wasmparser::for_each_operator!(def_unsupported);
1362 }
1363 
1364 impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M>
1365 where
1366     M: MacroAssembler,
1367 {
1368     fn cmp_i32s(&mut self, kind: IntCmpKind) {
1369         self.context.i32_binop(self.masm, |masm, dst, src, size| {
1370             masm.cmp_with_set(src, dst, kind, size);
1371         });
1372     }
1373 
1374     fn cmp_i64s(&mut self, kind: IntCmpKind) {
1375         self.context
1376             .i64_binop(self.masm, move |masm, dst, src, size| {
1377                 masm.cmp_with_set(src, dst, kind, size);
1378             });
1379     }
1380 }
1381 
1382 impl From<WasmType> for OperandSize {
1383     fn from(ty: WasmType) -> OperandSize {
1384         match ty {
1385             WasmType::I32 | WasmType::F32 => OperandSize::S32,
1386             WasmType::I64 | WasmType::F64 => OperandSize::S64,
1387             WasmType::Ref(rt) => {
1388                 match rt.heap_type {
1389                     // TODO: Harcoded size, assuming 64-bit support only. Once
1390                     // Wasmtime supports 32-bit architectures, this will need
1391                     // to be updated in such a way that the calculation of the
1392                     // OperandSize will depend on the target's  pointer size.
1393                     WasmHeapType::Func => OperandSize::S64,
1394                     t => unimplemented!("Support for WasmHeapType: {t}"),
1395                 }
1396             }
1397             ty => unimplemented!("Support for WasmType {ty}"),
1398         }
1399     }
1400 }
1401