xref: /wasmtime-44.0.1/winch/codegen/src/abi/mod.rs (revision 25e3bd12)
1 //!
2 //! The Default ABI
3 //!
4 //! Winch uses a default ABI, for all internal functions. This allows
5 //! us to push the complexity of system ABI compliance to the trampolines.  The
6 //! default ABI treats all allocatable registers as caller saved, which means
7 //! that (i) all register values in the Wasm value stack (which are normally
8 //! referred to as "live"), must be saved onto the machine stack (ii) function
9 //! prologues and epilogues don't store/restore other registers more than the
10 //! non-allocatable ones (e.g. rsp/rbp in x86_64).
11 //!
12 //! The calling convention in the default ABI, uses registers to a certain fixed
13 //! count for arguments and return values, and then the stack is used for all
14 //! additional arguments and return values. Aside from the parameters declared
15 //! in each WebAssembly function, Winch's ABI declares two extra parameters, to
16 //! hold the callee and caller `VMContext` pointers. A well-known `LocalSlot` is
17 //! reserved for the callee VMContext pointer and also a particular pinned
18 //! register is used to hold the value of the callee `VMContext`, which is
19 //! available throughout the lifetime of the function.
20 //!
21 //!
22 //! Generally the stack layout looks like:
23 //! +-------------------------------+
24 //! |                               |
25 //! |                               |
26 //! |         Stack Args            |
27 //! |                               |
28 //! |                               |
29 //! +-------------------------------+----> SP @ function entry
30 //! |         Ret addr              |
31 //! +-------------------------------+
32 //! |            SP                 |
33 //! +-------------------------------+----> SP @ Function prologue
34 //! |                               |
35 //! +-------------------------------+----> VMContext slot
36 //! |                               |
37 //! |                               |
38 //! |        Stack slots            |
39 //! |        + dynamic space        |
40 //! |                               |
41 //! |                               |
42 //! |                               |
43 //! +-------------------------------+----> SP @ callsite (after)
44 //! |        alignment              |
45 //! |        + arguments            |
46 //! |                               | ----> Space allocated for calls
47 //! |                               |
48 use crate::Result;
49 use crate::codegen::ptr_type_from_ptr_size;
50 use crate::isa::{CallingConvention, reg::Reg};
51 use crate::masm::SPOffset;
52 use smallvec::SmallVec;
53 use std::collections::HashSet;
54 use std::ops::{Add, BitAnd, Not, Sub};
55 use wasmtime_environ::{WasmFuncType, WasmValType};
56 
57 pub(crate) mod local;
58 pub(crate) use local::*;
59 
60 /// Internal classification for params or returns,
61 /// mainly used for params and return register assignment.
62 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
63 pub(super) enum ParamsOrReturns {
64     Params,
65     Returns,
66 }
67 
68 /// Macro to get the pinned register holding the [VMContext].
69 macro_rules! vmctx {
70     ($m:ident) => {
71         <$m::ABI as $crate::abi::ABI>::vmctx_reg()
72     };
73 }
74 
75 pub(crate) use vmctx;
76 
77 /// Constructs an [ABISig] using Winch's ABI.
wasm_sig<A: ABI>(ty: &WasmFuncType) -> Result<ABISig>78 pub(crate) fn wasm_sig<A: ABI>(ty: &WasmFuncType) -> Result<ABISig> {
79     // 6 is used semi-arbitrarily here, we can modify as we see fit.
80     let mut params: SmallVec<[WasmValType; 6]> = SmallVec::new();
81     params.extend_from_slice(&vmctx_types::<A>());
82     params.extend_from_slice(ty.params());
83 
84     A::sig_from(&params, ty.results(), &CallingConvention::Default)
85 }
86 
87 /// Returns the callee and caller [VMContext] types.
vmctx_types<A: ABI>() -> [WasmValType; 2]88 pub(crate) fn vmctx_types<A: ABI>() -> [WasmValType; 2] {
89     [A::ptr_type(), A::ptr_type()]
90 }
91 
92 /// Trait implemented by a specific ISA and used to provide
93 /// information about alignment, parameter passing, usage of
94 /// specific registers, etc.
95 pub(crate) trait ABI {
96     /// The required stack alignment.
stack_align() -> u897     fn stack_align() -> u8;
98 
99     /// The required stack alignment for calls.
call_stack_align() -> u8100     fn call_stack_align() -> u8;
101 
102     /// The offset to the argument base, relative to the frame pointer.
arg_base_offset() -> u8103     fn arg_base_offset() -> u8;
104 
105     /// The initial size in bytes of the function's frame.
106     ///
107     /// This amount is constant and accounts for all the stack space allocated
108     /// at the frame setup.
initial_frame_size() -> u8109     fn initial_frame_size() -> u8;
110 
111     /// Construct the ABI-specific signature from a WebAssembly
112     /// function type.
113     #[cfg(test)]
sig(wasm_sig: &WasmFuncType, call_conv: &CallingConvention) -> Result<ABISig>114     fn sig(wasm_sig: &WasmFuncType, call_conv: &CallingConvention) -> Result<ABISig> {
115         Self::sig_from(wasm_sig.params(), wasm_sig.results(), call_conv)
116     }
117 
118     /// Construct an ABI signature from WasmType params and returns.
sig_from( params: &[WasmValType], returns: &[WasmValType], call_conv: &CallingConvention, ) -> Result<ABISig>119     fn sig_from(
120         params: &[WasmValType],
121         returns: &[WasmValType],
122         call_conv: &CallingConvention,
123     ) -> Result<ABISig>;
124 
125     /// Construct [`ABIResults`] from a slice of [`WasmType`].
abi_results(returns: &[WasmValType], call_conv: &CallingConvention) -> Result<ABIResults>126     fn abi_results(returns: &[WasmValType], call_conv: &CallingConvention) -> Result<ABIResults>;
127 
128     /// Returns the number of bits in a word.
word_bits() -> u8129     fn word_bits() -> u8;
130 
131     /// Returns the number of bytes in a word.
word_bytes() -> u8132     fn word_bytes() -> u8 {
133         Self::word_bits() / 8
134     }
135 
136     /// Returns the pinned register used to hold
137     /// the `VMContext`.
vmctx_reg() -> Reg138     fn vmctx_reg() -> Reg;
139 
140     /// The size, in bytes, of each stack slot used for stack parameter passing.
stack_slot_size() -> u8141     fn stack_slot_size() -> u8;
142 
143     /// Returns the size in bytes of the given [`WasmType`].
sizeof(ty: &WasmValType) -> u8144     fn sizeof(ty: &WasmValType) -> u8;
145 
146     /// The target pointer size represented as [WasmValType].
ptr_type() -> WasmValType147     fn ptr_type() -> WasmValType {
148         // Defaulting to 64, since we currently only support 64-bit
149         // architectures.
150         WasmValType::I64
151     }
152 }
153 
154 /// ABI-specific representation of function argument or result.
155 #[derive(Clone, Debug)]
156 pub enum ABIOperand {
157     /// A register [`ABIOperand`].
158     Reg {
159         /// The type of the [`ABIOperand`].
160         ty: WasmValType,
161         /// Register holding the [`ABIOperand`].
162         reg: Reg,
163         /// The size of the [`ABIOperand`], in bytes.
164         size: u32,
165     },
166     /// A stack [`ABIOperand`].
167     Stack {
168         /// The type of the [`ABIOperand`].
169         ty: WasmValType,
170         /// Offset of the operand referenced through FP by the callee and
171         /// through SP by the caller.
172         offset: u32,
173         /// The size of the [`ABIOperand`], in bytes.
174         size: u32,
175     },
176 }
177 
178 impl ABIOperand {
179     /// Allocate a new register [`ABIOperand`].
reg(reg: Reg, ty: WasmValType, size: u32) -> Self180     pub fn reg(reg: Reg, ty: WasmValType, size: u32) -> Self {
181         Self::Reg { reg, ty, size }
182     }
183 
184     /// Allocate a new stack [`ABIOperand`].
stack_offset(offset: u32, ty: WasmValType, size: u32) -> Self185     pub fn stack_offset(offset: u32, ty: WasmValType, size: u32) -> Self {
186         Self::Stack { ty, offset, size }
187     }
188 
189     /// Is this [`ABIOperand`] in a register.
is_reg(&self) -> bool190     pub fn is_reg(&self) -> bool {
191         match *self {
192             ABIOperand::Reg { .. } => true,
193             _ => false,
194         }
195     }
196 
197     /// Unwraps the underlying register if it is one.
198     ///
199     /// # Panics
200     /// This function panics if the [`ABIOperand`] is not a register.
unwrap_reg(&self) -> Reg201     pub fn unwrap_reg(&self) -> Reg {
202         match self {
203             ABIOperand::Reg { reg, .. } => *reg,
204             _ => unreachable!(),
205         }
206     }
207 }
208 
209 /// Information about the [`ABIOperand`] information used in [`ABISig`].
210 #[derive(Clone, Debug)]
211 pub(crate) struct ABIOperands {
212     /// All the operands.
213     pub inner: SmallVec<[ABIOperand; 6]>,
214     /// All the registers used as operands.
215     pub regs: HashSet<Reg>,
216     /// Stack bytes used by the operands.
217     pub bytes: u32,
218 }
219 
220 impl Default for ABIOperands {
default() -> Self221     fn default() -> Self {
222         Self {
223             inner: Default::default(),
224             regs: HashSet::with_capacity(0),
225             bytes: 0,
226         }
227     }
228 }
229 
230 /// Machine stack location of the stack results.
231 #[derive(Debug, Copy, Clone)]
232 pub(crate) enum RetArea {
233     /// Addressed from the stack pointer at the given offset.
234     SP(SPOffset),
235     /// The address of the results base is stored at a particular,
236     /// well known [LocalSlot].
237     Slot(LocalSlot),
238     /// The return area cannot be fully resolved ahead-of-time.
239     /// If there are results on the stack, this is the default state to which
240     /// all return areas get initialized to until they can be fully resolved to
241     /// either a [RetArea::SP] or [RetArea::Slot].
242     ///
243     /// This allows a more explicit differentiation between the existence of
244     /// a return area versus no return area at all.
245     Uninit,
246 }
247 
248 impl Default for RetArea {
default() -> Self249     fn default() -> Self {
250         Self::Uninit
251     }
252 }
253 
254 impl RetArea {
255     /// Create a [RetArea] addressed from SP at the given offset.
sp(offs: SPOffset) -> Self256     pub fn sp(offs: SPOffset) -> Self {
257         Self::SP(offs)
258     }
259 
260     /// Create a [RetArea] addressed stored at the given [LocalSlot].
slot(local: LocalSlot) -> Self261     pub fn slot(local: LocalSlot) -> Self {
262         Self::Slot(local)
263     }
264 
265     /// Returns the [SPOffset] used as the base of the return area.
266     ///
267     /// # Panics
268     /// This function panics if the return area doesn't hold a [SPOffset].
unwrap_sp(&self) -> SPOffset269     pub fn unwrap_sp(&self) -> SPOffset {
270         match self {
271             Self::SP(offs) => *offs,
272             _ => unreachable!(),
273         }
274     }
275 
276     /// Returns true if the return area is addressed via the stack pointer.
is_sp(&self) -> bool277     pub fn is_sp(&self) -> bool {
278         match self {
279             Self::SP(_) => true,
280             _ => false,
281         }
282     }
283 
284     /// Returns true if the return area is uninitialized.
is_uninit(&self) -> bool285     pub fn is_uninit(&self) -> bool {
286         match self {
287             Self::Uninit => true,
288             _ => false,
289         }
290     }
291 }
292 
293 /// ABI-specific representation of an [`ABISig`].
294 #[derive(Clone, Debug, Default)]
295 pub(crate) struct ABIResults {
296     /// The result operands.
297     operands: ABIOperands,
298     /// The return area, if there are results on the stack.
299     ret_area: Option<RetArea>,
300 }
301 
302 impl ABIResults {
303     /// Creates [`ABIResults`] from a slice of `WasmType`.
304     /// This function maps the given return types to their ABI specific
305     /// representation. It does so, by iterating over them and applying the
306     /// given `map` closure. The map closure takes a [WasmValType], maps its ABI
307     /// representation, according to the calling convention. In the case of
308     /// results, one result is stored in registers and the rest at particular
309     /// offsets in the stack.
from<F>( returns: &[WasmValType], call_conv: &CallingConvention, mut map: F, ) -> Result<Self> where F: FnMut(&WasmValType, u32) -> Result<(ABIOperand, u32)>,310     pub fn from<F>(
311         returns: &[WasmValType],
312         call_conv: &CallingConvention,
313         mut map: F,
314     ) -> Result<Self>
315     where
316         F: FnMut(&WasmValType, u32) -> Result<(ABIOperand, u32)>,
317     {
318         if returns.len() == 0 {
319             return Ok(Self::default());
320         }
321 
322         type FoldTuple = (SmallVec<[ABIOperand; 6]>, HashSet<Reg>, u32);
323         type FoldTupleResult = Result<FoldTuple>;
324 
325         let fold_impl =
326             |(mut operands, mut regs, stack_bytes): FoldTuple, arg| -> FoldTupleResult {
327                 let (operand, bytes) = map(arg, stack_bytes)?;
328                 if operand.is_reg() {
329                     regs.insert(operand.unwrap_reg());
330                 }
331                 operands.push(operand);
332                 Ok((operands, regs, bytes))
333             };
334 
335         // When dealing with multiple results, Winch's calling convention stores the
336         // last return value in a register rather than the first one. In that
337         // sense, Winch's return values in the ABI signature are "reversed" in
338         // terms of storage. This technique is particularly helpful to ensure that
339         // the following invariants are maintained:
340         // * Spilled memory values always precede register values
341         // * Spilled values are stored from oldest to newest, matching their
342         //   respective locations on the machine stack.
343         let (mut operands, regs, bytes) = if call_conv.is_default() {
344             returns
345                 .iter()
346                 .rev()
347                 .try_fold((SmallVec::new(), HashSet::with_capacity(1), 0), fold_impl)?
348         } else {
349             returns
350                 .iter()
351                 .try_fold((SmallVec::new(), HashSet::with_capacity(1), 0), fold_impl)?
352         };
353 
354         // Similar to above, we reverse the result of the operands calculation
355         // to ensure that they match the declared order.
356         if call_conv.is_default() {
357             operands.reverse();
358         }
359 
360         Ok(Self::new(ABIOperands {
361             inner: operands,
362             regs,
363             bytes,
364         }))
365     }
366 
367     /// Create a new [`ABIResults`] from [`ABIOperands`].
new(operands: ABIOperands) -> Self368     pub fn new(operands: ABIOperands) -> Self {
369         let ret_area = (operands.bytes > 0).then(|| RetArea::default());
370         Self { operands, ret_area }
371     }
372 
373     /// Returns a reference to a [HashSet<Reg>], which includes
374     /// all the registers used to hold function results.
regs(&self) -> &HashSet<Reg>375     pub fn regs(&self) -> &HashSet<Reg> {
376         &self.operands.regs
377     }
378 
379     /// Get a slice over all the result [`ABIOperand`]s.
operands(&self) -> &[ABIOperand]380     pub fn operands(&self) -> &[ABIOperand] {
381         &self.operands.inner
382     }
383 
384     /// Returns the length of the result.
len(&self) -> usize385     pub fn len(&self) -> usize {
386         self.operands.inner.len()
387     }
388 
389     /// Returns the length of results on the stack.
stack_operands_len(&self) -> usize390     pub fn stack_operands_len(&self) -> usize {
391         self.operands().len() - self.regs().len()
392     }
393 
394     /// Get the [`ABIOperand`] result in the nth position.
395     #[cfg(test)]
get(&self, n: usize) -> Option<&ABIOperand>396     pub fn get(&self, n: usize) -> Option<&ABIOperand> {
397         self.operands.inner.get(n)
398     }
399 
400     /// Returns the first [`ABIOperand`].
401     /// Useful in situations where the function signature is known to
402     /// have a single return.
403     ///
404     /// # Panics
405     /// This function panics if the function signature contains more
unwrap_singleton(&self) -> &ABIOperand406     pub fn unwrap_singleton(&self) -> &ABIOperand {
407         debug_assert_eq!(self.len(), 1);
408         &self.operands.inner[0]
409     }
410 
411     /// Returns the size, in bytes of all the [`ABIOperand`]s in the stack.
size(&self) -> u32412     pub fn size(&self) -> u32 {
413         self.operands.bytes
414     }
415 
416     /// Returns true if the [`ABIResults`] require space on the machine stack
417     /// for results.
on_stack(&self) -> bool418     pub fn on_stack(&self) -> bool {
419         self.operands.bytes > 0
420     }
421 
422     /// Set the return area of the signature.
423     ///
424     /// # Panics
425     ///
426     /// This function will panic if trying to set a return area if there are
427     /// no results on the stack or if trying to set an uninitialize return area.
428     /// This method must only be used when the return area can be fully
429     /// materialized.
set_ret_area(&mut self, area: RetArea)430     pub fn set_ret_area(&mut self, area: RetArea) {
431         debug_assert!(self.on_stack());
432         debug_assert!(!area.is_uninit());
433         self.ret_area = Some(area);
434     }
435 
436     /// Returns a reference to the return area, if any.
ret_area(&self) -> Option<&RetArea>437     pub fn ret_area(&self) -> Option<&RetArea> {
438         self.ret_area.as_ref()
439     }
440 }
441 
442 /// ABI-specific representation of an [`ABISig`].
443 #[derive(Debug, Clone, Default)]
444 pub(crate) struct ABIParams {
445     /// The param operands.
446     operands: ABIOperands,
447     /// Whether [`ABIParams`] contains an extra parameter for the stack
448     /// result area.
449     has_retptr: bool,
450 }
451 
452 impl ABIParams {
453     /// Creates [`ABIParams`] from a slice of `WasmType`.
454     /// This function maps the given param types to their ABI specific
455     /// representation. It does so, by iterating over them and applying the
456     /// given `map` closure. The map closure takes a [WasmType], maps its ABI
457     /// representation, according to the calling convention. In the case of
458     /// params, multiple params may be passed in registers and the rest on the
459     /// stack depending on the calling convention.
from<F, A: ABI>( params: &[WasmValType], initial_bytes: u32, needs_stack_results: bool, mut map: F, ) -> Result<Self> where F: FnMut(&WasmValType, u32) -> Result<(ABIOperand, u32)>,460     pub fn from<F, A: ABI>(
461         params: &[WasmValType],
462         initial_bytes: u32,
463         needs_stack_results: bool,
464         mut map: F,
465     ) -> Result<Self>
466     where
467         F: FnMut(&WasmValType, u32) -> Result<(ABIOperand, u32)>,
468     {
469         if params.len() == 0 && !needs_stack_results {
470             return Ok(Self::with_bytes(initial_bytes));
471         }
472 
473         let register_capacity = params.len().min(6);
474         let mut operands = SmallVec::new();
475         let mut regs = HashSet::with_capacity(register_capacity);
476         let mut stack_bytes = initial_bytes;
477 
478         let ptr_type = ptr_type_from_ptr_size(<A as ABI>::word_bytes());
479         // Handle stack results by specifying an extra, implicit first argument.
480         let stack_results = if needs_stack_results {
481             let (operand, bytes) = map(&ptr_type, stack_bytes)?;
482             if operand.is_reg() {
483                 regs.insert(operand.unwrap_reg());
484             }
485             stack_bytes = bytes;
486             Some(operand)
487         } else {
488             None
489         };
490 
491         for arg in params.iter() {
492             let (operand, bytes) = map(arg, stack_bytes)?;
493             if operand.is_reg() {
494                 regs.insert(operand.unwrap_reg());
495             }
496             operands.push(operand);
497             stack_bytes = bytes;
498         }
499 
500         if let Some(operand) = stack_results {
501             // But still push the operand for stack results last as that is what
502             // the rest of the code expects.
503             operands.push(operand);
504         }
505 
506         Ok(Self {
507             operands: ABIOperands {
508                 inner: operands,
509                 regs,
510                 bytes: stack_bytes,
511             },
512             has_retptr: needs_stack_results,
513         })
514     }
515 
516     /// Creates new [`ABIParams`], with the specified amount of stack bytes.
with_bytes(bytes: u32) -> Self517     pub fn with_bytes(bytes: u32) -> Self {
518         let mut params = Self::default();
519         params.operands.bytes = bytes;
520         params
521     }
522 
523     /// Get the [`ABIOperand`] param in the nth position.
524     #[cfg(test)]
get(&self, n: usize) -> Option<&ABIOperand>525     pub fn get(&self, n: usize) -> Option<&ABIOperand> {
526         self.operands.inner.get(n)
527     }
528 
529     /// Get a slice over all the parameter [`ABIOperand`]s.
operands(&self) -> &[ABIOperand]530     pub fn operands(&self) -> &[ABIOperand] {
531         &self.operands.inner
532     }
533 
534     /// Returns the length of the params, including the return pointer,
535     /// if any.
len(&self) -> usize536     pub fn len(&self) -> usize {
537         self.operands.inner.len()
538     }
539 
540     /// Returns the length of the params, excluding the return pointer,
541     /// if any.
len_without_retptr(&self) -> usize542     pub fn len_without_retptr(&self) -> usize {
543         if self.has_retptr {
544             self.len() - 1
545         } else {
546             self.len()
547         }
548     }
549 
550     /// Returns true if the [ABISig] has an extra parameter for stack results.
has_retptr(&self) -> bool551     pub fn has_retptr(&self) -> bool {
552         self.has_retptr
553     }
554 
555     /// Returns the last [ABIOperand] used as the pointer to the
556     /// stack results area.
557     ///
558     /// # Panics
559     /// This function panics if the [ABIParams] doesn't have a stack results
560     /// parameter.
unwrap_results_area_operand(&self) -> &ABIOperand561     pub fn unwrap_results_area_operand(&self) -> &ABIOperand {
562         debug_assert!(self.has_retptr);
563         self.operands.inner.last().unwrap()
564     }
565 }
566 
567 /// An ABI-specific representation of a function signature.
568 #[derive(Debug, Clone)]
569 pub(crate) struct ABISig {
570     /// Function parameters.
571     pub params: ABIParams,
572     /// Function result.
573     pub results: ABIResults,
574     /// A unique set of registers used in the entire [`ABISig`].
575     pub regs: HashSet<Reg>,
576     /// Calling convention used.
577     pub call_conv: CallingConvention,
578 }
579 
580 impl Default for ABISig {
default() -> Self581     fn default() -> Self {
582         Self {
583             params: Default::default(),
584             results: Default::default(),
585             regs: Default::default(),
586             call_conv: CallingConvention::Default,
587         }
588     }
589 }
590 
591 impl ABISig {
592     /// Create a new ABI signature.
new(cc: CallingConvention, params: ABIParams, results: ABIResults) -> Self593     pub fn new(cc: CallingConvention, params: ABIParams, results: ABIResults) -> Self {
594         let regs = params
595             .operands
596             .regs
597             .union(&results.operands.regs)
598             .copied()
599             .collect();
600         Self {
601             params,
602             results,
603             regs,
604             call_conv: cc,
605         }
606     }
607 
608     /// Returns an iterator over all the parameter operands.
params(&self) -> &[ABIOperand]609     pub fn params(&self) -> &[ABIOperand] {
610         self.params.operands()
611     }
612 
613     /// Returns an iterator over all the result operands.
results(&self) -> &[ABIOperand]614     pub fn results(&self) -> &[ABIOperand] {
615         self.results.operands()
616     }
617 
618     /// Returns a slice over the signature params, excluding the results
619     /// base parameter, if any.
params_without_retptr(&self) -> &[ABIOperand]620     pub fn params_without_retptr(&self) -> &[ABIOperand] {
621         if self.params.has_retptr() {
622             &self.params()[0..(self.params.len() - 1)]
623         } else {
624             self.params()
625         }
626     }
627 
628     /// Returns the stack size, in bytes, needed for arguments on the stack.
params_stack_size(&self) -> u32629     pub fn params_stack_size(&self) -> u32 {
630         self.params.operands.bytes
631     }
632 
633     /// Returns the stack size, in bytes, needed for results on the stack.
results_stack_size(&self) -> u32634     pub fn results_stack_size(&self) -> u32 {
635         self.results.operands.bytes
636     }
637 
638     /// Returns true if the signature has results on the stack.
has_stack_results(&self) -> bool639     pub fn has_stack_results(&self) -> bool {
640         self.results.on_stack()
641     }
642 }
643 
644 /// Align a value up to the given power-of-two-alignment.
645 // See https://sites.google.com/site/theoryofoperatingsystems/labs/malloc/align8
align_to<N>(value: N, alignment: N) -> N where N: Not<Output = N> + BitAnd<N, Output = N> + Add<N, Output = N> + Sub<N, Output = N> + From<u8> + Copy,646 pub(crate) fn align_to<N>(value: N, alignment: N) -> N
647 where
648     N: Not<Output = N>
649         + BitAnd<N, Output = N>
650         + Add<N, Output = N>
651         + Sub<N, Output = N>
652         + From<u8>
653         + Copy,
654 {
655     let alignment_mask = alignment - 1.into();
656     (value + alignment_mask) & !alignment_mask
657 }
658 
659 /// Calculates the delta needed to adjust a function's frame plus some
660 /// addend to a given alignment.
calculate_frame_adjustment(frame_size: u32, addend: u32, alignment: u32) -> u32661 pub(crate) fn calculate_frame_adjustment(frame_size: u32, addend: u32, alignment: u32) -> u32 {
662     let total = frame_size + addend;
663     (alignment - (total % alignment)) % alignment
664 }
665