Skip to main content

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        intrinsic_dispatch_on_type! {
29            @declare [] $(#[$attr])*
30            $vis fn $name<$generic: $bound>($($arg: $arg_ty),*) -> $ret_ty;
31            $($concrete => $body)*
32        }
33    };
34
35    (
36        $(#[$attr:meta])*
37        $vis:vis const fn $name:ident<$generic:ident: $bound:path>(
38            $($arg:ident: $arg_ty:ty),* $(,)?
39        ) -> $ret_ty:ty;
40        $($concrete:ty => $body:block)*
41    ) => {
42        intrinsic_dispatch_on_type! {
43            @declare [const] $(#[$attr])*
44            $vis fn $name<$generic: $bound>($($arg: $arg_ty),*) -> $ret_ty;
45            $($concrete => $body)*
46        }
47    };
48
49    (
50        @declare [$($constness:tt)?] $(#[$attr:meta])*
51        $vis:vis fn $name:ident<$generic:ident: $bound:path>(
52            $($arg:ident: $arg_ty:ty),*
53        ) -> $ret_ty:ty;
54        $($concrete:ty => $body:block)*
55    ) => {
56        mod $name {
57            use super::*;
58
59            pub trait Dispatch<$generic = Self>: $bound {
60                fn dispatch($($arg: $arg_ty),*) -> $ret_ty;
61            }
62
63            intrinsic_dispatch_on_type! {
64                @impls $generic, ($($arg: $arg_ty),*) -> $ret_ty,
65                $($concrete => $body)*
66            }
67        }
68
69        $(#[$attr])*
70        $vis $($constness)? fn $name<$generic: $name::Dispatch>($($arg: $arg_ty),*) -> $ret_ty {
71            <$generic as $name::Dispatch>::dispatch($($arg),*)
72        }
73    };
74
75    (
76        @impls $generic:ident, $args:tt -> $ret_ty:ty,
77        $($concrete:ty => $body:block)*
78    ) => {
79        $(intrinsic_dispatch_on_type! { @impl $generic = $concrete, $args -> $ret_ty $body })*
80    };
81
82    (
83        @impl $generic:ident = $concrete:ty,
84        ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty $body:block
85    ) => {
86        // We need a const block here to define a type alias for the type var ($generic),
87        // because the arguments in `fn dispatch` are the ones used to define the intrinsic.
88        //
89        // For instance, when defining `fn exp<T: bounds::FloatPrimitive>(x: T) -> T`,
90        // the definition of `dispatch` below is going to be `fn dispatch(x: T) -> T`.
91        const _: () = {
92            type $generic = $concrete;
93
94            impl Dispatch<$concrete> for $concrete {
95                #[inline]
96                fn dispatch($($arg: $arg_ty),*) -> $ret_ty $body
97            }
98        };
99    };
100}
101
102pub(super) use intrinsic_dispatch_on_type;