diff options
author | Pat Gavlin <pagavlin@microsoft.com> | 2017-06-20 18:22:45 -0700 |
---|---|---|
committer | Pat Gavlin <pagavlin@microsoft.com> | 2017-06-24 14:10:19 -0700 |
commit | 04668c8a76da2b1ee07b48e00ae0376ddfbad960 (patch) | |
tree | 76e044caadb00e43853ba89b93aa329a2bef0136 /src | |
parent | ab7f3407fa9a03110157ee659b5145a8f6e392ca (diff) | |
download | coreclr-04668c8a76da2b1ee07b48e00ae0376ddfbad960.tar.gz coreclr-04668c8a76da2b1ee07b48e00ae0376ddfbad960.tar.bz2 coreclr-04668c8a76da2b1ee07b48e00ae0376ddfbad960.zip |
Maintain `LIR::IsUnusedValue` in the backend.
This flag indicates whether or not the SDSU temp produced by a node is
ever read. This information is needed by the register allocator, but is
also useful in other parts of the compiler (for example, `TryGetUse` can
return immediately if this flag is set). Setting this flag properly in
rationalize and maintaining it through decomposition and lowering allows
us to remove an IR walk immediately prior to LSRA.
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/decomposelongs.cpp | 59 | ||||
-rw-r--r-- | src/jit/flowgraph.cpp | 4 | ||||
-rw-r--r-- | src/jit/lir.cpp | 10 | ||||
-rw-r--r-- | src/jit/lir.h | 2 | ||||
-rw-r--r-- | src/jit/liveness.cpp | 5 | ||||
-rw-r--r-- | src/jit/lower.cpp | 19 | ||||
-rw-r--r-- | src/jit/lsra.cpp | 2 | ||||
-rw-r--r-- | src/jit/rationalize.cpp | 20 |
8 files changed, 97 insertions, 24 deletions
diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp index 5c3093a791..74031b2263 100644 --- a/src/jit/decomposelongs.cpp +++ b/src/jit/decomposelongs.cpp @@ -114,7 +114,7 @@ void DecomposeLongs::DecomposeRangeHelper() node = DecomposeNode(node); } - assert(Range().CheckLIR(m_compiler)); + assert(Range().CheckLIR(m_compiler, true)); } //------------------------------------------------------------------------ @@ -339,6 +339,14 @@ GenTree* DecomposeLongs::FinalizeDecomposition(LIR::Use& use, assert(Range().Contains(hiResult)); GenTree* gtLong = new (m_compiler, GT_LONG) GenTreeOp(GT_LONG, TYP_LONG, loResult, hiResult); + if (use.IsDummyUse()) + { + gtLong->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } + + loResult->gtLIRFlags &= ~LIR::Flags::IsUnusedValue; + hiResult->gtLIRFlags &= ~LIR::Flags::IsUnusedValue; + Range().InsertAfter(insertResultAfter, gtLong); use.ReplaceWith(m_compiler, gtLong); @@ -1115,7 +1123,11 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // feeds the hi operand while there are no side effects) if ((hiOp1->gtFlags & GTF_ALL_EFFECT) == 0) { - Range().Remove(hiOp1); + Range().Remove(hiOp1, true); + } + else + { + hiOp1->gtLIRFlags |= LIR::Flags::IsUnusedValue; } if (count < 64) @@ -1159,7 +1171,11 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // that feeds the lo operand while there are no side effects) if ((loOp1->gtFlags & GTF_ALL_EFFECT) == 0) { - Range().Remove(loOp1); + Range().Remove(loOp1, true); + } + else + { + loOp1->gtLIRFlags |= LIR::Flags::IsUnusedValue; } // Zero out hi (shift of >= 64 bits moves all the bits out of the two registers) @@ -1215,7 +1231,11 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // feeds the lo operand while there are no side effects) if ((loOp1->gtFlags & GTF_ALL_EFFECT) == 0) { - Range().Remove(loOp1); + Range().Remove(loOp1, true); + } + else + { + loOp1->gtLIRFlags |= LIR::Flags::IsUnusedValue; } assert(count >= 32); @@ -1247,7 +1267,11 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // that feeds the hi operand while there are no side effects) if ((hiOp1->gtFlags & GTF_ALL_EFFECT) == 0) { - Range().Remove(hiOp1); + Range().Remove(hiOp1, true); + } + else + { + hiOp1->gtLIRFlags |= LIR::Flags::IsUnusedValue; } // Zero out lo @@ -1305,7 +1329,11 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // feeds the lo operand while there are no side effects) if ((loOp1->gtFlags & GTF_ALL_EFFECT) == 0) { - Range().Remove(loOp1); + Range().Remove(loOp1, true); + } + else + { + loOp1->gtLIRFlags |= LIR::Flags::IsUnusedValue; } if (count < 64) @@ -1737,24 +1765,27 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use) index = simdTree->gtOp.gtOp2->gtIntCon.gtIconVal; } - LIR::Use op1(Range(), &simdTree->gtOp.gtOp1, simdTree); - unsigned simdTmpVarNum = op1.ReplaceWithLclVar(m_compiler, m_blockWeight); + GenTree* simdTmpVar = RepresentOpAsLocalVar(simdTree->gtOp.gtOp1, simdTree, &simdTree->gtOp.gtOp1); + unsigned simdTmpVarNum = simdTmpVar->AsLclVarCommon()->gtLclNum; JITDUMP("[DecomposeSimdGetItem]: Saving op1 tree to a temp var:\n"); - DISPTREERANGE(Range(), op1.Def()); + DISPTREERANGE(Range(), simdTmpVar); + Range().Remove(simdTmpVar); + GenTree* indexTmpVar = nullptr; unsigned indexTmpVarNum = 0; if (!indexIsConst) { - LIR::Use op2(Range(), &simdTree->gtOp.gtOp2, simdTree); - indexTmpVarNum = op2.ReplaceWithLclVar(m_compiler, m_blockWeight); + indexTmpVar = RepresentOpAsLocalVar(simdTree->gtOp.gtOp2, simdTree, &simdTree->gtOp.gtOp2); + indexTmpVarNum = indexTmpVar->AsLclVarCommon()->gtLclNum; JITDUMP("[DecomposeSimdGetItem]: Saving op2 tree to a temp var:\n"); - DISPTREERANGE(Range(), op2.Def()); + DISPTREERANGE(Range(), indexTmpVar); + Range().Remove(indexTmpVar); } // Create: // loResult = GT_SIMD{get_item}[int](tmp_simd_var, index * 2) - GenTree* simdTmpVar1 = m_compiler->gtNewLclLNode(simdTmpVarNum, simdTree->gtOp.gtOp1->gtType); + GenTree* simdTmpVar1 = simdTmpVar; GenTree* indexTimesTwo1; if (indexIsConst) @@ -1768,7 +1799,7 @@ GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use) } else { - GenTree* indexTmpVar1 = m_compiler->gtNewLclLNode(indexTmpVarNum, TYP_INT); + GenTree* indexTmpVar1 = indexTmpVar; GenTree* two1 = m_compiler->gtNewIconNode(2, TYP_INT); indexTimesTwo1 = m_compiler->gtNewOperNode(GT_MUL, TYP_INT, indexTmpVar1, two1); Range().InsertBefore(simdTree, simdTmpVar1, indexTmpVar1, two1, indexTimesTwo1); diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index e00e48e0dd..2d48b96d39 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -10298,7 +10298,7 @@ void Compiler::fgRemoveConditionalJump(BasicBlock* block) else { // Otherwise, just remove the jump node itself. - blockRange.Remove(test); + blockRange.Remove(test, true); } } else @@ -14070,7 +14070,7 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi else { // Otherwise, just remove the jump node itself. - blockRange.Remove(jmp); + blockRange.Remove(jmp, true); } } else diff --git a/src/jit/lir.cpp b/src/jit/lir.cpp index b6c36ca7ed..074e0e4639 100644 --- a/src/jit/lir.cpp +++ b/src/jit/lir.cpp @@ -972,11 +972,19 @@ void LIR::Range::InsertAtEnd(Range&& range) // Arguments: // node - The node to remove. Must be part of this range. // -void LIR::Range::Remove(GenTree* node) +void LIR::Range::Remove(GenTree* node, bool markOperandsUnused) { assert(node != nullptr); assert(Contains(node)); + if (markOperandsUnused) + { + for (GenTree* operand : node->Operands()) + { + operand->gtLIRFlags |= Flags::IsUnusedValue; + } + } + GenTree* prev = node->gtPrev; GenTree* next = node->gtNext; diff --git a/src/jit/lir.h b/src/jit/lir.h index e633303244..71c114747f 100644 --- a/src/jit/lir.h +++ b/src/jit/lir.h @@ -279,7 +279,7 @@ public: void InsertAtBeginning(Range&& range); void InsertAtEnd(Range&& range); - void Remove(GenTree* node); + void Remove(GenTree* node, bool markOperandsUnused = false); Range Remove(GenTree* firstNode, GenTree* lastNode); Range Remove(ReadOnlyRange&& range); diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp index b6aea60fc4..1ffb2ed2f2 100644 --- a/src/jit/liveness.cpp +++ b/src/jit/liveness.cpp @@ -2278,6 +2278,11 @@ bool Compiler::fgTryRemoveDeadLIRStore(LIR::Range& blockRange, GenTree* node, Ge // If the range of the operands contains unrelated code or if it contains any side effects, // do not remove it. Instead, just remove the store. + for (GenTree* operand : node->Operands()) + { + operand->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } + *next = node->gtPrev; } else diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index a626ff98e7..a623461387 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -2155,6 +2155,10 @@ void Lowering::LowerCompare(GenTree* cmp) comp->lvaDecRefCnts(m_block, loSrc1); } } + else + { + loSrc1->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } hiCmp = comp->gtNewOperNode(GT_CMP, TYP_VOID, hiSrc1, hiSrc2); BlockRange().InsertBefore(cmp, hiCmp); @@ -2182,6 +2186,10 @@ void Lowering::LowerCompare(GenTree* cmp) } hiCmp->gtFlags |= GTF_SET_FLAGS; + if (hiCmp->IsValue()) + { + hiCmp->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } LIR::Use cmpUse; if (BlockRange().TryGetUse(cmp, &cmpUse) && cmpUse.User()->OperIs(GT_JTRUE)) @@ -4410,6 +4418,10 @@ GenTree* Lowering::LowerArrElem(GenTree* node) { arrElemUse.ReplaceWith(comp, leaNode); } + else + { + leaNode->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } BlockRange().Remove(arrElem); @@ -4513,6 +4525,7 @@ void Lowering::DoPhase() comp->fgLocalVarLiveness(); } } + #ifdef DEBUG JITDUMP("Liveness pass finished after lowering, IR:\n"); JITDUMP("lvasortagain = %d\n", comp->lvaSortAgain); @@ -4522,6 +4535,8 @@ void Lowering::DoPhase() } #endif + assert(BlockRange().CheckLIR(comp, true)); + // The initialization code for the TreeNodeInfo map was initially part of a single full IR // traversal and it has been split because the order of traversal performed by fgWalkTreePost // does not necessarily lower nodes in execution order and also, it could potentially @@ -4589,7 +4604,7 @@ void Lowering::DoPhase() assert((node->gtLsraInfo.dstCount == 0) || node->IsValue()); // If the node produces an unused value, mark it as a local def-use - if ((node->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0) + if (node->IsValue() && ((node->gtLIRFlags & LIR::Flags::IsUnusedValue) != 0)) { node->gtLsraInfo.isLocalDefUse = true; node->gtLsraInfo.dstCount = 0; @@ -4726,7 +4741,7 @@ bool Lowering::CheckBlock(Compiler* compiler, BasicBlock* block) CheckNode(node); } - assert(blockRange.CheckLIR(compiler)); + assert(blockRange.CheckLIR(compiler, true)); return true; } #endif diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp index b6117d249a..9fc536a9ff 100644 --- a/src/jit/lsra.cpp +++ b/src/jit/lsra.cpp @@ -4770,7 +4770,7 @@ void LinearScan::buildIntervals() for (GenTree* node : blockRange.NonPhiNodes()) { assert(node->gtLsraInfo.loc >= currentLoc); - assert(((node->gtLIRFlags & LIR::Flags::IsUnusedValue) == 0) || node->gtLsraInfo.isLocalDefUse); + assert(!node->IsValue() || ((node->gtLIRFlags & LIR::Flags::IsUnusedValue) == 0) || node->gtLsraInfo.isLocalDefUse); currentLoc = node->gtLsraInfo.loc; buildRefPositionsForNode(node, block, listNodePool, operandToLocationInfoMap, currentLoc); diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp index 0afdff40ac..c7f63a3cb4 100644 --- a/src/jit/rationalize.cpp +++ b/src/jit/rationalize.cpp @@ -790,11 +790,18 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStack<G BlockRange().Delete(comp, m_block, std::move(lhsRange)); } + else + { + op1->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } + + BlockRange().Remove(node); GenTree* replacement = node->gtGetOp2(); if (!use.IsDummyUse()) { use.ReplaceWith(comp, replacement); + node = replacement; } else { @@ -812,9 +819,11 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStack<G BlockRange().Delete(comp, m_block, std::move(rhsRange)); } + else + { + node = replacement; + } } - - BlockRange().Remove(node); } break; @@ -984,6 +993,11 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStack<G node->gtFlags &= ~GTF_CALL; } + if (use.IsDummyUse()) + { + node->gtLIRFlags |= LIR::Flags::IsUnusedValue; + } + if (node->TypeGet() == TYP_LONG) { comp->compLongUsed = true; @@ -1096,7 +1110,7 @@ void Rationalizer::DoPhase() this, true); } - assert(BlockRange().CheckLIR(comp)); + assert(BlockRange().CheckLIR(comp, true)); } comp->compRationalIRForm = true; |