Introduce GT_JCC.
authorPat Gavlin <pagavlin@microsoft.com>
Wed, 14 Sep 2016 02:32:57 +0000 (19:32 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Wed, 14 Sep 2016 17:33:37 +0000 (10:33 -0700)
This node represents a jump that is conditional upon the value stored in
the target's condition code register. It is only valid in the backend.
No formal modeling of the CCR is performed, so its use must be
constrained such that instructions that def the CCR are not inserted
between the JCC node and the node that it expected to def the CCR.

This is currently only used when lowering compares of long-typed
values for x86.

Commit migrated from https://github.com/dotnet/coreclr/commit/4351a27c18a88c50c0e701975d9a58f5ade57e78

src/coreclr/src/jit/codegenxarch.cpp
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/gentree.cpp
src/coreclr/src/jit/gentree.h
src/coreclr/src/jit/gtlist.h
src/coreclr/src/jit/gtstructs.h
src/coreclr/src/jit/lir.cpp
src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/lowerxarch.cpp
src/coreclr/src/jit/lsra.cpp

index 6c73a0c..f715999 100644 (file)
@@ -2531,6 +2531,19 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
         }
         break;
 
+        case GT_JCC:
+        {
+            GenTreeJumpCC* jcc = treeNode->AsJumpCC();
+
+            assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
+
+            CompareKind compareKind = ((jcc->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+            emitJumpKind jumpKind   = genJumpKindForOper(jcc->gtCondition, compareKind);
+
+            inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
+        }
+        break;
+
         case GT_RETURNTRAP:
         {
             // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
index 28dddb1..50cc3f9 100644 (file)
@@ -4072,7 +4072,7 @@ public:
 
     void fgUnreachableBlock(BasicBlock* block);
 
-    void fgRemoveJTrue(BasicBlock* block);
+    void fgRemoveConditionalJump(BasicBlock* block);
 
     BasicBlock* fgLastBBInMainFunction();
 
index 9458967..9e6fd1c 100644 (file)
@@ -9339,6 +9339,7 @@ inline bool OperIsControlFlow(genTreeOps oper)
     switch (oper)
     {
         case GT_JTRUE:
+        case GT_JCC:
         case GT_SWITCH:
         case GT_LABEL:
 
@@ -10019,10 +10020,10 @@ void Compiler::fgUnreachableBlock(BasicBlock* block)
 
 /*****************************************************************************************************
  *
- *  Function called to remove or morph a GT_JTRUE statement when we jump to the same
+ *  Function called to remove or morph a jump when we jump to the same
  *  block when both the condition is true or false.
  */
-void Compiler::fgRemoveJTrue(BasicBlock* block)
+void Compiler::fgRemoveConditionalJump(BasicBlock* block)
 {
     noway_assert(block->bbJumpKind == BBJ_COND && block->bbJumpDest == block->bbNext);
     assert(compRationalIRForm == block->IsLIR());
@@ -10053,7 +10054,7 @@ void Compiler::fgRemoveJTrue(BasicBlock* block)
         LIR::Range& blockRange = LIR::AsRange(block);
 
         GenTree* test = blockRange.LastNode();
-        assert(test->OperGet() == GT_JTRUE);
+        assert(test->OperIsConditionalJump());
 
         bool               isClosed;
         unsigned           sideEffects;
@@ -10109,7 +10110,7 @@ void Compiler::fgRemoveJTrue(BasicBlock* block)
         {
             test->gtStmtExpr = sideEffList;
 
-            fgMorphBlockStmt(block, test DEBUGARG("fgRemoveJTrue"));
+            fgMorphBlockStmt(block, test DEBUGARG("fgRemoveConditionalJump"));
         }
     }
 }
@@ -10545,7 +10546,7 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
                         // Make sure we are replacing "block" with "succBlock" in predBlock->bbJumpDest.
                         noway_assert(predBlock->bbJumpDest == block);
                         predBlock->bbJumpDest = succBlock;
-                        fgRemoveJTrue(predBlock);
+                        fgRemoveConditionalJump(predBlock);
                         break;
                     }
 
@@ -10605,7 +10606,7 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
                 /* Check for branch to next block */
                 if (bPrev->bbJumpDest == bPrev->bbNext)
                 {
-                    fgRemoveJTrue(bPrev);
+                    fgRemoveConditionalJump(bPrev);
                 }
                 break;
 
@@ -13793,7 +13794,7 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi
         {
             LIR::Range& blockRange = LIR::AsRange(block);
             GenTree*    jmp        = blockRange.LastNode();
-            assert(jmp->OperGet() == GT_JTRUE);
+            assert(jmp->OperIsConditionalJump());
 
             bool               isClosed;
             unsigned           sideEffects;
@@ -15879,11 +15880,18 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication)
                         /* Reverse the jump condition */
 
                         GenTree* test = block->lastNode();
-                        noway_assert(test->gtOper == GT_JTRUE);
+                        noway_assert(test->OperIsConditionalJump());
 
-                        GenTree* cond = gtReverseCond(test->gtOp.gtOp1);
-                        assert(cond == test->gtOp.gtOp1); // Ensure `gtReverseCond` did not create a new node.
-                        test->gtOp.gtOp1 = cond;
+                        if (test->OperGet() == GT_JTRUE)
+                        {
+                            GenTree* cond = gtReverseCond(test->gtOp.gtOp1);
+                            assert(cond == test->gtOp.gtOp1); // Ensure `gtReverseCond` did not create a new node.
+                            test->gtOp.gtOp1 = cond;
+                        }
+                        else
+                        {
+                            gtReverseCond(test);
+                        }
 
                         // Optimize the Conditional JUMP to go to the new target
                         block->bbJumpDest = bNext->bbJumpDest;
@@ -19937,11 +19945,11 @@ void                Compiler::fgDebugCheckBBlist(bool checkBBNum  /* = false */,
 
         // If the block is a BBJ_COND, a BBJ_SWITCH or a
         // lowered GT_SWITCH_TABLE node then make sure it
-        // ends with a GT_JTRUE or a GT_SWITCH
+        // ends with a jump or a GT_SWITCH
 
         if (block->bbJumpKind == BBJ_COND)
         {
-            noway_assert(block->lastNode()->gtNext == nullptr && block->lastNode()->gtOper == GT_JTRUE);
+            noway_assert(block->lastNode()->gtNext == nullptr && block->lastNode()->OperIsConditionalJump());
         }
         else if (block->bbJumpKind == BBJ_SWITCH)
         {
index 159469f..8df171f 100644 (file)
@@ -3171,6 +3171,11 @@ GenTreePtr Compiler::gtReverseCond(GenTree* tree)
             tree->gtFlags ^= GTF_RELOP_NAN_UN;
         }
     }
+    else if (tree->OperGet() == GT_JCC)
+    {
+        GenTreeJumpCC* jcc = tree->AsJumpCC();
+        jcc->gtCondition = GenTree::ReverseRelop(jcc->gtCondition);
+    }
     else
     {
         tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
@@ -10763,6 +10768,10 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
             }
             break;
 
+        case GT_JCC:
+            printf(" cond=%s", GenTree::NodeName(tree->AsJumpCC()->gtCondition));
+            break;
+
         default:
             assert(!"don't know how to display tree leaf node");
     }
@@ -15381,6 +15390,7 @@ bool GenTree::isContained() const
     {
         case GT_STOREIND:
         case GT_JTRUE:
+        case GT_JCC:
         case GT_RETURN:
         case GT_RETFILT:
         case GT_STORE_LCL_FLD:
index 18108b8..3ce0895 100644 (file)
@@ -1428,6 +1428,11 @@ public:
         return (gtOper == GT_LIST) && ((gtFlags & GTF_LIST_AGGREGATE) != 0);
     }
 
+    bool OperIsConditionalJump()
+    {
+        return (gtOper == GT_JTRUE) || (gtOper == GT_JCC);
+    }
+
     // Requires that "op" is an op= operator.  Returns
     // the corresponding "op".
     static genTreeOps OpAsgToOper(genTreeOps op);
@@ -4640,6 +4645,26 @@ struct GenTreeAllocObj final : public GenTreeUnOp
 #endif
 };
 
