-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Optimizer: make destroy hoisting a mandatory pass #85334
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
Optimizer: make destroy hoisting a mandatory pass #85334
Conversation
|
@swift-ci test |
|
@swift-ci apple silicon benchmark |
|
The goal here is to just provide this optimization at -Onone rather than to guarantee some semantic effect? So it's okay that it doesn't run in bootstrap. |
|
Curious why you saw this
Non lexical lifetimes should not have observable program behavior. Was this because we did not correctly mark a value as lexical or lost this information during transformations? Is there a test showing this? |
right |
They do. For example, a temporary class reference can have a side effect in it's deinit. If such a temporary value is moved over a deinit barrier, it's changing the program behavior. |
|
@swift-ci test macos |
|
@swift-ci test windows |
|
@swift-ci test Windows |
|
@swift-ci smoke test Windows |
|
For diagnostics, we need to concept of "this value's lifetime represents the scope of a variable declaration". We should have a common way of checking for that. We have |
|
We currently build the standard library in a special mode that disables lexical lifetimes. It's important that we can eventually eliminate the special mode for the sanity of both standard library and compiler engineers. https://github.com/apple/swift/blob/main/stdlib/cmake/modules/AddSwiftStdlib.cmake#L2146 A good test of whether this DestroyHoisting pass does not create performance problems will be if we can remove My main concern is that, with this approach, we won't be able to optimize Array/String after inlining generic code. |
…ship-transitioning instructions except `copy_value`
It hoists `destroy_value` instructions for non-lexical values. ``` %1 = some_ownedValue ... last_use(%1) ... // other instructions destroy_value %1 ``` -> ``` %1 = some_ownedValue ... last_use(%1) destroy_value %1 // <- moved after the last use ... // other instructions ``` In contrast to non-mandatory optimization passes, this is the only pass which hoists destroys over deinit-barriers. This ensures consistent behavior in -Onone and optimized builds.
Also for non-lexical lifetimes
2aeabbf to
04688a6
Compare
|
@swift-ci smoke test |
atrick
left a comment
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.
LGTM, but I am concerned about general long-term performance and specifically that this will make it harder to enable lexical lifetimes in the standard library because we won't be able to optimize array/string after specialization and inlining.
|
Answering my own previous question... in the future we could probably teach optimizations about |
So far hoisting destroys (
destroy_valueanddestroy_addr) in the optimizer worked differently for lexical and non-lexical lifetimes: lexical lifetimes need to respect deinit-barriers, while destroys of non-lexical lifetimes could be moved over deinit-barriers.This had two problems:
This PR
This almost guarantees consistent behavior for Onone and optimized builds. Almost, because there is still one exception for COW types (like Arrays). Such values are not lexical, but MandatoryDestroyHoisting does not hoist destroys of such variables in debug builds to not compromise debug info.