Skip to content
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

Merged

Conversation

vitek-karas
Copy link
Member

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

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).
@vitek-karas
Copy link
Member Author

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.

@vitek-karas
Copy link
Member Author

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).

Copy link
Member

@jtschuster jtschuster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs Outdated Show resolved Hide resolved
@@ -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)
Copy link
Member

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?

Copy link
Member Author

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.
src/linker/Linker/MethodIL.cs Outdated Show resolved Hide resolved
src/linker/Linker/MethodIL.cs Show resolved Hide resolved
src/linker/Linker.Dataflow/CompilerGeneratedState.cs Outdated Show resolved Hide resolved
@vitek-karas vitek-karas merged commit e502e72 into dotnet:main Nov 1, 2022
@vitek-karas vitek-karas deleted the FixBranchRemovalInCompilerGeneratedCode branch November 1, 2022 21:17
tlakollo pushed a commit to dotnet/runtime that referenced this pull request Nov 4, 2022
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
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
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
vitek-karas added a commit to vitek-karas/linker that referenced this pull request Dec 13, 2022
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).
sbomer pushed a commit that referenced this pull request Jan 18, 2023
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants