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