Fix method and basic block flags used by early opts. (#2126)
authorEugene Rozenfeld <erozen@microsoft.com>
Mon, 27 Jan 2020 20:03:06 +0000 (12:03 -0800)
committerGitHub <noreply@github.com>
Mon, 27 Jan 2020 20:03:06 +0000 (12:03 -0800)
Fix method and basic block flags used by early opts.

Add missing BBF_HAS_NULLCHECK in loop test transformation.
This change had no diffs in frameworks and benchmark.

Add missing OMF_HAS_ARRAYREF and BBF_HAS_IDX_LEN in many places.
This change had diffs in frameworks and benchmark since the optimization
replacing GT_ARRLENGTH with a constant fires much more often.

Fix inlining to not lose basic block flags when the inlinee basic block
has a ret expr but no statements.

Change propGetType condition in optDoEarlyPropForFunc to check for OMF_HAS_NEWARRAY
in addition to OMF_HAS_NEWOBJ.

Check that methods and basic blocks that have calls to object allocation
helpers have OMF_HAS_NEWOBJ and BBF_HAS_NEWOBJ set.

Check that methods and basic blocks that have calls to array allocation
helpers have OMF_HAS_NEWARRAY and BBF_HAS_NEWARRAY set.

Check that methods and basic blocks that have GT_NULLCHECK nodes
helpers have OMF_HAS_NULLCHECK and BBF_HAS_NULLCHECK set.

Check that methods and basic blocks that access MethodTable
via GT_IND on a ref have OMF_HAS_VTABLEREF and BBF_HAS_VTABLEREF set.

Check that methods and basic blocks that have GT_ARRLENGTH
have OMF_HAS_ARRAYREF and BBF_HAS_IDX_LEN set.

Fix fgOptWhileLoop that could lose BBF_HAS_NEWOBJ and BBF_HAS_NEWARRAY.

Add asserts to make sure we don't have diverging codegen
in debug/checked/release because of early opts.

Add BBF_HAS_VTABREF to BBF_COMPACT_UPD and BBF_SPLIT_GAINED.

12 files changed:
src/coreclr/src/jit/block.h
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/compiler.hpp
src/coreclr/src/jit/earlyprop.cpp
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/gentree.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/jit/loopcloning.cpp
src/coreclr/src/jit/loopcloning.h
src/coreclr/src/jit/morph.cpp
src/coreclr/src/jit/optimizer.cpp
src/coreclr/src/jit/simd.cpp

index d9cf941..e783e25 100644 (file)
@@ -465,7 +465,7 @@ struct BasicBlock : private LIR::Range
 
 #define BBF_COMPACT_UPD                                                                                                \
     (BBF_CHANGED | BBF_GC_SAFE_POINT | BBF_HAS_JMP | BBF_NEEDS_GCPOLL | BBF_HAS_IDX_LEN | BBF_BACKWARD_JUMP |          \
-     BBF_HAS_NEWARRAY | BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK)
+     BBF_HAS_NEWARRAY | BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK | BBF_HAS_VTABREF)
 
 // Flags a block should not have had before it is split.
 
@@ -488,7 +488,8 @@ struct BasicBlock : private LIR::Range
 
 #define BBF_SPLIT_GAINED                                                                                               \
     (BBF_DONT_REMOVE | BBF_HAS_LABEL | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_NEWARRAY |          \
-     BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK)
+     BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK |             \
+     BBF_HAS_VTABREF)
 
 #ifndef __GNUC__ // GCC doesn't like C_ASSERT at global scope
     static_assert_no_msg((BBF_SPLIT_NONEXIST & BBF_SPLIT_LOST) == 0);
index 7468d35..72d2058 100644 (file)
@@ -2581,7 +2581,7 @@ public:
 
     GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
 
-    GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
+    GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset, BasicBlock* block);
 
     GenTree* gtNewIndir(var_types typ, GenTree* addr);
 
@@ -6397,8 +6397,8 @@ public:
     typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTree*> LocalNumberToNullCheckTreeMap;
 
     bool gtIsVtableRef(GenTree* tree);
