1//! Macros shared throughout the compiler-builtins implementation
2
3/// Changes the visibility to `pub` if feature "public-test-deps" is set
4#[cfg(not(feature = "public-test-deps"))]
5macro_rules! public_test_dep {
6 ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => {
7 $(#[$($meta)*])* pub(crate) $ident $($tokens)*
8 };
9}
10
11/// Changes the visibility to `pub` if feature "public-test-deps" is set
12#[cfg(feature = "public-test-deps")]
13macro_rules! public_test_dep {
14 {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => {
15 $(#[$($meta)*])* pub $ident $($tokens)*
16 };
17}
18
19/// The "main macro" used for defining intrinsics.
20///
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
26/// code.
27///
28/// When the weak-intrinsics feature is enabled, all intrinsics functions are
29/// marked with #[linkage = "weak"] so that they can be replaced by another
30/// implementation at link time. This is particularly useful for mixed Rust/C++
31/// binaries that want to use the C++ intrinsics, otherwise linking against the
32/// Rust stdlib will replace those from the compiler-rt library.
33///
34/// This macro is structured to be invoked with a bunch of functions that looks
35/// like:
36/// ```ignore
37/// intrinsics! {
38/// pub extern "C" fn foo(a: i32) -> u32 {
39/// // ...
40/// }
41///
42/// #[nonstandard_attribute]
43/// pub extern "C" fn bar(a: i32) -> u32 {
44/// // ...
45/// }
46/// }
47/// ```
48///
49/// Each function is defined in a manner that looks like a normal Rust function.
50/// The macro then accepts a few nonstandard attributes that can decorate
51/// various functions. Each of the attributes is documented below with what it
52/// can do, and each of them slightly tweaks how further expansion happens.
53///
54/// A quick overview of attributes supported right now are:
55///
56/// * `weak` - indicates that the function should always be given weak linkage.
57/// This attribute must come before other attributes, as the other attributes
58/// will generate the final output function and need to have `weak` modify
59/// them.
60/// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is
61/// ignored if an optimized C version was compiled.
62/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
63/// the specified ABI everywhere else.
64/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
65/// `"unadjusted"` abi on Win64 and the specified abi elsewhere.
66/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
67/// intrinsics where the ABI is slightly tweaked on Windows platforms, but
68/// it's a normal ABI elsewhere for returning a 128 bit integer.
69/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
70/// their otherwise typical names to other prefixed ones.
71macro_rules! intrinsics {
72 () => ();
73
74 // Support cfg_attr:
75 (
76 #[cfg_attr($e:meta, $($attr:tt)*)]
77 $(#[$($attrs:tt)*])*
78 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
79 $($body:tt)*
80 }
81 $($rest:tt)*
82 ) => (
83 #[cfg($e)]
84 intrinsics! {
85 #[$($attr)*]
86 $(#[$($attrs)*])*
87 pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? {
88 $($body)*
89 }
90 }
91
92 #[cfg(not($e))]
93 intrinsics! {
94 $(#[$($attrs)*])*
95 pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? {
96 $($body)*
97 }
98 }
99
100 intrinsics!($($rest)*);
101 );
102 // Same as above but for unsafe.
103 (
104 #[cfg_attr($e:meta, $($attr:tt)*)]
105 $(#[$($attrs:tt)*])*
106 pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
107 $($body:tt)*
108 }
109 $($rest:tt)*
110 ) => (
111 #[cfg($e)]
112 intrinsics! {
113 #[$($attr)*]
114 $(#[$($attrs)*])*
115 pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? {
116 $($body)*
117 }
118 }
119
120 #[cfg(not($e))]
121 intrinsics! {
122 $(#[$($attrs)*])*
123 pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? {
124 $($body)*
125 }
126 }
127
128 intrinsics!($($rest)*);
129 );
130
131 // Explicit weak linkage gets dropped when weak-intrinsics is on since it
132 // will be added unconditionally to all intrinsics and would conflict
133 // otherwise.
134 (
135 #[weak]
136 $(#[$($attr:tt)*])*
137 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
138 $($body:tt)*
139 }
140
141 $($rest:tt)*
142 ) => (
143 #[cfg(feature = "weak-intrinsics")]
144 intrinsics! {
145 $(#[$($attr)*])*
146 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
147 $($body)*
148 }
149 }
150
151 #[cfg(not(feature = "weak-intrinsics"))]
152 intrinsics! {
153 $(#[$($attr)*])*
154 #[linkage = "weak"]
155 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
156 $($body)*
157 }
158 }
159
160 intrinsics!($($rest)*);
161 );
162 // Same as above but for unsafe.
163 (
164 #[weak]
165 $(#[$($attr:tt)*])*
166 pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
167 $($body:tt)*
168 }
169
170 $($rest:tt)*
171 ) => (
172 #[cfg(feature = "weak-intrinsics")]
173 intrinsics! {
174 $(#[$($attr)*])*
175 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
176 $($body)*
177 }
178 }
179
180 #[cfg(not(feature = "weak-intrinsics"))]
181 intrinsics! {
182 $(#[$($attr)*])*
183 #[linkage = "weak"]
184 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
185 $($body)*
186 }
187 }
188
189 intrinsics!($($rest)*);
190 );
191
192 // Right now there's a bunch of architecture-optimized intrinsics in the
193 // stock compiler-rt implementation. Not all of these have been ported over
194 // to Rust yet so when the `c` feature of this crate is enabled we fall back
195 // to the architecture-specific versions which should be more optimized. The
196 // purpose of this macro is to easily allow specifying this.
197 //
198 // The `#[maybe_use_optimized_c_shim]` attribute indicates that this
199 // intrinsic may have an optimized C version. In these situations the build
200 // script, if the C code is enabled and compiled, will emit a cfg directive
201 // to get passed to rustc for our compilation. If that cfg is set we skip
202 // the Rust implementation, but if the attribute is not enabled then we
203 // compile in the Rust implementation.
204 (
205 #[maybe_use_optimized_c_shim]
206 $(#[$($attr:tt)*])*
207 pub $(unsafe $(@ $empty:tt)? )? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
208 $($body:tt)*
209 }
210
211 $($rest:tt)*
212 ) => (
213 #[cfg($name = "optimized-c")]
214 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
215 pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
216 extern $abi {
217 fn $name($($argname: $ty),*) $(-> $ret)?;
218 }
219 unsafe {
220 $name($($argname),*)
221 }
222 }
223
224 #[cfg(not($name = "optimized-c"))]
225 intrinsics! {
226 $(#[$($attr)*])*
227 pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
228 $($body)*
229 }
230 }
231
232 intrinsics!($($rest)*);
233 );
234
235 // We recognize the `#[aapcs_on_arm]` attribute here and generate the
236 // same intrinsic but force it to have the `"aapcs"` calling convention on
237 // ARM and `"C"` elsewhere.
238 (
239 #[aapcs_on_arm]
240 $(#[$($attr:tt)*])*
241 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
242 $($body:tt)*
243 }
244
245 $($rest:tt)*
246 ) => (
247 #[cfg(target_arch = "arm")]
248 intrinsics! {
249 $(#[$($attr)*])*
250 pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? {
251 $($body)*
252 }
253 }
254
255 #[cfg(not(target_arch = "arm"))]
256 intrinsics! {
257 $(#[$($attr)*])*
258 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
259 $($body)*
260 }
261 }
262
263 intrinsics!($($rest)*);
264 );
265
266 // Like aapcs above we recognize an attribute for the "unadjusted" abi on
267 // win64 for some methods.
268 (
269 #[unadjusted_on_win64]
270 $(#[$($attr:tt)*])*
271 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
272 $($body:tt)*
273 }
274
275 $($rest:tt)*
276 ) => (
277 #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))]
278 intrinsics! {
279 $(#[$($attr)*])*
280 pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? {
281 $($body)*
282 }
283 }
284
285 #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))]
286 intrinsics! {
287 $(#[$($attr)*])*
288 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
289 $($body)*
290 }
291 }
292
293 intrinsics!($($rest)*);
294 );
295
296 // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
297 // calling convention. That's managed here with this "abi hack" which alters
298 // the generated symbol's ABI.
299 //
300 // This will still define a function in this crate with the given name and
301 // signature, but the actual symbol for the intrinsic may have a slightly
302 // different ABI on win64.
303 (
304 #[win64_128bit_abi_hack]
305 $(#[$($attr:tt)*])*
306 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
307 $($body:tt)*
308 }
309
310 $($rest:tt)*
311 ) => (
312 #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))]
313 $(#[$($attr)*])*
314 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
315 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
316 $($body)*
317 }
318
319 #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))]
320 pub mod $name {
321 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
322 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
323 pub extern $abi fn $name( $($argname: $ty),* )
324 -> $crate::macros::win64_128bit_abi_hack::U64x2
325 {
326 let e: $($ret)? = super::$name($($argname),*);
327 $crate::macros::win64_128bit_abi_hack::U64x2::from(e)
328 }
329 }
330
331 #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))]
332 intrinsics! {
333 $(#[$($attr)*])*
334 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
335 $($body)*
336 }
337 }
338
339 intrinsics!($($rest)*);
340 );
341
342 // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
343 // build under `__aeabi_*` aliases, and LLVM will call these instead of the
344 // original function. The aliasing here is used to generate these symbols in
345 // the object file.
346 (
347 #[arm_aeabi_alias = $alias:ident]
348 $(#[$($attr:tt)*])*
349 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
350 $($body:tt)*
351 }
352
353 $($rest:tt)*
354 ) => (
355 #[cfg(target_arch = "arm")]
356 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
357 $($body)*
358 }
359
360 #[cfg(target_arch = "arm")]
361 pub mod $name {
362 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
363 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
364 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
365 super::$name($($argname),*)
366 }
367 }
368
369 #[cfg(target_arch = "arm")]
370 pub mod $alias {
371 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
372 #[cfg_attr(any(all(not(windows), not(target_vendor="apple")), feature = "weak-intrinsics"), linkage = "weak")]
373 pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? {
374 super::$name($($argname),*)
375 }
376 }
377
378 #[cfg(not(target_arch = "arm"))]
379 intrinsics! {
380 $(#[$($attr)*])*
381 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
382 $($body)*
383 }
384 }
385
386 intrinsics!($($rest)*);
387 );
388
389 // C mem* functions are only generated when the "mem" feature is enabled.
390 (
391 #[mem_builtin]
392 $(#[$($attr:tt)*])*
393 pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
394 $($body:tt)*
395 }
396
397 $($rest:tt)*
398 ) => (
399 $(#[$($attr)*])*
400 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
401 $($body)*
402 }
403
404 #[cfg(feature = "mem")]
405 pub mod $name {
406 $(#[$($attr)*])*
407 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
408 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
409 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
410 super::$name($($argname),*)
411 }
412 }
413
414 intrinsics!($($rest)*);
415 );
416
417 // Naked functions are special: we can't generate wrappers for them since
418 // they use a custom calling convention.
419 (
420 #[naked]
421 $(#[$($attr:tt)*])*
422 pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
423 $($body:tt)*
424 }
425
426 $($rest:tt)*
427 ) => (
428 pub mod $name {
429 #[naked]
430 $(#[$($attr)*])*
431 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
432 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
433 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
434 $($body)*
435 }
436 }
437
438 intrinsics!($($rest)*);
439 );
440
441 // For some intrinsics, AVR uses a custom calling convention¹ that does not
442 // match our definitions here. Ideally we would just use hand-written naked
443 // functions, but that's quite a lot of code to port² - so for the time
444 // being we are just ignoring the problematic functions, letting avr-gcc
445 // (which is required to compile to AVR anyway) link them from libgcc.
446 //
447 // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling
448 // Convention")
449 // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S
450 (
451 #[avr_skip]
452 $(#[$($attr:tt)*])*
453 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
454 $($body:tt)*
455 }
456
457 $($rest:tt)*
458 ) => (
459 #[cfg(not(target_arch = "avr"))]
460 intrinsics! {
461 $(#[$($attr)*])*
462 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
463 $($body)*
464 }
465 }
466
467 intrinsics!($($rest)*);
468 );
469
470 // This is the final catch-all rule. At this point we generate an
471 // intrinsic with a conditional `#[no_mangle]` directive to avoid
472 // interfering with duplicate symbols and whatnot during testing.
473 //
474 // The implementation is placed in a separate module, to take advantage
475 // of the fact that rustc partitions functions into code generation
476 // units based on module they are defined in. As a result we will have
477 // a separate object file for each intrinsic. For further details see
478 // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846
479 //
480 // After the intrinsic is defined we just continue with the rest of the
481 // input we were given.
482 (
483 $(#[$($attr:tt)*])*
484 pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
485 $($body:tt)*
486 }
487
488 $($rest:tt)*
489 ) => (
490 $(#[$($attr)*])*
491 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
492 $($body)*
493 }
494
495 pub mod $name {
496 $(#[$($attr)*])*
497 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
498 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
499 pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
500 super::$name($($argname),*)
501 }
502 }
503
504 intrinsics!($($rest)*);
505 );
506
507 // Same as the above for unsafe functions.
508 (
509 $(#[$($attr:tt)*])*
510 pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
511 $($body:tt)*
512 }
513
514 $($rest:tt)*
515 ) => (
516 $(#[$($attr)*])*
517 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
518 $($body)*
519 }
520
521 pub mod $name {
522 $(#[$($attr)*])*
523 #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
524 #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")]
525 pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
526 super::$name($($argname),*)
527 }
528 }
529
530 intrinsics!($($rest)*);
531 );
532}
533
534// Hack for LLVM expectations for ABI on windows. This is used by the
535// `#[win64_128bit_abi_hack]` attribute recognized above
536#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))]
537pub mod win64_128bit_abi_hack {
538 #[repr(simd)]
539 pub struct U64x2(u64, u64);
540
541 impl From<i128> for U64x2 {
542 fn from(i: i128) -> U64x2 {
543 use crate::int::DInt;
544 let j = i as u128;
545 U64x2(j.lo(), j.hi())
546 }
547 }
548
549 impl From<u128> for U64x2 {
550 fn from(i: u128) -> U64x2 {
551 use crate::int::DInt;
552 U64x2(i.lo(), i.hi())
553 }
554 }
555}
556