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" ))] |
5 | macro_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" )] |
13 | macro_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. |
71 | macro_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" ))] |
537 | pub 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 | |