-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
PowerPC C ZST ABI fixes #64259
PowerPC C ZST ABI fixes #64259
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
r? @nagisa |
Ping from triage, any updates? @nagisa |
from triaging, requesting a different reviewer. ping @oli-obk can you take a look? |
@bors r+ Sorry for taking so long to look at this |
📌 Commit 0f0d17295d7d706cd0430b86965b4fc98886f92a has been approved by |
target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; | ||
let indirect_zst = match target.arch.as_ref() { | ||
"powerpc" | "s390x" | "sparc64" => true, | ||
"x86_64" => target.target_os == "windows" && target.target_env == "gnu", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One day I want to figure out how this happened.
At least for mingw it somewhat makes sense - the win64 ABI does something unusual by special-casing only powers of 2 (and 0 isn't a power of 2), and the interaction with the GNU extension allowing ZSTs was likely accidentally overlooked.
But what's up with the other architectures? Why do they care about ZSTs at all? Were these all bugs in the GCC support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddyb The spec and the code driving this are quite simple: aggregates are passed by reference, full stop. There is no exception based on the size of the aggregate. Or in other words, they don't care about ZSTs, while rust does.
The PowerPC SVR4 psABI is linked above, and the gcc code driving this is rs6000_pass_by_reference() (with the if (DEFAULT_ABI == ABI_V4 && AGGREGATE_TYPE_P (type))
condition on line 12254).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or in other words, they don't care about ZSTs, while rust does.
AFAIK they don't mention ZSTs because ZSTs are not in the C standard, so the GCC implementation is a defacto standard for the ZST GNU extension.
What I think happened was that:
- GCC added this ZST extension
- GCC didn't bypass target-specific logic for ZSTs (whereas we do by default)
- new targets were added to GCC without anyone involved bringing up the ZST extension
Here are a couple architectures: https://godbolt.org/z/yOCJ-z - you can change the compilers involved to other architectures to check what they do, in that example MIPS64 is correct while MSP430 has the bug.
We might even support MSP430 without being aware of the bug - this is becoming quite sad, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because aggregates are passed in registers on MIPS/MIPS64/PowerPC64 (so the ZST takes up zero registers), while aggregates are passed indirectly on PowerPC/MSP (so the pointer to the ZST takes up one register, just like any other pointer). You need a caller to see the full picture.: https://godbolt.org/z/iMnRe-
if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { | ||
// FIXME: The C ABI case should be handled in adjust_for_cabi. | ||
// Zero-sized struct arguments cannot be ignored in the C ABI | ||
// if they are passed indirectly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes it sound like it's normal to a pass a pointer to nothing, and not likely some historical accident 😞.
(To be clear, I'm not asking for a change here, my wording was probably too strong anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The contents of the pointer don't really matter (the callee will never dereference it, although C++ guarantees that if you take the address of a ZST it will be unique). The important part is that we reserve a register or stack slot for the pointer, since the spec guarantees that there will be a pointer provided. Otherwise (and this was what was causing test failures), all arguments after the ZST will be misaligned (i.e. in the wrong register) from what the C compiler expects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spec doesn't apply to ZSTs because the C standard bans ZSTs (see my other comment for more details).
I don't think we need to read intent into what is pretty clearly a historical accident, given that x64/ARM/MIPS all do the right thing while some less-common targets don't.
let linux_sparc64 = | ||
target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; | ||
let indirect_zst = match target.arch.as_ref() { | ||
"powerpc" | "s390x" | "sparc64" => true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, you've removed the target_env == "gnu"
- this workaround only makes sense in that case, because ZSTs in C are a GNU extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddyb That's not true. It makes equally as much sense for target_env == "musl"
, which follows the exact same ELF ABI as glibc. As I mentioned before:
With these patches, I get a clean testsuite run on
powerpc-unknown-linux-musl
.
It is also necessary for the BSDs, since again they use the same ABI (both as specified, and as implemented in gcc/clang).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could probably add a has_gnu_extensions
or something that's set for target_env
being either "gnu"
or "musl"
.
While this doesn't feel ideal, I'd certainly prefer to broaden the whitelist than start including combinations we might not be aware of, and it does make sense that musl
would hit the same problems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That still doesn't make any sense to me. target_env
refers to the libc in use: glibc versus musl. That has nothing to do with the ABI, which is a property of the compiler.
Like I already said, this fix applies for the BSDs as well as Linux (regardless of target_env
), because they all use GCC or a GCC-compatible compiler.
☔ The latest upstream changes (presumably #64886) made this pull request unmergeable. Please resolve the merge conflicts. |
0f0d172
to
45b7579
Compare
I've rebased this on |
r? @eddyb |
Ping from triage. @eddyb any updates on this? Thanks. |
This PR has been waiting on this comment, not me: #64259 (comment). |
I think I actually ran into this problem and I understand what went wrong. This also explains the reluctance on the Rust side regarding this change. |
It shouldn't be problematic for Rust itself, I'm fairly sure they cross compile all of their tier 2+ targets anyway - so once it's merged and a release is made with it, all of the Mozilla-released tarballs should be suitable for bootstrapping from scratch... |
Adélie does have a PPC32 port which uses the SVR4 ABI, with an install base (at least 50 at my count), and most of these people do enjoy having Firefox, which builds with Rust, which means Rust needs to be fixed. To clarify, yes, we also have a PPC64BE port. This uses ELFv2, and works on 970 and up (G5, P5+). This has an even higher install base (a few hundred at my count). It's used in production for virtually all adelielinux.org services. We've worked with major projects across the ecosystem to ensure ELFv1/ELFv2 is a separate concern from BE/LE. Upstreams use auxv to determine VSX and VMX support so the silly requirement that ELFv2 is "only for POWER8" is irrelevant. Especially with things like microwatt and the opening of OpenPOWER, the ELFv2 ABI likely should be changed to note that auxv should be used instead of assuming an ISA level. But that's all irrelevant, I guess. Please do merge this upstream so we can stop carrying it. It is still useful, whether or not chips are "being produced". Wii/Wii U, Freescale chips, Apple G3/G4, there are millions of devices right now that use ppc32. See ibmruntimes/node#30 for another instance of ppc32 being neglected despite users desiring support. |
@awilfox Thanks for your comment. I agree with everything what you said and I highly appreciate the work you guys are doing on the PowerPC code. We profit from these fixes in openSUSE and Debian as well! |
Fix C aggregate-passing ABI on powerpc The existing code (which looks like it was copied from MIPS) passes aggregates by value in registers. This is wrong. According to the SVR4 powerpc psABI, all aggregates are passed indirectly. See rust-lang#64259 for more discussion, which addresses the ABI for the special case of ZSTs (empty structs).
For targets that pass zero-sized aggregates indirectly (generally those that pass all aggregates indirectly), we must allocate a register for passing the address of the ZST. Clean up the existing cases and add powerpc, which requires this as well. While there are not currently musl targets for s390x or sparc64, they would have the same ABI as gnu targets, so remove the env == "gnu" check in the Linux case. Ideally, since it is a property of the C ABI, the `!rust_abi` case would be handled entirely in `adjust_c_abi`. However, that would require updating each implementation of `compute_abi_info` to handle ZSTs.
45b7579
to
308071a
Compare
Ping from triage |
This is being discussed on zulip so there is progress |
To be honest I'm not aware of discussion beyond that shown in https://zulip-archive.rust-lang.org/131828tcompiler/69822PowerPCCABIfixesPR64259.html, where (as of now) the most recent comment was posted on November 7th. @Dylan-DPC did discussion continue after that in some other Zulip topic? (It would be good to try to get unblocked here...) |
Ah I probably misread it thinking it's latest. Sorry for that |
swiping from @eddyb to move this forward |
Is there actually stuff left to merge? The ABI fixes that were shipped with 1.40 actually reduced the number of testsuite failures for us on Debian powerpc dramatically. We're now down to only 23 failures, from over 60. |
We discussed this in our compiler team triage meeting today. We'd very much like to get some version of these changes landed. @eddyb suggested there is a small (approx. 1 line) diff that would fix the immediate/known problems that they'd prefer, and there was general consensus that a small, conservative step would be a good place to start. Hopefully @eddyb can either comment here (and we can update this PR) or it may be easier for them to just open a PR with the diff. @smaeul, I do wish to thank you both for the initial PR and for your patience! |
Discussed in T-compiler meeting. Closing under assumption that remaining desired work will be covered by PR's like #69263 |
Blacklist powerpc-unknown-linux-{gnu,musl} as having non-ignored GNU C ZSTs. Ref rust-lang#64259 (this is a simpler alternative to that). See also rust-lang#64259 (comment).
Blacklist powerpc-unknown-linux-{gnu,musl} as having non-ignored GNU C ZSTs. Ref #64259 (this is a simpler alternative to that). See also #64259 (comment).
This has reduced the number of testsuite failures on Debian/powerpc down to 10. On the other side, it's currently not possible to bootstrap rustc on openSUSE using the binaries provided by the Rust website. It seems that the Rust binaries for powerpc are still built with a toolchain without these fixes, isn't it? |
@mati865 I'm not sure whether that's related, is it? And more surprisingly, the number of testsuite failures went up to 51 with 1.42.0 again. |
These patches fix some longstanding issues with the PowerPC C ABI that were causing several test failures. With these patches, I get a clean testsuite run on
powerpc-unknown-linux-musl
.The PowerPC SVR4 ELF psABI specifies that, for parameter passing:
The first commit fixes this for most aggregates; the second commit fixes this for zero-size aggregates.