+
+struct GenTreeJumpCC final : public GenTree
+{
+    genTreeOps gtCondition; // any relop
+
+    GenTreeJumpCC(genTreeOps condition)
+        : GenTree(GT_JCC, TYP_VOID DEBUGARG(/*largeNode*/ FALSE))
+        , gtCondition(condition)
+    {
+        assert(OperIsCompare(condition));
+    }
+
+#if DEBUGGABLE_GENTREE
+    GenTreeJumpCC()
+        : GenTree()
+    {
+    }
+#endif // DEBUGGABLE_GENTREE
+};
+
 //------------------------------------------------------------------------
 // Deferred inline functions of GenTree -- these need the subtypes above to
 // be defined already.
index 4c69022..15ab933 100644 (file)
@@ -190,6 +190,7 @@ GTNODE(SIMD       , "simd"       ,0,GTK_BINOP|GTK_EXOP)   // SIMD functions/oper
 //-----------------------------------------------------------------------------
 
 GTNODE(JTRUE      , "jmpTrue"    ,0,GTK_UNOP|GTK_NOVALUE)
+GTNODE(JCC        , "jcc"        ,0,GTK_LEAF|GTK_NOVALUE)
 
 GTNODE(LIST       , "<list>"     ,0,GTK_BINOP)
 
