diff options
author | Pat Gavlin <pgavlin@gmail.com> | 2016-12-14 11:21:17 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-14 11:21:17 -0800 |
commit | b038f9094345f04564e88d8525e0b3ea110ef6e6 (patch) | |
tree | e7760c920bda53d4b25d8fc9e0771b1c114cbf34 /src/jit | |
parent | deb75b4f815fd4d86ad444d19eec50f0f869f994 (diff) | |
parent | 795435d457d4c06b85354afa3ff075a919497292 (diff) | |
download | coreclr-b038f9094345f04564e88d8525e0b3ea110ef6e6.tar.gz coreclr-b038f9094345f04564e88d8525e0b3ea110ef6e6.tar.bz2 coreclr-b038f9094345f04564e88d8525e0b3ea110ef6e6.zip |
Merge pull request #8601 from pgavlin/gh7963
Fix consume-order checking in codegen.
Diffstat (limited to 'src/jit')
-rwxr-xr-x | src/jit/codegen.h | 2 | ||||
-rw-r--r-- | src/jit/codegenarm.cpp | 4 | ||||
-rw-r--r-- | src/jit/codegenarm64.cpp | 4 | ||||
-rw-r--r-- | src/jit/codegenlinear.cpp | 96 | ||||
-rw-r--r-- | src/jit/codegenlinear.h | 3 | ||||
-rw-r--r-- | src/jit/codegenxarch.cpp | 15 | ||||
-rw-r--r-- | src/jit/gentree.h | 5 |
7 files changed, 84 insertions, 45 deletions
diff --git a/src/jit/codegen.h b/src/jit/codegen.h index b6c8c18b29..c6e38ab6af 100755 --- a/src/jit/codegen.h +++ b/src/jit/codegen.h @@ -122,7 +122,7 @@ private: void genRangeCheck(GenTree* node); - void genLockedInstructions(GenTree* node); + void genLockedInstructions(GenTreeOp* node); //------------------------------------------------------------------------- // Register-related methods diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp index 076fb0fb67..73e51f2ef7 100644 --- a/src/jit/codegenarm.cpp +++ b/src/jit/codegenarm.cpp @@ -662,7 +662,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_LOCKADD: case GT_XCHG: case GT_XADD: - genLockedInstructions(treeNode); + genLockedInstructions(treeNode->AsOp()); break; case GT_CMPXCHG: @@ -750,7 +750,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) // generate code for the locked operations: // GT_LOCKADD, GT_XCHG, GT_XADD -void CodeGen::genLockedInstructions(GenTree* treeNode) +void CodeGen::genLockedInstructions(GenTreeOp* treeNode) { NYI("genLockedInstructions"); } diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp index 65477faca8..cc7c5dc524 100644 --- a/src/jit/codegenarm64.cpp +++ b/src/jit/codegenarm64.cpp @@ -2731,7 +2731,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_LOCKADD: case GT_XCHG: case GT_XADD: - genLockedInstructions(treeNode); + genLockedInstructions(treeNode->AsOp()); break; case GT_MEMORYBARRIER: @@ -3719,7 +3719,7 @@ void CodeGen::genJumpTable(GenTree* treeNode) // generate code for the locked operations: // GT_LOCKADD, GT_XCHG, GT_XADD -void CodeGen::genLockedInstructions(GenTree* treeNode) +void CodeGen::genLockedInstructions(GenTreeOp* treeNode) { #if 0 GenTree* data = treeNode->gtOp.gtOp2; diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp index 8cd521494b..9713288e08 100644 --- a/src/jit/codegenlinear.cpp +++ b/src/jit/codegenlinear.cpp @@ -313,13 +313,6 @@ void CodeGen::genCodeForBBlist() bool firstMapping = true; - /*--------------------------------------------------------------------- - * - * Generate code for each statement-tree in the block - * - */ - CLANG_FORMAT_COMMENT_ANCHOR; - #if FEATURE_EH_FUNCLETS if (block->bbFlags & BBF_FUNCLET_BEG) { @@ -335,6 +328,28 @@ void CodeGen::genCodeForBBlist() // as we encounter it. CLANG_FORMAT_COMMENT_ANCHOR; +#ifdef DEBUG + // Set the use-order numbers for each node. + { + int useNum = 0; + for (GenTree* node : LIR::AsRange(block).NonPhiNodes()) + { + assert((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) == 0); + + node->gtUseNum = -1; + if (node->isContained() || node->IsCopyOrReload()) + { + continue; + } + + for (GenTree* operand : node->Operands()) + { + genNumberOperandUse(operand, useNum); + } + } + } +#endif // DEBUG + IL_OFFSETX currentILOffset = BAD_IL_OFFSET; for (GenTree* node : LIR::AsRange(block).NonPhiNodes()) { @@ -1031,34 +1046,55 @@ void CodeGen::genConsumeRegAndCopy(GenTree* node, regNumber needReg) // Check that registers are consumed in the right order for the current node being generated. #ifdef DEBUG -void CodeGen::genCheckConsumeNode(GenTree* treeNode) +void CodeGen::genNumberOperandUse(GenTree* const operand, int& useNum) const { - // GT_PUTARG_REG is consumed out of order. - if (treeNode->gtSeqNum != 0 && treeNode->OperGet() != GT_PUTARG_REG) + assert(operand != nullptr); + assert(operand->gtUseNum == -1); + + // Ignore argument placeholders. + if (operand->OperGet() == GT_ARGPLACE) { - if (lastConsumedNode != nullptr) + return; + } + + if (!operand->isContained() && !operand->IsCopyOrReload()) + { + operand->gtUseNum = useNum; + useNum++; + } + else + { + for (GenTree* operand : operand->Operands()) { - if (treeNode == lastConsumedNode) - { - if (verbose) - { - printf("Node was consumed twice:\n "); - compiler->gtDispTree(treeNode, nullptr, nullptr, true); - } - } - else - { - if (verbose && (lastConsumedNode->gtSeqNum > treeNode->gtSeqNum)) - { - printf("Nodes were consumed out-of-order:\n"); - compiler->gtDispTree(lastConsumedNode, nullptr, nullptr, true); - compiler->gtDispTree(treeNode, nullptr, nullptr, true); - } - // assert(lastConsumedNode->gtSeqNum < treeNode->gtSeqNum); - } + genNumberOperandUse(operand, useNum); + } + } +} + +void CodeGen::genCheckConsumeNode(GenTree* const node) +{ + assert(node != nullptr); + + if (verbose) + { + if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0) + { + printf("Node was consumed twice:\n"); + compiler->gtDispTree(node, nullptr, nullptr, true); + } + else if ((lastConsumedNode != nullptr) && (node->gtUseNum < lastConsumedNode->gtUseNum)) + { + printf("Nodes were consumed out-of-order:\n"); + compiler->gtDispTree(lastConsumedNode, nullptr, nullptr, true); + compiler->gtDispTree(node, nullptr, nullptr, true); } - lastConsumedNode = treeNode; } + + assert((node->OperGet() == GT_CATCH_ARG) || ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) == 0)); + assert((lastConsumedNode == nullptr) || (node->gtUseNum == -1) || (node->gtUseNum > lastConsumedNode->gtUseNum)); + + node->gtDebugFlags |= GTF_DEBUG_NODE_CG_CONSUMED; + lastConsumedNode = node; } #endif // DEBUG diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h index 1f5fca9d5e..1ecfba102e 100644 --- a/src/jit/codegenlinear.h +++ b/src/jit/codegenlinear.h @@ -256,7 +256,8 @@ unsigned m_stkArgOffset; #ifdef DEBUG GenTree* lastConsumedNode; -void genCheckConsumeNode(GenTree* treeNode); +void genNumberOperandUse(GenTree* const operand, int& useNum) const; +void genCheckConsumeNode(GenTree* const node); #else // !DEBUG inline void genCheckConsumeNode(GenTree* treeNode) { diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp index 1adefc12c9..8e0af48799 100644 --- a/src/jit/codegenxarch.cpp +++ b/src/jit/codegenxarch.cpp @@ -2006,7 +2006,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_LOCKADD: case GT_XCHG: case GT_XADD: - genLockedInstructions(treeNode); + genLockedInstructions(treeNode->AsOp()); break; case GT_MEMORYBARRIER: @@ -3796,7 +3796,7 @@ void CodeGen::genJumpTable(GenTree* treeNode) // generate code for the locked operations: // GT_LOCKADD, GT_XCHG, GT_XADD -void CodeGen::genLockedInstructions(GenTree* treeNode) +void CodeGen::genLockedInstructions(GenTreeOp* treeNode) { GenTree* data = treeNode->gtOp.gtOp2; GenTree* addr = treeNode->gtOp.gtOp1; @@ -3805,11 +3805,6 @@ void CodeGen::genLockedInstructions(GenTree* treeNode) regNumber addrReg = addr->gtRegNum; instruction ins; - // all of these nodes implicitly do an indirection on op1 - // so create a temporary node to feed into the pattern matching - GenTreeIndir i = indirForm(data->TypeGet(), addr); - genConsumeReg(addr); - // The register allocator should have extended the lifetime of the address // so that it is not used as the target. noway_assert(addrReg != targetReg); @@ -3819,7 +3814,7 @@ void CodeGen::genLockedInstructions(GenTree* treeNode) assert(targetReg != REG_NA || treeNode->OperGet() == GT_LOCKADD || !genIsRegCandidateLocal(data) || (data->gtFlags & GTF_VAR_DEATH) != 0); - genConsumeIfReg(data); + genConsumeOperands(treeNode); if (targetReg != REG_NA && dataReg != REG_NA && dataReg != targetReg) { inst_RV_RV(ins_Copy(data->TypeGet()), targetReg, dataReg); @@ -3845,6 +3840,10 @@ void CodeGen::genLockedInstructions(GenTree* treeNode) default: unreached(); } + + // all of these nodes implicitly do an indirection on op1 + // so create a temporary node to feed into the pattern matching + GenTreeIndir i = indirForm(data->TypeGet(), addr); getEmitter()->emitInsBinary(ins, emitTypeSize(data), &i, data); if (treeNode->gtRegNum != REG_NA) diff --git a/src/jit/gentree.h b/src/jit/gentree.h index b5390f3841..4611d35465 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -971,8 +971,9 @@ public: #define GTF_DEBUG_NODE_SMALL 0x00000002 #define GTF_DEBUG_NODE_LARGE 0x00000004 #define GTF_DEBUG_NODE_CG_PRODUCED 0x00000008 // genProduceReg has been called on this node +#define GTF_DEBUG_NODE_CG_CONSUMED 0x00000010 // genConsumeReg has been called on this node -#define GTF_DEBUG_NODE_MASK 0x0000000F // These flags are all node (rather than operation) properties. +#define GTF_DEBUG_NODE_MASK 0x0000001F // These flags are all node (rather than operation) properties. #define GTF_DEBUG_VAR_CSE_REF 0x00800000 // GT_LCL_VAR -- This is a CSE LCL_VAR node #endif // defined(DEBUG) @@ -983,6 +984,8 @@ public: #ifdef DEBUG unsigned gtTreeID; unsigned gtSeqNum; // liveness traversal order within the current statement + + int gtUseNum; // use-ordered traversal within the function #endif static const unsigned short gtOperKindTable[]; |