xref: /wasmtime-44.0.1/winch/codegen/src/masm.rs (revision 92cfda1b)
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, 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     /// A single context argument is required; the current pinned [VMcontext]
1179     /// register must be passed as the first argument of the function call.
1180     VMContext([VMContextLoc; 1]),
1181     /// The callee and caller context arguments are required. In this case, the
1182     /// callee context argument is usually stored into an allocatable register
1183     /// and the caller is always the current pinned [VMContext] pointer.
1184     CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]),
1185 }
1186 
1187 impl ContextArgs {
1188     /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext]
1189     /// register as both the caller and callee context arguments.
1190     pub fn pinned_callee_and_caller_vmctx() -> Self {
1191         Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned])
1192     }
1193 
1194     /// Construct a [ContextArgs] that declares the usage of the pinned
1195     /// [VMContext] register as the only context argument.
1196     pub fn pinned_vmctx() -> Self {
1197         Self::VMContext([VMContextLoc::Pinned])
1198     }
1199 
1200     /// Construct a [ContextArgs] that declares a dynamic callee context and the
1201     /// pinned [VMContext] register as the context arguments.
1202     pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self {
1203         Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned])
1204     }
1205 
1206     /// Get the length of the [ContextArgs].
1207     pub fn len(&self) -> usize {
1208         self.as_slice().len()
1209     }
1210 
1211     /// Get a slice of the context arguments.
1212     pub fn as_slice(&self) -> &[VMContextLoc] {
1213         match self {
1214             Self::VMContext(a) => a.as_slice(),
1215             Self::CalleeAndCallerVMContext(a) => a.as_slice(),
1216         }
1217     }
1218 }
1219 
1220 #[derive(Copy, Clone, Debug)]
1221 pub(crate) enum CalleeKind {
1222     /// A function call to a raw address.
1223     Indirect(Reg),
1224     /// A function call to a local function.
1225     Direct(UserExternalNameRef),
1226 }
1227 
1228 impl CalleeKind {
1229     /// Creates a callee kind from a register.
1230     pub fn indirect(reg: Reg) -> Self {
1231         Self::Indirect(reg)
1232     }
1233 
1234     /// Creates a direct callee kind from a function name.
1235     pub fn direct(name: UserExternalNameRef) -> Self {
1236         Self::Direct(name)
1237     }
1238 }
1239 
1240 impl RegImm {
1241     /// Register constructor.
1242     pub fn reg(r: Reg) -> Self {
1243         RegImm::Reg(r)
1244     }
1245 
1246     /// I64 immediate constructor.
1247     pub fn i64(val: i64) -> Self {
1248         RegImm::Imm(Imm::i64(val))
1249     }
1250 
1251     /// I32 immediate constructor.
1252     pub fn i32(val: i32) -> Self {
1253         RegImm::Imm(Imm::i32(val))
1254     }
1255 
1256     /// F32 immediate, stored using its bits representation.
1257     pub fn f32(bits: u32) -> Self {
1258         RegImm::Imm(Imm::f32(bits))
1259     }
1260 
1261     /// F64 immediate, stored using its bits representation.
1262     pub fn f64(bits: u64) -> Self {
1263         RegImm::Imm(Imm::f64(bits))
1264     }
1265 
1266     /// V128 immediate.
1267     pub fn v128(bits: i128) -> Self {
1268         RegImm::Imm(Imm::v128(bits))
1269     }
1270 }
1271 
1272 impl From<Reg> for RegImm {
1273     fn from(r: Reg) -> Self {
1274         Self::Reg(r)
1275     }
1276 }
1277 
1278 #[derive(Debug)]
1279 pub enum RoundingMode {
1280     Nearest,
1281     Up,
1282     Down,
1283     Zero,
1284 }
1285 
1286 /// Memory flags for trusted loads/stores.
1287 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted();
1288 
1289 /// Flags used for WebAssembly loads / stores.
1290 /// Untrusted by default so we don't set `no_trap`.
1291 /// We also ensure that the endianness is the right one for WebAssembly.
1292 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little);
1293 
1294 /// Generic MacroAssembler interface used by the code generation.
1295 ///
1296 /// The MacroAssembler trait aims to expose an interface, high-level enough,
1297 /// so that each ISA can provide its own lowering to machine code. For example,
1298 /// for WebAssembly operators that don't have a direct mapping to a machine
1299 /// a instruction, the interface defines a signature matching the WebAssembly
1300 /// operator, allowing each implementation to lower such operator entirely.
1301 /// This approach attributes more responsibility to the MacroAssembler, but frees
1302 /// the caller from concerning about assembling the right sequence of
1303 /// instructions at the operator callsite.
1304 ///
1305 /// The interface defaults to a three-argument form for binary operations;
1306 /// this allows a natural mapping to instructions for RISC architectures,
1307 /// that use three-argument form.
1308 /// This approach allows for a more general interface that can be restricted
1309 /// where needed, in the case of architectures that use a two-argument form.
1310 
1311 pub(crate) trait MacroAssembler {
1312     /// The addressing mode.
1313     type Address: Copy + Debug;
1314 
1315     /// The pointer representation of the target ISA,
1316     /// used to access information from [`VMOffsets`].
1317     type Ptr: PtrSize;
1318 
1319     /// The ABI details of the target.
1320     type ABI: abi::ABI;
1321 
1322     /// Emit the function prologue.
1323     fn prologue(&mut self, vmctx: Reg) -> Result<()> {
1324         self.frame_setup()?;
1325         self.check_stack(vmctx)
1326     }
1327 
1328     /// Generate the frame setup sequence.
1329     fn frame_setup(&mut self) -> Result<()>;
1330 
1331     /// Generate the frame restore sequence.
1332     fn frame_restore(&mut self) -> Result<()>;
1333 
1334     /// Emit a stack check.
1335     fn check_stack(&mut self, vmctx: Reg) -> Result<()>;
1336 
1337     /// Emit the function epilogue.
1338     fn epilogue(&mut self) -> Result<()> {
1339         self.frame_restore()
1340     }
1341 
1342     /// Reserve stack space.
1343     fn reserve_stack(&mut self, bytes: u32) -> Result<()>;
1344 
1345     /// Free stack space.
1346     fn free_stack(&mut self, bytes: u32) -> Result<()>;
1347 
1348     /// Reset the stack pointer to the given offset;
1349     ///
1350     /// Used to reset the stack pointer to a given offset
1351     /// when dealing with unreachable code.
1352     fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>;
1353 
1354     /// Get the address of a local slot.
1355     fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>;
1356 
1357     /// Constructs an address with an offset that is relative to the
1358     /// current position of the stack pointer (e.g. [sp + (sp_offset -
1359     /// offset)].
1360     fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>;
1361 
1362     /// Constructs an address with an offset that is absolute to the
1363     /// current position of the stack pointer (e.g. [sp + offset].
1364     fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>;
1365 
1366     /// Alias for [`Self::address_at_reg`] using the VMContext register as
1367     /// a base. The VMContext register is derived from the ABI type that is
1368     /// associated to the MacroAssembler.
1369     fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>;
1370 
1371     /// Construct an address that is absolute to the current position
1372     /// of the given register.
1373     fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>;
1374 
1375     /// Emit a function call to either a local or external function.
1376     fn call(
1377         &mut self,
1378         stack_args_size: u32,
1379         f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>,
1380     ) -> Result<u32>;
1381 
1382     /// Get stack pointer offset.
1383     fn sp_offset(&self) -> Result<SPOffset>;
1384 
1385     /// Perform a stack store.
1386     fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>;
1387 
1388     /// Alias for `MacroAssembler::store` with the operand size corresponding
1389     /// to the pointer size of the target.
1390     fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>;
1391 
1392     /// Perform a WebAssembly store.
1393     /// A WebAssembly store introduces several additional invariants compared to
1394     /// [Self::store], more precisely, it can implicitly trap, in certain
1395     /// circumstances, even if explicit bounds checks are elided, in that sense,
1396     /// we consider this type of load as untrusted. It can also differ with
1397     /// regards to the endianness depending on the target ISA. For this reason,
1398     /// [Self::wasm_store], should be explicitly used when emitting WebAssembly
1399     /// stores.
1400     fn wasm_store(&mut self, src: Reg, dst: Self::Address, store_kind: StoreKind) -> Result<()>;
1401 
1402     /// Perform a zero-extended stack load.
1403     fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>;
1404 
1405     /// Perform a WebAssembly load.
1406     /// A WebAssembly load introduces several additional invariants compared to
1407     /// [Self::load], more precisely, it can implicitly trap, in certain
1408     /// circumstances, even if explicit bounds checks are elided, in that sense,
1409     /// we consider this type of load as untrusted. It can also differ with
1410     /// regards to the endianness depending on the target ISA. For this reason,
1411     /// [Self::wasm_load], should be explicitly used when emitting WebAssembly
1412     /// loads.
1413     fn wasm_load(&mut self, src: Self::Address, dst: WritableReg, kind: LoadKind) -> Result<()>;
1414 
1415     /// Alias for `MacroAssembler::load` with the operand size corresponding
1416     /// to the pointer size of the target.
1417     fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>;
1418 
1419     /// Computes the effective address and stores the result in the destination
1420     /// register.
1421     fn compute_addr(
1422         &mut self,
1423         _src: Self::Address,
1424         _dst: WritableReg,
1425         _size: OperandSize,
1426     ) -> Result<()>;
1427 
1428     /// Pop a value from the machine stack into the given register.
1429     fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1430 
1431     /// Perform a move.
1432     fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>;
1433 
1434     /// Perform a conditional move.
1435     fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize)
1436         -> Result<()>;
1437 
1438     /// Performs a memory move of bytes from src to dest.
1439     /// Bytes are moved in blocks of 8 bytes, where possible.
1440     fn memmove(
1441         &mut self,
1442         src: SPOffset,
1443         dst: SPOffset,
1444         bytes: u32,
1445         direction: MemMoveDirection,
1446     ) -> Result<()> {
1447         match direction {
1448             MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()),
1449             MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()),
1450         }
1451         // At least 4 byte aligned.
1452         debug_assert!(bytes % 4 == 0);
1453         let mut remaining = bytes;
1454         let word_bytes = <Self::ABI as abi::ABI>::word_bytes();
1455         let scratch = scratch!(Self);
1456 
1457         let word_bytes = word_bytes as u32;
1458 
1459         let mut dst_offs;
1460         let mut src_offs;
1461         match direction {
1462             MemMoveDirection::LowToHigh => {
1463                 dst_offs = dst.as_u32() - bytes;
1464                 src_offs = src.as_u32() - bytes;
1465                 while remaining >= word_bytes {
1466                     remaining -= word_bytes;
1467                     dst_offs += word_bytes;
1468                     src_offs += word_bytes;
1469 
1470                     self.load_ptr(
1471                         self.address_from_sp(SPOffset::from_u32(src_offs))?,
1472                         writable!(scratch),
1473                     )?;
1474                     self.store_ptr(
1475                         scratch.into(),
1476                         self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1477                     )?;
1478                 }
1479             }
1480             MemMoveDirection::HighToLow => {
1481                 // Go from the end to the beginning to handle overlapping addresses.
1482                 src_offs = src.as_u32();
1483                 dst_offs = dst.as_u32();
1484                 while remaining >= word_bytes {
1485                     self.load_ptr(
1486                         self.address_from_sp(SPOffset::from_u32(src_offs))?,
1487                         writable!(scratch),
1488                     )?;
1489                     self.store_ptr(
1490                         scratch.into(),
1491                         self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1492                     )?;
1493 
1494                     remaining -= word_bytes;
1495                     src_offs -= word_bytes;
1496                     dst_offs -= word_bytes;
1497                 }
1498             }
1499         }
1500 
1501         if remaining > 0 {
1502             let half_word = word_bytes / 2;
1503             let ptr_size = OperandSize::from_bytes(half_word as u8);
1504             debug_assert!(remaining == half_word);
1505             // Need to move the offsets ahead in the `LowToHigh` case to
1506             // compensate for the initial subtraction of `bytes`.
1507             if direction == MemMoveDirection::LowToHigh {
1508                 dst_offs += half_word;
1509                 src_offs += half_word;
1510             }
1511 
1512             self.load(
1513                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
1514                 writable!(scratch),
1515                 ptr_size,
1516             )?;
1517             self.store(
1518                 scratch.into(),
1519                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1520                 ptr_size,
1521             )?;
1522         }
1523         Ok(())
1524     }
1525 
1526     /// Perform add operation.
1527     fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1528 
1529     /// Perform a checked unsigned integer addition, emitting the provided trap
1530     /// if the addition overflows.
1531     fn checked_uadd(
1532         &mut self,
1533         dst: WritableReg,
1534         lhs: Reg,
1535         rhs: RegImm,
1536         size: OperandSize,
1537         trap: TrapCode,
1538     ) -> Result<()>;
1539 
1540     /// Perform subtraction operation.
1541     fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1542 
1543     /// Perform multiplication operation.
1544     fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1545 
1546     /// Perform a floating point add operation.
1547     fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1548 
1549     /// Perform a floating point subtraction operation.
1550     fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1551 
1552     /// Perform a floating point multiply operation.
1553     fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1554 
1555     /// Perform a floating point divide operation.
1556     fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1557 
1558     /// Perform a floating point minimum operation. In x86, this will emit
1559     /// multiple instructions.
1560     fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1561 
1562     /// Perform a floating point maximum operation. In x86, this will emit
1563     /// multiple instructions.
1564     fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1565 
1566     /// Perform a floating point copysign operation. In x86, this will emit
1567     /// multiple instructions.
1568     fn float_copysign(
1569         &mut self,
1570         dst: WritableReg,
1571         lhs: Reg,
1572         rhs: Reg,
1573         size: OperandSize,
1574     ) -> Result<()>;
1575 
1576     /// Perform a floating point abs operation.
1577     fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1578 
1579     /// Perform a floating point negation operation.
1580     fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1581 
1582     /// Perform a floating point floor operation.
1583     fn float_round<
1584         F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>,
1585     >(
1586         &mut self,
1587         mode: RoundingMode,
1588         env: &mut FuncEnv<Self::Ptr>,
1589         context: &mut CodeGenContext<Emission>,
1590         size: OperandSize,
1591         fallback: F,
1592     ) -> Result<()>;
1593 
1594     /// Perform a floating point square root operation.
1595     fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1596 
1597     /// Perform logical and operation.
1598     fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1599 
1600     /// Perform logical or operation.
1601     fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1602 
1603     /// Perform logical exclusive or operation.
1604     fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1605 
1606     /// Perform a shift operation between a register and an immediate.
1607     fn shift_ir(
1608         &mut self,
1609         dst: WritableReg,
1610         imm: u64,
1611         lhs: Reg,
1612         kind: ShiftKind,
1613         size: OperandSize,
1614     ) -> Result<()>;
1615 
1616     /// Perform a shift operation between two registers.
1617     /// This case is special in that some architectures have specific expectations
1618     /// regarding the location of the instruction arguments. To free the
1619     /// caller from having to deal with the architecture specific constraints
1620     /// we give this function access to the code generation context, allowing
1621     /// each implementation to decide the lowering path.
1622     fn shift(
1623         &mut self,
1624         context: &mut CodeGenContext<Emission>,
1625         kind: ShiftKind,
1626         size: OperandSize,
1627     ) -> Result<()>;
1628 
1629     /// Perform division operation.
1630     /// Division is special in that some architectures have specific
1631     /// expectations regarding the location of the instruction
1632     /// arguments and regarding the location of the quotient /
1633     /// remainder. To free the caller from having to deal with the
1634     /// architecture specific constraints we give this function access
1635     /// to the code generation context, allowing each implementation
1636     /// to decide the lowering path.  For cases in which division is a
1637     /// unconstrained binary operation, the caller can decide to use
1638     /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop`
1639     /// functions.
1640     fn div(
1641         &mut self,
1642         context: &mut CodeGenContext<Emission>,
1643         kind: DivKind,
1644         size: OperandSize,
1645     ) -> Result<()>;
1646 
1647     /// Calculate remainder.
1648     fn rem(
1649         &mut self,
1650         context: &mut CodeGenContext<Emission>,
1651         kind: RemKind,
1652         size: OperandSize,
1653     ) -> Result<()>;
1654 
1655     /// Compares `src1` against `src2` for the side effect of setting processor
1656     /// flags.
1657     ///
1658     /// Note that `src1` is the left-hand-side of the comparison and `src2` is
1659     /// the right-hand-side, so if testing `a < b` then `src1 == a` and
1660     /// `src2 == b`
1661     fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>;
1662 
1663     /// Compare src and dst and put the result in dst.
1664     /// This function will potentially emit a series of instructions.
1665     ///
1666     /// The initial value in `dst` is the left-hand-side of the comparison and
1667     /// the initial value in `src` is the right-hand-side of the comparison.
1668     /// That means for `a < b` then `dst == a` and `src == b`.
1669     fn cmp_with_set(
1670         &mut self,
1671         dst: WritableReg,
1672         src: RegImm,
1673         kind: IntCmpKind,
1674         size: OperandSize,
1675     ) -> Result<()>;
1676 
1677     /// Compare floats in src1 and src2 and put the result in dst.
1678     /// In x86, this will emit multiple instructions.
1679     fn float_cmp_with_set(
1680         &mut self,
1681         dst: WritableReg,
1682         src1: Reg,
1683         src2: Reg,
1684         kind: FloatCmpKind,
1685         size: OperandSize,
1686     ) -> Result<()>;
1687 
1688     /// Count the number of leading zeroes in src and put the result in dst.
1689     /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is
1690     /// false.
1691     fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1692 
1693     /// Count the number of trailing zeroes in src and put the result in dst.masm
1694     /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is
1695     /// false.
1696     fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1697 
1698     /// Push the register to the stack, returning the stack slot metadata.
1699     // NB
1700     // The stack alignment should not be assumed after any call to `push`,
1701     // unless explicitly aligned otherwise.  Typically, stack alignment is
1702     // maintained at call sites and during the execution of
1703     // epilogues.
1704     fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>;
1705 
1706     /// Finalize the assembly and return the result.
1707     fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>;
1708 
1709     /// Zero a particular register.
1710     fn zero(&mut self, reg: WritableReg) -> Result<()>;
1711 
1712     /// Count the number of 1 bits in src and put the result in dst. In x64,
1713     /// this will emit multiple instructions if the `has_popcnt` flag is false.
1714     fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>;
1715 
1716     /// Converts an i64 to an i32 by discarding the high 32 bits.
1717     fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1718 
1719     /// Extends an integer of a given size to a larger size.
1720     fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>;
1721 
1722     /// Emits one or more instructions to perform a signed truncation of a
1723     /// float into an integer.
1724     fn signed_truncate(
1725         &mut self,
1726         dst: WritableReg,
1727         src: Reg,
1728         src_size: OperandSize,
1729         dst_size: OperandSize,
1730         kind: TruncKind,
1731     ) -> Result<()>;
1732 
1733     /// Emits one or more instructions to perform an unsigned truncation of a
1734     /// float into an integer.
1735     fn unsigned_truncate(
1736         &mut self,
1737         context: &mut CodeGenContext<Emission>,
1738         src_size: OperandSize,
1739         dst_size: OperandSize,
1740         kind: TruncKind,
1741     ) -> Result<()>;
1742 
1743     /// Emits one or more instructions to perform a signed convert of an
1744     /// integer into a float.
1745     fn signed_convert(
1746         &mut self,
1747         dst: WritableReg,
1748         src: Reg,
1749         src_size: OperandSize,
1750         dst_size: OperandSize,
1751     ) -> Result<()>;
1752 
1753     /// Emits one or more instructions to perform an unsigned convert of an
1754     /// integer into a float.
1755     fn unsigned_convert(
1756         &mut self,
1757         dst: WritableReg,
1758         src: Reg,
1759         tmp_gpr: Reg,
1760         src_size: OperandSize,
1761         dst_size: OperandSize,
1762     ) -> Result<()>;
1763 
1764     /// Reinterpret a float as an integer.
1765     fn reinterpret_float_as_int(
1766         &mut self,
1767         dst: WritableReg,
1768         src: Reg,
1769         size: OperandSize,
1770     ) -> Result<()>;
1771 
1772     /// Reinterpret an integer as a float.
1773     fn reinterpret_int_as_float(
1774         &mut self,
1775         dst: WritableReg,
1776         src: Reg,
1777         size: OperandSize,
1778     ) -> Result<()>;
1779 
1780     /// Demote an f64 to an f32.
1781     fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1782 
1783     /// Promote an f32 to an f64.
1784     fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1785 
1786     /// Zero a given memory range.
1787     ///
1788     /// The default implementation divides the given memory range
1789     /// into word-sized slots. Then it unrolls a series of store
1790     /// instructions, effectively assigning zero to each slot.
1791     fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> {
1792         let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32;
1793         if mem.is_empty() {
1794             return Ok(());
1795         }
1796 
1797         let start = if mem.start % word_size == 0 {
1798             mem.start
1799         } else {
1800             // Ensure that the start of the range is at least 4-byte aligned.
1801             assert!(mem.start % 4 == 0);
1802             let start = align_to(mem.start, word_size);
1803             let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?;
1804             self.store(RegImm::i32(0), addr, OperandSize::S32)?;
1805             // Ensure that the new start of the range, is word-size aligned.
1806             assert!(start % word_size == 0);
1807             start
1808         };
1809 
1810         let end = align_to(mem.end, word_size);
1811         let slots = (end - start) / word_size;
1812 
1813         if slots == 1 {
1814             let slot = LocalSlot::i64(start + word_size);
1815             let addr: Self::Address = self.local_address(&slot)?;
1816             self.store(RegImm::i64(0), addr, OperandSize::S64)?;
1817         } else {
1818             // TODO
1819             // Add an upper bound to this generation;
1820             // given a considerably large amount of slots
1821             // this will be inefficient.
1822             let zero = scratch!(Self);
1823             self.zero(writable!(zero))?;
1824             let zero = RegImm::reg(zero);
1825 
1826             for step in (start..end).into_iter().step_by(word_size as usize) {
1827                 let slot = LocalSlot::i64(step + word_size);
1828                 let addr: Self::Address = self.local_address(&slot)?;
1829                 self.store(zero, addr, OperandSize::S64)?;
1830             }
1831         }
1832 
1833         Ok(())
1834     }
1835 
1836     /// Generate a label.
1837     fn get_label(&mut self) -> Result<MachLabel>;
1838 
1839     /// Bind the given label at the current code offset.
1840     fn bind(&mut self, label: MachLabel) -> Result<()>;
1841 
1842     /// Conditional branch.
1843     ///
1844     /// Performs a comparison between the two operands,
1845     /// and immediately after emits a jump to the given
1846     /// label destination if the condition is met.
1847     fn branch(
1848         &mut self,
1849         kind: IntCmpKind,
1850         lhs: Reg,
1851         rhs: RegImm,
1852         taken: MachLabel,
1853         size: OperandSize,
1854     ) -> Result<()>;
1855 
1856     /// Emits and unconditional jump to the given label.
1857     fn jmp(&mut self, target: MachLabel) -> Result<()>;
1858 
1859     /// Emits a jump table sequence. The default label is specified as
1860     /// the last element of the targets slice.
1861     fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>;
1862 
1863     /// Emit an unreachable code trap.
1864     fn unreachable(&mut self) -> Result<()>;
1865 
1866     /// Emit an unconditional trap.
1867     fn trap(&mut self, code: TrapCode) -> Result<()>;
1868 
1869     /// Traps if the condition code is met.
1870     fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>;
1871 
1872     /// Trap if the source register is zero.
1873     fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>;
1874 
1875     /// Ensures that the stack pointer is correctly positioned before an unconditional
1876     /// jump according to the requirements of the destination target.
1877     fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> {
1878         let bytes = self
1879             .sp_offset()?
1880             .as_u32()
1881             .checked_sub(target.as_u32())
1882             .unwrap_or(0);
1883 
1884         if bytes > 0 {
1885             self.free_stack(bytes)?;
1886         }
1887 
1888         Ok(())
1889     }
1890 
1891     /// Mark the start of a source location returning the machine code offset
1892     /// and the relative source code location.
1893     fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>;
1894 
1895     /// Mark the end of a source location.
1896     fn end_source_loc(&mut self) -> Result<()>;
1897 
1898     /// The current offset, in bytes from the beginning of the function.
1899     fn current_code_offset(&self) -> Result<CodeOffset>;
1900 
1901     /// Performs a 128-bit addition
1902     fn add128(
1903         &mut self,
1904         dst_lo: WritableReg,
1905         dst_hi: WritableReg,
1906         lhs_lo: Reg,
1907         lhs_hi: Reg,
1908         rhs_lo: Reg,
1909         rhs_hi: Reg,
1910     ) -> Result<()>;
1911 
1912     /// Performs a 128-bit subtraction
1913     fn sub128(
1914         &mut self,
1915         dst_lo: WritableReg,
1916         dst_hi: WritableReg,
1917         lhs_lo: Reg,
1918         lhs_hi: Reg,
1919         rhs_lo: Reg,
1920         rhs_hi: Reg,
1921     ) -> Result<()>;
1922 
1923     /// Performs a widening multiplication from two 64-bit operands into a
1924     /// 128-bit result.
1925     ///
1926     /// Note that some platforms require special handling of registers in this
1927     /// instruction (e.g. x64) so full access to `CodeGenContext` is provided.
1928     fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind)
1929         -> Result<()>;
1930 
1931     /// Takes the value in a src operand and replicates it across lanes of
1932     /// `size` in a destination result.
1933     fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>;
1934 
1935     /// Performs a shuffle between two 128-bit vectors into a 128-bit result
1936     /// using lanes as a mask to select which indexes to copy.
1937     fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>;
1938 
1939     /// Performs a swizzle between two 128-bit vectors into a 128-bit result.
1940     fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>;
1941 
1942     /// Performs the RMW `op` operation on the passed `addr`.
1943     ///
1944     /// The value *before* the operation was performed is written back to the `operand` register.
1945     fn atomic_rmw(
1946         &mut self,
1947         context: &mut CodeGenContext<Emission>,
1948         addr: Self::Address,
1949         size: OperandSize,
1950         op: RmwOp,
1951         flags: MemFlags,
1952         extend: Option<Extend<Zero>>,
1953     ) -> Result<()>;
1954 
1955     /// Extracts the scalar value from `src` in `lane` to `dst`.
1956     fn extract_lane(
1957         &mut self,
1958         src: Reg,
1959         dst: WritableReg,
1960         lane: u8,
1961         kind: ExtractLaneKind,
1962     ) -> Result<()>;
1963 
1964     /// Replaces the value in `lane` in `dst` with the value in `src`.
1965     fn replace_lane(
1966         &mut self,
1967         src: RegImm,
1968         dst: WritableReg,
1969         lane: u8,
1970         kind: ReplaceLaneKind,
1971     ) -> Result<()>;
1972 
1973     /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected`
1974     /// and `replacement` (at the top of the context's stack).
1975     ///
1976     /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that
1977     /// expect parameters in specific registers. The context stack contains the `replacement`,
1978     /// and `expected` values in that order. The implementer is expected to push the value at
1979     /// `addr` before the update to the context's stack before returning.
1980     fn atomic_cas(
1981         &mut self,
1982         context: &mut CodeGenContext<Emission>,
1983         addr: Self::Address,
1984         size: OperandSize,
1985         flags: MemFlags,
1986         extend: Option<Extend<Zero>>,
1987     ) -> Result<()>;
1988 
1989     /// Compares vector registers `lhs` and `rhs` for equality and puts the
1990     /// vector of results in `dst`.
1991     fn v128_eq(
1992         &mut self,
1993         dst: WritableReg,
1994         lhs: Reg,
1995         rhs: Reg,
1996         kind: VectorEqualityKind,
1997     ) -> Result<()>;
1998 
1999     /// Compares vector registers `lhs` and `rhs` for inequality and puts the
2000     /// vector of results in `dst`.
2001     fn v128_ne(
2002         &mut self,
2003         dst: WritableReg,
2004         lhs: Reg,
2005         rhs: Reg,
2006         kind: VectorEqualityKind,
2007     ) -> Result<()>;
2008 
2009     /// Performs a less than comparison with vector registers `lhs` and `rhs`
2010     /// and puts the vector of results in `dst`.
2011     fn v128_lt(
2012         &mut self,
2013         dst: WritableReg,
2014         lhs: Reg,
2015         rhs: Reg,
2016         kind: VectorCompareKind,
2017     ) -> Result<()>;
2018 
2019     /// Performs a less than or equal comparison with vector registers `lhs`
2020     /// and `rhs` and puts the vector of results in `dst`.
2021     fn v128_le(
2022         &mut self,
2023         dst: WritableReg,
2024         lhs: Reg,
2025         rhs: Reg,
2026         kind: VectorCompareKind,
2027     ) -> Result<()>;
2028 
2029     /// Performs a greater than comparison with vector registers `lhs` and
2030     /// `rhs` and puts the vector of results in `dst`.
2031     fn v128_gt(
2032         &mut self,
2033         dst: WritableReg,
2034         lhs: Reg,
2035         rhs: Reg,
2036         kind: VectorCompareKind,
2037     ) -> Result<()>;
2038 
2039     /// Performs a greater than or equal comparison with vector registers `lhs`
2040     /// and `rhs` and puts the vector of results in `dst`.
2041     fn v128_ge(
2042         &mut self,
2043         dst: WritableReg,
2044         lhs: Reg,
2045         rhs: Reg,
2046         kind: VectorCompareKind,
2047     ) -> Result<()>;
2048 
2049     /// Emit a memory fence.
2050     fn fence(&mut self) -> Result<()>;
2051 
2052     /// Perform a logical `not` operation on the 128bits vector value in `dst`.
2053     fn v128_not(&mut self, dst: WritableReg) -> Result<()>;
2054 
2055     /// Perform a logical `and` operation on `src1` and `src1`, both 128bits vector values, writing
2056     /// the result to `dst`.
2057     fn v128_and(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2058 
2059     /// Perform a logical `and_not` operation on `src1` and `src1`, both 128bits vector values, writing
2060     /// the result to `dst`.
2061     ///
2062     /// `and_not` is not commutative: dst = !src1 & src2.
2063     fn v128_and_not(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2064 
2065     /// Perform a logical `or` operation on `src1` and `src1`, both 128bits vector values, writing
2066     /// the result to `dst`.
2067     fn v128_or(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2068 
2069     /// Perform a logical `xor` operation on `src1` and `src1`, both 128bits vector values, writing
2070     /// the result to `dst`.
2071     fn v128_xor(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>;
2072 
2073     /// Given two 128bits vectors `src1` and `src2`, and a 128bits bitmask `mask`, selects bits
2074     /// from `src1` when mask is 1, and from `src2` when mask is 0.
2075     ///
2076     /// This is equivalent to: `v128.or(v128.and(src1, mask), v128.and(src2, v128.not(mask)))`.
2077     fn v128_bitselect(&mut self, src1: Reg, src2: Reg, mask: Reg, dst: WritableReg) -> Result<()>;
2078 
2079     /// If any bit in `src` is 1, set `dst` to 1, or 0 otherwise.
2080     fn v128_any_true(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2081 
2082     /// Convert vector of integers to vector of floating points.
2083     fn v128_convert(&mut self, src: Reg, dst: WritableReg, kind: V128ConvertKind) -> Result<()>;
2084 
2085     /// Convert two input vectors into a smaller lane vector by narrowing each
2086     /// lane.
2087     fn v128_narrow(
2088         &mut self,
2089         src1: Reg,
2090         src2: Reg,
2091         dst: WritableReg,
2092         kind: V128NarrowKind,
2093     ) -> Result<()>;
2094 
2095     /// Converts a vector containing two 64-bit floating point lanes to two
2096     /// 32-bit floating point lanes and setting the two higher lanes to 0.
2097     fn v128_demote(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2098 
2099     /// Converts a vector containing four 32-bit floating point lanes to two
2100     /// 64-bit floating point lanes. Only the two lower lanes are converted.
2101     fn v128_promote(&mut self, src: Reg, dst: WritableReg) -> Result<()>;
2102 
2103     /// Converts low or high half of the smaller lane vector to a larger lane
2104     /// vector.
2105     fn v128_extend(&mut self, src: Reg, dst: WritableReg, kind: V128ExtendKind) -> Result<()>;
2106 
2107     /// Perform a vector add between `lsh` and `rhs`, placing the result in
2108     /// `dst`.
2109     fn v128_add(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128AddKind) -> Result<()>;
2110 
2111     /// Perform a vector sub between `lhs` and `rhs`, placing the result in `dst`.
2112     fn v128_sub(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128SubKind) -> Result<()>;
2113 
2114     /// Perform a vector lane-wise mul between `lhs` and `rhs`, placing the result in `dst`.
2115     fn v128_mul(&mut self, context: &mut CodeGenContext<Emission>, kind: V128MulKind)
2116         -> Result<()>;
2117 
2118     /// Perform an absolute operation on a vector.
2119     fn v128_abs(&mut self, src: Reg, dst: WritableReg, kind: V128AbsKind) -> Result<()>;
2120 
2121     /// Vectorized negate of the content of `op`.
2122     fn v128_neg(&mut self, op: WritableReg, kind: V128NegKind) -> Result<()>;
2123 
2124     /// Perform the shift operation specified by `kind`, by the shift amount specified by the 32-bit
2125     /// integer at the top of the stack, on the 128-bit vector specified by the second value
2126     /// from the top of the stack, interpreted as packed integers of size `lane_width`.
2127     ///
2128     /// The shift amount is taken modulo `lane_width`.
2129     fn v128_shift(
2130         &mut self,
2131         context: &mut CodeGenContext<Emission>,
2132         lane_width: OperandSize,
2133         kind: ShiftKind,
2134     ) -> Result<()>;
2135 
2136     /// Perform a saturating integer q-format rounding multiplication.
2137     fn v128_q15mulr_sat_s(
2138         &mut self,
2139         lhs: Reg,
2140         rhs: Reg,
2141         dst: WritableReg,
2142         size: OperandSize,
2143     ) -> Result<()>;
2144 
2145     /// Sets `dst` to 1 if all lanes in `src` are non-zero, sets `dst` to 0
2146     /// otherwise.
2147     fn v128_all_true(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2148 
2149     /// Extracts the high bit of each lane in `src` and produces a scalar mask
2150     /// with all bits concatenated in `dst`.
2151     fn v128_bitmask(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2152 
2153     /// Lanewise truncation operation.
2154     ///
2155     /// If using an integer kind of truncation, then this performs a lane-wise
2156     /// saturating conversion from float to integer using the IEEE
2157     /// `convertToIntegerTowardZero` function. If any input lane is NaN, the
2158     /// resulting lane is 0. If the rounded integer value of a lane is outside
2159     /// the range of the destination type, the result is saturated to the
2160     /// nearest representable integer value.
2161     fn v128_trunc(
2162         &mut self,
2163         context: &mut CodeGenContext<Emission>,
2164         kind: V128TruncKind,
2165     ) -> Result<()>;
2166 
2167     /// Perform a lane-wise `min` operation between `src1` and `src2`.
2168     fn v128_min(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MinKind)
2169         -> Result<()>;
2170 
2171     /// Perform a lane-wise `max` operation between `src1` and `src2`.
2172     fn v128_max(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MaxKind)
2173         -> Result<()>;
2174 
2175     /// Perform the lane-wise integer extended multiplication producing twice wider result than the
2176     /// inputs. This is equivalent to an extend followed by a multiply.
2177     ///
2178     /// The extension to be performed is inferred from the `lane_width` and the `kind` of extmul,
2179     /// e.g, if `lane_width` is `S16`, and `kind` is `LowSigned`, then we sign-extend the lower
2180     /// 8bits of the 16bits lanes.
2181     fn v128_extmul(
2182         &mut self,
2183         context: &mut CodeGenContext<Emission>,
2184         kind: V128ExtMulKind,
2185     ) -> Result<()>;
2186 
2187     /// Perform the lane-wise integer extended pairwise addition producing extended results (twice
2188     /// wider results than the inputs).
2189     fn v128_extadd_pairwise(
2190         &mut self,
2191         src: Reg,
2192         dst: WritableReg,
2193         kind: V128ExtAddKind,
2194     ) -> Result<()>;
2195 
2196     /// Lane-wise multiply signed 16-bit integers in `lhs` and `rhs` and add
2197     /// adjacent pairs of the 32-bit results.
2198     fn v128_dot(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg) -> Result<()>;
2199 
2200     /// Count the number of bits set in each lane.
2201     fn v128_popcnt(&mut self, context: &mut CodeGenContext<Emission>) -> Result<()>;
2202 
2203     /// Lane-wise rounding average of vectors of integers in `lhs` and `rhs`
2204     /// and put the results in `dst`.
2205     fn v128_avgr(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2206 
2207     /// Lane-wise IEEE division on vectors of floats.
2208     fn v128_div(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2209 
2210     /// Lane-wise IEEE square root of vector of floats.
2211     fn v128_sqrt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2212 
2213     /// Lane-wise ceiling of vector of floats.
2214     fn v128_ceil(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2215 
2216     /// Lane-wise flooring of vector of floats.
2217     fn v128_floor(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2218 
2219     /// Lane-wise rounding to nearest integer for vector of floats.
2220     fn v128_nearest(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2221 
2222     /// Lane-wise minimum value defined as `rhs < lhs ? rhs : lhs`.
2223     fn v128_pmin(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2224 
2225     /// Lane-wise maximum value defined as `lhs < rhs ? rhs : lhs`.
2226     fn v128_pmax(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>;
2227 }
2228