Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create optionally-available __int128 typedefs and use them for ARM64 definitions. #2719

Merged
merged 1 commit into from
Mar 24, 2022

Conversation

Gankra
Copy link
Contributor

@Gankra Gankra commented Mar 9, 2022

Potentially fixes #2524, see the comments in the patch for details.

@rust-highfive
Copy link

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Amanieu (or someone else) soon.

Please see the contribution instructions for more information.

@Gankra
Copy link
Contributor Author

Gankra commented Mar 9, 2022

See rust-lang/rust#54341 (comment) for details on my investigation into this.

I will happily fill in more OS/arches if anyone can run https://github.com/Gankra/abi-checker on that target and get full passes. I only have access to aarch64 Android (phone) and macOS (coworker). I'm kinda blindly assuming iOS is the same as macOS here.

@Gankra
Copy link
Contributor Author

Gankra commented Mar 9, 2022

For context, properly defining these types is important for saving a crashing process' registers (i.e. when generating a breakpad-style minidump, which I am currently working on porting to Rust for Android).

src/fixed_width_ints.rs Outdated Show resolved Hide resolved
@Gankra
Copy link
Contributor Author

Gankra commented Mar 9, 2022

In the upstream issue nagisa notes that rust uniformly has this repr on all aarch64 targets -- but I'd still like to verify that the primary C compilers for those targets agree.

Copy link
Member

@Amanieu Amanieu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I think this was sorely needed.

src/unix/linux_like/android/b64/aarch64/mod.rs Outdated Show resolved Hide resolved

cfg_if! {
if #[cfg(all(target_arch = "aarch64",
any(target_os = "android", target_os="macos", target_os = "ios")))] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would feel comfortable just doing not(windows) here. That way all non-Windows platforms automatically get support and this is confirmed by the static assert.

@Gankra
Copy link
Contributor Author

Gankra commented Mar 11, 2022

So since putting up this PR I spent a bit more time digging into what can be done to polyfill this type on x64 (since SysV actually passes structs the same as ints, in general). Unfortunately on x64 (linux, at least) clang and gcc actually disagree on the pass-on-stack convention for __int128:

https://twitter.com/Gankra_/status/1502320041315946499

x64 SysV fails to specify what "pushing" a value actually means and so clang packs __int128 while gcc properly aligns it. This can introduce padding and differences and completely desynchronize the offsets to args.

In discussing this on Twitter some Apple engineers also pointed out that clang actually has macos-specific ABI differences for backcompat with itself (details vague, no documentation for this in general). Similarly a coworker noted that stuff like this is a problem for clang plugins when the plugin and compiler weren't both consistently built by clang or gcc.

This now has me increasingly paranoid about claiming u128/i128 are ABI-compatible on ARM64 without any way for me to properly compare gcc and clang both targetting these platforms. And also makes me less inclined to willy-nilly declare that Rust agrees with C compilers for "all non-windows OSes". Even asserting they agree on size and align isn't sufficient because the compilers can still disagree on how the value is pushed to the stack. :(

I'm not sure what libc's policy is on divergent impls for one platform, and how to declare one "canonical" over the others.

Unfortunately I can't really test this stuff out better -- the "gcc" on my phone's termux is just an alias for clang, and similarly I expect that will be the case for m1 macbooks.


If anyone has better access to arm64 platforms and can setup clang/gcc properly, they can test this out by checking out:

https://github.com/Gankra/abi-checker

and running

cargo run -- --tests ui128

This will compare CC to rustc and CC to itself. That is a good start for rust matching the "canonical" implementation.

To exhaustively try out all the combos of clang+gcc+rust to check if the ABI is actually consistent between all impls, you can do:

cargo run -- --tests ui128 --pairs clang_calls_gcc gcc_calls_clang rustc_calls_gcc gcc_calls_rustc rustc_calls_clang clang_calls_rustc clang_calls_clang gcc_calls_gcc rustc_calls_rustc

Otherwise you can manually do something like this godbolt.

@Amanieu
Copy link
Member

Amanieu commented Mar 12, 2022

I ran your ABI checker on AArch64 Linux, all the tests pass:

Final Results:
ui128::c::clang_calls_gcc        all 226/226 passed
ui128::c::gcc_calls_clang        all 226/226 passed
ui128::c::rustc_calls_gcc        all 226/226 passed
ui128::c::gcc_calls_rustc        all 226/226 passed
ui128::c::rustc_calls_clang      all 226/226 passed
ui128::c::clang_calls_rustc      all 226/226 passed
ui128::c::clang_calls_clang      all 226/226 passed
ui128::c::gcc_calls_gcc          all 226/226 passed
ui128::c::rustc_calls_rustc      all 226/226 passed
ui128::cdecl::rustc_calls_rustc  all 226/226 passed
ui128::stdcall::rustc_calls_rustc all 226/226 passed
ui128::fastcall::rustc_calls_rustc all 226/226 passed

2712 passed, 0 failed, 0 completely failed, 33 skipped

@Gankra
Copy link
Contributor Author

