core/intrinsics/macros.rs
1//! Macros used to declare intrinsics.
2
3/// Declares an intrinsic that is generic over its type, but whose fallback body has to be
4/// written per-type. This is needed for the float intrinsics, which are generics but may
5/// have different fallback bodies for each float width.
6///
7/// ```ignore (illustrative)
8/// intrinsic_dispatch_on_type! {
9/// /// Returns the exponential of a float.
10/// #[rustc_nounwind]
11/// #[rustc_intrinsic]
12/// pub fn expf<T: bounds::FloatPrimitive>(x: T) -> T;
13///
14/// f16 => { expf(x as f32) as f16 }
15/// f32 => { libm::likely_available::expf(x) }
16/// f64 => { libm::likely_available::exp(x) }
17/// f128 => { libm::maybe_available::expf128(x) }
18/// }
19/// ```
20macro_rules! intrinsic_dispatch_on_type {
21 (
22 $(#[$attr:meta])*
23 $vis:vis fn $name:ident<$generic:ident: $bound:path>(
24 $($arg:ident: $arg_ty:ty),* $(,)?
25 ) -> $ret_ty:ty;
26 $($concrete:ty => $body:block)*
27 ) => {
28 mod $name {
29 use super::*;
30
31 pub trait Dispatch<$generic = Self>: $bound {
32 fn dispatch($($arg: $arg_ty),*) -> $ret_ty;
33 }
34
35 intrinsic_dispatch_on_type! {
36 @impls $generic, ($($arg: $arg_ty),*) -> $ret_ty,
37 $($concrete => $body)*
38 }
39 }
40
41 $(#[$attr])*
42 $vis fn $name<$generic: $name::Dispatch>($($arg: $arg_ty),*) -> $ret_ty {
43 <$generic as $name::Dispatch>::dispatch($($arg),*)
44 }
45 };
46
47 (
48 @impls $generic:ident, $args:tt -> $ret_ty:ty,
49 $($concrete:ty => $body:block)*
50 ) => {
51 $(intrinsic_dispatch_on_type! { @impl $generic = $concrete, $args -> $ret_ty $body })*
52 };
53
54 (
55 @impl $generic:ident = $concrete:ty,
56 ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty $body:block
57 ) => {
58 // We need a const block here to define a type alias for the type var ($generic),
59 // because the arguments in `fn dispatch` are the ones used to define the intrinsic.
60 //
61 // For instance, when defining `fn exp<T: bounds::FloatPrimitive>(x: T) -> T`,
62 // the definition of `dispatch` below is going to be `fn dispatch(x: T) -> T`.
63 const _: () = {
64 type $generic = $concrete;
65
66 impl Dispatch<$concrete> for $concrete {
67 #[inline]
68 fn dispatch($($arg: $arg_ty),*) -> $ret_ty $body
69 }
70 };
71 };
72}
73
74pub(super) use intrinsic_dispatch_on_type;