123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- //! Macros shared throughout the compiler-builtins implementation
- /// The "main macro" used for defining intrinsics.
- ///
- /// The compiler-builtins library is super platform-specific with tons of crazy
- /// little tweaks for various platforms. As a result it *could* involve a lot of
- /// #[cfg] and macro soup, but the intention is that this macro alleviates a lot
- /// of that complexity. Ideally this macro has all the weird ABI things
- /// platforms need and elsewhere in this library it just looks like normal Rust
- /// code.
- ///
- /// This macro is structured to be invoked with a bunch of functions that looks
- /// like:
- ///
- /// intrinsics! {
- /// pub extern "C" fn foo(a: i32) -> u32 {
- /// // ...
- /// }
- ///
- /// #[nonstandard_attribute]
- /// pub extern "C" fn bar(a: i32) -> u32 {
- /// // ...
- /// }
- /// }
- ///
- /// Each function is defined in a manner that looks like a normal Rust function.
- /// The macro then accepts a few nonstandard attributes that can decorate
- /// various functions. Each of the attributes is documented below with what it
- /// can do, and each of them slightly tweaks how further expansion happens.
- ///
- /// A quick overview of attributes supported right now are:
- ///
- /// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the
- /// C-compiled version if `use_c` is specified.
- /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
- /// the specified ABI everywhere else.
- /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
- /// `"unadjusted"` abi on Win64 and the specified abi elsewhere.
- /// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
- /// intrinsics where the ABI is slightly tweaked on Windows platforms, but
- /// it's a normal ABI elsewhere for returning a 128 bit integer.
- /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
- /// their otherwise typical names to other prefixed ones.
- ///
- macro_rules! intrinsics {
- () => ();
- // Right now there's a bunch of architecture-optimized intrinsics in the
- // stock compiler-rt implementation. Not all of these have been ported over
- // to Rust yet so when the `c` feature of this crate is enabled we fall back
- // to the architecture-specific versions which should be more optimized. The
- // purpose of this macro is to easily allow specifying this.
- //
- // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true,
- // will cause this crate's exported version of `$name` to just redirect to
- // the C implementation. No symbol named `$name` will be in the object file
- // for this crate itself.
- //
- // When the `#[cfg]` directive is false, or when the `c` feature is
- // disabled, the provided implementation is used instead.
- (
- #[use_c_shim_if($($cfg_clause:tt)*)]
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- #[cfg(all(use_c, $($cfg_clause)*))]
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- extern $abi {
- fn $name($($argname: $ty),*) -> $ret;
- }
- unsafe {
- $name($($argname),*)
- }
- }
- #[cfg(not(all(use_c, $($cfg_clause)*)))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- intrinsics!($($rest)*);
- );
- // We recognize the `#[aapcs_on_arm]` attribute here and generate the
- // same intrinsic but force it to have the `"aapcs"` calling convention on
- // ARM and `"C"` elsewhere.
- (
- #[aapcs_on_arm]
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- #[cfg(target_arch = "arm")]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- #[cfg(not(target_arch = "arm"))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- intrinsics!($($rest)*);
- );
- // Like aapcs above we recognize an attribute for the "unadjusted" abi on
- // win64 for some methods.
- (
- #[unadjusted_on_win64]
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- #[cfg(all(windows, target_pointer_width = "64"))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- #[cfg(not(all(windows, target_pointer_width = "64")))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- intrinsics!($($rest)*);
- );
- // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
- // calling convention. That's managed here with this "abi hack" which alters
- // the generated symbol's ABI.
- //
- // This will still define a function in this crate with the given name and
- // signature, but the actual symbol for the intrinsic may have a slightly
- // different ABI on win64.
- (
- #[win64_128bit_abi_hack]
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- #[cfg(all(windows, target_pointer_width = "64"))]
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- #[cfg(all(windows, target_pointer_width = "64"))]
- pub mod $name {
- intrinsics! {
- pub extern $abi fn $name( $($argname: $ty),* )
- -> ::macros::win64_128bit_abi_hack::U64x2
- {
- let e: $ret = super::$name($($argname),*);
- ::macros::win64_128bit_abi_hack::U64x2::from(e)
- }
- }
- }
- #[cfg(not(all(windows, target_pointer_width = "64")))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- intrinsics!($($rest)*);
- );
- // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
- // build under `__aeabi_*` aliases, and LLVM will call these instead of the
- // original function. The aliasing here is used to generate these symbols in
- // the object file.
- (
- #[arm_aeabi_alias = $alias:ident]
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- #[cfg(target_arch = "arm")]
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- #[cfg(target_arch = "arm")]
- pub mod $name {
- intrinsics! {
- pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret {
- super::$name($($argname),*)
- }
- }
- }
- #[cfg(not(target_arch = "arm"))]
- intrinsics! {
- $(#[$($attr)*])*
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- }
- intrinsics!($($rest)*);
- );
- // This is the final catch-all rule. At this point we just generate an
- // intrinsic with a conditional `#[no_mangle]` directive to avoid
- // interfereing with duplicate symbols and whatnot during testing.
- //
- // After the intrinsic is defined we just continue with the rest of the
- // input we were given.
- (
- $(#[$($attr:tt)*])*
- pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- $($rest:tt)*
- ) => (
- $(#[$($attr)*])*
- #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
- pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- intrinsics!($($rest)*);
- );
- }
- // Hack for LLVM expectations for ABI on windows. This is used by the
- // `#[win64_128bit_abi_hack]` attribute recognized above
- #[cfg(all(windows, target_pointer_width="64"))]
- pub mod win64_128bit_abi_hack {
- #[repr(simd)]
- pub struct U64x2(u64, u64);
- impl From<i128> for U64x2 {
- fn from(i: i128) -> U64x2 {
- use int::LargeInt;
- let j = i as u128;
- U64x2(j.low(), j.high())
- }
- }
- impl From<u128> for U64x2 {
- fn from(i: u128) -> U64x2 {
- use int::LargeInt;
- U64x2(i.low(), i.high())
- }
- }
- }
- macro_rules! u128_lang_items {
- ($(
- #[lang = $lang:tt]
- pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
- $($body:tt)*
- }
- )*) => ($(
- #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)]
- pub fn $name( $($argname: $ty),* ) -> $ret {
- $($body)*
- }
- )*)
- }
|