index 895d3b6..e0e1ee5 100644 (file)
@@ -100,6 +100,7 @@ GTSTRUCT_1(PhysReg     , GT_PHYSREG)
 GTSTRUCT_1(SIMD        , GT_SIMD) 
 #endif // FEATURE_SIMD
 GTSTRUCT_1(AllocObj    , GT_ALLOCOBJ)
+GTSTRUCT_1(JumpCC      , GT_JCC)
 /*****************************************************************************/
 #undef  GTSTRUCT_0
 #undef  GTSTRUCT_1
index 94206de..ed39dce 100644 (file)
@@ -1617,7 +1617,7 @@ void LIR::InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range)
         switch (block->bbJumpKind)
         {
         case BBJ_COND:
-            assert(insertionPoint->OperGet() == GT_JTRUE);
+            assert(insertionPoint->OperIsConditionalJump());
             break;
 
         case BBJ_SWITCH:
index 015020a..e0d840f 100644 (file)
@@ -1892,37 +1892,25 @@ void Lowering::LowerCompare(GenTree* cmp)
     unsigned weight = m_block->getBBWeight(comp);
 
     LIR::Use loSrc1(BlockRange(), &(src1->gtOp.gtOp1), src1);
-    LIR::Use hiSrc1(BlockRange(), &(src1->gtOp.gtOp2), src1);
     LIR::Use loSrc2(BlockRange(), &(src2->gtOp.gtOp1), src2);
-    LIR::Use hiSrc2(BlockRange(), &(src2->gtOp.gtOp2), src2);
 
     if (loSrc1.Def()->OperGet() != GT_CNS_INT && loSrc1.Def()->OperGet() != GT_LCL_VAR)
     {
         loSrc1.ReplaceWithLclVar(comp, weight);
     }
     
-    if (hiSrc1.Def()->OperGet() != GT_CNS_INT && hiSrc1.Def()->OperGet() != GT_LCL_VAR)
-    {
-        hiSrc1.ReplaceWithLclVar(comp, weight);
-    }
-    
     if (loSrc2.Def()->OperGet() != GT_CNS_INT && loSrc2.Def()->OperGet() != GT_LCL_VAR)
     {
         loSrc2.ReplaceWithLclVar(comp, weight);
     }
-    
-    if (hiSrc2.Def()->OperGet() != GT_CNS_INT && hiSrc2.Def()->OperGet() != GT_LCL_VAR)
-    {
-        hiSrc2.ReplaceWithLclVar(comp, weight);
-    }
 
     BasicBlock* jumpDest = m_block->bbJumpDest;
     BasicBlock* nextDest = m_block->bbNext;
     BasicBlock* newBlock = comp->fgSplitBlockAtEnd(m_block);
 
     cmp->gtType     = TYP_INT;
-    cmp->gtOp.gtOp1 = hiSrc1.Def();
-    cmp->gtOp.gtOp2 = hiSrc2.Def();
+    cmp->gtOp.gtOp1 = src1->gtOp.gtOp2;
+    cmp->gtOp.gtOp2 = src2->gtOp.gtOp2;
 
     if (cmp->OperGet() == GT_EQ || cmp->OperGet() == GT_NE)
     {
@@ -1930,8 +1918,8 @@ void Lowering::LowerCompare(GenTree* cmp)
         BlockRange().Remove(loSrc2.Def());
         GenTree* loCmp = comp->gtNewOperNode(cmp->OperGet(), TYP_INT, loSrc1.Def(), loSrc2.Def());
         loCmp->gtFlags = cmp->gtFlags;
-        GenTree* loJcc = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, loCmp);
-        LIR::AsRange(newBlock).InsertAfter(nullptr, loSrc1.Def(), loSrc2.Def(), loCmp, loJcc);
+        GenTree* loJtrue = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, loCmp);
+        LIR::AsRange(newBlock).InsertAfter(nullptr, loSrc1.Def(), loSrc2.Def(), loCmp, loJtrue);
 
         m_block->bbJumpKind = BBJ_COND;
 
