macros.rs 9.9 KB

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