-
Notifications
You must be signed in to change notification settings - Fork 127
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
Fix branch removal in compiler generated code #3088
Fix branch removal in compiler generated code #3088
Conversation
Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method. To make the code simple I added a hashset to prevent multiple optimization runs on the same method. Technically this can be guaranteed by the caller, but it's really complex and very fragile. Added tests. Note that there's still a whole in analysis of compiler generated code around state machines, see dotnet#3087
…e constant prop/branch removal happened on the method. This does have one possibly negative impact: the issue described in dotnet#2937 is now consistent and happens always. Basically if there's a local function which is going to be removed due to branch removal and if the body of that method contains code which produces a warning due to generic parameter validation, such warning will always be generated even though it's "dead" code and even if it's suppressed via RUC or similar. Basically in such case the analysis can't figure out to which method the local function belongs (since the call site has been removed).
I reworked this change to guard against accesses to Body and make sure that const. prop/branch removal happens always. This does have one negative effect: #2937 is not consistent and happens in all cases - meaning if the callsite to a local function is removed, we can't figure out to which method the local function belongs and may incorrectly report some warnings. Personally I prefer the consistent behavior (which is not order dependent anymore) - even if it's incorrect. We can use #2937 to track ideas on how to fix the problem. |
I measured perf of this change (using the sfx project from runtime) and there's no visible regression (although locally the noise is rather high). |
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, thank you!
@@ -699,7 +702,7 @@ protected virtual void Scan (MethodBody methodBody, ref InterproceduralState int | |||
} | |||
} | |||
|
|||
private static void ScanExceptionInformation (Dictionary<int, Stack<StackSlot>> knownStacks, MethodBody methodBody) | |||
private static void ScanExceptionInformation (Dictionary<int, Stack<StackSlot>> knownStacks, MethodBodyInstructionsProvider.ProcessedMethodBody methodBody) |
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.
Just to make sure I understand, this needs to be a ProcessedMethodBody because it's static, right? And the other instance methods we are just assuming we pass the ProcessedMethodBody.Body from Scan?
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.
I don't think I did anything with static/instance methods on this class. The idea is that Scan gets the processed method from the outside and it passes it to all of the helpers here - including this one.
Sorry, I probably don't understand the question.
Basically just refactored the helper class into a separate MethodIL and moved the logic onto LinkContext. The rest is just renames and cleanup.
Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method. The change guarantees that all accesses to Body are after the constant prop/branch removal happened on the method. This does have one possibly negative impact: the issue described in dotnet/linker#2937 is now consistent and happens always. Added tests. Note that there's still a whole in analysis of compiler generated code around state machines, see dotnet/linker#3087 Basically if there's a local function which is going to be removed due to branch removal and if the body of that method contains code which produces a warning due to generic parameter validation, such warning will always be generated even though it's "dead" code and even if it's suppressed via RUC or similar. In such case the analysis can't figure out to which method the local function belongs (since the call site has been removed). Commit migrated from dotnet/linker@e502e72
Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method. The change guarantees that all accesses to Body are after the constant prop/branch removal happened on the method. This does have one possibly negative impact: the issue described in dotnet/linker#2937 is now consistent and happens always. Added tests. Note that there's still a whole in analysis of compiler generated code around state machines, see dotnet/linker#3087 Basically if there's a local function which is going to be removed due to branch removal and if the body of that method contains code which produces a warning due to generic parameter validation, such warning will always be generated even though it's "dead" code and even if it's suppressed via RUC or similar. In such case the analysis can't figure out to which method the local function belongs (since the call site has been removed). Commit migrated from dotnet/linker@e502e72
Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method. The change guarantees that all accesses to Body are after the constant prop/branch removal happened on the method. This does have one possibly negative impact: the issue described in dotnet#2937 is now consistent and happens always. Added tests. Note that there's still a whole in analysis of compiler generated code around state machines, see dotnet#3087 Basically if there's a local function which is going to be removed due to branch removal and if the body of that method contains code which produces a warning due to generic parameter validation, such warning will always be generated even though it's "dead" code and even if it's suppressed via RUC or similar. In such case the analysis can't figure out to which method the local function belongs (since the call site has been removed).
* Fix branch removal in compiler generated code (#3088) Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method. The change guarantees that all accesses to Body are after the constant prop/branch removal happened on the method. This does have one possibly negative impact: the issue described in #2937 is now consistent and happens always. Added tests. Note that there's still a whole in analysis of compiler generated code around state machines, see #3087 Basically if there's a local function which is going to be removed due to branch removal and if the body of that method contains code which produces a warning due to generic parameter validation, such warning will always be generated even though it's "dead" code and even if it's suppressed via RUC or similar. In such case the analysis can't figure out to which method the local function belongs (since the call site has been removed). * PR feedback
Changes to processing of compiler generated methods lead to a state where we don't call constant prop and branch removal in all cases before we mark instructions of the method. This can lead to overmarking
This change fixes this by making sure that the branch removal executes on the method in all cases before we mark instructions of the method.
To make the code simple I added a hashset to prevent multiple optimization runs on the same method. Technically this can be guaranteed by the caller, but it's really complex and very fragile.
Added tests.
Note that there's still a whole in analysis of compiler generated code around state machines, see #3087