@@ -1984,19 +1972,16 @@ void Lowering::LowerCompare(GenTree* cmp)
 
         BasicBlock* newBlock2 = comp->fgSplitBlockAtEnd(newBlock);
 
-        GenTree* hiSrc1Def = comp->gtClone(hiSrc1.Def());
-        GenTree* hiSrc2Def = comp->gtClone(hiSrc2.Def());
-        GenTree* hiCmp = comp->gtNewOperNode(hiCmpOper, TYP_INT, hiSrc1Def, hiSrc2Def);
-        hiCmp->gtFlags = cmp->gtFlags;
-        GenTree* hiJcc = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, hiCmp);
-        LIR::AsRange(newBlock).InsertAfter(nullptr, hiSrc1Def, hiSrc2Def, hiCmp, hiJcc);
+        GenTree* hiJcc = new (comp, GT_JCC) GenTreeJumpCC(hiCmpOper);
+        hiJcc->gtFlags = cmp->gtFlags;
+        LIR::AsRange(newBlock).InsertAfter(nullptr, hiJcc);
 
         BlockRange().Remove(loSrc1.Def());
         BlockRange().Remove(loSrc2.Def());
         GenTree* loCmp = comp->gtNewOperNode(loCmpOper, TYP_INT, loSrc1.Def(), loSrc2.Def());
         loCmp->gtFlags = cmp->gtFlags | GTF_UNSIGNED;
-        GenTree* loJcc = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, loCmp);
-        LIR::AsRange(newBlock2).InsertAfter(nullptr, loSrc1.Def(), loSrc2.Def(), loCmp, loJcc);
+        GenTree* loJtrue = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, loCmp);
+        LIR::AsRange(newBlock2).InsertAfter(nullptr, loSrc1.Def(), loSrc2.Def(), loCmp, loJtrue);
 
         m_block->bbJumpKind = BBJ_COND;
         m_block->bbJumpDest = nextDest;
index 72c1ec8..cbd85e3 100644 (file)
@@ -323,6 +323,11 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
             l->clearDstCount(tree->gtOp.gtOp1);
             break;
 
+        case GT_JCC:
+            info->srcCount = 0;
+            info->dstCount = 0;
+            break;
+
         case GT_JMP:
             info->srcCount = 0;
             info->dstCount = 0;
index d4dcad7..72bed5f 100644 (file)
@@ -8529,7 +8529,7 @@ void LinearScan::insertMove(
             noway_assert(!blockRange.IsEmpty());
 
             GenTree* branch = blockRange.LastNode();
-            assert(branch->OperGet() == GT_JTRUE || branch->OperGet() == GT_SWITCH_TABLE ||
+            assert(branch->OperIsConditionalJump() || branch->OperGet() == GT_SWITCH_TABLE ||
                    branch->OperGet() == GT_SWITCH);
 
             blockRange.InsertBefore(branch, std::move(treeRange));
@@ -8600,7 +8600,7 @@ void LinearScan::insertSwap(
             noway_assert(!blockRange.IsEmpty());
 
             GenTree* branch = blockRange.LastNode();
-            assert(branch->OperGet() == GT_JTRUE || branch->OperGet() == GT_SWITCH_TABLE ||
+            assert(branch->OperIsConditionalJump() || branch->OperGet() == GT_SWITCH_TABLE ||
                    branch->OperGet() == GT_SWITCH);
 
             blockRange.InsertBefore(branch, std::move(swapRange));