-    GenTree* getArrayLengthFromAllocation(GenTree* tree);
-    GenTree* getObjectHandleNodeFromAllocation(GenTree* tree);
+    GenTree* getArrayLengthFromAllocation(GenTree* tree DEBUGARG(BasicBlock* block));
+    GenTree* getObjectHandleNodeFromAllocation(GenTree* tree DEBUGARG(BasicBlock* block));
     GenTree* optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
     GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
     GenTree* optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap);
@@ -6415,6 +6415,14 @@ public:
                                      unsigned nullCheckLclNum,
                                      bool     isInsideTry,
                                      bool     checkSideEffectSummary);
+#if DEBUG
+    void optCheckFlagsAreSet(unsigned    methodFlag,
+                             const char* methodFlagStr,
+                             unsigned    bbFlag,
+                             const char* bbFlagStr,
+                             GenTree*    tree,
+                             BasicBlock* basicBlock);
+#endif
 
 #if ASSERTION_PROP
     /**************************************************************************
index 1ab8b86..3e9a7d3 100644 (file)
@@ -1225,15 +1225,21 @@ inline GenTree* Compiler::gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree
 //    typ      -  Type of the node
 //    arrayOp  -  Array node
 //    lenOffset - Offset of the length field
+//    block     - Basic block that will contain the result
 //
 // Return Value:
 //    New GT_ARR_LENGTH node
 
-inline GenTreeArrLen* Compiler::gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset)
+inline GenTreeArrLen* Compiler::gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset, BasicBlock* block)
 {
     GenTreeArrLen* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(typ, arrayOp, lenOffset);
     static_assert_no_msg(GTF_ARRLEN_NONFAULTING == GTF_IND_NONFAULTING);
     arrLen->SetIndirExceptionFlags(this);
+    if (block != nullptr)
+    {
+        block->bbFlags |= BBF_HAS_IDX_LEN;
+    }
+    optMethodFlags |= OMF_HAS_ARRAYREF;
     return arrLen;
 }
 
index 64f6e98..48ccc66 100644 (file)
@@ -19,7 +19,7 @@
 bool Compiler::optDoEarlyPropForFunc()
 {
     bool propArrayLen  = (optMethodFlags & OMF_HAS_NEWARRAY) && (optMethodFlags & OMF_HAS_ARRAYREF);
-    bool propGetType   = (optMethodFlags & OMF_HAS_NEWOBJ) && (optMethodFlags & OMF_HAS_VTABLEREF);
+    bool propGetType   = (optMethodFlags & (OMF_HAS_NEWOBJ | OMF_HAS_NEWARRAY)) && (optMethodFlags & OMF_HAS_VTABLEREF);
     bool propNullCheck = (optMethodFlags & OMF_HAS_NULLCHECK) != 0;
     return propArrayLen || propGetType || propNullCheck;
 }
@@ -64,11 +64,12 @@ bool Compiler::gtIsVtableRef(GenTree* tree)
 //
 // Arguments:
 //    tree           - The array allocation helper call.
+//    block          - tree's basic block.
 //
 // Return Value:
 //    Return the array length node.
 
-GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree)
+GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree DEBUGARG(BasicBlock* block))
 {
     assert(tree != nullptr);
 
@@ -83,6 +84,10 @@ GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree)
                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_VC) ||
                 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8))
             {
+#ifdef DEBUG
+                optCheckFlagsAreSet(OMF_HAS_NEWARRAY, "OMF_HAS_NEWARRAY", BBF_HAS_NEWARRAY, "BBF_HAS_NEWARRAY", tree,
+                                    block);
+#endif
                 // This is an array allocation site. Grab the array length node.
                 return gtArgEntryByArgNum(call, 1)->GetNode();
             }
@@ -98,11 +103,12 @@ GenTree* Compiler::getArrayLengthFromAllocation(GenTree* tree)
 //
 // Arguments:
 //    tree           - The object allocation helper call.
+//    block          - tree's basic block.
 //
 // Return Value:
 //    Return the object type handle node.
 
-GenTree* Compiler::getObjectHandleNodeFromAllocation(GenTree* tree)
+GenTree* Compiler::getObjectHandleNodeFromAllocation(GenTree* tree DEBUGARG(BasicBlock* block))
 {
     assert(tree != nullptr);
 
@@ -112,16 +118,32 @@ GenTree* Compiler::getObjectHandleNodeFromAllocation(GenTree* tree)
 
         if (call->gtCallType == CT_HELPER)
         {
-            if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWFAST) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_FINALIZE) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8_VC) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_VC) ||
-                call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8))
+            bool hasNewObj = call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWFAST) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_FINALIZE) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8_VC) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE);
+
+            bool hasNewArr = call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_VC) ||
+                             call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_NEWARR_1_ALIGN8);
+
+#ifdef DEBUG
+            if (hasNewObj)
+            {
+                optCheckFlagsAreSet(OMF_HAS_NEWOBJ, "OMF_HAS_NEWOBJ", BBF_HAS_NEWOBJ, "BBF_HAS_NEWOBJ", tree, block);
+            }
+
+            if (hasNewArr)
+            {
+                optCheckFlagsAreSet(OMF_HAS_NEWARRAY, "OMF_HAS_NEWARRAY", BBF_HAS_NEWARRAY, "BBF_HAS_NEWARRAY", tree,
+                                    block);
+            }
+#endif // DEBUG
+
+            if (hasNewObj || hasNewArr)
             {
                 // This is an object allocation site. Return the runtime type handle node.
                 fgArgTabEntry* argTabEntry = gtArgEntryByArgNum(call, 0);
@@ -133,6 +155,42 @@ GenTree* Compiler::getObjectHandleNodeFromAllocation(GenTree* tree)
     return nullptr;
 }
 
+#ifdef DEBUG
+//-----------------------------------------------------------------------------
+// optCheckFlagsAreSet: Check that the method flag and the basic block flag are set.
+//
+// Arguments:
+//    methodFlag           - The method flag to check.
+//    methodFlagStr        - String representation of the method flag.
+//    bbFlag               - The basic block flag to check.
+//    bbFlagStr            - String representation of the basic block flag.
+//    tree                 - Tree that makes the flags required.
+//    basicBlock           - The basic block to check the flag on.
+
+void Compiler::optCheckFlagsAreSet(unsigned    methodFlag,
+                                   const char* methodFlagStr,
+                                   unsigned    bbFlag,
+                                   const char* bbFlagStr,
+                                   GenTree*    tree,
+                                   BasicBlock* basicBlock)
+{
+    if ((optMethodFlags & methodFlag) == 0)
+    {
+        printf("%s is not set on optMethodFlags but is required because of the following tree\n", methodFlagStr);
+        gtDispTree(tree);
+        assert(false);
+    }
+
+    if ((basicBlock->bbFlags & bbFlag) == 0)
+    {
+        printf("%s is not set on " FMT_BB " but is required because of the following tree \n", bbFlagStr,
+               compCurBB->bbNum);
+        gtDispTree(tree);
+        assert(false);
+    }
+}
+#endif
+
 //------------------------------------------------------------------------------------------
 // optEarlyProp: The entry point of the early value propagation.
 //
@@ -165,21 +223,23 @@ void Compiler::optEarlyProp()
     {
         printf("*************** In optEarlyProp()\n");
     }
-#endif
-
-    assert(fgSsaPassesCompleted == 1);
-
+#else
     if (!optDoEarlyPropForFunc())
     {
         return;
     }
+#endif
+
+    assert(fgSsaPassesCompleted == 1);
 
     for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
     {
+#ifndef DEBUG
         if (!optDoEarlyPropForBlock(block))
         {
             continue;
         }
+#endif
 
         compCurBB = block;
 
@@ -210,6 +270,8 @@ void Compiler::optEarlyProp()
             // Update the evaluation order and the statement info if the stmt has been rewritten.
             if (isRewritten)
             {
+                // Make sure the transformation happens in debug, check, and release build.
+                assert(optDoEarlyPropForFunc() && optDoEarlyPropForBlock(block));
                 gtSetStmtInfo(stmt);
                 fgSetStmtSeq(stmt);
             }
@@ -283,10 +345,24 @@ GenTree* Compiler::optEarlyPropRewriteTree(GenTree* tree, LocalNumberToNullCheck
     }
 
     if (!objectRefPtr->OperIsScalarLocal() || !lvaInSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
-
     {
         return nullptr;
     }
+#ifdef DEBUG
+    else
+    {
+        if (propKind == optPropKind::OPK_ARRAYLEN)
+        {
+            optCheckFlagsAreSet(OMF_HAS_ARRAYREF, "OMF_HAS_ARRAYREF", BBF_HAS_IDX_LEN, "BBF_HAS_IDX_LEN", tree,
+                                compCurBB);
+        }
+        else
+        {
+            optCheckFlagsAreSet(OMF_HAS_VTABLEREF, "OMF_HAS_VTABLEREF", BBF_HAS_VTABREF, "BBF_HAS_VTABREF", tree,
+                                compCurBB);
+        }
+    }
+#endif
 
     unsigned lclNum    = objectRefPtr->AsLclVarCommon()->GetLclNum();
     unsigned ssaNum    = objectRefPtr->AsLclVarCommon()->GetSsaNum();
@@ -430,7 +506,8 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
     }
 
     // Track along the use-def chain to get the array length
-    GenTreeOp* ssaDefAsg = lvaTable[lclNum].GetPerSsaData(ssaNum)->GetAssignment();
+    LclSsaVarDsc* ssaVarDsc = lvaTable[lclNum].GetPerSsaData(ssaNum);
+    GenTreeOp*    ssaDefAsg = ssaVarDsc->GetAssignment();
 
     if (ssaDefAsg == nullptr)
     {
@@ -456,7 +533,7 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
         {
             if (valueKind == optPropKind::OPK_ARRAYLEN)
             {
-                value = getArrayLengthFromAllocation(treeRhs);
+                value = getArrayLengthFromAllocation(treeRhs DEBUGARG(ssaVarDsc->GetBlock()));
                 if (value != nullptr)
                 {
                     if (!value->IsCnsIntOrI())
@@ -468,14 +545,10 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
             }
             else if (valueKind == optPropKind::OPK_OBJ_GETTYPE)
             {
-                value = getObjectHandleNodeFromAllocation(treeRhs);
+                value = getObjectHandleNodeFromAllocation(treeRhs DEBUGARG(ssaVarDsc->GetBlock()));
                 if (value != nullptr)
                 {
-                    if (!value->IsCnsIntOrI())
-                    {
-                        // Leave out non-constant-sized array
-                        value = nullptr;
-                    }
+                    assert(value->IsCnsIntOrI());
                 }
             }
         }
@@ -500,10 +573,18 @@ GenTree* Compiler::optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropK
 
 void Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nullCheckMap)
 {
+#ifdef DEBUG
+    if (tree->OperGet() == GT_NULLCHECK)
+    {
+        optCheckFlagsAreSet(OMF_HAS_NULLCHECK, "OMF_HAS_NULLCHECK", BBF_HAS_NULLCHECK, "BBF_HAS_NULLCHECK", tree,
+                            compCurBB);
+    }
+#else
     if ((compCurBB->bbFlags & BBF_HAS_NULLCHECK) == 0)
     {
         return;
     }
+#endif
 
     GenTree*   nullCheckTree   = optFindNullCheckToFold(tree, nullCheckMap);
     GenTree*   nullCheckParent = nullptr;
@@ -511,6 +592,9 @@ void Compiler::optFoldNullCheck(GenTree* tree, LocalNumberToNullCheckTreeMap* nu
     if ((nullCheckTree != nullptr) && optIsNullCheckFoldingLegal(tree, nullCheckTree, &nullCheckParent, &nullCheckStmt))
     {
 #ifdef DEBUG
+        // Make sure the transformation happens in debug, check, and release build.
+        assert(optDoEarlyPropForFunc() && optDoEarlyPropForBlock(compCurBB) &&
+               (compCurBB->bbFlags & BBF_HAS_NULLCHECK) != 0);
         if (verbose)
         {
             printf("optEarlyProp Marking a null check for removal\n");
index 3032ff1..cc19816 100644 (file)
@@ -22928,14 +22928,14 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
             if (InlineeCompiler->fgFirstBB->bbStmtList != nullptr)
             {
                 stmtAfter = fgInsertStmtListAfter(iciBlock, stmtAfter, InlineeCompiler->fgFirstBB->firstStmt());
-
-                // Copy inlinee bbFlags to caller bbFlags.
-                const unsigned __int64 inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
-                noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
-                noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
-                iciBlock->bbFlags |= inlineeBlockFlags;
             }
 
+            // Copy inlinee bbFlags to caller bbFlags.
+            const unsigned __int64 inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
+            noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
+            noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
+            iciBlock->bbFlags |= inlineeBlockFlags;
+
 #ifdef DEBUG
             if (verbose)
             {
@@ -23184,6 +23184,11 @@ _Done:
 #endif // DEBUG
         // Replace the call with the return expression
         iciCall->ReplaceWith(pInlineInfo->retExpr, this);
+
+        if (bottomBlock != nullptr)
+        {
+            bottomBlock->bbFlags |= InlineeCompiler->fgLastBB->bbFlags & BBF_SPLIT_GAINED;
+        }
     }
 
     //
index 6623c9e..161528d 100644 (file)
@@ -7318,7 +7318,7 @@ GenTree* Compiler::gtCloneExpr(
             break;
 
             case GT_ARR_LENGTH:
-                copy = gtNewArrLen(tree->TypeGet(), tree->AsOp()->gtOp1, tree->AsArrLen()->ArrLenOffset());
+                copy = gtNewArrLen(tree->TypeGet(), tree->AsOp()->gtOp1, tree->AsArrLen()->ArrLenOffset(), nullptr);
                 break;
 
             case GT_ARR_INDEX:
index 266f651..4950dba 100644 (file)
@@ -3632,7 +3632,7 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
             op1 = impPopStack().val;
             if (opts.OptimizationEnabled())
             {
-                GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_String__stringLen);
+                GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_String__stringLen, compCurBB);
                 op1                   = arrLen;
             }
             else
@@ -16014,14 +16014,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 if (opts.OptimizationEnabled())
                 {
                     /* Use GT_ARR_LENGTH operator so rng check opts see this */
