xref: /wasmtime-44.0.1/winch/codegen/src/masm.rs (revision efb4e4c0)
1 use crate::abi::{self, align_to, scratch, LocalSlot};
2 use crate::codegen::{CodeGenContext, Emission, FuncEnv};
3 use crate::isa::{
4     reg::{writable, Reg, WritableReg},
5     CallingConvention,
6 };
7 use anyhow::Result;
8 use cranelift_codegen::{
9     binemit::CodeOffset,
10     ir::{Endianness, LibCall, MemFlags, RelSourceLoc, SourceLoc, UserExternalNameRef},
11     Final, MachBufferFinalized, MachLabel,
12 };
13 use std::{fmt::Debug, ops::Range};
14 use wasmtime_environ::PtrSize;
15 
16 pub(crate) use cranelift_codegen::ir::TrapCode;
17 
18 #[derive(Eq, PartialEq)]
19 pub(crate) enum DivKind {
20     /// Signed division.
21     Signed,
22     /// Unsigned division.
23     Unsigned,
24 }
25 
26 /// Remainder kind.
27 #[derive(Copy, Clone)]
28 pub(crate) enum RemKind {
29     /// Signed remainder.
30     Signed,
31     /// Unsigned remainder.
32     Unsigned,
33 }
34 
35 impl RemKind {
36     pub fn is_signed(&self) -> bool {
37         matches!(self, Self::Signed)
38     }
39 }
40 
41 /// Kinds of vector min operation supported by WebAssembly.
42 pub(crate) enum V128MinKind {
43     /// 4 lanes of 32-bit floats.
44     F32x4,
45     /// 2 lanes of 64-bit floats.
46     F64x2,
47     /// 16 lanes of signed 8-bit integers.
48     I8x16S,
49     /// 16 lanes of unsigned 8-bit integers.
50     I8x16U,
51     /// 8 lanes of signed 16-bit integers.
52     I16x8S,
53     /// 8 lanes of unsigned 16-bit integers.
54     I16x8U,
55     /// 4 lanes of signed 32-bit integers.
56     I32x4S,
57     /// 4 lanes of unsigned 32-bit integers.
58     I32x4U,
59 }
60 
61 impl V128MinKind {
62     /// The size of each lane.
63     pub(crate) fn lane_size(&self) -> OperandSize {
64         match self {
65             Self::F32x4 | Self::I32x4S | Self::I32x4U => OperandSize::S32,
66             Self::F64x2 => OperandSize::S64,
67             Self::I8x16S | Self::I8x16U => OperandSize::S8,
68             Self::I16x8S | Self::I16x8U => OperandSize::S16,
69         }
70     }
71 }
72 
73 /// Kinds of vector max operation supported by WebAssembly.
74 pub(crate) enum V128MaxKind {
75     /// 4 lanes of 32-bit floats.
76     F32x4,
77     /// 2 lanes of 64-bit floats.
78     F64x2,
79     /// 16 lanes of signed 8-bit integers.
80     I8x16S,
81     /// 16 lanes of unsigned 8-bit integers.
82     I8x16U,
83     /// 8 lanes of signed 16-bit integers.
84     I16x8S,
85     /// 8 lanes of unsigned 16-bit integers.
86     I16x8U,
87     /// 4 lanes of signed 32-bit integers.
88     I32x4S,
89     /// 4 lanes of unsigned 32-bit integers.
90     I32x4U,
91 }
92 
93 impl V128MaxKind {
94     /// The size of each lane.
95     pub(crate) fn lane_size(&self) -> OperandSize {
96         match self {
97             Self::F32x4 | Self::I32x4S | Self::I32x4U => OperandSize::S32,
98             Self::F64x2 => OperandSize::S64,
99             Self::I8x16S | Self::I8x16U => OperandSize::S8,
100             Self::I16x8S | Self::I16x8U => OperandSize::S16,
101         }
102     }
103 }
104 
105 #[derive(Eq, PartialEq)]
106 pub(crate) enum MulWideKind {
107     Signed,
108     Unsigned,
109 }
110 
111 /// Type of operation for a read-modify-write instruction.
112 pub(crate) enum RmwOp {
113     Add,
114     Sub,
115     Xchg,
116     And,
117     Or,
118     Xor,
119 }
120 
121 /// The direction to perform the memory move.
122 #[derive(Debug, Clone, Eq, PartialEq)]
123 pub(crate) enum MemMoveDirection {
124     /// From high memory addresses to low memory addresses.
125     /// Invariant: the source location is closer to the FP than the destination
126     /// location, which will be closer to the SP.
127     HighToLow,
128     /// From low memory addresses to high memory addresses.
129     /// Invariant: the source location is closer to the SP than the destination
130     /// location, which will be closer to the FP.
131     LowToHigh,
132 }
133 
134 /// Classifies how to treat float-to-int conversions.
135 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
136 pub(crate) enum TruncKind {
137     /// Saturating conversion. If the source value is greater than the maximum
138     /// value of the destination type, the result is clamped to the
139     /// destination maximum value.
140     Checked,
141     /// An exception is raised if the source value is greater than the maximum
142     /// value of the destination type.
143     Unchecked,
144 }
145 
146 impl TruncKind {
147     /// Returns true if the truncation kind is checked.
148     pub(crate) fn is_checked(&self) -> bool {
149         *self == TruncKind::Checked
150     }
151 
152     /// Returns `true` if the trunc kind is [`Unchecked`].
153     ///
154     /// [`Unchecked`]: TruncKind::Unchecked
155     #[must_use]
156     pub(crate) fn is_unchecked(&self) -> bool {
157         matches!(self, Self::Unchecked)
158     }
159 }
160 
161 /// Representation of the stack pointer offset.
162 #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)]
163 pub struct SPOffset(u32);
164 
165 impl SPOffset {
166     pub fn from_u32(offs: u32) -> Self {
167         Self(offs)
168     }
169 
170     pub fn as_u32(&self) -> u32 {
171         self.0
172     }
173 }
174 
175 /// A stack slot.
176 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
177 pub struct StackSlot {
178     /// The location of the slot, relative to the stack pointer.
179     pub offset: SPOffset,
180     /// The size of the slot, in bytes.
181     pub size: u32,
182 }
183 
184 impl StackSlot {
185     pub fn new(offs: SPOffset, size: u32) -> Self {
186         Self { offset: offs, size }
187     }
188 }
189 
190 /// Kinds of integer binary comparison in WebAssembly. The [`MacroAssembler`]
191 /// implementation for each ISA is responsible for emitting the correct
192 /// sequence of instructions when lowering to machine code.
193 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
194 pub(crate) enum IntCmpKind {
195     /// Equal.
196     Eq,
197     /// Not equal.
198     Ne,
199     /// Signed less than.
200     LtS,
201     /// Unsigned less than.
202     LtU,
203     /// Signed greater than.
204     GtS,
205     /// Unsigned greater than.
206     GtU,
207     /// Signed less than or equal.
208     LeS,
209     /// Unsigned less than or equal.
210     LeU,
211     /// Signed greater than or equal.
212     GeS,
213     /// Unsigned greater than or equal.
214     GeU,
215 }
216 
217 /// Kinds of float binary comparison in WebAssembly. The [`MacroAssembler`]
218 /// implementation for each ISA is responsible for emitting the correct
219 /// sequence of instructions when lowering code.
220 #[derive(Debug)]
221 pub(crate) enum FloatCmpKind {
222     /// Equal.
223     Eq,
224     /// Not equal.
225     Ne,
226     /// Less than.
227     Lt,
228     /// Greater than.
229     Gt,
230     /// Less than or equal.
231     Le,
232     /// Greater than or equal.
233     Ge,
234 }
235 
236 /// Kinds of shifts in WebAssembly.The [`masm`] implementation for each ISA is
237 /// responsible for emitting the correct sequence of instructions when
238 /// lowering to machine code.
239 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
240 pub(crate) enum ShiftKind {
241     /// Left shift.
242     Shl,
243     /// Signed right shift.
244     ShrS,
245     /// Unsigned right shift.
246     ShrU,
247     /// Left rotate.
248     Rotl,
249     /// Right rotate.
250     Rotr,
251 }
252 
253 /// Kinds of extends in WebAssembly. Each MacroAssembler implementation
254 /// is responsible for emitting the correct sequence of instructions when
255 /// lowering to machine code.
256 #[derive(Copy, Clone)]
257 pub(crate) enum ExtendKind {
258     Signed(Extend<Signed>),
259     Unsigned(Extend<Zero>),
260 }
261 
262 #[derive(Copy, Clone)]
263 pub(crate) enum Signed {}
264 #[derive(Copy, Clone)]
265 pub(crate) enum Zero {}
266 
267 pub(crate) trait ExtendType {}
268 
269 impl ExtendType for Signed {}
270 impl ExtendType for Zero {}
271 
272 #[derive(Copy, Clone)]
273 pub(crate) enum Extend<T: ExtendType> {
274     /// 8 to 32 bit extend.
275     I32Extend8,
276     /// 16 to 32 bit extend.
277     I32Extend16,
278     /// 8 to 64 bit extend.
279     I64Extend8,
280     /// 16 to 64 bit extend.
281     I64Extend16,
282     /// 32 to 64 bit extend.
283     I64Extend32,
284 
285     /// Variant to hold the kind of extend marker.
286     ///
287     /// This is `Signed` or `Zero`, that are empty enums, which means that this variant cannot be
288     /// constructed.
289     __Kind(T),
290 }
291 
292 impl From<Extend<Zero>> for ExtendKind {
293     fn from(value: Extend<Zero>) -> Self {
294         ExtendKind::Unsigned(value)
295     }
296 }
297 
298 impl<T: ExtendType> Extend<T> {
299     pub fn from_size(&self) -> OperandSize {
300         match self {
301             Extend::I32Extend8 | Extend::I64Extend8 => OperandSize::S8,
302             Extend::I32Extend16 | Extend::I64Extend16 => OperandSize::S16,
303             Extend::I64Extend32 => OperandSize::S32,
304             Extend::__Kind(_) => unreachable!(),
305         }
306     }
307 
308     pub fn to_size(&self) -> OperandSize {
309         match self {
310             Extend::I32Extend8 | Extend::I32Extend16 => OperandSize::S32,
311             Extend::I64Extend8 | Extend::I64Extend16 | Extend::I64Extend32 => OperandSize::S64,
312             Extend::__Kind(_) => unreachable!(),
313         }
314     }
315 
316     pub fn from_bits(&self) -> u8 {
317         self.from_size().num_bits()
318     }
319 
320     pub fn to_bits(&self) -> u8 {
321         self.to_size().num_bits()
322     }
323 }
324 
325 impl From<Extend<Signed>> for ExtendKind {
326     fn from(value: Extend<Signed>) -> Self {
327         ExtendKind::Signed(value)
328     }
329 }
330 
331 impl ExtendKind {
332     pub fn signed(&self) -> bool {
333         match self {
334             Self::Signed(_) => true,
335             _ => false,
336         }
337     }
338 
339     pub fn from_bits(&self) -> u8 {
340         match self {
341             Self::Signed(s) => s.from_bits(),
342             Self::Unsigned(u) => u.from_bits(),
343         }
344     }
345 
346     pub fn to_bits(&self) -> u8 {
347         match self {
348             Self::Signed(s) => s.to_bits(),
349             Self::Unsigned(u) => u.to_bits(),
350         }
351     }
352 }
353 
354 /// Kinds of vector load and extends in WebAssembly. Each MacroAssembler
355 /// implementation is responsible for emitting the correct sequence of
356 /// instructions when lowering to machine code.
357 #[derive(Copy, Clone)]
358 pub(crate) enum V128LoadExtendKind {
359     /// Sign extends eight 8 bit integers to eight 16 bit lanes.
360     E8x8S,
361     /// Zero extends eight 8 bit integers to eight 16 bit lanes.
362     E8x8U,
363     /// Sign extends four 16 bit integers to four 32 bit lanes.
364     E16x4S,
365     /// Zero extends four 16 bit integers to four 32 bit lanes.
366     E16x4U,
367     /// Sign extends two 32 bit integers to two 64 bit lanes.
368     E32x2S,
369     /// Zero extends two 32 bit integers to two 64 bit lanes.
370     E32x2U,
371 }
372 
373 /// Kinds of splat loads supported by WebAssembly.
374 pub(crate) enum SplatLoadKind {
375     /// 8 bits.
376     S8,
377     /// 16 bits.
378     S16,
379     /// 32 bits.
380     S32,
381     /// 64 bits.
382     S64,
383 }
384 
385 /// Kinds of splat supported by WebAssembly.
386 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
387 pub(crate) enum SplatKind {
388     /// 8 bit integer.
389     I8x16,
390     /// 16 bit integer.
391     I16x8,
392     /// 32 bit integer.
393     I32x4,
394     /// 64 bit integer.
395     I64x2,
396     /// 32 bit float.
397     F32x4,
398     /// 64 bit float.
399     F64x2,
400 }
401 
402 impl SplatKind {
403     /// The lane size to use for different kinds of splats.
404     pub(crate) fn lane_size(&self) -> OperandSize {
405         match self {
406             SplatKind::I8x16 => OperandSize::S8,
407             SplatKind::I16x8 => OperandSize::S16,
408             SplatKind::I32x4 | SplatKind::F32x4 => OperandSize::S32,
409             SplatKind::I64x2 | SplatKind::F64x2 => OperandSize::S64,
410         }
411     }
412 }
413 
414 /// Kinds of extract lane supported by WebAssembly.
415 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
416 pub(crate) enum ExtractLaneKind {
417     /// 16 lanes of 8-bit integers sign extended to 32-bits.
418     I8x16S,
419     /// 16 lanes of 8-bit integers zero extended to 32-bits.
420     I8x16U,
421     /// 8 lanes of 16-bit integers sign extended to 32-bits.
422     I16x8S,
423     /// 8 lanes of 16-bit integers zero extended to 32-bits.
424     I16x8U,
425     /// 4 lanes of 32-bit integers.
426     I32x4,
427     /// 2 lanes of 64-bit integers.
428     I64x2,
429     /// 4 lanes of 32-bit floats.
430     F32x4,
431     /// 2 lanes of 64-bit floats.
432     F64x2,
433 }
434 
435 impl ExtractLaneKind {
436     /// The lane size to use for different kinds of extract lane kinds.
437     pub(crate) fn lane_size(&self) -> OperandSize {
438         match self {
439             ExtractLaneKind::I8x16S | ExtractLaneKind::I8x16U => OperandSize::S8,
440             ExtractLaneKind::I16x8S | ExtractLaneKind::I16x8U => OperandSize::S16,
441             ExtractLaneKind::I32x4 | ExtractLaneKind::F32x4 => OperandSize::S32,
442             ExtractLaneKind::I64x2 | ExtractLaneKind::F64x2 => OperandSize::S64,
443         }
444     }
445 }
446 
447 impl From<ExtractLaneKind> for Extend<Signed> {
448     fn from(value: ExtractLaneKind) -> Self {
449         match value {
450             ExtractLaneKind::I8x16S => Extend::I32Extend8,
451             ExtractLaneKind::I16x8S => Extend::I32Extend16,
452             _ => unimplemented!(),
453         }
454     }
455 }
456 
457 /// Kinds of replace lane supported by WebAssembly.
458 pub(crate) enum ReplaceLaneKind {
459     /// 16 lanes of 8 bit integers.
460     I8x16,
461     /// 8 lanes of 16 bit integers.
462     I16x8,
463     /// 4 lanes of 32 bit integers.
464     I32x4,
465     /// 2 lanes of 64 bit integers.
466     I64x2,
467     /// 4 lanes of 32 bit floats.
468     F32x4,
469     /// 2 lanes of 64 bit floats.
470     F64x2,
471 }
472 
473 impl ReplaceLaneKind {
474     /// The lane size to use for different kinds of replace lane kinds.
475     pub(crate) fn lane_size(&self) -> OperandSize {
476         match self {
477             ReplaceLaneKind::I8x16 => OperandSize::S8,
478             ReplaceLaneKind::I16x8 => OperandSize::S16,
479             ReplaceLaneKind::I32x4 => OperandSize::S32,
480             ReplaceLaneKind::I64x2 => OperandSize::S64,
481             ReplaceLaneKind::F32x4 => OperandSize::S32,
482             ReplaceLaneKind::F64x2 => OperandSize::S64,
483         }
484     }
485 }
486 
487 /// Kinds of behavior supported by Wasm loads.
488 pub(crate) enum LoadKind {
489     /// Load the entire bytes of the operand size without any modifications.
490     Operand(OperandSize),
491     /// Atomic load, with optional scalar extend.
492     Atomic(OperandSize, Option<ExtendKind>),
493     /// Duplicate value into vector lanes.
494     Splat(SplatLoadKind),
495     /// Scalar (non-vector) extend.
496     ScalarExtend(ExtendKind),
497     /// Vector extend.
498     VectorExtend(V128LoadExtendKind),
499     /// Load content into select lane.
500     VectorLane(LaneSelector),
501     /// Load a single element into the lowest bits of a vector and initialize
502     /// all other bits to zero.
503     VectorZero(OperandSize),
504 }
505 
506 impl LoadKind {
507     /// Returns the [`OperandSize`] used in the load operation.
508     pub(crate) fn derive_operand_size(&self) -> OperandSize {
509         match self {
510             Self::ScalarExtend(extend) | Self::Atomic(_, Some(extend)) => {
511                 Self::operand_size_for_scalar(extend)
512             }
513             Self::VectorExtend(_) => OperandSize::S64,
514             Self::Splat(kind) => Self::operand_size_for_splat(kind),
515             Self::Operand(size)
516             | Self::Atomic(size, None)
517             | Self::VectorLane(LaneSelector { size, .. })
518             | Self::VectorZero(size) => *size,
519         }
520     }
521 
522     pub fn vector_lane(lane: u8, size: OperandSize) -> Self {
523         Self::VectorLane(LaneSelector { lane, size })
524     }
525 
526     fn operand_size_for_scalar(extend_kind: &ExtendKind) -> OperandSize {
527         match extend_kind {
528             ExtendKind::Signed(s) => s.from_size(),
529             ExtendKind::Unsigned(u) => u.from_size(),
530         }
531     }
532 
533     fn operand_size_for_splat(kind: &SplatLoadKind) -> OperandSize {
534         match kind {
535             SplatLoadKind::S8 => OperandSize::S8,
536             SplatLoadKind::S16 => OperandSize::S16,
537             SplatLoadKind::S32 => OperandSize::S32,
538             SplatLoadKind::S64 => OperandSize::S64,
539         }
540     }
541 
542     pub(crate) fn is_atomic(&self) -> bool {
543         matches!(self, Self::Atomic(_, _))
544     }
545 }
546 
547 /// Kinds of behavior supported by Wasm loads.
548 #[derive(Copy, Clone)]
549 pub enum StoreKind {
550     /// Store the entire bytes of the operand size without any modifications.
551     Operand(OperandSize),
552     /// Store the entire bytes of the operand size without any modifications, atomically.
553     Atomic(OperandSize),
554     /// Store the content of selected lane.
555     VectorLane(LaneSelector),
556 }
557 
558 impl StoreKind {
559     pub fn vector_lane(lane: u8, size: OperandSize) -> Self {
560         Self::VectorLane(LaneSelector { lane, size })
561     }
562 }
563 
564 #[derive(Copy, Clone)]
565 pub struct LaneSelector {
566     pub lane: u8,
567     pub size: OperandSize,
568 }
569 
570 /// Types of vector integer to float conversions supported by WebAssembly.
571 pub(crate) enum V128ConvertKind {
572     /// 4 lanes of signed 32-bit integers to 4 lanes of 32-bit floats.
573     I32x4S,
574     /// 4 lanes of unsigned 32-bit integers to 4 lanes of 32-bit floats.
575     I32x4U,
576     /// 4 lanes of signed 32-bit integers to low bits of 2 lanes of 64-bit
577     /// floats.
578     I32x4LowS,
579     /// 4 lanes of unsigned 32-bit integers to low bits of 2 lanes of 64-bit
580     /// floats.
581     I32x4LowU,
582 }
583 
584 impl V128ConvertKind {
585     pub(crate) fn src_lane_size(&self) -> OperandSize {
586         match self {
587             V128ConvertKind::I32x4S
588             | V128ConvertKind::I32x4U
589             | V128ConvertKind::I32x4LowS
590             | V128ConvertKind::I32x4LowU => OperandSize::S32,
591         }
592     }
593 
594     pub(crate) fn dst_lane_size(&self) -> OperandSize {
595         match self {
596             V128ConvertKind::I32x4S | V128ConvertKind::I32x4U => OperandSize::S32,
597             V128ConvertKind::I32x4LowS | V128ConvertKind::I32x4LowU => OperandSize::S64,
598         }
599     }
600 }
601 
602 /// Kinds of vector narrowing operations supported by WebAssembly.
603 pub(crate) enum V128NarrowKind {
604     /// Narrow 8 lanes of 16-bit integers to 16 lanes of 8-bit integers using
605     /// signed saturation.
606     I16x8S,
607     /// Narrow 8 lanes of 16-bit integers to 16 lanes of 8-bit integers using
608     /// unsigned saturation.
609     I16x8U,
610     /// Narrow 4 lanes of 32-bit integers to 8 lanes of 16-bit integers using
611     /// signed saturation.
612     I32x4S,
613     /// Narrow 4 lanes of 32-bit integers to 8 lanes of 16-bit integers using
614     /// unsigned saturation.
615     I32x4U,
616 }
617 
618 impl V128NarrowKind {
619     /// Return the size of the destination lanes.
620     pub(crate) fn dst_lane_size(&self) -> OperandSize {
621         match self {
622             Self::I16x8S | Self::I16x8U => OperandSize::S8,
623             Self::I32x4S | Self::I32x4U => OperandSize::S16,
624         }
625     }
626 }
627 
628 /// Kinds of vector extending operations supported by WebAssembly.
629 #[derive(Debug, Copy, Clone)]
630 pub(crate) enum V128ExtendKind {
631     /// Low half of i8x16 sign extended.
632     LowI8x16S,
633     /// High half of i8x16 sign extended.
634     HighI8x16S,
635     /// Low half of i8x16 zero extended.
636     LowI8x16U,
637     /// High half of i8x16 zero extended.
638     HighI8x16U,
639     /// Low half of i16x8 sign extended.
640     LowI16x8S,
641     /// High half of i16x8 sign extended.
642     HighI16x8S,
643     /// Low half of i16x8 zero extended.
644     LowI16x8U,
645     /// High half of i16x8 zero extended.
646     HighI16x8U,
647     /// Low half of i32x4 sign extended.
648     LowI32x4S,
649     /// High half of i32x4 sign extended.
650     HighI32x4S,
651     /// Low half of i32x4 zero extended.
652     LowI32x4U,
653     /// High half of i32x4 zero extended.
654     HighI32x4U,
655 }
656 
657 impl V128ExtendKind {
658     /// The size of the source's lanes.
659     pub(crate) fn src_lane_size(&self) -> OperandSize {
660         match self {
661             Self::LowI8x16S | Self::LowI8x16U | Self::HighI8x16S | Self::HighI8x16U => {
662                 OperandSize::S8
663             }
664             Self::LowI16x8S | Self::LowI16x8U | Self::HighI16x8S | Self::HighI16x8U => {
665                 OperandSize::S16
666             }
667             Self::LowI32x4S | Self::LowI32x4U | Self::HighI32x4S | Self::HighI32x4U => {
668                 OperandSize::S32
669             }
670         }
671     }
672 }
673 
674 /// Kinds of vector equalities and non-equalities supported by WebAssembly.
675 pub(crate) enum VectorEqualityKind {
676     /// 16 lanes of 8 bit integers.
677     I8x16,
678     /// 8 lanes of 16 bit integers.
679     I16x8,
680     /// 4 lanes of 32 bit integers.
681     I32x4,
682     /// 2 lanes of 64 bit integers.
683     I64x2,
684     /// 4 lanes of 32 bit floats.
685     F32x4,
686     /// 2 lanes of 64 bit floats.
687     F64x2,
688 }
689 
690 impl VectorEqualityKind {
691     /// Get the lane size to use.
692     pub(crate) fn lane_size(&self) -> OperandSize {
693         match self {
694             Self::I8x16 => OperandSize::S8,
695             Self::I16x8 => OperandSize::S16,
696             Self::I32x4 | Self::F32x4 => OperandSize::S32,
697             Self::I64x2 | Self::F64x2 => OperandSize::S64,
698         }
699     }
700 }
701 
702 /// Kinds of vector comparisons supported by WebAssembly.
703 pub(crate) enum VectorCompareKind {
704     /// 16 lanes of signed 8 bit integers.
705     I8x16S,
706     /// 16 lanes of unsigned 8 bit integers.
707     I8x16U,
708     /// 8 lanes of signed 16 bit integers.
709     I16x8S,
710     /// 8 lanes of unsigned 16 bit integers.
711     I16x8U,
712     /// 4 lanes of signed 32 bit integers.
713     I32x4S,
714     /// 4 lanes of unsigned 32 bit integers.
715     I32x4U,
716     /// 2 lanes of signed 64 bit integers.
717     I64x2S,
718     /// 4 lanes of 32 bit floats.
719     F32x4,
720     /// 2 lanes of 64 bit floats.
721     F64x2,
722 }
723 
724 impl VectorCompareKind {
725     /// Get the lane size to use.
726     pub(crate) fn lane_size(&self) -> OperandSize {
727         match self {
728             Self::I8x16S | Self::I8x16U => OperandSize::S8,
729             Self::I16x8S | Self::I16x8U => OperandSize::S16,
730             Self::I32x4S | Self::I32x4U | Self::F32x4 => OperandSize::S32,
731             Self::I64x2S | Self::F64x2 => OperandSize::S64,
732         }
733     }
734 }
735 
736 /// Kinds of vector absolute operations supported by WebAssembly.
737 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
738 pub(crate) enum V128AbsKind {
739     /// 8 bit integers.
740     I8x16,
741     /// 16 bit integers.
742     I16x8,
743     /// 32 bit integers.
744     I32x4,
745     /// 64 bit integers.
746     I64x2,
747     /// 32 bit floats.
748     F32x4,
749     /// 64 bit floats.
750     F64x2,
751 }
752 
753 impl V128AbsKind {
754     /// The lane size to use.
755     pub(crate) fn lane_size(&self) -> OperandSize {
756         match self {
757             Self::I8x16 => OperandSize::S8,
758             Self::I16x8 => OperandSize::S16,
759             Self::I32x4 | Self::F32x4 => OperandSize::S32,
760             Self::I64x2 | Self::F64x2 => OperandSize::S64,
761         }
762     }
763 }
764 
765 /// Kinds of truncation for vectors supported by WebAssembly.
766 pub(crate) enum V128TruncKind {
767     /// Truncates 4 lanes of 32-bit floats to nearest integral value.
768     F32x4,
769     /// Truncates 2 lanes of 64-bit floats to nearest integral value.
770     F64x2,
771     /// Integers from signed F32x4.
772     I32x4FromF32x4S,
773     /// Integers from unsigned F32x4.
774     I32x4FromF32x4U,
775     /// Integers from signed F64x2.
776     I32x4FromF64x2SZero,
777     /// Integers from unsigned F64x2.
778     I32x4FromF64x2UZero,
779 }
780 
781 impl V128TruncKind {
782     /// The size of the source lanes.
783     pub(crate) fn src_lane_size(&self) -> OperandSize {
784         match self {
785             V128TruncKind::F32x4
786             | V128TruncKind::I32x4FromF32x4S
787             | V128TruncKind::I32x4FromF32x4U => OperandSize::S32,
788             V128TruncKind::F64x2
789             | V128TruncKind::I32x4FromF64x2SZero
790             | V128TruncKind::I32x4FromF64x2UZero => OperandSize::S64,
791         }
792     }
793 
794     /// The size of the destination lanes.
795     pub(crate) fn dst_lane_size(&self) -> OperandSize {
796         if let V128TruncKind::F64x2 = self {
797             OperandSize::S64
798         } else {
799             OperandSize::S32
800         }
801     }
802 }
803 
804 /// Kinds of vector addition supported by WebAssembly.
805 pub(crate) enum V128AddKind {
806     /// 4 lanes of 32-bit floats wrapping.
807     F32x4,
808     /// 2 lanes of 64-bit floats wrapping.
809     F64x2,
810     /// 16 lanes of 8-bit integers wrapping.
811     I8x16,
812     /// 16 lanes of 8-bit integers signed saturating.
813     I8x16SatS,
814     /// 16 lanes of 8-bit integers unsigned saturating.
815     I8x16SatU,
816     /// 8 lanes of 16-bit integers wrapping.
817     I16x8,
818     /// 8 lanes of 16-bit integers signed saturating.
819     I16x8SatS,
820     /// 8 lanes of 16-bit integers unsigned saturating.
821     I16x8SatU,
822     /// 4 lanes of 32-bit integers wrapping.
823     I32x4,
824     /// 2 lanes of 64-bit integers wrapping.
825     I64x2,
826 }
827 
828 /// Kinds of vector subtraction supported by WebAssembly.
829 pub(crate) enum V128SubKind {
830     /// 4 lanes of 32-bit floats wrapping.
831     F32x4,
832     /// 2 lanes of 64-bit floats wrapping.
833     F64x2,
834     /// 16 lanes of 8-bit integers wrapping.
835     I8x16,
836     /// 16 lanes of 8-bit integers signed saturating.
837     I8x16SatS,
838     /// 16 lanes of 8-bit integers unsigned saturating.
839     I8x16SatU,
840     /// 8 lanes of 16-bit integers wrapping.
841     I16x8,
842     /// 8 lanes of 16-bit integers signed saturating.
843     I16x8SatS,
844     /// 8 lanes of 16-bit integers unsigned saturating.
845     I16x8SatU,
846     /// 4 lanes of 32-bit integers wrapping.
847     I32x4,
848     /// 2 lanes of 64-bit integers wrapping.
849     I64x2,
850 }
851 
852 impl From<V128NegKind> for V128SubKind {
853     fn from(value: V128NegKind) -> Self {
854         match value {
855             V128NegKind::I8x16 => Self::I8x16,
856             V128NegKind::I16x8 => Self::I16x8,
857             V128NegKind::I32x4 => Self::I32x4,
858             V128NegKind::I64x2 => Self::I64x2,
859             V128NegKind::F32x4 | V128NegKind::F64x2 => unimplemented!(),
860         }
861     }
862 }
863 
864 /// Kinds of vector multiplication supported by WebAssembly.
865 pub(crate) enum V128MulKind {
866     /// 4 lanes of 32-bit floats.
867     F32x4,
868     /// 2 lanes of 64-bit floats.
869     F64x2,
870     /// 8 lanes of 16-bit integers.
871     I16x8,
872     /// 4 lanes of 32-bit integers.
873     I32x4,
874     /// 2 lanes of 64-bit integers.
875     I64x2,
876 }
877 
878 /// Kinds of vector negation supported by WebAssembly.
879 pub(crate) enum V128NegKind {
880     /// 4 lanes of 32-bit floats.
881     F32x4,
882     /// 2 lanes of 64-bit floats.
883     F64x2,
884     /// 16 lanes of 8-bit integers.
885     I8x16,
886     /// 8 lanes of 16-bit integers.
887     I16x8,
888     /// 4 lanes of 32-bit integers.
889     I32x4,
890     /// 2 lanes of 64-bit integers.
891     I64x2,
892 }
893 
894 impl V128NegKind {
895     /// The size of the lanes.
896     pub(crate) fn lane_size(&self) -> OperandSize {
897         match self {
898             Self::F32x4 | Self::I32x4 => OperandSize::S32,
899             Self::F64x2 | Self::I64x2 => OperandSize::S64,
900             Self::I8x16 => OperandSize::S8,
901             Self::I16x8 => OperandSize::S16,
902         }
903     }
904 }
905 
906 /// Kinds of extended pairwise addition supported by WebAssembly.
907 pub(crate) enum V128ExtAddKind {
908     /// 16 lanes of signed 8-bit integers.
909     I8x16S,
910     /// 16 lanes of unsigned 8-bit integers.
911     I8x16U,
912     /// 8 lanes of signed 16-bit integers.
913     I16x8S,
914     /// 8 lanes of unsigned 16-bit integers.
915     I16x8U,
916 }
917 
918 /// Kinds of vector extended multiplication supported by WebAssembly.
919 #[derive(Debug, Clone, Copy)]
920 pub(crate) enum V128ExtMulKind {
921     LowI8x16S,
922     HighI8x16S,
923     LowI8x16U,
924     HighI8x16U,
925     LowI16x8S,
926     HighI16x8S,
927     LowI16x8U,
928     HighI16x8U,
929     LowI32x4S,
930     HighI32x4S,
931     LowI32x4U,
932     HighI32x4U,
933 }
934 
935 impl From<V128ExtMulKind> for V128ExtendKind {
936     fn from(value: V128ExtMulKind) -> Self {
937         match value {
938             V128ExtMulKind::LowI8x16S => Self::LowI8x16S,
939             V128ExtMulKind::HighI8x16S => Self::HighI8x16S,
940             V128ExtMulKind::LowI8x16U => Self::LowI8x16U,
941             V128ExtMulKind::HighI8x16U => Self::HighI8x16U,
942             V128ExtMulKind::LowI16x8S => Self::LowI16x8S,
943             V128ExtMulKind::HighI16x8S => Self::HighI16x8S,
944             V128ExtMulKind::LowI16x8U => Self::LowI16x8U,
945             V128ExtMulKind::HighI16x8U => Self::HighI16x8U,
946             V128ExtMulKind::LowI32x4S => Self::LowI32x4S,
947             V128ExtMulKind::HighI32x4S => Self::HighI32x4S,
948             V128ExtMulKind::LowI32x4U => Self::LowI32x4U,
949             V128ExtMulKind::HighI32x4U => Self::HighI32x4U,
950         }
951     }
952 }
953 
954 impl From<V128ExtMulKind> for V128MulKind {
955     fn from(value: V128ExtMulKind) -> Self {
956         match value {
957             V128ExtMulKind::LowI8x16S
958             | V128ExtMulKind::HighI8x16S
959             | V128ExtMulKind::LowI8x16U
960             | V128ExtMulKind::HighI8x16U => Self::I16x8,
961             V128ExtMulKind::LowI16x8S
962             | V128ExtMulKind::HighI16x8S
963             | V128ExtMulKind::LowI16x8U
964             | V128ExtMulKind::HighI16x8U => Self::I32x4,
965             V128ExtMulKind::LowI32x4S
966             | V128ExtMulKind::HighI32x4S
967             | V128ExtMulKind::LowI32x4U
968             | V128ExtMulKind::HighI32x4U => Self::I64x2,
969         }
970     }
971 }
972 
973 /// Operand size, in bits.
974 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
975 pub(crate) enum OperandSize {
976     /// 8 bits.
977     S8,
978     /// 16 bits.
979     S16,
980     /// 32 bits.
981     S32,
982     /// 64 bits.
983     S64,
984     /// 128 bits.
985     S128,
986 }
987 
988 impl OperandSize {
989     /// The number of bits in the operand.
990     pub fn num_bits(&self) -> u8 {
991         match self {
992             OperandSize::S8 => 8,
993             OperandSize::S16 => 16,
994             OperandSize::S32 => 32,
995             OperandSize::S64 => 64,
996             OperandSize::S128 => 128,
997         }
998     }
999 
1000     /// The number of bytes in the operand.
1001     pub fn bytes(&self) -> u32 {
1002         match self {
1003             Self::S8 => 1,
1004             Self::S16 => 2,
1005             Self::S32 => 4,
1006             Self::S64 => 8,
1007             Self::S128 => 16,
1008         }
1009     }
1010 
1011     /// The binary logarithm of the number of bits in the operand.
1012     pub fn log2(&self) -> u8 {
1013         match self {
1014             OperandSize::S8 => 3,
1015             OperandSize::S16 => 4,
1016             OperandSize::S32 => 5,
1017             OperandSize::S64 => 6,
1018             OperandSize::S128 => 7,
1019         }
1020     }
1021 
1022     /// Create an [`OperandSize`]  from the given number of bytes.
1023     pub fn from_bytes(bytes: u8) -> Self {
1024         use OperandSize::*;
1025         match bytes {
1026             4 => S32,
1027             8 => S64,
1028             16 => S128,
1029             _ => panic!("Invalid bytes {bytes} for OperandSize"),
1030         }
1031     }
1032 
1033     pub fn extend_to<T: ExtendType>(&self, to: Self) -> Option<Extend<T>> {
1034         match to {
1035             OperandSize::S32 => match self {
1036                 OperandSize::S8 => Some(Extend::I32Extend8),
1037                 OperandSize::S16 => Some(Extend::I32Extend16),
1038                 _ => None,
1039             },
1040             OperandSize::S64 => match self {
1041                 OperandSize::S8 => Some(Extend::I64Extend8),
1042                 OperandSize::S16 => Some(Extend::I64Extend16),
1043                 OperandSize::S32 => Some(Extend::I64Extend32),
1044                 _ => None,
1045             },
1046             _ => None,
1047         }
1048     }
1049 
1050     /// The number of bits in the mantissa.
1051     ///
1052     /// Only implemented for floats.
1053     pub fn mantissa_bits(&self) -> u8 {
1054         match self {
1055             Self::S32 => 8,
1056             Self::S64 => 11,
1057             _ => unimplemented!(),
1058         }
1059     }
1060 }
1061 
1062 /// An abstraction over a register or immediate.
1063 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1064 pub(crate) enum RegImm {
1065     /// A register.
1066     Reg(Reg),
1067     /// A tagged immediate argument.
1068     Imm(Imm),
1069 }
1070 
1071 /// An tagged representation of an immediate.
1072 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1073 pub(crate) enum Imm {
1074     /// I32 immediate.
1075     I32(u32),
1076     /// I64 immediate.
1077     I64(u64),
1078     /// F32 immediate.
1079     F32(u32),
1080     /// F64 immediate.
1081     F64(u64),
1082     /// V128 immediate.
1083     V128(i128),
1084 }
1085 
1086 impl Imm {
1087     /// Create a new I64 immediate.
1088     pub fn i64(val: i64) -> Self {
1089         Self::I64(val as u64)
1090     }
1091 
1092     /// Create a new I32 immediate.
1093     pub fn i32(val: i32) -> Self {
1094         Self::I32(val as u32)
1095     }
1096 
1097     /// Create a new F32 immediate.
1098     pub fn f32(bits: u32) -> Self {
1099         Self::F32(bits)
1100     }
1101 
1102     /// Create a new F64 immediate.
1103     pub fn f64(bits: u64) -> Self {
1104         Self::F64(bits)
1105     }
1106 
1107     /// Create a new V128 immediate.
1108     pub fn v128(bits: i128) -> Self {
1109         Self::V128(bits)
1110     }
1111 
1112     /// Convert the immediate to i32, if possible.
1113     pub fn to_i32(&self) -> Option<i32> {
1114         match self {
1115             Self::I32(v) => Some(*v as i32),
1116             Self::I64(v) => i32::try_from(*v as i64).ok(),
1117             _ => None,
1118         }
1119     }
1120 
1121     /// Returns true if the [`Imm`] is float.
1122     pub fn is_float(&self) -> bool {
1123         match self {
1124             Self::F32(_) | Self::F64(_) => true,
1125             _ => false,
1126         }
1127     }
1128 
1129     /// Get the operand size of the immediate.
1130     pub fn size(&self) -> OperandSize {
1131         match self {
1132             Self::I32(_) | Self::F32(_) => OperandSize::S32,
1133             Self::I64(_) | Self::F64(_) => OperandSize::S64,
1134             Self::V128(_) => OperandSize::S128,
1135         }
1136     }
1137 
1138     /// Get a little endian representation of the immediate.
1139     ///
1140     /// This method heap allocates and is intended to be used when adding
1141     /// values to the constant pool.
1142     pub fn to_bytes(&self) -> Vec<u8> {
1143         match self {
1144             Imm::I32(n) => n.to_le_bytes().to_vec(),
1145             Imm::I64(n) => n.to_le_bytes().to_vec(),
1146             Imm::F32(n) => n.to_le_bytes().to_vec(),
1147             Imm::F64(n) => n.to_le_bytes().to_vec(),
1148             Imm::V128(n) => n.to_le_bytes().to_vec(),
1149         }
1150     }
1151 }
1152 
1153 /// The location of the [VMcontext] used for function calls.
1154 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
1155 pub(crate) enum VMContextLoc {
1156     /// Dynamic, stored in the given register.
1157     Reg(Reg),
1158     /// The pinned [VMContext] register.
1159     Pinned,
1160 }
1161 
1162 /// The maximum number of context arguments currently used across the compiler.
1163 pub(crate) const MAX_CONTEXT_ARGS: usize = 2;
1164 
1165 /// Out-of-band special purpose arguments used for function call emission.
1166 ///
1167 /// We cannot rely on the value stack for these values given that inserting
1168 /// register or memory values at arbitrary locations of the value stack has the
1169 /// potential to break the stack ordering principle, which states that older
1170 /// values must always precede newer values, effectively simulating the order of
1171 /// values in the machine stack.
1172 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases
1173 /// it might be possible to construct it early on, but given that it might
1174 /// contain allocatable registers, it's preferred to construct it in
1175 /// [FnCall::emit].
1176 #[derive(Clone, Debug)]
1177 pub(crate) enum ContextArgs {
1178     /// No context arguments required. This is used for libcalls that don't
1179     /// require any special context arguments. For example builtin functions
1180     /// that perform float calculations.
1181     None,
1182     /// A single context argument is required; the current pinned [VMcontext]
1183     /// register must be passed as the first argument of the function call.
1184     VMContext([VMContextLoc; 1]),
1185     /// The callee and caller context arguments are required. In this case, the
1186     /// callee context argument is usually stored into an allocatable register
1187     /// and the caller is always the current pinned [VMContext] pointer.
1188     CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]),
1189 }
1190 
1191 impl ContextArgs {
1192     /// Construct an empty [ContextArgs].
1193     pub fn none() -> Self {
1194         Self::None
1195     }
1196 
1197     /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext]
1198     /// register as both the caller and callee context arguments.
1199     pub fn pinned_callee_and_caller_vmctx() -> Self {
1200         Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned])
1201     }
1202 
1203     /// Construct a [ContextArgs] that declares the usage of the pinned
1204     /// [VMContext] register as the only context argument.
1205     pub fn pinned_vmctx() -> Self {
1206         Self::VMContext([VMContextLoc::Pinned])
1207     }
1208 
1209     /// Construct a [ContextArgs] that declares a dynamic callee context and the
1210     /// pinned [VMContext] register as the context arguments.
1211     pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self {
1212         Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned])
1213     }
1214 
1215     /// Get the length of the [ContextArgs].
1216     pub fn len(&self) -> usize {
1217         self.as_slice().len()
1218     }
1219 
1220     /// Get a slice of the context arguments.
1221     pub fn as_slice(&self) -> &[VMContextLoc] {
1222         match self {
1223             Self::None => &[],
1224             Self::VMContext(a) => a.as_slice(),
1225             Self::CalleeAndCallerVMContext(a) => a.as_slice(),
1226         }
1227     }
1228 }
1229 
1230 #[derive(Copy, Clone, Debug)]
1231 pub(crate) enum CalleeKind {
1232     /// A function call to a raw address.
1233     Indirect(Reg),
1234     /// A function call to a local function.
1235     Direct(UserExternalNameRef),
1236     /// Call to a well known LibCall.
1237     LibCall(LibCall),
1238 }
1239 
1240 impl CalleeKind {
1241     /// Creates a callee kind from a register.
1242     pub fn indirect(reg: Reg) -> Self {
1243         Self::Indirect(reg)
1244     }
1245 
1246     /// Creates a direct callee kind from a function name.
1247     pub fn direct(name: UserExternalNameRef) -> Self {
1248         Self::Direct(name)
1249     }
1250 
1251     /// Creates a known callee kind from a libcall.
1252     pub fn libcall(call: LibCall) -> Self {
1253         Self::LibCall(call)
1254     }
1255 }
1256 
1257 impl RegImm {
1258     /// Register constructor.
1259     pub fn reg(r: Reg) -> Self {
1260         RegImm::Reg(r)
1261     }
1262 
1263     /// I64 immediate constructor.
1264     pub fn i64(val: i64) -> Self {
1265         RegImm::Imm(Imm::i64(val))
1266     }
1267 
1268     /// I32 immediate constructor.
1269     pub fn i32(val: i32) -> Self {
1270         RegImm::Imm(Imm::i32(val))
1271     }
1272 
1273     /// F32 immediate, stored using its bits representation.
1274     pub fn f32(bits: u32) -> Self {
1275         RegImm::Imm(Imm::f32(bits))
1276     }
1277 
1278     /// F64 immediate, stored using its bits representation.
1279     pub fn f64(bits: u64) -> Self {
1280         RegImm::Imm(Imm::f64(bits))
1281     }
1282 
1283     /// V128 immediate.
1284     pub fn v128(bits: i128) -> Self {
1285         RegImm::Imm(Imm::v128(bits))
1286     }
1287 }
1288 
1289 impl From<Reg> for RegImm {
1290     fn from(r: Reg) -> Self {
1291         Self::Reg(r)
1292     }
1293 }
1294 
1295 #[derive(Debug)]
1296 pub enum RoundingMode {
1297     Nearest,
1298     Up,
1299     Down,
1300     Zero,
1301 }
1302 
1303 /// Memory flags for trusted loads/stores.
1304 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted();
1305 
1306 /// Flags used for WebAssembly loads / stores.
1307 /// Untrusted by default so we don't set `no_trap`.
1308 /// We also ensure that the endianness is the right one for WebAssembly.
1309 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little);
1310 
1311 /// Generic MacroAssembler interface used by the code generation.
1312 ///
1313 /// The MacroAssembler trait aims to expose an interface, high-level enough,
1314 /// so that each ISA can provide its own lowering to machine code. For example,
1315 /// for WebAssembly operators that don't have a direct mapping to a machine
1316 /// a instruction, the interface defines a signature matching the WebAssembly
1317 /// operator, allowing each implementation to lower such operator entirely.
1318 /// This approach attributes more responsibility to the MacroAssembler, but frees
1319 /// the caller from concerning about assembling the right sequence of
1320 /// instructions at the operator callsite.
1321 ///
1322 /// The interface defaults to a three-argument form for binary operations;
1323 /// this allows a natural mapping to instructions for RISC architectures,
1324 /// that use three-argument form.
1325 /// This approach allows for a more general interface that can be restricted
1326 /// where needed, in the case of architectures that use a two-argument form.
1327 
1328 pub(crate) trait MacroAssembler {
1329     /// The addressing mode.
1330     type Address: Copy + Debug;
1331 
1332     /// The pointer representation of the target ISA,
1333     /// used to access information from [`VMOffsets`].
1334     type Ptr: PtrSize;
1335 
1336     /// The ABI details of the target.
1337     type ABI: abi::ABI;
1338 
1339     /// Emit the function prologue.
1340     fn prologue(&mut self, vmctx: Reg) -> Result<()> {
1341         self.frame_setup()?;
1342         self.check_stack(vmctx)
1343     }
1344 
1345     /// Generate the frame setup sequence.
1346     fn frame_setup(&mut self) -> Result<()>;
1347 
1348     /// Generate the frame restore sequence.
1349     fn frame_restore(&mut self) -> Result<()>;
1350 
1351     /// Emit a stack check.
1352     fn check_stack(&mut self, vmctx: Reg) -> Result<()>;
1353 
1354     /// Emit the function epilogue.
1355     fn epilogue(&mut self) -> Result<()> {
1356         self.frame_restore()
1357     }
1358 
1359     /// Reserve stack space.
1360     fn reserve_stack(&mut self, bytes: u32) -> Result<()>;
1361 
1362     /// Free stack space.
1363     fn free_stack(&mut self, bytes: u32) -> Result<()>;
1364 
1365     /// Reset the stack pointer to the given offset;
1366     ///
1367     /// Used to reset the stack pointer to a given offset
1368     /// when dealing with unreachable code.
1369     fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>;
1370 
1371     /// Get the address of a local slot.
1372     fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>;
1373 
1374     /// Constructs an address with an offset that is relative to the
1375     /// current position of the stack pointer (e.g. [sp + (sp_offset -
1376     /// offset)].
1377     fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>;
1378 
1379     /// Constructs an address with an offset that is absolute to the
1380     /// current position of the stack pointer (e.g. [sp + offset].
1381     fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>;
1382 
1383     /// Alias for [`Self::address_at_reg`] using the VMContext register as
1384     /// a base. The VMContext register is derived from the ABI type that is
1385     /// associated to the MacroAssembler.
1386     fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>;
1387 
1388     /// Construct an address that is absolute to the current position
1389     /// of the given register.
1390     fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>;
1391 
1392     /// Emit a function call to either a local or external function.
1393     fn call(
1394         &mut self,
1395         stack_args_size: u32,
1396         f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>,
1397     ) -> Result<u32>;
1398 
1399     /// Get stack pointer offset.
1400     fn sp_offset(&self) -> Result<SPOffset>;
1401 
1402     /// Perform a stack store.
1403     fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>;
1404 
1405     /// Alias for `MacroAssembler::store` with the operand size corresponding
1406     /// to the pointer size of the target.
1407     fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>;
1408 
1409     /// Perform a WebAssembly store.
1410     /// A WebAssembly store introduces several additional invariants compared to
1411     /// [Self::store], more precisely, it can implicitly trap, in certain
1412     /// circumstances, even if explicit bounds checks are elided, in that sense,
1413     /// we consider this type of load as untrusted. It can also differ with
1414     /// regards to the endianness depending on the target ISA. For this reason,
1415     /// [Self::wasm_store], should be explicitly used when emitting WebAssembly
1416     /// stores.
1417     fn wasm_store(&mut self, src: Reg, dst: Self::Address, store_kind: StoreKind) -> Result<()>;
1418 
1419     /// Perform a zero-extended stack load.
1420     fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>;
1421 
1422     /// Perform a WebAssembly load.
1423     /// A WebAssembly load introduces several additional invariants compared to
1424     /// [Self::load], more precisely, it can implicitly trap, in certain
1425     /// circumstances, even if explicit bounds checks are elided, in that sense,
1426     /// we consider this type of load as untrusted. It can also differ with
1427     /// regards to the endianness depending on the target ISA. For this reason,
1428     /// [Self::wasm_load], should be explicitly used when emitting WebAssembly
1429     /// loads.
1430     fn wasm_load(&mut self, src: Self::Address, dst: WritableReg, kind: LoadKind) -> Result<()>;
1431 
1432     /// Alias for `MacroAssembler::load` with the operand size corresponding
1433     /// to the pointer size of the target.
1434     fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>;
1435 
1436     /// Computes the effective address and stores the result in the destination
1437     /// register.
1438     fn compute_addr(
1439         &mut self,
1440         _src: Self::Address,
1441         _dst: WritableReg,
1442         _size: OperandSize,
1443     ) -> Result<()>;
1444 
1445     /// Pop a value from the machine stack into the given register.
1446     fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1447 
1448     /// Perform a move.
1449     fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>;
1450 
1451     /// Perform a conditional move.
1452     fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize)
1453         -> Result<()>;
1454 
1455     /// Performs a memory move of bytes from src to dest.
1456     /// Bytes are moved in blocks of 8 bytes, where possible.
1457     fn memmove(
1458         &mut self,
1459         src: SPOffset,
1460         dst: SPOffset,
1461         bytes: u32,
1462         direction: MemMoveDirection,
1463     ) -> Result<()> {
1464         match direction {
1465             MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()),
1466             MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()),
1467         }
1468         // At least 4 byte aligned.
1469         debug_assert!(bytes % 4 == 0);
1470         let mut remaining = bytes;
1471         let word_bytes = <Self::ABI as abi::ABI>::word_bytes();
1472         let scratch = scratch!(Self);
1473 
1474         let word_bytes = word_bytes as u32;
1475 
1476         let mut dst_offs;
1477         let mut src_offs;
1478         match direction {
1479             MemMoveDirection::LowToHigh => {
1480                 dst_offs = dst.as_u32() - bytes;
1481                 src_offs = src.as_u32() - bytes;
1482                 while remaining >= word_bytes {
1483                     remaining -= word_bytes;
1484                     dst_offs += word_bytes;
1485                     src_offs += word_bytes;
1486 
1487                     self.load_ptr(
1488                         self.address_from_sp(SPOffset::from_u32(src_offs))?,
1489                         writable!(scratch),
1490                     )?;
1491                     self.store_ptr(
1492                         scratch.into(),
1493                         self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1494                     )?;
1495                 }
1496             }
1497             MemMoveDirection::HighToLow => {
1498                 // Go from the end to the beginning to handle overlapping addresses.
1499                 src_offs = src.as_u32();
1500                 dst_offs = dst.as_u32();
1501                 while remaining >= word_bytes {
1502                     self.load_ptr(
1503                         self.address_from_sp(SPOffset::from_u32(src_offs))?,
1504                         writable!(scratch),
1505                     )?;
1506                     self.store_ptr(
1507                         scratch.into(),
1508                         self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1509                     )?;
1510 
1511                     remaining -= word_bytes;
1512                     src_offs -= word_bytes;
1513                     dst_offs -= word_bytes;
1514                 }
1515             }
1516         }
1517 
1518         if remaining > 0 {
1519             let half_word = word_bytes / 2;
1520             let ptr_size = OperandSize::from_bytes(half_word as u8);
1521             debug_assert!(remaining == half_word);
1522             // Need to move the offsets ahead in the `LowToHigh` case to
1523             // compensate for the initial subtraction of `bytes`.
1524             if direction == MemMoveDirection::LowToHigh {
1525                 dst_offs += half_word;
1526                 src_offs += half_word;
1527             }
1528 
1529             self.load(
1530                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
1531                 writable!(scratch),
1532                 ptr_size,
1533             )?;
1534             self.store(
1535                 scratch.into(),
1536                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1537                 ptr_size,
1538             )?;
1539         }
1540         Ok(())
1541     }
1542 
1543     /// Perform add operation.
1544     fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1545 
1546     /// Perform a checked unsigned integer addition, emitting the provided trap
1547     /// if the addition overflows.
1548     fn checked_uadd(
1549         &mut self,
1550         dst: WritableReg,
1551         lhs: Reg,
1552         rhs: RegImm,
1553         size: OperandSize,
1554         trap: TrapCode,
1555     ) -> Result<()>;
1556 
1557     /// Perform subtraction operation.
1558     fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1559 
1560     /// Perform multiplication operation.
1561     fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1562 
1563     /// Perform a floating point add operation.
1564     fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1565 
1566     /// Perform a floating point subtraction operation.
1567     fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1568 
1569     /// Perform a floating point multiply operation.
1570     fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1571 
1572     /// Perform a floating point divide operation.
1573     fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1574 
1575     /// Perform a floating point minimum operation. In x86, this will emit
1576     /// multiple instructions.
1577     fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1578 
1579     /// Perform a floating point maximum operation. In x86, this will emit
1580     /// multiple instructions.
1581     fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1582 
1583     /// Perform a floating point copysign operation. In x86, this will emit
1584     /// multiple instructions.
1585     fn float_copysign(
1586         &mut self,
1587         dst: WritableReg,
1588         lhs: Reg,
1589         rhs: Reg,
1590         size: OperandSize,
1591     ) -> Result<()>;
1592 
1593     /// Perform a floating point abs operation.
1594     fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1595 
1596     /// Perform a floating point negation operation.
1597     fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1598 
1599     /// Perform a floating point floor operation.
1600     fn float_round<
1601         F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>,
1602     >(
1603         &mut self,
1604         mode: RoundingMode,
1605         env: &mut FuncEnv<Self::Ptr>,
1606         context: &mut CodeGenContext<Emission>,
1607         size: OperandSize,
1608         fallback: F,
1609     ) -> Result<()>;
1610 
1611     /// Perform a floating point square root operation.
1612     fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1613 
1614     /// Perform logical and operation.
1615     fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1616 
1617     /// Perform logical or operation.
1618     fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1619 
1620     /// Perform logical exclusive or operation.
1621     fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1622 
1623     /// Perform a shift operation between a register and an immediate.
1624     fn shift_ir(
1625         &mut self,
1626         dst: WritableReg,
1627         imm: u64,
1628         lhs: Reg,
1629         kind: ShiftKind,
1630         size: OperandSize,
1631     ) -> Result<()>;
1632 
1633     /// Perform a shift operation between two registers.
1634     /// This case is special in that some architectures have specific expectations
1635     /// regarding the location of the instruction arguments. To free the
1636     /// caller from having to deal with the architecture specific constraints
1637     /// we give this function access to the code generation context, allowing
1638     /// each implementation to decide the lowering path.
1639     fn shift(
1640         &mut self,
1641         context: &mut CodeGenContext<Emission>,
1642         kind: ShiftKind,
1643         size: OperandSize,
1644     ) -> Result<()>;
1645 
1646     /// Perform division operation.
1647     /// Division is special in that some architectures have specific
1648     /// expectations regarding the location of the instruction
1649     /// arguments and regarding the location of the quotient /
1650     /// remainder. To free the caller from having to deal with the
1651     /// architecture specific constraints we give this function access
1652     /// to the code generation context, allowing each implementation
1653     /// to decide the lowering path.  For cases in which division is a
1654     /// unconstrained binary operation, the caller can decide to use
1655     /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop`
1656     /// functions.
1657     fn div(
1658         &mut self,
1659         context: &mut CodeGenContext<Emission>,
1660         kind: DivKind,
1661         size: OperandSize,
1662     ) -> Result<()>;
1663 
1664     /// Calculate remainder.
1665     fn rem(
1666         &mut self,
1667         context: &mut CodeGenContext<Emission>,
1668         kind: RemKind,
1669         size: OperandSize,
1670     ) -> Result<()>;
1671 
1672     /// Compares `src1` against `src2` for the side effect of setting processor
1673     /// flags.
1674     ///
1675     /// Note that `src1` is the left-hand-side of the comparison and `src2` is
1676     /// the right-hand-side, so if testing `a < b` then `src1 == a` and
1677     /// `src2 == b`
1678     fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>;
1679 
1680     /// Compare src and dst and put the result in dst.
1681     /// This function will potentially emit a series of instructions.
1682     ///
1683     /// The initial value in `dst` is the left-hand-side of the comparison and
1684     /// the initial value in `src` is the right-hand-side of the comparison.
1685     /// That means for `a < b` then `dst == a` and `src == b`.
1686     fn cmp_with_set(
1687         &mut self,
1688         dst: WritableReg,
1689         src: RegImm,
1690         kind: IntCmpKind,
1691         size: OperandSize,
1692     ) -> Result<()>;
1693 
1694     /// Compare floats in src1 and src2 and put the result in dst.
1695     /// In x86, this will emit multiple instructions.
1696     fn float_cmp_with_set(
1697         &mut self,
1698         dst: WritableReg,
1699         src1: Reg,
1700         src2: Reg,
1701         kind: FloatCmpKind,
1702         size: OperandSize,
1703     ) -> Result<()>;
1704 
1705     /// Count the number of leading zeroes in src and put the result in dst.
1706     /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is
1707     /// false.
1708     fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1709 
1710     /// Count the number of trailing zeroes in src and put the result in dst.masm
1711     /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is
1712     /// false.
1713     fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1714 
1715     /// Push the register to the stack, returning the stack slot metadata.
1716     // NB
1717     // The stack alignment should not be assumed after any call to `push`,
1718     // unless explicitly aligned otherwise.  Typically, stack alignment is
1719     // maintained at call sites and during the execution of
1720     // epilogues.
1721     fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>;
1722 
1723     /// Finalize the assembly and return the result.
1724     fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>;
1725 
1726     /// Zero a particular register.
1727     fn zero(&mut self, reg: WritableReg) -> Result<()>;
1728 
1729     /// Count the number of 1 bits in src and put the result in dst. In x64,
1730     /// this will emit multiple instructions if the `has_popcnt` flag is false.
1731     fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>;
1732 
1733     /// Converts an i64 to an i32 by discarding the high 32 bits.
1734     fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1735 
1736     /// Extends an integer of a given size to a larger size.
1737     fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>;
1738 
1739     /// Emits one or more instructions to perform a signed truncation of a
1740     /// float into an integer.
1741     fn signed_truncate(
1742         &mut self,
1743         dst: WritableReg,
1744         src: Reg,
1745         src_size: OperandSize,
1746         dst_size: OperandSize,
1747         kind: TruncKind,
1748     ) -> Result<()>;
1749 
1750     /// Emits one or more instructions to perform an unsigned truncation of a
1751     /// float into an integer.
1752     fn unsigned_truncate(
1753         &mut self,
1754         context: &mut CodeGenContext<Emission>,
1755         src_size: OperandSize,
1756         dst_size: OperandSize,
1757         kind: TruncKind,
1758     ) -> Result<()>;
1759 
1760     /// Emits one or more instructions to perform a signed convert of an
1761     /// integer into a float.
1762     fn signed_convert(
1763         &mut self,
1764         dst: WritableReg,
1765         src: Reg,
1766         src_size: OperandSize,
1767         dst_size: OperandSize,
1768     ) -> Result<()>;
1769 
1770     /// Emits one or more instructions to perform an unsigned convert of an
1771     /// integer into a float.
1772     fn unsigned_convert(
1773         &mut self,
1774         dst: WritableReg,
1775         src: Reg,
1776         tmp_gpr: Reg,
1777         src_size: OperandSize,
1778         dst_size: OperandSize,
1779     ) -> Result<()>;
1780 
1781     /// Reinterpret a float as an integer.
1782     fn reinterpret_float_as_int(
1783         &mut self,
1784         dst: WritableReg,
1785         src: Reg,
1786         size: OperandSize,
1787     ) -> Result<()>;
1788 
1789     /// Reinterpret an integer as a float.
1790     fn reinterpret_int_as_float(
1791         &mut self,
1792         dst: WritableReg,
1793         src: Reg,
1794         size: OperandSize,
1795     ) -> Result<()>;
1796 
1797     /// Demote an f64 to an f32.
1798     fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1799 
1800     /// Promote an f32 to an f64.
1801     fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1802 
1803     /// Zero a given memory range.
1804     ///
1805     /// The default implementation divides the given memory range
1806     /// into word-sized slots. Then it unrolls a series of store
1807     /// instructions, effectively assigning zero to each slot.
1808     fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> {
1809         let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32;
1810         if mem.is_empty() {
1811             return Ok(());
1812         }
1813 
1814         let start = if mem.start % word_size == 0 {
1815             mem.start
1816         } else {
1817             // Ensure that the start of the range is at least 4-byte aligned.
1818             assert!(mem.start % 4 == 0);
1819             let start = align_to(mem.start, word_size);
1820             let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?;
1821             self.store(RegImm::i32(0), addr, OperandSize::S32)?;
1822             // Ensure that the new start of the range, is word-size aligned.
1823             assert!(start % word_size == 0);
1824             start
1825         };
1826 
1827         let end = align_to(mem.end, word_size);
1828         let slots = (end - start) / word_size;
1829 
1830         if slots == 1 {
1831             let slot = LocalSlot::i64(start + word_size);
1832             let addr: Self::Address = self.local_address(&slot)?;
1833             self.store(RegImm::i64(0), addr, OperandSize::S64)?;
1834         } else {
1835             // TODO
1836             // Add an upper bound to this generation;
1837             // given a considerably large amount of slots
1838             // this will be inefficient.
1839             let zero = scratch!(Self);
1840             self.zero(writable!(zero))?;
1841             let zero = RegImm::reg(zero);
1842 
1843             for step in (start..end).into_iter().step_by(word_size as usize) {
1844                 let slot = LocalSlot::i64(step + word_size);
1845                 let addr: Self::Address = self.local_address(&slot)?;
1846                 self.store(zero, addr, OperandSize::S64)?;
1847             }
1848         }
1849 
1850         Ok(())
1851     }
1852 
1853     /// Generate a label.
1854     fn get_label(&mut self) -> Result<MachLabel>;
1855 
1856     /// Bind the given label at the current code offset.
1857     fn bind(&mut self, label: MachLabel) -> Result<()>;
1858 
1859     /// Conditional branch.
1860     ///
1861     /// Performs a comparison between the two operands,
1862     /// and immediately after emits a jump to the given
1863     /// label destination if the condition is met.
1864     fn branch(
1865         &mut self,
1866         kind: IntCmpKind,
1867         lhs: Reg,
1868         rhs: RegImm,
1869         taken: MachLabel,
1870         size: OperandSize,
1871     ) -> Result<()>;
1872 
1873     /// Emits and unconditional jump to the given label.
1874     fn jmp(&mut self, target: MachLabel) -> Result<()>;
1875 
1876     /// Emits a jump table sequence. The default label is specified as
1877     /// the last element of the targets slice.
1878     fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>;
1879 
1880     /// Emit an unreachable code trap.
1881     fn unreachable(&mut self) -> Result<()>;
1882 
1883     /// Emit an unconditional trap.
1884     fn trap(&mut self, code: TrapCode) -> Result<()>;
1885 
1886     /// Traps if the condition code is met.
1887     fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>;
1888 
1889     /// Trap if the source register is zero.
1890     fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>;
1891 
1892     /// Ensures that the stack pointer is correctly positioned before an unconditional
1893     /// jump according to the requirements of the destination target.
1894     fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> {
1895         let bytes = self
1896             .sp_offset()?
1897             .as_u32()
1898             .checked_sub(target.as_u32())
1899             .unwrap_or(0);
1900 
1901         if bytes > 0 {
1902             self.free_stack(bytes)?;
1903         }
1904 
1905         Ok(())
1906     }
1907 
1908     /// Mark the start of a source location returning the machine code offset
1909     /// and the relative source code location.
1910     fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>;
1911 
1912     /// Mark the end of a source location.
1913     fn end_source_loc(&mut self) -> Result<()>;
1914 
1915     /// The current offset, in bytes from the beginning of the function.
1916     fn current_code_offset(&self) -> Result<CodeOffset>;
1917 
1918     /// Performs a 128-bit addition
1919     fn add128(
1920         &mut self,
1921         dst_lo: WritableReg,
1922         dst_hi: WritableReg,
1923         lhs_lo: Reg,
1924         lhs_hi: Reg,
1925         rhs_lo: Reg,
1926         rhs_hi: Reg,
1927     ) -> Result<()>;
1928 
1929     /// Performs a 128-bit subtraction
1930     fn sub128(
1931         &mut self,
1932         dst_lo: WritableReg,
1933         dst_hi: WritableReg,
1934         lhs_lo: Reg,
1935         lhs_hi: Reg,
1936         rhs_lo: Reg,
1937         rhs_hi: Reg,
1938     ) -> Result<()>;
1939 
1940     /// Performs a widening multiplication from two 64-bit operands into a
1941     /// 128-bit result.
1942     ///
1943     /// Note that some platforms require special handling of registers in this
1944     /// instruction (e.g. x64) so full access to `CodeGenContext` is provided.
1945     fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind)
1946         -> Result<()>;
1947 
1948     /// Takes the value in a src operand and replicates it across lanes of
1949     /// `size` in a destination result.
1950     fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>;
1951 
1952     /// Performs a shuffle between two 128-bit vectors into a 128-bit result
1953     /// using lanes as a mask to select which indexes to copy.
1954     fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>;
1955 
1956     /// Performs a swizzle between two 128-bit vectors into a 128-bit result.
1957     fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>;
1958 
1959     /// Performs the RMW `op` operation on the passed `addr`.
1960     ///
1961     /// The value *before* the operation was performed is written back to the `operand` register.
1962     fn atomic_rmw(
1963         &mut self,
1964         context: &mut CodeGenContext<Emission>,
1965         addr: Self::Address,
1966         size: OperandSize,
1967         op: RmwOp,
1968         flags: MemFlags,
1969         extend: Option<Extend<Zero>>,
1970     ) -> Result<()>;
1971 
1972     /// Extracts the scalar value from `src` in `lane` to `dst`.
1973     fn extract_lane(
1974         &mut self,
1975         src: Reg,
1976         dst: WritableReg,
1977         lane: u8,
1978         kind: ExtractLaneKind,
1979     ) -> Result<()>;
1980 
1981     /// Replaces the value in `lane` in `dst` with the value in `src`.
1982     fn replace_lane(
1983         &mut self,
1984         src: RegImm,
1985         dst: WritableReg,
1986         lane: u8,
1987         kind: ReplaceLaneKind,
1988     ) -> Result<()>;
1989 
1990     /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected`
1991     /// and `replacement` (at the top of the context's stack).
1992     ///
1993     /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that
1994     /// expect parameters in specific registers. The context stack contains the `replacement`,
1995     /// and `expected` values in that order. The implementer is expected to push the value at
1996     /// `addr` before the update to the context's stack before returning.
1997     fn atomic_cas(
1998         &mut self,
1999         context: &mut CodeGenContext<Emission>,
2000         addr: Self::Address,
2001         size: OperandSize,
2002         flags: MemFlags,
2003         extend: Option<Extend<Zero>>,
2004     ) -> Result<()>;
2005 
2006     /// Compares vector registers `lhs` and `rhs` for equality and puts the
2007     /// vector of results in `dst`.
2008     fn v128_eq(
2009         &mut self,
2010         dst: WritableReg,
2011         lhs: Reg,
2012         rhs: Reg,
2013         kind: VectorEqualityKind,
2014     ) -> Result<()>;
2015 
2016     /// Compares vector registers `lhs` and `rhs` for inequality and puts the
2017     /// vector of results in `dst`.
2018     fn v128_ne(
2019         &mut self,
2020         dst: WritableReg,
2021         lhs: Reg,
2022         rhs: Reg,
2023         kind: VectorEqualityKind,
2024     ) -> Result<()>;
2025 
2026     /// Performs a less than comparison with vector registers `lhs` and `rhs`
2027     /// and puts the vector of results in `dst`.
2028     fn v128_lt(
2029         &mut self,
2030         dst: WritableReg,
2031         lhs: Reg,
2032         rhs: Reg,
2033         kind: VectorCompareKind,
2034     ) -> Result<()>;
2035 
2036     /// Performs a less than or equal comparison with vector registers `lhs`
2037     /// and `rhs` and puts the vector of results in `dst`.
2038     fn v128_le(
2039         &mut self,
2040         dst: WritableReg,
2041         lhs: Reg,
2042         rhs: Reg,
2043         kind: VectorCompareKind,
2044     ) -> Result<()>;
2045 
2046     /// Performs a greater than comparison with vector registers `lhs` and
2047     /// `rhs` and puts the vector of results in `dst`.
2048     fn v128_gt(
2049         &mut self,
2050         dst: WritableReg,
2051         lhs: Reg,
2052         rhs: Reg,
2053         kind: VectorCompareKind,
2054     ) -> Result<()>;
2055 
2056     /// Performs a greater than or equal comparison with vector registers `lhs`
2057     /// and `rhs` and puts the vector of results in `dst`.
2058     fn v128_ge(
2059         &mut self,
2060         dst: WritableReg,
2061         lhs: Reg,
2062         rhs: Reg,
2063         kind: VectorCompareKind,
2064     ) -> Result<()>;
2065 
2066     /// Emit a memory fence.
2067     fn fence(&mut self) -> Result<()>;
2068 
2069     /// Perform a logical `not` operation on the 128bits vector value in `dst`.
2070     fn v128_not(&mut self, dst: WritableReg) -> Result<()>;
2071 
2072     /// Perform a logical `and` operation on `src1` and `src1`, both 128bits vector values, writing
2073     /// the result to `dst`.
2074     fn v128_and(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2075 
2076     /// Perform a logical `and_not` operation on `src1` and `src1`, both 128bits vector values, writing
2077     /// the result to `dst`.
2078     ///
2079     /// `and_not` is not commutative: dst = !src1 & src2.
2080     fn v128_and_not(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2081 
2082     /// Perform a logical `or` operation on `src1` and `src1`, both 128bits vector values, writing
2083     /// the result to `dst`.
2084     fn v128_or(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2085 
2086     /// Perform a logical `xor` operation on `src1` and `src1`, both 128bits vector values, writing
2087     /// the result to `dst`.
2088     fn v128_xor(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2089 
2090     /// Given two 128bits vectors `src1` and `src2`, and a 128bits bitmask `mask`, selects bits
2091     /// from `src1` when mask is 1, and from `src2` when mask is 0.
2092     ///
2093     /// This is equivalent to: `v128.or(v128.and(src1, mask), v128.and(src2, v128.not(mask)))`.
2094     fn v128_bitselect(&mut self, src1: Reg, src2: Reg, mask: Reg, dst: WritableReg) -> Result<()>;
2095 
2096     /// If any bit in `src` is 1, set `dst` to 1, or 0 otherwise.
2097     fn v128_any_true(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2098 
2099     /// Convert vector of integers to vector of floating points.
2100     fn v128_convert(&mut self, src: Reg, dst: WritableReg, kind: V128ConvertKind) -> Result<()>;
2101 
2102     /// Convert two input vectors into a smaller lane vector by narrowing each
2103     /// lane.
2104     fn v128_narrow(
2105         &mut self,
2106         src1: Reg,
2107         src2: Reg,
2108         dst: WritableReg,
2109         kind: V128NarrowKind,
2110     ) -> Result<()>;
2111 
2112     /// Converts a vector containing two 64-bit floating point lanes to two
2113     /// 32-bit floating point lanes and setting the two higher lanes to 0.
2114     fn v128_demote(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2115 
2116     /// Converts a vector containing four 32-bit floating point lanes to two
2117     /// 64-bit floating point lanes. Only the two lower lanes are converted.
2118     fn v128_promote(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2119 
2120     /// Converts low or high half of the smaller lane vector to a larger lane
2121     /// vector.
2122     fn v128_extend(&mut self, src: Reg, dst: WritableReg, kind: V128ExtendKind) -> Result<()>;
2123 
2124     /// Perform a vector add between `lsh` and `rhs`, placing the result in
2125     /// `dst`.
2126     fn v128_add(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128AddKind) -> Result<()>;
2127 
2128     /// Perform a vector sub between `lhs` and `rhs`, placing the result in `dst`.
2129     fn v128_sub(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128SubKind) -> Result<()>;
2130 
2131     /// Perform a vector lane-wise mul between `lhs` and `rhs`, placing the result in `dst`.
2132     fn v128_mul(&mut self, context: &mut CodeGenContext<Emission>, kind: V128MulKind)
2133         -> Result<()>;
2134 
2135     /// Perform an absolute operation on a vector.
2136     fn v128_abs(&mut self, src: Reg, dst: WritableReg, kind: V128AbsKind) -> Result<()>;
2137 
2138     /// Vectorized negate of the content of `op`.
2139     fn v128_neg(&mut self, op: WritableReg, kind: V128NegKind) -> Result<()>;
2140 
2141     /// Perform the shift operation specified by `kind`, by the shift amount specified by the 32-bit
2142     /// integer at the top of the stack, on the 128-bit vector specified by the second value
2143     /// from the top of the stack, interpreted as packed integers of size `lane_width`.
2144     ///
2145     /// The shift amount is taken modulo `lane_width`.
2146     fn v128_shift(
2147         &mut self,
2148         context: &mut CodeGenContext<Emission>,
2149         lane_width: OperandSize,
2150         kind: ShiftKind,
2151     ) -> Result<()>;
2152 
2153     /// Perform a saturating integer q-format rounding multiplication.
2154     fn v128_q15mulr_sat_s(
2155         &mut self,
2156         lhs: Reg,
2157         rhs: Reg,
2158         dst: WritableReg,
2159         size: OperandSize,
2160     ) -> Result<()>;
2161 
2162     /// Sets `dst` to 1 if all lanes in `src` are non-zero, sets `dst` to 0
2163     /// otherwise.
2164     fn v128_all_true(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2165 
2166     /// Extracts the high bit of each lane in `src` and produces a scalar mask
2167     /// with all bits concatenated in `dst`.
2168     fn v128_bitmask(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2169 
2170     /// Lanewise truncation operation.
2171     ///
2172     /// If using an integer kind of truncation, then this performs a lane-wise
2173     /// saturating conversion from float to integer using the IEEE
2174     /// `convertToIntegerTowardZero` function. If any input lane is NaN, the
2175     /// resulting lane is 0. If the rounded integer value of a lane is outside
2176     /// the range of the destination type, the result is saturated to the
2177     /// nearest representable integer value.
2178     fn v128_trunc(
2179         &mut self,
2180         context: &mut CodeGenContext<Emission>,
2181         kind: V128TruncKind,
2182     ) -> Result<()>;
2183 
2184     /// Perform a lane-wise `min` operation between `src1` and `src2`.
2185     fn v128_min(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MinKind)
2186         -> Result<()>;
2187 
2188     /// Perform a lane-wise `max` operation between `src1` and `src2`.
2189     fn v128_max(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MaxKind)
2190         -> Result<()>;
2191 
2192     /// Perform the lane-wise integer extended multiplication producing twice wider result than the
2193     /// inputs. This is equivalent to an extend followed by a multiply.
2194     ///
2195     /// The extension to be performed is inferred from the `lane_width` and the `kind` of extmul,
2196     /// e.g, if `lane_width` is `S16`, and `kind` is `LowSigned`, then we sign-extend the lower
2197     /// 8bits of the 16bits lanes.
2198     fn v128_extmul(
2199         &mut self,
2200         context: &mut CodeGenContext<Emission>,
2201         kind: V128ExtMulKind,
2202     ) -> Result<()>;
2203 
2204     /// Perform the lane-wise integer extended pairwise addition producing extended results (twice
2205     /// wider results than the inputs).
2206     fn v128_extadd_pairwise(
2207         &mut self,
2208         src: Reg,
2209         dst: WritableReg,
2210         kind: V128ExtAddKind,
2211     ) -> Result<()>;
2212 
2213     /// Lane-wise multiply signed 16-bit integers in `lhs` and `rhs` and add
2214     /// adjacent pairs of the 32-bit results.
2215     fn v128_dot(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg) -> Result<()>;
2216 
2217     /// Count the number of bits set in each lane.
2218     fn v128_popcnt(&mut self, context: &mut CodeGenContext<Emission>) -> Result<()>;
2219 
2220     /// Lane-wise rounding average of vectors of integers in `lhs` and `rhs`
2221     /// and put the results in `dst`.
2222     fn v128_avgr(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2223 
2224     /// Lane-wise IEEE division on vectors of floats.
2225     fn v128_div(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2226 
2227     /// Lane-wise IEEE square root of vector of floats.
2228     fn v128_sqrt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2229 
2230     /// Lane-wise ceiling of vector of floats.
2231     fn v128_ceil(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2232 
2233     /// Lane-wise flooring of vector of floats.
2234     fn v128_floor(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2235 
2236     /// Lane-wise rounding to nearest integer for vector of floats.
2237     fn v128_nearest(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2238 
2239     /// Lane-wise minimum value defined as `rhs < lhs ? rhs : lhs`.
2240     fn v128_pmin(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2241 
2242     /// Lane-wise maximum value defined as `lhs < rhs ? rhs : lhs`.
2243     fn v128_pmax(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2244 }
2245