-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Rewrite StackNesting to use a single-pass algorithm
#84688
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
|
@swift-ci Please test |
19b34ee to
30df880
Compare
|
@swift-ci Please test |
|
@rjmccall can you please
|
I saw your comment before, and I'm intending to write a lot more tests, yes. Right now I'm still just trying to get this thing working. |
|
@swift-ci Please test windows |
1 similar comment
|
@swift-ci Please test windows |
94538b0 to
0b5853e
Compare
|
@swift-ci Please test |
|
Now with the tweaked algorithm and a rather over-pedantic proof. Still needs benchmarking and (mostly) testing |
0b5853e to
203f0f7
Compare
|
@swift-ci Please test |
|
@swift-ci Please test compiler performance |
|
Well, the performance run seems to show no drastic regressions, and that Windows failure seems unrelated, so I just need to write tests. |
The previous algorithm was doing an iterative forward data flow analysis followed by a reverse data flow analysis. I suspect the history here is that it was a reverse analysis, and that didn't really work for infinite loops, and so complexity accumulated. The new algorithm is quite straightforward and relies on the allocations being properly jointly post-dominated, just not nested. We simply walk forward through the blocks in consistent-with-dominance order, maintaining the stack of active allocations and deferring deallocations that are improperly nested until we deallocate the allocations above it. The only real subtlety is that we have to delay walking into dead-end regions until we've seen all of the edges into them, so that we can know whether we have a coherent stack state in them. If the state is incoherent, we need to remove any deallocations of previous allocations because we cannot talk correctly about what's on top of the stack. The reason I'm doing this, besides it just being a simpler and hopefully faster algorithm, is that modeling some of the uses of the async stack allocator properly requires builtins that cannot just be semantically reordered. That should be somewhat easier to handle with the new approach, although really (1) we should not have runtime functions that need this and (2) we're going to need a conservatively-correct solution that's different from this anyway because hoisting allocations is *also* limited in its own way. I've attached a rather pedantic proof of the correctness of the algorithm. The thing that concerns me most about the rewritten pass is that it isn't actually validating joint post-dominance on input, so if you give it bad input, it might be a little mystifying to debug the verifier failures.
203f0f7 to
8d231d2
Compare
|
@swift-ci Please test |
|
@eeckstein Tests added, ready for final review. |
The previous algorithm was doing an iterative forward data flow analysis followed by a reverse data flow analysis. I suspect the history here is that it was a reverse analysis, and that didn't really work for infinite loops, and so complexity kindof accumulated.
The new algorithm is quite straightforward and relies on the allocations being properly jointly post-dominated, just not nested. We simply walk forward through the blocks in consistent-with-dominance order, maintaining the stack of active allocations and deferring deallocations that are improperly nested until we deallocate the allocations above it.
The reason I'm doing this, besides it just being a simpler, faster algorithm, is that modeling some of the uses of the async stack allocator properly requires builtins that cannot just be semantically reordered. That should be somewhat easier to handle with the new approach, although really (1) we should not have runtime functions that need this and (2) we're going to need a conservatively-correct solution that's different from this anyway because hoisting allocations is also limited in its own way.
The test cases that changed are... I don't think the new output is wrong under the current rules that are being enforced, but really we should be enforcing different rules, because it's not really okay to have broken stack nesting in blocks just because they don't lead to an exit. But it's broken coming into StackNesting, and I don't think the rewrite actually makes it worse, so...
The thing that concerns me most about the rewritten pass is that it isn't actually validating joint post-dominance on input, so if you give it bad input, it might be a little mystifying to debug the verifier failures.