macros.rs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. /// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the
  33. /// C-compiled version if `use_c` is specified.
  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 argument to `use_c_shim_if` is a `#[cfg]` directive which, when true,
  53. // will cause this crate's exported version of `$name` to just redirect to
  54. // the C implementation. No symbol named `$name` will be in the object file
  55. // for this crate itself.
  56. //
  57. // When the `#[cfg]` directive is false, or when the `c` feature is
  58. // disabled, the provided implementation is used instead.
  59. (
  60. #[use_c_shim_if($($cfg_clause:tt)*)]
  61. $(#[$($attr:tt)*])*
  62. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  63. $($body:tt)*
  64. }
  65. $($rest:tt)*
  66. ) => (
  67. #[cfg(all(use_c, $($cfg_clause)*))]
  68. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  69. extern $abi {
  70. fn $name($($argname: $ty),*) -> $ret;
  71. }
  72. unsafe {
  73. $name($($argname),*)
  74. }
  75. }
  76. #[cfg(not(all(use_c, $($cfg_clause)*)))]
  77. intrinsics! {
  78. $(#[$($attr)*])*
  79. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  80. $($body)*
  81. }
  82. }
  83. intrinsics!($($rest)*);
  84. );
  85. // We recognize the `#[aapcs_on_arm]` attribute here and generate the
  86. // same intrinsic but force it to have the `"aapcs"` calling convention on
  87. // ARM and `"C"` elsewhere.
  88. (
  89. #[aapcs_on_arm]
  90. $(#[$($attr:tt)*])*
  91. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  92. $($body:tt)*
  93. }
  94. $($rest:tt)*
  95. ) => (
  96. #[cfg(target_arch = "arm")]
  97. intrinsics! {
  98. $(#[$($attr)*])*
  99. pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret {
  100. $($body)*
  101. }
  102. }
  103. #[cfg(not(target_arch = "arm"))]
  104. intrinsics! {
  105. $(#[$($attr)*])*
  106. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  107. $($body)*
  108. }
  109. }
  110. intrinsics!($($rest)*);
  111. );
  112. // Like aapcs above we recognize an attribute for the "unadjusted" abi on
  113. // win64 for some methods.
  114. (
  115. #[unadjusted_on_win64]
  116. $(#[$($attr:tt)*])*
  117. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  118. $($body:tt)*
  119. }
  120. $($rest:tt)*
  121. ) => (
  122. #[cfg(all(windows, target_pointer_width = "64"))]
  123. intrinsics! {
  124. $(#[$($attr)*])*
  125. pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret {
  126. $($body)*
  127. }
  128. }
  129. #[cfg(not(all(windows, target_pointer_width = "64")))]
  130. intrinsics! {
  131. $(#[$($attr)*])*
  132. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  133. $($body)*
  134. }
  135. }
  136. intrinsics!($($rest)*);
  137. );
  138. // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
  139. // calling convention. That's managed here with this "abi hack" which alters
  140. // the generated symbol's ABI.
  141. //
  142. // This will still define a function in this crate with the given name and
  143. // signature, but the actual symbol for the intrinsic may have a slightly
  144. // different ABI on win64.
  145. (
  146. #[win64_128bit_abi_hack]
  147. $(#[$($attr:tt)*])*
  148. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  149. $($body:tt)*
  150. }
  151. $($rest:tt)*
  152. ) => (
  153. #[cfg(all(windows, target_pointer_width = "64"))]
  154. $(#[$($attr)*])*
  155. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  156. $($body)*
  157. }
  158. #[cfg(all(windows, target_pointer_width = "64"))]
  159. pub mod $name {
  160. intrinsics! {
  161. pub extern $abi fn $name( $($argname: $ty),* )
  162. -> ::macros::win64_128bit_abi_hack::U64x2
  163. {
  164. let e: $ret = super::$name($($argname),*);
  165. ::macros::win64_128bit_abi_hack::U64x2::from(e)
  166. }
  167. }
  168. }
  169. #[cfg(not(all(windows, target_pointer_width = "64")))]
  170. intrinsics! {
  171. $(#[$($attr)*])*
  172. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  173. $($body)*
  174. }
  175. }
  176. intrinsics!($($rest)*);
  177. );
  178. // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
  179. // build under `__aeabi_*` aliases, and LLVM will call these instead of the
  180. // original function. The aliasing here is used to generate these symbols in
  181. // the object file.
  182. (
  183. #[arm_aeabi_alias = $alias:ident]
  184. $(#[$($attr:tt)*])*
  185. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  186. $($body:tt)*
  187. }
  188. $($rest:tt)*
  189. ) => (
  190. #[cfg(target_arch = "arm")]
  191. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  192. $($body)*
  193. }
  194. #[cfg(target_arch = "arm")]
  195. pub mod $name {
  196. intrinsics! {
  197. pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret {
  198. super::$name($($argname),*)
  199. }
  200. }
  201. }
  202. #[cfg(not(target_arch = "arm"))]
  203. intrinsics! {
  204. $(#[$($attr)*])*
  205. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  206. $($body)*
  207. }
  208. }
  209. intrinsics!($($rest)*);
  210. );
  211. // This is the final catch-all rule. At this point we just generate an
  212. // intrinsic with a conditional `#[no_mangle]` directive to avoid
  213. // interfereing with duplicate symbols and whatnot during testing.
  214. //
  215. // After the intrinsic is defined we just continue with the rest of the
  216. // input we were given.
  217. (
  218. $(#[$($attr:tt)*])*
  219. pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  220. $($body:tt)*
  221. }
  222. $($rest:tt)*
  223. ) => (
  224. $(#[$($attr)*])*
  225. #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
  226. pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
  227. $($body)*
  228. }
  229. intrinsics!($($rest)*);
  230. );
  231. }
  232. // Hack for LLVM expectations for ABI on windows. This is used by the
  233. // `#[win64_128bit_abi_hack]` attribute recognized above
  234. #[cfg(all(windows, target_pointer_width="64"))]
  235. pub mod win64_128bit_abi_hack {
  236. #[repr(simd)]
  237. pub struct U64x2(u64, u64);
  238. impl From<i128> for U64x2 {
  239. fn from(i: i128) -> U64x2 {
  240. use int::LargeInt;
  241. let j = i as u128;
  242. U64x2(j.low(), j.high())
  243. }
  244. }
  245. impl From<u128> for U64x2 {
  246. fn from(i: u128) -> U64x2 {
  247. use int::LargeInt;
  248. U64x2(i.low(), i.high())
  249. }
  250. }
  251. }
  252. macro_rules! u128_lang_items {
  253. ($(
  254. #[lang = $lang:tt]
  255. pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
  256. $($body:tt)*
  257. }
  258. )*) => ($(
  259. #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)]
  260. pub fn $name( $($argname: $ty),* ) -> $ret {
  261. $($body)*
  262. }
  263. )*)
  264. }