diff options
author | Aria Beingessner <a.beingessner@gmail.com> | 2022-03-09 01:42:43 -0500 |
---|---|---|
committer | Aria Beingessner <a.beingessner@gmail.com> | 2022-03-23 18:21:00 -0400 |
commit | adfa38507c1aa4adce7010a58825af35a1f5fb99 (patch) | |
tree | 690ae45788aa6aec9385d9c1015d73cb87cb775d /src/fixed_width_ints.rs | |
parent | 1708299c6b49e9fb7e7c34b9edd37c77e7af003c (diff) | |
download | rust-libc-adfa38507c1aa4adce7010a58825af35a1f5fb99.tar.gz |
Create optionally-available __int128 typedefs and use them for ARM64 definitions.
This adds the following types to fixed_width_ints behind appropriate platform cfgs:
* __int128
* __int128_t
* __uint128
* __uint128_t
and user_fpsimd_struct to arm64 android and linux.
Diffstat (limited to 'src/fixed_width_ints.rs')
-rw-r--r-- | src/fixed_width_ints.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/fixed_width_ints.rs b/src/fixed_width_ints.rs index 014640855f..44cf8b592e 100644 --- a/src/fixed_width_ints.rs +++ b/src/fixed_width_ints.rs @@ -18,3 +18,78 @@ pub type uint16_t = u16; pub type uint32_t = u32; #[deprecated(since = "0.2.55", note = "Use u64 instead.")] pub type uint64_t = u64; + +cfg_if! { + if #[cfg(all(libc_int128, target_arch = "aarch64", not(target_os = "windows")))] { + // This introduces partial support for FFI with __int128 and + // equivalent types on platforms where Rust's definition is validated + // to match the standard C ABI of that platform. + // + // Rust does not guarantee u128/i128 are sound for FFI, and its + // definitions are in fact known to be incompatible. [0] + // + // However these problems aren't fundamental, and are just platform + // inconsistencies. Specifically at the time of this writing: + // + // * For x64 SysV ABIs (everything but Windows), the types are underaligned. + // * For all Windows ABIs, Microsoft doesn't actually officially define __int128, + // and as a result different implementations don't actually agree on its ABI. + // + // But on the other major aarch64 platforms (android, linux, ios, macos) we have + // validated that rustc has the right ABI for these types. This is important because + // aarch64 uses these types in some fundamental OS types like user_fpsimd_struct, + // which represents saved simd registers. + // + // Any API which uses these types will need to `#[ignore(improper_ctypes)]` + // until the upstream rust issue is resolved, but this at least lets us make + // progress on platforms where this type is important. + // + // The supported architectures and OSes is intentionally very restricted, + // as careful work needs to be done to verify that a particular platform + // has a conformant ABI. + // + // [0]: https://github.com/rust-lang/rust/issues/54341 + + /// C `__int128` (a GCC extension that's part of many ABIs) + pub type __int128 = i128; + /// C `unsigned __int128` (a GCC extension that's part of many ABIs) + pub type __uint128 = u128; + /// C __int128_t (alternate name for [__int128][]) + pub type __int128_t = i128; + /// C __uint128_t (alternate name for [__uint128][]) + pub type __uint128_t = u128; + + cfg_if! { + if #[cfg(libc_const_assert)] { + // NOTE: if you add more platforms to here, you may need to cfg + // these consts. They should always match the platform's values + // for `sizeof(__int128)` and `_Alignof(__int128)`. + const _SIZE_128: usize = 16; + const _ALIGN_128: usize = 16; + + /// Since Rust doesn't officially guarantee that these types + /// have compatible ABIs, we const assert that these values have the + /// known size/align of the target platform's libc. If rustc ever + /// tries to regress things, it will cause a compilation error. + /// + /// This isn't a bullet-proof solution because e.g. it doesn't + /// catch the fact that llvm and gcc disagree on how x64 __int128 + /// is actually *passed* on the stack (clang underaligns it for + /// the same reason that rustc *never* properly aligns it). + const _ASSERT_128_COMPAT: () = { + assert!(core::mem::size_of::<__int128>() == _SIZE_128); + assert!(core::mem::align_of::<__int128>() == _ALIGN_128); + + assert!(core::mem::size_of::<__uint128>() == _SIZE_128); + assert!(core::mem::align_of::<__uint128>() == _ALIGN_128); + + assert!(core::mem::size_of::<__int128_t>() == _SIZE_128); + assert!(core::mem::align_of::<__int128_t>() == _ALIGN_128); + + assert!(core::mem::size_of::<__uint128_t>() == _SIZE_128); + assert!(core::mem::align_of::<__uint128_t>() == _ALIGN_128); + }; + } + } + } +} |