xref: /wasmtime-44.0.1/winch/codegen/src/masm.rs (revision 0afaa2f4)
1 use crate::abi::{self, align_to, scratch, LocalSlot};
2 use crate::codegen::{CodeGenContext, Emission, FuncEnv};
3 use crate::isa::{
4     reg::{writable, Reg, WritableReg},
5     CallingConvention,
6 };
7 use anyhow::Result;
8 use cranelift_codegen::{
9     binemit::CodeOffset,
10     ir::{Endianness, LibCall, MemFlags, RelSourceLoc, SourceLoc, UserExternalNameRef},
11     Final, MachBufferFinalized, MachLabel,
12 };
13 use std::{fmt::Debug, ops::Range};
14 use wasmtime_environ::PtrSize;
15 
16 pub(crate) use cranelift_codegen::ir::TrapCode;
17 
18 #[derive(Eq, PartialEq)]
19 pub(crate) enum DivKind {
20     /// Signed division.
21     Signed,
22     /// Unsigned division.
23     Unsigned,
24 }
25 
26 /// Remainder kind.
27 #[derive(Copy, Clone)]
28 pub(crate) enum RemKind {
29     /// Signed remainder.
30     Signed,
31     /// Unsigned remainder.
32     Unsigned,
33 }
34 
35 impl RemKind {
36     pub fn is_signed(&self) -> bool {
37         matches!(self, Self::Signed)
38     }
39 }
40 
41 #[derive(Copy, Clone, PartialEq, Eq)]
42 pub(crate) enum MemOpKind {
43     /// An atomic memory operation with SeqCst memory ordering.
44     Atomic,
45     /// A memory operation with no memory ordering constraint.
46     Normal,
47 }
48 
49 #[derive(Eq, PartialEq)]
50 pub(crate) enum MulWideKind {
51     Signed,
52     Unsigned,
53 }
54 
55 /// Type of operation for a read-modify-write instruction.
56 pub(crate) enum RmwOp {
57     Add,
58     Sub,
59     Xchg,
60     And,
61     Or,
62     Xor,
63 }
64 
65 /// The direction to perform the memory move.
66 #[derive(Debug, Clone, Eq, PartialEq)]
67 pub(crate) enum MemMoveDirection {
68     /// From high memory addresses to low memory addresses.
69     /// Invariant: the source location is closer to the FP than the destination
70     /// location, which will be closer to the SP.
71     HighToLow,
72     /// From low memory addresses to high memory addresses.
73     /// Invariant: the source location is closer to the SP than the destination
74     /// location, which will be closer to the FP.
75     LowToHigh,
76 }
77 
78 /// Classifies how to treat float-to-int conversions.
79 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
80 pub(crate) enum TruncKind {
81     /// Saturating conversion. If the source value is greater than the maximum
82     /// value of the destination type, the result is clamped to the
83     /// destination maximum value.
84     Checked,
85     /// An exception is raised if the source value is greater than the maximum
86     /// value of the destination type.
87     Unchecked,
88 }
89 
90 impl TruncKind {
91     /// Returns true if the truncation kind is checked.
92     pub(crate) fn is_checked(&self) -> bool {
93         *self == TruncKind::Checked
94     }
95 
96     /// Returns `true` if the trunc kind is [`Unchecked`].
97     ///
98     /// [`Unchecked`]: TruncKind::Unchecked
99     #[must_use]
100     pub(crate) fn is_unchecked(&self) -> bool {
101         matches!(self, Self::Unchecked)
102     }
103 }
104 
105 /// Representation of the stack pointer offset.
106 #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)]
107 pub struct SPOffset(u32);
108 
109 impl SPOffset {
110     pub fn from_u32(offs: u32) -> Self {
111         Self(offs)
112     }
113 
114     pub fn as_u32(&self) -> u32 {
115         self.0
116     }
117 }
118 
119 /// A stack slot.
120 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
121 pub struct StackSlot {
122     /// The location of the slot, relative to the stack pointer.
123     pub offset: SPOffset,
124     /// The size of the slot, in bytes.
125     pub size: u32,
126 }
127 
128 impl StackSlot {
129     pub fn new(offs: SPOffset, size: u32) -> Self {
130         Self { offset: offs, size }
131     }
132 }
133 
134 /// Kinds of integer binary comparison in WebAssembly. The [`MacroAssembler`]
135 /// implementation for each ISA is responsible for emitting the correct
136 /// sequence of instructions when lowering to machine code.
137 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
138 pub(crate) enum IntCmpKind {
139     /// Equal.
140     Eq,
141     /// Not equal.
142     Ne,
143     /// Signed less than.
144     LtS,
145     /// Unsigned less than.
146     LtU,
147     /// Signed greater than.
148     GtS,
149     /// Unsigned greater than.
150     GtU,
151     /// Signed less than or equal.
152     LeS,
153     /// Unsigned less than or equal.
154     LeU,
155     /// Signed greater than or equal.
156     GeS,
157     /// Unsigned greater than or equal.
158     GeU,
159 }
160 
161 /// Kinds of float binary comparison in WebAssembly. The [`MacroAssembler`]
162 /// implementation for each ISA is responsible for emitting the correct
163 /// sequence of instructions when lowering code.
164 #[derive(Debug)]
165 pub(crate) enum FloatCmpKind {
166     /// Equal.
167     Eq,
168     /// Not equal.
169     Ne,
170     /// Less than.
171     Lt,
172     /// Greater than.
173     Gt,
174     /// Less than or equal.
175     Le,
176     /// Greater than or equal.
177     Ge,
178 }
179 
180 /// Kinds of shifts in WebAssembly.The [`masm`] implementation for each ISA is
181 /// responsible for emitting the correct sequence of instructions when
182 /// lowering to machine code.
183 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
184 pub(crate) enum ShiftKind {
185     /// Left shift.
186     Shl,
187     /// Signed right shift.
188     ShrS,
189     /// Unsigned right shift.
190     ShrU,
191     /// Left rotate.
192     Rotl,
193     /// Right rotate.
194     Rotr,
195 }
196 
197 /// Kinds of extends in WebAssembly. Each MacroAssembler implementation
198 /// is responsible for emitting the correct sequence of instructions when
199 /// lowering to machine code.
200 #[derive(Copy, Clone)]
201 pub(crate) enum ExtendKind {
202     Signed(Extend<Signed>),
203     Unsigned(Extend<Zero>),
204 }
205 
206 #[derive(Copy, Clone)]
207 pub(crate) enum Signed {}
208 #[derive(Copy, Clone)]
209 pub(crate) enum Zero {}
210 
211 pub(crate) trait ExtendType {}
212 
213 impl ExtendType for Signed {}
214 impl ExtendType for Zero {}
215 
216 #[derive(Copy, Clone)]
217 pub(crate) enum Extend<T: ExtendType> {
218     /// 8 to 32 bit extend.
219     I32Extend8,
220     /// 16 to 32 bit extend.
221     I32Extend16,
222     /// 8 to 64 bit extend.
223     I64Extend8,
224     /// 16 to 64 bit extend.
225     I64Extend16,
226     /// 32 to 64 bit extend.
227     I64Extend32,
228 
229     /// Variant to hold the kind of extend marker.
230     ///
231     /// This is `Signed` or `Zero`, that are empty enums, which means that this variant cannot be
232     /// constructed.
233     __Kind(T),
234 }
235 
236 impl From<Extend<Zero>> for ExtendKind {
237     fn from(value: Extend<Zero>) -> Self {
238         ExtendKind::Unsigned(value)
239     }
240 }
241 
242 impl<T: ExtendType> Extend<T> {
243     pub fn from_size(&self) -> OperandSize {
244         match self {
245             Extend::I32Extend8 | Extend::I64Extend8 => OperandSize::S8,
246             Extend::I32Extend16 | Extend::I64Extend16 => OperandSize::S16,
247             Extend::I64Extend32 => OperandSize::S32,
248             Extend::__Kind(_) => unreachable!(),
249         }
250     }
251 
252     pub fn to_size(&self) -> OperandSize {
253         match self {
254             Extend::I32Extend8 | Extend::I32Extend16 => OperandSize::S32,
255             Extend::I64Extend8 | Extend::I64Extend16 | Extend::I64Extend32 => OperandSize::S64,
256             Extend::__Kind(_) => unreachable!(),
257         }
258     }
259 
260     pub fn from_bits(&self) -> u8 {
261         self.from_size().num_bits()
262     }
263 
264     pub fn to_bits(&self) -> u8 {
265         self.to_size().num_bits()
266     }
267 }
268 
269 impl From<Extend<Signed>> for ExtendKind {
270     fn from(value: Extend<Signed>) -> Self {
271         ExtendKind::Signed(value)
272     }
273 }
274 
275 impl ExtendKind {
276     pub fn signed(&self) -> bool {
277         match self {
278             Self::Signed(_) => true,
279             _ => false,
280         }
281     }
282 
283     pub fn from_bits(&self) -> u8 {
284         match self {
285             Self::Signed(s) => s.from_bits(),
286             Self::Unsigned(u) => u.from_bits(),
287         }
288     }
289 
290     pub fn to_bits(&self) -> u8 {
291         match self {
292             Self::Signed(s) => s.to_bits(),
293             Self::Unsigned(u) => u.to_bits(),
294         }
295     }
296 }
297 
298 /// Kinds of vector extends in WebAssembly. Each MacroAssembler implementation
299 /// is responsible for emitting the correct sequence of instructions when
300 /// lowering to machine code.
301 pub(crate) enum VectorExtendKind {
302     /// Sign extends eight 8 bit integers to eight 16 bit lanes.
303     V128Extend8x8S,
304     /// Zero extends eight 8 bit integers to eight 16 bit lanes.
305     V128Extend8x8U,
306     /// Sign extends four 16 bit integers to four 32 bit lanes.
307     V128Extend16x4S,
308     /// Zero extends four 16 bit integers to four 32 bit lanes.
309     V128Extend16x4U,
310     /// Sign extends two 32 bit integers to two 64 bit lanes.
311     V128Extend32x2S,
312     /// Zero extends two 32 bit integers to two 64 bit lanes.
313     V128Extend32x2U,
314 }
315 
316 /// Kinds of splat loads supported by WebAssembly.
317 pub(crate) enum SplatLoadKind {
318     /// 8 bits.
319     S8,
320     /// 16 bits.
321     S16,
322     /// 32 bits.
323     S32,
324     /// 64 bits.
325     S64,
326 }
327 
328 /// Kinds of splat supported by WebAssembly.
329 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
330 pub(crate) enum SplatKind {
331     /// 8 bit integer.
332     I8x16,
333     /// 16 bit integer.
334     I16x8,
335     /// 32 bit integer.
336     I32x4,
337     /// 64 bit integer.
338     I64x2,
339     /// 32 bit float.
340     F32x4,
341     /// 64 bit float.
342     F64x2,
343 }
344 
345 impl SplatKind {
346     /// The lane size to use for different kinds of splats.
347     pub(crate) fn lane_size(&self) -> OperandSize {
348         match self {
349             SplatKind::I8x16 => OperandSize::S8,
350             SplatKind::I16x8 => OperandSize::S16,
351             SplatKind::I32x4 | SplatKind::F32x4 => OperandSize::S32,
352             SplatKind::I64x2 | SplatKind::F64x2 => OperandSize::S64,
353         }
354     }
355 }
356 
357 /// Kinds of extract lane supported by WebAssembly.
358 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
359 pub(crate) enum ExtractLaneKind {
360     /// 16 lanes of 8-bit integers sign extended to 32-bits.
361     I8x16S,
362     /// 16 lanes of 8-bit integers zero extended to 32-bits.
363     I8x16U,
364     /// 8 lanes of 16-bit integers sign extended to 32-bits.
365     I16x8S,
366     /// 8 lanes of 16-bit integers zero extended to 32-bits.
367     I16x8U,
368     /// 4 lanes of 32-bit integers.
369     I32x4,
370     /// 2 lanes of 64-bit integers.
371     I64x2,
372     /// 4 lanes of 32-bit floats.
373     F32x4,
374     /// 2 lanes of 64-bit floats.
375     F64x2,
376 }
377 
378 impl ExtractLaneKind {
379     /// The lane size to use for different kinds of extract lane kinds.
380     pub(crate) fn lane_size(&self) -> OperandSize {
381         match self {
382             ExtractLaneKind::I8x16S | ExtractLaneKind::I8x16U => OperandSize::S8,
383             ExtractLaneKind::I16x8S | ExtractLaneKind::I16x8U => OperandSize::S16,
384             ExtractLaneKind::I32x4 | ExtractLaneKind::F32x4 => OperandSize::S32,
385             ExtractLaneKind::I64x2 | ExtractLaneKind::F64x2 => OperandSize::S64,
386         }
387     }
388 }
389 
390 impl From<ExtractLaneKind> for Extend<Signed> {
391     fn from(value: ExtractLaneKind) -> Self {
392         match value {
393             ExtractLaneKind::I8x16S => Extend::I32Extend8,
394             ExtractLaneKind::I16x8S => Extend::I32Extend16,
395             _ => unimplemented!(),
396         }
397     }
398 }
399 
400 /// Kinds of behavior supported by Wasm loads.
401 pub(crate) enum LoadKind {
402     /// Load the entire bytes of the operand size without any modifications.
403     Operand(OperandSize),
404     /// Duplicate value into vector lanes.
405     Splat(SplatLoadKind),
406     /// Scalar (non-vector) extend.
407     ScalarExtend(ExtendKind),
408     /// Vector extend.
409     VectorExtend(VectorExtendKind),
410 }
411 
412 impl LoadKind {
413     /// Returns the [`OperandSize`] used in the load operation.
414     pub(crate) fn derive_operand_size(&self) -> OperandSize {
415         match self {
416             Self::ScalarExtend(scalar) => Self::operand_size_for_scalar(scalar),
417             Self::VectorExtend(vector) => Self::operand_size_for_vector(vector),
418             Self::Splat(kind) => Self::operand_size_for_splat(kind),
419             Self::Operand(op) => *op,
420         }
421     }
422 
423     fn operand_size_for_vector(vector: &VectorExtendKind) -> OperandSize {
424         match vector {
425             VectorExtendKind::V128Extend8x8S | VectorExtendKind::V128Extend8x8U => OperandSize::S8,
426             VectorExtendKind::V128Extend16x4S | VectorExtendKind::V128Extend16x4U => {
427                 OperandSize::S16
428             }
429             VectorExtendKind::V128Extend32x2S | VectorExtendKind::V128Extend32x2U => {
430                 OperandSize::S32
431             }
432         }
433     }
434 
435     fn operand_size_for_scalar(extend_kind: &ExtendKind) -> OperandSize {
436         match extend_kind {
437             ExtendKind::Signed(s) => s.from_size(),
438             ExtendKind::Unsigned(u) => u.from_size(),
439         }
440     }
441 
442     fn operand_size_for_splat(kind: &SplatLoadKind) -> OperandSize {
443         match kind {
444             SplatLoadKind::S8 => OperandSize::S8,
445             SplatLoadKind::S16 => OperandSize::S16,
446             SplatLoadKind::S32 => OperandSize::S32,
447             SplatLoadKind::S64 => OperandSize::S64,
448         }
449     }
450 }
451 
452 /// Operand size, in bits.
453 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
454 pub(crate) enum OperandSize {
455     /// 8 bits.
456     S8,
457     /// 16 bits.
458     S16,
459     /// 32 bits.
460     S32,
461     /// 64 bits.
462     S64,
463     /// 128 bits.
464     S128,
465 }
466 
467 impl OperandSize {
468     /// The number of bits in the operand.
469     pub fn num_bits(&self) -> u8 {
470         match self {
471             OperandSize::S8 => 8,
472             OperandSize::S16 => 16,
473             OperandSize::S32 => 32,
474             OperandSize::S64 => 64,
475             OperandSize::S128 => 128,
476         }
477     }
478 
479     /// The number of bytes in the operand.
480     pub fn bytes(&self) -> u32 {
481         match self {
482             Self::S8 => 1,
483             Self::S16 => 2,
484             Self::S32 => 4,
485             Self::S64 => 8,
486             Self::S128 => 16,
487         }
488     }
489 
490     /// The binary logarithm of the number of bits in the operand.
491     pub fn log2(&self) -> u8 {
492         match self {
493             OperandSize::S8 => 3,
494             OperandSize::S16 => 4,
495             OperandSize::S32 => 5,
496             OperandSize::S64 => 6,
497             OperandSize::S128 => 7,
498         }
499     }
500 
501     /// Create an [`OperandSize`]  from the given number of bytes.
502     pub fn from_bytes(bytes: u8) -> Self {
503         use OperandSize::*;
504         match bytes {
505             4 => S32,
506             8 => S64,
507             16 => S128,
508             _ => panic!("Invalid bytes {bytes} for OperandSize"),
509         }
510     }
511 
512     pub fn extend_to<T: ExtendType>(&self, to: Self) -> Option<Extend<T>> {
513         match to {
514             OperandSize::S32 => match self {
515                 OperandSize::S8 => Some(Extend::I32Extend8),
516                 OperandSize::S16 => Some(Extend::I32Extend16),
517                 _ => None,
518             },
519             OperandSize::S64 => match self {
520                 OperandSize::S8 => Some(Extend::I64Extend8),
521                 OperandSize::S16 => Some(Extend::I64Extend16),
522                 OperandSize::S32 => Some(Extend::I64Extend32),
523                 _ => None,
524             },
525             _ => None,
526         }
527     }
528 }
529 
530 /// An abstraction over a register or immediate.
531 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
532 pub(crate) enum RegImm {
533     /// A register.
534     Reg(Reg),
535     /// A tagged immediate argument.
536     Imm(Imm),
537 }
538 
539 /// An tagged representation of an immediate.
540 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
541 pub(crate) enum Imm {
542     /// I32 immediate.
543     I32(u32),
544     /// I64 immediate.
545     I64(u64),
546     /// F32 immediate.
547     F32(u32),
548     /// F64 immediate.
549     F64(u64),
550     /// V128 immediate.
551     V128(i128),
552 }
553 
554 impl Imm {
555     /// Create a new I64 immediate.
556     pub fn i64(val: i64) -> Self {
557         Self::I64(val as u64)
558     }
559 
560     /// Create a new I32 immediate.
561     pub fn i32(val: i32) -> Self {
562         Self::I32(val as u32)
563     }
564 
565     /// Create a new F32 immediate.
566     pub fn f32(bits: u32) -> Self {
567         Self::F32(bits)
568     }
569 
570     /// Create a new F64 immediate.
571     pub fn f64(bits: u64) -> Self {
572         Self::F64(bits)
573     }
574 
575     /// Create a new V128 immediate.
576     pub fn v128(bits: i128) -> Self {
577         Self::V128(bits)
578     }
579 
580     /// Convert the immediate to i32, if possible.
581     pub fn to_i32(&self) -> Option<i32> {
582         match self {
583             Self::I32(v) => Some(*v as i32),
584             Self::I64(v) => i32::try_from(*v as i64).ok(),
585             _ => None,
586         }
587     }
588 
589     /// Returns true if the [`Imm`] is float.
590     pub fn is_float(&self) -> bool {
591         match self {
592             Self::F32(_) | Self::F64(_) => true,
593             _ => false,
594         }
595     }
596 
597     /// Get the operand size of the immediate.
598     pub fn size(&self) -> OperandSize {
599         match self {
600             Self::I32(_) | Self::F32(_) => OperandSize::S32,
601             Self::I64(_) | Self::F64(_) => OperandSize::S64,
602             Self::V128(_) => OperandSize::S128,
603         }
604     }
605 
606     /// Get a little endian representation of the immediate.
607     ///
608     /// This method heap allocates and is intended to be used when adding
609     /// values to the constant pool.
610     pub fn to_bytes(&self) -> Vec<u8> {
611         match self {
612             Imm::I32(n) => n.to_le_bytes().to_vec(),
613             Imm::I64(n) => n.to_le_bytes().to_vec(),
614             Imm::F32(n) => n.to_le_bytes().to_vec(),
615             Imm::F64(n) => n.to_le_bytes().to_vec(),
616             Imm::V128(n) => n.to_le_bytes().to_vec(),
617         }
618     }
619 }
620 
621 /// The location of the [VMcontext] used for function calls.
622 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
623 pub(crate) enum VMContextLoc {
624     /// Dynamic, stored in the given register.
625     Reg(Reg),
626     /// The pinned [VMContext] register.
627     Pinned,
628 }
629 
630 /// The maximum number of context arguments currently used across the compiler.
631 pub(crate) const MAX_CONTEXT_ARGS: usize = 2;
632 
633 /// Out-of-band special purpose arguments used for function call emission.
634 ///
635 /// We cannot rely on the value stack for these values given that inserting
636 /// register or memory values at arbitrary locations of the value stack has the
637 /// potential to break the stack ordering principle, which states that older
638 /// values must always precede newer values, effectively simulating the order of
639 /// values in the machine stack.
640 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases
641 /// it might be possible to construct it early on, but given that it might
642 /// contain allocatable registers, it's preferred to construct it in
643 /// [FnCall::emit].
644 #[derive(Clone, Debug)]
645 pub(crate) enum ContextArgs {
646     /// No context arguments required. This is used for libcalls that don't
647     /// require any special context arguments. For example builtin functions
648     /// that perform float calculations.
649     None,
650     /// A single context argument is required; the current pinned [VMcontext]
651     /// register must be passed as the first argument of the function call.
652     VMContext([VMContextLoc; 1]),
653     /// The callee and caller context arguments are required. In this case, the
654     /// callee context argument is usually stored into an allocatable register
655     /// and the caller is always the current pinned [VMContext] pointer.
656     CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]),
657 }
658 
659 impl ContextArgs {
660     /// Construct an empty [ContextArgs].
661     pub fn none() -> Self {
662         Self::None
663     }
664 
665     /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext]
666     /// register as both the caller and callee context arguments.
667     pub fn pinned_callee_and_caller_vmctx() -> Self {
668         Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned])
669     }
670 
671     /// Construct a [ContextArgs] that declares the usage of the pinned
672     /// [VMContext] register as the only context argument.
673     pub fn pinned_vmctx() -> Self {
674         Self::VMContext([VMContextLoc::Pinned])
675     }
676 
677     /// Construct a [ContextArgs] that declares a dynamic callee context and the
678     /// pinned [VMContext] register as the context arguments.
679     pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self {
680         Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned])
681     }
682 
683     /// Get the length of the [ContextArgs].
684     pub fn len(&self) -> usize {
685         self.as_slice().len()
686     }
687 
688     /// Get a slice of the context arguments.
689     pub fn as_slice(&self) -> &[VMContextLoc] {
690         match self {
691             Self::None => &[],
692             Self::VMContext(a) => a.as_slice(),
693             Self::CalleeAndCallerVMContext(a) => a.as_slice(),
694         }
695     }
696 }
697 
698 #[derive(Copy, Clone, Debug)]
699 pub(crate) enum CalleeKind {
700     /// A function call to a raw address.
701     Indirect(Reg),
702     /// A function call to a local function.
703     Direct(UserExternalNameRef),
704     /// Call to a well known LibCall.
705     LibCall(LibCall),
706 }
707 
708 impl CalleeKind {
709     /// Creates a callee kind from a register.
710     pub fn indirect(reg: Reg) -> Self {
711         Self::Indirect(reg)
712     }
713 
714     /// Creates a direct callee kind from a function name.
715     pub fn direct(name: UserExternalNameRef) -> Self {
716         Self::Direct(name)
717     }
718 
719     /// Creates a known callee kind from a libcall.
720     pub fn libcall(call: LibCall) -> Self {
721         Self::LibCall(call)
722     }
723 }
724 
725 impl RegImm {
726     /// Register constructor.
727     pub fn reg(r: Reg) -> Self {
728         RegImm::Reg(r)
729     }
730 
731     /// I64 immediate constructor.
732     pub fn i64(val: i64) -> Self {
733         RegImm::Imm(Imm::i64(val))
734     }
735 
736     /// I32 immediate constructor.
737     pub fn i32(val: i32) -> Self {
738         RegImm::Imm(Imm::i32(val))
739     }
740 
741     /// F32 immediate, stored using its bits representation.
742     pub fn f32(bits: u32) -> Self {
743         RegImm::Imm(Imm::f32(bits))
744     }
745 
746     /// F64 immediate, stored using its bits representation.
747     pub fn f64(bits: u64) -> Self {
748         RegImm::Imm(Imm::f64(bits))
749     }
750 
751     /// V128 immediate.
752     pub fn v128(bits: i128) -> Self {
753         RegImm::Imm(Imm::v128(bits))
754     }
755 }
756 
757 impl From<Reg> for RegImm {
758     fn from(r: Reg) -> Self {
759         Self::Reg(r)
760     }
761 }
762 
763 #[derive(Debug)]
764 pub enum RoundingMode {
765     Nearest,
766     Up,
767     Down,
768     Zero,
769 }
770 
771 /// Memory flags for trusted loads/stores.
772 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted();
773 
774 /// Flags used for WebAssembly loads / stores.
775 /// Untrusted by default so we don't set `no_trap`.
776 /// We also ensure that the endianness is the right one for WebAssembly.
777 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little);
778 
779 /// Generic MacroAssembler interface used by the code generation.
780 ///
781 /// The MacroAssembler trait aims to expose an interface, high-level enough,
782 /// so that each ISA can provide its own lowering to machine code. For example,
783 /// for WebAssembly operators that don't have a direct mapping to a machine
784 /// a instruction, the interface defines a signature matching the WebAssembly
785 /// operator, allowing each implementation to lower such operator entirely.
786 /// This approach attributes more responsibility to the MacroAssembler, but frees
787 /// the caller from concerning about assembling the right sequence of
788 /// instructions at the operator callsite.
789 ///
790 /// The interface defaults to a three-argument form for binary operations;
791 /// this allows a natural mapping to instructions for RISC architectures,
792 /// that use three-argument form.
793 /// This approach allows for a more general interface that can be restricted
794 /// where needed, in the case of architectures that use a two-argument form.
795 
796 pub(crate) trait MacroAssembler {
797     /// The addressing mode.
798     type Address: Copy + Debug;
799 
800     /// The pointer representation of the target ISA,
801     /// used to access information from [`VMOffsets`].
802     type Ptr: PtrSize;
803 
804     /// The ABI details of the target.
805     type ABI: abi::ABI;
806 
807     /// Emit the function prologue.
808     fn prologue(&mut self, vmctx: Reg) -> Result<()> {
809         self.frame_setup()?;
810         self.check_stack(vmctx)
811     }
812 
813     /// Generate the frame setup sequence.
814     fn frame_setup(&mut self) -> Result<()>;
815 
816     /// Generate the frame restore sequence.
817     fn frame_restore(&mut self) -> Result<()>;
818 
819     /// Emit a stack check.
820     fn check_stack(&mut self, vmctx: Reg) -> Result<()>;
821 
822     /// Emit the function epilogue.
823     fn epilogue(&mut self) -> Result<()> {
824         self.frame_restore()
825     }
826 
827     /// Reserve stack space.
828     fn reserve_stack(&mut self, bytes: u32) -> Result<()>;
829 
830     /// Free stack space.
831     fn free_stack(&mut self, bytes: u32) -> Result<()>;
832 
833     /// Reset the stack pointer to the given offset;
834     ///
835     /// Used to reset the stack pointer to a given offset
836     /// when dealing with unreachable code.
837     fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>;
838 
839     /// Get the address of a local slot.
840     fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>;
841 
842     /// Constructs an address with an offset that is relative to the
843     /// current position of the stack pointer (e.g. [sp + (sp_offset -
844     /// offset)].
845     fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>;
846 
847     /// Constructs an address with an offset that is absolute to the
848     /// current position of the stack pointer (e.g. [sp + offset].
849     fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>;
850 
851     /// Alias for [`Self::address_at_reg`] using the VMContext register as
852     /// a base. The VMContext register is derived from the ABI type that is
853     /// associated to the MacroAssembler.
854     fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>;
855 
856     /// Construct an address that is absolute to the current position
857     /// of the given register.
858     fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>;
859 
860     /// Emit a function call to either a local or external function.
861     fn call(
862         &mut self,
863         stack_args_size: u32,
864         f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>,
865     ) -> Result<u32>;
866 
867     /// Get stack pointer offset.
868     fn sp_offset(&self) -> Result<SPOffset>;
869 
870     /// Perform a stack store.
871     fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>;
872 
873     /// Alias for `MacroAssembler::store` with the operand size corresponding
874     /// to the pointer size of the target.
875     fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>;
876 
877     /// Perform a WebAssembly store.
878     /// A WebAssembly store introduces several additional invariants compared to
879     /// [Self::store], more precisely, it can implicitly trap, in certain
880     /// circumstances, even if explicit bounds checks are elided, in that sense,
881     /// we consider this type of load as untrusted. It can also differ with
882     /// regards to the endianness depending on the target ISA. For this reason,
883     /// [Self::wasm_store], should be explicitly used when emitting WebAssembly
884     /// stores.
885     fn wasm_store(
886         &mut self,
887         src: Reg,
888         dst: Self::Address,
889         size: OperandSize,
890         op_kind: MemOpKind,
891     ) -> Result<()>;
892 
893     /// Perform a zero-extended stack load.
894     fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>;
895 
896     /// Perform a WebAssembly load.
897     /// A WebAssembly load introduces several additional invariants compared to
898     /// [Self::load], more precisely, it can implicitly trap, in certain
899     /// circumstances, even if explicit bounds checks are elided, in that sense,
900     /// we consider this type of load as untrusted. It can also differ with
901     /// regards to the endianness depending on the target ISA. For this reason,
902     /// [Self::wasm_load], should be explicitly used when emitting WebAssembly
903     /// loads.
904     fn wasm_load(
905         &mut self,
906         src: Self::Address,
907         dst: WritableReg,
908         kind: LoadKind,
909         op_kind: MemOpKind,
910     ) -> Result<()>;
911 
912     /// Alias for `MacroAssembler::load` with the operand size corresponding
913     /// to the pointer size of the target.
914     fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>;
915 
916     /// Loads the effective address into destination.
917     fn load_addr(
918         &mut self,
919         _src: Self::Address,
920         _dst: WritableReg,
921         _size: OperandSize,
922     ) -> Result<()>;
923 
924     /// Pop a value from the machine stack into the given register.
925     fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
926 
927     /// Perform a move.
928     fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>;
929 
930     /// Perform a conditional move.
931     fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize)
932         -> Result<()>;
933 
934     /// Performs a memory move of bytes from src to dest.
935     /// Bytes are moved in blocks of 8 bytes, where possible.
936     fn memmove(
937         &mut self,
938         src: SPOffset,
939         dst: SPOffset,
940         bytes: u32,
941         direction: MemMoveDirection,
942     ) -> Result<()> {
943         match direction {
944             MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()),
945             MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()),
946         }
947         // At least 4 byte aligned.
948         debug_assert!(bytes % 4 == 0);
949         let mut remaining = bytes;
950         let word_bytes = <Self::ABI as abi::ABI>::word_bytes();
951         let scratch = scratch!(Self);
952 
953         let mut dst_offs = dst.as_u32() - bytes;
954         let mut src_offs = src.as_u32() - bytes;
955 
956         let word_bytes = word_bytes as u32;
957         while remaining >= word_bytes {
958             remaining -= word_bytes;
959             dst_offs += word_bytes;
960             src_offs += word_bytes;
961 
962             self.load_ptr(
963                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
964                 writable!(scratch),
965             )?;
966             self.store_ptr(
967                 scratch.into(),
968                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
969             )?;
970         }
971 
972         if remaining > 0 {
973             let half_word = word_bytes / 2;
974             let ptr_size = OperandSize::from_bytes(half_word as u8);
975             debug_assert!(remaining == half_word);
976             dst_offs += half_word;
977             src_offs += half_word;
978 
979             self.load(
980                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
981                 writable!(scratch),
982                 ptr_size,
983             )?;
984             self.store(
985                 scratch.into(),
986                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
987                 ptr_size,
988             )?;
989         }
990         Ok(())
991     }
992 
993     /// Perform add operation.
994     fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
995 
996     /// Perform a checked unsigned integer addition, emitting the provided trap
997     /// if the addition overflows.
998     fn checked_uadd(
999         &mut self,
1000         dst: WritableReg,
1001         lhs: Reg,
1002         rhs: RegImm,
1003         size: OperandSize,
1004         trap: TrapCode,
1005     ) -> Result<()>;
1006 
1007     /// Perform subtraction operation.
1008     fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1009 
1010     /// Perform multiplication operation.
1011     fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1012 
1013     /// Perform a floating point add operation.
1014     fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1015 
1016     /// Perform a floating point subtraction operation.
1017     fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1018 
1019     /// Perform a floating point multiply operation.
1020     fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1021 
1022     /// Perform a floating point divide operation.
1023     fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1024 
1025     /// Perform a floating point minimum operation. In x86, this will emit
1026     /// multiple instructions.
1027     fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1028 
1029     /// Perform a floating point maximum operation. In x86, this will emit
1030     /// multiple instructions.
1031     fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1032 
1033     /// Perform a floating point copysign operation. In x86, this will emit
1034     /// multiple instructions.
1035     fn float_copysign(
1036         &mut self,
1037         dst: WritableReg,
1038         lhs: Reg,
1039         rhs: Reg,
1040         size: OperandSize,
1041     ) -> Result<()>;
1042 
1043     /// Perform a floating point abs operation.
1044     fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1045 
1046     /// Perform a floating point negation operation.
1047     fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1048 
1049     /// Perform a floating point floor operation.
1050     fn float_round<
1051         F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>,
1052     >(
1053         &mut self,
1054         mode: RoundingMode,
1055         env: &mut FuncEnv<Self::Ptr>,
1056         context: &mut CodeGenContext<Emission>,
1057         size: OperandSize,
1058         fallback: F,
1059     ) -> Result<()>;
1060 
1061     /// Perform a floating point square root operation.
1062     fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1063 
1064     /// Perform logical and operation.
1065     fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1066 
1067     /// Perform logical or operation.
1068     fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1069 
1070     /// Perform logical exclusive or operation.
1071     fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1072 
1073     /// Perform a shift operation between a register and an immediate.
1074     fn shift_ir(
1075         &mut self,
1076         dst: WritableReg,
1077         imm: u64,
1078         lhs: Reg,
1079         kind: ShiftKind,
1080         size: OperandSize,
1081     ) -> Result<()>;
1082 
1083     /// Perform a shift operation between two registers.
1084     /// This case is special in that some architectures have specific expectations
1085     /// regarding the location of the instruction arguments. To free the
1086     /// caller from having to deal with the architecture specific constraints
1087     /// we give this function access to the code generation context, allowing
1088     /// each implementation to decide the lowering path.
1089     fn shift(
1090         &mut self,
1091         context: &mut CodeGenContext<Emission>,
1092         kind: ShiftKind,
1093         size: OperandSize,
1094     ) -> Result<()>;
1095 
1096     /// Perform division operation.
1097     /// Division is special in that some architectures have specific
1098     /// expectations regarding the location of the instruction
1099     /// arguments and regarding the location of the quotient /
1100     /// remainder. To free the caller from having to deal with the
1101     /// architecture specific constraints we give this function access
1102     /// to the code generation context, allowing each implementation
1103     /// to decide the lowering path.  For cases in which division is a
1104     /// unconstrained binary operation, the caller can decide to use
1105     /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop`
1106     /// functions.
1107     fn div(
1108         &mut self,
1109         context: &mut CodeGenContext<Emission>,
1110         kind: DivKind,
1111         size: OperandSize,
1112     ) -> Result<()>;
1113 
1114     /// Calculate remainder.
1115     fn rem(
1116         &mut self,
1117         context: &mut CodeGenContext<Emission>,
1118         kind: RemKind,
1119         size: OperandSize,
1120     ) -> Result<()>;
1121 
1122     /// Compares `src1` against `src2` for the side effect of setting processor
1123     /// flags.
1124     ///
1125     /// Note that `src1` is the left-hand-side of the comparison and `src2` is
1126     /// the right-hand-side, so if testing `a < b` then `src1 == a` and
1127     /// `src2 == b`
1128     fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>;
1129 
1130     /// Compare src and dst and put the result in dst.
1131     /// This function will potentially emit a series of instructions.
1132     ///
1133     /// The initial value in `dst` is the left-hand-side of the comparison and
1134     /// the initial value in `src` is the right-hand-side of the comparison.
1135     /// That means for `a < b` then `dst == a` and `src == b`.
1136     fn cmp_with_set(
1137         &mut self,
1138         dst: WritableReg,
1139         src: RegImm,
1140         kind: IntCmpKind,
1141         size: OperandSize,
1142     ) -> Result<()>;
1143 
1144     /// Compare floats in src1 and src2 and put the result in dst.
1145     /// In x86, this will emit multiple instructions.
1146     fn float_cmp_with_set(
1147         &mut self,
1148         dst: WritableReg,
1149         src1: Reg,
1150         src2: Reg,
1151         kind: FloatCmpKind,
1152         size: OperandSize,
1153     ) -> Result<()>;
1154 
1155     /// Count the number of leading zeroes in src and put the result in dst.
1156     /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is
1157     /// false.
1158     fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1159 
1160     /// Count the number of trailing zeroes in src and put the result in dst.masm
1161     /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is
1162     /// false.
1163     fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1164 
1165     /// Push the register to the stack, returning the stack slot metadata.
1166     // NB
1167     // The stack alignment should not be assumed after any call to `push`,
1168     // unless explicitly aligned otherwise.  Typically, stack alignment is
1169     // maintained at call sites and during the execution of
1170     // epilogues.
1171     fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>;
1172 
1173     /// Finalize the assembly and return the result.
1174     fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>;
1175 
1176     /// Zero a particular register.
1177     fn zero(&mut self, reg: WritableReg) -> Result<()>;
1178 
1179     /// Count the number of 1 bits in src and put the result in dst. In x64,
1180     /// this will emit multiple instructions if the `has_popcnt` flag is false.
1181     fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>;
1182 
1183     /// Converts an i64 to an i32 by discarding the high 32 bits.
1184     fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1185 
1186     /// Extends an integer of a given size to a larger size.
1187     fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>;
1188 
1189     /// Emits one or more instructions to perform a signed truncation of a
1190     /// float into an integer.
1191     fn signed_truncate(
1192         &mut self,
1193         dst: WritableReg,
1194         src: Reg,
1195         src_size: OperandSize,
1196         dst_size: OperandSize,
1197         kind: TruncKind,
1198     ) -> Result<()>;
1199 
1200     /// Emits one or more instructions to perform an unsigned truncation of a
1201     /// float into an integer.
1202     fn unsigned_truncate(
1203         &mut self,
1204         context: &mut CodeGenContext<Emission>,
1205         src_size: OperandSize,
1206         dst_size: OperandSize,
1207         kind: TruncKind,
1208     ) -> Result<()>;
1209 
1210     /// Emits one or more instructions to perform a signed convert of an
1211     /// integer into a float.
1212     fn signed_convert(
1213         &mut self,
1214         dst: WritableReg,
1215         src: Reg,
1216         src_size: OperandSize,
1217         dst_size: OperandSize,
1218     ) -> Result<()>;
1219 
1220     /// Emits one or more instructions to perform an unsigned convert of an
1221     /// integer into a float.
1222     fn unsigned_convert(
1223         &mut self,
1224         dst: WritableReg,
1225         src: Reg,
1226         tmp_gpr: Reg,
1227         src_size: OperandSize,
1228         dst_size: OperandSize,
1229     ) -> Result<()>;
1230 
1231     /// Reinterpret a float as an integer.
1232     fn reinterpret_float_as_int(
1233         &mut self,
1234         dst: WritableReg,
1235         src: Reg,
1236         size: OperandSize,
1237     ) -> Result<()>;
1238 
1239     /// Reinterpret an integer as a float.
1240     fn reinterpret_int_as_float(
1241         &mut self,
1242         dst: WritableReg,
1243         src: Reg,
1244         size: OperandSize,
1245     ) -> Result<()>;
1246 
1247     /// Demote an f64 to an f32.
1248     fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1249 
1250     /// Promote an f32 to an f64.
1251     fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1252 
1253     /// Zero a given memory range.
1254     ///
1255     /// The default implementation divides the given memory range
1256     /// into word-sized slots. Then it unrolls a series of store
1257     /// instructions, effectively assigning zero to each slot.
1258     fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> {
1259         let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32;
1260         if mem.is_empty() {
1261             return Ok(());
1262         }
1263 
1264         let start = if mem.start % word_size == 0 {
1265             mem.start
1266         } else {
1267             // Ensure that the start of the range is at least 4-byte aligned.
1268             assert!(mem.start % 4 == 0);
1269             let start = align_to(mem.start, word_size);
1270             let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?;
1271             self.store(RegImm::i32(0), addr, OperandSize::S32)?;
1272             // Ensure that the new start of the range, is word-size aligned.
1273             assert!(start % word_size == 0);
1274             start
1275         };
1276 
1277         let end = align_to(mem.end, word_size);
1278         let slots = (end - start) / word_size;
1279 
1280         if slots == 1 {
1281             let slot = LocalSlot::i64(start + word_size);
1282             let addr: Self::Address = self.local_address(&slot)?;
1283             self.store(RegImm::i64(0), addr, OperandSize::S64)?;
1284         } else {
1285             // TODO
1286             // Add an upper bound to this generation;
1287             // given a considerably large amount of slots
1288             // this will be inefficient.
1289             let zero = scratch!(Self);
1290             self.zero(writable!(zero))?;
1291             let zero = RegImm::reg(zero);
1292 
1293             for step in (start..end).into_iter().step_by(word_size as usize) {
1294                 let slot = LocalSlot::i64(step + word_size);
1295                 let addr: Self::Address = self.local_address(&slot)?;
1296                 self.store(zero, addr, OperandSize::S64)?;
1297             }
1298         }
1299 
1300         Ok(())
1301     }
1302 
1303     /// Generate a label.
1304     fn get_label(&mut self) -> Result<MachLabel>;
1305 
1306     /// Bind the given label at the current code offset.
1307     fn bind(&mut self, label: MachLabel) -> Result<()>;
1308 
1309     /// Conditional branch.
1310     ///
1311     /// Performs a comparison between the two operands,
1312     /// and immediately after emits a jump to the given
1313     /// label destination if the condition is met.
1314     fn branch(
1315         &mut self,
1316         kind: IntCmpKind,
1317         lhs: Reg,
1318         rhs: RegImm,
1319         taken: MachLabel,
1320         size: OperandSize,
1321     ) -> Result<()>;
1322 
1323     /// Emits and unconditional jump to the given label.
1324     fn jmp(&mut self, target: MachLabel) -> Result<()>;
1325 
1326     /// Emits a jump table sequence. The default label is specified as
1327     /// the last element of the targets slice.
1328     fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>;
1329 
1330     /// Emit an unreachable code trap.
1331     fn unreachable(&mut self) -> Result<()>;
1332 
1333     /// Emit an unconditional trap.
1334     fn trap(&mut self, code: TrapCode) -> Result<()>;
1335 
1336     /// Traps if the condition code is met.
1337     fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>;
1338 
1339     /// Trap if the source register is zero.
1340     fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>;
1341 
1342     /// Ensures that the stack pointer is correctly positioned before an unconditional
1343     /// jump according to the requirements of the destination target.
1344     fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> {
1345         let bytes = self
1346             .sp_offset()?
1347             .as_u32()
1348             .checked_sub(target.as_u32())
1349             .unwrap_or(0);
1350 
1351         if bytes > 0 {
1352             self.free_stack(bytes)?;
1353         }
1354 
1355         Ok(())
1356     }
1357 
1358     /// Mark the start of a source location returning the machine code offset
1359     /// and the relative source code location.
1360     fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>;
1361 
1362     /// Mark the end of a source location.
1363     fn end_source_loc(&mut self) -> Result<()>;
1364 
1365     /// The current offset, in bytes from the beginning of the function.
1366     fn current_code_offset(&self) -> Result<CodeOffset>;
1367 
1368     /// Performs a 128-bit addition
1369     fn add128(
1370         &mut self,
1371         dst_lo: WritableReg,
1372         dst_hi: WritableReg,
1373         lhs_lo: Reg,
1374         lhs_hi: Reg,
1375         rhs_lo: Reg,
1376         rhs_hi: Reg,
1377     ) -> Result<()>;
1378 
1379     /// Performs a 128-bit subtraction
1380     fn sub128(
1381         &mut self,
1382         dst_lo: WritableReg,
1383         dst_hi: WritableReg,
1384         lhs_lo: Reg,
1385         lhs_hi: Reg,
1386         rhs_lo: Reg,
1387         rhs_hi: Reg,
1388     ) -> Result<()>;
1389 
1390     /// Performs a widening multiplication from two 64-bit operands into a
1391     /// 128-bit result.
1392     ///
1393     /// Note that some platforms require special handling of registers in this
1394     /// instruction (e.g. x64) so full access to `CodeGenContext` is provided.
1395     fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind)
1396         -> Result<()>;
1397 
1398     /// Takes the value in a src operand and replicates it across lanes of
1399     /// `size` in a destination result.
1400     fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>;
1401 
1402     /// Performs a shuffle between two 128-bit vectors into a 128-bit result
1403     /// using lanes as a mask to select which indexes to copy.
1404     fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>;
1405 
1406     /// Performs a swizzle between two 128-bit vectors into a 128-bit result.
1407     fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>;
1408 
1409     /// Performs the RMW `op` operation on the passed `addr`.
1410     ///
1411     /// The value *before* the operation was performed is written back to the `operand` register.
1412     fn atomic_rmw(
1413         &mut self,
1414         context: &mut CodeGenContext<Emission>,
1415         addr: Self::Address,
1416         size: OperandSize,
1417         op: RmwOp,
1418         flags: MemFlags,
1419         extend: Option<Extend<Zero>>,
1420     ) -> Result<()>;
1421 
1422     /// Extracts the scalar value from `src` in `lane` to `dst`.
1423     fn extract_lane(
1424         &mut self,
1425         src: Reg,
1426         dst: WritableReg,
1427         lane: u8,
1428         kind: ExtractLaneKind,
1429     ) -> Result<()>;
1430 
1431     /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected`
1432     /// and `replacement` (at the top of the context's stack).
1433     ///
1434     /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that
1435     /// expect parameters in specific registers. The context stack contains the `replacement`,
1436     /// and `expected` values in that order. The implementer is expected to push the value at
1437     /// `addr` before the update to the context's stack before returning.
1438     fn atomic_cas(
1439         &mut self,
1440         context: &mut CodeGenContext<Emission>,
1441         addr: Self::Address,
1442         size: OperandSize,
1443         flags: MemFlags,
1444         extend: Option<Extend<Zero>>,
1445     ) -> Result<()>;
1446 }
1447