1 //! Macros shared throughout the compiler-builtins implementation
3 /// Changes the visibility to `pub` if feature "public-test-deps" is set
4 #[cfg(not(feature = "public-test-deps"))]
5 macro_rules
! public_test_dep
{
6 ($
(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => {
7 $
(#[$($meta)*])* pub(crate) $ident $($tokens)*
11 /// Changes the visibility to `pub` if feature "public-test-deps" is set
12 #[cfg(feature = "public-test-deps")]
13 macro_rules
! public_test_dep
{
14 {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*}
=> {
15 $
(#[$($meta)*])* pub $ident $($tokens)*
19 /// The "main macro" used for defining intrinsics.
21 /// The compiler-builtins library is super platform-specific with tons of crazy
22 /// little tweaks for various platforms. As a result it *could* involve a lot of
23 /// #[cfg] and macro soup, but the intention is that this macro alleviates a lot
24 /// of that complexity. Ideally this macro has all the weird ABI things
25 /// platforms need and elsewhere in this library it just looks like normal Rust
28 /// This macro is structured to be invoked with a bunch of functions that looks
32 /// pub extern "C" fn foo(a: i32) -> u32 {
36 /// #[nonstandard_attribute]
37 /// pub extern "C" fn bar(a: i32) -> u32 {
42 /// Each function is defined in a manner that looks like a normal Rust function.
43 /// The macro then accepts a few nonstandard attributes that can decorate
44 /// various functions. Each of the attributes is documented below with what it
45 /// can do, and each of them slightly tweaks how further expansion happens.
47 /// A quick overview of attributes supported right now are:
49 /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is
50 /// ignored if an optimized C version was compiled.
51 /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
52 /// the specified ABI everywhere else.
53 /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
54 /// `"unadjusted"` abi on Win64 and the specified abi elsewhere.
55 /// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
56 /// intrinsics where the ABI is slightly tweaked on Windows platforms, but
57 /// it's a normal ABI elsewhere for returning a 128 bit integer.
58 /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
59 /// their otherwise typical names to other prefixed ones.
61 macro_rules
! intrinsics
{
66 #[cfg_attr($e:meta, $($attr:tt)*)]
68 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
77 pub extern $abi
fn $
name($
($argname
: $ty
),*) $
(-> $ret
)?
{
85 pub extern $abi
fn $
name($
($argname
: $ty
),*) $
(-> $ret
)?
{
90 intrinsics
!($
($rest
)*);
93 // Right now there's a bunch of architecture-optimized intrinsics in the
94 // stock compiler-rt implementation. Not all of these have been ported over
95 // to Rust yet so when the `c` feature of this crate is enabled we fall back
96 // to the architecture-specific versions which should be more optimized. The
97 // purpose of this macro is to easily allow specifying this.
99 // The `#[maybe_use_optimized_c_shim]` attribute indicates that this
100 // intrinsic may have an optimized C version. In these situations the build
101 // script, if the C code is enabled and compiled, will emit a cfg directive
102 // to get passed to rustc for our compilation. If that cfg is set we skip
103 // the Rust implementation, but if the attribute is not enabled then we
104 // compile in the Rust implementation.
106 #[maybe_use_optimized_c_shim]
108 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
114 #[cfg($name = "optimized-c")]
115 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
117 fn $
name($
($argname
: $ty
),*) $
(-> $ret
)?
;
124 #[cfg(not($name = "optimized-c"))]
127 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
132 intrinsics
!($
($rest
)*);
135 // We recognize the `#[aapcs_on_arm]` attribute here and generate the
136 // same intrinsic but force it to have the `"aapcs"` calling convention on
137 // ARM and `"C"` elsewhere.
141 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
147 #[cfg(target_arch = "arm")]
150 pub extern "aapcs" fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
155 #[cfg(not(target_arch = "arm"))]
158 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
163 intrinsics
!($
($rest
)*);
166 // Like aapcs above we recognize an attribute for the "unadjusted" abi on
167 // win64 for some methods.
169 #[unadjusted_on_win64]
171 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
177 #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))]
180 pub extern "unadjusted" fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
185 #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))]
188 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
193 intrinsics
!($
($rest
)*);
196 // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
197 // calling convention. That's managed here with this "abi hack" which alters
198 // the generated symbol's ABI.
200 // This will still define a function in this crate with the given name and
201 // signature, but the actual symbol for the intrinsic may have a slightly
202 // different ABI on win64.
204 #[win64_128bit_abi_hack]
206 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
212 #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))]
214 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
218 #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))]
220 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
221 pub extern $abi
fn $
name( $
($argname
: $ty
),* )
222 -> ::macros
::win64_128bit_abi_hack
::U64x2
224 let e
: $
($ret
)?
= super::$
name($
($argname
),*);
225 ::macros
::win64_128bit_abi_hack
::U64x2
::from(e
)
229 #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))]
232 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
237 intrinsics
!($
($rest
)*);
240 // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
241 // build under `__aeabi_*` aliases, and LLVM will call these instead of the
242 // original function. The aliasing here is used to generate these symbols in
245 #[arm_aeabi_alias = $alias:ident]
247 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
253 #[cfg(target_arch = "arm")]
254 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
258 #[cfg(target_arch = "arm")]
260 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
261 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
262 super::$
name($
($argname
),*)
266 #[cfg(target_arch = "arm")]
268 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
269 pub extern "aapcs" fn $
alias( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
270 super::$
name($
($argname
),*)
274 #[cfg(not(target_arch = "arm"))]
277 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
282 intrinsics
!($
($rest
)*);
285 // C mem* functions are only generated when the "mem" feature is enabled.
289 pub unsafe extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
296 pub unsafe extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
300 #[cfg(feature = "mem")]
303 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
304 pub unsafe extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
305 super::$
name($
($argname
),*)
309 intrinsics
!($
($rest
)*);
312 // Naked functions are special: we can't generate wrappers for them since
313 // they use a custom calling convention.
317 pub unsafe extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
326 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
327 pub unsafe extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
332 intrinsics
!($
($rest
)*);
335 // For division and modulo, AVR uses a custom calling convention¹ that does
336 // not match our definitions here. Ideally we would just use hand-written
337 // naked functions, but that's quite a lot of code to port² - so for the
338 // time being we are just ignoring the problematic functions, letting
339 // avr-gcc (which is required to compile to AVR anyway) link them from
342 // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling
344 // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S
348 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
354 #[cfg(not(target_arch = "avr"))]
357 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
362 intrinsics
!($
($rest
)*);
365 // This is the final catch-all rule. At this point we generate an
366 // intrinsic with a conditional `#[no_mangle]` directive to avoid
367 // interfering with duplicate symbols and whatnot during testing.
369 // The implementation is placed in a separate module, to take advantage
370 // of the fact that rustc partitions functions into code generation
371 // units based on module they are defined in. As a result we will have
372 // a separate object file for each intrinsic. For further details see
373 // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846
375 // After the intrinsic is defined we just continue with the rest of the
376 // input we were given.
379 pub extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
386 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
392 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
393 pub extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
394 super::$
name($
($argname
),*)
398 intrinsics
!($
($rest
)*);
401 // Same as the above for unsafe functions.
404 pub unsafe extern $abi
:tt
fn $name
:ident( $
($argname
:ident
: $ty
:ty
),* ) $
(-> $ret
:ty
)?
{
411 pub unsafe extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
417 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
418 pub unsafe extern $abi
fn $
name( $
($argname
: $ty
),* ) $
(-> $ret
)?
{
419 super::$
name($
($argname
),*)
423 intrinsics
!($
($rest
)*);
427 // Hack for LLVM expectations for ABI on windows. This is used by the
428 // `#[win64_128bit_abi_hack]` attribute recognized above
429 #[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))]
430 pub mod win64_128bit_abi_hack
{
432 pub struct U64x2(u64, u64);
434 impl From
<i128
> for U64x2
{
435 fn from(i
: i128
) -> U64x2
{
438 U64x2(j
.lo(), j
.hi())
442 impl From
<u128
> for U64x2
{
443 fn from(i
: u128
) -> U64x2
{
445 U64x2(i
.lo(), i
.hi())