macros.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. //! Macros shared throughout the compiler-builtins implementation
  2. /// Changes the visibility to `pub` if feature "public-test-deps" is set
  3. #[cfg(not(feature = "public-test-deps"))]
  4. macro_rules! public_test_dep {
  5. ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => {
  6. $(#[$($meta)*])* pub(crate) $ident $($tokens)*
  7. };
  8. }
  9. /// Changes the visibility to `pub` if feature "public-test-deps" is set
  10. #[cfg(feature = "public-test-deps")]
  11. macro_rules! public_test_dep {
  12. {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => {
  13. $(#[$($meta)*])* pub $ident $($tokens)*
  14. };
  15. }
  16. /// The "main macro" used for defining intrinsics.
  17. ///
  18. /// The compiler-builtins library is super platform-specific with tons of crazy
  19. /// little tweaks for various platforms. As a result it *could* involve a lot of
  20. /// #[cfg] and macro soup, but the intention is that this macro alleviates a lot
  21. /// of that complexity. Ideally this macro has all the weird ABI things
  22. /// platforms need and elsewhere in this library it just looks like normal Rust
  23. /// code.
  24. ///
  25. /// This macro is structured to be invoked with a bunch of functions that looks
  26. /// like:
  27. ///
  28. /// intrinsics! {
  29. /// pub extern "C" fn foo(a: i32) -> u32 {
  30. /// // ...
  31. /// }
  32. ///
  33. /// #[nonstandard_attribute]
  34. /// pub extern "C" fn bar(a: i32) -> u32 {
  35. /// // ...
  36. /// }
  37. /// }
  38. ///
  39. /// Each function is defined in a manner that looks like a normal Rust function.
  40. /// The macro then accepts a few nonstandard attributes that can decorate
  41. /// various functions. Each of the attributes is documented below with what it
  42. /// can do, and each of them slightly tweaks how further expansion happens.
  43. ///
  44. /// A quick overview of attributes supported right now are:
  45. ///
  46. /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is
  47. /// ignored if an optimized C version was compiled.
  48. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
  49. /// the specified ABI everywhere else.
  50. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
  51. /// `"unadjusted"` abi on Win64 and the specified abi elsewhere.
  52. /// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
  53. /// intrinsics where the ABI is slightly tweaked on Windows platforms, but
  54. /// it's a normal ABI elsewhere for returning a 128 bit integer.
  55. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
  56. /// their otherwise typical names to other prefixed ones.
  57. ///
  58. macro_rules! intrinsics {
  59. () => ();
  60. // Right now there's a bunch of architecture-optimized intrinsics in the
  61. // stock compiler-rt implementation. Not all of these have been ported over
  62. // to Rust yet so when the `c` feature of this crate is enabled we fall back
  63. // to the architecture-specific versions which should be more optimized. The
  64. // purpose of this macro is to easily allow specifying this.
  65. //
  66. // The `#[maybe_use_optimized_c_shim]` attribute indicates that this
  67. // intrinsic may have an optimized C version. In these situations the build
  68. // script, if the C code is enabled and compiled, will emit a cfg directive
  69. // to get passed to rustc for our compilation. If that cfg is set we skip
  70. // the Rust implementation, but if the attribute is not enabled then we
  71. // compile in the Rust implementation.
  72. (
  73. #[maybe_use_optimized_c_shim]
  74. $(#[$($attr:tt)*])*
  75. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  76. $($body:tt)*
  77. }
  78. $($rest:tt)*
  79. ) => (
  80. #[cfg($name = "optimized-c")]
  81. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  82. extern $abi {
  83. fn $name($($argname: $ty),*) $(-> $ret)?;
  84. }
  85. unsafe {
  86. $name($($argname),*)
  87. }
  88. }
  89. #[cfg(not($name = "optimized-c"))]
  90. intrinsics! {
  91. $(#[$($attr)*])*
  92. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  93. $($body)*
  94. }
  95. }
  96. intrinsics!($($rest)*);
  97. );
  98. // We recognize the `#[aapcs_on_arm]` attribute here and generate the
  99. // same intrinsic but force it to have the `"aapcs"` calling convention on
  100. // ARM and `"C"` elsewhere.
  101. (
  102. #[aapcs_on_arm]
  103. $(#[$($attr:tt)*])*
  104. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  105. $($body:tt)*
  106. }
  107. $($rest:tt)*
  108. ) => (
  109. #[cfg(target_arch = "arm")]
  110. intrinsics! {
  111. $(#[$($attr)*])*
  112. pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? {
  113. $($body)*
  114. }
  115. }
  116. #[cfg(not(target_arch = "arm"))]
  117. intrinsics! {
  118. $(#[$($attr)*])*
  119. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  120. $($body)*
  121. }
  122. }
  123. intrinsics!($($rest)*);
  124. );
  125. // Like aapcs above we recognize an attribute for the "unadjusted" abi on
  126. // win64 for some methods.
  127. (
  128. #[unadjusted_on_win64]
  129. $(#[$($attr:tt)*])*
  130. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  131. $($body:tt)*
  132. }
  133. $($rest:tt)*
  134. ) => (
  135. #[cfg(all(windows, target_pointer_width = "64"))]
  136. intrinsics! {
  137. $(#[$($attr)*])*
  138. pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? {
  139. $($body)*
  140. }
  141. }
  142. #[cfg(not(all(windows, target_pointer_width = "64")))]
  143. intrinsics! {
  144. $(#[$($attr)*])*
  145. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  146. $($body)*
  147. }
  148. }
  149. intrinsics!($($rest)*);
  150. );
  151. // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
  152. // calling convention. That's managed here with this "abi hack" which alters
  153. // the generated symbol's ABI.
  154. //
  155. // This will still define a function in this crate with the given name and
  156. // signature, but the actual symbol for the intrinsic may have a slightly
  157. // different ABI on win64.
  158. (
  159. #[win64_128bit_abi_hack]
  160. $(#[$($attr:tt)*])*
  161. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  162. $($body:tt)*
  163. }
  164. $($rest:tt)*
  165. ) => (
  166. #[cfg(all(windows, target_arch = "x86_64"))]
  167. $(#[$($attr)*])*
  168. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  169. $($body)*
  170. }
  171. #[cfg(all(windows, target_arch = "x86_64"))]
  172. pub mod $name {
  173. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  174. pub extern $abi fn $name( $($argname: $ty),* )
  175. -> ::macros::win64_128bit_abi_hack::U64x2
  176. {
  177. let e: $($ret)? = super::$name($($argname),*);
  178. ::macros::win64_128bit_abi_hack::U64x2::from(e)
  179. }
  180. }
  181. #[cfg(not(all(windows, target_arch = "x86_64")))]
  182. intrinsics! {
  183. $(#[$($attr)*])*
  184. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  185. $($body)*
  186. }
  187. }
  188. intrinsics!($($rest)*);
  189. );
  190. // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
  191. // build under `__aeabi_*` aliases, and LLVM will call these instead of the
  192. // original function. The aliasing here is used to generate these symbols in
  193. // the object file.
  194. (
  195. #[arm_aeabi_alias = $alias:ident]
  196. $(#[$($attr:tt)*])*
  197. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  198. $($body:tt)*
  199. }
  200. $($rest:tt)*
  201. ) => (
  202. #[cfg(target_arch = "arm")]
  203. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  204. $($body)*
  205. }
  206. #[cfg(target_arch = "arm")]
  207. pub mod $name {
  208. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  209. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  210. super::$name($($argname),*)
  211. }
  212. }
  213. #[cfg(target_arch = "arm")]
  214. pub mod $alias {
  215. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  216. pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? {
  217. super::$name($($argname),*)
  218. }
  219. }
  220. #[cfg(not(target_arch = "arm"))]
  221. intrinsics! {
  222. $(#[$($attr)*])*
  223. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  224. $($body)*
  225. }
  226. }
  227. intrinsics!($($rest)*);
  228. );
  229. // C mem* functions are only generated when the "mem" feature is enabled.
  230. (
  231. #[mem_builtin]
  232. $(#[$($attr:tt)*])*
  233. pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  234. $($body:tt)*
  235. }
  236. $($rest:tt)*
  237. ) => (
  238. $(#[$($attr)*])*
  239. pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  240. $($body)*
  241. }
  242. #[cfg(feature = "mem")]
  243. pub mod $name {
  244. $(#[$($attr)*])*
  245. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  246. pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  247. super::$name($($argname),*)
  248. }
  249. }
  250. intrinsics!($($rest)*);
  251. );
  252. // Naked functions are special: we can't generate wrappers for them since
  253. // they use a custom calling convention.
  254. (
  255. #[naked]
  256. $(#[$($attr:tt)*])*
  257. pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  258. $($body:tt)*
  259. }
  260. $($rest:tt)*
  261. ) => (
  262. pub mod $name {
  263. #[naked]
  264. $(#[$($attr)*])*
  265. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  266. pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  267. $($body)*
  268. }
  269. }
  270. intrinsics!($($rest)*);
  271. );
  272. // This is the final catch-all rule. At this point we generate an
  273. // intrinsic with a conditional `#[no_mangle]` directive to avoid
  274. // interfering with duplicate symbols and whatnot during testing.
  275. //
  276. // The implementation is placed in a separate module, to take advantage
  277. // of the fact that rustc partitions functions into code generation
  278. // units based on module they are defined in. As a result we will have
  279. // a separate object file for each intrinsic. For further details see
  280. // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846
  281. //
  282. // After the intrinsic is defined we just continue with the rest of the
  283. // input we were given.
  284. (
  285. $(#[$($attr:tt)*])*
  286. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  287. $($body:tt)*
  288. }
  289. $($rest:tt)*
  290. ) => (
  291. $(#[$($attr)*])*
  292. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  293. $($body)*
  294. }
  295. pub mod $name {
  296. $(#[$($attr)*])*
  297. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  298. pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  299. super::$name($($argname),*)
  300. }
  301. }
  302. intrinsics!($($rest)*);
  303. );
  304. // Same as the above for unsafe functions.
  305. (
  306. $(#[$($attr:tt)*])*
  307. pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
  308. $($body:tt)*
  309. }
  310. $($rest:tt)*
  311. ) => (
  312. $(#[$($attr)*])*
  313. pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  314. $($body)*
  315. }
  316. pub mod $name {
  317. $(#[$($attr)*])*
  318. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  319. pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
  320. super::$name($($argname),*)
  321. }
  322. }
  323. intrinsics!($($rest)*);
  324. );
  325. }
  326. // Hack for LLVM expectations for ABI on windows. This is used by the
  327. // `#[win64_128bit_abi_hack]` attribute recognized above
  328. #[cfg(all(windows, target_pointer_width = "64"))]
  329. pub mod win64_128bit_abi_hack {
  330. #[repr(simd)]
  331. pub struct U64x2(u64, u64);
  332. impl From<i128> for U64x2 {
  333. fn from(i: i128) -> U64x2 {
  334. use int::DInt;
  335. let j = i as u128;
  336. U64x2(j.lo(), j.hi())
  337. }
  338. }
  339. impl From<u128> for U64x2 {
  340. fn from(i: u128) -> U64x2 {
  341. use int::DInt;
  342. U64x2(i.lo(), i.hi())
  343. }
  344. }
  345. }