-
Notifications
You must be signed in to change notification settings - Fork 10.5k
IRGen: ensure that helper functions are COMDAT'ed #20059
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
Conversation
CC: @aschwaighofer Yes, I know, I should go clean up the other cases, but this is sufficient to unblock me. I'll try to get to the other cases in a follow up. |
@swift-ci please test |
Build failed |
Build failed |
Fine with me |
test/IRGen/alloc.sil
Outdated
// CHECK: define linkonce_odr hidden i8* @__swift_memcpy4097_8(i8*, i8*, %swift.type*) | ||
// CHECK-COMDAT: define linkonce_odr hidden i8* @__swift_memcpy4097_8(i8*, i8*, %swift.type*) | ||
// CHECK-COMDAT-SAME: comdat | ||
// CHECK-NOCOMDAT-NOT:comdat |
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 will only check that "comdat" isn't written here, not that it isn't written at all. Did you mean to leave the first line as CHECK instead of CHECK-COMDAT?
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.
Oops, yeah, the first line should be CHECK
.
This uncovered a bug in LLVM ( |
c72ea22
to
649f6d3
Compare
@swift-ci please test |
Build failed |
Build failed |
649f6d3
to
2556e2c
Compare
@swift-ci please test |
Build failed |
Build failed |
2556e2c
to
c4e6514
Compare
@swift-ci please test |
Build failed |
Build failed |
@compnerd Can you point out where this change happened in LLVM? It wasn't well-communicated. |
Are you sure this was an intentional LLVM change? It seems like a pretty severe break if |
@rjmccall, @jckarter - yes, this was intentional :-( ... I just have it on what Reid Klecker mentioned to me. @jckarter - it still can coalesce on ELF - because of weak symbols. This definitely does not work on COFF where you do not have weak symbols. By creating the COMDAT group we ensure that there is a single definition. |
CC: @rnk |
@rnk Do you remember what changed here? |
Yeah, like everything. You gotta use comdats now if you want comdats. That happened back in 2014. It looks like the final change was r226467, so I guess 2015. Unfortunately, I have not been able to find a good llvm-dev discussion summarizing the change, but I remember there was a lot of discussion. You know, the plans to bulldoze linkonce_odr semantics were on display down at the planning office for months. =P |
😢 Failing Tests (5): The DebugInfo failure is due to the DIE check being invalid. That was relaxed in LLVM (by me). I'm not sure why the Reflection tests are failing after this change. |
I feel like the old semantics were a useful common core across all targets, which is all that was necessary for the vast majority of frontend use cases. But PE/COFF does some other things in IR pointlessly differently, so I guess this is of a piece. |
CC: @slavapestov |
sigh okay, binaries built with lld work but fail with gold? This is starting to smell like a linker issue :-(. I am amused at the number of linker issues we are finding with swift code. |
Alas, the more you deviate from what C compilers do, the more linker breakage you overturn. Can we stick to using COMDAT only for COFF, and continue to rely on weak definitions on ELF? |
@jckarter that definitely is what I have in mind, but this does come at a cost, we should definitely consider this. We already know that the BFD linker doesn't work for swift. Perhaps it is time to switch from gold to lld. With COMDAT: Weak: |
We dropped BFD support because they broke |
In order to handle LinkOnceODR semantics correctly across various object formats, introduce a new helper ApplyIRLinkage. This abstracts the need to create a COMDAT group and set it on the GlobalValue. Adjust all sites where we set the IR linkage attributes to use this mechanism instead to avoid having to track down symbols not being added to a COMDAT group.
c4e6514
to
86e5b25
Compare
@swift-ci please test |
Build failed |
Build failed |
Uh, no, C++ compilers use comdat and weak on ELF. I would suggest setting both comdat and linkonce_odr linkage everywhere to more closely match what clang does.
There were nice things about the old way of doing things, but as usual, people wanted to access lower-level features that LLVM was hiding from them. This isn't PE/COFF being weirdly different for its own sake, though. ELF has comdats too, and you need to use them if you want to generate vague linkage things the same way that clang does. Here's what the main object file formats support (ignoring wasm): All of the weak, linkonce, and ODR linkages used to enable weak and comdat, depending on what the object file format supported. For ELF, weak and comdat are kind of redundant. If all symbol definitions are weak, the first one will prevail, otherwise the one and only strong one prevails. Adding a comdat group basically does a first pass to drop duplicate symbols before doing that weak vs. strong resolution. |
I'm aware of that, but there could be interactions with comdat and other things Swift does that C doesn't that gold doesn't handle correctly. (Particularly, we've had persistent problems with ld64 on Darwin not handling subtractions for relative references correctly with symbols in coalesced sections; doesn't seem totally out of the question gold might have similar latent phase-order bugs.) |
@swift-ci please clean test macOS platform |
I've filed SR-9197 to track the ELF side of things. This currently is limited to COFF for the COMDAT group construction. We should work out the bug in gold and enable this for ELF too. |
alias->setVisibility(link.getVisibility()); | ||
alias->setDLLStorageClass(link.getDLLStorage()); | ||
ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) | ||
.to(alias); |
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 pattern — repeated over and over again — where we create a declaration and then immediately override half the values from it with the values of an IRLinkage
is quite unfortunate. I like the idea of encapsulating IRLinkage
; perhaps it ought to have functions on it to actually create these globals?
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.
I disliked that we were setting the properties for the linkage everywhere but didn't manage to do it very uniformly. So, the application of the IRLinkage at least ensures we set the properties more uniformly. But, I can try to sink this into createVariable and createFunction. I'm happy to try to do that in a follow up.
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.
I'm fine with doing it in multiple stages. Some other suggestions:
- As mentioned, please add functions to create variables and functions.
- Please look around IRGen for other places that create variables and functions that could use this. LLVM's API for creating globals is really a mess, so it shouldn't be hard to create something that's friendlier and therefore encourages people to use it (and thus implicitly get the correctness benefits).
- Please add static factories (like
shared()
orinternal()
) for the common patterns. - Consider incorporating
unnamed_addr
into this, and maybe an optional section name. Butconstant
probably ought to be a mandatory argument to the function to create a global, not part of the linkage.
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.
Yeah, unnamed_addr
and dso_local
are other attributes that I think that we should grow into this. But, this unblocks Windows builds and improves things.
The linkonce_odr semantics in LLVM have changed. They no longer create
a COMDAT group. This means that the helper functions that we are
generating inline globally are not collected and uniqued. This results
in multiple definitions, which is a hard error in PE/COFF. ELF would
get away with it due to the weak linkage semantics that it provides.
Explicitly mark the helpers for COMDAT. This should enable building the
swift SDK overlay for libdispatch on Windows again.
Replace this paragraph with a description of your changes and rationale. Provide links to external references/discussions if appropriate.
Resolves SR-NNNN.