mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 21:21:31 +11:00
272 lines
7.5 KiB
Rust
272 lines
7.5 KiB
Rust
|
/// Generate a series of aliases for an intrinsic function.
|
||
|
macro_rules! intrinsics_aliases {
|
||
|
(
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||
|
) => {};
|
||
|
(
|
||
|
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||
|
) => {};
|
||
|
|
||
|
(
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||
|
$alias:ident
|
||
|
$($rest:ident)*
|
||
|
) => {
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
intrinsics! {
|
||
|
extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||
|
$name($($argname),*)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics_aliases! {
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||
|
$($rest)*
|
||
|
}
|
||
|
};
|
||
|
|
||
|
(
|
||
|
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||
|
$alias:ident
|
||
|
$($rest:ident)*
|
||
|
) => {
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
intrinsics! {
|
||
|
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||
|
$name($($argname),*)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics_aliases! {
|
||
|
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||
|
$($rest)*
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/// The macro used to define overridden intrinsics.
|
||
|
///
|
||
|
/// This is heavily inspired by the macro used by compiler-builtins. The idea
|
||
|
/// is to abstract anything special that needs to be done to override an
|
||
|
/// intrinsic function. Intrinsic generation is disabled for non-ARM targets
|
||
|
/// so things like CI and docs generation do not have problems. Additionally
|
||
|
/// they can be disabled with the crate feature `disable-intrinsics` for
|
||
|
/// testing or comparing performance.
|
||
|
///
|
||
|
/// Like the compiler-builtins macro, it accepts a series of functions that
|
||
|
/// looks like normal Rust code:
|
||
|
///
|
||
|
/// intrinsics! {
|
||
|
/// extern "C" fn foo(a: i32) -> u32 {
|
||
|
/// // ...
|
||
|
/// }
|
||
|
///
|
||
|
/// #[nonstandard_attribute]
|
||
|
/// extern "C" fn bar(a: i32) -> u32 {
|
||
|
/// // ...
|
||
|
/// }
|
||
|
/// }
|
||
|
///
|
||
|
/// Each function can also be decorated with nonstandard attributes to control
|
||
|
/// additional behaviour:
|
||
|
///
|
||
|
/// * `slower_than_default` - indicates that the override is slower than the
|
||
|
/// default implementation. Currently this just disables the override
|
||
|
/// entirely.
|
||
|
/// * `bootrom_v2` - indicates that the override is only available
|
||
|
/// on a V2 bootrom or higher. Only enabled when the feature
|
||
|
/// `rom-v2-intrinsics` is set.
|
||
|
/// * `alias` - accepts a list of names to alias the intrinsic to.
|
||
|
/// * `aeabi` - accepts a list of ARM EABI names to alias to.
|
||
|
///
|
||
|
macro_rules! intrinsics {
|
||
|
() => {};
|
||
|
|
||
|
(
|
||
|
#[slower_than_default]
|
||
|
$(#[$($attr:tt)*])*
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
// Not exported, but defined so the actual implementation is
|
||
|
// considered used
|
||
|
#[allow(dead_code)]
|
||
|
fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
#[bootrom_v2]
|
||
|
$(#[$($attr:tt)*])*
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
// Not exported, but defined so the actual implementation is
|
||
|
// considered used
|
||
|
#[cfg(not(feature = "rom-v2-intrinsics"))]
|
||
|
#[allow(dead_code)]
|
||
|
fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "rom-v2-intrinsics")]
|
||
|
intrinsics! {
|
||
|
$(#[$($attr)*])*
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
#[alias = $($alias:ident),*]
|
||
|
$(#[$($attr:tt)*])*
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
intrinsics! {
|
||
|
$(#[$($attr)*])*
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics_aliases! {
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||
|
$($alias) *
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
#[alias = $($alias:ident),*]
|
||
|
$(#[$($attr:tt)*])*
|
||
|
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
intrinsics! {
|
||
|
$(#[$($attr)*])*
|
||
|
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics_aliases! {
|
||
|
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||
|
$($alias) *
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
#[aeabi = $($alias:ident),*]
|
||
|
$(#[$($attr:tt)*])*
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
intrinsics! {
|
||
|
$(#[$($attr)*])*
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
intrinsics_aliases! {
|
||
|
extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret,
|
||
|
$($alias) *
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
$(#[$($attr:tt)*])*
|
||
|
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
$(#[$($attr)*])*
|
||
|
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
mod $name {
|
||
|
#[no_mangle]
|
||
|
$(#[$($attr)*])*
|
||
|
pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
super::$name($($argname),*)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Not exported, but defined so the actual implementation is
|
||
|
// considered used
|
||
|
#[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))]
|
||
|
#[allow(dead_code)]
|
||
|
fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
|
||
|
(
|
||
|
$(#[$($attr:tt)*])*
|
||
|
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||
|
$($body:tt)*
|
||
|
}
|
||
|
|
||
|
$($rest:tt)*
|
||
|
) => {
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
$(#[$($attr)*])*
|
||
|
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||
|
mod $name {
|
||
|
#[no_mangle]
|
||
|
$(#[$($attr)*])*
|
||
|
pub unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
super::$name($($argname),*)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Not exported, but defined so the actual implementation is
|
||
|
// considered used
|
||
|
#[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))]
|
||
|
#[allow(dead_code)]
|
||
|
unsafe fn $name( $($argname: $ty),* ) -> $ret {
|
||
|
$($body)*
|
||
|
}
|
||
|
|
||
|
intrinsics!($($rest)*);
|
||
|
};
|
||
|
}
|