-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Generalize and cleanup code for existential specialization. #21316
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
Generalize and cleanup code for existential specialization. #21316
Conversation
@swift-ci test. |
I'm assuming it knows the existential has the concrete type -- is it still not correct to do that? |
I would like to understand more as well @atrick. |
I see this comment on your code Can you paste an example here to make it concrete? |
Overall, it looks good to me.. I have put in a couple of comments. Please have a look. Thanks a lot for doing this. |
/// If the Arg is already init_existential, return the concrete type. | ||
if (InitExistential && | ||
findConcreteTypeFromInitExistential(InitExistential, ConcreteType)) { | ||
return 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.
Does findInitExistential handle this GlobalAddr case now? It might be the case. I need to make sure the tests I wrote for them do not fail.
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.
getStackInitInst
calls findInitExistentialFromGlobalAddr
. I think findInitExistentialFromGlobalAddrAndApply
was just a trivial. If you have any out-of-tree test cases, please try them.
if (!findConcreteType(Apply, Idx, ConcreteType)) { | ||
Operand &ArgOper = Apply.getArgumentRef(Idx); | ||
CanType ConcreteType = | ||
ConcreteExistentialInfo(ArgOper.get(), ArgOper.getUser()).ConcreteType; |
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.
Thanks a lot for doing this. This was due from my side as the next PR cleanup :) You should also look at this other PR that also tries to create a concrete existential using SoleConformingType: #20977
Ideally, we should do all these in Existential.cpp with both ExistentialSpecializer and SILCombiner as consumers. Then we would have to pass PCA and CHA to this function.
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 PRs look mostly complementary. In this PR, the ConcreteExistentialInfo constructor always first attempts to find an init_existential first before using the provided ConreteType--it basically avoids doing an unnecessary cast. If you end up merging first, I can change this PR so that it's the caller's job to first attempt to create CEI from an init_existential, then create a different CEI using the sole conforming type.
I just remembered that this PR does remove some functionality from ExistentialSpecializer:
My original motivation for this cleanup was that I wanted to extend ConcreteExistentialInfo to handle
@rajbarik None of the unit tests broke by removing this, and I can't see why we would need to handle |
@slavapestov, @rajbarik The FIXME in the code explains it:
When PCA/soleConformingType kicks in, we do know the existential's conforming type, but we do not know the type that was actually stored in the existential. I think it will be the maximally reabstracted form, right? I think the reason I'm unable to create a test case is that PCA doesn't handle conformance on generic types:
Otherwise something like this would probably miscompile:
The CastOptimizer might have the same problem when it replaces an @jckarter I'd like to call this issue out explicitly in the code, and make the existential specialization and cast optimizer safe without handling all the special cases or implicitly relying on the caller to filter them out. I think we should have API something like: |
That's not specific to existentials, though, you need to maximally reabstract in any situation where you're going to use unconditional_checked_cast_addr. If we don't already, we should check for that in the SIL verifier. I believe we already do when constructing existentials or binding generic types. |
@rajbarik I'm happy to merge this now, but let me know if you want to merge any of your older PRs first that are going to have conflicts. |
I replaced the FIXME with a test for reabstraction. |
@swift-ci test. |
@swift-ci test source compatibility. |
Build failed |
Build failed |
@swift-ci test. |
Build failed |
Build failed |
@atrick I merged the other one. Please go ahead and merge this one. Thanks. |
@slavapestov @atrick One thing to note is that by inserting casts (from open to concrete type), we devirtualize the witness methods, however the existential code surrounding the open existential remains (which is actually dead code). I am thinking about writing a pass that would eliminate the existential related dead codes leading up to the cast, when possible. Makes sense? |
@rajbarik I noticed that useless existentials (they are used only to open them) aren't being removed. Doing so would simplify witness specialization in SILCombineApplyVisitors. I even added a TODO in the code about this, but haven't investigated where it should be done yet. I think it's essentially the same problem that you're describing. Before prototyping it, I suggest bring it up on the forums to get suggestions. |
@rajbarik please request commit access. You just need to send an email to [email protected] with 4-5 examples of PRs that you've committed. From https://swift.org/contributing/#contributing-code Once you’ve been granted commit access, you will be able to commit to all of the GitHub repositories that host Swift.org projects. To verify that your commit access works, please make a test commit (for example, change a comment or add a blank line). The following policies apply to users with commit access: You are granted commit-after-approval to all parts of Swift. To get approval, create a pull request. When the pull request is approved, you may merge it yourself. You may commit an obvious change without first getting approval. The community expects you to use good judgment. Examples are reverting obviously broken patches, correcting code comments, and other minor changes. You are allowed to commit changes without approval to the portions of Swift to which you have contributed or for which you have been assigned responsibility. Such commits must not break the build. This is a “trust but verify” policy, and commits of this nature are reviewed after being committed. Multiple violations of these policies or a single egregious violation may cause commit access to be revoked. Even with commit access, your changes are still subject to code review. Of course, you are also encouraged to review other peoples’ changes. |
@swift-ci test. |
@swift-ci test source compatibility. |
This required a nontrivial rebase but it's ready to merge now as soon as the branch is unlocked. |
Build failed |
Build failed |
@swift-ci test. |
Build failed |
Build failed |
@swift-ci test. |
@swift-ci test source compatibility. |
Build failed |
Build failed |
Generalizes the ConcreteExistentialInfo abstraction so it can be used both by the ExistentialSpecializer and SILCombine, allowing redundant code in ExistentialSpecializer.cpp to be deleted. Splits OpenedArchetypeInfo from ConcreteExistentialInfo. Adds a ConcreteOpenedArchetypeInfo convenience wrapper around them both, for use wherever we were originally using ConcreteExistentialInfo. Splits getAddressOfStackInit into getStackInitInst, This is cleaner and allows both the ExistentialSpecializer and SILCombine to handle more interesting cases in the future, like unconditional_checked_cast. Creates utilities, initializeSubstitutionMap, and initializeConcreteTypeDef to simplify an generalize ConcreteExistentialInfo. While rewriting ExistentialSpecializer to use the new abstraction, I fixed a latent bug in which is was using a SIL argument index as a function type parameter index (this would have broken up if/when we decide to enable calls with indirect results).
This code was force casting the address of the opened existential to the lowered SIL type of the known conformance. This is superficially incorrect because values are stored in existentials with maximal reabstraction. Bail on any concrete types that require reabstraction. I don't think we will hit this currently because there is an earlier check that prevents optimizing a conformance on a generic types. In theory someone could add that functionality later for internal generic types with a single instantiation. More importantly, we don't want anyone copying this logic and assuming it's generally correct.
@swift-ci test. |
Build failed |
Build failed |
Generalizes the ConcreteExistentialInfo abstraction so it can be used
both by the ExistentialSpecializer and SILCombine.
Splits OpenedArchetypeInfo apart from ConcreteExistentialInfo. Adds a
convenience wrapper around them both, ConcreteOpenedArchetypeInfo, for
use wherever we were originally using ConcreteExistentialInfo. This
allows a large amount of redundant code in ExistentialSpecializer.cpp
to be deleted.
Fixes a latent bug where the ExistentialSpecializer used a SIL
argument index as a function type parameter index (this will show up
if/when we decide to enable calls with indirect results).
There is still a bug where ExistentialSpecializer bit-casts an opened
existential to a concrete type. I'll attempt to fix that bug in a
follow-up PR.
Splits getAddressOfStackInit into getStackInitInst, This is cleaner and
allows both the ExistentialSpecializer and SILCombine to handle more
interesting cases in the future, like unconditional_checked_cast.
Creates utilities, initializeSubstitutionMap, and
initializeConcreteTypeDef to simplify an generalize
ConcreteExistentialInfo.