-                    GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_Array__length);
-
-                    /* Mark the block as containing a length expression */
-
-                    if (op1->gtOper == GT_LCL_VAR)
-                    {
-                        block->bbFlags |= BBF_HAS_IDX_LEN;
-                    }
+                    GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_Array__length, block);
 
                     op1 = arrLen;
                 }
index 2c697b1..72ae9bc 100644 (file)
@@ -18,6 +18,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 //
 // Arguments:
 //      comp    Compiler instance to allocate trees
+//      bb      Basic block of the new tree
 //
 // Return Values:
 //      Returns the gen tree representation for arrLen or MD Array node as defined by
@@ -27,7 +28,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 //      This tree produces GT_INDEX node, the caller is supposed to morph it appropriately
 //      so it can be codegen'ed.
 //
-GenTree* LC_Array::ToGenTree(Compiler* comp)
+GenTree* LC_Array::ToGenTree(Compiler* comp, BasicBlock* bb)
 {
     // If jagged array
     if (type == Jagged)
@@ -43,7 +44,7 @@ GenTree* LC_Array::ToGenTree(Compiler* comp)
         // If asked for arrlen invoke arr length operator.
         if (oper == ArrLen)
         {
-            GenTree* arrLen = comp->gtNewArrLen(TYP_INT, arr, OFFSETOF__CORINFO_Array__length);
+            GenTree* arrLen = comp->gtNewArrLen(TYP_INT, arr, OFFSETOF__CORINFO_Array__length, bb);
             return arrLen;
         }
         else
@@ -65,12 +66,13 @@ GenTree* LC_Array::ToGenTree(Compiler* comp)
 //
 // Arguments:
 //      comp    Compiler instance to allocate trees
+//      bb      Basic block of the new tree
 //
 // Return Values:
 //      Returns the gen tree representation for either a constant or a variable or an arrLen operation
 //      defined by the "type" member
 //
-GenTree* LC_Ident::ToGenTree(Compiler* comp)
+GenTree* LC_Ident::ToGenTree(Compiler* comp, BasicBlock* bb)
 {
     // Convert to GenTree nodes.
     switch (type)
@@ -81,7 +83,7 @@ GenTree* LC_Ident::ToGenTree(Compiler* comp)
         case Var:
             return comp->gtNewLclvNode(constant, comp->lvaTable[constant].lvType);
         case ArrLen:
-            return arrLen.ToGenTree(comp);
+            return arrLen.ToGenTree(comp, bb);
         case Null:
             return comp->gtNewIconNode(0, TYP_REF);
         default:
@@ -96,18 +98,19 @@ GenTree* LC_Ident::ToGenTree(Compiler* comp)
 //
 // Arguments:
 //      comp    Compiler instance to allocate trees
+//      bb      Basic block of the new tree
 //
 // Return Values:
 //      Returns the gen tree representation for either a constant or a variable or an arrLen operation
 //      defined by the "type" member
 //
-GenTree* LC_Expr::ToGenTree(Compiler* comp)
+GenTree* LC_Expr::ToGenTree(Compiler* comp, BasicBlock* bb)
 {
     // Convert to GenTree nodes.
     switch (type)
     {
         case Ident:
-            return ident.ToGenTree(comp);
+            return ident.ToGenTree(comp, bb);
         default:
             assert(!"Could not convert LC_Expr to GenTree");
             unreached();
@@ -120,14 +123,15 @@ GenTree* LC_Expr::ToGenTree(Compiler* comp)
 //
 // Arguments:
 //      comp    Compiler instance to allocate trees
+//      bb      Basic block of the new tree
 //
 // Return Values:
 //      Returns the gen tree representation for the conditional operator on lhs and rhs trees
 //
-GenTree* LC_Condition::ToGenTree(Compiler* comp)
+GenTree* LC_Condition::ToGenTree(Compiler* comp, BasicBlock* bb)
 {
-    GenTree* op1Tree = op1.ToGenTree(comp);
-    GenTree* op2Tree = op2.ToGenTree(comp);
+    GenTree* op1Tree = op1.ToGenTree(comp, bb);
+    GenTree* op2Tree = op2.ToGenTree(comp, bb);
     assert(genTypeSize(genActualType(op1Tree->TypeGet())) == genTypeSize(genActualType(op2Tree->TypeGet())));
     return comp->gtNewOperNode(oper, TYP_INT, op1Tree, op2Tree);
 }
@@ -676,11 +680,11 @@ void LoopCloneContext::CondToStmtInBlock(Compiler*                          comp
     noway_assert(conds.Size() > 0);
 
     // Get the first condition.
-    GenTree* cond = conds[0].ToGenTree(comp);
+    GenTree* cond = conds[0].ToGenTree(comp, block);
     for (unsigned i = 1; i < conds.Size(); ++i)
     {
         // Append all conditions using AND operator.
-        cond = comp->gtNewOperNode(GT_AND, TYP_INT, cond, conds[i].ToGenTree(comp));
+        cond = comp->gtNewOperNode(GT_AND, TYP_INT, cond, conds[i].ToGenTree(comp, block));
     }
 
     // Add "cond == 0" node
index 7dac794..a6197f5 100644 (file)
@@ -308,7 +308,7 @@ struct LC_Array
     }
 
     // Get a tree representation for this symbolic a.length
-    GenTree* ToGenTree(Compiler* comp);
+    GenTree* ToGenTree(Compiler* comp, BasicBlock* bb);
 };
 
 /**
@@ -387,7 +387,7 @@ struct LC_Ident
     }
 
     // Convert this symbolic representation into a tree node.
-    GenTree* ToGenTree(Compiler* comp);
+    GenTree* ToGenTree(Compiler* comp, BasicBlock* bb);
 };
 
 /**
@@ -438,7 +438,7 @@ struct LC_Expr
     }
 
     // Convert LC_Expr into a tree node.
-    GenTree* ToGenTree(Compiler* comp);
+    GenTree* ToGenTree(Compiler* comp, BasicBlock* bb);
 };
 
 /**
@@ -477,7 +477,7 @@ struct LC_Condition
     }
 
     // Convert this conditional operation into a GenTree.
-    GenTree* ToGenTree(Compiler* comp);
+    GenTree* ToGenTree(Compiler* comp, BasicBlock* bb);
 };
 
 /**
index 2cd1776..fae4b25 100644 (file)
@@ -5504,7 +5504,7 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
         }
 #endif // _TARGET_64BIT_
 
-        GenTree* arrLen = gtNewArrLen(TYP_INT, arrRef, (int)lenOffs);
+        GenTree* arrLen = gtNewArrLen(TYP_INT, arrRef, (int)lenOffs, compCurBB);
 
         if (bndsChkType != TYP_INT)
         {
index cddf3e1..53702e0 100644 (file)
@@ -4264,8 +4264,10 @@ void Compiler::fgOptWhileLoop(BasicBlock* block)
     }
 
     // Flag the block that received the copy as potentially having an array/vtable
-    // reference if the block copied from did; this is a conservative guess.
-    if (auto copyFlags = bTest->bbFlags & (BBF_HAS_VTABREF | BBF_HAS_IDX_LEN))
+    // reference, nullcheck, object/array allocation if the block copied from did;
+    // this is a conservative guess.
+    if (auto copyFlags = bTest->bbFlags &
+                         (BBF_HAS_VTABREF | BBF_HAS_IDX_LEN | BBF_HAS_NULLCHECK | BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY))
     {
         block->bbFlags |= copyFlags;
     }
index 6f980c0..52bdbb3 100644 (file)
@@ -2274,7 +2274,7 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize
         // = indexVal + arrayElementsCount - 1
         unsigned arrayElementsCount  = simdSize / genTypeSize(baseType);
         checkIndexExpr               = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT, indexVal + arrayElementsCount - 1);
-        GenTreeArrLen*    arrLen     = gtNewArrLen(TYP_INT, arrayRef, (int)OFFSETOF__CORINFO_Array__length);
+        GenTreeArrLen*    arrLen     = gtNewArrLen(TYP_INT, arrayRef, (int)OFFSETOF__CORINFO_Array__length, compCurBB);
         GenTreeBoundsChk* arrBndsChk = new (this, GT_ARR_BOUNDS_CHECK)
             GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, checkIndexExpr, arrLen, SCK_RNGCHK_FAIL);
 
@@ -2712,7 +2712,7 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE                opcode,
                 }
 
                 GenTreeArrLen* arrLen =
-                    gtNewArrLen(TYP_INT, arrayRefForArgRngChk, (int)OFFSETOF__CORINFO_Array__length);
+                    gtNewArrLen(TYP_INT, arrayRefForArgRngChk, (int)OFFSETOF__CORINFO_Array__length, compCurBB);
                 argRngChk = new (this, GT_ARR_BOUNDS_CHECK)
                     GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, index, arrLen, op3CheckKind);
                 // Now, clone op3 to create another node for the argChk
@@ -2732,7 +2732,8 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE                opcode,
             {
                 op2CheckKind = SCK_ARG_EXCPN;
             }
-            GenTreeArrLen*    arrLen = gtNewArrLen(TYP_INT, arrayRefForArgChk, (int)OFFSETOF__CORINFO_Array__length);
+            GenTreeArrLen* arrLen =
+                gtNewArrLen(TYP_INT, arrayRefForArgChk, (int)OFFSETOF__CORINFO_Array__length, compCurBB);
             GenTreeBoundsChk* argChk = new (this, GT_ARR_BOUNDS_CHECK)
                 GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, checkIndexExpr, arrLen, op2CheckKind);