Gankra commented Mar 12, 2022

Oh nice!! that helps my confidence with going forward with this a lot. I'll clean this up on monday.

@Gankra
Copy link
Contributor Author

Gankra commented Mar 12, 2022

Also lmao @ rustc actually managing to do something on linux when you ask it to fastcall/stdcall with itself, I hadn't actually every tested that.

@Gankra
Copy link
Contributor Author

Gankra commented Mar 15, 2022

Applied review requests and squashed.

@Gankra Gankra changed the title WIP attempt to implement user_fpsimd_struct. Create optionally-available __int128 typedefs and use them for ARM64 definitions. Mar 15, 2022
@Amanieu
Copy link
Member

Amanieu commented Mar 17, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Mar 17, 2022

📌 Commit 3741d52 has been approved by Amanieu

@bors
Copy link
Contributor

bors commented Mar 17, 2022

⌛ Testing commit 3741d52 with merge ca04d09...

bors added a commit that referenced this pull request Mar 17, 2022
Create optionally-available __int128 typedefs and use them for ARM64 definitions.

Potentially fixes #2524, see the comments in the patch for details.
@bors
Copy link
Contributor

bors commented Mar 17, 2022

💔 Test failed - checks-actions

/// is actually *passed* on the stack (clang underaligns it for
/// the same reason that rustc *never* properly aligns it).
const _ASSERT_128_COMPAT: () = {
assert!(std::mem::size_of::<__int128>() == SIZE_128);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use core instead of std.

@@ -55,6 +55,12 @@ s! {
pub pc: u64,
pub pstate: u64,
}

pub struct user_fpsimd_struct {
pub vregs: [__uint128_t; 32],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type needs to be imported:

Suggested change
pub vregs: [__uint128_t; 32],
pub vregs: [::__uint128_t; 32],

@Gankra
Copy link
Contributor Author

Gankra commented Mar 18, 2022

ok!!! this one actually seems to work and satisfy the nightmare cfg macro rube-goldberg machine (remaining failures are the pre-existing ones in the repo itself).

@bors
Copy link
Contributor

bors commented Mar 18, 2022

💔 Test failed - checks-actions

@Gankra
Copy link
Contributor Author

Gankra commented Mar 18, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Mar 18, 2022

📌 Commit 127542f has been approved by Gankra

bors added a commit that referenced this pull request Mar 18, 2022
Create optionally-available __int128 typedefs and use them for ARM64 definitions.

Potentially fixes #2524, see the comments in the patch for details.
@bors
Copy link
Contributor

bors commented Mar 18, 2022

⌛ Testing commit 127542f with merge aeb1a4e...

@bors
Copy link
Contributor

bors commented Mar 18, 2022

💔 Test failed - checks-actions

…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.
@Gankra
Copy link
Contributor Author

Gankra commented Mar 23, 2022

ok coming back to this with a fresh mind and the design of libc i think now has congealed into a coherent form for me. Hopefully this works now...

@Gankra
Copy link
Contributor Author

Gankra commented Mar 23, 2022

@bors try

bors added a commit that referenced this pull request Mar 23, 2022
Create optionally-available __int128 typedefs and use them for ARM64 definitions.

Potentially fixes #2524, see the comments in the patch for details.
@bors
Copy link
Contributor

bors commented Mar 23, 2022

⌛ Trying commit adfa385 with merge 245c710...

@Gankra
Copy link
Contributor Author

Gankra commented Mar 23, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Mar 23, 2022

📌 Commit adfa385 has been approved by Gankra

@bors
Copy link
Contributor

bors commented Mar 23, 2022

⌛ Testing commit adfa385 with merge f00ea00...

@bors
Copy link
Contributor

bors commented Mar 24, 2022

☀️ Test successful - checks-actions, checks-cirrus-freebsd-11, checks-cirrus-freebsd-12, checks-cirrus-freebsd-13
Approved by: Gankra
Pushing f00ea00 to master...

@bors bors merged commit f00ea00 into rust-lang:master Mar 24, 2022
bors added a commit that referenced this pull request Mar 26, 2022
Two improvements of the latest i128 numbers change

Two improvements of #2719:

* First, a typo/grammar fix
* Second, a fix to avoid usage of the anti pattern of `==` inside an `assert` macro. Since a few releases, `assert` is usable inside `const` expressions, but for the purpose of `==`, superior alternatives exist that also work at compile time but print the two values at a mismatch. `assert_eq` is not yet usable in const contexts due to formatting.
bors added a commit that referenced this pull request Mar 27, 2022
Two improvements of the latest i128 numbers change

Two improvements of #2719:

* First, a typo/grammar fix
* Second, a fix to avoid usage of the anti pattern of `==` inside an `assert` macro. Since a few releases, `assert` is usable inside `const` expressions, but for the purpose of `==`, superior alternatives exist that also work at compile time but print the two values at a mismatch. `assert_eq` is not yet usable in const contexts due to formatting.
@Gankra Gankra mentioned this pull request Apr 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

user_fpsimd_struct on aarch64
6 participants