xref: /wasmtime-44.0.1/winch/codegen/src/masm.rs (revision cccc4e64)
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 replace lane supported by WebAssembly.
401 pub(crate) enum ReplaceLaneKind {
402     /// 16 lanes of 8 bit integers.
403     I8x16,
404     /// 8 lanes of 16 bit integers.
405     I16x8,
406     /// 4 lanes of 32 bit integers.
407     I32x4,
408     /// 2 lanes of 64 bit integers.
409     I64x2,
410     /// 4 lanes of 32 bit floats.
411     F32x4,
412     /// 2 lanes of 64 bit floats.
413     F64x2,
414 }
415 
416 impl ReplaceLaneKind {
417     /// The lane size to use for different kinds of replace lane kinds.
418     pub(crate) fn lane_size(&self) -> OperandSize {
419         match self {
420             ReplaceLaneKind::I8x16 => OperandSize::S8,
421             ReplaceLaneKind::I16x8 => OperandSize::S16,
422             ReplaceLaneKind::I32x4 => OperandSize::S32,
423             ReplaceLaneKind::I64x2 => OperandSize::S64,
424             ReplaceLaneKind::F32x4 => OperandSize::S32,
425             ReplaceLaneKind::F64x2 => OperandSize::S64,
426         }
427     }
428 }
429 
430 /// Kinds of behavior supported by Wasm loads.
431 pub(crate) enum LoadKind {
432     /// Load the entire bytes of the operand size without any modifications.
433     Operand(OperandSize),
434     /// Duplicate value into vector lanes.
435     Splat(SplatLoadKind),
436     /// Scalar (non-vector) extend.
437     ScalarExtend(ExtendKind),
438     /// Vector extend.
439     VectorExtend(VectorExtendKind),
440 }
441 
442 impl LoadKind {
443     /// Returns the [`OperandSize`] used in the load operation.
444     pub(crate) fn derive_operand_size(&self) -> OperandSize {
445         match self {
446             Self::ScalarExtend(scalar) => Self::operand_size_for_scalar(scalar),
447             Self::VectorExtend(_) => OperandSize::S64,
448             Self::Splat(kind) => Self::operand_size_for_splat(kind),
449             Self::Operand(op) => *op,
450         }
451     }
452 
453     fn operand_size_for_scalar(extend_kind: &ExtendKind) -> OperandSize {
454         match extend_kind {
455             ExtendKind::Signed(s) => s.from_size(),
456             ExtendKind::Unsigned(u) => u.from_size(),
457         }
458     }
459 
460     fn operand_size_for_splat(kind: &SplatLoadKind) -> OperandSize {
461         match kind {
462             SplatLoadKind::S8 => OperandSize::S8,
463             SplatLoadKind::S16 => OperandSize::S16,
464             SplatLoadKind::S32 => OperandSize::S32,
465             SplatLoadKind::S64 => OperandSize::S64,
466         }
467     }
468 }
469 
470 /// Operand size, in bits.
471 #[derive(Copy, Debug, Clone, Eq, PartialEq)]
472 pub(crate) enum OperandSize {
473     /// 8 bits.
474     S8,
475     /// 16 bits.
476     S16,
477     /// 32 bits.
478     S32,
479     /// 64 bits.
480     S64,
481     /// 128 bits.
482     S128,
483 }
484 
485 impl OperandSize {
486     /// The number of bits in the operand.
487     pub fn num_bits(&self) -> u8 {
488         match self {
489             OperandSize::S8 => 8,
490             OperandSize::S16 => 16,
491             OperandSize::S32 => 32,
492             OperandSize::S64 => 64,
493             OperandSize::S128 => 128,
494         }
495     }
496 
497     /// The number of bytes in the operand.
498     pub fn bytes(&self) -> u32 {
499         match self {
500             Self::S8 => 1,
501             Self::S16 => 2,
502             Self::S32 => 4,
503             Self::S64 => 8,
504             Self::S128 => 16,
505         }
506     }
507 
508     /// The binary logarithm of the number of bits in the operand.
509     pub fn log2(&self) -> u8 {
510         match self {
511             OperandSize::S8 => 3,
512             OperandSize::S16 => 4,
513             OperandSize::S32 => 5,
514             OperandSize::S64 => 6,
515             OperandSize::S128 => 7,
516         }
517     }
518 
519     /// Create an [`OperandSize`]  from the given number of bytes.
520     pub fn from_bytes(bytes: u8) -> Self {
521         use OperandSize::*;
522         match bytes {
523             4 => S32,
524             8 => S64,
525             16 => S128,
526             _ => panic!("Invalid bytes {bytes} for OperandSize"),
527         }
528     }
529 
530     pub fn extend_to<T: ExtendType>(&self, to: Self) -> Option<Extend<T>> {
531         match to {
532             OperandSize::S32 => match self {
533                 OperandSize::S8 => Some(Extend::I32Extend8),
534                 OperandSize::S16 => Some(Extend::I32Extend16),
535                 _ => None,
536             },
537             OperandSize::S64 => match self {
538                 OperandSize::S8 => Some(Extend::I64Extend8),
539                 OperandSize::S16 => Some(Extend::I64Extend16),
540                 OperandSize::S32 => Some(Extend::I64Extend32),
541                 _ => None,
542             },
543             _ => None,
544         }
545     }
546 }
547 
548 /// An abstraction over a register or immediate.
549 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
550 pub(crate) enum RegImm {
551     /// A register.
552     Reg(Reg),
553     /// A tagged immediate argument.
554     Imm(Imm),
555 }
556 
557 /// An tagged representation of an immediate.
558 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
559 pub(crate) enum Imm {
560     /// I32 immediate.
561     I32(u32),
562     /// I64 immediate.
563     I64(u64),
564     /// F32 immediate.
565     F32(u32),
566     /// F64 immediate.
567     F64(u64),
568     /// V128 immediate.
569     V128(i128),
570 }
571 
572 impl Imm {
573     /// Create a new I64 immediate.
574     pub fn i64(val: i64) -> Self {
575         Self::I64(val as u64)
576     }
577 
578     /// Create a new I32 immediate.
579     pub fn i32(val: i32) -> Self {
580         Self::I32(val as u32)
581     }
582 
583     /// Create a new F32 immediate.
584     pub fn f32(bits: u32) -> Self {
585         Self::F32(bits)
586     }
587 
588     /// Create a new F64 immediate.
589     pub fn f64(bits: u64) -> Self {
590         Self::F64(bits)
591     }
592 
593     /// Create a new V128 immediate.
594     pub fn v128(bits: i128) -> Self {
595         Self::V128(bits)
596     }
597 
598     /// Convert the immediate to i32, if possible.
599     pub fn to_i32(&self) -> Option<i32> {
600         match self {
601             Self::I32(v) => Some(*v as i32),
602             Self::I64(v) => i32::try_from(*v as i64).ok(),
603             _ => None,
604         }
605     }
606 
607     /// Returns true if the [`Imm`] is float.
608     pub fn is_float(&self) -> bool {
609         match self {
610             Self::F32(_) | Self::F64(_) => true,
611             _ => false,
612         }
613     }
614 
615     /// Get the operand size of the immediate.
616     pub fn size(&self) -> OperandSize {
617         match self {
618             Self::I32(_) | Self::F32(_) => OperandSize::S32,
619             Self::I64(_) | Self::F64(_) => OperandSize::S64,
620             Self::V128(_) => OperandSize::S128,
621         }
622     }
623 
624     /// Get a little endian representation of the immediate.
625     ///
626     /// This method heap allocates and is intended to be used when adding
627     /// values to the constant pool.
628     pub fn to_bytes(&self) -> Vec<u8> {
629         match self {
630             Imm::I32(n) => n.to_le_bytes().to_vec(),
631             Imm::I64(n) => n.to_le_bytes().to_vec(),
632             Imm::F32(n) => n.to_le_bytes().to_vec(),
633             Imm::F64(n) => n.to_le_bytes().to_vec(),
634             Imm::V128(n) => n.to_le_bytes().to_vec(),
635         }
636     }
637 }
638 
639 /// The location of the [VMcontext] used for function calls.
640 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
641 pub(crate) enum VMContextLoc {
642     /// Dynamic, stored in the given register.
643     Reg(Reg),
644     /// The pinned [VMContext] register.
645     Pinned,
646 }
647 
648 /// The maximum number of context arguments currently used across the compiler.
649 pub(crate) const MAX_CONTEXT_ARGS: usize = 2;
650 
651 /// Out-of-band special purpose arguments used for function call emission.
652 ///
653 /// We cannot rely on the value stack for these values given that inserting
654 /// register or memory values at arbitrary locations of the value stack has the
655 /// potential to break the stack ordering principle, which states that older
656 /// values must always precede newer values, effectively simulating the order of
657 /// values in the machine stack.
658 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases
659 /// it might be possible to construct it early on, but given that it might
660 /// contain allocatable registers, it's preferred to construct it in
661 /// [FnCall::emit].
662 #[derive(Clone, Debug)]
663 pub(crate) enum ContextArgs {
664     /// No context arguments required. This is used for libcalls that don't
665     /// require any special context arguments. For example builtin functions
666     /// that perform float calculations.
667     None,
668     /// A single context argument is required; the current pinned [VMcontext]
669     /// register must be passed as the first argument of the function call.
670     VMContext([VMContextLoc; 1]),
671     /// The callee and caller context arguments are required. In this case, the
672     /// callee context argument is usually stored into an allocatable register
673     /// and the caller is always the current pinned [VMContext] pointer.
674     CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]),
675 }
676 
677 impl ContextArgs {
678     /// Construct an empty [ContextArgs].
679     pub fn none() -> Self {
680         Self::None
681     }
682 
683     /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext]
684     /// register as both the caller and callee context arguments.
685     pub fn pinned_callee_and_caller_vmctx() -> Self {
686         Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned])
687     }
688 
689     /// Construct a [ContextArgs] that declares the usage of the pinned
690     /// [VMContext] register as the only context argument.
691     pub fn pinned_vmctx() -> Self {
692         Self::VMContext([VMContextLoc::Pinned])
693     }
694 
695     /// Construct a [ContextArgs] that declares a dynamic callee context and the
696     /// pinned [VMContext] register as the context arguments.
697     pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self {
698         Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned])
699     }
700 
701     /// Get the length of the [ContextArgs].
702     pub fn len(&self) -> usize {
703         self.as_slice().len()
704     }
705 
706     /// Get a slice of the context arguments.
707     pub fn as_slice(&self) -> &[VMContextLoc] {
708         match self {
709             Self::None => &[],
710             Self::VMContext(a) => a.as_slice(),
711             Self::CalleeAndCallerVMContext(a) => a.as_slice(),
712         }
713     }
714 }
715 
716 #[derive(Copy, Clone, Debug)]
717 pub(crate) enum CalleeKind {
718     /// A function call to a raw address.
719     Indirect(Reg),
720     /// A function call to a local function.
721     Direct(UserExternalNameRef),
722     /// Call to a well known LibCall.
723     LibCall(LibCall),
724 }
725 
726 impl CalleeKind {
727     /// Creates a callee kind from a register.
728     pub fn indirect(reg: Reg) -> Self {
729         Self::Indirect(reg)
730     }
731 
732     /// Creates a direct callee kind from a function name.
733     pub fn direct(name: UserExternalNameRef) -> Self {
734         Self::Direct(name)
735     }
736 
737     /// Creates a known callee kind from a libcall.
738     pub fn libcall(call: LibCall) -> Self {
739         Self::LibCall(call)
740     }
741 }
742 
743 impl RegImm {
744     /// Register constructor.
745     pub fn reg(r: Reg) -> Self {
746         RegImm::Reg(r)
747     }
748 
749     /// I64 immediate constructor.
750     pub fn i64(val: i64) -> Self {
751         RegImm::Imm(Imm::i64(val))
752     }
753 
754     /// I32 immediate constructor.
755     pub fn i32(val: i32) -> Self {
756         RegImm::Imm(Imm::i32(val))
757     }
758 
759     /// F32 immediate, stored using its bits representation.
760     pub fn f32(bits: u32) -> Self {
761         RegImm::Imm(Imm::f32(bits))
762     }
763 
764     /// F64 immediate, stored using its bits representation.
765     pub fn f64(bits: u64) -> Self {
766         RegImm::Imm(Imm::f64(bits))
767     }
768 
769     /// V128 immediate.
770     pub fn v128(bits: i128) -> Self {
771         RegImm::Imm(Imm::v128(bits))
772     }
773 }
774 
775 impl From<Reg> for RegImm {
776     fn from(r: Reg) -> Self {
777         Self::Reg(r)
778     }
779 }
780 
781 #[derive(Debug)]
782 pub enum RoundingMode {
783     Nearest,
784     Up,
785     Down,
786     Zero,
787 }
788 
789 /// Memory flags for trusted loads/stores.
790 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted();
791 
792 /// Flags used for WebAssembly loads / stores.
793 /// Untrusted by default so we don't set `no_trap`.
794 /// We also ensure that the endianness is the right one for WebAssembly.
795 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little);
796 
797 /// Generic MacroAssembler interface used by the code generation.
798 ///
799 /// The MacroAssembler trait aims to expose an interface, high-level enough,
800 /// so that each ISA can provide its own lowering to machine code. For example,
801 /// for WebAssembly operators that don't have a direct mapping to a machine
802 /// a instruction, the interface defines a signature matching the WebAssembly
803 /// operator, allowing each implementation to lower such operator entirely.
804 /// This approach attributes more responsibility to the MacroAssembler, but frees
805 /// the caller from concerning about assembling the right sequence of
806 /// instructions at the operator callsite.
807 ///
808 /// The interface defaults to a three-argument form for binary operations;
809 /// this allows a natural mapping to instructions for RISC architectures,
810 /// that use three-argument form.
811 /// This approach allows for a more general interface that can be restricted
812 /// where needed, in the case of architectures that use a two-argument form.
813 
814 pub(crate) trait MacroAssembler {
815     /// The addressing mode.
816     type Address: Copy + Debug;
817 
818     /// The pointer representation of the target ISA,
819     /// used to access information from [`VMOffsets`].
820     type Ptr: PtrSize;
821 
822     /// The ABI details of the target.
823     type ABI: abi::ABI;
824 
825     /// Emit the function prologue.
826     fn prologue(&mut self, vmctx: Reg) -> Result<()> {
827         self.frame_setup()?;
828         self.check_stack(vmctx)
829     }
830 
831     /// Generate the frame setup sequence.
832     fn frame_setup(&mut self) -> Result<()>;
833 
834     /// Generate the frame restore sequence.
835     fn frame_restore(&mut self) -> Result<()>;
836 
837     /// Emit a stack check.
838     fn check_stack(&mut self, vmctx: Reg) -> Result<()>;
839 
840     /// Emit the function epilogue.
841     fn epilogue(&mut self) -> Result<()> {
842         self.frame_restore()
843     }
844 
845     /// Reserve stack space.
846     fn reserve_stack(&mut self, bytes: u32) -> Result<()>;
847 
848     /// Free stack space.
849     fn free_stack(&mut self, bytes: u32) -> Result<()>;
850 
851     /// Reset the stack pointer to the given offset;
852     ///
853     /// Used to reset the stack pointer to a given offset
854     /// when dealing with unreachable code.
855     fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>;
856 
857     /// Get the address of a local slot.
858     fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>;
859 
860     /// Constructs an address with an offset that is relative to the
861     /// current position of the stack pointer (e.g. [sp + (sp_offset -
862     /// offset)].
863     fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>;
864 
865     /// Constructs an address with an offset that is absolute to the
866     /// current position of the stack pointer (e.g. [sp + offset].
867     fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>;
868 
869     /// Alias for [`Self::address_at_reg`] using the VMContext register as
870     /// a base. The VMContext register is derived from the ABI type that is
871     /// associated to the MacroAssembler.
872     fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>;
873 
874     /// Construct an address that is absolute to the current position
875     /// of the given register.
876     fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>;
877 
878     /// Emit a function call to either a local or external function.
879     fn call(
880         &mut self,
881         stack_args_size: u32,
882         f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>,
883     ) -> Result<u32>;
884 
885     /// Get stack pointer offset.
886     fn sp_offset(&self) -> Result<SPOffset>;
887 
888     /// Perform a stack store.
889     fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>;
890 
891     /// Alias for `MacroAssembler::store` with the operand size corresponding
892     /// to the pointer size of the target.
893     fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>;
894 
895     /// Perform a WebAssembly store.
896     /// A WebAssembly store introduces several additional invariants compared to
897     /// [Self::store], more precisely, it can implicitly trap, in certain
898     /// circumstances, even if explicit bounds checks are elided, in that sense,
899     /// we consider this type of load as untrusted. It can also differ with
900     /// regards to the endianness depending on the target ISA. For this reason,
901     /// [Self::wasm_store], should be explicitly used when emitting WebAssembly
902     /// stores.
903     fn wasm_store(
904         &mut self,
905         src: Reg,
906         dst: Self::Address,
907         size: OperandSize,
908         op_kind: MemOpKind,
909     ) -> Result<()>;
910 
911     /// Perform a zero-extended stack load.
912     fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>;
913 
914     /// Perform a WebAssembly load.
915     /// A WebAssembly load introduces several additional invariants compared to
916     /// [Self::load], more precisely, it can implicitly trap, in certain
917     /// circumstances, even if explicit bounds checks are elided, in that sense,
918     /// we consider this type of load as untrusted. It can also differ with
919     /// regards to the endianness depending on the target ISA. For this reason,
920     /// [Self::wasm_load], should be explicitly used when emitting WebAssembly
921     /// loads.
922     fn wasm_load(
923         &mut self,
924         src: Self::Address,
925         dst: WritableReg,
926         kind: LoadKind,
927         op_kind: MemOpKind,
928     ) -> Result<()>;
929 
930     /// Alias for `MacroAssembler::load` with the operand size corresponding
931     /// to the pointer size of the target.
932     fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>;
933 
934     /// Loads the effective address into destination.
935     fn load_addr(
936         &mut self,
937         _src: Self::Address,
938         _dst: WritableReg,
939         _size: OperandSize,
940     ) -> Result<()>;
941 
942     /// Pop a value from the machine stack into the given register.
943     fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
944 
945     /// Perform a move.
946     fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>;
947 
948     /// Perform a conditional move.
949     fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize)
950         -> Result<()>;
951 
952     /// Performs a memory move of bytes from src to dest.
953     /// Bytes are moved in blocks of 8 bytes, where possible.
954     fn memmove(
955         &mut self,
956         src: SPOffset,
957         dst: SPOffset,
958         bytes: u32,
959         direction: MemMoveDirection,
960     ) -> Result<()> {
961         match direction {
962             MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()),
963             MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()),
964         }
965         // At least 4 byte aligned.
966         debug_assert!(bytes % 4 == 0);
967         let mut remaining = bytes;
968         let word_bytes = <Self::ABI as abi::ABI>::word_bytes();
969         let scratch = scratch!(Self);
970 
971         let mut dst_offs = dst.as_u32() - bytes;
972         let mut src_offs = src.as_u32() - bytes;
973 
974         let word_bytes = word_bytes as u32;
975         while remaining >= word_bytes {
976             remaining -= word_bytes;
977             dst_offs += word_bytes;
978             src_offs += word_bytes;
979 
980             self.load_ptr(
981                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
982                 writable!(scratch),
983             )?;
984             self.store_ptr(
985                 scratch.into(),
986                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
987             )?;
988         }
989 
990         if remaining > 0 {
991             let half_word = word_bytes / 2;
992             let ptr_size = OperandSize::from_bytes(half_word as u8);
993             debug_assert!(remaining == half_word);
994             dst_offs += half_word;
995             src_offs += half_word;
996 
997             self.load(
998                 self.address_from_sp(SPOffset::from_u32(src_offs))?,
999                 writable!(scratch),
1000                 ptr_size,
1001             )?;
1002             self.store(
1003                 scratch.into(),
1004                 self.address_from_sp(SPOffset::from_u32(dst_offs))?,
1005                 ptr_size,
1006             )?;
1007         }
1008         Ok(())
1009     }
1010 
1011     /// Perform add operation.
1012     fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1013 
1014     /// Perform a checked unsigned integer addition, emitting the provided trap
1015     /// if the addition overflows.
1016     fn checked_uadd(
1017         &mut self,
1018         dst: WritableReg,
1019         lhs: Reg,
1020         rhs: RegImm,
1021         size: OperandSize,
1022         trap: TrapCode,
1023     ) -> Result<()>;
1024 
1025     /// Perform subtraction operation.
1026     fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1027 
1028     /// Perform multiplication operation.
1029     fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1030 
1031     /// Perform a floating point add operation.
1032     fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1033 
1034     /// Perform a floating point subtraction operation.
1035     fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1036 
1037     /// Perform a floating point multiply operation.
1038     fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1039 
1040     /// Perform a floating point divide operation.
1041     fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1042 
1043     /// Perform a floating point minimum operation. In x86, this will emit
1044     /// multiple instructions.
1045     fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1046 
1047     /// Perform a floating point maximum operation. In x86, this will emit
1048     /// multiple instructions.
1049     fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>;
1050 
1051     /// Perform a floating point copysign operation. In x86, this will emit
1052     /// multiple instructions.
1053     fn float_copysign(
1054         &mut self,
1055         dst: WritableReg,
1056         lhs: Reg,
1057         rhs: Reg,
1058         size: OperandSize,
1059     ) -> Result<()>;
1060 
1061     /// Perform a floating point abs operation.
1062     fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1063 
1064     /// Perform a floating point negation operation.
1065     fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>;
1066 
1067     /// Perform a floating point floor operation.
1068     fn float_round<
1069         F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>,
1070     >(
1071         &mut self,
1072         mode: RoundingMode,
1073         env: &mut FuncEnv<Self::Ptr>,
1074         context: &mut CodeGenContext<Emission>,
1075         size: OperandSize,
1076         fallback: F,
1077     ) -> Result<()>;
1078 
1079     /// Perform a floating point square root operation.
1080     fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1081 
1082     /// Perform logical and operation.
1083     fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1084 
1085     /// Perform logical or operation.
1086     fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1087 
1088     /// Perform logical exclusive or operation.
1089     fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>;
1090 
1091     /// Perform a shift operation between a register and an immediate.
1092     fn shift_ir(
1093         &mut self,
1094         dst: WritableReg,
1095         imm: u64,
1096         lhs: Reg,
1097         kind: ShiftKind,
1098         size: OperandSize,
1099     ) -> Result<()>;
1100 
1101     /// Perform a shift operation between two registers.
1102     /// This case is special in that some architectures have specific expectations
1103     /// regarding the location of the instruction arguments. To free the
1104     /// caller from having to deal with the architecture specific constraints
1105     /// we give this function access to the code generation context, allowing
1106     /// each implementation to decide the lowering path.
1107     fn shift(
1108         &mut self,
1109         context: &mut CodeGenContext<Emission>,
1110         kind: ShiftKind,
1111         size: OperandSize,
1112     ) -> Result<()>;
1113 
1114     /// Perform division operation.
1115     /// Division is special in that some architectures have specific
1116     /// expectations regarding the location of the instruction
1117     /// arguments and regarding the location of the quotient /
1118     /// remainder. To free the caller from having to deal with the
1119     /// architecture specific constraints we give this function access
1120     /// to the code generation context, allowing each implementation
1121     /// to decide the lowering path.  For cases in which division is a
1122     /// unconstrained binary operation, the caller can decide to use
1123     /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop`
1124     /// functions.
1125     fn div(
1126         &mut self,
1127         context: &mut CodeGenContext<Emission>,
1128         kind: DivKind,
1129         size: OperandSize,
1130     ) -> Result<()>;
1131 
1132     /// Calculate remainder.
1133     fn rem(
1134         &mut self,
1135         context: &mut CodeGenContext<Emission>,
1136         kind: RemKind,
1137         size: OperandSize,
1138     ) -> Result<()>;
1139 
1140     /// Compares `src1` against `src2` for the side effect of setting processor
1141     /// flags.
1142     ///
1143     /// Note that `src1` is the left-hand-side of the comparison and `src2` is
1144     /// the right-hand-side, so if testing `a < b` then `src1 == a` and
1145     /// `src2 == b`
1146     fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>;
1147 
1148     /// Compare src and dst and put the result in dst.
1149     /// This function will potentially emit a series of instructions.
1150     ///
1151     /// The initial value in `dst` is the left-hand-side of the comparison and
1152     /// the initial value in `src` is the right-hand-side of the comparison.
1153     /// That means for `a < b` then `dst == a` and `src == b`.
1154     fn cmp_with_set(
1155         &mut self,
1156         dst: WritableReg,
1157         src: RegImm,
1158         kind: IntCmpKind,
1159         size: OperandSize,
1160     ) -> Result<()>;
1161 
1162     /// Compare floats in src1 and src2 and put the result in dst.
1163     /// In x86, this will emit multiple instructions.
1164     fn float_cmp_with_set(
1165         &mut self,
1166         dst: WritableReg,
1167         src1: Reg,
1168         src2: Reg,
1169         kind: FloatCmpKind,
1170         size: OperandSize,
1171     ) -> Result<()>;
1172 
1173     /// Count the number of leading zeroes in src and put the result in dst.
1174     /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is
1175     /// false.
1176     fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1177 
1178     /// Count the number of trailing zeroes in src and put the result in dst.masm
1179     /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is
1180     /// false.
1181     fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>;
1182 
1183     /// Push the register to the stack, returning the stack slot metadata.
1184     // NB
1185     // The stack alignment should not be assumed after any call to `push`,
1186     // unless explicitly aligned otherwise.  Typically, stack alignment is
1187     // maintained at call sites and during the execution of
1188     // epilogues.
1189     fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>;
1190 
1191     /// Finalize the assembly and return the result.
1192     fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>;
1193 
1194     /// Zero a particular register.
1195     fn zero(&mut self, reg: WritableReg) -> Result<()>;
1196 
1197     /// Count the number of 1 bits in src and put the result in dst. In x64,
1198     /// this will emit multiple instructions if the `has_popcnt` flag is false.
1199     fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>;
1200 
1201     /// Converts an i64 to an i32 by discarding the high 32 bits.
1202     fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1203 
1204     /// Extends an integer of a given size to a larger size.
1205     fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>;
1206 
1207     /// Emits one or more instructions to perform a signed truncation of a
1208     /// float into an integer.
1209     fn signed_truncate(
1210         &mut self,
1211         dst: WritableReg,
1212         src: Reg,
1213         src_size: OperandSize,
1214         dst_size: OperandSize,
1215         kind: TruncKind,
1216     ) -> Result<()>;
1217 
1218     /// Emits one or more instructions to perform an unsigned truncation of a
1219     /// float into an integer.
1220     fn unsigned_truncate(
1221         &mut self,
1222         context: &mut CodeGenContext<Emission>,
1223         src_size: OperandSize,
1224         dst_size: OperandSize,
1225         kind: TruncKind,
1226     ) -> Result<()>;
1227 
1228     /// Emits one or more instructions to perform a signed convert of an
1229     /// integer into a float.
1230     fn signed_convert(
1231         &mut self,
1232         dst: WritableReg,
1233         src: Reg,
1234         src_size: OperandSize,
1235         dst_size: OperandSize,
1236     ) -> Result<()>;
1237 
1238     /// Emits one or more instructions to perform an unsigned convert of an
1239     /// integer into a float.
1240     fn unsigned_convert(
1241         &mut self,
1242         dst: WritableReg,
1243         src: Reg,
1244         tmp_gpr: Reg,
1245         src_size: OperandSize,
1246         dst_size: OperandSize,
1247     ) -> Result<()>;
1248 
1249     /// Reinterpret a float as an integer.
1250     fn reinterpret_float_as_int(
1251         &mut self,
1252         dst: WritableReg,
1253         src: Reg,
1254         size: OperandSize,
1255     ) -> Result<()>;
1256 
1257     /// Reinterpret an integer as a float.
1258     fn reinterpret_int_as_float(
1259         &mut self,
1260         dst: WritableReg,
1261         src: Reg,
1262         size: OperandSize,
1263     ) -> Result<()>;
1264 
1265     /// Demote an f64 to an f32.
1266     fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1267 
1268     /// Promote an f32 to an f64.
1269     fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>;
1270 
1271     /// Zero a given memory range.
1272     ///
1273     /// The default implementation divides the given memory range
1274     /// into word-sized slots. Then it unrolls a series of store
1275     /// instructions, effectively assigning zero to each slot.
1276     fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> {
1277         let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32;
1278         if mem.is_empty() {
1279             return Ok(());
1280         }
1281 
1282         let start = if mem.start % word_size == 0 {
1283             mem.start
1284         } else {
1285             // Ensure that the start of the range is at least 4-byte aligned.
1286             assert!(mem.start % 4 == 0);
1287             let start = align_to(mem.start, word_size);
1288             let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?;
1289             self.store(RegImm::i32(0), addr, OperandSize::S32)?;
1290             // Ensure that the new start of the range, is word-size aligned.
1291             assert!(start % word_size == 0);
1292             start
1293         };
1294 
1295         let end = align_to(mem.end, word_size);
1296         let slots = (end - start) / word_size;
1297 
1298         if slots == 1 {
1299             let slot = LocalSlot::i64(start + word_size);
1300             let addr: Self::Address = self.local_address(&slot)?;
1301             self.store(RegImm::i64(0), addr, OperandSize::S64)?;
1302         } else {
1303             // TODO
1304             // Add an upper bound to this generation;
1305             // given a considerably large amount of slots
1306             // this will be inefficient.
1307             let zero = scratch!(Self);
1308             self.zero(writable!(zero))?;
1309             let zero = RegImm::reg(zero);
1310 
1311             for step in (start..end).into_iter().step_by(word_size as usize) {
1312                 let slot = LocalSlot::i64(step + word_size);
1313                 let addr: Self::Address = self.local_address(&slot)?;
1314                 self.store(zero, addr, OperandSize::S64)?;
1315             }
1316         }
1317 
1318         Ok(())
1319     }
1320 
1321     /// Generate a label.
1322     fn get_label(&mut self) -> Result<MachLabel>;
1323 
1324     /// Bind the given label at the current code offset.
1325     fn bind(&mut self, label: MachLabel) -> Result<()>;
1326 
1327     /// Conditional branch.
1328     ///
1329     /// Performs a comparison between the two operands,
1330     /// and immediately after emits a jump to the given
1331     /// label destination if the condition is met.
1332     fn branch(
1333         &mut self,
1334         kind: IntCmpKind,
1335         lhs: Reg,
1336         rhs: RegImm,
1337         taken: MachLabel,
1338         size: OperandSize,
1339     ) -> Result<()>;
1340 
1341     /// Emits and unconditional jump to the given label.
1342     fn jmp(&mut self, target: MachLabel) -> Result<()>;
1343 
1344     /// Emits a jump table sequence. The default label is specified as
1345     /// the last element of the targets slice.
1346     fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>;
1347 
1348     /// Emit an unreachable code trap.
1349     fn unreachable(&mut self) -> Result<()>;
1350 
1351     /// Emit an unconditional trap.
1352     fn trap(&mut self, code: TrapCode) -> Result<()>;
1353 
1354     /// Traps if the condition code is met.
1355     fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>;
1356 
1357     /// Trap if the source register is zero.
1358     fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>;
1359 
1360     /// Ensures that the stack pointer is correctly positioned before an unconditional
1361     /// jump according to the requirements of the destination target.
1362     fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> {
1363         let bytes = self
1364             .sp_offset()?
1365             .as_u32()
1366             .checked_sub(target.as_u32())
1367             .unwrap_or(0);
1368 
1369         if bytes > 0 {
1370             self.free_stack(bytes)?;
1371         }
1372 
1373         Ok(())
1374     }
1375 
1376     /// Mark the start of a source location returning the machine code offset
1377     /// and the relative source code location.
1378     fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>;
1379 
1380     /// Mark the end of a source location.
1381     fn end_source_loc(&mut self) -> Result<()>;
1382 
1383     /// The current offset, in bytes from the beginning of the function.
1384     fn current_code_offset(&self) -> Result<CodeOffset>;
1385 
1386     /// Performs a 128-bit addition
1387     fn add128(
1388         &mut self,
1389         dst_lo: WritableReg,
1390         dst_hi: WritableReg,
1391         lhs_lo: Reg,
1392         lhs_hi: Reg,
1393         rhs_lo: Reg,
1394         rhs_hi: Reg,
1395     ) -> Result<()>;
1396 
1397     /// Performs a 128-bit subtraction
1398     fn sub128(
1399         &mut self,
1400         dst_lo: WritableReg,
1401         dst_hi: WritableReg,
1402         lhs_lo: Reg,
1403         lhs_hi: Reg,
1404         rhs_lo: Reg,
1405         rhs_hi: Reg,
1406     ) -> Result<()>;
1407 
1408     /// Performs a widening multiplication from two 64-bit operands into a
1409     /// 128-bit result.
1410     ///
1411     /// Note that some platforms require special handling of registers in this
1412     /// instruction (e.g. x64) so full access to `CodeGenContext` is provided.
1413     fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind)
1414         -> Result<()>;
1415 
1416     /// Takes the value in a src operand and replicates it across lanes of
1417     /// `size` in a destination result.
1418     fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>;
1419 
1420     /// Performs a shuffle between two 128-bit vectors into a 128-bit result
1421     /// using lanes as a mask to select which indexes to copy.
1422     fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>;
1423 
1424     /// Performs a swizzle between two 128-bit vectors into a 128-bit result.
1425     fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>;
1426 
1427     /// Performs the RMW `op` operation on the passed `addr`.
1428     ///
1429     /// The value *before* the operation was performed is written back to the `operand` register.
1430     fn atomic_rmw(
1431         &mut self,
1432         context: &mut CodeGenContext<Emission>,
1433         addr: Self::Address,
1434         size: OperandSize,
1435         op: RmwOp,
1436         flags: MemFlags,
1437         extend: Option<Extend<Zero>>,
1438     ) -> Result<()>;
1439 
1440     /// Extracts the scalar value from `src` in `lane` to `dst`.
1441     fn extract_lane(
1442         &mut self,
1443         src: Reg,
1444         dst: WritableReg,
1445         lane: u8,
1446         kind: ExtractLaneKind,
1447     ) -> Result<()>;
1448 
1449     /// Replaces the value in `lane` in `dst` with the value in `src`.
1450     fn replace_lane(
1451         &mut self,
1452         src: RegImm,
1453         dst: WritableReg,
1454         lane: u8,
1455         kind: ReplaceLaneKind,
1456     ) -> Result<()>;
1457 
1458     /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected`
1459     /// and `replacement` (at the top of the context's stack).
1460     ///
1461     /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that
1462     /// expect parameters in specific registers. The context stack contains the `replacement`,
1463     /// and `expected` values in that order. The implementer is expected to push the value at
1464     /// `addr` before the update to the context's stack before returning.
1465     fn atomic_cas(
1466         &mut self,
1467         context: &mut CodeGenContext<Emission>,
1468         addr: Self::Address,
1469         size: OperandSize,
1470         flags: MemFlags,
1471         extend: Option<Extend<Zero>>,
1472     ) -> Result<()>;
1473 
1474     /// Emit a memory fence.
1475     fn fence(&mut self) -> Result<()>;
1476 }
1477