diff options
author | Russ Keldorph <Russ.Keldorph@microsoft.com> | 2016-01-11 16:51:49 -0800 |
---|---|---|
committer | Russ Keldorph <Russ.Keldorph@microsoft.com> | 2016-01-12 15:25:08 -0800 |
commit | 8657824294d106720cef63d872beeca7bc277e1b (patch) | |
tree | 1f91edb12486e59faefa38b31f096b93c51be1bd /src | |
parent | fb9eda843f9fc89656a9782ea46c0df8ec4d75e3 (diff) | |
download | coreclr-8657824294d106720cef63d872beeca7bc277e1b.tar.gz coreclr-8657824294d106720cef63d872beeca7bc277e1b.tar.bz2 coreclr-8657824294d106720cef63d872beeca7bc277e1b.zip |
Do loop cloning only if zero trip test can be ensured.
The problem is our loop detection logic detects the loop structure, but it
doesnt know the code outside the loop structure, esp., nothing about the
edge from the "head" into the loop "entry" block.
In the bug case, there is no zero-trip test in the "head", so the entrance
into the loop is not guarded. Note that the other point of entrance into
the "entry" block is from the "top" block which will be guarded by the
loop "bottom" test.
One way to make sure is when we invert a while loop into a do-while with
an explicit compiler cloned zero trip test, in fgOptWhileLoop, i.e., we
mark it as good to optimize with a flag. The fix marks the loop as ZTT.
The caveat is the JIT doesnt always do loop inversion.
This change is more conservative than it needs to be in the interest of
managing risk.
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/gentree.h | 1 | ||||
-rw-r--r-- | src/jit/optimizer.cpp | 15 |
2 files changed, 15 insertions, 1 deletions
diff --git a/src/jit/gentree.h b/src/jit/gentree.h index ee80ce5d64..9756dcbd6a 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -846,6 +846,7 @@ public: #define GTF_RELOP_JMP_USED 0x40000000 // GT_<relop> -- result of compare used for jump or ?: #define GTF_RELOP_QMARK 0x20000000 // GT_<relop> -- the node is the condition for ?: #define GTF_RELOP_SMALL 0x10000000 // GT_<relop> -- We should use a byte or short sized compare (op1->gtType is the small type) + #define GTF_RELOP_ZTT 0x08000000 // GT_<relop> -- Loop test cloned for converting while-loops into do-while with explicit "loop test" in the header block. #define GTF_QMARK_CAST_INSTOF 0x80000000 // GT_QMARK -- Is this a top (not nested) level qmark created for castclass or instanceof? diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index ff22902e55..67c963fb92 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -3428,8 +3428,9 @@ void Compiler::fgOptWhileLoop(BasicBlock * block) #ifdef DEBUG if (verbose) { - printf("\nDuplication of loop condition %s, because the cost of duplication (%i) is %s than %i," + printf("\nDuplication of loop condition [%06u] is %s, because the cost of duplication (%i) is %s than %i," "\n loopIterations = %7.3f, countOfHelpers = %d, validProfileWeights = %s\n", + condTree->gtTreeID, costIsTooHigh ? "not done" : "performed", estDupCostSz, costIsTooHigh ? "greater" : "less or equal", @@ -3446,9 +3447,14 @@ void Compiler::fgOptWhileLoop(BasicBlock * block) /* Looks good - duplicate the condition test */ + condTree->gtFlags |= GTF_RELOP_ZTT; + condTree = gtCloneExpr(condTree); gtReverseCond(condTree); + // Make sure clone expr copied the flag + assert(condTree->gtFlags & GTF_RELOP_ZTT); + condTree = gtNewOperNode(GT_JTRUE, TYP_VOID, condTree); /* Create a statement entry out of the condition and @@ -7270,6 +7276,13 @@ bool Compiler::optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneC GenTree::NodeName(pLoop->lpTestOper()), GenTree::NodeName(pLoop->lpIterOper())); return false; } + + if (!(pLoop->lpTestTree->OperKind() & GTK_RELOP) || !(pLoop->lpTestTree->gtFlags & GTF_RELOP_ZTT)) + { + JITDUMP("> Loop inversion NOT present, loop test [%06u] may not protect entry from head.\n", pLoop->lpTestTree->gtTreeID); + return false; + } + #ifdef DEBUG GenTreePtr op1 = pLoop->lpIterator(); noway_assert((op1->gtOper == GT_LCL_VAR) && (op1->gtLclVarCommon.gtLclNum == ivLclNum)); |