mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2025-02-04 15:36:35 +11:00
b8ef969d92
Using the full module structure generated by the intrinsics macro interacts oddly with inlining on some optimization levels, causing a duplicate identical function body to be generated. This doesn't affect performance, but it wastes space, so just declare the alias directly which seems to cause the symbol to be aliased as it should be.
273 lines
7.6 KiB
Rust
273 lines
7.6 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")))]
|
|
mod $alias {
|
|
#[no_mangle]
|
|
pub extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
|
super::$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")))]
|
|
mod $alias {
|
|
#[no_mangle]
|
|
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
|
super::$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)*);
|
|
};
|
|
}
|