This repository was archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Fix for a jit liveness bug. #24282
Merged
Merged
Fix for a jit liveness bug. #24282
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2235,137 +2235,95 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, | |
| return false; | ||
| } | ||
|
|
||
| /* Test for interior statement */ | ||
| // Check for side effects | ||
| GenTree* sideEffList = nullptr; | ||
| if (rhsNode->gtFlags & GTF_SIDE_EFFECT) | ||
| { | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| { | ||
| printf(FMT_BB " - Dead assignment has side effects...\n", compCurBB->bbNum); | ||
| gtDispTree(asgNode); | ||
| printf("\n"); | ||
| } | ||
| #endif // DEBUG | ||
| // Extract the side effects | ||
| if (rhsNode->TypeGet() == TYP_STRUCT) | ||
| { | ||
| // This is a block assignment. An indirection of the rhs is not considered to | ||
| // happen until the assignment, so we will extract the side effects from only | ||
| // the address. | ||
| if (rhsNode->OperIsIndir()) | ||
| { | ||
| assert(rhsNode->OperGet() != GT_NULLCHECK); | ||
| rhsNode = rhsNode->AsIndir()->Addr(); | ||
| } | ||
| } | ||
| gtExtractSideEffList(rhsNode, &sideEffList); | ||
| } | ||
|
|
||
| // Test for interior statement | ||
|
|
||
| if (asgNode->gtNext == nullptr) | ||
| { | ||
| /* This is a "NORMAL" statement with the | ||
| * assignment node hanging from the GT_STMT node */ | ||
| // This is a "NORMAL" statement with the assignment node hanging from the GT_STMT node. | ||
|
|
||
| noway_assert(compCurStmt->gtStmtExpr == asgNode); | ||
| JITDUMP("top level assign\n"); | ||
|
|
||
| /* Check for side effects */ | ||
|
|
||
| if (rhsNode->gtFlags & GTF_SIDE_EFFECT) | ||
| if (sideEffList != nullptr) | ||
| { | ||
| EXTRACT_SIDE_EFFECTS: | ||
| /* Extract the side effects */ | ||
|
|
||
| GenTree* sideEffList = nullptr; | ||
| noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT); | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| { | ||
| printf(FMT_BB " - Dead assignment has side effects...\n", compCurBB->bbNum); | ||
| gtDispTree(asgNode); | ||
| printf("Extracted side effects list...\n"); | ||
| gtDispTree(sideEffList); | ||
| printf("\n"); | ||
| } | ||
| #endif // DEBUG | ||
| if (rhsNode->TypeGet() == TYP_STRUCT) | ||
| { | ||
| // This is a block assignment. An indirection of the rhs is not considered to | ||
| // happen until the assignment, so we will extract the side effects from only | ||
| // the address. | ||
| if (rhsNode->OperIsIndir()) | ||
| { | ||
| assert(rhsNode->OperGet() != GT_NULLCHECK); | ||
| rhsNode = rhsNode->AsIndir()->Addr(); | ||
| } | ||
| } | ||
| gtExtractSideEffList(rhsNode, &sideEffList); | ||
|
|
||
| if (sideEffList) | ||
| { | ||
| noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT); | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| { | ||
| printf("Extracted side effects list...\n"); | ||
| gtDispTree(sideEffList); | ||
| printf("\n"); | ||
| } | ||
| #endif // DEBUG | ||
|
|
||
| /* Replace the assignment statement with the list of side effects */ | ||
| noway_assert(sideEffList->gtOper != GT_STMT); | ||
| // Replace the assignment statement with the list of side effects | ||
| noway_assert(sideEffList->gtOper != GT_STMT); | ||
|
|
||
| *pTree = compCurStmt->gtStmtExpr = sideEffList; | ||
| *pTree = compCurStmt->gtStmtExpr = sideEffList; | ||
| #ifdef DEBUG | ||
| *treeModf = true; | ||
| *treeModf = true; | ||
| #endif // DEBUG | ||
| /* Update ordering, costs, FP levels, etc. */ | ||
| gtSetStmtInfo(compCurStmt); | ||
|
|
||
| /* Re-link the nodes for this statement */ | ||
| fgSetStmtSeq(compCurStmt); | ||
| // Update ordering, costs, FP levels, etc. | ||
| gtSetStmtInfo(compCurStmt); | ||
|
|
||
| // Since the whole statement gets replaced it is safe to | ||
| // re-thread and update order. No need to compute costs again. | ||
| *pStmtInfoDirty = false; | ||
| // Re-link the nodes for this statement | ||
| fgSetStmtSeq(compCurStmt); | ||
|
|
||
| /* Compute the live set for the new statement */ | ||
| *doAgain = true; | ||
| return false; | ||
| } | ||
| else | ||
| { | ||
| /* No side effects, most likely we forgot to reset some flags */ | ||
| fgRemoveStmt(compCurBB, compCurStmt); | ||
| // Since the whole statement gets replaced it is safe to | ||
| // re-thread and update order. No need to compute costs again. | ||
| *pStmtInfoDirty = false; | ||
|
|
||
| return true; | ||
| } | ||
| // Compute the live set for the new statement | ||
| *doAgain = true; | ||
| return false; | ||
| } | ||
| else | ||
| { | ||
| /* If this is GT_CATCH_ARG saved to a local var don't bother */ | ||
|
|
||
| JITDUMP("removing stmt with no side effects\n"); | ||
|
|
||
| if (asgNode->gtFlags & GTF_ORDER_SIDEEFF) | ||
| { | ||
| if (rhsNode->gtOper == GT_CATCH_ARG) | ||
| { | ||
| goto EXTRACT_SIDE_EFFECTS; | ||
| } | ||
| } | ||
|
|
||
| /* No side effects - remove the whole statement from the block->bbTreeList */ | ||
|
|
||
| // No side effects - remove the whole statement from the block->bbTreeList | ||
| fgRemoveStmt(compCurBB, compCurStmt); | ||
|
|
||
| /* Since we removed it do not process the rest (i.e. RHS) of the statement | ||
| * variables in the RHS will not be marked as live, so we get the benefit of | ||
| * propagating dead variables up the chain */ | ||
|
|
||
| // Since we removed it do not process the rest (i.e. RHS) of the statement | ||
| // variables in the RHS will not be marked as live, so we get the benefit of | ||
| // propagating dead variables up the chain | ||
| return true; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| /* This is an INTERIOR STATEMENT with a dead assignment - remove it */ | ||
|
|
||
| // This is an INTERIOR STATEMENT with a dead assignment - remove it | ||
| noway_assert(!VarSetOps::IsMember(this, life, varDsc->lvVarIndex)); | ||
|
|
||
| if (rhsNode->gtFlags & GTF_SIDE_EFFECT) | ||
| if (sideEffList != nullptr) | ||
| { | ||
| /* :-( we have side effects */ | ||
|
|
||
| GenTree* sideEffList = nullptr; | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| { | ||
| printf(FMT_BB " - INTERIOR dead assignment has side effects...\n", compCurBB->bbNum); | ||
| gtDispTree(asgNode); | ||
| printf("\n"); | ||
| } | ||
| #endif // DEBUG | ||
| gtExtractSideEffList(rhsNode, &sideEffList); | ||
|
|
||
| if (!sideEffList) | ||
| { | ||
| goto NO_SIDE_EFFECTS; | ||
| } | ||
|
|
||
| noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT); | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
|
|
@@ -2389,7 +2347,7 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, | |
| #ifdef DEBUG | ||
| *treeModf = true; | ||
| #endif // DEBUG | ||
| /* Change the node to a GT_COMMA holding the side effect list */ | ||
| // Change the node to a GT_COMMA holding the side effect list | ||
| asgNode->gtBashToNOP(); | ||
|
|
||
| asgNode->ChangeOper(GT_COMMA); | ||
|
|
@@ -2409,7 +2367,6 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, | |
| } | ||
| else | ||
| { | ||
| NO_SIDE_EFFECTS: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love getting rid of |
||
| #ifdef DEBUG | ||
| if (verbose) | ||
| { | ||
|
|
@@ -2420,15 +2377,15 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, | |
| printf("\n"); | ||
| } | ||
| #endif // DEBUG | ||
| /* No side effects - Change the assignment to a GT_NOP node */ | ||
| // No side effects - Change the assignment to a GT_NOP node | ||
| asgNode->gtBashToNOP(); | ||
|
|
||
| #ifdef DEBUG | ||
| *treeModf = true; | ||
| #endif // DEBUG | ||
| } | ||
|
|
||
| /* Re-link the nodes for this statement - Do not update ordering! */ | ||
| // Re-link the nodes for this statement - Do not update ordering! | ||
|
|
||
| // Do not update costs by calling gtSetStmtInfo. fgSetStmtSeq modifies | ||
| // the tree threading based on the new costs. Removing nodes could | ||
|
|
@@ -2439,7 +2396,7 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree, | |
|
|
||
| fgSetStmtSeq(compCurStmt); | ||
|
|
||
| /* Continue analysis from this node */ | ||
| // Continue analysis from this node | ||
|
|
||
| *pTree = asgNode; | ||
|
|
||
|
|
||
57 changes: 57 additions & 0 deletions
57
tests/src/JIT/Regression/JitBlue/GitHub_24253/GitHub_24253.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| using System; | ||
| using System.Runtime.CompilerServices; | ||
|
|
||
| // Test removal of a dead struct assignment when the assignment is "internal" | ||
| // i.e., is not a direct child of a statement node. | ||
| // In this example, the statement is STMT(COMMA(CALL HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, ASG)). | ||
|
|
||
| namespace GitHub_24253 | ||
| { | ||
| struct TestStruct | ||
| { | ||
| public static readonly TestStruct ZeroStruct = new TestStruct(0); | ||
|
|
||
| [MethodImpl(MethodImplOptions.NoInlining)] | ||
| public TestStruct(int i) | ||
| { | ||
| this.i = i; | ||
| this.j = 5; | ||
| this.k = 5; | ||
| this.l = 5; | ||
| } | ||
|
|
||
| int i; | ||
| int j; | ||
| short k; | ||
| short l; | ||
| } | ||
|
|
||
| class Program | ||
| { | ||
| static int Main(string[] args) | ||
| { | ||
| GetStruct(1); | ||
| return 100; | ||
| } | ||
|
|
||
| [MethodImpl(MethodImplOptions.NoInlining)] | ||
| private static TestStruct GetStruct(int i) | ||
| { | ||
| // This is the dead assignment that is causing the bug assert. | ||
| TestStruct result = TestStruct.ZeroStruct; | ||
| try | ||
| { | ||
| result = new TestStruct(i); | ||
| } | ||
| catch | ||
| { | ||
| throw new ArgumentException(); | ||
| } | ||
| return result; | ||
| } | ||
| } | ||
| } |
33 changes: 33 additions & 0 deletions
33
tests/src/JIT/Regression/JitBlue/GitHub_24253/GitHub_24253.csproj
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> | ||
| <PropertyGroup> | ||
| <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
| <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
| <SchemaVersion>2.0</SchemaVersion> | ||
| <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> | ||
| <OutputType>Exe</OutputType> | ||
| <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||
| <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> | ||
| </PropertyGroup> | ||
| <!-- Default configurations to help VS understand the configurations --> | ||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> | ||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | ||
| <ItemGroup> | ||
| <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> | ||
| <Visible>False</Visible> | ||
| </CodeAnalysisDependentAssemblyPaths> | ||
| </ItemGroup> | ||
| <PropertyGroup> | ||
| <DebugType>None</DebugType> | ||
| <Optimize>True</Optimize> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <Compile Include="$(MSBuildProjectName).cs" /> | ||
| </ItemGroup> | ||
| <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> | ||
| <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> | ||
| </Project> |
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.
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.
Is it possible that
pTree != &compCurStmt->gtStmtExpr?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.
pTree is an address of a local GenTree* variable in the caller, (e.g., address of
treeinfgComputeLife.