-
Notifications
You must be signed in to change notification settings - Fork 842
Improved pattern compilation #11993
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
Merged
Merged
Improved pattern compilation #11993
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Happypig375
suggested changes
Aug 22, 2021
Contributor
Author
|
This is ready for review @vzarytovskii @KevinRansom @TIHan |
vzarytovskii
approved these changes
Mar 4, 2022
KevinRansom
approved these changes
Mar 8, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This contains two related improvements to how we approach pattern-match compilation
Improved pattern match compilation for type tests and null tests
Using multiple "columns" of type tests and null tests was generating exponential amounts of code, e.g. see #12687
This is fixed by moving to a "column" of type tests and doing the work to properly determine when the success/failure of earlier elements of the column inform us about later patterns. For example:
Here the success of
:? stringtells us that all the other (sealed) type tests will fail. Likewise consider this:Here the failure of
:? Atells us that:? Bwill fail. Similar information can be deduced from null tests and type tests on interfaces.This removes a cause of exponential code generation, and for examples like #12687 the code goes down from, say 17MB of IL in one method to 3K - you can make this as dramatic as you like by adding extra clauses.
This also has the benefit that many new cases of "rule never matched" are detected.
There is also an improvement with generating more "fast" type tests that use the
isinstinstruction rather than a helper. Also the IL code sequenceisinst; ldnull; cgt.un; brtrue/brfalseis improved toisinst; brtrue/brfalseImproved pattern match compilation with
whenWhile looking at #11981 I went back and reconsidered out approach for "problematic pattern matching clauses" that can lead to substantial code generation. For example, consider code like this:
Previously, we were doing these clauses "one by one", because the presence of the "when" pattern led us to consider the clause set "potentially-problematic", and so the complexity of pattern matching was reduced by doing it clause-by-clause. This means we fetched and tested the tag again and again, instead of doing it in a switch. This PR uses a new way of detecting potentially-problematic clauses.
After this PR, the clauses above are considered "all together" and a
switchis now emitted. This is because the first thing tested in pattern matching is the Tag ofU, that is, we use aswitchto test down the "column" A1/A2/A3/A4, all of which correspond to the same "investigation". After this investigation, the pattern logic reduces to a set of conditionals (for thewhenclauses) and, crucially, the failure branch of awhenclause just proceeds on to th nextwhenclause (and the success branch goes to the necessary target). That is, the pattern logic is linear and without duplication or problematic expansion.The IL optimized code size for the above example reduces from 181 to 173. Is that important? Not in itself. Does this help performance? I'm not certain. It feels better, the code looks improved.
This comes with a gain - we now have improved detection of unused patterns! This can give rise to additional warnings (which may mean it needs a
--langversionswitch?). For example,Previously this didn't give an "unused match" warning. Now it does. This is because the presence of the initial
whenclauses don't disable unused clause warning errors.There were about 4 places in our codebase where this detected unused pattern match clauses. Two of these were in the TypeProvider SDK.
Specification of pattern clause grouping
A note from the code is copied below.