-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[SIL] Only visit final partial_apply [on_stack] lifetime ends. #78651
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
99a1a50
to
ae006b6
Compare
@swift-ci please test |
@swift-ci please apple silicon benchmark |
@swift-ci please test source compatibility |
Source compat failures match failures in baseline:
|
I'm wondering if this is the right approach. I'm pretty sure that other utilities, like OwnershipLiveness.swift doesn't handle this correctly, too. |
The problem I have with this is that it's very complicated to compute this implicit borrow scope. It's already bad enough that and partial_apply's argument borrow-scope is defined by a forward-extended liverange. But also needing to visit copies (and "parallel" liveranges) transitively is terrible. |
Yeah, that would definitely be nice. Something that's been observed in the past when similar problems have arisen is that such values ought to be represented as non-copyable values. Unfortunately, that's not the current state of affairs. And also unfortunately, SILGen and passes both introduce copies in numerous places. |
Suggestion:
We can detect optimizations which introduce such copies easily and run the utility at the end of such passes. |
Pulled out the miscellaneous improvements into #78682 while we discuss the main fix here. |
ae006b6
to
5660d63
Compare
Unfortunately, it looks like more interesting changes representational would be required to eliminate copies. Here is some simplified SIL from the _Backtracing library:
|
The fundamental idea behind OSSA is that we do not run liveness analysis to find a value's ownership lifetime. Now that we have formal abstractions for As pointed out here, a copy of a dependent value does normally not carry that dependency. So, it does not make sense for The Incidentally, |
I think the cleanest solution would be to add |
I don't see how adding borrow scopes solves the problem. The problem just moves around to different places. Ultimately, we need to figure out how to represent the fact that each owned copy of the closure depends on the captures. So either we make the copies illegal or add mark_dependence to all of them so they all depend on the original partial_apply. |
Well, it solves the problem that the lifetime of partial_apply arguments is defined explicitly and not implicitly by complicated traversing of forwarding instructions (and maybe copies) - like we do for all other borrow scopes, too. The ownership verifier still has to check that the forward-extended lifetime of the closure does not extend the borrow scopes of the arguments.
That's what we should do anyway. |
Replaced a - with a _.
In OSSA, the `partial_apply [on_stack]` instruction produces a value with odd characteristics that correspond to the fact that it is lowered to a stack-allocating instruction. Among these characteristics is the fact that copies of such values aren't load bearing. When visiting the lifetime-ending uses of a `partial_apply [on_stack]` the lifetime ending uses of (transitive) copies of the partial_apply must be considered as well. Otherwise, the borrow scope it defins may be incorrectly short: ``` %closure = partial_apply %fn(%value) // borrows %value %closure2 = copy_value %closure destroy_value %closure // does _not_ end borrow of %value! ... destroy_value %closure2 // ends borrow of %value ... destroy_value %value ``` Furthermore, _only_ the final such destroys actually count as the real lifetime ends. At least one client (OME) relies on `visitOnStackLifetimeEnds` visiting at most a single lifetime end on any path. Rewrite the utility to use PrunedLiveness, tracking only destroys of copies and forwards. The final destroys are the destroys on the boundary. rdar://142636711
Now that the other caller of the function has been removed, it's more convenient to have it adjacent to the only remaining caller.
5660d63
to
41bee47
Compare
@swift-ci please test |
@swift-ci please test source compatibility |
@swift-ci please apple silicon benchmark |
Merging as-is to unblock OSSA progress. Filed rdar://143821866 (Fix representation of partial_apply [on_stack] to ban copies) to track the correct solution. |
In OSSA, the
partial_apply [on_stack]
instruction produces a value with odd characteristics that correspond to the fact that it is lowered to a stack-allocating instruction. Among these characteristics is the fact that copies of such values aren't load bearing.When visiting the lifetime-ending uses of a
partial_apply [on_stack]
the lifetime ending uses of (transitive) copies of the partial_apply must be considered as well. Otherwise, the borrow scope it defines may be incorrectly short:Furthermore, only the final such destroys actually count as the real lifetime ends. At least one client (OME) relies on
visitOnStackLifetimeEnds
visiting at most a single lifetime end on any path.Rewrite the utility to use
PrunedLiveness
, tracking only destroys of copies and forwards. The final destroys are the destroys on the boundary.Also, add here a couple other changes:
CopyPropagation
, where the original problem showed up, by adding subpass bailouts.DestroyAddrHoisting
, where a different issue (a missing!
) introduced by a previous version of this patch appeared to show up.TempRValueOpt
when lifetime completion had an effect. This lack of invalidation resulted in not verifying or printing the SIL after the pass withsil-print-function
despite the fact that it had indeed been changed (without using more exotic flags likesil-verify-force-analysis
), obscuring the actual source of the issue introduced by a previous version of this patch.rdar://142636711