From eabb6fab4a4b63ef51bbab284918b6c16218bef7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 16:28:50 -0700 Subject: [PATCH] Shore up docs in the macros module --- src/macros.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 2e65e96..6e34066 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,10 +1,63 @@ +//! 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 fo +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof +/// 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 `feature = "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 { () => (); - // Anything which has a `not(feature = "c")` we'll generate a shim function - // which calls out to the C function if the `c` feature is enabled. - // Otherwise if the `c` feature isn't enabled then we'll just have a normal - // intrinsic. + // 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)*])* @@ -97,8 +150,13 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Another attribute we recognize is an "abi hack" for win64 to get the 128 - // bit calling convention correct. + // 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)*])* @@ -119,10 +177,10 @@ macro_rules! intrinsics { intrinsics! { pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_abi_hack::U64x2 + -> ::macros::win64_128bit_abi_hack::U64x2 { let e: $ret = super::$name($($argname),*); - ::macros::win64_abi_hack::U64x2::from(e) + ::macros::win64_128bit_abi_hack::U64x2::from(e) } } } @@ -140,7 +198,8 @@ macro_rules! intrinsics { // 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. Handle that here + // original function. The aliasing here is used to generate these symbols in + // the object file. ( #[arm_aeabi_alias = $alias:ident] $(#[$($attr:tt)*])* @@ -151,7 +210,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -180,6 +238,12 @@ macro_rules! intrinsics { 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. + // + // 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 { @@ -198,9 +262,10 @@ macro_rules! intrinsics { ); } -// Hack for LLVM expectations for ABI on windows +// 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_abi_hack { +pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64);