1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 #include "allocacheck.h" // for alloca
21 /*****************************************************************************/
23 void Compiler::fgInit()
27 /* Initialization for fgWalkTreePre() and fgWalkTreePost() */
29 fgFirstBBScratch = nullptr;
32 fgPrintInlinedMethods = JitConfig.JitPrintInlinedMethods() == 1;
35 /* We haven't yet computed the bbPreds lists */
36 fgComputePredsDone = false;
38 /* We haven't yet computed the bbCheapPreds lists */
39 fgCheapPredsValid = false;
41 /* We haven't yet computed the edge weight */
42 fgEdgeWeightsComputed = false;
43 fgHaveValidEdgeWeights = false;
44 fgSlopUsedInEdgeWeights = false;
45 fgRangeUsedInEdgeWeights = true;
46 fgNeedsUpdateFlowGraph = false;
47 fgCalledWeight = BB_ZERO_WEIGHT;
49 /* We haven't yet computed the dominator sets */
50 fgDomsComputed = false;
53 fgReachabilitySetsValid = false;
56 /* We don't know yet which loops will always execute calls */
57 fgLoopCallMarked = false;
59 /* We haven't created GC Poll blocks yet. */
60 fgGCPollsCreated = false;
62 /* Initialize the basic block list */
66 fgFirstColdBlock = nullptr;
68 #if FEATURE_EH_FUNCLETS
69 fgFirstFuncletBB = nullptr;
70 fgFuncletsCreated = false;
71 #endif // FEATURE_EH_FUNCLETS
76 fgBBcountAtCodegen = 0;
82 fgBBVarSetsInited = false;
85 // Initialize BlockSet data.
88 fgBBSetCountInSizeTUnits = 0;
90 genReturnBB = nullptr;
92 /* We haven't reached the global morphing phase */
93 fgGlobalMorph = false;
94 fgExpandInline = false;
98 fgSafeBasicBlockCreation = true;
101 fgLocalVarLivenessDone = false;
103 /* Statement list is not threaded yet */
105 fgStmtListThreaded = false;
107 // Initialize the logic for adding code. This is used to insert code such
108 // as the code that raises an exception when an array range check fails.
110 fgAddCodeList = nullptr;
111 fgAddCodeModf = false;
113 for (int i = 0; i < SCK_COUNT; i++)
115 fgExcptnTargetCache[i] = nullptr;
118 /* Keep track of the max count of pointer arguments */
123 /* This global flag is set whenever we remove a statement */
124 fgStmtRemoved = false;
126 /* This global flag is set whenever we add a throw block for a RngChk */
127 fgRngChkThrowAdded = false; /* reset flag for fgIsCodeAdded() */
131 /* We will record a list of all BBJ_RETURN blocks here */
132 fgReturnBlocks = nullptr;
134 /* This is set by fgComputeReachability */
135 fgEnterBlks = BlockSetOps::UninitVal();
138 fgEnterBlksSetValid = false;
141 #if !FEATURE_EH_FUNCLETS
142 ehMaxHndNestingCount = 0;
143 #endif // !FEATURE_EH_FUNCLETS
145 /* Init the fgBigOffsetMorphingTemps to be BAD_VAR_NUM. */
146 for (int i = 0; i < TYP_COUNT; i++)
148 fgBigOffsetMorphingTemps[i] = BAD_VAR_NUM;
151 fgNoStructPromotion = false;
152 fgNoStructParamPromotion = false;
154 optValnumCSE_phase = false; // referenced in fgMorphSmpOp()
157 fgNormalizeEHDone = false;
161 if (!compIsForInlining())
163 if ((JitConfig.JitNoStructPromotion() & 1) == 1)
165 fgNoStructPromotion = true;
167 if ((JitConfig.JitNoStructPromotion() & 2) == 2)
169 fgNoStructParamPromotion = true;
174 if (!compIsForInlining())
176 m_promotedStructDeathVars = nullptr;
179 fgPreviousCandidateSIMDFieldAsgStmt = nullptr;
183 bool Compiler::fgHaveProfileData()
185 if (compIsForInlining() || compIsForImportOnly())
190 return (fgProfileBuffer != nullptr);
193 bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weightWB)
195 noway_assert(weightWB != nullptr);
199 unsigned hashSeed = fgStressBBProf();
202 unsigned hash = (info.compMethodHash() * hashSeed) ^ (offset * 1027);
204 // We need to especially stress the procedure splitting codepath. Therefore
205 // one third the time we should return a weight of zero.
206 // Otherwise we should return some random weight (usually between 0 and 288).
207 // The below gives a weight of zero, 44% of the time
213 else if (hash % 11 == 0)
215 weight = (hash % 23) * (hash % 29) * (hash % 31);
219 weight = (hash % 17) * (hash % 19);
222 // The first block is never given a weight of zero
223 if ((offset == 0) && (weight == 0))
225 weight = 1 + (hash % 5);
233 if (fgHaveProfileData() == false)
238 noway_assert(!compIsForInlining());
239 for (unsigned i = 0; i < fgProfileBufferCount; i++)
241 if (fgProfileBuffer[i].ILOffset == offset)
243 weight = fgProfileBuffer[i].ExecutionCount;
254 void Compiler::fgInstrumentMethod()
256 noway_assert(!compIsForInlining());
258 // Count the number of basic blocks in the method
260 int countOfBlocks = 0;
262 for (block = fgFirstBB; block; block = block->bbNext)
264 if (!(block->bbFlags & BBF_IMPORTED) || (block->bbFlags & BBF_INTERNAL))
271 // Allocate the profile buffer
273 ICorJitInfo::ProfileBuffer* bbProfileBuffer;
275 HRESULT res = info.compCompHnd->allocBBProfileBuffer(countOfBlocks, &bbProfileBuffer);
277 ICorJitInfo::ProfileBuffer* bbProfileBufferStart = bbProfileBuffer;
283 // The E_NOTIMPL status is returned when we are profiling a generic method from a different assembly
284 if (res == E_NOTIMPL)
286 // In such cases we still want to add the method entry callback node
288 GenTreeArgList* args = gtNewArgList(gtNewIconEmbMethHndNode(info.compMethodHnd));
289 GenTreePtr call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, 0, args);
291 stmt = gtNewStmt(call);
295 noway_assert(!"Error: failed to allocate bbProfileBuffer");
301 // Assign a buffer entry for each basic block
303 for (block = fgFirstBB; block; block = block->bbNext)
305 if (!(block->bbFlags & BBF_IMPORTED) || (block->bbFlags & BBF_INTERNAL))
310 bbProfileBuffer->ILOffset = block->bbCodeOffs;
315 value = gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode((void*)&bbProfileBuffer->ExecutionCount, nullptr,
317 value = gtNewOperNode(GT_ADD, TYP_INT, value, gtNewIconNode(1));
319 addr = gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode((void*)&bbProfileBuffer->ExecutionCount, nullptr,
322 addr = gtNewAssignNode(addr, value);
324 fgInsertStmtAtBeg(block, addr);
329 noway_assert(countOfBlocks == 0);
331 // Add the method entry callback node
333 GenTreeArgList* args = gtNewArgList(gtNewIconEmbMethHndNode(info.compMethodHnd));
334 GenTreePtr call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, 0, args);
337 gtNewIconEmbHndNode((void*)&bbProfileBufferStart->ExecutionCount, nullptr, GTF_ICON_BBC_PTR);
338 GenTreePtr value = gtNewOperNode(GT_IND, TYP_INT, handle);
339 GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, value, gtNewIconNode(0, TYP_INT));
340 relop->gtFlags |= GTF_RELOP_QMARK;
341 GenTreePtr colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call);
342 GenTreePtr cond = gtNewQmarkNode(TYP_VOID, relop, colon);
343 stmt = gtNewStmt(cond);
346 fgEnsureFirstBBisScratch();
348 fgInsertStmtAtEnd(fgFirstBB, stmt);
351 /*****************************************************************************
353 * Create a basic block and append it to the current BB list.
356 BasicBlock* Compiler::fgNewBasicBlock(BBjumpKinds jumpKind)
358 // This method must not be called after the exception table has been
359 // constructed, because it doesn't not provide support for patching
360 // the exception table.
362 noway_assert(compHndBBtabCount == 0);
366 /* Allocate the block descriptor */
368 block = bbNewBasicBlock(jumpKind);
369 noway_assert(block->bbJumpKind == jumpKind);
371 /* Append the block to the end of the global basic block list */
375 fgLastBB->setNext(block);
380 block->bbPrev = nullptr;
388 /*****************************************************************************
390 * Ensures that fgFirstBB is a scratch BasicBlock that we have added.
391 * This can be used to add initialization code (without worrying
392 * about other blocks jumping to it).
394 * Callers have to be careful that they do not mess up the order of things
395 * added to fgEnsureFirstBBisScratch in a way as to change semantics.
398 void Compiler::fgEnsureFirstBBisScratch()
400 // Have we already allocated a scratch block?
402 if (fgFirstBBisScratch())
407 assert(fgFirstBBScratch == nullptr);
409 BasicBlock* block = bbNewBasicBlock(BBJ_NONE);
411 if (fgFirstBB != nullptr)
413 // If we have profile data the new block will inherit fgFirstBlock's weight
414 if (fgFirstBB->bbFlags & BBF_PROF_WEIGHT)
416 block->inheritWeight(fgFirstBB);
418 fgInsertBBbefore(fgFirstBB, block);
422 noway_assert(fgLastBB == nullptr);
427 noway_assert(fgLastBB != nullptr);
429 block->bbFlags |= (BBF_INTERNAL | BBF_IMPORTED);
431 fgFirstBBScratch = fgFirstBB;
436 printf("New scratch BB%02u\n", block->bbNum);
441 bool Compiler::fgFirstBBisScratch()
443 if (fgFirstBBScratch != nullptr)
445 assert(fgFirstBBScratch == fgFirstBB);
446 assert(fgFirstBBScratch->bbFlags & BBF_INTERNAL);
447 assert(fgFirstBBScratch->countOfInEdges() == 1);
449 // Normally, the first scratch block is a fall-through block. However, if the block after it was an empty
450 // BBJ_ALWAYS block, it might get removed, and the code that removes it will make the first scratch block
451 // a BBJ_ALWAYS block.
452 assert((fgFirstBBScratch->bbJumpKind == BBJ_NONE) || (fgFirstBBScratch->bbJumpKind == BBJ_ALWAYS));
462 bool Compiler::fgBBisScratch(BasicBlock* block)
464 return fgFirstBBisScratch() && (block == fgFirstBB);
468 // Check to see if block contains a statement but don't spend more than a certain
469 // budget doing this per method compiled.
470 // If the budget is exceeded, return 'answerOnBoundExceeded' as the answer.
472 bool Compiler::fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded /*= true*/)
474 const __int64 maxLinks = 1000000000;
476 assert(stmt->gtOper == GT_STMT);
478 __int64* numTraversed = &JitTls::GetCompiler()->compNumStatementLinksTraversed;
480 if (*numTraversed > maxLinks)
482 return answerOnBoundExceeded;
485 GenTree* curr = block->firstStmt();
495 return curr != nullptr;
499 //------------------------------------------------------------------------
500 // fgInsertStmtAtBeg: Insert the given tree or statement at the start of the given basic block.
503 // block - The block into which 'stmt' will be inserted.
504 // stmt - The statement to be inserted.
507 // Returns the new (potentially) GT_STMT node.
510 // If 'stmt' is not already a statement, a new statement is created from it.
511 // We always insert phi statements at the beginning.
512 // In other cases, if there are any phi assignments and/or an assignment of
513 // the GT_CATCH_ARG, we insert after those.
515 GenTreePtr Compiler::fgInsertStmtAtBeg(BasicBlock* block, GenTreePtr stmt)
517 if (stmt->gtOper != GT_STMT)
519 stmt = gtNewStmt(stmt);
522 GenTreePtr list = block->firstStmt();
524 if (!stmt->IsPhiDefnStmt())
526 GenTreePtr insertBeforeStmt = block->FirstNonPhiDefOrCatchArgAsg();
527 if (insertBeforeStmt != nullptr)
529 return fgInsertStmtBefore(block, insertBeforeStmt, stmt);
531 else if (list != nullptr)
533 return fgInsertStmtAtEnd(block, stmt);
535 // Otherwise, we will simply insert at the beginning, below.
538 /* The new tree will now be the first one of the block */
540 block->bbTreeList = stmt;
543 /* Are there any statements in the block? */
549 /* There is at least one statement already */
552 noway_assert(last && last->gtNext == nullptr);
554 /* Insert the statement in front of the first one */
561 /* The block was completely empty */
569 /*****************************************************************************
571 * Insert the given tree or statement at the end of the given basic block.
572 * Returns the (potentially) new GT_STMT node.
573 * If the block can be a conditional block, use fgInsertStmtNearEnd.
576 GenTreeStmt* Compiler::fgInsertStmtAtEnd(BasicBlock* block, GenTreePtr node)
578 GenTreePtr list = block->firstStmt();
581 if (node->gtOper != GT_STMT)
583 stmt = gtNewStmt(node);
587 stmt = node->AsStmt();
590 assert(stmt->gtNext == nullptr); // We don't set it, and it needs to be this after the insert
596 /* There is at least one statement already */
599 noway_assert(last && last->gtNext == nullptr);
601 /* Append the statement after the last one */
609 /* The block is completely empty */
611 block->bbTreeList = stmt;
618 /*****************************************************************************
620 * Insert the given tree or statement at the end of the given basic block, but before
621 * the GT_JTRUE, if present.
622 * Returns the (potentially) new GT_STMT node.
625 GenTreeStmt* Compiler::fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node)
629 // This routine can only be used when in tree order.
630 assert(fgOrder == FGOrderTree);
632 if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH) || (block->bbJumpKind == BBJ_RETURN))
634 if (node->gtOper != GT_STMT)
636 stmt = gtNewStmt(node);
640 stmt = node->AsStmt();
643 GenTreeStmt* first = block->firstStmt();
645 GenTreeStmt* last = block->lastStmt();
646 noway_assert(last && last->gtNext == nullptr);
647 GenTreePtr after = last->gtPrev;
650 if (block->bbJumpKind == BBJ_COND)
652 noway_assert(last->gtStmtExpr->gtOper == GT_JTRUE);
654 else if (block->bbJumpKind == BBJ_RETURN)
656 noway_assert((last->gtStmtExpr->gtOper == GT_RETURN) || (last->gtStmtExpr->gtOper == GT_JMP) ||
657 // BBJ_RETURN blocks in functions returning void do not get a GT_RETURN node if they
658 // have a .tail prefix (even if canTailCall returns false for these calls)
659 // code:Compiler::impImportBlockCode (search for the RET: label)
660 // Ditto for real tail calls (all code after them has been removed)
661 ((last->gtStmtExpr->gtOper == GT_CALL) &&
662 ((info.compRetType == TYP_VOID) || last->gtStmtExpr->AsCall()->IsTailCall())));
666 noway_assert(block->bbJumpKind == BBJ_SWITCH);
667 noway_assert(last->gtStmtExpr->gtOper == GT_SWITCH);
671 /* Append 'stmt' before 'last' */
678 /* There is only one stmt in the block */
680 block->bbTreeList = stmt;
685 noway_assert(after && (after->gtNext == last));
687 /* Append 'stmt' after 'after' */
689 after->gtNext = stmt;
690 stmt->gtPrev = after;
697 return fgInsertStmtAtEnd(block, node);
701 /*****************************************************************************
703 * Insert the given statement "stmt" after GT_STMT node "insertionPoint".
704 * Returns the newly inserted GT_STMT node.
705 * Note that the gtPrev list of statement nodes is circular, but the gtNext list is not.
708 GenTreePtr Compiler::fgInsertStmtAfter(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt)
710 assert(block->bbTreeList != nullptr);
711 noway_assert(insertionPoint->gtOper == GT_STMT);
712 noway_assert(stmt->gtOper == GT_STMT);
713 assert(fgBlockContainsStatementBounded(block, insertionPoint));
714 assert(!fgBlockContainsStatementBounded(block, stmt, false));
716 if (insertionPoint->gtNext == nullptr)
718 // Ok, we want to insert after the last statement of the block.
719 stmt->gtNext = nullptr;
720 stmt->gtPrev = insertionPoint;
722 insertionPoint->gtNext = stmt;
724 // Update the backward link of the first statement of the block
725 // to point to the new last statement.
726 assert(block->bbTreeList->gtPrev == insertionPoint);
727 block->bbTreeList->gtPrev = stmt;
731 stmt->gtNext = insertionPoint->gtNext;
732 stmt->gtPrev = insertionPoint;
734 insertionPoint->gtNext->gtPrev = stmt;
735 insertionPoint->gtNext = stmt;
741 // Insert the given tree or statement before GT_STMT node "insertionPoint".
742 // Returns the newly inserted GT_STMT node.
744 GenTreePtr Compiler::fgInsertStmtBefore(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt)
746 assert(block->bbTreeList != nullptr);
747 noway_assert(insertionPoint->gtOper == GT_STMT);
748 noway_assert(stmt->gtOper == GT_STMT);
749 assert(fgBlockContainsStatementBounded(block, insertionPoint));
750 assert(!fgBlockContainsStatementBounded(block, stmt, false));
752 if (insertionPoint == block->bbTreeList)
754 // We're inserting before the first statement in the block.
755 GenTreePtr list = block->bbTreeList;
756 GenTreePtr last = list->gtPrev;
761 block->bbTreeList = stmt;
766 stmt->gtNext = insertionPoint;
767 stmt->gtPrev = insertionPoint->gtPrev;
769 insertionPoint->gtPrev->gtNext = stmt;
770 insertionPoint->gtPrev = stmt;
776 /*****************************************************************************
778 * Insert the list of statements stmtList after the stmtAfter in block.
779 * Return the last statement stmtList.
782 GenTreePtr Compiler::fgInsertStmtListAfter(BasicBlock* block, // the block where stmtAfter is in.
783 GenTreePtr stmtAfter, // the statement where stmtList should be inserted
787 // Currently we can handle when stmtAfter and stmtList are non-NULL. This makes everything easy.
788 noway_assert(stmtAfter && stmtAfter->gtOper == GT_STMT);
789 noway_assert(stmtList && stmtList->gtOper == GT_STMT);
791 GenTreePtr stmtLast = stmtList->gtPrev; // Last statement in a non-empty list, circular in the gtPrev list.
792 noway_assert(stmtLast);
793 noway_assert(stmtLast->gtNext == nullptr);
795 GenTreePtr stmtNext = stmtAfter->gtNext;
799 stmtAfter->gtNext = stmtList;
800 stmtList->gtPrev = stmtAfter;
801 block->bbTreeList->gtPrev = stmtLast;
805 stmtAfter->gtNext = stmtList;
806 stmtList->gtPrev = stmtAfter;
808 stmtLast->gtNext = stmtNext;
809 stmtNext->gtPrev = stmtLast;
813 noway_assert(block->bbTreeList == nullptr || block->bbTreeList->gtPrev->gtNext == nullptr);
819 Removes a block from the return block list
821 void Compiler::fgRemoveReturnBlock(BasicBlock* block)
823 if (fgReturnBlocks == nullptr)
828 if (fgReturnBlocks->block == block)
830 // It's the 1st entry, assign new head of list.
831 fgReturnBlocks = fgReturnBlocks->next;
835 for (BasicBlockList* retBlocks = fgReturnBlocks; retBlocks->next != nullptr; retBlocks = retBlocks->next)
837 if (retBlocks->next->block == block)
839 // Found it; splice it out.
840 retBlocks->next = retBlocks->next->next;
846 //------------------------------------------------------------------------
847 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
850 // block -- The block with the predecessor list to operate on.
851 // blockPred -- The predecessor block to find in the predecessor list.
854 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
855 // then returns nullptr.
858 // -- This only works on the full predecessor lists, not the cheap preds lists.
860 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred)
863 noway_assert(blockPred);
864 assert(!fgCheapPredsValid);
868 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
870 if (blockPred == pred->flBlock)
879 //------------------------------------------------------------------------
880 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
881 // Also returns the address of the pointer that points to this edge, to make it possible to remove this edge from the
882 // predecessor list without doing another linear search over the edge list.
885 // block -- The block with the predecessor list to operate on.
886 // blockPred -- The predecessor block to find in the predecessor list.
887 // ptrToPred -- Out parameter: set to the address of the pointer that points to the returned predecessor edge.
890 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
891 // then returns nullptr.
894 // -- This only works on the full predecessor lists, not the cheap preds lists.
896 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred)
901 assert(!fgCheapPredsValid);
903 flowList** predPrevAddr;
906 for (predPrevAddr = &block->bbPreds, pred = *predPrevAddr; pred != nullptr;
907 predPrevAddr = &pred->flNext, pred = *predPrevAddr)
909 if (blockPred == pred->flBlock)
911 *ptrToPred = predPrevAddr;
916 *ptrToPred = nullptr;
920 //------------------------------------------------------------------------
921 // fgSpliceOutPred: Removes a predecessor edge for a block from the predecessor list.
924 // block -- The block with the predecessor list to operate on.
925 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
928 // The flowList edge that was removed.
931 // -- "blockPred" must be a predecessor block of "block".
932 // -- This simply splices out the flowList object. It doesn't update block ref counts, handle duplicate counts, etc.
933 // For that, use fgRemoveRefPred() or fgRemoveAllRefPred().
934 // -- This only works on the full predecessor lists, not the cheap preds lists.
937 // -- This must walk the predecessor list to find the block in question. If the predecessor edge
938 // is found using fgGetPredForBlock(), consider using the version that hands back the predecessor pointer
939 // address instead, to avoid this search.
940 // -- Marks fgModified = true, since the flow graph has changed.
942 flowList* Compiler::fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred)
944 assert(!fgCheapPredsValid);
945 noway_assert(block->bbPreds);
947 flowList* oldEdge = nullptr;
949 // Is this the first block in the pred list?
950 if (blockPred == block->bbPreds->flBlock)
952 oldEdge = block->bbPreds;
953 block->bbPreds = block->bbPreds->flNext;
958 for (pred = block->bbPreds; (pred->flNext != nullptr) && (blockPred != pred->flNext->flBlock);
963 oldEdge = pred->flNext;
964 if (oldEdge == nullptr)
966 noway_assert(!"Should always find the blockPred");
968 pred->flNext = pred->flNext->flNext;
971 // Any changes to the flow graph invalidate the dominator sets.
977 //------------------------------------------------------------------------
978 // fgAddRefPred: Increment block->bbRefs by one and add "blockPred" to the predecessor list of "block".
981 // block -- A block to operate on.
982 // blockPred -- The predecessor block to add to the predecessor list.
983 // oldEdge -- Optional (default: nullptr). If non-nullptr, and a new edge is created (and the dup count
984 // of an existing edge is not just incremented), the edge weights are copied from this edge.
985 // initializingPreds -- Optional (default: false). Only set to "true" when the initial preds computation is
989 // The flow edge representing the predecessor.
992 // -- This only works on the full predecessor lists, not the cheap preds lists.
995 // -- block->bbRefs is incremented by one to account for the reduction in incoming edges.
996 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
997 // the preds themselves aren't touched.
998 // -- fgModified is set if a new flow edge is created (but not if an existing flow edge dup count is incremented),
999 // indicating that the flow graph shape has changed.
1001 flowList* Compiler::fgAddRefPred(BasicBlock* block,
1002 BasicBlock* blockPred,
1003 flowList* oldEdge /* = nullptr */,
1004 bool initializingPreds /* = false */)
1006 assert(block != nullptr);
1007 assert(blockPred != nullptr);
1011 if (!fgComputePredsDone && !initializingPreds)
1013 // Why is someone trying to update the preds list when the preds haven't been created?
1014 // Ignore them! This can happen when fgMorph is called before the preds list is created.
1018 assert(!fgCheapPredsValid);
1020 flowList* flow = fgGetPredForBlock(block, blockPred);
1024 noway_assert(flow->flDupCount > 0);
1029 flow = new (this, CMK_FlowList) flowList();
1031 #if MEASURE_BLOCK_SIZE
1032 genFlowNodeCnt += 1;
1033 genFlowNodeSize += sizeof(flowList);
1034 #endif // MEASURE_BLOCK_SIZE
1036 // Any changes to the flow graph invalidate the dominator sets.
1039 // Keep the predecessor list in lowest to highest bbNum order
1040 // This allows us to discover the loops in optFindNaturalLoops
1041 // from innermost to outermost.
1043 // TODO-Throughput: This search is quadratic if you have many jumps
1044 // to the same target. We need to either not bother sorting for
1045 // debuggable code, or sort in optFindNaturalLoops, or better, make
1046 // the code in optFindNaturalLoops not depend on order.
1048 flowList** listp = &block->bbPreds;
1049 while (*listp && ((*listp)->flBlock->bbNum < blockPred->bbNum))
1051 listp = &(*listp)->flNext;
1054 flow->flNext = *listp;
1057 flow->flBlock = blockPred;
1058 flow->flDupCount = 1;
1060 if (fgHaveValidEdgeWeights)
1062 // We are creating an edge from blockPred to block
1063 // and we have already computed the edge weights, so
1064 // we will try to setup this new edge with valid edge weights.
1066 if (oldEdge != nullptr)
1068 // If our caller has given us the old edge weights
1069 // then we will use them.
1071 flow->flEdgeWeightMin = oldEdge->flEdgeWeightMin;
1072 flow->flEdgeWeightMax = oldEdge->flEdgeWeightMax;
1076 // Set the max edge weight to be the minimum of block's or blockPred's weight
1078 flow->flEdgeWeightMax = min(block->bbWeight, blockPred->bbWeight);
1080 // If we are inserting a conditional block the minimum weight is zero,
1081 // otherwise it is the same as the edge's max weight.
1082 if (blockPred->NumSucc() > 1)
1084 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1088 flow->flEdgeWeightMin = flow->flEdgeWeightMax;
1094 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1095 flow->flEdgeWeightMax = BB_MAX_WEIGHT;
1101 //------------------------------------------------------------------------
1102 // fgRemoveRefPred: Decrements the reference count of a predecessor edge from "blockPred" to "block",
1103 // removing the edge if it is no longer necessary.
1106 // block -- A block to operate on.
1107 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1110 // If the flow edge was removed (the predecessor has a "dup count" of 1),
1111 // returns the flow graph edge that was removed. This means "blockPred" is no longer a predecessor of "block".
1112 // Otherwise, returns nullptr. This means that "blockPred" is still a predecessor of "block" (because "blockPred"
1113 // is a switch with multiple cases jumping to "block", or a BBJ_COND with both conditional and fall-through
1114 // paths leading to "block").
1117 // -- "blockPred" must be a predecessor block of "block".
1118 // -- This only works on the full predecessor lists, not the cheap preds lists.
1121 // -- block->bbRefs is decremented by one to account for the reduction in incoming edges.
1122 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
1123 // the preds themselves aren't touched.
1124 // -- fgModified is set if a flow edge is removed (but not if an existing flow edge dup count is decremented),
1125 // indicating that the flow graph shape has changed.
1127 flowList* Compiler::fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred)
1129 noway_assert(block != nullptr);
1130 noway_assert(blockPred != nullptr);
1132 noway_assert(block->countOfInEdges() > 0);
1135 // Do nothing if we haven't calculated the predecessor list yet.
1136 // Yes, this does happen.
1137 // For example the predecessor lists haven't been created yet when we do fgMorph.
1138 // But fgMorph calls fgFoldConditional, which in turn calls fgRemoveRefPred.
1139 if (!fgComputePredsDone)
1144 assert(!fgCheapPredsValid);
1146 flowList** ptrToPred;
1147 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1149 noway_assert(pred->flDupCount > 0);
1153 if (pred->flDupCount == 0)
1155 // Splice out the predecessor edge since it's no longer necessary.
1156 *ptrToPred = pred->flNext;
1158 // Any changes to the flow graph invalidate the dominator sets.
1169 //------------------------------------------------------------------------
1170 // fgRemoveAllRefPreds: Removes a predecessor edge from one block to another, no matter what the "dup count" is.
1173 // block -- A block to operate on.
1174 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1177 // Returns the flow graph edge that was removed. The dup count on the edge is no longer valid.
1180 // -- "blockPred" must be a predecessor block of "block".
1181 // -- This only works on the full predecessor lists, not the cheap preds lists.
1184 // block->bbRefs is decremented to account for the reduction in incoming edges.
1186 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred)
1188 assert(block != nullptr);
1189 assert(blockPred != nullptr);
1190 assert(fgComputePredsDone);
1191 assert(!fgCheapPredsValid);
1192 assert(block->countOfInEdges() > 0);
1194 flowList** ptrToPred;
1195 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1196 assert(pred != nullptr);
1197 assert(pred->flDupCount > 0);
1199 assert(block->bbRefs >= pred->flDupCount);
1200 block->bbRefs -= pred->flDupCount;
1202 // Now splice out the predecessor edge.
1203 *ptrToPred = pred->flNext;
1205 // Any changes to the flow graph invalidate the dominator sets.
1211 //------------------------------------------------------------------------
1212 // fgRemoveAllRefPreds: Remove a predecessor edge, given the address of a pointer to it in the
1213 // predecessor list, no matter what the "dup count" is.
1216 // block -- A block with the predecessor list to operate on.
1217 // ptrToPred -- The address of a pointer to the predecessor to remove.
1220 // The removed predecessor edge. The dup count on the edge is no longer valid.
1223 // -- The predecessor edge must be in the predecessor list for "block".
1224 // -- This only works on the full predecessor lists, not the cheap preds lists.
1227 // block->bbRefs is decremented by the dup count of the predecessor edge, to account for the reduction in incoming
1230 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred)
1232 assert(block != nullptr);
1233 assert(ptrToPred != nullptr);
1234 assert(fgComputePredsDone);
1235 assert(!fgCheapPredsValid);
1236 assert(block->countOfInEdges() > 0);
1238 flowList* pred = *ptrToPred;
1239 assert(pred != nullptr);
1240 assert(pred->flDupCount > 0);
1242 assert(block->bbRefs >= pred->flDupCount);
1243 block->bbRefs -= pred->flDupCount;
1245 // Now splice out the predecessor edge.
1246 *ptrToPred = pred->flNext;
1248 // Any changes to the flow graph invalidate the dominator sets.
1255 Removes all the appearances of block as predecessor of others
1258 void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
1260 assert(!fgCheapPredsValid);
1262 PREFIX_ASSUME(block != nullptr);
1266 switch (block->bbJumpKind)
1268 case BBJ_CALLFINALLY:
1269 if (!(block->bbFlags & BBF_RETLESS_CALL))
1271 assert(block->isBBCallAlwaysPair());
1273 /* The block after the BBJ_CALLFINALLY block is not reachable */
1274 bNext = block->bbNext;
1276 /* bNext is an unreachable BBJ_ALWAYS block */
1277 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
1279 while (bNext->countOfInEdges() > 0)
1281 fgRemoveRefPred(bNext, bNext->bbPreds->flBlock);
1289 case BBJ_EHCATCHRET:
1291 /* Update the predecessor list for 'block->bbJumpDest' and 'block->bbNext' */
1292 fgRemoveRefPred(block->bbJumpDest, block);
1294 if (block->bbJumpKind != BBJ_COND)
1299 /* If BBJ_COND fall through */
1304 /* Update the predecessor list for 'block->bbNext' */
1305 fgRemoveRefPred(block->bbNext, block);
1308 case BBJ_EHFILTERRET:
1310 block->bbJumpDest->bbRefs++; // To compensate the bbRefs-- inside fgRemoveRefPred
1311 fgRemoveRefPred(block->bbJumpDest, block);
1314 case BBJ_EHFINALLYRET:
1316 /* Remove block as the predecessor of the bbNext of all
1317 BBJ_CALLFINALLY blocks calling this finally. No need
1318 to look for BBJ_CALLFINALLY for fault handlers. */
1320 unsigned hndIndex = block->getHndIndex();
1321 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
1323 if (ehDsc->HasFinallyHandler())
1327 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
1329 BasicBlock* finBeg = ehDsc->ebdHndBeg;
1331 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
1333 if ((bcall->bbFlags & BBF_REMOVED) || bcall->bbJumpKind != BBJ_CALLFINALLY ||
1334 bcall->bbJumpDest != finBeg)
1339 assert(bcall->isBBCallAlwaysPair());
1340 fgRemoveRefPred(bcall->bbNext, block);
1352 unsigned jumpCnt = block->bbJumpSwt->bbsCount;
1353 BasicBlock** jumpTab = block->bbJumpSwt->bbsDstTab;
1357 fgRemoveRefPred(*jumpTab, block);
1358 } while (++jumpTab, --jumpCnt);
1364 noway_assert(!"Block doesn't have a valid bbJumpKind!!!!");
1369 /*****************************************************************************
1370 * fgChangeSwitchBlock:
1372 * We have a BBJ_SWITCH jump at 'oldSwitchBlock' and we want to move this
1373 * switch jump over to 'newSwitchBlock'. All of the blocks that are jumped
1374 * to from jumpTab[] need to have their predecessor lists updated by removing
1375 * the 'oldSwitchBlock' and adding 'newSwitchBlock'.
1378 void Compiler::fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock)
1380 noway_assert(oldSwitchBlock != nullptr);
1381 noway_assert(newSwitchBlock != nullptr);
1382 noway_assert(oldSwitchBlock->bbJumpKind == BBJ_SWITCH);
1384 unsigned jumpCnt = oldSwitchBlock->bbJumpSwt->bbsCount;
1385 BasicBlock** jumpTab = oldSwitchBlock->bbJumpSwt->bbsDstTab;
1389 // Walk the switch's jump table, updating the predecessor for each branch.
1390 for (i = 0; i < jumpCnt; i++)
1392 BasicBlock* bJump = jumpTab[i];
1393 noway_assert(bJump != nullptr);
1395 // Note that if there are duplicate branch targets in the switch jump table,
1396 // fgRemoveRefPred()/fgAddRefPred() will do the right thing: the second and
1397 // subsequent duplicates will simply subtract from and add to the duplicate
1398 // count (respectively).
1401 // Remove the old edge [oldSwitchBlock => bJump]
1403 fgRemoveRefPred(bJump, oldSwitchBlock);
1406 // Create the new edge [newSwitchBlock => bJump]
1408 fgAddRefPred(bJump, newSwitchBlock);
1411 if (m_switchDescMap != nullptr)
1413 SwitchUniqueSuccSet uniqueSuccSet;
1415 // If already computed and cached the unique descriptors for the old block, let's
1416 // update those for the new block.
1417 if (m_switchDescMap->Lookup(oldSwitchBlock, &uniqueSuccSet))
1419 m_switchDescMap->Set(newSwitchBlock, uniqueSuccSet);
1423 fgInvalidateSwitchDescMapEntry(newSwitchBlock);
1425 fgInvalidateSwitchDescMapEntry(oldSwitchBlock);
1429 /*****************************************************************************
1430 * fgReplaceSwitchJumpTarget:
1432 * We have a BBJ_SWITCH at 'blockSwitch' and we want to replace all entries
1433 * in the jumpTab[] such that so that jumps that previously went to
1434 * 'oldTarget' now go to 'newTarget'.
1435 * We also must update the predecessor lists for 'oldTarget' and 'newPred'.
1438 void Compiler::fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget)
1440 noway_assert(blockSwitch != nullptr);
1441 noway_assert(newTarget != nullptr);
1442 noway_assert(oldTarget != nullptr);
1443 noway_assert(blockSwitch->bbJumpKind == BBJ_SWITCH);
1445 // For the jump targets values that match oldTarget of our BBJ_SWITCH
1446 // replace predecessor 'blockSwitch' with 'newTarget'
1449 unsigned jumpCnt = blockSwitch->bbJumpSwt->bbsCount;
1450 BasicBlock** jumpTab = blockSwitch->bbJumpSwt->bbsDstTab;
1454 // Walk the switch's jump table looking for blocks to update the preds for
1457 if (jumpTab[i] == oldTarget) // We will update when jumpTab[i] matches
1459 // Remove the old edge [oldTarget from blockSwitch]
1461 fgRemoveAllRefPreds(oldTarget, blockSwitch);
1464 // Change the jumpTab entry to branch to the new location
1466 jumpTab[i] = newTarget;
1469 // Create the new edge [newTarget from blockSwitch]
1471 flowList* newEdge = fgAddRefPred(newTarget, blockSwitch);
1473 // Now set the correct value of newEdge->flDupCount
1474 // and replace any other jumps in jumpTab[] that go to oldTarget.
1479 if (jumpTab[i] == oldTarget)
1482 // We also must update this entry in the jumpTab
1484 jumpTab[i] = newTarget;
1485 newTarget->bbRefs++;
1488 // Increment the flDupCount
1490 newEdge->flDupCount++;
1492 i++; // Check the next entry in jumpTab[]
1495 // Maintain, if necessary, the set of unique targets of "block."
1496 UpdateSwitchTableTarget(blockSwitch, oldTarget, newTarget);
1498 // Make sure the new target has the proper bits set for being a branch target.
1499 newTarget->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
1501 return; // We have replaced the jumps to oldTarget with newTarget
1503 i++; // Check the next entry in jumpTab[] for a match
1505 noway_assert(!"Did not find oldTarget in jumpTab[]");
1508 //------------------------------------------------------------------------
1509 // Compiler::fgReplaceJumpTarget: For a given block, replace the target 'oldTarget' with 'newTarget'.
1512 // block - the block in which a jump target will be replaced.
1513 // newTarget - the new branch target of the block.
1514 // oldTarget - the old branch target of the block.
1517 // 1. Only branches are changed: BBJ_ALWAYS, the non-fallthrough path of BBJ_COND, BBJ_SWITCH, etc.
1518 // We ignore other block types.
1519 // 2. Only the first target found is updated. If there are multiple ways for a block
1520 // to reach 'oldTarget' (e.g., multiple arms of a switch), only the first one found is changed.
1521 // 3. The predecessor lists are not changed.
1522 // 4. The switch table "unique successor" cache is invalidated.
1524 // This function is most useful early, before the full predecessor lists have been computed.
1526 void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget)
1528 assert(block != nullptr);
1530 switch (block->bbJumpKind)
1532 case BBJ_CALLFINALLY:
1535 case BBJ_EHCATCHRET:
1536 case BBJ_EHFILTERRET:
1537 case BBJ_LEAVE: // This function will be called before import, so we still have BBJ_LEAVE
1539 if (block->bbJumpDest == oldTarget)
1541 block->bbJumpDest = newTarget;
1546 case BBJ_EHFINALLYRET:
1553 jumpCnt = block->bbJumpSwt->bbsCount;
1554 BasicBlock** jumpTab;
1555 jumpTab = block->bbJumpSwt->bbsDstTab;
1557 for (unsigned i = 0; i < jumpCnt; i++)
1559 if (jumpTab[i] == oldTarget)
1561 jumpTab[i] = newTarget;
1568 assert(!"Block doesn't have a valid bbJumpKind!!!!");
1574 /*****************************************************************************
1575 * Updates the predecessor list for 'block' by replacing 'oldPred' with 'newPred'.
1576 * Note that a block can only appear once in the preds list (for normal preds, not
1577 * cheap preds): if a predecessor has multiple ways to get to this block, then
1578 * flDupCount will be >1, but the block will still appear exactly once. Thus, this
1579 * function assumes that all branches from the predecessor (practically, that all
1580 * switch cases that target this block) are changed to branch from the new predecessor,
1581 * with the same dup count.
1583 * Note that the block bbRefs is not changed, since 'block' has the same number of
1584 * references as before, just from a different predecessor block.
1587 void Compiler::fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred)
1589 noway_assert(block != nullptr);
1590 noway_assert(oldPred != nullptr);
1591 noway_assert(newPred != nullptr);
1592 assert(!fgCheapPredsValid);
1596 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1598 if (oldPred == pred->flBlock)
1600 pred->flBlock = newPred;
1606 /*****************************************************************************
1608 * Returns true if block b1 dominates block b2.
1611 bool Compiler::fgDominate(BasicBlock* b1, BasicBlock* b2)
1613 noway_assert(fgDomsComputed);
1614 assert(!fgCheapPredsValid);
1617 // If the fgModified flag is false then we made some modifications to
1618 // the flow graph, like adding a new block or changing a conditional branch
1619 // into an unconditional branch.
1621 // We can continue to use the dominator and reachable information to
1622 // unmark loops as long as we haven't renumbered the blocks or we aren't
1623 // asking for information about a new block
1626 if (b2->bbNum > fgDomBBcount)
1633 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1635 if (!fgDominate(b1, pred->flBlock))
1641 return b2->bbPreds != nullptr;
1644 if (b1->bbNum > fgDomBBcount)
1646 // if b1 is a loop preheader and Succ is its only successor, then all predecessors of
1647 // Succ either are b1 itself or are dominated by Succ. Under these conditions, b1
1648 // dominates b2 if and only if Succ dominates b2 (or if b2 == b1, but we already tested
1650 if (b1->bbFlags & BBF_LOOP_PREHEADER)
1652 noway_assert(b1->bbFlags & BBF_INTERNAL);
1653 noway_assert(b1->bbJumpKind == BBJ_NONE);
1654 return fgDominate(b1->bbNext, b2);
1657 // unknown dominators; err on the safe side and return false
1661 /* Check if b1 dominates b2 */
1662 unsigned numA = b1->bbNum;
1663 noway_assert(numA <= fgDomBBcount);
1664 unsigned numB = b2->bbNum;
1665 noway_assert(numB <= fgDomBBcount);
1667 // What we want to ask here is basically if A is in the middle of the path from B to the root (the entry node)
1668 // in the dominator tree. Turns out that can be translated as:
1670 // A dom B <-> preorder(A) <= preorder(B) && postorder(A) >= postorder(B)
1672 // where the equality holds when you ask if A dominates itself.
1674 fgDomTreePreOrder[numA] <= fgDomTreePreOrder[numB] && fgDomTreePostOrder[numA] >= fgDomTreePostOrder[numB];
1679 /*****************************************************************************
1681 * Returns true if block b1 can reach block b2.
1684 bool Compiler::fgReachable(BasicBlock* b1, BasicBlock* b2)
1686 noway_assert(fgDomsComputed);
1687 assert(!fgCheapPredsValid);
1690 // If the fgModified flag is false then we made some modifications to
1691 // the flow graph, like adding a new block or changing a conditional branch
1692 // into an unconditional branch.
1694 // We can continue to use the dominator and reachable information to
1695 // unmark loops as long as we haven't renumbered the blocks or we aren't
1696 // asking for information about a new block
1699 if (b2->bbNum > fgDomBBcount)
1706 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1708 if (fgReachable(b1, pred->flBlock))
1717 if (b1->bbNum > fgDomBBcount)
1719 noway_assert(b1->bbJumpKind == BBJ_NONE || b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND);
1721 if (b1->bbFallsThrough() && fgReachable(b1->bbNext, b2))
1726 if (b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND)
1728 return fgReachable(b1->bbJumpDest, b2);
1734 /* Check if b1 can reach b2 */
1735 assert(fgReachabilitySetsValid);
1736 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
1737 return BlockSetOps::IsMember(this, b2->bbReach, b1->bbNum);
1740 /*****************************************************************************
1741 * Update changed flow graph information.
1743 * If the flow graph has changed, we need to recompute various information if we want to use
1747 void Compiler::fgUpdateChangedFlowGraph()
1749 // We need to clear this so we don't hit an assert calling fgRenumberBlocks().
1750 fgDomsComputed = false;
1752 JITDUMP("\nRenumbering the basic blocks for fgUpdateChangeFlowGraph\n");
1756 fgComputeEnterBlocksSet();
1757 fgComputeReachabilitySets();
1761 /*****************************************************************************
1762 * Compute the bbReach sets.
1764 * This can be called to recompute the bbReach sets after the flow graph changes, such as when the
1765 * number of BasicBlocks change (and thus, the BlockSet epoch changes).
1767 * Finally, this also sets the BBF_GC_SAFE_POINT flag on blocks.
1769 * Assumes the predecessor lists are correct.
1771 * TODO-Throughput: This algorithm consumes O(n^2) because we're using dense bitsets to
1772 * represent reachability. While this yields O(1) time queries, it bloats the memory usage
1773 * for large code. We can do better if we try to approach reachability by
1774 * computing the strongly connected components of the flow graph. That way we only need
1775 * linear memory to label every block with its SCC.
1778 void Compiler::fgComputeReachabilitySets()
1780 assert(fgComputePredsDone);
1781 assert(!fgCheapPredsValid);
1784 fgReachabilitySetsValid = false;
1789 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1791 // Initialize the per-block bbReach sets. (Note that we can't just call BlockSetOps::ClearD()
1792 // when re-running this computation, because if the epoch changes, the size and representation of the
1793 // sets might change).
1794 block->bbReach = BlockSetOps::MakeEmpty(this);
1796 /* Mark block as reaching itself */
1797 BlockSetOps::AddElemD(this, block->bbReach, block->bbNum);
1800 /* Find the reachable blocks */
1801 // Also, set BBF_GC_SAFE_POINT.
1804 BlockSet BLOCKSET_INIT_NOCOPY(newReach, BlockSetOps::MakeEmpty(this));
1809 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1811 BlockSetOps::Assign(this, newReach, block->bbReach);
1813 bool predGcSafe = (block->bbPreds != nullptr); // Do all of our predecessor blocks have a GC safe bit?
1815 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1817 BasicBlock* predBlock = pred->flBlock;
1819 /* Union the predecessor's reachability set into newReach */
1820 BlockSetOps::UnionD(this, newReach, predBlock->bbReach);
1822 if (!(predBlock->bbFlags & BBF_GC_SAFE_POINT))
1830 block->bbFlags |= BBF_GC_SAFE_POINT;
1833 if (!BlockSetOps::Equal(this, newReach, block->bbReach))
1835 BlockSetOps::Assign(this, block->bbReach, newReach);
1844 printf("\nAfter computing reachability sets:\n");
1848 fgReachabilitySetsValid = true;
1852 /*****************************************************************************
1853 * Compute the entry blocks set.
1855 * Initialize fgEnterBlks to the set of blocks for which we don't have explicit control
1856 * flow edges. These are the entry basic block and each of the EH handler blocks.
1857 * For ARM, also include the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
1858 * to avoid creating "retless" calls, since we need the BBJ_ALWAYS for the purpose
1859 * of unwinding, even if the call doesn't return (due to an explicit throw, for example).
1862 void Compiler::fgComputeEnterBlocksSet()
1865 fgEnterBlksSetValid = false;
1868 fgEnterBlks = BlockSetOps::MakeEmpty(this);
1870 /* Now set the entry basic block */
1871 BlockSetOps::AddElemD(this, fgEnterBlks, fgFirstBB->bbNum);
1872 assert(fgFirstBB->bbNum == 1);
1874 if (compHndBBtabCount > 0)
1876 /* Also 'or' in the handler basic blocks */
1879 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
1881 if (HBtab->HasFilter())
1883 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdFilter->bbNum);
1885 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdHndBeg->bbNum);
1889 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1890 // TODO-ARM-Cleanup: The ARM code here to prevent creating retless calls by adding the BBJ_ALWAYS
1891 // to the enter blocks is a bit of a compromise, because sometimes the blocks are already reachable,
1892 // and it messes up DFS ordering to have them marked as enter block. We should prevent the
1893 // creation of retless calls some other way.
1894 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
1896 if (block->bbJumpKind == BBJ_CALLFINALLY)
1898 assert(block->isBBCallAlwaysPair());
1900 // Don't remove the BBJ_ALWAYS block that is only here for the unwinder. It might be dead
1901 // if the finally is no-return, so mark it as an entry point.
1902 BlockSetOps::AddElemD(this, fgEnterBlks, block->bbNext->bbNum);
1905 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1910 printf("Enter blocks: ");
1911 BLOCKSET_ITER_INIT(this, iter, fgEnterBlks, bbNum);
1912 while (iter.NextElem(this, &bbNum))
1914 printf("BB%02u ", bbNum);
1921 fgEnterBlksSetValid = true;
1925 /*****************************************************************************
1926 * Remove unreachable blocks.
1928 * Return true if any unreachable blocks were removed.
1931 bool Compiler::fgRemoveUnreachableBlocks()
1933 assert(!fgCheapPredsValid);
1934 assert(fgReachabilitySetsValid);
1936 bool hasLoops = false;
1937 bool hasUnreachableBlocks = false;
1940 /* Record unreachable blocks */
1941 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1943 /* Internal throw blocks are also reachable */
1944 if (fgIsThrowHlpBlk(block))
1948 else if (block == genReturnBB)
1950 // Don't remove statements for the genReturnBB block, as we might have special hookups there.
1951 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
1952 // the profiler hookup needs to have the "void GT_RETURN" statement
1953 // to properly set the info.compProfilerCallback flag.
1958 // If any of the entry blocks can reach this block, then we skip it.
1959 if (!BlockSetOps::IsEmptyIntersection(this, fgEnterBlks, block->bbReach))
1965 // Remove all the code for the block
1966 fgUnreachableBlock(block);
1968 // Make sure that the block was marked as removed */
1969 noway_assert(block->bbFlags & BBF_REMOVED);
1971 // Some blocks mark the end of trys and catches
1972 // and can't be removed. We convert these into
1973 // empty blocks of type BBJ_THROW
1975 if (block->bbFlags & BBF_DONT_REMOVE)
1977 bool bIsBBCallAlwaysPair = block->isBBCallAlwaysPair();
1979 /* Unmark the block as removed, */
1980 /* clear BBF_INTERNAL as well and set BBJ_IMPORTED */
1982 block->bbFlags &= ~(BBF_REMOVED | BBF_INTERNAL | BBF_NEEDS_GCPOLL);
1983 block->bbFlags |= BBF_IMPORTED;
1984 block->bbJumpKind = BBJ_THROW;
1985 block->bbSetRunRarely();
1987 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1988 // If this is a <BBJ_CALLFINALLY, BBJ_ALWAYS> pair, we have to clear BBF_FINALLY_TARGET flag on
1989 // the target node (of BBJ_ALWAYS) since BBJ_CALLFINALLY node is getting converted to a BBJ_THROW.
1990 if (bIsBBCallAlwaysPair)
1992 noway_assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
1993 fgClearFinallyTargetBit(block->bbNext->bbJumpDest);
1995 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1999 /* We have to call fgRemoveBlock next */
2000 hasUnreachableBlocks = true;
2006 // if (block->isRunRarely())
2008 if (block->bbJumpKind == BBJ_RETURN)
2013 /* Set BBF_LOOP_HEAD if we have backwards branches to this block */
2015 unsigned blockNum = block->bbNum;
2016 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
2018 BasicBlock* predBlock = pred->flBlock;
2019 if (blockNum <= predBlock->bbNum)
2021 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
2026 /* If block can reach predBlock then we have a loop head */
2027 if (BlockSetOps::IsMember(this, predBlock->bbReach, blockNum))
2031 /* Set the BBF_LOOP_HEAD flag */
2032 block->bbFlags |= BBF_LOOP_HEAD;
2039 fgHasLoops = hasLoops;
2041 if (hasUnreachableBlocks)
2043 // Now remove the unreachable blocks
2044 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2046 // If we mark the block with BBF_REMOVED then
2047 // we need to call fgRemovedBlock() on it
2049 if (block->bbFlags & BBF_REMOVED)
2051 fgRemoveBlock(block, true);
2053 // When we have a BBJ_CALLFINALLY, BBJ_ALWAYS pair; fgRemoveBlock will remove
2054 // both blocks, so we must advance 1 extra place in the block list
2056 if (block->isBBCallAlwaysPair())
2058 block = block->bbNext;
2064 return hasUnreachableBlocks;
2067 /*****************************************************************************
2069 * Function called to compute the dominator and reachable sets.
2071 * Assumes the predecessor lists are computed and correct.
2074 void Compiler::fgComputeReachability()
2079 printf("*************** In fgComputeReachability\n");
2082 fgVerifyHandlerTab();
2084 // Make sure that the predecessor lists are accurate
2085 assert(fgComputePredsDone);
2086 fgDebugCheckBBlist();
2089 /* Create a list of all BBJ_RETURN blocks. The head of the list is 'fgReturnBlocks'. */
2090 fgReturnBlocks = nullptr;
2092 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2094 // If this is a BBJ_RETURN block, add it to our list of all BBJ_RETURN blocks. This list is only
2095 // used to find return blocks.
2096 if (block->bbJumpKind == BBJ_RETURN)
2098 fgReturnBlocks = new (this, CMK_Reachability) BasicBlockList(block, fgReturnBlocks);
2102 // Compute reachability and then delete blocks determined to be unreachable. If we delete blocks, we
2103 // need to loop, as that might have caused more blocks to become unreachable. This can happen in the
2104 // case where a call to a finally is unreachable and deleted (maybe the call to the finally is
2105 // preceded by a throw or an infinite loop), making the blocks following the finally unreachable.
2106 // However, all EH entry blocks are considered global entry blocks, causing the blocks following the
2107 // call to the finally to stay rooted, until a second round of reachability is done.
2108 // The dominator algorithm expects that all blocks can be reached from the fgEnterBlks set.
2109 unsigned passNum = 1;
2113 // Just to be paranoid, avoid infinite loops; fall back to minopts.
2116 noway_assert(!"Too many unreachable block removal loops");
2119 /* Walk the flow graph, reassign block numbers to keep them in ascending order */
2120 JITDUMP("\nRenumbering the basic blocks for fgComputeReachability pass #%u\n", passNum);
2125 // Compute fgEnterBlks
2128 fgComputeEnterBlocksSet();
2134 fgComputeReachabilitySets();
2137 // Use reachability information to delete unreachable blocks.
2138 // Also, determine if the flow graph has loops and set 'fgHasLoops' accordingly.
2139 // Set the BBF_LOOP_HEAD flag on the block target of backwards branches.
2142 changed = fgRemoveUnreachableBlocks();
2149 printf("\nAfter computing reachability:\n");
2150 fgDispBasicBlocks(verboseTrees);
2154 fgVerifyHandlerTab();
2155 fgDebugCheckBBlist(true);
2159 // Now, compute the dominators
2165 /** In order to be able to compute dominance, we need to first get a DFS reverse post order sort on the basic flow graph
2166 * for the dominance algorithm to operate correctly. The reason why we need the DFS sort is because
2167 * we will build the dominance sets using the partial order induced by the DFS sorting. With this
2168 * precondition not holding true, the algorithm doesn't work properly.
2170 void Compiler::fgDfsInvPostOrder()
2172 // NOTE: This algorithm only pays attention to the actual blocks. It ignores the imaginary entry block.
2174 // visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid
2176 BlockSet BLOCKSET_INIT_NOCOPY(visited, BlockSetOps::MakeEmpty(this));
2178 // We begin by figuring out which basic blocks don't have incoming edges and mark them as
2179 // start nodes. Later on we run the recursive algorithm for each node that we
2180 // mark in this step.
2181 BlockSet_ValRet_T startNodes = fgDomFindStartNodes();
2183 // Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is
2184 // an incoming edge into the block).
2185 assert(fgEnterBlksSetValid);
2187 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2189 // BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2191 // This causes problems on ARM, because we for BBJ_CALLFINALLY/BBJ_ALWAYS pairs, we add the BBJ_ALWAYS
2192 // to the enter blocks set to prevent flow graph optimizations from removing it and creating retless call finallies
2193 // (BBF_RETLESS_CALL). This leads to an incorrect DFS ordering in some cases, because we start the recursive walk
2194 // from the BBJ_ALWAYS, which is reachable from other blocks. A better solution would be to change ARM to avoid
2195 // creating retless calls in a different way, not by adding BBJ_ALWAYS to fgEnterBlks.
2197 // So, let us make sure at least fgFirstBB is still there, even if it participates in a loop.
2198 BlockSetOps::AddElemD(this, startNodes, 1);
2199 assert(fgFirstBB->bbNum == 1);
2201 BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2204 assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum));
2206 // Call the flowgraph DFS traversal helper.
2207 unsigned postIndex = 1;
2208 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2210 // If the block has no predecessors, and we haven't already visited it (because it's in fgEnterBlks but also
2211 // reachable from the first block), go ahead and traverse starting from this block.
2212 if (BlockSetOps::IsMember(this, startNodes, block->bbNum) &&
2213 !BlockSetOps::IsMember(this, visited, block->bbNum))
2215 fgDfsInvPostOrderHelper(block, visited, &postIndex);
2219 // After the DFS reverse postorder is completed, we must have visited all the basic blocks.
2220 noway_assert(postIndex == fgBBcount + 1);
2221 noway_assert(fgBBNumMax == fgBBcount);
2226 printf("\nAfter doing a post order traversal of the BB graph, this is the ordering:\n");
2227 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2229 printf("%02u -> BB%02u\n", i, fgBBInvPostOrder[i]->bbNum);
2236 BlockSet_ValRet_T Compiler::fgDomFindStartNodes()
2241 // startNodes :: A set that represents which basic blocks in the flow graph don't have incoming edges.
2242 // We begin assuming everything is a start block and remove any block that is being referenced by another in its
2245 BlockSet BLOCKSET_INIT_NOCOPY(startNodes, BlockSetOps::MakeFull(this));
2247 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2249 unsigned cSucc = block->NumSucc(this);
2250 for (j = 0; j < cSucc; ++j)
2252 BasicBlock* succ = block->GetSucc(j, this);
2253 BlockSetOps::RemoveElemD(this, startNodes, succ->bbNum);
2260 printf("\nDominator computation start blocks (those blocks with no incoming edges):\n");
2261 BLOCKSET_ITER_INIT(this, iter, startNodes, bbNum);
2262 while (iter.NextElem(this, &bbNum))
2264 printf("BB%02u ", bbNum);
2273 //------------------------------------------------------------------------
2274 // fgDfsInvPostOrderHelper: Helper to assign post-order numbers to blocks.
2277 // block - The starting entry block
2278 // visited - The set of visited blocks
2279 // count - Pointer to the Dfs counter
2282 // Compute a non-recursive DFS traversal of the flow graph using an
2283 // evaluation stack to assign post-order numbers.
2285 void Compiler::fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count)
2287 // Assume we haven't visited this node yet (callers ensure this).
2288 assert(!BlockSetOps::IsMember(this, visited, block->bbNum));
2290 // Allocate a local stack to hold the DFS traversal actions necessary
2291 // to compute pre/post-ordering of the control flowgraph.
2292 ArrayStack<DfsBlockEntry> stack(this);
2294 // Push the first block on the stack to seed the traversal.
2295 stack.Push(DfsBlockEntry(DSS_Pre, block));
2296 // Flag the node we just visited to avoid backtracking.
2297 BlockSetOps::AddElemD(this, visited, block->bbNum);
2299 // The search is terminated once all the actions have been processed.
2300 while (stack.Height() != 0)
2302 DfsBlockEntry current = stack.Pop();
2303 BasicBlock* currentBlock = current.dfsBlock;
2305 if (current.dfsStackState == DSS_Pre)
2307 // This is a pre-visit that corresponds to the first time the
2308 // node is encountered in the spanning tree and receives pre-order
2309 // numberings. By pushing the post-action on the stack here we
2310 // are guaranteed to only process it after all of its successors
2311 // pre and post actions are processed.
2312 stack.Push(DfsBlockEntry(DSS_Post, currentBlock));
2314 unsigned cSucc = currentBlock->NumSucc(this);
2315 for (unsigned j = 0; j < cSucc; ++j)
2317 BasicBlock* succ = currentBlock->GetSucc(j, this);
2319 // If this is a node we haven't seen before, go ahead and process
2320 if (!BlockSetOps::IsMember(this, visited, succ->bbNum))
2322 // Push a pre-visit action for this successor onto the stack and
2323 // mark it as visited in case this block has multiple successors
2324 // to the same node (multi-graph).
2325 stack.Push(DfsBlockEntry(DSS_Pre, succ));
2326 BlockSetOps::AddElemD(this, visited, succ->bbNum);
2332 // This is a post-visit that corresponds to the last time the
2333 // node is visited in the spanning tree and only happens after
2334 // all descendents in the spanning tree have had pre and post
2337 assert(current.dfsStackState == DSS_Post);
2339 unsigned invCount = fgBBcount - *count + 1;
2340 assert(1 <= invCount && invCount <= fgBBNumMax);
2341 fgBBInvPostOrder[invCount] = currentBlock;
2342 currentBlock->bbDfsNum = invCount;
2348 void Compiler::fgComputeDoms()
2350 assert(!fgCheapPredsValid);
2355 printf("*************** In fgComputeDoms\n");
2358 fgVerifyHandlerTab();
2360 // Make sure that the predecessor lists are accurate.
2361 // Also check that the blocks are properly, densely numbered (so calling fgRenumberBlocks is not necessary).
2362 fgDebugCheckBBlist(true);
2364 // Assert things related to the BlockSet epoch.
2365 assert(fgBBcount == fgBBNumMax);
2366 assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);
2369 BlockSet BLOCKSET_INIT_NOCOPY(processedBlks, BlockSetOps::MakeEmpty(this));
2371 fgBBInvPostOrder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1];
2372 memset(fgBBInvPostOrder, 0, sizeof(BasicBlock*) * (fgBBNumMax + 1));
2374 fgDfsInvPostOrder();
2375 noway_assert(fgBBInvPostOrder[0] == nullptr);
2377 // flRoot and bbRoot represent an imaginary unique entry point in the flow graph.
2378 // All the orphaned EH blocks and fgFirstBB will temporarily have its predecessors list
2379 // (with bbRoot as the only basic block in it) set as flRoot.
2380 // Later on, we clear their predecessors and let them to be nullptr again.
2381 // Since we number basic blocks starting at one, the imaginary entry block is conveniently numbered as zero.
2385 bbRoot.bbPreds = nullptr;
2387 bbRoot.bbIDom = &bbRoot;
2388 bbRoot.bbDfsNum = 0;
2389 flRoot.flNext = nullptr;
2390 flRoot.flBlock = &bbRoot;
2392 fgBBInvPostOrder[0] = &bbRoot;
2394 // Mark both bbRoot and fgFirstBB processed
2395 BlockSetOps::AddElemD(this, processedBlks, 0); // bbRoot == block #0
2396 BlockSetOps::AddElemD(this, processedBlks, 1); // fgFirstBB == block #1
2397 assert(fgFirstBB->bbNum == 1);
2399 // Special case fgFirstBB to say its IDom is bbRoot.
2400 fgFirstBB->bbIDom = &bbRoot;
2402 BasicBlock* block = nullptr;
2404 for (block = fgFirstBB->bbNext; block != nullptr; block = block->bbNext)
2406 // If any basic block has no predecessors then we flag it as processed and temporarily
2407 // mark its precedessor list to be flRoot. This makes the flowgraph connected,
2408 // a precondition that is needed by the dominance algorithm to operate properly.
2409 if (block->bbPreds == nullptr)
2411 block->bbPreds = &flRoot;
2412 block->bbIDom = &bbRoot;
2413 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2417 block->bbIDom = nullptr;
2421 // Mark the EH blocks as entry blocks and also flag them as processed.
2422 if (compHndBBtabCount > 0)
2426 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
2428 if (HBtab->HasFilter())
2430 HBtab->ebdFilter->bbIDom = &bbRoot;
2431 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdFilter->bbNum);
2433 HBtab->ebdHndBeg->bbIDom = &bbRoot;
2434 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdHndBeg->bbNum);
2438 // Now proceed to compute the immediate dominators for each basic block.
2439 bool changed = true;
2443 for (unsigned i = 1; i <= fgBBNumMax;
2444 ++i) // Process each actual block; don't process the imaginary predecessor block.
2446 flowList* first = nullptr;
2447 BasicBlock* newidom = nullptr;
2448 block = fgBBInvPostOrder[i];
2450 // If we have a block that has bbRoot as its bbIDom
2451 // it means we flag it as processed and as an entry block so
2452 // in this case we're all set.
2453 if (block->bbIDom == &bbRoot)
2458 // Pick up the first processed predecesor of the current block.
2459 for (first = block->bbPreds; first != nullptr; first = first->flNext)
2461 if (BlockSetOps::IsMember(this, processedBlks, first->flBlock->bbNum))
2466 noway_assert(first != nullptr);
2468 // We assume the first processed predecessor will be the
2469 // immediate dominator and then compute the forward flow analysis.
2470 newidom = first->flBlock;
2471 for (flowList* p = block->bbPreds; p != nullptr; p = p->flNext)
2473 if (p->flBlock == first->flBlock)
2477 if (p->flBlock->bbIDom != nullptr)
2479 // fgIntersectDom is basically the set intersection between
2480 // the dominance sets of the new IDom and the current predecessor
2481 // Since the nodes are ordered in DFS inverse post order and
2482 // IDom induces a tree, fgIntersectDom actually computes
2483 // the lowest common ancestor in the dominator tree.
2484 newidom = fgIntersectDom(p->flBlock, newidom);
2488 // If the Immediate dominator changed, assign the new one
2489 // to the current working basic block.
2490 if (block->bbIDom != newidom)
2492 noway_assert(newidom != nullptr);
2493 block->bbIDom = newidom;
2496 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2500 // As stated before, once we have computed immediate dominance we need to clear
2501 // all the basic blocks whose predecessor list was set to flRoot. This
2502 // reverts that and leaves the blocks the same as before.
2503 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2505 if (block->bbPreds == &flRoot)
2507 block->bbPreds = nullptr;
2521 fgDomBBcount = fgBBcount;
2522 assert(fgBBcount == fgBBNumMax);
2523 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
2525 fgDomsComputed = true;
2528 void Compiler::fgBuildDomTree()
2536 printf("\nInside fgBuildDomTree\n");
2540 // domTree :: The dominance tree represented using adjacency lists. We use BasicBlockList to represent edges.
2541 // Indexed by basic block number.
2542 unsigned bbArraySize = fgBBNumMax + 1;
2543 BasicBlockList** domTree = new (this, CMK_DominatorMemory) BasicBlockList*[bbArraySize];
2545 fgDomTreePreOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2546 fgDomTreePostOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2548 // Initialize all the data structures.
2549 for (i = 0; i < bbArraySize; ++i)
2551 domTree[i] = nullptr;
2552 fgDomTreePreOrder[i] = fgDomTreePostOrder[i] = 0;
2555 // Build the dominance tree.
2556 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2558 // If the immediate dominator is not the imaginary root (bbRoot)
2559 // we proceed to append this block to the children of the dominator node.
2560 if (block->bbIDom->bbNum != 0)
2562 int bbNum = block->bbIDom->bbNum;
2563 domTree[bbNum] = new (this, CMK_DominatorMemory) BasicBlockList(block, domTree[bbNum]);
2567 // This means this block had bbRoot set as its IDom. We clear it out
2568 // and convert the tree back to a forest.
2569 block->bbIDom = nullptr;
2576 printf("\nAfter computing the Dominance Tree:\n");
2577 fgDispDomTree(domTree);
2581 // Get the bitset that represents the roots of the dominance tree.
2582 // Something to note here is that the dominance tree has been converted from a forest to a tree
2583 // by using the bbRoot trick on fgComputeDoms. The reason we have a forest instead of a real tree
2584 // is because we treat the EH blocks as entry nodes so the real dominance tree is not necessarily connected.
2585 BlockSet_ValRet_T domTreeEntryNodes = fgDomTreeEntryNodes(domTree);
2587 // The preorder and postorder numbers.
2588 // We start from 1 to match the bbNum ordering.
2589 unsigned preNum = 1;
2590 unsigned postNum = 1;
2592 // There will be nodes in the dominance tree that will not be reachable:
2593 // the catch blocks that return since they don't have any predecessor.
2594 // For that matter we'll keep track of how many nodes we can
2595 // reach and assert at the end that we visited all of them.
2596 unsigned domTreeReachable = fgBBcount;
2598 // Once we have the dominance tree computed, we need to traverse it
2599 // to get the preorder and postorder numbers for each node. The purpose of
2600 // this is to achieve O(1) queries for of the form A dominates B.
2601 for (i = 1; i <= fgBBNumMax; ++i)
2603 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2605 if (domTree[i] == nullptr)
2607 // If this is an entry node but there's no children on this
2608 // node, it means it's unreachable so we decrement the reachable
2614 // Otherwise, we do a DFS traversal of the dominator tree.
2615 fgTraverseDomTree(i, domTree, &preNum, &postNum);
2620 noway_assert(preNum == domTreeReachable + 1);
2621 noway_assert(postNum == domTreeReachable + 1);
2623 // Once we have all the reachable nodes numbered, we proceed to
2624 // assign numbers to the non-reachable ones, just assign incrementing
2625 // values. We must reach fgBBcount at the end.
2627 for (i = 1; i <= fgBBNumMax; ++i)
2629 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2631 if (domTree[i] == nullptr)
2633 fgDomTreePreOrder[i] = preNum++;
2634 fgDomTreePostOrder[i] = postNum++;
2639 noway_assert(preNum == fgBBNumMax + 1);
2640 noway_assert(postNum == fgBBNumMax + 1);
2641 noway_assert(fgDomTreePreOrder[0] == 0); // Unused first element
2642 noway_assert(fgDomTreePostOrder[0] == 0); // Unused first element
2647 printf("\nAfter traversing the dominance tree:\n");
2648 printf("PreOrder:\n");
2649 for (i = 1; i <= fgBBNumMax; ++i)
2651 printf("BB%02u : %02u\n", i, fgDomTreePreOrder[i]);
2653 printf("PostOrder:\n");
2654 for (i = 1; i <= fgBBNumMax; ++i)
2656 printf("BB%02u : %02u\n", i, fgDomTreePostOrder[i]);
2662 BlockSet_ValRet_T Compiler::fgDomTreeEntryNodes(BasicBlockList** domTree)
2664 // domTreeEntryNodes :: Set that represents which basic blocks are roots of the dominator forest.
2666 BlockSet BLOCKSET_INIT_NOCOPY(domTreeEntryNodes, BlockSetOps::MakeFull(this));
2668 // First of all we need to find all the roots of the dominance forest.
2670 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2672 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2674 BlockSetOps::RemoveElemD(this, domTreeEntryNodes, current->block->bbNum);
2678 return domTreeEntryNodes;
2682 void Compiler::fgDispDomTree(BasicBlockList** domTree)
2684 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2686 if (domTree[i] != nullptr)
2688 printf("BB%02u : ", i);
2689 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2691 assert(current->block);
2692 printf("BB%02u ", current->block->bbNum);
2701 //------------------------------------------------------------------------
2702 // fgTraverseDomTree: Assign pre/post-order numbers to the dominator tree.
2705 // bbNum - The basic block number of the starting block
2706 // domTree - The dominator tree (as child block lists)
2707 // preNum - Pointer to the pre-number counter
2708 // postNum - Pointer to the post-number counter
2711 // Runs a non-recursive DFS traversal of the dominator tree using an
2712 // evaluation stack to assign pre-order and post-order numbers.
2713 // These numberings are used to provide constant time lookup for
2714 // ancestor/descendent tests between pairs of nodes in the tree.
2716 void Compiler::fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum)
2718 noway_assert(bbNum <= fgBBNumMax);
2720 // If the block preorder number is not zero it means we already visited
2721 // that node, so we skip it.
2722 if (fgDomTreePreOrder[bbNum] == 0)
2724 // If this is the first time we visit this node, both preorder and postnumber
2725 // values must be zero.
2726 noway_assert(fgDomTreePostOrder[bbNum] == 0);
2728 // Allocate a local stack to hold the Dfs traversal actions necessary
2729 // to compute pre/post-ordering of the dominator tree.
2730 ArrayStack<DfsNumEntry> stack(this);
2732 // Push the first entry number on the stack to seed the traversal.
2733 stack.Push(DfsNumEntry(DSS_Pre, bbNum));
2735 // The search is terminated once all the actions have been processed.
2736 while (stack.Height() != 0)
2738 DfsNumEntry current = stack.Pop();
2739 unsigned currentNum = current.dfsNum;
2741 if (current.dfsStackState == DSS_Pre)
2743 // This pre-visit action corresponds to the first time the
2744 // node is encountered during the spanning traversal.
2745 noway_assert(fgDomTreePreOrder[currentNum] == 0);
2746 noway_assert(fgDomTreePostOrder[currentNum] == 0);
2748 // Assign the preorder number on the first visit.
2749 fgDomTreePreOrder[currentNum] = (*preNum)++;
2751 // Push this nodes post-action on the stack such that all successors
2752 // pre-order visits occur before this nodes post-action. We will assign
2753 // its post-order numbers when we pop off the stack.
2754 stack.Push(DfsNumEntry(DSS_Post, currentNum));
2756 // For each child in the dominator tree process its pre-actions.
2757 for (BasicBlockList* child = domTree[currentNum]; child != nullptr; child = child->next)
2759 unsigned childNum = child->block->bbNum;
2761 // This is a tree so never could have been visited
2762 assert(fgDomTreePreOrder[childNum] == 0);
2764 // Push the successor in the dominator tree for pre-actions.
2765 stack.Push(DfsNumEntry(DSS_Pre, childNum));
2770 // This post-visit action corresponds to the last time the node
2771 // is encountered and only after all descendents in the spanning
2772 // tree have had pre and post-order numbers assigned.
2774 assert(current.dfsStackState == DSS_Post);
2775 assert(fgDomTreePreOrder[currentNum] != 0);
2776 assert(fgDomTreePostOrder[currentNum] == 0);
2778 // Now assign this nodes post-order number.
2779 fgDomTreePostOrder[currentNum] = (*postNum)++;
2785 // This code finds the lowest common ancestor in the
2786 // dominator tree between two basic blocks. The LCA in the Dominance tree
2787 // represents the closest dominator between the two basic blocks. Used to
2788 // adjust the IDom value in fgComputDoms.
2789 BasicBlock* Compiler::fgIntersectDom(BasicBlock* a, BasicBlock* b)
2791 BasicBlock* finger1 = a;
2792 BasicBlock* finger2 = b;
2793 while (finger1 != finger2)
2795 while (finger1->bbDfsNum > finger2->bbDfsNum)
2797 finger1 = finger1->bbIDom;
2799 while (finger2->bbDfsNum > finger1->bbDfsNum)
2801 finger2 = finger2->bbIDom;
2807 // Return a BlockSet containing all the blocks that dominate 'block'.
2808 BlockSet_ValRet_T Compiler::fgGetDominatorSet(BasicBlock* block)
2810 assert(block != nullptr);
2812 BlockSet BLOCKSET_INIT_NOCOPY(domSet, BlockSetOps::MakeEmpty(this));
2816 BlockSetOps::AddElemD(this, domSet, block->bbNum);
2817 if (block == block->bbIDom)
2819 break; // We found a cycle in the IDom list, so we're done.
2821 block = block->bbIDom;
2822 } while (block != nullptr);
2827 /*****************************************************************************
2829 * fgComputeCheapPreds: Function called to compute the BasicBlock::bbCheapPreds lists.
2831 * No other block data is changed (e.g., bbRefs, bbFlags).
2833 * The cheap preds lists are similar to the normal (bbPreds) predecessor lists, but are cheaper to
2834 * compute and store, as follows:
2835 * 1. A flow edge is typed BasicBlockList, which only has a block pointer and 'next' pointer. It doesn't
2836 * have weights or a dup count.
2837 * 2. The preds list for a block is not sorted by block number.
2838 * 3. The predecessors of the block following a BBJ_CALLFINALLY (the corresponding BBJ_ALWAYS,
2839 * for normal, non-retless calls to the finally) are not computed.
2840 * 4. The cheap preds lists will contain duplicates if a single switch table has multiple branches
2841 * to the same block. Thus, we don't spend the time looking for duplicates for every edge we insert.
2843 void Compiler::fgComputeCheapPreds()
2845 noway_assert(!fgComputePredsDone); // We can't do this if we've got the full preds.
2846 noway_assert(fgFirstBB != nullptr);
2853 printf("\n*************** In fgComputeCheapPreds()\n");
2854 fgDispBasicBlocks();
2859 // Clear out the cheap preds lists.
2862 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2864 switch (block->bbJumpKind)
2867 fgAddCheapPred(block->bbJumpDest, block);
2868 fgAddCheapPred(block->bbNext, block);
2871 case BBJ_CALLFINALLY:
2872 case BBJ_LEAVE: // If fgComputeCheapPreds is called before all blocks are imported, BBJ_LEAVE blocks are
2873 // still in the BB list.
2875 case BBJ_EHCATCHRET:
2876 fgAddCheapPred(block->bbJumpDest, block);
2880 fgAddCheapPred(block->bbNext, block);
2883 case BBJ_EHFILTERRET:
2884 // Connect end of filter to catch handler.
2885 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
2886 // fgComputeCheapPreds before fgImport on an ill-formed program; the problem will be detected in
2888 if (block->bbJumpDest != nullptr)
2890 fgAddCheapPred(block->bbJumpDest, block);
2896 jumpCnt = block->bbJumpSwt->bbsCount;
2897 BasicBlock** jumpTab;
2898 jumpTab = block->bbJumpSwt->bbsDstTab;
2902 fgAddCheapPred(*jumpTab, block);
2903 } while (++jumpTab, --jumpCnt);
2907 case BBJ_EHFINALLYRET: // It's expensive to compute the preds for this case, so we don't for the cheap
2914 noway_assert(!"Unexpected bbJumpKind");
2919 fgCheapPredsValid = true;
2924 printf("\n*************** After fgComputeCheapPreds()\n");
2925 fgDispBasicBlocks();
2931 /*****************************************************************************
2932 * Add 'blockPred' to the cheap predecessor list of 'block'.
2935 void Compiler::fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred)
2937 assert(!fgComputePredsDone);
2938 assert(block != nullptr);
2939 assert(blockPred != nullptr);
2941 block->bbCheapPreds = new (this, CMK_FlowList) BasicBlockList(blockPred, block->bbCheapPreds);
2943 #if MEASURE_BLOCK_SIZE
2944 genFlowNodeCnt += 1;
2945 genFlowNodeSize += sizeof(BasicBlockList);
2946 #endif // MEASURE_BLOCK_SIZE
2949 /*****************************************************************************
2950 * Remove 'blockPred' from the cheap predecessor list of 'block'.
2951 * If there are duplicate edges, only remove one of them.
2953 void Compiler::fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred)
2955 assert(!fgComputePredsDone);
2956 assert(fgCheapPredsValid);
2958 flowList* oldEdge = nullptr;
2960 assert(block != nullptr);
2961 assert(blockPred != nullptr);
2962 assert(block->bbCheapPreds != nullptr);
2964 /* Is this the first block in the pred list? */
2965 if (blockPred == block->bbCheapPreds->block)
2967 block->bbCheapPreds = block->bbCheapPreds->next;
2971 BasicBlockList* pred;
2972 for (pred = block->bbCheapPreds; pred->next != nullptr; pred = pred->next)
2974 if (blockPred == pred->next->block)
2979 noway_assert(pred->next != nullptr); // we better have found it!
2980 pred->next = pred->next->next; // splice it out
2984 void Compiler::fgRemovePreds()
2986 C_ASSERT(offsetof(BasicBlock, bbPreds) ==
2987 offsetof(BasicBlock, bbCheapPreds)); // bbPreds and bbCheapPreds are at the same place in a union,
2988 C_ASSERT(sizeof(((BasicBlock*)0)->bbPreds) ==
2989 sizeof(((BasicBlock*)0)->bbCheapPreds)); // and are the same size. So, this function removes both.
2991 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2993 block->bbPreds = nullptr;
2995 fgComputePredsDone = false;
2996 fgCheapPredsValid = false;
2999 /*****************************************************************************
3001 * Function called to compute the bbPreds lists.
3003 void Compiler::fgComputePreds()
3005 noway_assert(fgFirstBB);
3012 printf("\n*************** In fgComputePreds()\n");
3013 fgDispBasicBlocks();
3018 // reset the refs count for each basic block
3020 for (block = fgFirstBB; block; block = block->bbNext)
3025 /* the first block is always reachable! */
3026 fgFirstBB->bbRefs = 1;
3028 /* Treat the initial block as a jump target */
3029 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3033 for (block = fgFirstBB; block; block = block->bbNext)
3035 switch (block->bbJumpKind)
3037 case BBJ_CALLFINALLY:
3038 if (!(block->bbFlags & BBF_RETLESS_CALL))
3040 assert(block->isBBCallAlwaysPair());
3042 /* Mark the next block as being a jump target,
3043 since the call target will return there */
3044 PREFIX_ASSUME(block->bbNext != nullptr);
3045 block->bbNext->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
3050 case BBJ_LEAVE: // Sometimes fgComputePreds is called before all blocks are imported, so BBJ_LEAVE
3051 // blocks are still in the BB list.
3054 case BBJ_EHCATCHRET:
3056 /* Mark the jump dest block as being a jump target */
3057 block->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3059 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3061 /* Is the next block reachable? */
3063 if (block->bbJumpKind != BBJ_COND)
3068 noway_assert(block->bbNext);
3070 /* Fall through, the next block is also reachable */
3075 fgAddRefPred(block->bbNext, block, nullptr, true);
3078 case BBJ_EHFILTERRET:
3080 // Connect end of filter to catch handler.
3081 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
3082 // fgComputePreds before fgImport on an ill-formed program; the problem will be detected in fgImport.
3083 if (block->bbJumpDest != nullptr)
3085 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3089 case BBJ_EHFINALLYRET:
3091 /* Connect the end of the finally to the successor of
3092 the call to this finally */
3094 if (!block->hasHndIndex())
3096 NO_WAY("endfinally outside a finally/fault block.");
3099 unsigned hndIndex = block->getHndIndex();
3100 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3102 if (!ehDsc->HasFinallyOrFaultHandler())
3104 NO_WAY("endfinally outside a finally/fault block.");
3107 if (ehDsc->HasFinallyHandler())
3109 // Find all BBJ_CALLFINALLY that branched to this finally handler.
3112 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3114 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3115 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3117 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3122 noway_assert(bcall->isBBCallAlwaysPair());
3123 fgAddRefPred(bcall->bbNext, block, nullptr, true);
3135 jumpCnt = block->bbJumpSwt->bbsCount;
3136 BasicBlock** jumpTab;
3137 jumpTab = block->bbJumpSwt->bbsDstTab;
3141 /* Mark the target block as being a jump target */
3142 (*jumpTab)->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3144 fgAddRefPred(*jumpTab, block, nullptr, true);
3145 } while (++jumpTab, --jumpCnt);
3150 noway_assert(!"Unexpected bbJumpKind");
3155 for (unsigned EHnum = 0; EHnum < compHndBBtabCount; EHnum++)
3157 EHblkDsc* ehDsc = ehGetDsc(EHnum);
3159 if (ehDsc->HasFilter())
3161 ehDsc->ebdFilter->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3164 ehDsc->ebdHndBeg->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3168 fgComputePredsDone = true;
3173 printf("\n*************** After fgComputePreds()\n");
3174 fgDispBasicBlocks();
3180 unsigned Compiler::fgNSuccsOfFinallyRet(BasicBlock* block)
3184 fgSuccOfFinallyRetWork(block, ~0, &bb, &res);
3188 BasicBlock* Compiler::fgSuccOfFinallyRet(BasicBlock* block, unsigned i)
3192 fgSuccOfFinallyRetWork(block, i, &bb, &res);
3196 void Compiler::fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres)
3198 assert(block->hasHndIndex()); // Otherwise, endfinally outside a finally/fault block?
3200 unsigned hndIndex = block->getHndIndex();
3201 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3203 assert(ehDsc->HasFinallyOrFaultHandler()); // Otherwise, endfinally outside a finally/fault block.
3206 unsigned succNum = 0;
3208 if (ehDsc->HasFinallyHandler())
3212 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3214 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3216 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3218 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3223 assert(bcall->isBBCallAlwaysPair());
3227 *bres = bcall->bbNext;
3233 assert(i == ~0u || ehDsc->HasFaultHandler()); // Should reach here only for fault blocks.
3240 Compiler::SwitchUniqueSuccSet Compiler::GetDescriptorForSwitch(BasicBlock* switchBlk)
3242 assert(switchBlk->bbJumpKind == BBJ_SWITCH);
3243 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3244 SwitchUniqueSuccSet res;
3245 if (switchMap->Lookup(switchBlk, &res))
3251 // We must compute the descriptor. Find which are dups, by creating a bit set with the unique successors.
3252 // We create a temporary bitset of blocks to compute the unique set of successor blocks,
3253 // since adding a block's number twice leaves just one "copy" in the bitset. Note that
3254 // we specifically don't use the BlockSet type, because doing so would require making a
3255 // call to EnsureBasicBlockEpoch() to make sure the epoch is up-to-date. However, that
3256 // can create a new epoch, thus invalidating all existing BlockSet objects, such as
3257 // reachability information stored in the blocks. To avoid that, we just use a local BitVec.
3259 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
3260 BitVec BITVEC_INIT_NOCOPY(uniqueSuccBlocks, BitVecOps::MakeEmpty(&blockVecTraits));
3261 BasicBlock** jumpTable = switchBlk->bbJumpSwt->bbsDstTab;
3262 unsigned jumpCount = switchBlk->bbJumpSwt->bbsCount;
3263 for (unsigned i = 0; i < jumpCount; i++)
3265 BasicBlock* targ = jumpTable[i];
3266 BitVecOps::AddElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3268 // Now we have a set of unique successors.
3269 unsigned numNonDups = BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks);
3271 typedef BasicBlock* BasicBlockPtr;
3272 BasicBlockPtr* nonDups = new (getAllocator()) BasicBlockPtr[numNonDups];
3274 unsigned nonDupInd = 0;
3275 // At this point, all unique targets are in "uniqueSuccBlocks". As we encounter each,
3276 // add to nonDups, remove from "uniqueSuccBlocks".
3277 for (unsigned i = 0; i < jumpCount; i++)
3279 BasicBlock* targ = jumpTable[i];
3280 if (BitVecOps::IsMember(&blockVecTraits, uniqueSuccBlocks, targ->bbNum))
3282 nonDups[nonDupInd] = targ;
3284 BitVecOps::RemoveElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3288 assert(nonDupInd == numNonDups);
3289 assert(BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks) == 0);
3290 res.numDistinctSuccs = numNonDups;
3291 res.nonDuplicates = nonDups;
3292 switchMap->Set(switchBlk, res);
3297 void Compiler::SwitchUniqueSuccSet::UpdateTarget(IAllocator* alloc,
3298 BasicBlock* switchBlk,
3302 assert(switchBlk->bbJumpKind == BBJ_SWITCH); // Precondition.
3303 unsigned jmpTabCnt = switchBlk->bbJumpSwt->bbsCount;
3304 BasicBlock** jmpTab = switchBlk->bbJumpSwt->bbsDstTab;
3306 // Is "from" still in the switch table (because it had more than one entry before?)
3307 bool fromStillPresent = false;
3308 for (unsigned i = 0; i < jmpTabCnt; i++)
3310 if (jmpTab[i] == from)
3312 fromStillPresent = true;
3317 // Is "to" already in "this"?
3318 bool toAlreadyPresent = false;
3319 for (unsigned i = 0; i < numDistinctSuccs; i++)
3321 if (nonDuplicates[i] == to)
3323 toAlreadyPresent = true;
3329 // If "from" is still present, and "to" is already present, do nothing
3330 // If "from" is still present, and "to" is not, must reallocate to add an entry.
3331 // If "from" is not still present, and "to" is not present, write "to" where "from" was.
3332 // If "from" is not still present, but "to" is present, remove "from".
3333 if (fromStillPresent && toAlreadyPresent)
3337 else if (fromStillPresent && !toAlreadyPresent)
3339 // reallocate to add an entry
3340 typedef BasicBlock* BasicBlockPtr;
3341 BasicBlockPtr* newNonDups = new (alloc) BasicBlockPtr[numDistinctSuccs + 1];
3342 memcpy(newNonDups, nonDuplicates, numDistinctSuccs * sizeof(BasicBlock*));
3343 newNonDups[numDistinctSuccs] = to;
3345 nonDuplicates = newNonDups;
3347 else if (!fromStillPresent && !toAlreadyPresent)
3350 // write "to" where "from" was
3351 bool foundFrom = false;
3353 for (unsigned i = 0; i < numDistinctSuccs; i++)
3355 if (nonDuplicates[i] == from)
3357 nonDuplicates[i] = to;
3368 assert(!fromStillPresent && toAlreadyPresent);
3371 bool foundFrom = false;
3373 for (unsigned i = 0; i < numDistinctSuccs; i++)
3375 if (nonDuplicates[i] == from)
3377 nonDuplicates[i] = nonDuplicates[numDistinctSuccs - 1];
3389 /*****************************************************************************
3391 * Simple utility function to remove an entry for a block in the switch desc
3392 * map. So it can be called from other phases.
3395 void Compiler::fgInvalidateSwitchDescMapEntry(BasicBlock* block)
3397 // Check if map has no entries yet.
3398 if (m_switchDescMap != nullptr)
3400 m_switchDescMap->Remove(block);
3404 void Compiler::UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to)
3406 if (m_switchDescMap == nullptr)
3408 return; // No mappings, nothing to do.
3412 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3413 SwitchUniqueSuccSet* res = switchMap->LookupPointer(switchBlk);
3416 // If no result, nothing to do. Otherwise, update it.
3417 res->UpdateTarget(getAllocator(), switchBlk, from, to);
3421 /*****************************************************************************
3422 * For a block that is in a handler region, find the first block of the most-nested
3423 * handler containing the block.
3425 BasicBlock* Compiler::fgFirstBlockOfHandler(BasicBlock* block)
3427 assert(block->hasHndIndex());
3428 return ehGetDsc(block->getHndIndex())->ebdHndBeg;
3431 /*****************************************************************************
3433 * Function called to find back edges and return blocks and mark them as needing GC Polls. This marks all
3436 void Compiler::fgMarkGCPollBlocks()
3438 if (GCPOLL_NONE == opts.compGCPollType)
3444 /* Check that the flowgraph data (bbNum, bbRefs, bbPreds) is up-to-date */
3445 fgDebugCheckBBlist();
3450 // Return blocks always need GC polls. In addition, all back edges (including those from switch
3451 // statements) need GC polls. The poll is on the block with the outgoing back edge (or ret), rather than
3452 // on the destination or on the edge itself.
3453 for (block = fgFirstBB; block; block = block->bbNext)
3455 bool blockNeedsPoll = false;
3456 switch (block->bbJumpKind)
3460 blockNeedsPoll = (block->bbJumpDest->bbNum <= block->bbNum);
3464 blockNeedsPoll = true;
3469 jumpCnt = block->bbJumpSwt->bbsCount;
3470 BasicBlock** jumpTab;
3471 jumpTab = block->bbJumpSwt->bbsDstTab;
3475 if ((*jumpTab)->bbNum <= block->bbNum)
3477 blockNeedsPoll = true;
3480 } while (++jumpTab, --jumpCnt);
3489 block->bbFlags |= BBF_NEEDS_GCPOLL;
3494 void Compiler::fgInitBlockVarSets()
3496 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3498 block->InitVarSets(this);
3501 // QMarks are much like blocks, and need their VarSets initialized.
3502 assert(!compIsForInlining());
3503 for (unsigned i = 0; i < compQMarks->Size(); i++)
3505 GenTreePtr qmark = compQMarks->Get(i);
3506 // Perhaps the gtOper of a QMark node was changed to something else since it was created and put on this list.
3507 // So can't hurt to check.
3508 if (qmark->OperGet() == GT_QMARK)
3510 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtThenLiveSet, VarSetOps::UninitVal());
3511 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtElseLiveSet, VarSetOps::UninitVal());
3514 fgBBVarSetsInited = true;
3517 /*****************************************************************************
3519 * The following does the final pass on BBF_NEEDS_GCPOLL and then actually creates the GC Polls.
3521 void Compiler::fgCreateGCPolls()
3523 if (GCPOLL_NONE == opts.compGCPollType)
3528 bool createdPollBlocks = false;
3533 printf("*************** In fgCreateGCPolls() for %s\n", info.compFullName);
3537 if (!(opts.MinOpts() || opts.compDbgCode))
3539 // Remove polls from well formed loops with a constant upper bound.
3540 for (unsigned lnum = 0; lnum < optLoopCount; ++lnum)
3542 // Look for constant counted loops that run for a short duration. This logic is very similar to
3543 // what's in code:Compiler::optUnrollLoops, since they have similar constraints. However, this
3544 // logic is much more permissive since we're not doing a complex transformation.
3547 * I feel bad cloning so much logic from optUnrollLoops
3550 // Filter out loops not meeting the obvious preconditions.
3552 if (optLoopTable[lnum].lpFlags & LPFLG_REMOVED)
3557 if (!(optLoopTable[lnum].lpFlags & LPFLG_CONST))
3562 BasicBlock* head = optLoopTable[lnum].lpHead;
3563 BasicBlock* bottom = optLoopTable[lnum].lpBottom;
3565 // Loops dominated by GC_SAFE_POINT won't have this set.
3566 if (!(bottom->bbFlags & BBF_NEEDS_GCPOLL))
3571 /* Get the loop data:
3575 - iterator increment
3576 - increment operation type (i.e. ASG_ADD, ASG_SUB, etc...)
3577 - loop test type (i.e. GT_GE, GT_LT, etc...)
3580 int lbeg = optLoopTable[lnum].lpConstInit;
3581 int llim = optLoopTable[lnum].lpConstLimit();
3582 genTreeOps testOper = optLoopTable[lnum].lpTestOper();
3584 int lvar = optLoopTable[lnum].lpIterVar();
3585 int iterInc = optLoopTable[lnum].lpIterConst();
3586 genTreeOps iterOper = optLoopTable[lnum].lpIterOper();
3588 var_types iterOperType = optLoopTable[lnum].lpIterOperType();
3589 bool unsTest = (optLoopTable[lnum].lpTestTree->gtFlags & GTF_UNSIGNED) != 0;
3590 if (lvaTable[lvar].lvAddrExposed)
3591 { // Can't reason about the value of the iteration variable.
3597 /* Find the number of iterations - the function returns false if not a constant number */
3599 if (!optComputeLoopRep(lbeg, llim, iterInc, iterOper, iterOperType, testOper, unsTest,
3600 // The value here doesn't matter for this variation of the optimization
3606 printf("Could not compute loop iterations for loop from BB%02u to BB%02u", head->bbNum,
3610 (void)head; // suppress gcc error.
3615 /* Forget it if there are too many repetitions or not a constant loop */
3617 static const unsigned ITER_LIMIT = 256;
3618 if (totalIter > ITER_LIMIT)
3623 // It is safe to elminate the poll from this loop.
3624 bottom->bbFlags &= ~BBF_NEEDS_GCPOLL;
3629 printf("Removing poll in block BB%02u because it forms a bounded counted loop\n", bottom->bbNum);
3635 // Final chance to optimize the polls. Move all polls in loops from the bottom of the loop up to the
3636 // loop head. Also eliminate all epilog polls in non-leaf methods. This only works if we have dominator
3640 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3642 if (!(block->bbFlags & BBF_NEEDS_GCPOLL))
3647 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
3649 // make sure that this is loop-like
3650 if (!fgReachable(block->bbJumpDest, block))
3652 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3656 printf("Removing poll in block BB%02u because it is not loop\n", block->bbNum);
3662 else if (!(block->bbJumpKind == BBJ_RETURN || block->bbJumpKind == BBJ_SWITCH))
3664 noway_assert(!"GC Poll on a block that has no control transfer.");
3668 printf("Removing poll in block BB%02u because it is not a jump\n", block->bbNum);
3671 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3675 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3676 // Clean those up now.
3678 if (block->bbFlags & BBF_GC_SAFE_POINT)
3683 printf("Removing poll in return block BB%02u because it is GC Safe\n", block->bbNum);
3686 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3690 if (block->bbJumpKind == BBJ_RETURN)
3692 if (!optReachWithoutCall(fgFirstBB, block))
3694 // check to see if there is a call along the path between the first block and the return
3696 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3700 printf("Removing poll in return block BB%02u because it dominated by a call\n", block->bbNum);
3709 noway_assert(!fgGCPollsCreated);
3711 fgGCPollsCreated = true;
3713 // Walk through the blocks and hunt for a block that has BBF_NEEDS_GCPOLL
3714 for (block = fgFirstBB; block; block = block->bbNext)
3716 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3717 // And if !fgDomsComputed, we won't have cleared them, so skip them now
3718 if (!(block->bbFlags & BBF_NEEDS_GCPOLL) || (block->bbFlags & BBF_GC_SAFE_POINT))
3723 // This block needs a poll. We either just insert a callout or we split the block and inline part of
3724 // the test. This depends on the value of opts.compGCPollType.
3726 // If we're doing GCPOLL_CALL, just insert a GT_CALL node before the last node in the block.
3727 CLANG_FORMAT_COMMENT_ANCHOR;
3730 switch (block->bbJumpKind)
3738 noway_assert(!"Unknown block type for BBF_NEEDS_GCPOLL");
3742 noway_assert(opts.compGCPollType);
3744 GCPollType pollType = opts.compGCPollType;
3745 // pollType is set to either CALL or INLINE at this point. Below is the list of places where we
3746 // can't or don't want to emit an inline check. Check all of those. If after all of that we still
3747 // have INLINE, then emit an inline check.
3749 if (opts.MinOpts() || opts.compDbgCode)
3754 printf("Selecting CALL poll in block BB%02u because of debug/minopts\n", block->bbNum);
3758 // Don't split blocks and create inlined polls unless we're optimizing.
3759 pollType = GCPOLL_CALL;
3761 else if (genReturnBB == block)
3766 printf("Selecting CALL poll in block BB%02u because it is the single return block\n", block->bbNum);
3770 // we don't want to split the single return block
3771 pollType = GCPOLL_CALL;
3773 else if (BBJ_SWITCH == block->bbJumpKind)
3778 printf("Selecting CALL poll in block BB%02u because it is a loop formed by a SWITCH\n", block->bbNum);
3782 // I don't want to deal with all the outgoing edges of a switch block.
3783 pollType = GCPOLL_CALL;
3786 // TODO-Cleanup: potentially don't split if we're in an EH region.
3788 createdPollBlocks |= fgCreateGCPoll(pollType, block);
3791 // If we split a block to create a GC Poll, then rerun fgReorderBlocks to push the rarely run blocks out
3792 // past the epilog. We should never split blocks unless we're optimizing.
3793 if (createdPollBlocks)
3795 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
3800 /*****************************************************************************
3802 * Actually create a GCPoll in the given block. Returns true if it created
3806 bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block)
3808 assert(!(block->bbFlags & BBF_GC_SAFE_POINT));
3809 bool createdPollBlocks;
3812 void* pAddrOfCaptureThreadGlobal;
3814 addrTrap = info.compCompHnd->getAddrOfCaptureThreadGlobal(&pAddrOfCaptureThreadGlobal);
3816 #ifdef ENABLE_FAST_GCPOLL_HELPER
3817 // I never want to split blocks if we've got two indirections here.
3818 // This is a size trade-off assuming the VM has ENABLE_FAST_GCPOLL_HELPER.
3819 // So don't do it when that is off
3820 if (pAddrOfCaptureThreadGlobal != NULL)
3822 pollType = GCPOLL_CALL;
3824 #endif // ENABLE_FAST_GCPOLL_HELPER
3826 if (GCPOLL_CALL == pollType)
3828 createdPollBlocks = false;
3829 GenTreePtr tree = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3830 #if GTF_CALL_REG_SAVE
3831 tree->gtCall.gtCallMoreFlags |= GTF_CALL_REG_SAVE;
3832 #endif // GTF_CALL_REG_SAVE
3834 // for BBJ_ALWAYS I don't need to insert it before the condition. Just append it.
3835 if (block->bbJumpKind == BBJ_ALWAYS)
3837 fgInsertStmtAtEnd(block, tree);
3841 GenTreeStmt* newStmt = fgInsertStmtNearEnd(block, tree);
3842 // For DDB156656, we need to associate the GC Poll with the IL offset (and therefore sequence
3843 // point) of the tree before which we inserted the poll. One example of when this is a
3854 // If we take the if statement at 1, we encounter a jump at 2. This jumps over the else
3855 // and lands at 4. 4 is where we inserted the gcpoll. However, that is associated with
3856 // the sequence point a 3. Therefore, the debugger displays the wrong source line at the
3857 // gc poll location.
3859 // More formally, if control flow targets an instruction, that instruction must be the
3860 // start of a new sequence point.
3861 if (newStmt->gtNext)
3863 // Is it possible for gtNext to be NULL?
3864 noway_assert(newStmt->gtNext->gtOper == GT_STMT);
3865 newStmt->gtStmtILoffsx = newStmt->gtNextStmt->gtStmtILoffsx;
3869 block->bbFlags |= BBF_GC_SAFE_POINT;
3873 printf("*** creating GC Poll in block BB%02u\n", block->bbNum);
3874 gtDispTreeList(block->bbTreeList);
3880 createdPollBlocks = true;
3881 // if we're doing GCPOLL_INLINE, then:
3882 // 1) Create two new blocks: Poll and Bottom. The original block is called Top.
3884 // I want to create:
3885 // top -> poll -> bottom (lexically)
3886 // so that we jump over poll to get to bottom.
3887 BasicBlock* top = block;
3888 BasicBlock* poll = fgNewBBafter(BBJ_NONE, top, true);
3889 BasicBlock* bottom = fgNewBBafter(top->bbJumpKind, poll, true);
3890 BBjumpKinds oldJumpKind = top->bbJumpKind;
3892 // Update block flags
3893 unsigned originalFlags;
3894 originalFlags = top->bbFlags | BBF_GC_SAFE_POINT;
3896 // Unlike Fei's inliner from puclr, I'm allowed to split loops.
3897 // And we keep a few other flags...
3898 noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~(BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1))) == 0);
3899 top->bbFlags = originalFlags & (~BBF_SPLIT_LOST | BBF_GC_SAFE_POINT);
3900 bottom->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3901 bottom->inheritWeight(top);
3902 poll->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3904 // 9) Mark Poll as rarely run.
3905 poll->bbSetRunRarely();
3907 // 5) Bottom gets all the outgoing edges and inherited flags of Original.
3908 bottom->bbJumpDest = top->bbJumpDest;
3910 // 2) Add a GC_CALL node to Poll.
3911 GenTreePtr tree = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3912 #if GTF_CALL_REG_SAVE
3913 tree->gtCall.gtCallMoreFlags |= GTF_CALL_REG_SAVE;
3914 #endif // GTF_CALL_REG_SAVE
3915 fgInsertStmtAtEnd(poll, tree);
3917 // 3) Remove the last statement from Top and add it to Bottom.
3918 if (oldJumpKind != BBJ_ALWAYS)
3920 // if I'm always jumping to the target, then this is not a condition that needs moving.
3921 GenTreeStmt* stmt = top->firstStmt();
3922 while (stmt->gtNext)
3924 stmt = stmt->gtNextStmt;
3926 fgRemoveStmt(top, stmt);
3927 fgInsertStmtAtEnd(bottom, stmt);
3930 // for BBJ_ALWAYS blocks, bottom is an empty block.
3932 // 4) Create a GT_EQ node that checks against g_TrapReturningThreads. True jumps to Bottom,
3933 // false falls through to poll. Add this to the end of Top. Top is now BBJ_COND. Bottom is
3934 // now a jump target
3935 CLANG_FORMAT_COMMENT_ANCHOR;
3937 #ifdef ENABLE_FAST_GCPOLL_HELPER
3938 // Prefer the fast gc poll helepr over the double indirection
3939 noway_assert(pAddrOfCaptureThreadGlobal == nullptr);
3943 if (pAddrOfCaptureThreadGlobal != nullptr)
3945 trap = gtNewOperNode(GT_IND, TYP_I_IMPL,
3946 gtNewIconHandleNode((size_t)pAddrOfCaptureThreadGlobal, GTF_ICON_PTR_HDL));
3950 trap = gtNewIconHandleNode((size_t)addrTrap, GTF_ICON_PTR_HDL);
3953 GenTreePtr trapRelop = gtNewOperNode(GT_EQ, TYP_INT,
3954 // lhs [g_TrapReturningThreads]
3955 gtNewOperNode(GT_IND, TYP_INT, trap),
3957 gtNewIconNode(0, TYP_INT));
3958 trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE; // Treat reading g_TrapReturningThreads as volatile.
3959 GenTreePtr trapCheck = gtNewOperNode(GT_JTRUE, TYP_VOID, trapRelop);
3960 fgInsertStmtAtEnd(top, trapCheck);
3961 top->bbJumpDest = bottom;
3962 top->bbJumpKind = BBJ_COND;
3963 bottom->bbFlags |= BBF_JMP_TARGET;
3965 // 7) Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor.
3966 fgAddRefPred(bottom, poll);
3967 fgAddRefPred(bottom, top);
3968 fgAddRefPred(poll, top);
3970 // 8) Replace Top with Bottom in the predecessor list of all outgoing edges from Bottom (1 for
3971 // jumps, 2 for conditional branches, N for switches).
3972 switch (oldJumpKind)
3978 // replace predecessor in the fall through block.
3979 noway_assert(bottom->bbNext);
3980 fgReplacePred(bottom->bbNext, top, bottom);
3982 // fall through for the jump target
3986 fgReplacePred(bottom->bbJumpDest, top, bottom);
3989 NO_WAY("SWITCH should be a call rather than an inlined poll.");
3992 NO_WAY("Unknown block type for updating predecessor lists.");
3995 top->bbFlags &= ~BBF_NEEDS_GCPOLL;
3996 noway_assert(!(poll->bbFlags & BBF_NEEDS_GCPOLL));
3997 noway_assert(!(bottom->bbFlags & BBF_NEEDS_GCPOLL));
3999 if (compCurBB == top)
4007 printf("*** creating inlined GC Poll in top block BB%02u\n", top->bbNum);
4008 gtDispTreeList(top->bbTreeList);
4009 printf(" poll block is BB%02u\n", poll->bbNum);
4010 gtDispTreeList(poll->bbTreeList);
4011 printf(" bottom block is BB%02u\n", bottom->bbNum);
4012 gtDispTreeList(bottom->bbTreeList);
4017 return createdPollBlocks;
4020 /*****************************************************************************
4022 * The following helps find a basic block given its PC offset.
4025 void Compiler::fgInitBBLookup()
4027 BasicBlock** dscBBptr;
4028 BasicBlock* tmpBBdesc;
4030 /* Allocate the basic block table */
4032 dscBBptr = fgBBs = new (this, CMK_BasicBlock) BasicBlock*[fgBBcount];
4034 /* Walk all the basic blocks, filling in the table */
4036 for (tmpBBdesc = fgFirstBB; tmpBBdesc; tmpBBdesc = tmpBBdesc->bbNext)
4038 *dscBBptr++ = tmpBBdesc;
4041 noway_assert(dscBBptr == fgBBs + fgBBcount);
4044 BasicBlock* Compiler::fgLookupBB(unsigned addr)
4049 /* Do a binary search */
4051 for (lo = 0, hi = fgBBcount - 1;;)
4061 unsigned mid = (lo + hi) / 2;
4062 BasicBlock* dsc = fgBBs[mid];
4064 // We introduce internal blocks for BBJ_CALLFINALLY. Skip over these.
4066 while (dsc->bbFlags & BBF_INTERNAL)
4071 // We skipped over too many, Set hi back to the original mid - 1
4075 mid = (lo + hi) / 2;
4081 unsigned pos = dsc->bbCodeOffs;
4085 if ((lo == hi) && (lo == (fgBBcount - 1)))
4087 noway_assert(addr == dsc->bbCodeOffsEnd);
4088 return nullptr; // NULL means the end of method
4103 printf("ERROR: Couldn't find basic block at offset %04X\n", addr);
4105 NO_WAY("fgLookupBB failed.");
4108 /*****************************************************************************
4110 * The 'jump target' array uses the following flags to indicate what kind
4111 * of label is present.
4114 #define JT_NONE 0x00 // This IL offset is never used
4115 #define JT_ADDR 0x01 // merely make sure this is an OK address
4116 #define JT_JUMP 0x02 // 'normal' jump target
4117 #define JT_MULTI 0x04 // target of multiple jumps
4119 inline void Compiler::fgMarkJumpTarget(BYTE* jumpTarget, unsigned offs)
4121 /* Make sure we set JT_MULTI if target of multiple jumps */
4123 noway_assert(JT_MULTI == JT_JUMP << 1);
4125 jumpTarget[offs] |= (jumpTarget[offs] & JT_JUMP) << 1 | JT_JUMP;
4128 //------------------------------------------------------------------------
4129 // FgStack: simple stack model for the inlinee's evaluation stack.
4131 // Model the inputs available to various operations in the inline body.
4132 // Tracks constants, arguments, array lengths.
4137 FgStack() : slot0(SLOT_INVALID), slot1(SLOT_INVALID), depth(0)
4152 Push(SLOT_CONSTANT);
4156 Push(SLOT_ARRAYLEN);
4158 void PushArgument(unsigned arg)
4160 Push(SLOT_ARGUMENT + arg);
4162 unsigned GetSlot0() const
4167 unsigned GetSlot1() const
4172 static bool IsConstant(unsigned value)
4174 return value == SLOT_CONSTANT;
4176 static bool IsArrayLen(unsigned value)
4178 return value == SLOT_ARRAYLEN;
4180 static bool IsArgument(unsigned value)
4182 return value >= SLOT_ARGUMENT;
4184 static unsigned SlotTypeToArgNum(unsigned value)
4186 assert(IsArgument(value));
4187 return value - SLOT_ARGUMENT;
4189 bool IsStackTwoDeep() const
4193 bool IsStackOneDeep() const
4197 bool IsStackAtLeastOneDeep() const
4205 SLOT_INVALID = UINT_MAX,
4234 //------------------------------------------------------------------------
4235 // fgFindJumpTargets: walk the IL stream, determining jump target offsets
4238 // codeAddr - base address of the IL code buffer
4239 // codeSize - number of bytes in the IL code buffer
4240 // jumpTarget - [OUT] byte array for flagging jump targets
4243 // If inlining or prejitting the root, this method also makes
4244 // various observations about the method that factor into inline
4247 // May throw an exception if the IL is malformed.
4249 // jumpTarget[N] is set to a JT_* value if IL offset N is a
4250 // jump target in the method.
4252 // Also sets lvAddrExposed and lvArgWrite in lvaTable[].
4255 #pragma warning(push)
4256 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
4259 void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
4261 const BYTE* codeBegp = codeAddr;
4262 const BYTE* codeEndp = codeAddr + codeSize;
4264 bool seenJump = false;
4265 var_types varType = DUMMY_INIT(TYP_UNDEF); // TYP_ type
4266 typeInfo ti; // Verifier type.
4267 bool typeIsNormed = false;
4268 FgStack pushedStack;
4269 const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
4270 const bool makeInlineObservations = (compInlineResult != nullptr);
4271 const bool isInlining = compIsForInlining();
4273 if (makeInlineObservations)
4275 // Observe force inline state and code size.
4276 compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
4277 compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
4281 // If inlining, this method should still be a candidate.
4284 assert(compInlineResult->IsCandidate());
4289 // note that we're starting to look at the opcodes.
4290 compInlineResult->Note(InlineObservation::CALLEE_BEGIN_OPCODE_SCAN);
4293 while (codeAddr < codeEndp)
4295 OPCODE opcode = (OPCODE)getU1LittleEndian(codeAddr);
4296 codeAddr += sizeof(__int8);
4298 typeIsNormed = false;
4302 if (opcode >= CEE_COUNT)
4304 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4307 if ((opcode >= CEE_LDARG_0 && opcode <= CEE_STLOC_S) || (opcode >= CEE_LDARG && opcode <= CEE_STLOC))
4312 if (makeInlineObservations && (opcode >= CEE_LDNULL) && (opcode <= CEE_LDC_R8))
4314 pushedStack.PushConstant();
4317 unsigned sz = opcodeSizes[opcode];
4323 if (codeAddr >= codeEndp)
4327 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
4328 codeAddr += sizeof(__int8);
4340 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4346 // There has to be code after the call, otherwise the inlinee is unverifiable.
4350 noway_assert(codeAddr < codeEndp - sz);
4353 // If the method has a call followed by a ret, assume that
4354 // it is a wrapper method.
4355 if (makeInlineObservations)
4357 if ((OPCODE)getU1LittleEndian(codeAddr + sz) == CEE_RET)
4359 compInlineResult->Note(InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER);
4396 if (codeAddr > codeEndp - sz)
4401 // Compute jump target address
4402 signed jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
4404 if (compIsForInlining() && jmpDist == 0 &&
4405 (opcode == CEE_LEAVE || opcode == CEE_LEAVE_S || opcode == CEE_BR || opcode == CEE_BR_S))
4410 unsigned jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
4412 // Make sure target is reasonable
4413 if (jmpAddr >= codeSize)
4415 BADCODE3("code jumps to outer space", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4418 // Mark the jump target
4419 fgMarkJumpTarget(jumpTarget, jmpAddr);
4421 // See if jump might be sensitive to inlining
4422 if (makeInlineObservations && (opcode != CEE_BR_S) && (opcode != CEE_BR))
4424 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4433 if (makeInlineObservations)
4435 compInlineResult->Note(InlineObservation::CALLEE_HAS_SWITCH);
4437 // Fail fast, if we're inlining and can't handle this.
4438 if (isInlining && compInlineResult->IsFailure())
4444 // Make sure we don't go past the end reading the number of cases
4445 if (codeAddr > codeEndp - sizeof(DWORD))
4450 // Read the number of cases
4451 unsigned jmpCnt = getU4LittleEndian(codeAddr);
4452 codeAddr += sizeof(DWORD);
4454 if (jmpCnt > codeSize / sizeof(DWORD))
4459 // Find the end of the switch table
4460 unsigned jmpBase = (unsigned)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
4462 // Make sure there is more code after the switch
4463 if (jmpBase >= codeSize)
4468 // jmpBase is also the target of the default case, so mark it
4469 fgMarkJumpTarget(jumpTarget, jmpBase);
4471 // Process table entries
4474 unsigned jmpAddr = jmpBase + getI4LittleEndian(codeAddr);
4477 if (jmpAddr >= codeSize)
4479 BADCODE3("jump target out of range", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4482 fgMarkJumpTarget(jumpTarget, jmpAddr);
4486 // We've advanced past all the bytes in this instruction
4492 case CEE_CONSTRAINED:
4497 if (codeAddr >= codeEndp)
4507 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4509 if (codeAddr > codeEndp - sz)
4514 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4515 varNum = compMapILargNum(varNum); // account for possible hidden param
4517 // This check is only intended to prevent an AV. Bad varNum values will later
4518 // be handled properly by the verifier.
4519 if (varNum < lvaTableCnt)
4523 impInlineInfo->inlArgInfo[varNum].argHasStargOp = true;
4527 // In non-inline cases, note written-to locals.
4528 lvaTable[varNum].lvArgWrite = 1;
4539 // Handle address-taken args or locals
4540 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4542 if (codeAddr > codeEndp - sz)
4547 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4551 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4553 varType = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclTypeInfo;
4554 ti = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclVerTypeInfo;
4556 impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclHasLdlocaOp = true;
4560 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4562 varType = impInlineInfo->lclVarInfo[varNum].lclTypeInfo;
4563 ti = impInlineInfo->lclVarInfo[varNum].lclVerTypeInfo;
4565 impInlineInfo->inlArgInfo[varNum].argHasLdargaOp = true;
4567 pushedStack.PushArgument(varNum);
4572 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4574 if (varNum >= info.compMethodInfo->locals.numArgs)
4576 BADCODE("bad local number");
4579 varNum += info.compArgsCount;
4583 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4585 if (varNum >= info.compILargsCount)
4587 BADCODE("bad argument number");
4590 varNum = compMapILargNum(varNum); // account for possible hidden param
4593 varType = (var_types)lvaTable[varNum].lvType;
4594 ti = lvaTable[varNum].lvVerTypeInfo;
4596 // Determine if the next instruction will consume
4597 // the address. If so we won't mark this var as
4600 // We will put structs on the stack and changing
4601 // the addrTaken of a local requires an extra pass
4602 // in the morpher so we won't apply this
4603 // optimization to structs.
4605 // Debug code spills for every IL instruction, and
4606 // therefore it will split statements, so we will
4607 // need the address. Note that this optimization
4608 // is based in that we know what trees we will
4609 // generate for this ldfld, and we require that we
4610 // won't need the address of this local at all
4611 noway_assert(varNum < lvaTableCnt);
4613 const bool notStruct = !varTypeIsStruct(&lvaTable[varNum]);
4614 const bool notLastInstr = (codeAddr < codeEndp - sz);
4615 const bool notDebugCode = !opts.compDbgCode;
4617 if (notStruct && notLastInstr && notDebugCode &&
4618 impILConsumesAddr(codeAddr + sz, impTokenLookupContextHandle, info.compScopeHnd))
4620 // We can skip the addrtaken, as next IL instruction consumes
4625 lvaTable[varNum].lvHasLdAddrOp = 1;
4626 if (!info.compIsStatic && (varNum == 0))
4628 // Addr taken on "this" pointer is significant,
4629 // go ahead to mark it as permanently addr-exposed here.
4630 lvaSetVarAddrExposed(0);
4631 // This may be conservative, but probably not very.
4636 typeIsNormed = ti.IsValueClass() && !varTypeIsStruct(varType);
4642 #if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
4645 // We transform this into a set of ldarg's + tail call and
4646 // thus may push more onto the stack than originally thought.
4647 // This doesn't interfere with verification because CEE_JMP
4648 // is never verifiable, and there's nothing unsafe you can
4649 // do with a an IL stack overflow if the JIT is expecting it.
4650 info.compMaxStack = max(info.compMaxStack, info.compILargsCount);
4653 #endif // !_TARGET_X86_ && !_TARGET_ARM_
4655 // If we are inlining, we need to fail for a CEE_JMP opcode, just like
4656 // the list of other opcodes (for all platforms).
4664 // CEE_CALLI should not be inlined because the JIT cannot generate an inlined call frame. If the call
4666 // is a no-marshal CALLI P/Invoke we end up calling the IL stub. We don't NGEN these stubs, so we'll
4668 // JIT an IL stub for a trivial func. It's almost certainly a better choice to leave out the inline
4669 // candidate so we can generate an inlined call frame. It might be nice to call getCallInfo to figure
4671 // what kind of call we have here.
4673 // Consider making this only for not force inline.
4674 if (makeInlineObservations)
4676 // Arguably this should be NoteFatal, but the legacy behavior is
4677 // to ignore this for the prejit root.
4678 compInlineResult->Note(InlineObservation::CALLEE_UNSUPPORTED_OPCODE);
4680 // Fail fast if we're inlining...
4683 assert(compInlineResult->IsFailure());
4693 if (makeInlineObservations)
4695 pushedStack.PushArgument(opcode - CEE_LDARG_0);
4702 if (codeAddr > codeEndp - sz)
4707 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4709 if (makeInlineObservations)
4711 pushedStack.PushArgument(varNum);
4717 if (makeInlineObservations)
4719 pushedStack.PushArrayLen();
4728 if (makeInlineObservations)
4730 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4738 // Skip any remaining operands this opcode may have
4741 // Note the opcode we just saw
4742 if (makeInlineObservations)
4744 InlineObservation obs =
4745 typeIsNormed ? InlineObservation::CALLEE_OPCODE_NORMED : InlineObservation::CALLEE_OPCODE;
4746 compInlineResult->NoteInt(obs, opcode);
4750 if (codeAddr != codeEndp)
4753 BADCODE3("Code ends in the middle of an opcode, or there is a branch past the end of the method",
4754 " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4757 if (makeInlineObservations)
4759 compInlineResult->Note(InlineObservation::CALLEE_END_OPCODE_SCAN);
4761 // If the inline is viable and discretionary, do the
4762 // profitability screening.
4763 if (compInlineResult->IsDiscretionaryCandidate())
4765 // Make some callsite specific observations that will feed
4766 // into the profitability model.
4767 impMakeDiscretionaryInlineObservations(impInlineInfo, compInlineResult);
4769 // None of those observations should have changed the
4770 // inline's viability.
4771 assert(compInlineResult->IsCandidate());
4775 // Assess profitability...
4776 CORINFO_METHOD_INFO* methodInfo = &impInlineInfo->inlineCandidateInfo->methInfo;
4777 compInlineResult->DetermineProfitability(methodInfo);
4779 if (compInlineResult->IsFailure())
4781 impInlineRoot()->m_inlineStrategy->NoteUnprofitable();
4782 JITDUMP("\n\nInline expansion aborted, inline not profitable\n");
4787 // The inline is still viable.
4788 assert(compInlineResult->IsCandidate());
4793 // Prejit root case. Profitability assessment for this
4794 // is done over in compCompileHelper.
4799 // None of the local vars in the inlinee should have address taken or been written to.
4800 // Therefore we should NOT need to enter this "if" statement.
4801 if (!isInlining && !info.compIsStatic)
4803 fgAdjustForAddressExposedOrWrittenThis();
4808 #pragma warning(pop)
4811 //------------------------------------------------------------------------
4812 // fgAdjustForAddressExposedOrWrittenThis: update var table for cases
4813 // where the this pointer value can change.
4816 // Modifies lvaArg0Var to refer to a temp if the value of 'this' can
4817 // change. The original this (info.compThisArg) then remains
4818 // unmodified in the method. fgAddInternal is reponsible for
4819 // adding the code to copy the initial this into the temp.
4821 void Compiler::fgAdjustForAddressExposedOrWrittenThis()
4823 // Optionally enable adjustment during stress.
4824 if (!tiVerificationNeeded && compStressCompile(STRESS_GENERIC_VARN, 15))
4826 lvaTable[info.compThisArg].lvArgWrite = true;
4829 // If this is exposed or written to, create a temp for the modifiable this
4830 if (lvaTable[info.compThisArg].lvAddrExposed || lvaTable[info.compThisArg].lvArgWrite)
4832 // If there is a "ldarga 0" or "starg 0", grab and use the temp.
4833 lvaArg0Var = lvaGrabTemp(false DEBUGARG("Address-exposed, or written this pointer"));
4834 noway_assert(lvaArg0Var > (unsigned)info.compThisArg);
4835 lvaTable[lvaArg0Var].lvType = lvaTable[info.compThisArg].TypeGet();
4836 lvaTable[lvaArg0Var].lvAddrExposed = lvaTable[info.compThisArg].lvAddrExposed;
4837 lvaTable[lvaArg0Var].lvDoNotEnregister = lvaTable[info.compThisArg].lvDoNotEnregister;
4839 lvaTable[lvaArg0Var].lvVMNeedsStackAddr = lvaTable[info.compThisArg].lvVMNeedsStackAddr;
4840 lvaTable[lvaArg0Var].lvLiveInOutOfHndlr = lvaTable[info.compThisArg].lvLiveInOutOfHndlr;
4841 lvaTable[lvaArg0Var].lvLclFieldExpr = lvaTable[info.compThisArg].lvLclFieldExpr;
4842 lvaTable[lvaArg0Var].lvLiveAcrossUCall = lvaTable[info.compThisArg].lvLiveAcrossUCall;
4844 lvaTable[lvaArg0Var].lvArgWrite = lvaTable[info.compThisArg].lvArgWrite;
4845 lvaTable[lvaArg0Var].lvVerTypeInfo = lvaTable[info.compThisArg].lvVerTypeInfo;
4847 // Clear the TI_FLAG_THIS_PTR in the original 'this' pointer.
4848 noway_assert(lvaTable[lvaArg0Var].lvVerTypeInfo.IsThisPtr());
4849 lvaTable[info.compThisArg].lvVerTypeInfo.ClearThisPtr();
4850 lvaTable[info.compThisArg].lvAddrExposed = false;
4851 lvaTable[info.compThisArg].lvArgWrite = false;
4855 //------------------------------------------------------------------------
4856 // fgObserveInlineConstants: look for operations that might get optimized
4857 // if this method were to be inlined, and report these to the inliner.
4860 // opcode -- MSIL opcode under consideration
4861 // stack -- abstract stack model at this point in the IL
4862 // isInlining -- true if we're inlining (vs compiling a prejit root)
4865 // Currently only invoked on compare and branch opcodes.
4867 // If we're inlining we also look at the argument values supplied by
4868 // the caller at this call site.
4870 // The crude stack model may overestimate stack depth.
4872 void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining)
4874 // We should be able to record inline observations.
4875 assert(compInlineResult != nullptr);
4877 // The stack only has to be 1 deep for BRTRUE/FALSE
4878 bool lookForBranchCases = stack.IsStackAtLeastOneDeep();
4880 if (compInlineResult->UsesLegacyPolicy())
4882 // LegacyPolicy misses cases where the stack is really one
4883 // deep but the model says it's two deep. We need to do
4884 // likewise to preseve old behavior.
4885 lookForBranchCases &= !stack.IsStackTwoDeep();
4888 if (lookForBranchCases)
4890 if (opcode == CEE_BRFALSE || opcode == CEE_BRFALSE_S || opcode == CEE_BRTRUE || opcode == CEE_BRTRUE_S)
4892 unsigned slot0 = stack.GetSlot0();
4893 if (FgStack::IsArgument(slot0))
4895 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
4899 // Check for the double whammy of an incoming constant argument
4900 // feeding a constant test.
4901 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
4902 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
4904 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
4913 // Remaining cases require at least two things on the stack.
4914 if (!stack.IsStackTwoDeep())
4919 unsigned slot0 = stack.GetSlot0();
4920 unsigned slot1 = stack.GetSlot1();
4922 // Arg feeds constant test
4923 if ((FgStack::IsConstant(slot0) && FgStack::IsArgument(slot1)) ||
4924 (FgStack::IsConstant(slot1) && FgStack::IsArgument(slot0)))
4926 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
4929 // Arg feeds range check
4930 if ((FgStack::IsArrayLen(slot0) && FgStack::IsArgument(slot1)) ||
4931 (FgStack::IsArrayLen(slot1) && FgStack::IsArgument(slot0)))
4933 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK);
4936 // Check for an incoming arg that's a constant
4939 if (FgStack::IsArgument(slot0))
4941 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
4942 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
4944 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
4948 if (FgStack::IsArgument(slot1))
4950 unsigned varNum = FgStack::SlotTypeToArgNum(slot1);
4951 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
4953 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
4959 /*****************************************************************************
4961 * Finally link up the bbJumpDest of the blocks together
4964 void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock)
4966 noway_assert(startBlock->bbNum <= endBlock->bbNum);
4968 for (BasicBlock* block = startBlock; block != endBlock->bbNext; block = block->bbNext)
4970 if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0)
4972 block->bbFlags |= BBF_BACKWARD_JUMP;
4977 /*****************************************************************************
4979 * Finally link up the bbJumpDest of the blocks together
4982 void Compiler::fgLinkBasicBlocks()
4984 /* Create the basic block lookup tables */
4988 /* First block is always reachable */
4990 fgFirstBB->bbRefs = 1;
4992 /* Walk all the basic blocks, filling in the target addresses */
4994 for (BasicBlock* curBBdesc = fgFirstBB; curBBdesc; curBBdesc = curBBdesc->bbNext)
4996 switch (curBBdesc->bbJumpKind)
5001 curBBdesc->bbJumpDest = fgLookupBB(curBBdesc->bbJumpOffs);
5002 curBBdesc->bbJumpDest->bbRefs++;
5003 if (curBBdesc->bbJumpDest->bbNum <= curBBdesc->bbNum)
5005 fgMarkBackwardJump(curBBdesc->bbJumpDest, curBBdesc);
5008 /* Is the next block reachable? */
5010 if (curBBdesc->bbJumpKind == BBJ_ALWAYS || curBBdesc->bbJumpKind == BBJ_LEAVE)
5015 if (!curBBdesc->bbNext)
5017 BADCODE("Fall thru the end of a method");
5020 // Fall through, the next block is also reachable
5023 curBBdesc->bbNext->bbRefs++;
5026 case BBJ_EHFINALLYRET:
5027 case BBJ_EHFILTERRET:
5035 jumpCnt = curBBdesc->bbJumpSwt->bbsCount;
5036 BasicBlock** jumpPtr;
5037 jumpPtr = curBBdesc->bbJumpSwt->bbsDstTab;
5041 *jumpPtr = fgLookupBB((unsigned)*(size_t*)jumpPtr);
5042 (*jumpPtr)->bbRefs++;
5043 if ((*jumpPtr)->bbNum <= curBBdesc->bbNum)
5045 fgMarkBackwardJump(*jumpPtr, curBBdesc);
5047 } while (++jumpPtr, --jumpCnt);
5049 /* Default case of CEE_SWITCH (next block), is at end of jumpTab[] */
5051 noway_assert(*(jumpPtr - 1) == curBBdesc->bbNext);
5054 case BBJ_CALLFINALLY: // BBJ_CALLFINALLY and BBJ_EHCATCHRET don't appear until later
5055 case BBJ_EHCATCHRET:
5057 noway_assert(!"Unexpected bbJumpKind");
5063 /*****************************************************************************
5065 * Walk the instrs to create the basic blocks.
5068 void Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
5070 const BYTE* codeBegp = codeAddr;
5071 const BYTE* codeEndp = codeAddr + codeSize;
5072 bool tailCall = false;
5074 BasicBlock* curBBdesc;
5076 /* Clear the beginning offset for the first BB */
5080 #ifdef DEBUGGING_SUPPORT
5081 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5083 compResetScopeLists();
5085 // Ignore scopes beginning at offset 0
5086 while (compGetNextEnterScope(0))
5089 while (compGetNextExitScope(0))
5095 BBjumpKinds jmpKind;
5101 unsigned jmpAddr = DUMMY_INIT(BAD_IL_OFFSET);
5102 unsigned bbFlags = 0;
5103 BBswtDesc* swtDsc = nullptr;
5106 opcode = (OPCODE)getU1LittleEndian(codeAddr);
5107 codeAddr += sizeof(__int8);
5112 /* Get the size of additional parameters */
5114 noway_assert(opcode < CEE_COUNT);
5116 sz = opcodeSizes[opcode];
5123 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5125 BADCODE3("jump target between prefix 0xFE and opcode", " at offset %04X",
5126 (IL_OFFSET)(codeAddr - codeBegp));
5129 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
5130 codeAddr += sizeof(__int8);
5133 /* Check to see if we have a jump/return opcode */
5167 // We need to check if we are jumping out of a finally-protected try.
5168 jmpKind = BBJ_LEAVE;
5173 jmpKind = BBJ_ALWAYS;
5178 /* Compute the target address of the jump */
5180 jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
5182 if (compIsForInlining() && jmpDist == 0 && (opcode == CEE_BR || opcode == CEE_BR_S))
5187 jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
5193 unsigned jmpCnt; // # of switch cases (excluding defualt)
5195 BasicBlock** jmpTab;
5196 BasicBlock** jmpPtr;
5198 /* Allocate the switch descriptor */
5200 swtDsc = new (this, CMK_BasicBlock) BBswtDesc;
5202 /* Read the number of entries in the table */
5204 jmpCnt = getU4LittleEndian(codeAddr);
5207 /* Compute the base offset for the opcode */
5209 jmpBase = (IL_OFFSET)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
5211 /* Allocate the jump table */
5213 jmpPtr = jmpTab = new (this, CMK_BasicBlock) BasicBlock*[jmpCnt + 1];
5215 /* Fill in the jump table */
5217 for (unsigned count = jmpCnt; count; count--)
5219 jmpDist = getI4LittleEndian(codeAddr);
5222 // store the offset in the pointer. We change these in fgLinkBasicBlocks().
5223 *jmpPtr++ = (BasicBlock*)(size_t)(jmpBase + jmpDist);
5226 /* Append the default label to the target table */
5228 *jmpPtr++ = (BasicBlock*)(size_t)jmpBase;
5230 /* Make sure we found the right number of labels */
5232 noway_assert(jmpPtr == jmpTab + jmpCnt + 1);
5234 /* Compute the size of the switch opcode operands */
5236 sz = sizeof(DWORD) + jmpCnt * sizeof(DWORD);
5238 /* Fill in the remaining fields of the switch descriptor */
5240 swtDsc->bbsCount = jmpCnt + 1;
5241 swtDsc->bbsDstTab = jmpTab;
5243 /* This is definitely a jump */
5245 jmpKind = BBJ_SWITCH;
5248 #ifndef LEGACY_BACKEND
5249 if (opts.compProcedureSplitting)
5251 // TODO-CQ: We might need to create a switch table; we won't know for sure until much later.
5252 // However, switch tables don't work with hot/cold splitting, currently. The switch table data needs
5253 // a relocation such that if the base (the first block after the prolog) and target of the switch
5254 // branch are put in different sections, the difference stored in the table is updated. However, our
5255 // relocation implementation doesn't support three different pointers (relocation address, base, and
5256 // target). So, we need to change our switch table implementation to be more like
5257 // JIT64: put the table in the code section, in the same hot/cold section as the switch jump itself
5258 // (maybe immediately after the switch jump), and make the "base" address be also in that section,
5259 // probably the address after the switch jump.
5260 opts.compProcedureSplitting = false;
5261 JITDUMP("Turning off procedure splitting for this method, as it might need switch tables; "
5262 "implementation limitation.\n");
5264 #endif // !LEGACY_BACKEND
5269 bbFlags |= BBF_DONT_REMOVE;
5270 jmpKind = BBJ_EHFILTERRET;
5273 case CEE_ENDFINALLY:
5274 jmpKind = BBJ_EHFINALLYRET;
5278 if (compIsForInlining())
5280 // TODO-CQ: We can inline some callees with explicit tail calls if we can guarantee that the calls
5281 // can be dispatched as tail calls from the caller.
5282 compInlineResult->NoteFatal(InlineObservation::CALLEE_EXPLICIT_TAIL_PREFIX);
5289 case CEE_CONSTRAINED:
5292 // fgFindJumpTargets should have ruled out this possibility
5293 // (i.e. a prefix opcodes as last intruction in a block)
5294 noway_assert(codeAddr < codeEndp);
5296 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5298 BADCODE3("jump target between prefix and an opcode", " at offset %04X",
5299 (IL_OFFSET)(codeAddr - codeBegp));
5307 if (compIsForInlining() || // Ignore tail call in the inlinee. Period.
5308 (!tailCall && !compTailCallStress()) // A new BB with BBJ_RETURN would have been created
5310 // after a tailcall statement.
5311 // We need to keep this invariant if we want to stress the tailcall.
5312 // That way, the potential (tail)call statement is always the last
5313 // statement in the block.
5314 // Otherwise, we will assert at the following line in fgMorphCall()
5315 // noway_assert(fgMorphStmt->gtNext == NULL);
5318 // Neither .tailcall prefix, no tailcall stress. So move on.
5322 // Make sure the code sequence is legal for the tail call.
5323 // If so, mark this BB as having a BBJ_RETURN.
5325 if (codeAddr >= codeEndp - sz)
5327 BADCODE3("No code found after the call instruction", " at offset %04X",
5328 (IL_OFFSET)(codeAddr - codeBegp));
5333 bool isCallPopAndRet = false;
5335 // impIsTailCallILPattern uses isRecursive flag to determine whether ret in a fallthrough block is
5336 // allowed. We don't know at this point whether the call is recursive so we conservatively pass
5337 // false. This will only affect explicit tail calls when IL verification is not needed for the
5339 bool isRecursive = false;
5340 if (!impIsTailCallILPattern(tailCall, opcode, codeAddr + sz, codeEndp, isRecursive,
5343 #ifdef _TARGET_AMD64_
5344 BADCODE3("tail call not followed by ret or pop+ret", " at offset %04X",
5345 (IL_OFFSET)(codeAddr - codeBegp));
5347 BADCODE3("tail call not followed by ret", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5348 #endif //_TARGET_AMD64_
5351 #ifdef _TARGET_AMD64_
5352 if (isCallPopAndRet)
5354 // By breaking here, we let pop and ret opcodes to be
5355 // imported after tail call. If tail prefix is honored,
5356 // stmts corresponding to pop and ret will be removed
5357 // in fgMorphCall().
5360 #endif //_TARGET_AMD64_
5364 OPCODE nextOpcode = (OPCODE)getU1LittleEndian(codeAddr + sz);
5366 if (nextOpcode != CEE_RET)
5368 noway_assert(compTailCallStress());
5369 // Next OPCODE is not a CEE_RET, bail the attempt to stress the tailcall.
5370 // (I.e. We will not make a new BB after the "call" statement.)
5376 /* For tail call, we just call CORINFO_HELP_TAILCALL, and it jumps to the
5377 target. So we don't need an epilog - just like CORINFO_HELP_THROW.
5378 Make the block BBJ_RETURN, but we will change it to BBJ_THROW
5379 if the tailness of the call is satisfied.
5380 NOTE : The next instruction is guaranteed to be a CEE_RET
5381 and it will create another BasicBlock. But there may be an
5382 jump directly to that CEE_RET. If we want to avoid creating
5383 an unnecessary block, we need to check if the CEE_RETURN is
5384 the target of a jump.
5390 /* These are equivalent to a return from the current method
5391 But instead of directly returning to the caller we jump and
5392 execute something else in between */
5394 jmpKind = BBJ_RETURN;
5399 jmpKind = BBJ_THROW;
5403 // make certain we did not forget any flow of control instructions
5404 // by checking the 'ctrl' field in opcode.def. First filter out all
5405 // non-ctrl instructions
5406 #define BREAK(name) \
5409 #define NEXT(name) \
5414 #undef RETURN // undef contract RETURN macro
5415 #define RETURN(name)
5417 #define BRANCH(name)
5418 #define COND_BRANCH(name)
5421 #define OPDEF(name, string, pop, push, oprType, opcType, l, s1, s2, ctrl) ctrl(name)
5422 #include "opcode.def"
5435 // These ctrl-flow opcodes don't need any special handling
5436 case CEE_NEWOBJ: // CTRL_CALL
5439 // what's left are forgotten instructions
5441 BADCODE("Unrecognized control Opcode");
5449 /* Jump over the operand */
5455 tailCall = (opcode == CEE_TAILCALL);
5457 /* Make sure a jump target isn't in the middle of our opcode */
5461 IL_OFFSET offs = (IL_OFFSET)(codeAddr - codeBegp) - sz; // offset of the operand
5463 for (unsigned i = 0; i < sz; i++, offs++)
5465 if (jumpTarget[offs] != JT_NONE)
5467 BADCODE3("jump into the middle of an opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5472 /* Compute the offset of the next opcode */
5474 nxtBBoffs = (IL_OFFSET)(codeAddr - codeBegp);
5476 #ifdef DEBUGGING_SUPPORT
5478 bool foundScope = false;
5480 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5482 while (compGetNextEnterScope(nxtBBoffs))
5486 while (compGetNextExitScope(nxtBBoffs))
5493 /* Do we have a jump? */
5495 if (jmpKind == BBJ_NONE)
5497 /* No jump; make sure we don't fall off the end of the function */
5499 if (codeAddr == codeEndp)
5501 BADCODE3("missing return opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5504 /* If a label follows this opcode, we'll have to make a new BB */
5506 bool makeBlock = (jumpTarget[nxtBBoffs] != JT_NONE);
5508 #ifdef DEBUGGING_SUPPORT
5509 if (!makeBlock && foundScope)
5515 printf("Splitting at BBoffs = %04u\n", nxtBBoffs);
5519 #endif // DEBUGGING_SUPPORT
5527 /* We need to create a new basic block */
5529 curBBdesc = fgNewBasicBlock(jmpKind);
5531 curBBdesc->bbFlags |= bbFlags;
5532 curBBdesc->bbRefs = 0;
5534 curBBdesc->bbCodeOffs = curBBoffs;
5535 curBBdesc->bbCodeOffsEnd = nxtBBoffs;
5537 unsigned profileWeight;
5538 if (fgGetProfileWeightForBasicBlock(curBBoffs, &profileWeight))
5540 curBBdesc->setBBProfileWeight(profileWeight);
5541 if (profileWeight == 0)
5543 curBBdesc->bbSetRunRarely();
5547 // Note that bbNewBasicBlock (called from fgNewBasicBlock) may have
5548 // already marked the block as rarely run. In that case (and when we know
5549 // that the block profile weight is non-zero) we want to unmark that.
5551 curBBdesc->bbFlags &= ~BBF_RUN_RARELY;
5558 curBBdesc->bbJumpSwt = swtDsc;
5564 noway_assert(jmpAddr != DUMMY_INIT(BAD_IL_OFFSET));
5565 curBBdesc->bbJumpOffs = jmpAddr;
5572 DBEXEC(verbose, curBBdesc->dspBlockHeader(this, false, false, false));
5574 /* Remember where the next BB will start */
5576 curBBoffs = nxtBBoffs;
5577 } while (codeAddr < codeEndp);
5579 noway_assert(codeAddr == codeEndp);
5581 /* Finally link up the bbJumpDest of the blocks together */
5583 fgLinkBasicBlocks();
5586 /*****************************************************************************
5588 * Main entry point to discover the basic blocks for the current function.
5591 void Compiler::fgFindBasicBlocks()
5596 printf("*************** In fgFindBasicBlocks() for %s\n", info.compFullName);
5600 /* Allocate the 'jump target' vector
5602 * We need one extra byte as we mark
5603 * jumpTarget[info.compILCodeSize] with JT_ADDR
5604 * when we need to add a dummy block
5605 * to record the end of a try or handler region.
5607 BYTE* jumpTarget = new (this, CMK_Unknown) BYTE[info.compILCodeSize + 1];
5608 memset(jumpTarget, JT_NONE, info.compILCodeSize + 1);
5609 noway_assert(JT_NONE == 0);
5611 /* Walk the instrs to find all jump targets */
5613 fgFindJumpTargets(info.compCode, info.compILCodeSize, jumpTarget);
5614 if (compDonotInline())
5621 /* Are there any exception handlers? */
5623 if (info.compXcptnsCount > 0)
5625 noway_assert(!compIsForInlining());
5627 /* Check and mark all the exception handlers */
5629 for (XTnum = 0; XTnum < info.compXcptnsCount; XTnum++)
5632 CORINFO_EH_CLAUSE clause;
5633 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5634 noway_assert(clause.HandlerLength != (unsigned)-1);
5636 if (clause.TryLength <= 0)
5638 BADCODE("try block length <=0");
5641 /* Mark the 'try' block extent and the handler itself */
5643 if (clause.TryOffset > info.compILCodeSize)
5645 BADCODE("try offset is > codesize");
5647 if (jumpTarget[clause.TryOffset] == JT_NONE)
5649 jumpTarget[clause.TryOffset] = JT_ADDR;
5652 tmpOffset = clause.TryOffset + clause.TryLength;
5653 if (tmpOffset > info.compILCodeSize)
5655 BADCODE("try end is > codesize");
5657 if (jumpTarget[tmpOffset] == JT_NONE)
5659 jumpTarget[tmpOffset] = JT_ADDR;
5662 if (clause.HandlerOffset > info.compILCodeSize)
5664 BADCODE("handler offset > codesize");
5666 if (jumpTarget[clause.HandlerOffset] == JT_NONE)
5668 jumpTarget[clause.HandlerOffset] = JT_ADDR;
5671 tmpOffset = clause.HandlerOffset + clause.HandlerLength;
5672 if (tmpOffset > info.compILCodeSize)
5674 BADCODE("handler end > codesize");
5676 if (jumpTarget[tmpOffset] == JT_NONE)
5678 jumpTarget[tmpOffset] = JT_ADDR;
5681 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5683 if (clause.FilterOffset > info.compILCodeSize)
5685 BADCODE("filter offset > codesize");
5687 if (jumpTarget[clause.FilterOffset] == JT_NONE)
5689 jumpTarget[clause.FilterOffset] = JT_ADDR;
5698 bool anyJumpTargets = false;
5699 printf("Jump targets:\n");
5700 for (unsigned i = 0; i < info.compILCodeSize + 1; i++)
5702 if (jumpTarget[i] == JT_NONE)
5707 anyJumpTargets = true;
5708 printf(" IL_%04x", i);
5710 if (jumpTarget[i] & JT_ADDR)
5714 if (jumpTarget[i] & JT_MULTI)
5720 if (!anyJumpTargets)
5727 /* Now create the basic blocks */
5729 fgMakeBasicBlocks(info.compCode, info.compILCodeSize, jumpTarget);
5731 if (compIsForInlining())
5733 if (compInlineResult->IsFailure())
5738 bool hasReturnBlocks = false;
5739 bool hasMoreThanOneReturnBlock = false;
5741 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
5743 if (block->bbJumpKind == BBJ_RETURN)
5745 if (hasReturnBlocks)
5747 hasMoreThanOneReturnBlock = true;
5751 hasReturnBlocks = true;
5755 if (!hasReturnBlocks && !compInlineResult->UsesLegacyPolicy())
5758 // Mark the call node as "no return". The inliner might ignore CALLEE_DOES_NOT_RETURN and
5759 // fail inline for a different reasons. In that case we still want to make the "no return"
5760 // information available to the caller as it can impact caller's code quality.
5763 impInlineInfo->iciCall->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
5766 compInlineResult->NoteBool(InlineObservation::CALLEE_DOES_NOT_RETURN, !hasReturnBlocks);
5768 if (compInlineResult->IsFailure())
5773 noway_assert(info.compXcptnsCount == 0);
5774 compHndBBtab = impInlineInfo->InlinerCompiler->compHndBBtab;
5775 compHndBBtabAllocCount =
5776 impInlineInfo->InlinerCompiler->compHndBBtabAllocCount; // we probably only use the table, not add to it.
5777 compHndBBtabCount = impInlineInfo->InlinerCompiler->compHndBBtabCount;
5778 info.compXcptnsCount = impInlineInfo->InlinerCompiler->info.compXcptnsCount;
5780 if (info.compRetNativeType != TYP_VOID && hasMoreThanOneReturnBlock)
5782 // The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp.
5783 lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline candidate multiple BBJ_RETURN spill temp"));
5784 lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetNativeType;
5789 /* Mark all blocks within 'try' blocks as such */
5791 if (info.compXcptnsCount == 0)
5796 if (info.compXcptnsCount > MAX_XCPTN_INDEX)
5798 IMPL_LIMITATION("too many exception clauses");
5801 /* Allocate the exception handler table */
5805 /* Assume we don't need to sort the EH table (such that nested try/catch
5806 * appear before their try or handler parent). The EH verifier will notice
5807 * when we do need to sort it.
5810 fgNeedToSortEHTable = false;
5812 verInitEHTree(info.compXcptnsCount);
5813 EHNodeDsc* initRoot = ehnNext; // remember the original root since
5814 // it may get modified during insertion
5816 // Annotate BBs with exception handling information required for generating correct eh code
5817 // as well as checking for correct IL
5821 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
5823 CORINFO_EH_CLAUSE clause;
5824 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5825 noway_assert(clause.HandlerLength != (unsigned)-1); // @DEPRECATED
5830 dispIncomingEHClause(XTnum, clause);
5834 IL_OFFSET tryBegOff = clause.TryOffset;
5835 IL_OFFSET tryEndOff = tryBegOff + clause.TryLength;
5836 IL_OFFSET filterBegOff = 0;
5837 IL_OFFSET hndBegOff = clause.HandlerOffset;
5838 IL_OFFSET hndEndOff = hndBegOff + clause.HandlerLength;
5840 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5842 filterBegOff = clause.FilterOffset;
5845 if (tryEndOff > info.compILCodeSize)
5847 BADCODE3("end of try block beyond end of method for try", " at offset %04X", tryBegOff);
5849 if (hndEndOff > info.compILCodeSize)
5851 BADCODE3("end of hnd block beyond end of method for try", " at offset %04X", tryBegOff);
5854 HBtab->ebdTryBegOffset = tryBegOff;
5855 HBtab->ebdTryEndOffset = tryEndOff;
5856 HBtab->ebdFilterBegOffset = filterBegOff;
5857 HBtab->ebdHndBegOffset = hndBegOff;
5858 HBtab->ebdHndEndOffset = hndEndOff;
5860 /* Convert the various addresses to basic blocks */
5862 BasicBlock* tryBegBB = fgLookupBB(tryBegOff);
5863 BasicBlock* tryEndBB =
5864 fgLookupBB(tryEndOff); // note: this can be NULL if the try region is at the end of the function
5865 BasicBlock* hndBegBB = fgLookupBB(hndBegOff);
5866 BasicBlock* hndEndBB = nullptr;
5867 BasicBlock* filtBB = nullptr;
5871 // Assert that the try/hnd beginning blocks are set up correctly
5873 if (tryBegBB == nullptr)
5875 BADCODE("Try Clause is invalid");
5878 if (hndBegBB == nullptr)
5880 BADCODE("Handler Clause is invalid");
5883 tryBegBB->bbFlags |= BBF_HAS_LABEL;
5884 hndBegBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
5886 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
5887 // This will change the block weight from 0 to 1
5888 // and clear the rarely run flag
5889 hndBegBB->makeBlockHot();
5891 hndBegBB->bbSetRunRarely(); // handler entry points are rarely executed
5894 if (hndEndOff < info.compILCodeSize)
5896 hndEndBB = fgLookupBB(hndEndOff);
5899 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5901 filtBB = HBtab->ebdFilter = fgLookupBB(clause.FilterOffset);
5903 filtBB->bbCatchTyp = BBCT_FILTER;
5904 filtBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
5906 hndBegBB->bbCatchTyp = BBCT_FILTER_HANDLER;
5908 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
5909 // This will change the block weight from 0 to 1
5910 // and clear the rarely run flag
5911 filtBB->makeBlockHot();
5913 filtBB->bbSetRunRarely(); // filter entry points are rarely executed
5916 // Mark all BBs that belong to the filter with the XTnum of the corresponding handler
5917 for (block = filtBB; /**/; block = block->bbNext)
5919 if (block == nullptr)
5921 BADCODE3("Missing endfilter for filter", " at offset %04X", filtBB->bbCodeOffs);
5925 // Still inside the filter
5926 block->setHndIndex(XTnum);
5928 if (block->bbJumpKind == BBJ_EHFILTERRET)
5930 // Mark catch handler as successor.
5931 block->bbJumpDest = hndBegBB;
5932 assert(block->bbJumpDest->bbCatchTyp == BBCT_FILTER_HANDLER);
5937 if (!block->bbNext || block->bbNext != hndBegBB)
5939 BADCODE3("Filter does not immediately precede handler for filter", " at offset %04X",
5940 filtBB->bbCodeOffs);
5945 HBtab->ebdTyp = clause.ClassToken;
5947 /* Set bbCatchTyp as appropriate */
5949 if (clause.Flags & CORINFO_EH_CLAUSE_FINALLY)
5951 hndBegBB->bbCatchTyp = BBCT_FINALLY;
5955 if (clause.Flags & CORINFO_EH_CLAUSE_FAULT)
5957 hndBegBB->bbCatchTyp = BBCT_FAULT;
5961 hndBegBB->bbCatchTyp = clause.ClassToken;
5963 // These values should be non-zero value that will
5964 // not collide with real tokens for bbCatchTyp
5965 if (clause.ClassToken == 0)
5967 BADCODE("Exception catch type is Null");
5970 noway_assert(clause.ClassToken != BBCT_FAULT);
5971 noway_assert(clause.ClassToken != BBCT_FINALLY);
5972 noway_assert(clause.ClassToken != BBCT_FILTER);
5973 noway_assert(clause.ClassToken != BBCT_FILTER_HANDLER);
5978 /* Mark the initial block and last blocks in the 'try' region */
5980 tryBegBB->bbFlags |= BBF_TRY_BEG | BBF_HAS_LABEL;
5982 /* Prevent future optimizations of removing the first block */
5983 /* of a TRY block and the first block of an exception handler */
5985 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
5986 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
5987 hndBegBB->bbRefs++; // The first block of a handler gets an extra, "artificial" reference count.
5989 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5991 filtBB->bbFlags |= BBF_DONT_REMOVE;
5992 filtBB->bbRefs++; // The first block of a filter gets an extra, "artificial" reference count.
5995 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
5996 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
5999 // Store the info to the table of EH block handlers
6002 HBtab->ebdHandlerType = ToEHHandlerType(clause.Flags);
6004 HBtab->ebdTryBeg = tryBegBB;
6005 HBtab->ebdTryLast = (tryEndBB == nullptr) ? fgLastBB : tryEndBB->bbPrev;
6007 HBtab->ebdHndBeg = hndBegBB;
6008 HBtab->ebdHndLast = (hndEndBB == nullptr) ? fgLastBB : hndEndBB->bbPrev;
6011 // Assert that all of our try/hnd blocks are setup correctly.
6013 if (HBtab->ebdTryLast == nullptr)
6015 BADCODE("Try Clause is invalid");
6018 if (HBtab->ebdHndLast == nullptr)
6020 BADCODE("Handler Clause is invalid");
6024 // Verify that it's legal
6027 verInsertEhNode(&clause, HBtab);
6029 } // end foreach handler table entry
6033 // Next, set things related to nesting that depend on the sorting being complete.
6035 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6037 /* Mark all blocks in the finally/fault or catch clause */
6039 BasicBlock* tryBegBB = HBtab->ebdTryBeg;
6040 BasicBlock* hndBegBB = HBtab->ebdHndBeg;
6042 IL_OFFSET tryBegOff = HBtab->ebdTryBegOffset;
6043 IL_OFFSET tryEndOff = HBtab->ebdTryEndOffset;
6045 IL_OFFSET hndBegOff = HBtab->ebdHndBegOffset;
6046 IL_OFFSET hndEndOff = HBtab->ebdHndEndOffset;
6050 for (block = hndBegBB; block && (block->bbCodeOffs < hndEndOff); block = block->bbNext)
6052 if (!block->hasHndIndex())
6054 block->setHndIndex(XTnum);
6057 // All blocks in a catch handler or filter are rarely run, except the entry
6058 if ((block != hndBegBB) && (hndBegBB->bbCatchTyp != BBCT_FINALLY))
6060 block->bbSetRunRarely();
6064 /* Mark all blocks within the covered range of the try */
6066 for (block = tryBegBB; block && (block->bbCodeOffs < tryEndOff); block = block->bbNext)
6068 /* Mark this BB as belonging to a 'try' block */
6070 if (!block->hasTryIndex())
6072 block->setTryIndex(XTnum);
6076 /* Note: the BB can't span the 'try' block */
6078 if (!(block->bbFlags & BBF_INTERNAL))
6080 noway_assert(tryBegOff <= block->bbCodeOffs);
6081 noway_assert(tryEndOff >= block->bbCodeOffsEnd || tryEndOff == tryBegOff);
6086 /* Init ebdHandlerNestingLevel of current clause, and bump up value for all
6087 * enclosed clauses (which have to be before it in the table).
6088 * Innermost try-finally blocks must precede outermost
6089 * try-finally blocks.
6092 #if !FEATURE_EH_FUNCLETS
6093 HBtab->ebdHandlerNestingLevel = 0;
6094 #endif // !FEATURE_EH_FUNCLETS
6096 HBtab->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6097 HBtab->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6099 noway_assert(XTnum < compHndBBtabCount);
6100 noway_assert(XTnum == ehGetIndex(HBtab));
6102 for (EHblkDsc* xtab = compHndBBtab; xtab < HBtab; xtab++)
6104 #if !FEATURE_EH_FUNCLETS
6105 if (jitIsBetween(xtab->ebdHndBegOffs(), hndBegOff, hndEndOff))
6107 xtab->ebdHandlerNestingLevel++;
6109 #endif // !FEATURE_EH_FUNCLETS
6111 /* If we haven't recorded an enclosing try index for xtab then see
6112 * if this EH region should be recorded. We check if the
6113 * first offset in the xtab lies within our region. If so,
6114 * the last offset also must lie within the region, due to
6115 * nesting rules. verInsertEhNode(), below, will check for proper nesting.
6117 if (xtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6119 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), tryBegOff, tryEndOff);
6122 // Record the enclosing scope link
6123 xtab->ebdEnclosingTryIndex = (unsigned short)XTnum;
6127 /* Do the same for the enclosing handler index.
6129 if (xtab->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6131 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), hndBegOff, hndEndOff);
6134 // Record the enclosing scope link
6135 xtab->ebdEnclosingHndIndex = (unsigned short)XTnum;
6140 } // end foreach handler table entry
6142 #if !FEATURE_EH_FUNCLETS
6145 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
6147 if (ehMaxHndNestingCount <= HBtab->ebdHandlerNestingLevel)
6148 ehMaxHndNestingCount = HBtab->ebdHandlerNestingLevel + 1;
6151 #endif // !FEATURE_EH_FUNCLETS
6154 if (tiVerificationNeeded)
6157 // always run these checks for a debug build
6158 verCheckNestingLevel(initRoot);
6162 // fgNormalizeEH assumes that this test has been passed. And Ssa assumes that fgNormalizeEHTable
6163 // has been run. So do this unless we're in minOpts mode (and always in debug).
6164 if (tiVerificationNeeded || !opts.MinOpts())
6167 fgCheckBasicBlockControlFlow();
6173 JITDUMP("*************** After fgFindBasicBlocks() has created the EH table\n");
6177 // We can't verify the handler table until all the IL legality checks have been done (above), since bad IL
6178 // (such as illegal nesting of regions) will trigger asserts here.
6179 fgVerifyHandlerTab();
6185 /*****************************************************************************
6186 * Check control flow constraints for well formed IL. Bail if any of the constraints
6190 void Compiler::fgCheckBasicBlockControlFlow()
6192 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6196 for (BasicBlock* blk = fgFirstBB; blk; blk = blk->bbNext)
6198 if (blk->bbFlags & BBF_INTERNAL)
6203 switch (blk->bbJumpKind)
6205 case BBJ_NONE: // block flows into the next one (no jump)
6207 fgControlFlowPermitted(blk, blk->bbNext);
6211 case BBJ_ALWAYS: // block does unconditional jump to target
6213 fgControlFlowPermitted(blk, blk->bbJumpDest);
6217 case BBJ_COND: // block conditionally jumps to the target
6219 fgControlFlowPermitted(blk, blk->bbNext);
6221 fgControlFlowPermitted(blk, blk->bbJumpDest);
6225 case BBJ_RETURN: // block ends with 'ret'
6227 if (blk->hasTryIndex() || blk->hasHndIndex())
6229 BADCODE3("Return from a protected block", ". Before offset %04X", blk->bbCodeOffsEnd);
6233 case BBJ_EHFINALLYRET:
6234 case BBJ_EHFILTERRET:
6236 if (!blk->hasHndIndex()) // must be part of a handler
6238 BADCODE3("Missing handler", ". Before offset %04X", blk->bbCodeOffsEnd);
6241 HBtab = ehGetDsc(blk->getHndIndex());
6243 // Endfilter allowed only in a filter block
6244 if (blk->bbJumpKind == BBJ_EHFILTERRET)
6246 if (!HBtab->HasFilter())
6248 BADCODE("Unexpected endfilter");
6251 // endfinally allowed only in a finally/fault block
6252 else if (!HBtab->HasFinallyOrFaultHandler())
6254 BADCODE("Unexpected endfinally");
6257 // The handler block should be the innermost block
6258 // Exception blocks are listed, innermost first.
6259 if (blk->hasTryIndex() && (blk->getTryIndex() < blk->getHndIndex()))
6261 BADCODE("endfinally / endfilter in nested try block");
6266 case BBJ_THROW: // block ends with 'throw'
6267 /* throw is permitted from every BB, so nothing to check */
6268 /* importer makes sure that rethrow is done from a catch */
6271 case BBJ_LEAVE: // block always jumps to the target, maybe out of guarded
6272 // region. Used temporarily until importing
6273 fgControlFlowPermitted(blk, blk->bbJumpDest, TRUE);
6277 case BBJ_SWITCH: // block ends with a switch statement
6280 swtDesc = blk->bbJumpSwt;
6285 for (i = 0; i < swtDesc->bbsCount; i++)
6287 fgControlFlowPermitted(blk, swtDesc->bbsDstTab[i]);
6292 case BBJ_EHCATCHRET: // block ends with a leave out of a catch (only #if FEATURE_EH_FUNCLETS)
6293 case BBJ_CALLFINALLY: // block always calls the target finally
6295 noway_assert(!"Unexpected bbJumpKind"); // these blocks don't get created until importing
6301 /****************************************************************************
6302 * Check that the leave from the block is legal.
6303 * Consider removing this check here if we can do it cheaply during importing
6306 void Compiler::fgControlFlowPermitted(BasicBlock* blkSrc, BasicBlock* blkDest, BOOL isLeave)
6308 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6310 unsigned srcHndBeg, destHndBeg;
6311 unsigned srcHndEnd, destHndEnd;
6312 bool srcInFilter, destInFilter;
6313 bool srcInCatch = false;
6315 EHblkDsc* srcHndTab;
6317 srcHndTab = ehInitHndRange(blkSrc, &srcHndBeg, &srcHndEnd, &srcInFilter);
6318 ehInitHndRange(blkDest, &destHndBeg, &destHndEnd, &destInFilter);
6320 /* Impose the rules for leaving or jumping from handler blocks */
6322 if (blkSrc->hasHndIndex())
6324 srcInCatch = srcHndTab->HasCatchHandler() && srcHndTab->InHndRegionILRange(blkSrc);
6326 /* Are we jumping within the same handler index? */
6327 if (BasicBlock::sameHndRegion(blkSrc, blkDest))
6329 /* Do we have a filter clause? */
6330 if (srcHndTab->HasFilter())
6332 /* filters and catch handlers share same eh index */
6333 /* we need to check for control flow between them. */
6334 if (srcInFilter != destInFilter)
6336 if (!jitIsBetween(blkDest->bbCodeOffs, srcHndBeg, srcHndEnd))
6338 BADCODE3("Illegal control flow between filter and handler", ". Before offset %04X",
6339 blkSrc->bbCodeOffsEnd);
6346 /* The handler indexes of blkSrc and blkDest are different */
6349 /* Any leave instructions must not enter the dest handler from outside*/
6350 if (!jitIsBetween(srcHndBeg, destHndBeg, destHndEnd))
6352 BADCODE3("Illegal use of leave to enter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6357 /* We must use a leave to exit a handler */
6358 BADCODE3("Illegal control flow out of a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6361 /* Do we have a filter clause? */
6362 if (srcHndTab->HasFilter())
6364 /* It is ok to leave from the handler block of a filter, */
6365 /* but not from the filter block of a filter */
6366 if (srcInFilter != destInFilter)
6368 BADCODE3("Illegal to leave a filter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6372 /* We should never leave a finally handler */
6373 if (srcHndTab->HasFinallyHandler())
6375 BADCODE3("Illegal to leave a finally handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6378 /* We should never leave a fault handler */
6379 if (srcHndTab->HasFaultHandler())
6381 BADCODE3("Illegal to leave a fault handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6385 else if (blkDest->hasHndIndex())
6387 /* blkSrc was not inside a handler, but blkDst is inside a handler */
6388 BADCODE3("Illegal control flow into a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6391 /* Are we jumping from a catch handler into the corresponding try? */
6392 /* VB uses this for "on error goto " */
6394 if (isLeave && srcInCatch)
6396 // inspect all handlers containing the jump source
6398 bool bValidJumpToTry = false; // are we jumping in a valid way from a catch to the corresponding try?
6399 bool bCatchHandlerOnly = true; // false if we are jumping out of a non-catch handler
6400 EHblkDsc* ehTableEnd;
6403 for (ehDsc = compHndBBtab, ehTableEnd = compHndBBtab + compHndBBtabCount;
6404 bCatchHandlerOnly && ehDsc < ehTableEnd; ehDsc++)
6406 if (ehDsc->InHndRegionILRange(blkSrc))
6408 if (ehDsc->HasCatchHandler())
6410 if (ehDsc->InTryRegionILRange(blkDest))
6412 // If we already considered the jump for a different try/catch,
6413 // we would have two overlapping try regions with two overlapping catch
6414 // regions, which is illegal.
6415 noway_assert(!bValidJumpToTry);
6417 // Allowed if it is the first instruction of an inner try
6418 // (and all trys in between)
6428 // _tryNestedIllegal:
6440 // leave _tryAgain // Allowed
6442 // leave _tryNestedInner // Allowed
6444 // leave _tryNestedIllegal // Not Allowed
6448 // Note: The leave is allowed also from catches nested inside the catch shown above.
6450 /* The common case where leave is to the corresponding try */
6451 if (ehDsc->ebdIsSameTry(this, blkDest->getTryIndex()) ||
6452 /* Also allowed is a leave to the start of a try which starts in the handler's try */
6453 fgFlowToFirstBlockOfInnerTry(ehDsc->ebdTryBeg, blkDest, false))
6455 bValidJumpToTry = true;
6461 // We are jumping from a handler which is not a catch handler.
6463 // If it's a handler, but not a catch handler, it must be either a finally or fault
6464 if (!ehDsc->HasFinallyOrFaultHandler())
6466 BADCODE3("Handlers must be catch, finally, or fault", ". Before offset %04X",
6467 blkSrc->bbCodeOffsEnd);
6470 // Are we jumping out of this handler?
6471 if (!ehDsc->InHndRegionILRange(blkDest))
6473 bCatchHandlerOnly = false;
6477 else if (ehDsc->InFilterRegionILRange(blkSrc))
6479 // Are we jumping out of a filter?
6480 if (!ehDsc->InFilterRegionILRange(blkDest))
6482 bCatchHandlerOnly = false;
6487 if (bCatchHandlerOnly)
6489 if (bValidJumpToTry)
6496 // This is either the case of a leave to outside the try/catch,
6497 // or a leave to a try not nested in this try/catch.
6498 // The first case is allowed, the second one will be checked
6499 // later when we check the try block rules (it is illegal if we
6500 // jump to the middle of the destination try).
6505 BADCODE3("illegal leave to exit a finally, fault or filter", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6509 /* Check all the try block rules */
6511 IL_OFFSET srcTryBeg;
6512 IL_OFFSET srcTryEnd;
6513 IL_OFFSET destTryBeg;
6514 IL_OFFSET destTryEnd;
6516 ehInitTryRange(blkSrc, &srcTryBeg, &srcTryEnd);
6517 ehInitTryRange(blkDest, &destTryBeg, &destTryEnd);
6519 /* Are we jumping between try indexes? */
6520 if (!BasicBlock::sameTryRegion(blkSrc, blkDest))
6522 // Are we exiting from an inner to outer try?
6523 if (jitIsBetween(srcTryBeg, destTryBeg, destTryEnd) && jitIsBetween(srcTryEnd - 1, destTryBeg, destTryEnd))
6527 BADCODE3("exit from try block without a leave", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6530 else if (jitIsBetween(destTryBeg, srcTryBeg, srcTryEnd))
6532 // check that the dest Try is first instruction of an inner try
6533 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, false))
6535 BADCODE3("control flow into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6538 else // there is no nesting relationship between src and dest
6542 // check that the dest Try is first instruction of an inner try sibling
6543 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, true))
6545 BADCODE3("illegal leave into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6550 BADCODE3("illegal control flow in to/out of try block", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6556 /*****************************************************************************
6557 * Check that blkDest is the first block of an inner try or a sibling
6558 * with no intervening trys in between
6561 bool Compiler::fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling)
6563 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6565 noway_assert(blkDest->hasTryIndex());
6567 unsigned XTnum = blkDest->getTryIndex();
6568 unsigned lastXTnum = blkSrc->hasTryIndex() ? blkSrc->getTryIndex() : compHndBBtabCount;
6569 noway_assert(XTnum < compHndBBtabCount);
6570 noway_assert(lastXTnum <= compHndBBtabCount);
6572 EHblkDsc* HBtab = ehGetDsc(XTnum);
6574 // check that we are not jumping into middle of try
6575 if (HBtab->ebdTryBeg != blkDest)
6582 noway_assert(!BasicBlock::sameTryRegion(blkSrc, blkDest));
6584 // find the l.u.b of the two try ranges
6585 // Set lastXTnum to the l.u.b.
6587 HBtab = ehGetDsc(lastXTnum);
6589 for (lastXTnum++, HBtab++; lastXTnum < compHndBBtabCount; lastXTnum++, HBtab++)
6591 if (jitIsBetweenInclusive(blkDest->bbNum, HBtab->ebdTryBeg->bbNum, HBtab->ebdTryLast->bbNum))
6598 // now check there are no intervening trys between dest and l.u.b
6599 // (it is ok to have intervening trys as long as they all start at
6600 // the same code offset)
6602 HBtab = ehGetDsc(XTnum);
6604 for (XTnum++, HBtab++; XTnum < lastXTnum; XTnum++, HBtab++)
6606 if (HBtab->ebdTryBeg->bbNum < blkDest->bbNum && blkDest->bbNum <= HBtab->ebdTryLast->bbNum)
6615 /*****************************************************************************
6616 * Returns the handler nesting level of the block.
6617 * *pFinallyNesting is set to the nesting level of the inner-most
6618 * finally-protected try the block is in.
6621 unsigned Compiler::fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting)
6623 unsigned curNesting = 0; // How many handlers is the block in
6624 unsigned tryFin = (unsigned)-1; // curNesting when we see innermost finally-protected try
6628 /* We find the block's handler nesting level by walking over the
6629 complete exception table and find enclosing clauses. */
6631 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6633 noway_assert(HBtab->ebdTryBeg && HBtab->ebdHndBeg);
6635 if (HBtab->HasFinallyHandler() && (tryFin == (unsigned)-1) && bbInTryRegions(XTnum, block))
6637 tryFin = curNesting;
6639 else if (bbInHandlerRegions(XTnum, block))
6645 if (tryFin == (unsigned)-1)
6647 tryFin = curNesting;
6650 if (pFinallyNesting)
6652 *pFinallyNesting = curNesting - tryFin;
6658 /*****************************************************************************
6660 * Import the basic blocks of the procedure.
6663 void Compiler::fgImport()
6665 fgHasPostfix = false;
6667 impImport(fgFirstBB);
6669 if (!(opts.eeFlags & CORJIT_FLG_SKIP_VERIFICATION))
6671 CorInfoMethodRuntimeFlags verFlag;
6672 verFlag = tiIsVerifiableCode ? CORINFO_FLG_VERIFIABLE : CORINFO_FLG_UNVERIFIABLE;
6673 info.compCompHnd->setMethodAttribs(info.compMethodHnd, verFlag);
6677 /*****************************************************************************
6678 * This function returns true if tree is a node with a call
6679 * that unconditionally throws an exception
6682 bool Compiler::fgIsThrow(GenTreePtr tree)
6684 if ((tree->gtOper != GT_CALL) || (tree->gtCall.gtCallType != CT_HELPER))
6689 // TODO-Throughput: Replace all these calls to eeFindHelper() with a table based lookup
6691 if ((tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW)) ||
6692 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VERIFICATION)) ||
6693 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
6694 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
6695 #if COR_JIT_EE_VERSION > 460
6696 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
6697 #endif // COR_JIT_EE_VERSION
6698 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW)) ||
6699 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)))
6701 noway_assert(tree->gtFlags & GTF_CALL);
6702 noway_assert(tree->gtFlags & GTF_EXCEPT);
6706 // TODO-CQ: there are a bunch of managed methods in [mscorlib]System.ThrowHelper
6707 // that would be nice to recognize.
6712 /*****************************************************************************
6713 * This function returns true for blocks that are in different hot-cold regions.
6714 * It returns false when the blocks are both in the same regions
6717 bool Compiler::fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2)
6719 noway_assert(blk1 != nullptr);
6720 noway_assert(blk2 != nullptr);
6722 if (fgFirstColdBlock == nullptr)
6727 // If one block is Hot and the other is Cold then we are in different regions
6728 return ((blk1->bbFlags & BBF_COLD) != (blk2->bbFlags & BBF_COLD));
6731 bool Compiler::fgIsBlockCold(BasicBlock* blk)
6733 noway_assert(blk != nullptr);
6735 if (fgFirstColdBlock == nullptr)
6740 return ((blk->bbFlags & BBF_COLD) != 0);
6743 /*****************************************************************************
6744 * This function returns true if tree is a GT_COMMA node with a call
6745 * that unconditionally throws an exception
6748 bool Compiler::fgIsCommaThrow(GenTreePtr tree, bool forFolding /* = false */)
6750 // Instead of always folding comma throws,
6751 // with stress enabled we only fold half the time
6753 if (forFolding && compStressCompile(STRESS_FOLD, 50))
6755 return false; /* Don't fold */
6758 /* Check for cast of a GT_COMMA with a throw overflow */
6759 if ((tree->gtOper == GT_COMMA) && (tree->gtFlags & GTF_CALL) && (tree->gtFlags & GTF_EXCEPT))
6761 return (fgIsThrow(tree->gtOp.gtOp1));
6766 //------------------------------------------------------------------------
6767 // fgIsIndirOfAddrOfLocal: Determine whether "tree" is an indirection of a local.
6770 // tree - The tree node under consideration
6773 // If "tree" is a indirection (GT_IND, GT_BLK, or GT_OBJ) whose arg is an ADDR,
6774 // whose arg in turn is a LCL_VAR, return that LCL_VAR node, else nullptr.
6777 GenTreePtr Compiler::fgIsIndirOfAddrOfLocal(GenTreePtr tree)
6779 GenTreePtr res = nullptr;
6780 if (tree->OperIsIndir())
6782 GenTreePtr addr = tree->AsIndir()->Addr();
6784 // Post rationalization, we can have Indir(Lea(..) trees. Therefore to recognize
6785 // Indir of addr of a local, skip over Lea in Indir(Lea(base, index, scale, offset))
6786 // to get to base variable.
6787 if (addr->OperGet() == GT_LEA)
6789 // We use this method in backward dataflow after liveness computation - fgInterBlockLocalVarLiveness().
6790 // Therefore it is critical that we don't miss 'uses' of any local. It may seem this method overlooks
6791 // if the index part of the LEA has indir( someAddrOperator ( lclVar ) ) to search for a use but it's
6792 // covered by the fact we're traversing the expression in execution order and we also visit the index.
6793 GenTreeAddrMode* lea = addr->AsAddrMode();
6794 GenTreePtr base = lea->Base();
6796 if (base != nullptr)
6798 if (base->OperGet() == GT_IND)
6800 return fgIsIndirOfAddrOfLocal(base);
6802 // else use base as addr
6807 if (addr->OperGet() == GT_ADDR)
6809 GenTreePtr lclvar = addr->gtOp.gtOp1;
6810 if (lclvar->OperGet() == GT_LCL_VAR)
6815 else if (addr->OperGet() == GT_LCL_VAR_ADDR)
6823 GenTreePtr Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper)
6825 bool bNeedClassID = true;
6826 unsigned callFlags = 0;
6828 var_types type = TYP_BYREF;
6830 // This is sort of ugly, as we have knowledge of what the helper is returning.
6831 // We need the return type.
6834 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
6835 bNeedClassID = false;
6838 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
6839 callFlags |= GTF_CALL_HOISTABLE;
6842 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
6843 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
6844 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
6845 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
6846 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
6847 // type = TYP_BYREF;
6850 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
6851 bNeedClassID = false;
6854 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
6855 callFlags |= GTF_CALL_HOISTABLE;
6858 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
6859 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
6860 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
6861 case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
6866 assert(!"unknown shared statics helper");
6870 GenTreeArgList* argList = nullptr;
6872 GenTreePtr opModuleIDArg;
6873 GenTreePtr opClassIDArg;
6881 clsID = info.compCompHnd->getClassDomainID(cls, &pclsID);
6883 moduleID = info.compCompHnd->getClassModuleIdForStatics(cls, nullptr, &pmoduleID);
6885 if (!(callFlags & GTF_CALL_HOISTABLE))
6887 if (info.compCompHnd->getClassAttribs(cls) & CORINFO_FLG_BEFOREFIELDINIT)
6889 callFlags |= GTF_CALL_HOISTABLE;
6895 opModuleIDArg = gtNewIconHandleNode((size_t)pmoduleID, GTF_ICON_CIDMID_HDL);
6896 opModuleIDArg = gtNewOperNode(GT_IND, TYP_I_IMPL, opModuleIDArg);
6897 opModuleIDArg->gtFlags |= GTF_IND_INVARIANT;
6901 opModuleIDArg = gtNewIconNode((size_t)moduleID, TYP_I_IMPL);
6908 opClassIDArg = gtNewIconHandleNode((size_t)pclsID, GTF_ICON_CIDMID_HDL);
6909 opClassIDArg = gtNewOperNode(GT_IND, TYP_INT, opClassIDArg);
6910 opClassIDArg->gtFlags |= GTF_IND_INVARIANT;
6914 opClassIDArg = gtNewIconNode(clsID, TYP_INT);
6917 // call the helper to get the base
6918 argList = gtNewArgList(opModuleIDArg, opClassIDArg);
6922 argList = gtNewArgList(opModuleIDArg);
6925 if (!s_helperCallProperties.NoThrow(helper))
6927 callFlags |= GTF_EXCEPT;
6930 return gtNewHelperCallNode(helper, type, callFlags, argList);
6933 GenTreePtr Compiler::fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls)
6935 #ifdef FEATURE_READYTORUN_COMPILER
6936 if (opts.IsReadyToRun())
6938 CORINFO_RESOLVED_TOKEN resolvedToken;
6939 ZeroMemory(&resolvedToken, sizeof(resolvedToken));
6940 resolvedToken.hClass = cls;
6942 return impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_STATIC_BASE, TYP_BYREF);
6946 // Call the shared non gc static helper, as its the fastest
6947 return fgGetStaticsCCtorHelper(cls, info.compCompHnd->getSharedCCtorHelper(cls));
6951 // Returns true unless the address expression could
6952 // never represent a NULL
6954 bool Compiler::fgAddrCouldBeNull(GenTreePtr addr)
6956 if (addr->gtOper == GT_ADDR)
6958 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
6960 GenTreePtr cns1Tree = addr->gtOp.gtOp1;
6961 if (!cns1Tree->IsIconHandle())
6963 // Indirection of some random constant...
6964 // It is safest just to return true
6968 else if (addr->gtOp.gtOp1->OperIsLocalAddr())
6972 return false; // we can't have a null address
6974 else if (addr->gtOper == GT_ADD)
6976 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
6978 GenTreePtr cns1Tree = addr->gtOp.gtOp1;
6979 if (!cns1Tree->IsIconHandle())
6981 if (!fgIsBigOffset(cns1Tree->gtIntCon.gtIconVal))
6983 // Op1 was an ordinary small constant
6984 return fgAddrCouldBeNull(addr->gtOp.gtOp2);
6987 else // Op1 was a handle represented as a constant
6989 // Is Op2 also a constant?
6990 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
6992 GenTreePtr cns2Tree = addr->gtOp.gtOp2;
6993 // Is this an addition of a handle and constant
6994 if (!cns2Tree->IsIconHandle())
6996 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
6998 // Op2 was an ordinary small constant
6999 return false; // we can't have a null address
7007 // Op1 is not a constant
7009 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
7011 GenTreePtr cns2Tree = addr->gtOp.gtOp2;
7012 // Is this an addition of a small constant
7013 if (!cns2Tree->IsIconHandle())
7015 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
7017 // Op2 was an ordinary small constant
7018 return fgAddrCouldBeNull(addr->gtOp.gtOp1);
7024 return true; // default result: addr could be null
7027 /*****************************************************************************
7028 * Optimize the call to the delegate constructor.
7031 GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreePtr call, CORINFO_CONTEXT_HANDLE* ExactContextHnd)
7033 noway_assert(call->gtOper == GT_CALL);
7035 noway_assert(call->gtCall.gtCallType == CT_USER_FUNC);
7036 CORINFO_METHOD_HANDLE methHnd = call->gtCall.gtCallMethHnd;
7037 CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getMethodClass(methHnd);
7039 GenTreePtr targetMethod = call->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
7040 noway_assert(targetMethod->TypeGet() == TYP_I_IMPL);
7041 genTreeOps oper = targetMethod->OperGet();
7042 if (oper == GT_FTN_ADDR || oper == GT_CALL || oper == GT_QMARK)
7044 CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
7045 GenTreePtr qmarkNode = nullptr;
7046 if (oper == GT_FTN_ADDR)
7048 targetMethodHnd = targetMethod->gtFptrVal.gtFptrMethod;
7050 else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
7052 GenTreePtr handleNode = targetMethod->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp1;
7054 if (handleNode->OperGet() == GT_CNS_INT)
7056 // it's a ldvirtftn case, fetch the methodhandle off the helper for ldvirtftn. It's the 3rd arg
7057 targetMethodHnd = CORINFO_METHOD_HANDLE(handleNode->gtIntCon.gtCompileTimeHandle);
7059 // Sometimes the argument to this is the result of a generic dictionary lookup, which shows
7060 // up as a GT_QMARK.
7061 else if (handleNode->OperGet() == GT_QMARK)
7063 qmarkNode = handleNode;
7066 // Sometimes we don't call CORINFO_HELP_VIRTUAL_FUNC_PTR but instead just call
7067 // CORINFO_HELP_RUNTIMEHANDLE_METHOD directly.
7068 else if (oper == GT_QMARK)
7070 qmarkNode = targetMethod;
7074 noway_assert(qmarkNode->OperGet() == GT_QMARK);
7075 // The argument is actually a generic dictionary lookup. For delegate creation it looks
7080 // Arg 1 -> token (has compile time handle)
7084 // In this case I can find the token (which is a method handle) and that is the compile time
7086 noway_assert(qmarkNode->gtOp.gtOp2->OperGet() == GT_COLON);
7087 noway_assert(qmarkNode->gtOp.gtOp2->gtOp.gtOp1->OperGet() == GT_CALL);
7088 GenTreePtr runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1;
7090 // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
7091 GenTreePtr tokenNode = runtimeLookupCall->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
7092 noway_assert(tokenNode->OperGet() == GT_CNS_INT);
7093 targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
7096 #ifdef FEATURE_READYTORUN_COMPILER
7097 if (opts.IsReadyToRun())
7099 // ReadyToRun has this optimization for a non-virtual function pointers only for now.
7100 if (oper == GT_FTN_ADDR)
7102 // The first argument of the helper is delegate this pointer
7103 GenTreeArgList* helperArgs = gtNewArgList(call->gtCall.gtCallObjp);
7104 CORINFO_CONST_LOOKUP entryPoint;
7106 // The second argument of the helper is the target object pointers
7107 helperArgs->gtOp.gtOp2 = gtNewArgList(call->gtCall.gtCallArgs->gtOp.gtOp1);
7109 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs);
7110 #if COR_JIT_EE_VERSION > 460
7111 info.compCompHnd->getReadyToRunDelegateCtorHelper(targetMethod->gtFptrVal.gtLdftnResolvedToken, clsHnd,
7114 info.compCompHnd->getReadyToRunHelper(targetMethod->gtFptrVal.gtLdftnResolvedToken,
7115 CORINFO_HELP_READYTORUN_DELEGATE_CTOR, &entryPoint);
7117 call->gtCall.setEntryPoint(entryPoint);
7122 if (targetMethodHnd != nullptr)
7124 CORINFO_METHOD_HANDLE alternateCtor = nullptr;
7125 DelegateCtorArgs ctorData;
7126 ctorData.pMethod = info.compMethodHnd;
7127 ctorData.pArg3 = nullptr;
7128 ctorData.pArg4 = nullptr;
7129 ctorData.pArg5 = nullptr;
7131 alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
7132 if (alternateCtor != methHnd)
7134 // we erase any inline info that may have been set for generics has it is not needed here,
7135 // and in fact it will pass the wrong info to the inliner code
7136 *ExactContextHnd = nullptr;
7138 call->gtCall.gtCallMethHnd = alternateCtor;
7140 noway_assert(call->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2 == nullptr);
7143 call->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2 =
7144 gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR));
7148 call->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2 =
7149 gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR));
7153 call->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2 =
7154 gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR));
7165 bool Compiler::fgCastNeeded(GenTreePtr tree, var_types toType)
7168 // If tree is a relop and we need an 4-byte integer
7169 // then we never need to insert a cast
7171 if ((tree->OperKind() & GTK_RELOP) && (genActualType(toType) == TYP_INT))
7179 // Is the tree as GT_CAST or a GT_CALL ?
7181 if (tree->OperGet() == GT_CAST)
7183 fromType = tree->CastToType();
7185 else if (tree->OperGet() == GT_CALL)
7187 fromType = (var_types)tree->gtCall.gtReturnType;
7191 fromType = tree->TypeGet();
7195 // If both types are the same then an additional cast is not necessary
7197 if (toType == fromType)
7202 // If the sign-ness of the two types are different then a cast is necessary
7204 if (varTypeIsUnsigned(toType) != varTypeIsUnsigned(fromType))
7209 // If the from type is the same size or smaller then an additional cast is not necessary
7211 if (genTypeSize(toType) >= genTypeSize(fromType))
7217 // Looks like we will need the cast
7222 // If assigning to a local var, add a cast if the target is
7223 // marked as NormalizedOnStore. Returns true if any change was made
7224 GenTreePtr Compiler::fgDoNormalizeOnStore(GenTreePtr tree)
7227 // Only normalize the stores in the global morph phase
7231 noway_assert(tree->OperGet() == GT_ASG);
7233 GenTreePtr op1 = tree->gtOp.gtOp1;
7234 GenTreePtr op2 = tree->gtOp.gtOp2;
7236 if (op1->gtOper == GT_LCL_VAR && genActualType(op1->TypeGet()) == TYP_INT)
7238 // Small-typed arguments and aliased locals are normalized on load.
7239 // Other small-typed locals are normalized on store.
7240 // If it is an assignment to one of the latter, insert the cast on RHS
7241 unsigned varNum = op1->gtLclVarCommon.gtLclNum;
7242 LclVarDsc* varDsc = &lvaTable[varNum];
7244 if (varDsc->lvNormalizeOnStore())
7246 noway_assert(op1->gtType <= TYP_INT);
7247 op1->gtType = TYP_INT;
7249 if (fgCastNeeded(op2, varDsc->TypeGet()))
7251 op2 = gtNewCastNode(TYP_INT, op2, varDsc->TypeGet());
7252 tree->gtOp.gtOp2 = op2;
7254 // Propagate GTF_COLON_COND
7255 op2->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7264 /*****************************************************************************
7266 * Mark whether the edge "srcBB -> dstBB" forms a loop that will always
7267 * execute a call or not.
7270 inline void Compiler::fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB)
7272 /* Bail if this is not a backward edge */
7274 if (srcBB->bbNum < dstBB->bbNum)
7279 /* Unless we already know that there is a loop without a call here ... */
7281 if (!(dstBB->bbFlags & BBF_LOOP_CALL0))
7283 /* Check whether there is a loop path that doesn't call */
7285 if (optReachWithoutCall(dstBB, srcBB))
7287 dstBB->bbFlags |= BBF_LOOP_CALL0;
7288 dstBB->bbFlags &= ~BBF_LOOP_CALL1;
7292 dstBB->bbFlags |= BBF_LOOP_CALL1;
7295 // if this loop will always call, then we can omit the GC Poll
7296 if ((GCPOLL_NONE != opts.compGCPollType) && (dstBB->bbFlags & BBF_LOOP_CALL1))
7298 srcBB->bbFlags &= ~BBF_NEEDS_GCPOLL;
7302 /*****************************************************************************
7304 * Mark which loops are guaranteed to execute a call.
7307 void Compiler::fgLoopCallMark()
7311 /* If we've already marked all the block, bail */
7313 if (fgLoopCallMarked)
7318 fgLoopCallMarked = true;
7320 /* Walk the blocks, looking for backward edges */
7322 for (block = fgFirstBB; block; block = block->bbNext)
7324 switch (block->bbJumpKind)
7327 case BBJ_CALLFINALLY:
7329 case BBJ_EHCATCHRET:
7330 fgLoopCallTest(block, block->bbJumpDest);
7336 jumpCnt = block->bbJumpSwt->bbsCount;
7337 BasicBlock** jumpPtr;
7338 jumpPtr = block->bbJumpSwt->bbsDstTab;
7342 fgLoopCallTest(block, *jumpPtr);
7343 } while (++jumpPtr, --jumpCnt);
7353 /*****************************************************************************
7355 * Note the fact that the given block is a loop header.
7358 inline void Compiler::fgMarkLoopHead(BasicBlock* block)
7363 printf("fgMarkLoopHead: Checking loop head block BB%02u: ", block->bbNum);
7367 /* Have we decided to generate fully interruptible code already? */
7369 if (genInterruptible)
7374 printf("method is already fully interruptible\n");
7380 /* Is the loop head block known to execute a method call? */
7382 if (block->bbFlags & BBF_GC_SAFE_POINT)
7387 printf("this block will execute a call\n");
7390 // single block loops that contain GC safe points don't need polls.
7391 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
7395 /* Are dominator sets available? */
7399 /* Make sure that we know which loops will always execute calls */
7401 if (!fgLoopCallMarked)
7406 /* Will every trip through our loop execute a call? */
7408 if (block->bbFlags & BBF_LOOP_CALL1)
7413 printf("this block dominates a block that will execute a call\n");
7421 * We have to make this method fully interruptible since we can not
7422 * ensure that this loop will execute a call every time it loops.
7424 * We'll also need to generate a full register map for this method.
7427 assert(!codeGen->isGCTypeFixed());
7429 if (!compCanEncodePtrArgCntMax())
7434 printf("a callsite with more than 1023 pushed args exists\n");
7443 printf("no guaranteed callsite exits, marking method as fully interruptible\n");
7447 // only enable fully interruptible code for if we're hijacking.
7448 if (GCPOLL_NONE == opts.compGCPollType)
7450 genInterruptible = true;
7454 GenTreePtr Compiler::fgGetCritSectOfStaticMethod()
7456 noway_assert(!compIsForInlining());
7458 noway_assert(info.compIsStatic); // This method should only be called for static methods.
7460 GenTreePtr tree = nullptr;
7462 CORINFO_LOOKUP_KIND kind = info.compCompHnd->getLocationOfThisType(info.compMethodHnd);
7464 if (!kind.needsRuntimeLookup)
7466 void *critSect = nullptr, **pCrit = nullptr;
7467 critSect = info.compCompHnd->getMethodSync(info.compMethodHnd, (void**)&pCrit);
7468 noway_assert((!critSect) != (!pCrit));
7470 tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL);
7474 // Collectible types requires that for shared generic code, if we use the generic context paramter
7475 // that we report it. (This is a conservative approach, we could detect some cases particularly when the
7476 // context parameter is this that we don't need the eager reporting logic.)
7477 lvaGenericsContextUsed = true;
7479 switch (kind.runtimeLookupKind)
7481 case CORINFO_LOOKUP_THISOBJ:
7483 noway_assert(!"Should never get this for static method.");
7487 case CORINFO_LOOKUP_CLASSPARAM:
7489 // In this case, the hidden param is the class handle.
7490 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7494 case CORINFO_LOOKUP_METHODPARAM:
7496 // In this case, the hidden param is the method handle.
7497 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7498 // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the class handle
7499 // from the method handle.
7500 tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, 0, gtNewArgList(tree));
7506 noway_assert(!"Unknown LOOKUP_KIND");
7511 noway_assert(tree); // tree should now contain the CORINFO_CLASS_HANDLE for the exact class.
7513 // Given the class handle, get the pointer to the Monitor.
7514 tree = gtNewHelperCallNode(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, TYP_I_IMPL, 0, gtNewArgList(tree));
7521 #if !defined(_TARGET_X86_)
7523 /*****************************************************************************
7525 * Add monitor enter/exit calls for synchronized methods, and a try/fault
7526 * to ensure the 'exit' is called if the 'enter' was successful. On x86, we
7527 * generate monitor enter/exit calls and tell the VM the code location of
7528 * these calls. When an exception occurs between those locations, the VM
7529 * automatically releases the lock. For non-x86 platforms, the JIT is
7530 * responsible for creating a try/finally to protect the monitor enter/exit,
7531 * and the VM doesn't need to know anything special about the method during
7532 * exception processing -- it's just a normal try/finally.
7534 * We generate the following code:
7538 * unsigned byte acquired = 0;
7540 * JIT_MonEnterWorker(<lock object>, &acquired);
7542 * *** all the preexisting user code goes here ***
7544 * JIT_MonExitWorker(<lock object>, &acquired);
7546 * JIT_MonExitWorker(<lock object>, &acquired);
7552 * If the lock is actually acquired, then the 'acquired' variable is set to 1
7553 * by the helper call. During normal exit, the finally is called, 'acquired'
7554 * is 1, and the lock is released. If an exception occurs before the lock is
7555 * acquired, but within the 'try' (extremely unlikely, but possible), 'acquired'
7556 * will be 0, and the monitor exit call will quickly return without attempting
7557 * to release the lock. Otherwise, 'acquired' will be 1, and the lock will be
7558 * released during exception processing.
7560 * For synchronized methods, we generate a single return block.
7561 * We can do this without creating additional "step" blocks because "ret" blocks
7562 * must occur at the top-level (of the original code), not nested within any EH
7563 * constructs. From the CLI spec, 12.4.2.8.2.3 "ret": "Shall not be enclosed in any
7564 * protected block, filter, or handler." Also, 3.57: "The ret instruction cannot be
7565 * used to transfer control out of a try, filter, catch, or finally block. From within
7566 * a try or catch, use the leave instruction with a destination of a ret instruction
7567 * that is outside all enclosing exception blocks."
7569 * In addition, we can add a "fault" at the end of a method and be guaranteed that no
7570 * control falls through. From the CLI spec, section 12.4 "Control flow": "Control is not
7571 * permitted to simply fall through the end of a method. All paths shall terminate with one
7572 * of these instructions: ret, throw, jmp, or (tail. followed by call, calli, or callvirt)."
7574 * We only need to worry about "ret" and "throw", as the CLI spec prevents any other
7575 * alternatives. Section 15.4.3.3 "Implementation information" states about exiting
7576 * synchronized methods: "Exiting a synchronized method using a tail. call shall be
7577 * implemented as though the tail. had not been specified." Section 3.37 "jmp" states:
7578 * "The jmp instruction cannot be used to transferred control out of a try, filter,
7579 * catch, fault or finally block; or out of a synchronized region." And, "throw" will
7580 * be handled naturally; no additional work is required.
7583 void Compiler::fgAddSyncMethodEnterExit()
7585 assert((info.compFlags & CORINFO_FLG_SYNCH) != 0);
7587 // We need to do this transformation before funclets are created.
7588 assert(!fgFuncletsCreated);
7590 // Assume we don't need to update the bbPreds lists.
7591 assert(!fgComputePredsDone);
7594 // If we don't support EH, we can't add the EH needed by synchronized methods.
7595 // Of course, we could simply ignore adding the EH constructs, since we don't
7596 // support exceptions being thrown in this mode, but we would still need to add
7597 // the monitor enter/exit, and that doesn't seem worth it for this minor case.
7598 // By the time EH is working, we can just enable the whole thing.
7599 NYI("No support for synchronized methods");
7600 #endif // !FEATURE_EH
7602 // Create a scratch first BB where we can put the new variable initialization.
7603 // Don't put the scratch BB in the protected region.
7605 fgEnsureFirstBBisScratch();
7607 // Create a block for the start of the try region, where the monitor enter call
7610 assert(fgFirstBB->bbFallsThrough());
7612 BasicBlock* tryBegBB = fgNewBBafter(BBJ_NONE, fgFirstBB, false);
7613 BasicBlock* tryLastBB = fgLastBB;
7615 // Create a block for the fault.
7617 assert(!tryLastBB->bbFallsThrough());
7618 BasicBlock* faultBB = fgNewBBafter(BBJ_EHFINALLYRET, tryLastBB, false);
7620 assert(tryLastBB->bbNext == faultBB);
7621 assert(faultBB->bbNext == nullptr);
7622 assert(faultBB == fgLastBB);
7624 { // Scope the EH region creation
7626 // Add the new EH region at the end, since it is the least nested,
7627 // and thus should be last.
7630 unsigned XTnew = compHndBBtabCount;
7632 newEntry = fgAddEHTableEntry(XTnew);
7634 // Initialize the new entry
7636 newEntry->ebdHandlerType = EH_HANDLER_FAULT;
7638 newEntry->ebdTryBeg = tryBegBB;
7639 newEntry->ebdTryLast = tryLastBB;
7641 newEntry->ebdHndBeg = faultBB;
7642 newEntry->ebdHndLast = faultBB;
7644 newEntry->ebdTyp = 0; // unused for fault
7646 newEntry->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7647 newEntry->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7649 newEntry->ebdTryBegOffset = tryBegBB->bbCodeOffs;
7650 newEntry->ebdTryEndOffset = tryLastBB->bbCodeOffsEnd;
7651 newEntry->ebdFilterBegOffset = 0;
7652 newEntry->ebdHndBegOffset = 0; // handler doesn't correspond to any IL
7653 newEntry->ebdHndEndOffset = 0; // handler doesn't correspond to any IL
7655 // Set some flags on the new region. This is the same as when we set up
7656 // EH regions in fgFindBasicBlocks(). Note that the try has no enclosing
7657 // handler, and the fault has no enclosing try.
7659 tryBegBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_TRY_BEG | BBF_IMPORTED;
7661 faultBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_IMPORTED;
7662 faultBB->bbCatchTyp = BBCT_FAULT;
7664 tryBegBB->setTryIndex(XTnew);
7665 tryBegBB->clearHndIndex();
7667 faultBB->clearTryIndex();
7668 faultBB->setHndIndex(XTnew);
7670 // Walk the user code blocks and set all blocks that don't already have a try handler
7671 // to point to the new try handler.
7674 for (tmpBB = tryBegBB->bbNext; tmpBB != faultBB; tmpBB = tmpBB->bbNext)
7676 if (!tmpBB->hasTryIndex())
7678 tmpBB->setTryIndex(XTnew);
7682 // Walk the EH table. Make every EH entry that doesn't already have an enclosing
7683 // try index mark this new entry as their enclosing try index.
7688 for (XTnum = 0, HBtab = compHndBBtab; XTnum < XTnew; XTnum++, HBtab++)
7690 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
7692 HBtab->ebdEnclosingTryIndex =
7693 (unsigned short)XTnew; // This EH region wasn't previously nested, but now it is.
7700 JITDUMP("Synchronized method - created additional EH descriptor EH#%u for try/fault wrapping monitor "
7703 fgDispBasicBlocks();
7707 fgVerifyHandlerTab();
7711 // Create a 'monitor acquired' boolean (actually, an unsigned byte: 1 = acquired, 0 = not acquired).
7713 var_types typeMonAcquired = TYP_UBYTE;
7714 this->lvaMonAcquired = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7716 lvaTable[lvaMonAcquired].lvType = typeMonAcquired;
7718 { // Scope the variables of the variable initialization
7720 // Initialize the 'acquired' boolean.
7722 GenTreePtr zero = gtNewZeroConNode(genActualType(typeMonAcquired));
7723 GenTreePtr varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
7724 GenTreePtr initNode = gtNewAssignNode(varNode, zero);
7726 fgInsertStmtAtEnd(fgFirstBB, initNode);
7731 printf("\nSynchronized method - Add 'acquired' initialization in first block BB%02u [%08p]\n", fgFirstBB,
7733 gtDispTree(initNode);
7739 // Make a copy of the 'this' pointer to be used in the handler so it does not inhibit enregistration
7740 // of all uses of the variable.
7741 unsigned lvaCopyThis = 0;
7742 if (!info.compIsStatic)
7744 lvaCopyThis = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7745 lvaTable[lvaCopyThis].lvType = TYP_REF;
7747 GenTreePtr thisNode = gtNewLclvNode(info.compThisArg, TYP_REF);
7748 GenTreePtr copyNode = gtNewLclvNode(lvaCopyThis, TYP_REF);
7749 GenTreePtr initNode = gtNewAssignNode(copyNode, thisNode);
7751 fgInsertStmtAtEnd(tryBegBB, initNode);
7754 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, tryBegBB, true /*enter*/);
7757 fgCreateMonitorTree(lvaMonAcquired, lvaCopyThis, faultBB, false /*exit*/);
7759 // non-exceptional cases
7760 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
7762 if (block->bbJumpKind == BBJ_RETURN)
7764 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, block, false /*exit*/);
7769 // fgCreateMonitorTree: Create tree to execute a monitor enter or exit operation for synchronized methods
7770 // lvaMonAcquired: lvaNum of boolean variable that tracks if monitor has been acquired.
7771 // lvaThisVar: lvaNum of variable being used as 'this' pointer, may not be the original one. Is only used for
7772 // nonstatic methods
7773 // block: block to insert the tree in. It is inserted at the end or in the case of a return, immediately before the
7775 // enter: whether to create a monitor enter or exit
7777 GenTree* Compiler::fgCreateMonitorTree(unsigned lvaMonAcquired, unsigned lvaThisVar, BasicBlock* block, bool enter)
7779 // Insert the expression "enter/exitCrit(this, &acquired)" or "enter/exitCrit(handle, &acquired)"
7781 var_types typeMonAcquired = TYP_UBYTE;
7782 GenTreePtr varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
7783 GenTreePtr varAddrNode = gtNewOperNode(GT_ADDR, TYP_BYREF, varNode);
7786 if (info.compIsStatic)
7788 tree = fgGetCritSectOfStaticMethod();
7789 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER_STATIC : CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, 0,
7790 gtNewArgList(tree, varAddrNode));
7794 tree = gtNewLclvNode(lvaThisVar, TYP_REF);
7795 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT, TYP_VOID, 0,
7796 gtNewArgList(tree, varAddrNode));
7802 printf("\nSynchronized method - Add monitor %s call to block BB%02u [%08p]\n", enter ? "enter" : "exit", block,
7809 if (block->bbJumpKind == BBJ_RETURN && block->lastStmt()->gtStmtExpr->gtOper == GT_RETURN)
7811 GenTree* retNode = block->lastStmt()->gtStmtExpr;
7812 GenTree* retExpr = retNode->gtOp.gtOp1;
7814 if (retExpr != nullptr)
7816 // have to insert this immediately before the GT_RETURN so we transform:
7818 // ret(comma(comma(tmp=...,call mon_exit), tmp)
7821 // Before morph stage, it is possible to have a case of GT_RETURN(TYP_LONG, op1) where op1's type is
7822 // TYP_STRUCT (of 8-bytes) and op1 is call node. See the big comment block in impReturnInstruction()
7823 // for details for the case where info.compRetType is not the same as info.compRetNativeType. For
7824 // this reason pass compMethodInfo->args.retTypeClass which is guaranteed to be a valid class handle
7825 // if the return type is a value class. Note that fgInsertCommFormTemp() in turn uses this class handle
7826 // if the type of op1 is TYP_STRUCT to perform lvaSetStruct() on the new temp that is created, which
7827 // in turn passes it to VM to know the size of value type.
7828 GenTree* temp = fgInsertCommaFormTemp(&retNode->gtOp.gtOp1, info.compMethodInfo->args.retTypeClass);
7830 GenTree* lclVar = retNode->gtOp.gtOp1->gtOp.gtOp2;
7831 retNode->gtOp.gtOp1->gtOp.gtOp2 = gtNewOperNode(GT_COMMA, retExpr->TypeGet(), tree, lclVar);
7835 // Insert this immediately before the GT_RETURN
7836 fgInsertStmtNearEnd(block, tree);
7841 fgInsertStmtAtEnd(block, tree);
7847 // Convert a BBJ_RETURN block in a synchronized method to a BBJ_ALWAYS.
7848 // We've previously added a 'try' block around the original program code using fgAddSyncMethodEnterExit().
7849 // Thus, we put BBJ_RETURN blocks inside a 'try'. In IL this is illegal. Instead, we would
7850 // see a 'leave' inside a 'try' that would get transformed into BBJ_CALLFINALLY/BBJ_ALWAYS blocks
7851 // during importing, and the BBJ_ALWAYS would point at an outer block with the BBJ_RETURN.
7852 // Here, we mimic some of the logic of importing a LEAVE to get the same effect for synchronized methods.
7853 void Compiler::fgConvertSyncReturnToLeave(BasicBlock* block)
7855 assert(!fgFuncletsCreated);
7856 assert(info.compFlags & CORINFO_FLG_SYNCH);
7857 assert(genReturnBB != nullptr);
7858 assert(genReturnBB != block);
7859 assert(fgReturnCount <= 1); // We have a single return for synchronized methods
7860 assert(block->bbJumpKind == BBJ_RETURN);
7861 assert((block->bbFlags & BBF_HAS_JMP) == 0);
7862 assert(block->hasTryIndex());
7863 assert(!block->hasHndIndex());
7864 assert(compHndBBtabCount >= 1);
7866 unsigned tryIndex = block->getTryIndex();
7867 assert(tryIndex == compHndBBtabCount - 1); // The BBJ_RETURN must be at the top-level before we inserted the
7868 // try/finally, which must be the last EH region.
7870 EHblkDsc* ehDsc = ehGetDsc(tryIndex);
7871 assert(ehDsc->ebdEnclosingTryIndex ==
7872 EHblkDsc::NO_ENCLOSING_INDEX); // There are no enclosing regions of the BBJ_RETURN block
7873 assert(ehDsc->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX);
7875 // Convert the BBJ_RETURN to BBJ_ALWAYS, jumping to genReturnBB.
7876 block->bbJumpKind = BBJ_ALWAYS;
7877 block->bbJumpDest = genReturnBB;
7878 block->bbJumpDest->bbRefs++;
7883 printf("Synchronized method - convert block BB%02u to BBJ_ALWAYS [targets BB%02u]\n", block->bbNum,
7884 block->bbJumpDest->bbNum);
7889 #endif // !_TARGET_X86_
7891 //------------------------------------------------------------------------
7892 // fgAddReversePInvokeEnterExit: Add enter/exit calls for reverse PInvoke methods
7900 void Compiler::fgAddReversePInvokeEnterExit()
7902 assert(opts.IsReversePInvoke());
7904 #if COR_JIT_EE_VERSION > 460
7905 lvaReversePInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Reverse Pinvoke FrameVar"));
7907 LclVarDsc* varDsc = &lvaTable[lvaReversePInvokeFrameVar];
7908 varDsc->lvType = TYP_BLK;
7909 varDsc->lvExactSize = eeGetEEInfo()->sizeOfReversePInvokeFrame;
7913 // Add enter pinvoke exit callout at the start of prolog
7915 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
7917 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, 0, gtNewArgList(tree));
7919 fgEnsureFirstBBisScratch();
7921 fgInsertStmtAtBeg(fgFirstBB, tree);
7926 printf("\nReverse PInvoke method - Add reverse pinvoke enter in first basic block [%08p]\n", dspPtr(fgFirstBB));
7932 // Add reverse pinvoke exit callout at the end of epilog
7934 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
7936 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, 0, gtNewArgList(tree));
7938 assert(genReturnBB != nullptr);
7940 fgInsertStmtAtEnd(genReturnBB, tree);
7945 printf("\nReverse PInvoke method - Add reverse pinvoke exit in return basic block [%08p]\n",
7946 dspPtr(genReturnBB));
7952 #endif // COR_JIT_EE_VERSION > 460
7955 /*****************************************************************************
7957 * Return 'true' if there is more than one BBJ_RETURN block.
7960 bool Compiler::fgMoreThanOneReturnBlock()
7962 unsigned retCnt = 0;
7964 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
7966 if (block->bbJumpKind == BBJ_RETURN)
7979 /*****************************************************************************
7981 * Add any internal blocks/trees we may need
7984 void Compiler::fgAddInternal()
7986 noway_assert(!compIsForInlining());
7989 <BUGNUM> VSW441487 </BUGNUM>
7991 The "this" pointer is implicitly used in the following cases:
7992 1. Locking of synchronized methods
7993 2. Dictionary access of shared generics code
7994 3. If a method has "catch(FooException<T>)", the EH code accesses "this" to determine T.
7995 4. Initializing the type from generic methods which require precise cctor semantics
7996 5. Verifier does special handling of "this" in the .ctor
7998 However, we might overwrite it with a "starg 0".
7999 In this case, we will redirect all "ldarg(a)/starg(a) 0" to a temp lvaTable[lvaArg0Var]
8002 if (!info.compIsStatic)
8004 if (lvaArg0Var != info.compThisArg)
8006 // When we're using the general encoder, we mark compThisArg address-taken to ensure that it is not
8007 // enregistered (since the decoder always reports a stack location for "this" for generics
8009 bool lva0CopiedForGenericsCtxt;
8010 #ifndef JIT32_GCENCODER
8011 lva0CopiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
8012 #else // JIT32_GCENCODER
8013 lva0CopiedForGenericsCtxt = false;
8014 #endif // JIT32_GCENCODER
8015 noway_assert(lva0CopiedForGenericsCtxt || !lvaTable[info.compThisArg].lvAddrExposed);
8016 noway_assert(!lvaTable[info.compThisArg].lvArgWrite);
8017 noway_assert(lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvArgWrite ||
8018 lva0CopiedForGenericsCtxt);
8020 var_types thisType = lvaTable[info.compThisArg].TypeGet();
8022 // Now assign the original input "this" to the temp
8026 tree = gtNewLclvNode(lvaArg0Var, thisType);
8028 tree = gtNewAssignNode(tree, // dst
8029 gtNewLclvNode(info.compThisArg, thisType) // src
8032 /* Create a new basic block and stick the assignment in it */
8034 fgEnsureFirstBBisScratch();
8036 fgInsertStmtAtEnd(fgFirstBB, tree);
8041 printf("\nCopy \"this\" to lvaArg0Var in first basic block [%08p]\n", dspPtr(fgFirstBB));
8049 // Grab a temp for the security object.
8050 // (Note: opts.compDbgEnC currently also causes the security object to be generated. See Compiler::compCompile)
8051 if (opts.compNeedSecurityCheck)
8053 noway_assert(lvaSecurityObject == BAD_VAR_NUM);
8054 lvaSecurityObject = lvaGrabTempWithImplicitUse(false DEBUGARG("security check"));
8055 lvaTable[lvaSecurityObject].lvType = TYP_REF;
8058 /* Assume we will generate a single shared return sequence */
8060 ULONG returnWeight = 0;
8065 // We will generate just one epilog (return block)
8066 // when we are asked to generate enter/leave callbacks
8067 // or for methods with PInvoke
8068 // or for methods calling into unmanaged code
8069 // or for synchronized methods.
8071 if (compIsProfilerHookNeeded() || (info.compCallUnmanaged != 0) || opts.IsReversePInvoke() ||
8072 ((info.compFlags & CORINFO_FLG_SYNCH) != 0))
8074 // We will generate only one return block
8075 // We will transform the BBJ_RETURN blocks
8076 // into jumps to the one return block
8079 allProfWeight = false;
8084 // We are allowed to have multiple individual exits
8085 // However we can still decide to have a single return
8088 allProfWeight = true;
8090 // Count the BBJ_RETURN blocks and set the returnWeight to the
8091 // sum of all these blocks.
8094 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
8096 if (block->bbJumpKind == BBJ_RETURN)
8099 // returnCount is the count of BBJ_RETURN blocks in this method
8103 // If all BBJ_RETURN blocks have a valid profiled weights
8104 // then allProfWeight will be true, else it is false
8106 if ((block->bbFlags & BBF_PROF_WEIGHT) == 0)
8108 allProfWeight = false;
8111 // returnWeight is the sum of the weights of all BBJ_RETURN blocks
8112 returnWeight += block->bbWeight;
8117 // If we only have one (or zero) return blocks then
8118 // we do not need a special one return block
8120 if (fgReturnCount > 1)
8123 // should we generate a single return block?
8125 if (fgReturnCount > 4)
8127 // Our epilog encoding only supports up to 4 epilogs
8128 // TODO-CQ: support >4 return points for ARM/AMD64, which presumably support any number of epilogs?
8132 else if (compCodeOpt() == SMALL_CODE)
8134 // For the Small_Code case we always generate a
8135 // single return block when we have multiple
8143 #if !defined(_TARGET_X86_)
8144 // Add the synchronized method enter/exit calls and try/finally protection. Note
8145 // that this must happen before the one BBJ_RETURN block is created below, so the
8146 // BBJ_RETURN block gets placed at the top-level, not within an EH region. (Otherwise,
8147 // we'd have to be really careful when creating the synchronized method try/finally
8148 // not to include the BBJ_RETURN block.)
8149 if ((info.compFlags & CORINFO_FLG_SYNCH) != 0)
8151 fgAddSyncMethodEnterExit();
8153 #endif // !_TARGET_X86_
8157 genReturnBB = fgNewBBinRegion(BBJ_RETURN);
8158 genReturnBB->bbRefs = 1; // bbRefs gets update later, for now it should be 1
8164 // if we have profile data for all BBJ_RETURN blocks
8165 // then we can set BBF_PROF_WEIGHT for genReturnBB
8167 genReturnBB->bbFlags |= BBF_PROF_WEIGHT;
8172 // We can't rely upon the calculated returnWeight unless
8173 // all of the BBJ_RETURN blocks had valid profile weights
8174 // So we will use the weight of the first block instead
8176 returnWeight = fgFirstBB->bbWeight;
8180 // Set the weight of the oneReturn block
8182 genReturnBB->bbWeight = min(returnWeight, BB_MAX_WEIGHT);
8184 if (returnWeight == 0)
8187 // If necessary set the Run Rarely flag
8189 genReturnBB->bbFlags |= BBF_RUN_RARELY;
8193 // Make sure that the RunRarely flag is clear
8194 // because fgNewBBinRegion will set it to true
8196 genReturnBB->bbFlags &= ~BBF_RUN_RARELY;
8199 genReturnBB->bbFlags |= (BBF_INTERNAL | BBF_DONT_REMOVE);
8201 noway_assert(genReturnBB->bbNext == nullptr);
8206 printf("\n genReturnBB [BB%02u] created\n", genReturnBB->bbNum);
8213 // We don't have a oneReturn block for this method
8215 genReturnBB = nullptr;
8218 // If there is a return value, then create a temp for it. Real returns will store the value in there and
8219 // it'll be reloaded by the single return.
8220 if (genReturnBB && compMethodHasRetVal())
8222 genReturnLocal = lvaGrabTemp(true DEBUGARG("Single return block return value"));
8224 if (compMethodReturnsNativeScalarType())
8226 lvaTable[genReturnLocal].lvType = genActualType(info.compRetNativeType);
8228 else if (compMethodReturnsRetBufAddr())
8230 lvaTable[genReturnLocal].lvType = TYP_BYREF;
8232 else if (compMethodReturnsMultiRegRetType())
8234 lvaTable[genReturnLocal].lvType = TYP_STRUCT;
8235 lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true);
8236 lvaTable[genReturnLocal].lvIsMultiRegRet = true;
8240 assert(!"unreached");
8243 if (varTypeIsFloating(lvaTable[genReturnLocal].lvType))
8245 this->compFloatingPointUsed = true;
8248 if (!varTypeIsFloating(info.compRetType))
8250 lvaTable[genReturnLocal].setPrefReg(REG_INTRET, this);
8255 lvaTable[genReturnLocal].setPrefReg(REG_FLOATRET, this);
8260 // This temporary should not be converted to a double in stress mode,
8261 // because we introduce assigns to it after the stress conversion
8262 lvaTable[genReturnLocal].lvKeepType = 1;
8267 genReturnLocal = BAD_VAR_NUM;
8270 if (info.compCallUnmanaged != 0)
8272 // The P/Invoke helpers only require a frame variable, so only allocate the
8273 // TCB variable if we're not using them.
8274 if (!opts.ShouldUsePInvokeHelpers())
8276 info.compLvFrameListRoot = lvaGrabTemp(false DEBUGARG("Pinvoke FrameListRoot"));
8279 lvaInlinedPInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Pinvoke FrameVar"));
8281 LclVarDsc* varDsc = &lvaTable[lvaInlinedPInvokeFrameVar];
8282 varDsc->addPrefReg(RBM_PINVOKE_TCB, this);
8283 varDsc->lvType = TYP_BLK;
8284 // Make room for the inlined frame.
8285 varDsc->lvExactSize = eeGetEEInfo()->inlinedCallFrameInfo.size;
8286 #if FEATURE_FIXED_OUT_ARGS
8287 // Grab and reserve space for TCB, Frame regs used in PInvoke epilog to pop the inlined frame.
8288 // See genPInvokeMethodEpilog() for use of the grabbed var. This is only necessary if we are
8289 // not using the P/Invoke helpers.
8290 if (!opts.ShouldUsePInvokeHelpers() && compJmpOpUsed)
8292 lvaPInvokeFrameRegSaveVar = lvaGrabTempWithImplicitUse(false DEBUGARG("PInvokeFrameRegSave Var"));
8293 varDsc = &lvaTable[lvaPInvokeFrameRegSaveVar];
8294 varDsc->lvType = TYP_BLK;
8295 varDsc->lvExactSize = 2 * REGSIZE_BYTES;
8300 // Do we need to insert a "JustMyCode" callback?
8302 CORINFO_JUST_MY_CODE_HANDLE* pDbgHandle = nullptr;
8303 CORINFO_JUST_MY_CODE_HANDLE dbgHandle = nullptr;
8304 if (opts.compDbgCode && !(opts.eeFlags & CORJIT_FLG_IL_STUB))
8306 dbgHandle = info.compCompHnd->getJustMyCodeHandle(info.compMethodHnd, &pDbgHandle);
8309 #ifdef _TARGET_ARM64_
8310 // TODO-ARM64-NYI: don't do just-my-code
8311 dbgHandle = nullptr;
8312 pDbgHandle = nullptr;
8313 #endif // _TARGET_ARM64_
8315 noway_assert(!dbgHandle || !pDbgHandle);
8317 if (dbgHandle || pDbgHandle)
8319 GenTreePtr guardCheckVal =
8320 gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode(dbgHandle, pDbgHandle, GTF_ICON_TOKEN_HDL));
8321 GenTreePtr guardCheckCond = gtNewOperNode(GT_EQ, TYP_INT, guardCheckVal, gtNewZeroConNode(TYP_INT));
8322 guardCheckCond->gtFlags |= GTF_RELOP_QMARK;
8324 // Create the callback which will yield the final answer
8326 GenTreePtr callback = gtNewHelperCallNode(CORINFO_HELP_DBG_IS_JUST_MY_CODE, TYP_VOID);
8327 callback = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), callback);
8329 // Stick the conditional call at the start of the method
8331 fgEnsureFirstBBisScratch();
8332 fgInsertStmtAtEnd(fgFirstBB, gtNewQmarkNode(TYP_VOID, guardCheckCond, callback));
8335 /* Do we need to call out for security ? */
8337 if (tiSecurityCalloutNeeded)
8339 // We must have grabbed this local.
8340 noway_assert(opts.compNeedSecurityCheck);
8341 noway_assert(lvaSecurityObject != BAD_VAR_NUM);
8345 /* Insert the expression "call JIT_Security_Prolog(MethodHnd, &SecurityObject)" */
8347 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
8349 tree = gtNewHelperCallNode(info.compCompHnd->getSecurityPrologHelper(info.compMethodHnd), TYP_VOID, 0,
8350 gtNewArgList(tree, gtNewOperNode(GT_ADDR, TYP_BYREF,
8351 gtNewLclvNode(lvaSecurityObject, TYP_REF))));
8353 /* Create a new basic block and stick the call in it */
8355 fgEnsureFirstBBisScratch();
8357 fgInsertStmtAtEnd(fgFirstBB, tree);
8362 printf("\ntiSecurityCalloutNeeded - Add call JIT_Security_Prolog(%08p) statement ",
8363 dspPtr(info.compMethodHnd));
8365 printf(" in first basic block [%08p]\n", dspPtr(fgFirstBB));
8372 #if defined(_TARGET_X86_)
8374 /* Is this a 'synchronized' method? */
8376 if (info.compFlags & CORINFO_FLG_SYNCH)
8378 GenTreePtr tree = NULL;
8380 /* Insert the expression "enterCrit(this)" or "enterCrit(handle)" */
8382 if (info.compIsStatic)
8384 tree = fgGetCritSectOfStaticMethod();
8386 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER_STATIC, TYP_VOID, 0, gtNewArgList(tree));
8390 noway_assert(lvaTable[info.compThisArg].lvType == TYP_REF);
8392 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
8394 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER, TYP_VOID, 0, gtNewArgList(tree));
8397 /* Create a new basic block and stick the call in it */
8399 fgEnsureFirstBBisScratch();
8401 fgInsertStmtAtEnd(fgFirstBB, tree);
8406 printf("\nSynchronized method - Add enterCrit statement in first basic block [%08p]\n", dspPtr(fgFirstBB));
8412 /* We must be generating a single exit point for this to work */
8414 noway_assert(oneReturn);
8415 noway_assert(genReturnBB);
8417 /* Create the expression "exitCrit(this)" or "exitCrit(handle)" */
8419 if (info.compIsStatic)
8421 tree = fgGetCritSectOfStaticMethod();
8423 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, 0, gtNewArgList(tree));
8427 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
8429 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT, TYP_VOID, 0, gtNewArgList(tree));
8432 fgInsertStmtAtEnd(genReturnBB, tree);
8437 printf("\nSynchronized method - Add exit expression ");
8443 // Reset cookies used to track start and end of the protected region in synchronized methods
8444 syncStartEmitCookie = NULL;
8445 syncEndEmitCookie = NULL;
8448 #endif // _TARGET_X86_
8450 /* Do we need to do runtime call out to check the security? */
8452 if (tiRuntimeCalloutNeeded)
8456 /* Insert the expression "call verificationRuntimeCheck(MethodHnd)" */
8458 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
8460 tree = gtNewHelperCallNode(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, TYP_VOID, 0, gtNewArgList(tree));
8462 /* Create a new basic block and stick the call in it */
8464 fgEnsureFirstBBisScratch();
8466 fgInsertStmtAtEnd(fgFirstBB, tree);
8471 printf("\ntiRuntimeCalloutNeeded - Call verificationRuntimeCheck(%08p) statement in first basic block "
8473 dspPtr(info.compMethodHnd), dspPtr(fgFirstBB));
8480 if (opts.IsReversePInvoke())
8482 fgAddReversePInvokeEnterExit();
8486 // Add 'return' expression to the return block if we made it as "oneReturn" before.
8493 // Make the 'return' expression.
8496 // make sure to reload the return value as part of the return (it is saved by the "real return").
8497 if (genReturnLocal != BAD_VAR_NUM)
8499 noway_assert(compMethodHasRetVal());
8501 GenTreePtr retTemp = gtNewLclvNode(genReturnLocal, lvaTable[genReturnLocal].TypeGet());
8503 // make sure copy prop ignores this node (make sure it always does a reload from the temp).
8504 retTemp->gtFlags |= GTF_DONT_CSE;
8505 tree = gtNewOperNode(GT_RETURN, retTemp->gtType, retTemp);
8509 noway_assert(info.compRetType == TYP_VOID || varTypeIsStruct(info.compRetType));
8511 tree = new (this, GT_RETURN) GenTreeOp(GT_RETURN, TYP_VOID);
8514 /* Add 'return' expression to the return block */
8516 noway_assert(genReturnBB);
8518 fgInsertStmtAtEnd(genReturnBB, tree);
8523 printf("\noneReturn statement tree ");
8525 printf(" added to genReturnBB [%08p]\n", dspPtr(genReturnBB));
8535 printf("\n*************** After fgAddInternal()\n");
8536 fgDispBasicBlocks();
8542 /*****************************************************************************
8544 * Create a new statement from tree and wire the links up.
8546 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs)
8548 GenTreeStmt* stmt = gtNewStmt(tree, offs);
8549 gtSetStmtInfo(stmt);
8553 if (block != nullptr)
8555 fgDebugCheckNodeLinks(block, stmt);
8562 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree)
8564 return fgNewStmtFromTree(tree, nullptr, BAD_IL_OFFSET);
8567 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block)
8569 return fgNewStmtFromTree(tree, block, BAD_IL_OFFSET);
8572 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, IL_OFFSETX offs)
8574 return fgNewStmtFromTree(tree, nullptr, offs);
8577 //------------------------------------------------------------------------
8578 // fgFindBlockILOffset: Given a block, find the IL offset corresponding to the first statement
8579 // in the block with a legal IL offset. Skip any leading statements that have BAD_IL_OFFSET.
8580 // If no statement has an initialized statement offset (including the case where there are
8581 // no statements in the block), then return BAD_IL_OFFSET. This function is used when
8582 // blocks are split or modified, and we want to maintain the IL offset as much as possible
8583 // to preserve good debugging behavior.
8586 // block - The block to check.
8589 // The first good IL offset of a statement in the block, or BAD_IL_OFFSET if such an IL offset
8592 // If we are not built with DEBUGGING_SUPPORT or DEBUG, then always report BAD_IL_OFFSET,
8593 // since in that case statements don't contain an IL offset. The effect will be that split
8594 // blocks will lose their IL offset information.
8596 IL_OFFSET Compiler::fgFindBlockILOffset(BasicBlock* block)
8598 // This function searches for IL offsets in statement nodes, so it can't be used in LIR. We
8599 // could have a similar function for LIR that searches for GT_IL_OFFSET nodes.
8600 assert(!block->IsLIR());
8602 #if defined(DEBUGGING_SUPPORT) || defined(DEBUG)
8603 for (GenTree* stmt = block->bbTreeList; stmt != nullptr; stmt = stmt->gtNext)
8605 assert(stmt->IsStatement());
8606 if (stmt->gtStmt.gtStmtILoffsx != BAD_IL_OFFSET)
8608 return jitGetILoffs(stmt->gtStmt.gtStmtILoffsx);
8611 #endif // defined(DEBUGGING_SUPPORT) || defined(DEBUG)
8613 return BAD_IL_OFFSET;
8616 //------------------------------------------------------------------------------
8617 // fgSplitBlockAtEnd - split the given block into two blocks.
8618 // All code in the block stays in the original block.
8619 // Control falls through from original to new block, and
8620 // the new block is returned.
8621 //------------------------------------------------------------------------------
8622 BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr)
8624 // We'd like to use fgNewBBafter(), but we need to update the preds list before linking in the new block.
8625 // (We need the successors of 'curr' to be correct when we do this.)
8626 BasicBlock* newBlock = bbNewBasicBlock(curr->bbJumpKind);
8628 // Start the new block with no refs. When we set the preds below, this will get updated correctly.
8629 newBlock->bbRefs = 0;
8631 // For each successor of the original block, set the new block as their predecessor.
8632 // Note we are using the "rational" version of the successor iterator that does not hide the finallyret arcs.
8633 // Without these arcs, a block 'b' may not be a member of succs(preds(b))
8634 if (curr->bbJumpKind != BBJ_SWITCH)
8636 unsigned numSuccs = curr->NumSucc(this);
8637 for (unsigned i = 0; i < numSuccs; i++)
8639 BasicBlock* succ = curr->GetSucc(i, this);
8640 if (succ != newBlock)
8642 JITDUMP("BB%02u previous predecessor was BB%02u, now is BB%02u\n", succ->bbNum, curr->bbNum,
8644 fgReplacePred(succ, curr, newBlock);
8648 newBlock->bbJumpDest = curr->bbJumpDest;
8649 curr->bbJumpDest = nullptr;
8653 // In the case of a switch statement there's more complicated logic in order to wire up the predecessor lists
8654 // but fortunately there's an existing method that implements this functionality.
8655 newBlock->bbJumpSwt = curr->bbJumpSwt;
8657 fgChangeSwitchBlock(curr, newBlock);
8659 curr->bbJumpSwt = nullptr;
8662 newBlock->inheritWeight(curr);
8664 // Set the new block's flags. Note that the new block isn't BBF_INTERNAL unless the old block is.
8665 newBlock->bbFlags = curr->bbFlags;
8667 // Remove flags that the new block can't have.
8668 newBlock->bbFlags &= ~(BBF_TRY_BEG | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1 | BBF_HAS_LABEL |
8669 BBF_JMP_TARGET | BBF_FUNCLET_BEG | BBF_LOOP_PREHEADER | BBF_KEEP_BBJ_ALWAYS);
8671 // Remove the GC safe bit on the new block. It seems clear that if we split 'curr' at the end,
8672 // such that all the code is left in 'curr', and 'newBlock' just gets the control flow, then
8673 // both 'curr' and 'newBlock' could accurately retain an existing GC safe bit. However, callers
8674 // use this function to split blocks in the middle, or at the beginning, and they don't seem to
8675 // be careful about updating this flag appropriately. So, removing the GC safe bit is simply
8676 // conservative: some functions might end up being fully interruptible that could be partially
8677 // interruptible if we exercised more care here.
8678 newBlock->bbFlags &= ~BBF_GC_SAFE_POINT;
8680 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
8681 newBlock->bbFlags &= ~(BBF_FINALLY_TARGET);
8682 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
8684 // The new block has no code, so we leave bbCodeOffs/bbCodeOffsEnd set to BAD_IL_OFFSET. If a caller
8685 // puts code in the block, then it needs to update these.
8687 // Insert the new block in the block list after the 'curr' block.
8688 fgInsertBBafter(curr, newBlock);
8689 fgExtendEHRegionAfter(curr); // The new block is in the same EH region as the old block.
8691 // Remove flags from the old block that are no longer possible.
8692 curr->bbFlags &= ~(BBF_HAS_JMP | BBF_RETLESS_CALL);
8694 // Default to fallthru, and add the arc for that.
8695 curr->bbJumpKind = BBJ_NONE;
8696 fgAddRefPred(newBlock, curr);
8701 //------------------------------------------------------------------------------
8702 // fgSplitBlockAfterStatement - Split the given block, with all code after
8703 // the given statement going into the second block.
8704 //------------------------------------------------------------------------------
8705 BasicBlock* Compiler::fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt)
8707 assert(!curr->IsLIR()); // No statements in LIR, so you can't use this function.
8709 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8713 newBlock->bbTreeList = stmt->gtNext;
8714 if (newBlock->bbTreeList)
8716 newBlock->bbTreeList->gtPrev = curr->bbTreeList->gtPrev;
8718 curr->bbTreeList->gtPrev = stmt;
8719 stmt->gtNext = nullptr;
8721 // Update the IL offsets of the blocks to match the split.
8723 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
8724 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
8726 // curr->bbCodeOffs remains the same
8727 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8729 IL_OFFSET splitPointILOffset = fgFindBlockILOffset(newBlock);
8731 curr->bbCodeOffsEnd = splitPointILOffset;
8732 newBlock->bbCodeOffs = splitPointILOffset;
8736 assert(curr->bbTreeList == nullptr); // if no tree was given then it better be an empty block
8742 //------------------------------------------------------------------------------
8743 // fgSplitBlockAfterNode - Split the given block, with all code after
8744 // the given node going into the second block.
8745 // This function is only used in LIR.
8746 //------------------------------------------------------------------------------
8747 BasicBlock* Compiler::fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node)
8749 assert(curr->IsLIR());
8751 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8753 if (node != nullptr)
8755 LIR::Range& currBBRange = LIR::AsRange(curr);
8757 if (node != currBBRange.LastNode())
8759 LIR::Range nodesToMove = currBBRange.Remove(node->gtNext, currBBRange.LastNode());
8760 LIR::AsRange(newBlock).InsertAtBeginning(std::move(nodesToMove));
8763 // Update the IL offsets of the blocks to match the split.
8765 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
8766 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
8768 // curr->bbCodeOffs remains the same
8769 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8771 // Search backwards from the end of the current block looking for the IL offset to use
8772 // for the end IL offset for the original block.
8773 IL_OFFSET splitPointILOffset = BAD_IL_OFFSET;
8774 LIR::Range::ReverseIterator riter;
8775 LIR::Range::ReverseIterator riterEnd;
8776 for (riter = currBBRange.rbegin(), riterEnd = currBBRange.rend(); riter != riterEnd; ++riter)
8778 if ((*riter)->gtOper == GT_IL_OFFSET)
8780 GenTreeStmt* stmt = (*riter)->AsStmt();
8781 if (stmt->gtStmtILoffsx != BAD_IL_OFFSET)
8783 splitPointILOffset = jitGetILoffs(stmt->gtStmtILoffsx);
8789 curr->bbCodeOffsEnd = splitPointILOffset;
8791 // Also use this as the beginning offset of the next block. Presumably we could/should
8792 // look to see if the first node is a GT_IL_OFFSET node, and use that instead.
8793 newBlock->bbCodeOffs = splitPointILOffset;
8797 assert(curr->bbTreeList == nullptr); // if no node was given then it better be an empty block
8803 //------------------------------------------------------------------------------
8804 // fgSplitBlockAtBeginning - Split the given block into two blocks.
8805 // Control falls through from original to new block,
8806 // and the new block is returned.
8807 // All code in the original block goes into the new block
8808 //------------------------------------------------------------------------------
8809 BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr)
8811 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8813 newBlock->bbTreeList = curr->bbTreeList;
8814 curr->bbTreeList = nullptr;
8816 // The new block now has all the code, and the old block has none. Update the
8817 // IL offsets for the block to reflect this.
8819 newBlock->bbCodeOffs = curr->bbCodeOffs;
8820 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8822 curr->bbCodeOffs = BAD_IL_OFFSET;
8823 curr->bbCodeOffsEnd = BAD_IL_OFFSET;
8828 //------------------------------------------------------------------------
8829 // fgSplitEdge: Splits the edge between a block 'curr' and its successor 'succ' by creating a new block
8830 // that replaces 'succ' as a successor of 'curr', and which branches unconditionally
8831 // to (or falls through to) 'succ'. Note that for a BBJ_COND block 'curr',
8832 // 'succ' might be the fall-through path or the branch path from 'curr'.
8835 // curr - A block which branches conditionally to 'succ'
8836 // succ - The target block
8839 // Returns a new block, that is a successor of 'curr' and which branches unconditionally to 'succ'
8842 // 'curr' must have a bbJumpKind of BBJ_COND or BBJ_SWITCH
8845 // The returned block is empty.
8847 BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ)
8849 assert(curr->bbJumpKind == BBJ_COND || curr->bbJumpKind == BBJ_SWITCH);
8850 assert(fgGetPredForBlock(succ, curr) != nullptr);
8852 BasicBlock* newBlock;
8853 if (succ == curr->bbNext)
8855 // The successor is the fall-through path of a BBJ_COND, or
8856 // an immediately following block of a BBJ_SWITCH (which has
8857 // no fall-through path). For this case, simply insert a new
8858 // fall-through block after 'curr'.
8859 newBlock = fgNewBBafter(BBJ_NONE, curr, true /*extendRegion*/);
8863 newBlock = fgNewBBinRegion(BBJ_ALWAYS, curr, curr->isRunRarely());
8864 // The new block always jumps to 'succ'
8865 newBlock->bbJumpDest = succ;
8867 newBlock->bbFlags |= (curr->bbFlags & succ->bbFlags & (BBF_BACKWARD_JUMP));
8869 JITDUMP("Splitting edge from BB%02u to BB%02u; adding BB%02u\n", curr->bbNum, succ->bbNum, newBlock->bbNum);
8871 if (curr->bbJumpKind == BBJ_COND)
8873 fgReplacePred(succ, curr, newBlock);
8874 if (curr->bbJumpDest == succ)
8876 // Now 'curr' jumps to newBlock
8877 curr->bbJumpDest = newBlock;
8878 newBlock->bbFlags |= BBF_JMP_TARGET;
8880 fgAddRefPred(newBlock, curr);
8884 assert(curr->bbJumpKind == BBJ_SWITCH);
8886 // newBlock replaces 'succ' in the switch.
8887 fgReplaceSwitchJumpTarget(curr, newBlock, succ);
8889 // And 'succ' has 'newBlock' as a new predecessor.
8890 fgAddRefPred(succ, newBlock);
8893 // This isn't accurate, but it is complex to compute a reasonable number so just assume that we take the
8894 // branch 50% of the time.
8895 newBlock->inheritWeightPercentage(curr, 50);
8897 // The bbLiveIn and bbLiveOut are both equal to the bbLiveIn of 'succ'
8898 if (fgLocalVarLivenessDone)
8900 VarSetOps::Assign(this, newBlock->bbLiveIn, succ->bbLiveIn);
8901 VarSetOps::Assign(this, newBlock->bbLiveOut, succ->bbLiveIn);
8907 /*****************************************************************************/
8908 /*****************************************************************************/
8910 void Compiler::fgFindOperOrder()
8915 printf("*************** In fgFindOperOrder()\n");
8922 /* Walk the basic blocks and for each statement determine
8923 * the evaluation order, cost, FP levels, etc... */
8925 for (block = fgFirstBB; block; block = block->bbNext)
8928 for (stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8930 /* Recursively process the statement */
8933 gtSetStmtInfo(stmt);
8938 /*****************************************************************************/
8939 void Compiler::fgSimpleLowering()
8941 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
8943 // Walk the statement trees in this basic block, converting ArrLength nodes.
8944 compCurBB = block; // Used in fgRngChkTarget.
8946 #ifdef LEGACY_BACKEND
8947 for (GenTreeStmt* stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNextStmt)
8949 for (GenTreePtr tree = stmt->gtStmtList; tree; tree = tree->gtNext)
8952 LIR::Range& range = LIR::AsRange(block);
8953 for (GenTree* tree : range)
8957 if (tree->gtOper == GT_ARR_LENGTH)
8959 GenTreeArrLen* arrLen = tree->AsArrLen();
8960 GenTreePtr arr = arrLen->gtArrLen.ArrRef();
8964 /* Create the expression "*(array_addr + ArrLenOffs)" */
8966 noway_assert(arr->gtNext == tree);
8968 noway_assert(arrLen->ArrLenOffset() == offsetof(CORINFO_Array, length) ||
8969 arrLen->ArrLenOffset() == offsetof(CORINFO_String, stringLen));
8971 if ((arr->gtOper == GT_CNS_INT) && (arr->gtIntCon.gtIconVal == 0))
8973 // If the array is NULL, then we should get a NULL reference
8974 // exception when computing its length. We need to maintain
8975 // an invariant where there is no sum of two constants node, so
8976 // let's simply return an indirection of NULL.
8982 con = gtNewIconNode(arrLen->ArrLenOffset(), TYP_I_IMPL);
8983 con->gtRsvdRegs = 0;
8985 add = gtNewOperNode(GT_ADD, TYP_REF, arr, con);
8986 add->gtRsvdRegs = arr->gtRsvdRegs;
8988 #ifdef LEGACY_BACKEND
8989 con->gtCopyFPlvl(arr);
8991 add->gtCopyFPlvl(arr);
8992 add->CopyCosts(arr);
9003 range.InsertAfter(arr, con, add);
9007 // Change to a GT_IND.
9008 tree->ChangeOperUnchecked(GT_IND);
9010 tree->gtOp.gtOp1 = add;
9012 else if (tree->OperGet() == GT_ARR_BOUNDS_CHECK
9014 || tree->OperGet() == GT_SIMD_CHK
9015 #endif // FEATURE_SIMD
9018 // Add in a call to an error routine.
9019 fgSetRngChkTarget(tree, false);
9026 if (verbose && fgRngChkThrowAdded)
9028 printf("\nAfter fgSimpleLowering() added some RngChk throw blocks");
9029 fgDispBasicBlocks();
9036 /*****************************************************************************
9039 void Compiler::fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTreePtr clonedTree)
9041 assert(clonedTree->gtOper != GT_STMT);
9043 if (lvaLocalVarRefCounted)
9045 compCurBB = addedToBlock;
9046 fgWalkTreePre(&clonedTree, Compiler::lvaIncRefCntsCB, (void*)this, true);
9050 /*****************************************************************************
9053 void Compiler::fgUpdateRefCntForExtract(GenTreePtr wholeTree, GenTreePtr keptTree)
9055 if (lvaLocalVarRefCounted)
9057 /* Update the refCnts of removed lcl vars - The problem is that
9058 * we have to consider back the side effects trees so we first
9059 * increment all refCnts for side effects then decrement everything
9064 fgWalkTreePre(&keptTree, Compiler::lvaIncRefCntsCB, (void*)this, true);
9067 fgWalkTreePre(&wholeTree, Compiler::lvaDecRefCntsCB, (void*)this, true);
9071 VARSET_VALRET_TP Compiler::fgGetVarBits(GenTreePtr tree)
9073 VARSET_TP VARSET_INIT_NOCOPY(varBits, VarSetOps::MakeEmpty(this));
9075 assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_REG_VAR);
9077 unsigned int lclNum = tree->gtLclVarCommon.gtLclNum;
9078 LclVarDsc* varDsc = lvaTable + lclNum;
9079 if (varDsc->lvTracked)
9081 VarSetOps::AddElemD(this, varBits, varDsc->lvVarIndex);
9083 else if (varDsc->lvType == TYP_STRUCT && varDsc->lvPromoted)
9085 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
9087 noway_assert(lvaTable[i].lvIsStructField);
9088 if (lvaTable[i].lvTracked)
9090 unsigned varIndex = lvaTable[i].lvVarIndex;
9091 noway_assert(varIndex < lvaTrackedCount);
9092 VarSetOps::AddElemD(this, varBits, varIndex);
9099 /*****************************************************************************
9101 * Find and remove any basic blocks that are useless (e.g. they have not been
9102 * imported because they are not reachable, or they have been optimized away).
9105 void Compiler::fgRemoveEmptyBlocks()
9110 /* If we remove any blocks, we'll have to do additional work */
9112 unsigned removedBlks = 0;
9114 for (cur = fgFirstBB; cur != nullptr; cur = nxt)
9116 /* Get hold of the next block (in case we delete 'cur') */
9120 /* Should this block be removed? */
9122 if (!(cur->bbFlags & BBF_IMPORTED))
9124 noway_assert(cur->isEmpty());
9126 if (ehCanDeleteEmptyBlock(cur))
9128 /* Mark the block as removed */
9130 cur->bbFlags |= BBF_REMOVED;
9132 /* Remember that we've removed a block from the list */
9139 printf("BB%02u was not imported, marked as removed (%d)\n", cur->bbNum, removedBlks);
9143 /* Drop the block from the list */
9149 // We were prevented from deleting this block by EH normalization. Mark the block as imported.
9150 cur->bbFlags |= BBF_IMPORTED;
9155 /* If no blocks were removed, we're done */
9157 if (removedBlks == 0)
9162 /* Update all references in the exception handler table.
9163 * Mark the new blocks as non-removable.
9165 * We may have made the entire try block unreachable.
9166 * Check for this case and remove the entry from the EH table.
9171 INDEBUG(unsigned delCnt = 0;)
9173 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
9176 /* If the beginning of the try block was not imported, we
9177 * need to remove the entry from the EH table. */
9179 if (HBtab->ebdTryBeg->bbFlags & BBF_REMOVED)
9181 noway_assert(!(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED));
9185 printf("Beginning of try block (BB%02u) not imported "
9186 "- remove index #%u from the EH table\n",
9187 HBtab->ebdTryBeg->bbNum, XTnum + delCnt);
9192 fgRemoveEHTableEntry(XTnum);
9194 if (XTnum < compHndBBtabCount)
9196 // There are more entries left to process, so do more. Note that
9197 // HBtab now points to the next entry, that we copied down to the
9198 // current slot. XTnum also stays the same.
9202 break; // no more entries (we deleted the last one), so exit the loop
9205 /* At this point we know we have a valid try block */
9208 assert(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED);
9209 assert(HBtab->ebdTryBeg->bbFlags & BBF_DONT_REMOVE);
9211 assert(HBtab->ebdHndBeg->bbFlags & BBF_IMPORTED);
9212 assert(HBtab->ebdHndBeg->bbFlags & BBF_DONT_REMOVE);
9214 if (HBtab->HasFilter())
9216 assert(HBtab->ebdFilter->bbFlags & BBF_IMPORTED);
9217 assert(HBtab->ebdFilter->bbFlags & BBF_DONT_REMOVE);
9221 fgSkipRmvdBlocks(HBtab);
9222 } /* end of the for loop over XTnum */
9224 // Renumber the basic blocks
9225 JITDUMP("\nRenumbering the basic blocks for fgRemoveEmptyBlocks\n");
9229 fgVerifyHandlerTab();
9233 /*****************************************************************************
9235 * Remove a useless statement from a basic block.
9236 * The default is to decrement ref counts of included vars
9240 void Compiler::fgRemoveStmt(BasicBlock* block,
9242 // whether to decrement ref counts for tracked vars in statement
9243 bool updateRefCount)
9246 assert(fgOrder == FGOrderTree);
9248 GenTreeStmt* tree = block->firstStmt();
9249 GenTreeStmt* stmt = node->AsStmt();
9253 stmt->gtStmtExpr->gtOper != GT_NOP) // Don't print if it is a GT_NOP. Too much noise from the inliner.
9255 printf("\nRemoving statement ");
9257 printf(" in BB%02u as useless:\n", block->bbNum);
9262 if (opts.compDbgCode && stmt->gtPrev != stmt && stmt->gtStmtILoffsx != BAD_IL_OFFSET)
9264 /* TODO: For debuggable code, should we remove significant
9265 statement boundaries. Or should we leave a GT_NO_OP in its place? */
9268 /* Is it the first statement in the list? */
9270 GenTreeStmt* firstStmt = block->firstStmt();
9271 if (firstStmt == stmt)
9273 if (firstStmt->gtNext == nullptr)
9275 assert(firstStmt == block->lastStmt());
9277 /* this is the only statement - basic block becomes empty */
9278 block->bbTreeList = nullptr;
9282 block->bbTreeList = tree->gtNext;
9283 block->bbTreeList->gtPrev = tree->gtPrev;
9288 /* Is it the last statement in the list? */
9290 if (stmt == block->lastStmt())
9292 stmt->gtPrev->gtNext = nullptr;
9293 block->bbTreeList->gtPrev = stmt->gtPrev;
9297 tree = stmt->gtPrevStmt;
9300 tree->gtNext = stmt->gtNext;
9301 stmt->gtNext->gtPrev = tree;
9304 fgStmtRemoved = true;
9306 if (optValnumCSE_phase)
9308 optValnumCSE_UnmarkCSEs(stmt->gtStmtExpr, nullptr);
9314 if (fgStmtListThreaded)
9316 fgWalkTreePre(&stmt->gtStmtExpr, Compiler::lvaDecRefCntsCB, (void*)this, true);
9324 if (block->bbTreeList == nullptr)
9326 printf("\nBB%02u becomes empty", block->bbNum);
9333 /******************************************************************************/
9334 // Returns true if the operator is involved in control-flow
9335 // TODO-Cleanup: Move this into genTreeKinds in genTree.h
9337 inline bool OperIsControlFlow(genTreeOps oper)
9350 #if !FEATURE_EH_FUNCLETS
9352 #endif // !FEATURE_EH_FUNCLETS
9360 /******************************************************************************
9361 * Tries to throw away a stmt. The statement can be anywhere in block->bbTreeList.
9362 * Returns true if it did remove the statement.
9365 bool Compiler::fgCheckRemoveStmt(BasicBlock* block, GenTreePtr node)
9367 if (opts.compDbgCode)
9372 GenTreeStmt* stmt = node->AsStmt();
9374 GenTreePtr tree = stmt->gtStmtExpr;
9375 genTreeOps oper = tree->OperGet();
9377 if (OperIsControlFlow(oper) || oper == GT_NO_OP)
9382 // TODO: Use a recursive version of gtNodeHasSideEffects()
9383 if (tree->gtFlags & GTF_SIDE_EFFECT)
9388 fgRemoveStmt(block, stmt);
9392 /****************************************************************************************************
9396 bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext)
9398 if ((block == nullptr) || (bNext == nullptr))
9403 noway_assert(block->bbNext == bNext);
9405 if (block->bbJumpKind != BBJ_NONE)
9410 // If the next block has multiple incoming edges, we can still compact if the first block is empty.
9411 // However, not if it is the beginning of a handler.
9412 if (bNext->countOfInEdges() != 1 &&
9413 (!block->isEmpty() || (block->bbFlags & BBF_FUNCLET_BEG) || (block->bbCatchTyp != BBCT_NONE)))
9418 if (bNext->bbFlags & BBF_DONT_REMOVE)
9423 // Don't compact the first block if it was specially created as a scratch block.
9424 if (fgBBisScratch(block))
9429 #if defined(_TARGET_ARM_)
9430 // We can't compact a finally target block, as we need to generate special code for such blocks during code
9432 if ((bNext->bbFlags & BBF_FINALLY_TARGET) != 0)
9436 // We don't want to compact blocks that are in different Hot/Cold regions
9438 if (fgInDifferentRegions(block, bNext))
9443 // We cannot compact two blocks in different EH regions.
9445 if (fgCanRelocateEHRegions)
9447 if (!BasicBlock::sameEHRegion(block, bNext))
9452 // if there is a switch predecessor don't bother because we'd have to update the uniquesuccs as well
9453 // (if they are valid)
9454 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
9456 if (pred->flBlock->bbJumpKind == BBJ_SWITCH)
9465 /*****************************************************************************************************
9467 * Function called to compact two given blocks in the flowgraph
9468 * Assumes that all necessary checks have been performed,
9469 * i.e. fgCanCompactBlocks returns true.
9471 * Uses for this function - whenever we change links, insert blocks,...
9472 * It will keep the flowgraph data in synch - bbNum, bbRefs, bbPreds
9475 void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext)
9477 noway_assert(block != nullptr);
9478 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
9479 noway_assert(block->bbJumpKind == BBJ_NONE);
9481 noway_assert(bNext == block->bbNext);
9482 noway_assert(bNext != nullptr);
9483 noway_assert((bNext->bbFlags & BBF_REMOVED) == 0);
9484 noway_assert(bNext->countOfInEdges() == 1 || block->isEmpty());
9485 noway_assert(bNext->bbPreds);
9487 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9488 noway_assert((bNext->bbFlags & BBF_FINALLY_TARGET) == 0);
9489 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9491 // Make sure the second block is not the start of a TRY block or an exception handler
9493 noway_assert(bNext->bbCatchTyp == BBCT_NONE);
9494 noway_assert((bNext->bbFlags & BBF_TRY_BEG) == 0);
9495 noway_assert((bNext->bbFlags & BBF_DONT_REMOVE) == 0);
9497 /* both or none must have an exception handler */
9498 noway_assert(block->hasTryIndex() == bNext->hasTryIndex());
9503 printf("\nCompacting blocks BB%02u and BB%02u:\n", block->bbNum, bNext->bbNum);
9507 if (bNext->countOfInEdges() > 1)
9509 JITDUMP("Second block has multiple incoming edges\n");
9511 assert(block->isEmpty());
9512 block->bbFlags |= BBF_JMP_TARGET;
9513 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
9515 fgReplaceJumpTarget(pred->flBlock, block, bNext);
9517 if (pred->flBlock != block)
9519 fgAddRefPred(block, pred->flBlock);
9522 bNext->bbPreds = nullptr;
9526 noway_assert(bNext->bbPreds->flNext == nullptr);
9527 noway_assert(bNext->bbPreds->flBlock == block);
9530 /* Start compacting - move all the statements in the second block to the first block */
9532 // First move any phi definitions of the second block after the phi defs of the first.
9533 // TODO-CQ: This may be the wrong thing to do. If we're compacting blocks, it's because a
9534 // control-flow choice was constant-folded away. So probably phi's need to go away,
9535 // as well, in favor of one of the incoming branches. Or at least be modified.
9537 assert(block->IsLIR() == bNext->IsLIR());
9540 LIR::Range& blockRange = LIR::AsRange(block);
9541 LIR::Range& nextRange = LIR::AsRange(bNext);
9543 // Does the next block have any phis?
9544 GenTree* nextFirstNonPhi = nullptr;
9545 LIR::ReadOnlyRange nextPhis = nextRange.PhiNodes();
9546 if (!nextPhis.IsEmpty())
9548 GenTree* blockLastPhi = blockRange.LastPhiNode();
9549 nextFirstNonPhi = nextPhis.LastNode()->gtNext;
9551 LIR::Range phisToMove = nextRange.Remove(std::move(nextPhis));
9552 blockRange.InsertAfter(blockLastPhi, std::move(phisToMove));
9556 nextFirstNonPhi = nextRange.FirstNode();
9559 // Does the block have any other code?
9560 if (nextFirstNonPhi != nullptr)
9562 LIR::Range nextNodes = nextRange.Remove(nextFirstNonPhi, nextRange.LastNode());
9563 blockRange.InsertAtEnd(std::move(nextNodes));
9568 GenTreePtr blkNonPhi1 = block->FirstNonPhiDef();
9569 GenTreePtr bNextNonPhi1 = bNext->FirstNonPhiDef();
9570 GenTreePtr blkFirst = block->firstStmt();
9571 GenTreePtr bNextFirst = bNext->firstStmt();
9573 // Does the second have any phis?
9574 if (bNextFirst != nullptr && bNextFirst != bNextNonPhi1)
9576 GenTreePtr bNextLast = bNextFirst->gtPrev;
9577 assert(bNextLast->gtNext == nullptr);
9579 // Does "blk" have phis?
9580 if (blkNonPhi1 != blkFirst)
9583 // Insert after the last phi of "block."
9584 // First, bNextPhis after last phi of block.
9585 GenTreePtr blkLastPhi;
9586 if (blkNonPhi1 != nullptr)
9588 blkLastPhi = blkNonPhi1->gtPrev;
9592 blkLastPhi = blkFirst->gtPrev;
9595 blkLastPhi->gtNext = bNextFirst;
9596 bNextFirst->gtPrev = blkLastPhi;
9598 // Now, rest of "block" after last phi of "bNext".
9599 GenTreePtr bNextLastPhi = nullptr;
9600 if (bNextNonPhi1 != nullptr)
9602 bNextLastPhi = bNextNonPhi1->gtPrev;
9606 bNextLastPhi = bNextFirst->gtPrev;
9609 bNextLastPhi->gtNext = blkNonPhi1;
9610 if (blkNonPhi1 != nullptr)
9612 blkNonPhi1->gtPrev = bNextLastPhi;
9616 // block has no non phis, so make the last statement be the last added phi.
9617 blkFirst->gtPrev = bNextLastPhi;
9620 // Now update the bbTreeList of "bNext".
9621 bNext->bbTreeList = bNextNonPhi1;
9622 if (bNextNonPhi1 != nullptr)
9624 bNextNonPhi1->gtPrev = bNextLast;
9629 if (blkFirst != nullptr) // If "block" has no statements, fusion will work fine...
9631 // First, bNextPhis at start of block.
9632 GenTreePtr blkLast = blkFirst->gtPrev;
9633 block->bbTreeList = bNextFirst;
9634 // Now, rest of "block" (if it exists) after last phi of "bNext".
9635 GenTreePtr bNextLastPhi = nullptr;
9636 if (bNextNonPhi1 != nullptr)
9638 // There is a first non phi, so the last phi is before it.
9639 bNextLastPhi = bNextNonPhi1->gtPrev;
9643 // All the statements are phi defns, so the last one is the prev of the first.
9644 bNextLastPhi = bNextFirst->gtPrev;
9646 bNextFirst->gtPrev = blkLast;
9647 bNextLastPhi->gtNext = blkFirst;
9648 blkFirst->gtPrev = bNextLastPhi;
9649 // Now update the bbTreeList of "bNext"
9650 bNext->bbTreeList = bNextNonPhi1;
9651 if (bNextNonPhi1 != nullptr)
9653 bNextNonPhi1->gtPrev = bNextLast;
9659 // Now proceed with the updated bbTreeLists.
9660 GenTreePtr stmtList1 = block->firstStmt();
9661 GenTreePtr stmtList2 = bNext->firstStmt();
9663 /* the block may have an empty list */
9667 GenTreePtr stmtLast1 = block->lastStmt();
9669 /* The second block may be a GOTO statement or something with an empty bbTreeList */
9672 GenTreePtr stmtLast2 = bNext->lastStmt();
9674 /* append list2 to list 1 */
9676 stmtLast1->gtNext = stmtList2;
9677 stmtList2->gtPrev = stmtLast1;
9678 stmtList1->gtPrev = stmtLast2;
9683 /* block was formerly empty and now has bNext's statements */
9684 block->bbTreeList = stmtList2;
9688 // Note we could update the local variable weights here by
9689 // calling lvaMarkLocalVars, with the block and weight adjustment.
9691 // If either block or bNext has a profile weight
9692 // or if both block and bNext have non-zero weights
9693 // then we select the highest weight block.
9695 if ((block->bbFlags & BBF_PROF_WEIGHT) || (bNext->bbFlags & BBF_PROF_WEIGHT) ||
9696 (block->bbWeight && bNext->bbWeight))
9698 // We are keeping block so update its fields
9699 // when bNext has a greater weight
9701 if (block->bbWeight < bNext->bbWeight)
9703 block->bbWeight = bNext->bbWeight;
9705 block->bbFlags |= (bNext->bbFlags & BBF_PROF_WEIGHT); // Set the profile weight flag (if necessary)
9706 if (block->bbWeight != 0)
9708 block->bbFlags &= ~BBF_RUN_RARELY; // Clear any RarelyRun flag
9712 // otherwise if either block has a zero weight we select the zero weight
9715 noway_assert((block->bbWeight == BB_ZERO_WEIGHT) || (bNext->bbWeight == BB_ZERO_WEIGHT));
9716 block->bbWeight = BB_ZERO_WEIGHT;
9717 block->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
9720 /* set the right links */
9722 block->bbJumpKind = bNext->bbJumpKind;
9723 VarSetOps::AssignAllowUninitRhs(this, block->bbLiveOut, bNext->bbLiveOut);
9725 // Update the beginning and ending IL offsets (bbCodeOffs and bbCodeOffsEnd).
9726 // Set the beginning IL offset to the minimum, and the ending offset to the maximum, of the respective blocks.
9727 // If one block has an unknown offset, we take the other block.
9728 // We are merging into 'block', so if its values are correct, just leave them alone.
9729 // TODO: we should probably base this on the statements within.
9731 if (block->bbCodeOffs == BAD_IL_OFFSET)
9733 block->bbCodeOffs = bNext->bbCodeOffs; // If they are both BAD_IL_OFFSET, this doesn't change anything.
9735 else if (bNext->bbCodeOffs != BAD_IL_OFFSET)
9737 // The are both valid offsets; compare them.
9738 if (block->bbCodeOffs > bNext->bbCodeOffs)
9740 block->bbCodeOffs = bNext->bbCodeOffs;
9744 if (block->bbCodeOffsEnd == BAD_IL_OFFSET)
9746 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd; // If they are both BAD_IL_OFFSET, this doesn't change anything.
9748 else if (bNext->bbCodeOffsEnd != BAD_IL_OFFSET)
9750 // The are both valid offsets; compare them.
9751 if (block->bbCodeOffsEnd < bNext->bbCodeOffsEnd)
9753 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd;
9757 if (((block->bbFlags & BBF_INTERNAL) != 0) && ((bNext->bbFlags & BBF_INTERNAL) == 0))
9759 // If 'block' is an internal block and 'bNext' isn't, then adjust the flags set on 'block'.
9760 block->bbFlags &= ~BBF_INTERNAL; // Clear the BBF_INTERNAL flag
9761 block->bbFlags |= BBF_IMPORTED; // Set the BBF_IMPORTED flag
9764 /* Update the flags for block with those found in bNext */
9766 block->bbFlags |= (bNext->bbFlags & BBF_COMPACT_UPD);
9768 /* mark bNext as removed */
9770 bNext->bbFlags |= BBF_REMOVED;
9772 /* Unlink bNext and update all the marker pointers if necessary */
9774 fgUnlinkRange(block->bbNext, bNext);
9776 // If bNext was the last block of a try or handler, update the EH table.
9778 ehUpdateForDeletedBlock(bNext);
9780 /* If we're collapsing a block created after the dominators are
9781 computed, rename the block and reuse dominator information from
9783 if (fgDomsComputed && block->bbNum > fgDomBBcount)
9785 BlockSetOps::Assign(this, block->bbReach, bNext->bbReach);
9786 BlockSetOps::ClearD(this, bNext->bbReach);
9788 block->bbIDom = bNext->bbIDom;
9789 bNext->bbIDom = nullptr;
9791 // In this case, there's no need to update the preorder and postorder numbering
9792 // since we're changing the bbNum, this makes the basic block all set.
9793 block->bbNum = bNext->bbNum;
9796 /* Set the jump targets */
9798 switch (bNext->bbJumpKind)
9800 case BBJ_CALLFINALLY:
9801 // Propagate RETLESS property
9802 block->bbFlags |= (bNext->bbFlags & BBF_RETLESS_CALL);
9808 case BBJ_EHCATCHRET:
9809 block->bbJumpDest = bNext->bbJumpDest;
9811 /* Update the predecessor list for 'bNext->bbJumpDest' */
9812 fgReplacePred(bNext->bbJumpDest, bNext, block);
9814 /* Update the predecessor list for 'bNext->bbNext' if it is different than 'bNext->bbJumpDest' */
9815 if (bNext->bbJumpKind == BBJ_COND && bNext->bbJumpDest != bNext->bbNext)
9817 fgReplacePred(bNext->bbNext, bNext, block);
9822 /* Update the predecessor list for 'bNext->bbNext' */
9823 fgReplacePred(bNext->bbNext, bNext, block);
9826 case BBJ_EHFILTERRET:
9827 fgReplacePred(bNext->bbJumpDest, bNext, block);
9830 case BBJ_EHFINALLYRET:
9832 unsigned hndIndex = block->getHndIndex();
9833 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
9835 if (ehDsc->HasFinallyHandler()) // No need to do this for fault handlers
9839 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
9841 BasicBlock* finBeg = ehDsc->ebdHndBeg;
9843 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
9845 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
9850 noway_assert(bcall->isBBCallAlwaysPair());
9851 fgReplacePred(bcall->bbNext, bNext, block);
9859 /* no jumps or fall through blocks to set here */
9863 block->bbJumpSwt = bNext->bbJumpSwt;
9864 // We are moving the switch jump from bNext to block. Examine the jump targets
9865 // of the BBJ_SWITCH at bNext and replace the predecessor to 'bNext' with ones to 'block'
9866 fgChangeSwitchBlock(bNext, block);
9870 noway_assert(!"Unexpected bbJumpKind");
9874 fgUpdateLoopsAfterCompacting(block, bNext);
9879 printf("\nAfter compacting:\n");
9880 fgDispBasicBlocks(false);
9885 if (JitConfig.JitSlowDebugChecksEnabled() != 0)
9887 // Make sure that the predecessor lists are accurate
9888 fgDebugCheckBBlist();
9893 void Compiler::fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext)
9895 /* Check if the removed block is not part the loop table */
9896 noway_assert(bNext);
9898 for (unsigned loopNum = 0; loopNum < optLoopCount; loopNum++)
9900 /* Some loops may have been already removed by
9901 * loop unrolling or conditional folding */
9903 if (optLoopTable[loopNum].lpFlags & LPFLG_REMOVED)
9908 /* Check the loop head (i.e. the block preceding the loop) */
9910 if (optLoopTable[loopNum].lpHead == bNext)
9912 optLoopTable[loopNum].lpHead = block;
9915 /* Check the loop bottom */
9917 if (optLoopTable[loopNum].lpBottom == bNext)
9919 optLoopTable[loopNum].lpBottom = block;
9922 /* Check the loop exit */
9924 if (optLoopTable[loopNum].lpExit == bNext)
9926 noway_assert(optLoopTable[loopNum].lpExitCnt == 1);
9927 optLoopTable[loopNum].lpExit = block;
9930 /* Check the loop entry */
9932 if (optLoopTable[loopNum].lpEntry == bNext)
9934 optLoopTable[loopNum].lpEntry = block;
9939 /*****************************************************************************************************
9941 * Function called to remove a block when it is unreachable.
9943 * This function cannot remove the first block.
9946 void Compiler::fgUnreachableBlock(BasicBlock* block)
9948 // genReturnBB should never be removed, as we might have special hookups there.
9949 // Therefore, we should never come here to remove the statements in the genReturnBB block.
9950 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
9951 // the profiler hookup needs to have the "void GT_RETURN" statement
9952 // to properly set the info.compProfilerCallback flag.
9953 noway_assert(block != genReturnBB);
9955 if (block->bbFlags & BBF_REMOVED)
9960 /* Removing an unreachable block */
9965 printf("\nRemoving unreachable BB%02u\n", block->bbNum);
9969 noway_assert(block->bbPrev != nullptr); // Can use this function to remove the first block
9971 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9972 assert(!block->bbPrev->isBBCallAlwaysPair()); // can't remove the BBJ_ALWAYS of a BBJ_CALLFINALLY / BBJ_ALWAYS pair
9973 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9975 /* First walk the statement trees in this basic block and delete each stmt */
9977 /* Make the block publicly available */
9982 LIR::Range& blockRange = LIR::AsRange(block);
9983 if (!blockRange.IsEmpty())
9985 blockRange.Delete(this, block, blockRange.FirstNode(), blockRange.LastNode());
9990 // TODO-Cleanup: I'm not sure why this happens -- if the block is unreachable, why does it have phis?
9991 // Anyway, remove any phis.
9993 GenTreePtr firstNonPhi = block->FirstNonPhiDef();
9994 if (block->bbTreeList != firstNonPhi)
9996 if (firstNonPhi != nullptr)
9998 firstNonPhi->gtPrev = block->lastStmt();
10000 block->bbTreeList = firstNonPhi;
10003 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
10005 fgRemoveStmt(block, stmt);
10007 noway_assert(block->bbTreeList == nullptr);
10010 /* Next update the loop table and bbWeights */
10011 optUpdateLoopsBeforeRemoveBlock(block);
10013 /* Mark the block as removed */
10014 block->bbFlags |= BBF_REMOVED;
10016 /* update bbRefs and bbPreds for the blocks reached by this block */
10017 fgRemoveBlockAsPred(block);
10020 /*****************************************************************************************************
10022 * Function called to remove or morph a GT_JTRUE statement when we jump to the same
10023 * block when both the condition is true or false.
10025 void Compiler::fgRemoveJTrue(BasicBlock* block)
10027 noway_assert(block->bbJumpKind == BBJ_COND && block->bbJumpDest == block->bbNext);
10028 assert(compRationalIRForm == block->IsLIR());
10030 flowList* flow = fgGetPredForBlock(block->bbNext, block);
10031 noway_assert(flow->flDupCount == 2);
10033 // Change the BBJ_COND to BBJ_NONE, and adjust the refCount and dupCount.
10034 block->bbJumpKind = BBJ_NONE;
10035 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
10036 --block->bbNext->bbRefs;
10037 --flow->flDupCount;
10040 block->bbJumpDest = nullptr;
10043 printf("Block BB%02u becoming a BBJ_NONE to BB%02u (jump target is the same whether the condition is true or "
10045 block->bbNum, block->bbNext->bbNum);
10049 /* Remove the block jump condition */
10051 if (block->IsLIR())
10053 LIR::Range& blockRange = LIR::AsRange(block);
10055 GenTree* test = blockRange.LastNode();
10056 assert(test->OperGet() == GT_JTRUE);
10059 unsigned sideEffects;
10060 LIR::ReadOnlyRange testRange = blockRange.GetTreeRange(test, &isClosed, &sideEffects);
10062 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
10063 // diffs compared to the existing backend.
10064 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
10066 // If the jump and its operands form a contiguous, side-effect-free range,
10068 blockRange.Delete(this, block, std::move(testRange));
10072 // Otherwise, just remove the jump node itself.
10073 blockRange.Remove(test);
10078 GenTreeStmt* test = block->lastStmt();
10079 GenTree* tree = test->gtStmtExpr;
10081 noway_assert(tree->gtOper == GT_JTRUE);
10083 GenTree* sideEffList = nullptr;
10085 if (tree->gtFlags & GTF_SIDE_EFFECT)
10087 gtExtractSideEffList(tree, &sideEffList);
10091 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
10095 printf("Extracted side effects list from condition...\n");
10096 gtDispTree(sideEffList);
10103 // Delete the cond test or replace it with the side effect tree
10104 if (sideEffList == nullptr)
10106 fgRemoveStmt(block, test);
10110 test->gtStmtExpr = sideEffList;
10112 fgMorphBlockStmt(block, test DEBUGARG("fgRemoveJTrue"));
10117 /*****************************************************************************************************
10119 * Function to return the last basic block in the main part of the function. With funclets, it is
10120 * the block immediately before the first funclet.
10121 * An inclusive end of the main method.
10124 BasicBlock* Compiler::fgLastBBInMainFunction()
10126 #if FEATURE_EH_FUNCLETS
10128 if (fgFirstFuncletBB != nullptr)
10130 return fgFirstFuncletBB->bbPrev;
10133 #endif // FEATURE_EH_FUNCLETS
10135 assert(fgLastBB->bbNext == nullptr);
10140 /*****************************************************************************************************
10142 * Function to return the first basic block after the main part of the function. With funclets, it is
10143 * the block of the first funclet. Otherwise it is NULL if there are no funclets (fgLastBB->bbNext).
10144 * This is equivalent to fgLastBBInMainFunction()->bbNext
10145 * An exclusive end of the main method.
10148 BasicBlock* Compiler::fgEndBBAfterMainFunction()
10150 #if FEATURE_EH_FUNCLETS
10152 if (fgFirstFuncletBB != nullptr)
10154 return fgFirstFuncletBB;
10157 #endif // FEATURE_EH_FUNCLETS
10159 assert(fgLastBB->bbNext == nullptr);
10164 // Removes the block from the bbPrev/bbNext chain
10165 // Updates fgFirstBB and fgLastBB if necessary
10166 // Does not update fgFirstFuncletBB or fgFirstColdBlock (fgUnlinkRange does)
10168 void Compiler::fgUnlinkBlock(BasicBlock* block)
10172 block->bbPrev->bbNext = block->bbNext;
10175 block->bbNext->bbPrev = block->bbPrev;
10179 fgLastBB = block->bbPrev;
10184 assert(block == fgFirstBB);
10185 assert(block != fgLastBB);
10186 assert((fgFirstBBScratch == nullptr) || (fgFirstBBScratch == fgFirstBB));
10188 fgFirstBB = block->bbNext;
10189 fgFirstBB->bbPrev = nullptr;
10191 if (fgFirstBBScratch != nullptr)
10194 // We had created an initial scratch BB, but now we're deleting it.
10197 printf("Unlinking scratch BB%02u\n", block->bbNum);
10200 fgFirstBBScratch = nullptr;
10205 /*****************************************************************************************************
10207 * Function called to unlink basic block range [bBeg .. bEnd] from the basic block list.
10209 * 'bBeg' can't be the first block.
10212 void Compiler::fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd)
10214 assert(bBeg != nullptr);
10215 assert(bEnd != nullptr);
10217 BasicBlock* bPrev = bBeg->bbPrev;
10218 assert(bPrev != nullptr); // Can't unlink a range starting with the first block
10220 bPrev->setNext(bEnd->bbNext);
10222 /* If we removed the last block in the method then update fgLastBB */
10223 if (fgLastBB == bEnd)
10226 noway_assert(fgLastBB->bbNext == nullptr);
10229 // If bEnd was the first Cold basic block update fgFirstColdBlock
10230 if (fgFirstColdBlock == bEnd)
10232 fgFirstColdBlock = bPrev->bbNext;
10235 #if FEATURE_EH_FUNCLETS
10237 // You can't unlink a range that includes the first funclet block. A range certainly
10238 // can't cross the non-funclet/funclet region. And you can't unlink the first block
10239 // of the first funclet with this, either. (If that's necessary, it could be allowed
10240 // by updating fgFirstFuncletBB to bEnd->bbNext.)
10241 for (BasicBlock* tempBB = bBeg; tempBB != bEnd->bbNext; tempBB = tempBB->bbNext)
10243 assert(tempBB != fgFirstFuncletBB);
10246 #endif // FEATURE_EH_FUNCLETS
10249 /*****************************************************************************************************
10251 * Function called to remove a basic block
10254 void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
10256 BasicBlock* bPrev = block->bbPrev;
10258 /* The block has to be either unreachable or empty */
10260 PREFIX_ASSUME(block != nullptr);
10262 JITDUMP("fgRemoveBlock BB%02u\n", block->bbNum);
10264 // If we've cached any mappings from switch blocks to SwitchDesc's (which contain only the
10265 // *unique* successors of the switch block), invalidate that cache, since an entry in one of
10266 // the SwitchDescs might be removed.
10267 InvalidateUniqueSwitchSuccMap();
10269 noway_assert((block == fgFirstBB) || (bPrev && (bPrev->bbNext == block)));
10270 noway_assert(!(block->bbFlags & BBF_DONT_REMOVE));
10272 // Should never remove a genReturnBB, as we might have special hookups there.
10273 noway_assert(block != genReturnBB);
10275 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10276 // Don't remove a finally target
10277 assert(!(block->bbFlags & BBF_FINALLY_TARGET));
10278 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10282 PREFIX_ASSUME(bPrev != nullptr);
10284 fgUnreachableBlock(block);
10286 /* If this is the last basic block update fgLastBB */
10287 if (block == fgLastBB)
10292 #if FEATURE_EH_FUNCLETS
10293 // If block was the fgFirstFuncletBB then set fgFirstFuncletBB to block->bbNext
10294 if (block == fgFirstFuncletBB)
10296 fgFirstFuncletBB = block->bbNext;
10298 #endif // FEATURE_EH_FUNCLETS
10300 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
10302 // bPrev CALL becomes RETLESS as the BBJ_ALWAYS block is unreachable
10303 bPrev->bbFlags |= BBF_RETLESS_CALL;
10305 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10306 NO_WAY("No retless call finally blocks; need unwind target instead");
10307 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10309 else if (bPrev->bbJumpKind == BBJ_ALWAYS && bPrev->bbJumpDest == block->bbNext &&
10310 !(bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) && (block != fgFirstColdBlock) &&
10311 (block->bbNext != fgFirstColdBlock))
10313 // previous block is a BBJ_ALWAYS to the next block: change to BBJ_NONE.
10314 // Note that we don't do it if bPrev follows a BBJ_CALLFINALLY block (BBF_KEEP_BBJ_ALWAYS),
10315 // because that would violate our invariant that BBJ_CALLFINALLY blocks are followed by
10316 // BBJ_ALWAYS blocks.
10317 bPrev->bbJumpKind = BBJ_NONE;
10318 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
10321 // If this is the first Cold basic block update fgFirstColdBlock
10322 if (block == fgFirstColdBlock)
10324 fgFirstColdBlock = block->bbNext;
10327 /* Unlink this block from the bbNext chain */
10328 fgUnlinkBlock(block);
10330 /* At this point the bbPreds and bbRefs had better be zero */
10331 noway_assert((block->bbRefs == 0) && (block->bbPreds == nullptr));
10333 /* A BBJ_CALLFINALLY is usually paired with a BBJ_ALWAYS.
10334 * If we delete such a BBJ_CALLFINALLY we also delete the BBJ_ALWAYS
10336 if (block->isBBCallAlwaysPair())
10338 BasicBlock* leaveBlk = block->bbNext;
10339 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
10341 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
10342 leaveBlk->bbRefs = 0;
10343 leaveBlk->bbPreds = nullptr;
10345 fgRemoveBlock(leaveBlk, true);
10347 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10348 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
10349 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10351 else if (block->bbJumpKind == BBJ_RETURN)
10353 fgRemoveReturnBlock(block);
10356 else // block is empty
10358 noway_assert(block->isEmpty());
10360 /* The block cannot follow a non-retless BBJ_CALLFINALLY (because we don't know who may jump to it) */
10361 noway_assert((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair());
10363 /* This cannot be the last basic block */
10364 noway_assert(block != fgLastBB);
10369 printf("Removing empty BB%02u\n", block->bbNum);
10374 /* Some extra checks for the empty case */
10376 switch (block->bbJumpKind)
10382 /* Do not remove a block that jumps to itself - used for while (true){} */
10383 noway_assert(block->bbJumpDest != block);
10385 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
10386 noway_assert(bPrev && bPrev->bbJumpKind == BBJ_NONE);
10390 noway_assert(!"Empty block of this type cannot be removed!");
10395 noway_assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS);
10397 /* Who is the "real" successor of this block? */
10399 BasicBlock* succBlock;
10401 if (block->bbJumpKind == BBJ_ALWAYS)
10403 succBlock = block->bbJumpDest;
10407 succBlock = block->bbNext;
10410 bool skipUnmarkLoop = false;
10412 // If block is the backedge for a loop and succBlock precedes block
10413 // then the succBlock becomes the new LOOP HEAD
10414 // NOTE: there's an assumption here that the blocks are numbered in increasing bbNext order.
10415 // NOTE 2: if fgDomsComputed is false, then we can't check reachability. However, if this is
10416 // the case, then the loop structures probably are also invalid, and shouldn't be used. This
10417 // can be the case late in compilation (such as Lower), where remnants of earlier created
10418 // structures exist, but haven't been maintained.
10419 if (block->isLoopHead() && (succBlock->bbNum <= block->bbNum))
10421 succBlock->bbFlags |= BBF_LOOP_HEAD;
10422 if (fgDomsComputed && fgReachable(succBlock, block))
10424 /* Mark all the reachable blocks between 'succBlock' and 'block', excluding 'block' */
10425 optMarkLoopBlocks(succBlock, block, true);
10428 else if (succBlock->isLoopHead() && bPrev && (succBlock->bbNum <= bPrev->bbNum))
10430 skipUnmarkLoop = true;
10433 noway_assert(succBlock);
10435 // If this is the first Cold basic block update fgFirstColdBlock
10436 if (block == fgFirstColdBlock)
10438 fgFirstColdBlock = block->bbNext;
10441 #if FEATURE_EH_FUNCLETS
10442 // Update fgFirstFuncletBB if necessary
10443 if (block == fgFirstFuncletBB)
10445 fgFirstFuncletBB = block->bbNext;
10447 #endif // FEATURE_EH_FUNCLETS
10449 /* First update the loop table and bbWeights */
10450 optUpdateLoopsBeforeRemoveBlock(block, skipUnmarkLoop);
10452 /* Remove the block */
10454 if (bPrev == nullptr)
10456 /* special case if this is the first BB */
10458 noway_assert(block == fgFirstBB);
10460 /* Must be a fall through to next block */
10462 noway_assert(block->bbJumpKind == BBJ_NONE);
10464 /* old block no longer gets the extra ref count for being the first block */
10466 succBlock->bbRefs++;
10468 /* Set the new firstBB */
10469 fgUnlinkBlock(block);
10471 /* Always treat the initial block as a jump target */
10472 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
10476 fgUnlinkBlock(block);
10479 /* mark the block as removed and set the change flag */
10481 block->bbFlags |= BBF_REMOVED;
10483 /* Update bbRefs and bbPreds.
10484 * All blocks jumping to 'block' now jump to 'succBlock'.
10485 * First, remove 'block' from the predecessor list of succBlock.
10488 fgRemoveRefPred(succBlock, block);
10490 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
10492 BasicBlock* predBlock = pred->flBlock;
10494 /* Are we changing a loop backedge into a forward jump? */
10496 if (block->isLoopHead() && (predBlock->bbNum >= block->bbNum) && (predBlock->bbNum <= succBlock->bbNum))
10498 /* First update the loop table and bbWeights */
10499 optUpdateLoopsBeforeRemoveBlock(predBlock);
10502 /* If predBlock is a new predecessor, then add it to succBlock's
10503 predecessor's list. */
10504 if (predBlock->bbJumpKind != BBJ_SWITCH)
10506 // Even if the pred is not a switch, we could have a conditional branch
10507 // to the fallthrough, so duplicate there could be preds
10508 for (unsigned i = 0; i < pred->flDupCount; i++)
10510 fgAddRefPred(succBlock, predBlock);
10514 /* change all jumps to the removed block */
10515 switch (predBlock->bbJumpKind)
10518 noway_assert(!"Unexpected bbJumpKind in fgRemoveBlock()");
10522 noway_assert(predBlock == bPrev);
10523 PREFIX_ASSUME(bPrev != nullptr);
10525 /* In the case of BBJ_ALWAYS we have to change the type of its predecessor */
10526 if (block->bbJumpKind == BBJ_ALWAYS)
10528 /* bPrev now becomes a BBJ_ALWAYS */
10529 bPrev->bbJumpKind = BBJ_ALWAYS;
10530 bPrev->bbJumpDest = succBlock;
10535 /* The links for the direct predecessor case have already been updated above */
10536 if (predBlock->bbJumpDest != block)
10538 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
10542 /* Check if both side of the BBJ_COND now jump to the same block */
10543 if (predBlock->bbNext == succBlock)
10545 // Make sure we are replacing "block" with "succBlock" in predBlock->bbJumpDest.
10546 noway_assert(predBlock->bbJumpDest == block);
10547 predBlock->bbJumpDest = succBlock;
10548 fgRemoveJTrue(predBlock);
10552 /* Fall through for the jump case */
10555 case BBJ_CALLFINALLY:
10557 case BBJ_EHCATCHRET:
10558 noway_assert(predBlock->bbJumpDest == block);
10559 predBlock->bbJumpDest = succBlock;
10560 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
10564 // Change any jumps from 'predBlock' (a BBJ_SWITCH) to 'block' to jump to 'succBlock'
10566 // For the jump targets of 'predBlock' (a BBJ_SWITCH) that jump to 'block'
10567 // remove the old predecessor at 'block' from 'predBlock' and
10568 // add the new predecessor at 'succBlock' from 'predBlock'
10570 fgReplaceSwitchJumpTarget(predBlock, succBlock, block);
10576 if (bPrev != nullptr)
10578 switch (bPrev->bbJumpKind)
10580 case BBJ_CALLFINALLY:
10581 // If prev is a BBJ_CALLFINALLY it better be marked as RETLESS
10582 noway_assert(bPrev->bbFlags & BBF_RETLESS_CALL);
10586 // Check for branch to next block. Just make sure the BBJ_ALWAYS block is not
10587 // part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair. We do this here and don't rely on fgUpdateFlowGraph
10588 // because we can be called by ComputeDominators and it expects it to remove this jump to
10589 // the next block. This is the safest fix. We should remove all this BBJ_CALLFINALLY/BBJ_ALWAYS
10592 if ((bPrev->bbJumpDest == bPrev->bbNext) &&
10593 !fgInDifferentRegions(bPrev, bPrev->bbJumpDest)) // We don't remove a branch from Hot -> Cold
10595 if ((bPrev == fgFirstBB) || !bPrev->bbPrev->isBBCallAlwaysPair())
10597 // It's safe to change the jump type
10598 bPrev->bbJumpKind = BBJ_NONE;
10599 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
10605 /* Check for branch to next block */
10606 if (bPrev->bbJumpDest == bPrev->bbNext)
10608 fgRemoveJTrue(bPrev);
10616 ehUpdateForDeletedBlock(block);
10620 /*****************************************************************************
10622 * Function called to connect to block that previously had a fall through
10625 BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
10627 BasicBlock* jmpBlk = nullptr;
10629 /* If bSrc is non-NULL */
10631 if (bSrc != nullptr)
10633 /* If bSrc falls through to a block that is not bDst, we will insert a jump to bDst */
10635 if (bSrc->bbFallsThrough() && (bSrc->bbNext != bDst))
10637 switch (bSrc->bbJumpKind)
10641 bSrc->bbJumpKind = BBJ_ALWAYS;
10642 bSrc->bbJumpDest = bDst;
10643 bSrc->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
10647 printf("Block BB%02u ended with a BBJ_NONE, Changed to an unconditional jump to BB%02u\n",
10648 bSrc->bbNum, bSrc->bbJumpDest->bbNum);
10653 case BBJ_CALLFINALLY:
10656 // Add a new block after bSrc which jumps to 'bDst'
10657 jmpBlk = fgNewBBafter(BBJ_ALWAYS, bSrc, true);
10659 if (fgComputePredsDone)
10661 fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc));
10664 // When adding a new jmpBlk we will set the bbWeight and bbFlags
10666 if (fgHaveValidEdgeWeights)
10668 noway_assert(fgComputePredsDone);
10670 flowList* newEdge = fgGetPredForBlock(jmpBlk, bSrc);
10672 jmpBlk->bbWeight = (newEdge->flEdgeWeightMin + newEdge->flEdgeWeightMax) / 2;
10673 if (bSrc->bbWeight == 0)
10675 jmpBlk->bbWeight = 0;
10678 if (jmpBlk->bbWeight == 0)
10680 jmpBlk->bbFlags |= BBF_RUN_RARELY;
10683 BasicBlock::weight_t weightDiff = (newEdge->flEdgeWeightMax - newEdge->flEdgeWeightMin);
10684 BasicBlock::weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst);
10687 // If the [min/max] values for our edge weight is within the slop factor
10688 // then we will set the BBF_PROF_WEIGHT flag for the block
10690 if (weightDiff <= slop)
10692 jmpBlk->bbFlags |= BBF_PROF_WEIGHT;
10697 // We set the bbWeight to the smaller of bSrc->bbWeight or bDst->bbWeight
10698 if (bSrc->bbWeight < bDst->bbWeight)
10700 jmpBlk->bbWeight = bSrc->bbWeight;
10701 jmpBlk->bbFlags |= (bSrc->bbFlags & BBF_RUN_RARELY);
10705 jmpBlk->bbWeight = bDst->bbWeight;
10706 jmpBlk->bbFlags |= (bDst->bbFlags & BBF_RUN_RARELY);
10710 jmpBlk->bbJumpDest = bDst;
10711 jmpBlk->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
10713 if (fgComputePredsDone)
10715 fgReplacePred(bDst, bSrc, jmpBlk);
10719 jmpBlk->bbFlags |= BBF_IMPORTED;
10725 printf("Added an unconditional jump to BB%02u after block BB%02u\n", jmpBlk->bbJumpDest->bbNum,
10732 noway_assert(!"Unexpected bbJumpKind");
10738 // If bSrc is an unconditional branch to the next block
10739 // then change it to a BBJ_NONE block
10741 if ((bSrc->bbJumpKind == BBJ_ALWAYS) && !(bSrc->bbFlags & BBF_KEEP_BBJ_ALWAYS) &&
10742 (bSrc->bbJumpDest == bSrc->bbNext))
10744 bSrc->bbJumpKind = BBJ_NONE;
10745 bSrc->bbFlags &= ~BBF_NEEDS_GCPOLL;
10749 printf("Changed an unconditional jump from BB%02u to the next block BB%02u into a BBJ_NONE block\n",
10750 bSrc->bbNum, bSrc->bbNext->bbNum);
10760 /*****************************************************************************
10761 Walk the flow graph, reassign block numbers to keep them in ascending order.
10762 Returns 'true' if any renumbering was actually done, OR if we change the
10763 maximum number of assigned basic blocks (this can happen if we do inlining,
10764 create a new, high-numbered block, then that block goes away. We go to
10765 renumber the blocks, none of them actually change number, but we shrink the
10766 maximum assigned block number. This affects the block set epoch).
10769 bool Compiler::fgRenumberBlocks()
10771 // If we renumber the blocks the dominator information will be out-of-date
10772 if (fgDomsComputed)
10774 noway_assert(!"Can't call Compiler::fgRenumberBlocks() when fgDomsComputed==true");
10780 printf("\n*************** Before renumbering the basic blocks\n");
10781 fgDispBasicBlocks();
10782 fgDispHandlerTab();
10786 bool renumbered = false;
10787 bool newMaxBBNum = false;
10790 unsigned numStart = 1 + (compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : 0);
10793 for (block = fgFirstBB, num = numStart; block != nullptr; block = block->bbNext, num++)
10795 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
10797 if (block->bbNum != num)
10803 printf("Renumber BB%02u to BB%02u\n", block->bbNum, num);
10806 block->bbNum = num;
10809 if (block->bbNext == nullptr)
10812 fgBBcount = num - numStart + 1;
10813 if (compIsForInlining())
10815 if (impInlineInfo->InlinerCompiler->fgBBNumMax != num)
10817 impInlineInfo->InlinerCompiler->fgBBNumMax = num;
10818 newMaxBBNum = true;
10823 if (fgBBNumMax != num)
10826 newMaxBBNum = true;
10835 printf("\n*************** After renumbering the basic blocks\n");
10838 fgDispBasicBlocks();
10839 fgDispHandlerTab();
10843 printf("=============== No blocks renumbered!\n");
10848 // Now update the BlockSet epoch, which depends on the block numbers.
10849 // If any blocks have been renumbered then create a new BlockSet epoch.
10850 // Even if we have not renumbered any blocks, we might still need to force
10851 // a new BlockSet epoch, for one of several reasons. If there are any new
10852 // blocks with higher numbers than the former maximum numbered block, then we
10853 // need a new epoch with a new size matching the new largest numbered block.
10854 // Also, if the number of blocks is different from the last time we set the
10855 // BlockSet epoch, then we need a new epoch. This wouldn't happen if we
10856 // renumbered blocks after every block addition/deletion, but it might be
10857 // the case that we can change the number of blocks, then set the BlockSet
10858 // epoch without renumbering, then change the number of blocks again, then
10860 if (renumbered || newMaxBBNum)
10862 NewBasicBlockEpoch();
10864 // The key in the unique switch successor map is dependent on the block number, so invalidate that cache.
10865 InvalidateUniqueSwitchSuccMap();
10869 EnsureBasicBlockEpoch();
10872 // Tell our caller if any blocks actually were renumbered.
10873 return renumbered || newMaxBBNum;
10876 /*****************************************************************************
10878 * Is the BasicBlock bJump a forward branch?
10879 * Optionally bSrc can be supplied to indicate that
10880 * bJump must be forward with respect to bSrc
10882 bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc /* = NULL */)
10884 bool result = false;
10886 if ((bJump->bbJumpKind == BBJ_COND) || (bJump->bbJumpKind == BBJ_ALWAYS))
10888 BasicBlock* bDest = bJump->bbJumpDest;
10889 BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc;
10893 bTemp = bTemp->bbNext;
10895 if (bTemp == nullptr)
10900 if (bTemp == bDest)
10911 /*****************************************************************************
10913 * Function called to expand the set of rarely run blocks
10916 bool Compiler::fgExpandRarelyRunBlocks()
10918 bool result = false;
10923 printf("\n*************** In fgExpandRarelyRunBlocks()\n");
10926 const char* reason = nullptr;
10929 // We expand the number of rarely run blocks by observing
10930 // that a block that falls into or jumps to a rarely run block,
10931 // must itself be rarely run and when we have a conditional
10932 // jump in which both branches go to rarely run blocks then
10933 // the block must itself be rarely run
10938 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
10940 if (bPrev->isRunRarely())
10945 /* bPrev is known to be a normal block here */
10946 switch (bPrev->bbJumpKind)
10950 /* Is the jump target rarely run? */
10951 if (bPrev->bbJumpDest->isRunRarely())
10953 INDEBUG(reason = "Unconditional jump to a rarely run block";)
10954 goto NEW_RARELY_RUN;
10958 case BBJ_CALLFINALLY:
10960 // Check for a BBJ_CALLFINALLY followed by a rarely run paired BBJ_ALWAYS
10962 if (bPrev->isBBCallAlwaysPair())
10964 /* Is the next block rarely run? */
10965 if (block->isRunRarely())
10967 INDEBUG(reason = "Call of finally followed by a rarely run block";)
10968 goto NEW_RARELY_RUN;
10975 /* is fall through target rarely run? */
10976 if (block->isRunRarely())
10978 INDEBUG(reason = "Falling into a rarely run block";)
10979 goto NEW_RARELY_RUN;
10985 if (!block->isRunRarely())
10990 /* If both targets of the BBJ_COND are run rarely then don't reorder */
10991 if (bPrev->bbJumpDest->isRunRarely())
10993 /* bPrev should also be marked as run rarely */
10994 if (!bPrev->isRunRarely())
10996 INDEBUG(reason = "Both sides of a conditional jump are rarely run";)
10999 /* If the weight of the block was obtained from a profile run,
11000 than it's more accurate than our static analysis */
11001 if (bPrev->bbFlags & BBF_PROF_WEIGHT)
11008 assert(reason != nullptr);
11011 printf("%s, marking BB%02u as rarely run\n", reason, bPrev->bbNum);
11015 /* Must not have previously been marked */
11016 noway_assert(!bPrev->isRunRarely());
11018 /* Mark bPrev as a new rarely run block */
11019 bPrev->bbSetRunRarely();
11021 BasicBlock* bPrevPrev = nullptr;
11024 if ((bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
11026 // If we've got a BBJ_CALLFINALLY/BBJ_ALWAYS pair, treat the BBJ_CALLFINALLY as an
11027 // additional predecessor for the BBJ_ALWAYS block
11028 tmpbb = bPrev->bbPrev;
11029 noway_assert(tmpbb != nullptr);
11030 #if FEATURE_EH_FUNCLETS
11031 noway_assert(tmpbb->isBBCallAlwaysPair());
11034 if (tmpbb->bbJumpKind == BBJ_CALLFINALLY)
11041 /* Now go back to it's earliest predecessor to see */
11042 /* if it too should now be marked as rarely run */
11043 flowList* pred = bPrev->bbPreds;
11045 if ((pred != nullptr) || (bPrevPrev != nullptr))
11047 // bPrevPrev will be set to the lexically
11048 // earliest predecessor of bPrev.
11050 while (pred != nullptr)
11052 if (bPrevPrev == nullptr)
11054 // Initially we select the first block in the bbPreds list
11055 bPrevPrev = pred->flBlock;
11059 // Walk the flow graph lexically forward from pred->flBlock
11060 // if we find (block == bPrevPrev) then
11061 // pred->flBlock is an earlier predecessor.
11062 for (tmpbb = pred->flBlock; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11064 if (tmpbb == bPrevPrev)
11066 /* We found an ealier predecessor */
11067 bPrevPrev = pred->flBlock;
11070 else if (tmpbb == bPrev)
11072 // We have reached bPrev so stop walking
11073 // as this cannot be an earlier predecessor
11078 // Onto the next predecessor
11079 pred = pred->flNext;
11082 // Walk the flow graph forward from bPrevPrev
11083 // if we don't find (tmpbb == bPrev) then our candidate
11084 // bPrevPrev is lexically after bPrev and we do not
11085 // want to select it as our new block
11087 for (tmpbb = bPrevPrev; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11089 if (tmpbb == bPrev)
11091 // Set up block back to the lexically
11092 // earliest predecessor of pPrev
11107 // Now iterate over every block to see if we can prove that a block is rarely run
11108 // (i.e. when all predecessors to the block are rarely run)
11110 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
11112 // If block is not run rarely, then check to make sure that it has
11113 // at least one non-rarely run block.
11115 if (!block->isRunRarely())
11119 /* Make sure that block has at least one normal predecessor */
11120 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
11122 /* Find the fall through predecessor, if any */
11123 if (!pred->flBlock->isRunRarely())
11132 // If 'block' is the start of a handler or filter then we cannot make it
11133 // rarely run because we may have an exceptional edge that
11136 if (bbIsHandlerBeg(block))
11144 block->bbSetRunRarely();
11150 printf("All branches to BB%02u are from rarely run blocks, marking as rarely run\n", block->bbNum);
11154 // When marking a BBJ_CALLFINALLY as rarely run we also mark
11155 // the BBJ_ALWAYS that comes after it as rarely run
11157 if (block->isBBCallAlwaysPair())
11159 BasicBlock* bNext = block->bbNext;
11160 PREFIX_ASSUME(bNext != nullptr);
11161 bNext->bbSetRunRarely();
11165 printf("Also marking the BBJ_ALWAYS at BB%02u as rarely run\n", bNext->bbNum);
11172 /* COMPACT blocks if possible */
11173 if (bPrev->bbJumpKind == BBJ_NONE)
11175 if (fgCanCompactBlocks(bPrev, block))
11177 fgCompactBlocks(bPrev, block);
11184 // if bPrev->bbWeight is not based upon profile data we can adjust
11185 // the weights of bPrev and block
11187 else if (bPrev->isBBCallAlwaysPair() && // we must have a BBJ_CALLFINALLY and BBK_ALWAYS pair
11188 (bPrev->bbWeight != block->bbWeight) && // the weights are currently different
11189 ((bPrev->bbFlags & BBF_PROF_WEIGHT) == 0)) // and the BBJ_CALLFINALLY block is not using profiled
11192 if (block->isRunRarely())
11195 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11196 bPrev->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11200 printf("Marking the BBJ_CALLFINALLY block at BB%02u as rarely run because BB%02u is rarely run\n",
11201 bPrev->bbNum, block->bbNum);
11205 else if (bPrev->isRunRarely())
11208 bPrev->bbWeight; // the BBJ_ALWAYS block now has the same weight as the BBJ_CALLFINALLY block
11209 block->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11213 printf("Marking the BBJ_ALWAYS block at BB%02u as rarely run because BB%02u is rarely run\n",
11214 block->bbNum, bPrev->bbNum);
11218 else // Both blocks are hot, bPrev is known not to be using profiled weight
11221 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11223 noway_assert(block->bbWeight == bPrev->bbWeight);
11230 /*****************************************************************************
11232 * Returns true if it is allowable (based upon the EH regions)
11233 * to place block bAfter immediately after bBefore. It is allowable
11234 * if the 'bBefore' and 'bAfter' blocks are in the exact same EH region.
11237 bool Compiler::fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter)
11239 return BasicBlock::sameEHRegion(bBefore, bAfter);
11242 /*****************************************************************************
11244 * Function called to move the range of blocks [bStart .. bEnd].
11245 * The blocks are placed immediately after the insertAfterBlk.
11246 * fgFirstFuncletBB is not updated; that is the responsibility of the caller, if necessary.
11249 void Compiler::fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk)
11251 /* We have decided to insert the block(s) after 'insertAfterBlk' */
11252 CLANG_FORMAT_COMMENT_ANCHOR;
11257 printf("Relocated block%s [BB%02u..BB%02u] inserted after BB%02u%s\n", (bStart == bEnd) ? "" : "s",
11258 bStart->bbNum, bEnd->bbNum, insertAfterBlk->bbNum,
11259 (insertAfterBlk->bbNext == nullptr) ? " at the end of method" : "");
11263 /* relink [bStart .. bEnd] into the flow graph */
11265 bEnd->bbNext = insertAfterBlk->bbNext;
11266 if (insertAfterBlk->bbNext)
11268 insertAfterBlk->bbNext->bbPrev = bEnd;
11270 insertAfterBlk->setNext(bStart);
11272 /* If insertAfterBlk was fgLastBB then update fgLastBB */
11273 if (insertAfterBlk == fgLastBB)
11276 noway_assert(fgLastBB->bbNext == nullptr);
11280 /*****************************************************************************
11282 * Function called to relocate a single range to the end of the method.
11283 * Only an entire consecutive region can be moved and it will be kept together.
11284 * Except for the first block, the range cannot have any blocks that jump into or out of the region.
11285 * When successful we return the bLast block which is the last block that we relocated.
11286 * When unsuccessful we return NULL.
11288 =============================================================
11289 NOTE: This function can invalidate all pointers into the EH table, as well as change the size of the EH table!
11290 =============================================================
11293 BasicBlock* Compiler::fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType)
11295 INDEBUG(const char* reason = "None";)
11297 // Figure out the range of blocks we're going to move
11301 BasicBlock* bStart = nullptr;
11302 BasicBlock* bMiddle = nullptr;
11303 BasicBlock* bLast = nullptr;
11304 BasicBlock* bPrev = nullptr;
11306 #if FEATURE_EH_FUNCLETS
11307 // We don't support moving try regions... yet?
11308 noway_assert(relocateType == FG_RELOCATE_HANDLER);
11309 #endif // FEATURE_EH_FUNCLETS
11311 HBtab = ehGetDsc(regionIndex);
11313 if (relocateType == FG_RELOCATE_TRY)
11315 bStart = HBtab->ebdTryBeg;
11316 bLast = HBtab->ebdTryLast;
11318 else if (relocateType == FG_RELOCATE_HANDLER)
11320 if (HBtab->HasFilter())
11322 // The filter and handler funclets must be moved together, and remain contiguous.
11323 bStart = HBtab->ebdFilter;
11324 bMiddle = HBtab->ebdHndBeg;
11325 bLast = HBtab->ebdHndLast;
11329 bStart = HBtab->ebdHndBeg;
11330 bLast = HBtab->ebdHndLast;
11334 // Our range must contain either all rarely run blocks or all non-rarely run blocks
11335 bool inTheRange = false;
11336 bool validRange = false;
11340 noway_assert(bStart != nullptr && bLast != nullptr);
11341 if (bStart == fgFirstBB)
11343 INDEBUG(reason = "can not relocate first block";)
11347 #if !FEATURE_EH_FUNCLETS
11348 // In the funclets case, we still need to set some information on the handler blocks
11349 if (bLast->bbNext == NULL)
11351 INDEBUG(reason = "region is already at the end of the method";)
11354 #endif // !FEATURE_EH_FUNCLETS
11356 // Walk the block list for this purpose:
11357 // 1. Verify that all the blocks in the range are either all rarely run or not rarely run.
11358 // When creating funclets, we ignore the run rarely flag, as we need to be able to move any blocks
11360 CLANG_FORMAT_COMMENT_ANCHOR;
11362 #if !FEATURE_EH_FUNCLETS
11364 isRare = bStart->isRunRarely();
11365 #endif // !FEATURE_EH_FUNCLETS
11369 if (block == bStart)
11371 noway_assert(inTheRange == false);
11374 else if (block == bLast->bbNext)
11376 noway_assert(inTheRange == true);
11377 inTheRange = false;
11378 break; // we found the end, so we're done
11383 #if !FEATURE_EH_FUNCLETS
11384 // Unless all blocks are (not) run rarely we must return false.
11385 if (isRare != block->isRunRarely())
11387 INDEBUG(reason = "this region contains both rarely run and non-rarely run blocks";)
11390 #endif // !FEATURE_EH_FUNCLETS
11395 if (block == nullptr)
11400 block = block->bbNext;
11402 // Ensure that bStart .. bLast defined a valid range
11403 noway_assert((validRange == true) && (inTheRange == false));
11405 bPrev = bStart->bbPrev;
11406 noway_assert(bPrev != nullptr); // Can't move a range that includes the first block of the function.
11408 JITDUMP("Relocating %s range BB%02u..BB%02u (EH#%u) to end of BBlist\n",
11409 (relocateType == FG_RELOCATE_TRY) ? "try" : "handler", bStart->bbNum, bLast->bbNum, regionIndex);
11414 fgDispBasicBlocks();
11415 fgDispHandlerTab();
11418 if (!FEATURE_EH_FUNCLETS)
11420 // This is really expensive, and quickly becomes O(n^n) with funclets
11421 // so only do it once after we've created them (see fgCreateFunclets)
11422 if (expensiveDebugCheckLevel >= 2)
11424 fgDebugCheckBBlist();
11429 #if FEATURE_EH_FUNCLETS
11431 bStart->bbFlags |= BBF_FUNCLET_BEG; // Mark the start block of the funclet
11433 if (bMiddle != nullptr)
11435 bMiddle->bbFlags |= BBF_FUNCLET_BEG; // Also mark the start block of a filter handler as a funclet
11438 #endif // FEATURE_EH_FUNCLETS
11441 bNext = bLast->bbNext;
11443 /* Temporarily unlink [bStart .. bLast] from the flow graph */
11444 fgUnlinkRange(bStart, bLast);
11446 BasicBlock* insertAfterBlk;
11447 insertAfterBlk = fgLastBB;
11449 #if FEATURE_EH_FUNCLETS
11451 // There are several cases we need to consider when moving an EH range.
11452 // If moving a range X, we must consider its relationship to every other EH
11453 // range A in the table. Note that each entry in the table represents both
11454 // a protected region and a handler region (possibly including a filter region
11455 // that must live before and adjacent to the handler region), so we must
11456 // consider try and handler regions independently. These are the cases:
11457 // 1. A is completely contained within X (where "completely contained" means
11458 // that the 'begin' and 'last' parts of A are strictly between the 'begin'
11459 // and 'end' parts of X, and aren't equal to either, for example, they don't
11460 // share 'last' blocks). In this case, when we move X, A moves with it, and
11461 // the EH table doesn't need to change.
11462 // 2. X is completely contained within A. In this case, X gets extracted from A,
11463 // and the range of A shrinks, but because A is strictly within X, the EH
11464 // table doesn't need to change.
11465 // 3. A and X have exactly the same range. In this case, A is moving with X and
11466 // the EH table doesn't need to change.
11467 // 4. A and X share the 'last' block. There are two sub-cases:
11468 // (a) A is a larger range than X (such that the beginning of A precedes the
11469 // beginning of X): in this case, we are moving the tail of A. We set the
11470 // 'last' block of A to the the block preceding the beginning block of X.
11471 // (b) A is a smaller range than X. Thus, we are moving the entirety of A along
11472 // with X. In this case, nothing in the EH record for A needs to change.
11473 // 5. A and X share the 'beginning' block (but aren't the same range, as in #3).
11474 // This can never happen here, because we are only moving handler ranges (we don't
11475 // move try ranges), and handler regions cannot start at the beginning of a try
11476 // range or handler range and be a subset.
11478 // Note that A and X must properly nest for the table to be well-formed. For example,
11479 // the beginning of A can't be strictly within the range of X (that is, the beginning
11480 // of A isn't shared with the beginning of X) and the end of A outside the range.
11482 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
11484 if (XTnum != regionIndex) // we don't need to update our 'last' pointer
11486 if (HBtab->ebdTryLast == bLast)
11488 // If we moved a set of blocks that were at the end of
11489 // a different try region then we may need to update ebdTryLast
11490 for (block = HBtab->ebdTryBeg; block != nullptr; block = block->bbNext)
11492 if (block == bPrev)
11494 // We were contained within it, so shrink its region by
11495 // setting its 'last'
11496 fgSetTryEnd(HBtab, bPrev);
11499 else if (block == HBtab->ebdTryLast->bbNext)
11501 // bPrev does not come after the TryBeg, thus we are larger, and
11502 // it is moving with us.
11507 if (HBtab->ebdHndLast == bLast)
11509 // If we moved a set of blocks that were at the end of
11510 // a different handler region then we must update ebdHndLast
11511 for (block = HBtab->ebdHndBeg; block != nullptr; block = block->bbNext)
11513 if (block == bPrev)
11515 fgSetHndEnd(HBtab, bPrev);
11518 else if (block == HBtab->ebdHndLast->bbNext)
11520 // bPrev does not come after the HndBeg
11526 } // end exception table iteration
11528 // Insert the block(s) we are moving after fgLastBlock
11529 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
11531 if (fgFirstFuncletBB == nullptr) // The funclet region isn't set yet
11533 fgFirstFuncletBB = bStart;
11537 assert(fgFirstFuncletBB !=
11538 insertAfterBlk->bbNext); // We insert at the end, not at the beginning, of the funclet region.
11541 // These asserts assume we aren't moving try regions (which we might need to do). Only
11542 // try regions can have fall through into or out of the region.
11544 noway_assert(!bPrev->bbFallsThrough()); // There can be no fall through into a filter or handler region
11545 noway_assert(!bLast->bbFallsThrough()); // There can be no fall through out of a handler region
11550 printf("Create funclets: moved region\n");
11551 fgDispHandlerTab();
11554 // We have to wait to do this until we've created all the additional regions
11555 // Because this relies on ebdEnclosingTryIndex and ebdEnclosingHndIndex
11556 if (!FEATURE_EH_FUNCLETS)
11558 // This is really expensive, and quickly becomes O(n^n) with funclets
11559 // so only do it once after we've created them (see fgCreateFunclets)
11560 if (expensiveDebugCheckLevel >= 2)
11562 fgDebugCheckBBlist();
11567 #else // FEATURE_EH_FUNCLETS
11569 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
11571 if (XTnum == regionIndex)
11573 // Don't update our handler's Last info
11577 if (HBtab->ebdTryLast == bLast)
11579 // If we moved a set of blocks that were at the end of
11580 // a different try region then we may need to update ebdTryLast
11581 for (block = HBtab->ebdTryBeg; block != NULL; block = block->bbNext)
11583 if (block == bPrev)
11585 fgSetTryEnd(HBtab, bPrev);
11588 else if (block == HBtab->ebdTryLast->bbNext)
11590 // bPrev does not come after the TryBeg
11595 if (HBtab->ebdHndLast == bLast)
11597 // If we moved a set of blocks that were at the end of
11598 // a different handler region then we must update ebdHndLast
11599 for (block = HBtab->ebdHndBeg; block != NULL; block = block->bbNext)
11601 if (block == bPrev)
11603 fgSetHndEnd(HBtab, bPrev);
11606 else if (block == HBtab->ebdHndLast->bbNext)
11608 // bPrev does not come after the HndBeg
11613 } // end exception table iteration
11615 // We have decided to insert the block(s) after fgLastBlock
11616 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
11618 // If bPrev falls through, we will insert a jump to block
11619 fgConnectFallThrough(bPrev, bStart);
11621 // If bLast falls through, we will insert a jump to bNext
11622 fgConnectFallThrough(bLast, bNext);
11624 #endif // FEATURE_EH_FUNCLETS
11633 printf("*************** Failed fgRelocateEHRange(BB%02u..BB%02u) because %s\n", bStart->bbNum, bLast->bbNum,
11645 #if FEATURE_EH_FUNCLETS
11647 #if defined(_TARGET_ARM_)
11649 /*****************************************************************************
11650 * We just removed a BBJ_CALLFINALLY/BBJ_ALWAYS pair. If this was the only such pair
11651 * targeting the BBJ_ALWAYS target, then we need to clear the BBF_FINALLY_TARGET bit
11652 * so that target can also be removed. 'block' is the finally target. Since we just
11653 * removed the BBJ_ALWAYS, it better have the BBF_FINALLY_TARGET bit set.
11656 void Compiler::fgClearFinallyTargetBit(BasicBlock* block)
11658 assert((block->bbFlags & BBF_FINALLY_TARGET) != 0);
11660 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
11662 if (pred->flBlock->bbJumpKind == BBJ_ALWAYS && pred->flBlock->bbJumpDest == block)
11664 BasicBlock* pPrev = pred->flBlock->bbPrev;
11667 if (pPrev->bbJumpKind == BBJ_CALLFINALLY)
11669 // We found a BBJ_CALLFINALLY / BBJ_ALWAYS that still points to this finally target
11676 // Didn't find any BBJ_CALLFINALLY / BBJ_ALWAYS that still points here, so clear the bit
11678 block->bbFlags &= ~BBF_FINALLY_TARGET;
11681 #endif // defined(_TARGET_ARM_)
11683 /*****************************************************************************
11684 * Is this an intra-handler control flow edge?
11686 * 'block' is the head block of a funclet/handler region, or .
11687 * 'predBlock' is a predecessor block of 'block' in the predecessor list.
11689 * 'predBlock' can legally only be one of three things:
11690 * 1. in the same handler region (e.g., the source of a back-edge of a loop from
11691 * 'predBlock' to 'block'), including in nested regions within the handler,
11692 * 2. if 'block' begins a handler that is a filter-handler, 'predBlock' must be in the 'filter' region,
11693 * 3. for other handlers, 'predBlock' must be in the 'try' region corresponding to handler (or any
11694 * region nested in the 'try' region).
11696 * Note that on AMD64/ARM64, the BBJ_CALLFINALLY block that calls a finally handler is not
11697 * within the corresponding 'try' region: it is placed in the corresponding 'try' region's
11698 * parent (which might be the main function body). This is how it is represented to the VM
11699 * (with a special "cloned finally" EH table entry).
11701 * Return 'true' for case #1, and 'false' otherwise.
11703 bool Compiler::fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block)
11705 // Some simple preconditions (as stated above)
11706 assert(!fgFuncletsCreated);
11707 assert(fgGetPredForBlock(block, predBlock) != nullptr);
11708 assert(block->hasHndIndex());
11710 EHblkDsc* xtab = ehGetDsc(block->getHndIndex());
11712 #if FEATURE_EH_CALLFINALLY_THUNKS
11713 if (xtab->HasFinallyHandler())
11715 assert((xtab->ebdHndBeg == block) || // The normal case
11716 ((xtab->ebdHndBeg->bbNext == block) &&
11717 (xtab->ebdHndBeg->bbFlags & BBF_INTERNAL))); // After we've already inserted a header block, and we're
11718 // trying to decide how to split up the predecessor edges.
11719 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
11721 assert(predBlock->bbJumpDest == block);
11723 // A BBJ_CALLFINALLY predecessor of the handler can only come from the corresponding try,
11724 // not from any EH clauses nested in this handler. However, we represent the BBJ_CALLFINALLY
11725 // as being in the 'try' region's parent EH region, which might be the main function body.
11727 unsigned tryIndex = xtab->ebdEnclosingTryIndex;
11728 if (tryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
11730 assert(!predBlock->hasTryIndex());
11734 assert(predBlock->hasTryIndex());
11735 assert(tryIndex == predBlock->getTryIndex());
11736 assert(ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
11741 #endif // FEATURE_EH_CALLFINALLY_THUNKS
11743 assert(predBlock->hasHndIndex() || predBlock->hasTryIndex());
11745 // We could search the try region looking for predBlock by using bbInTryRegions
11746 // but that does a lexical search for the block, and then assumes funclets
11747 // have been created and does a lexical search of all funclets that were pulled
11748 // out of the parent try region.
11749 // First, funclets haven't been created yet, and even if they had been, we shouldn't
11750 // have any funclet directly branching to another funclet (they have to return first).
11751 // So we can safely use CheckIsTryRegion instead of bbInTryRegions.
11752 // Second, I believe the depth of any EH graph will on average be smaller than the
11753 // breadth of the blocks within a try body. Thus it is faster to get our answer by
11754 // looping outward over the region graph. However, I have added asserts, as a
11755 // precaution, to ensure both algorithms agree. The asserts also check that the only
11756 // way to reach the head of a funclet is from the corresponding try body or from
11757 // within the funclet (and *not* any nested funclets).
11759 if (predBlock->hasTryIndex())
11761 // Because the EH clauses are listed inside-out, any nested trys will be at a
11762 // lower index than the current try and if there's no enclosing try, tryIndex
11763 // will terminate at NO_ENCLOSING_INDEX
11765 unsigned tryIndex = predBlock->getTryIndex();
11766 while (tryIndex < block->getHndIndex())
11768 tryIndex = ehGetEnclosingTryIndex(tryIndex);
11770 // tryIndex should enclose predBlock
11771 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
11773 // At this point tryIndex is either block's handler's corresponding try body
11774 // or some outer try region that contains both predBlock & block or
11775 // NO_ENCLOSING_REGION (because there was no try body that encloses both).
11776 if (tryIndex == block->getHndIndex())
11778 assert(xtab->InTryRegionBBRange(predBlock));
11779 assert(!xtab->InHndRegionBBRange(predBlock));
11782 // tryIndex should enclose block (and predBlock as previously asserted)
11783 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(block));
11785 if (xtab->HasFilter())
11787 // The block is a handler. Check if the pred block is from its filter. We only need to
11788 // check the end filter flag, as there is only a single filter for any handler, and we
11789 // already know predBlock is a predecessor of block.
11790 if (predBlock->bbJumpKind == BBJ_EHFILTERRET)
11792 assert(!xtab->InHndRegionBBRange(predBlock));
11796 // It is not in our try region (or filter), so it must be within this handler (or try bodies
11797 // within this handler)
11798 assert(!xtab->InTryRegionBBRange(predBlock));
11799 assert(xtab->InHndRegionBBRange(predBlock));
11803 /*****************************************************************************
11804 * Does this block, first block of a handler region, have any predecessor edges
11805 * that are not from its corresponding try region?
11808 bool Compiler::fgAnyIntraHandlerPreds(BasicBlock* block)
11810 assert(block->hasHndIndex());
11811 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
11815 for (pred = block->bbPreds; pred; pred = pred->flNext)
11817 BasicBlock* predBlock = pred->flBlock;
11819 if (fgIsIntraHandlerPred(predBlock, block))
11821 // We have a predecessor that is not from our try region
11829 /*****************************************************************************
11830 * Introduce a new head block of the handler for the prolog to be put in, ahead
11831 * of the current handler head 'block'.
11832 * Note that this code has some similarities to fgCreateLoopPreHeader().
11835 void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block)
11840 printf("\nCreating funclet prolog header for BB%02u\n", block->bbNum);
11844 assert(block->hasHndIndex());
11845 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
11847 /* Allocate a new basic block */
11849 BasicBlock* newHead = bbNewBasicBlock(BBJ_NONE);
11851 // In fgComputePreds() we set the BBF_JMP_TARGET and BBF_HAS_LABEL for all of the handler entry points
11853 newHead->bbFlags |= (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL);
11854 newHead->inheritWeight(block);
11855 newHead->bbRefs = 0;
11857 fgInsertBBbefore(block, newHead); // insert the new block in the block list
11858 fgExtendEHRegionBefore(block); // Update the EH table to make the prolog block the first block in the block's EH
11861 // fgExtendEHRegionBefore mucks with the bbRefs without updating the pred list, which we will
11862 // do below for this block. So, undo that change.
11863 assert(newHead->bbRefs > 0);
11867 // Distribute the pred list between newHead and block. Incoming edges coming from outside
11868 // the handler go to the prolog. Edges coming from with the handler are back-edges, and
11869 // go to the existing 'block'.
11871 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
11873 BasicBlock* predBlock = pred->flBlock;
11874 if (!fgIsIntraHandlerPred(predBlock, block))
11876 // It's a jump from outside the handler; add it to the newHead preds list and remove
11877 // it from the block preds list.
11879 switch (predBlock->bbJumpKind)
11881 case BBJ_CALLFINALLY:
11882 noway_assert(predBlock->bbJumpDest == block);
11883 predBlock->bbJumpDest = newHead;
11884 fgRemoveRefPred(block, predBlock);
11885 fgAddRefPred(newHead, predBlock);
11889 // The only way into the handler is via a BBJ_CALLFINALLY (to a finally handler), or
11890 // via exception handling.
11891 noway_assert(false);
11897 assert(nullptr == fgGetPredForBlock(block, newHead));
11898 fgAddRefPred(block, newHead);
11900 assert((newHead->bbFlags & (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL)) ==
11901 (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL));
11904 /*****************************************************************************
11906 * Every funclet will have a prolog. That prolog will be inserted as the first instructions
11907 * in the first block of the funclet. If the prolog is also the head block of a loop, we
11908 * would end up with the prolog instructions being executed more than once.
11909 * Check for this by searching the predecessor list for loops, and create a new prolog header
11910 * block when needed. We detect a loop by looking for any predecessor that isn't in the
11911 * handler's try region, since the only way to get into a handler is via that try region.
11914 void Compiler::fgCreateFuncletPrologBlocks()
11916 noway_assert(fgComputePredsDone);
11917 noway_assert(!fgDomsComputed); // this function doesn't maintain the dom sets
11918 assert(!fgFuncletsCreated);
11920 bool prologBlocksCreated = false;
11921 EHblkDsc* HBtabEnd;
11924 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
11926 BasicBlock* head = HBtab->ebdHndBeg;
11928 if (fgAnyIntraHandlerPreds(head))
11930 // We need to create a new block in which to place the prolog, and split the existing
11931 // head block predecessor edges into those that should point to the prolog, and those
11934 // It's arguable that we should just always do this, and not only when we "need to",
11935 // so there aren't two different code paths. However, it's unlikely to be necessary
11936 // for catch handlers because they have an incoming argument (the exception object)
11937 // that needs to get stored or saved, so back-arcs won't normally go to the head. It's
11938 // possible when writing in IL to generate a legal loop (e.g., push an Exception object
11939 // on the stack before jumping back to the catch head), but C# probably won't. This will
11940 // most commonly only be needed for finallys with a do/while loop at the top of the
11943 // Note that we don't check filters. This might be a bug, but filters always have a filter
11944 // object live on entry, so it's at least unlikely (illegal?) that a loop edge targets the
11947 fgInsertFuncletPrologBlock(head);
11948 prologBlocksCreated = true;
11952 if (prologBlocksCreated)
11954 // If we've modified the graph, reset the 'modified' flag, since the dominators haven't
11956 fgModified = false;
11961 JITDUMP("\nAfter fgCreateFuncletPrologBlocks()");
11962 fgDispBasicBlocks();
11963 fgDispHandlerTab();
11966 fgVerifyHandlerTab();
11967 fgDebugCheckBBlist();
11972 /*****************************************************************************
11974 * Function to create funclets out of all EH catch/finally/fault blocks.
11975 * We only move filter and handler blocks, not try blocks.
11978 void Compiler::fgCreateFunclets()
11980 assert(!fgFuncletsCreated);
11985 printf("*************** In fgCreateFunclets()\n");
11989 fgCreateFuncletPrologBlocks();
11993 const unsigned int funcCnt = ehFuncletCount() + 1;
11995 if (!FitsIn<unsigned short>(funcCnt))
11997 IMPL_LIMITATION("Too many funclets");
12000 FuncInfoDsc* funcInfo = new (this, CMK_BasicBlock) FuncInfoDsc[funcCnt];
12002 unsigned short funcIdx;
12004 // Setup the root FuncInfoDsc and prepare to start associating
12005 // FuncInfoDsc's with their corresponding EH region
12006 memset((void*)funcInfo, 0, funcCnt * sizeof(FuncInfoDsc));
12007 assert(funcInfo[0].funKind == FUNC_ROOT);
12010 // Because we iterate from the top to the bottom of the compHndBBtab array, we are iterating
12011 // from most nested (innermost) to least nested (outermost) EH region. It would be reasonable
12012 // to iterate in the opposite order, but the order of funclets shouldn't matter.
12014 // We move every handler region to the end of the function: each handler will become a funclet.
12016 // Note that fgRelocateEHRange() can add new entries to the EH table. However, they will always
12017 // be added *after* the current index, so our iteration here is not invalidated.
12018 // It *can* invalidate the compHndBBtab pointer itself, though, if it gets reallocated!
12020 for (XTnum = 0; XTnum < compHndBBtabCount; XTnum++)
12022 HBtab = ehGetDsc(XTnum); // must re-compute this every loop, since fgRelocateEHRange changes the table
12023 if (HBtab->HasFilter())
12025 assert(funcIdx < funcCnt);
12026 funcInfo[funcIdx].funKind = FUNC_FILTER;
12027 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12030 assert(funcIdx < funcCnt);
12031 funcInfo[funcIdx].funKind = FUNC_HANDLER;
12032 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12033 HBtab->ebdFuncIndex = funcIdx;
12035 fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12038 // We better have populated all of them by now
12039 assert(funcIdx == funcCnt);
12042 compCurrFuncIdx = 0;
12043 compFuncInfos = funcInfo;
12044 compFuncInfoCount = (unsigned short)funcCnt;
12046 fgFuncletsCreated = true;
12051 JITDUMP("\nAfter fgCreateFunclets()");
12052 fgDispBasicBlocks();
12053 fgDispHandlerTab();
12056 fgVerifyHandlerTab();
12057 fgDebugCheckBBlist();
12061 #else // !FEATURE_EH_FUNCLETS
12063 /*****************************************************************************
12065 * Function called to relocate any and all EH regions.
12066 * Only entire consecutive EH regions will be moved and they will be kept together.
12067 * Except for the first block, the range can not have any blocks that jump into or out of the region.
12070 bool Compiler::fgRelocateEHRegions()
12072 bool result = false; // Our return value
12076 printf("*************** In fgRelocateEHRegions()\n");
12079 if (fgCanRelocateEHRegions)
12084 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
12086 // Nested EH regions cannot be moved.
12087 // Also we don't want to relocate an EH region that has a filter
12088 if ((HBtab->ebdHandlerNestingLevel == 0) && !HBtab->HasFilter())
12090 bool movedTry = false;
12092 bool movedHnd = false;
12095 // Only try to move the outermost try region
12096 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
12098 // Move the entire try region if it can be moved
12099 if (HBtab->ebdTryBeg->isRunRarely())
12101 BasicBlock* bTryLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_TRY);
12102 if (bTryLastBB != NULL)
12109 if (verbose && movedTry)
12111 printf("\nAfter relocating an EH try region");
12112 fgDispBasicBlocks();
12113 fgDispHandlerTab();
12115 // Make sure that the predecessor lists are accurate
12116 if (expensiveDebugCheckLevel >= 2)
12118 fgDebugCheckBBlist();
12124 // Currently it is not good to move the rarely run handler regions to the end of the method
12125 // because fgDetermineFirstColdBlock() must put the start of any handler region in the hot section.
12126 CLANG_FORMAT_COMMENT_ANCHOR;
12129 // Now try to move the entire handler region if it can be moved.
12130 // Don't try to move a finally handler unless we already moved the try region.
12131 if (HBtab->ebdHndBeg->isRunRarely() &&
12132 !HBtab->ebdHndBeg->hasTryIndex() &&
12133 (movedTry || !HBtab->HasFinallyHandler()))
12135 BasicBlock* bHndLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12136 if (bHndLastBB != NULL)
12145 if (verbose && movedHnd)
12147 printf("\nAfter relocating an EH handler region");
12148 fgDispBasicBlocks();
12149 fgDispHandlerTab();
12151 // Make sure that the predecessor lists are accurate
12152 if (expensiveDebugCheckLevel >= 2)
12154 fgDebugCheckBBlist();
12163 fgVerifyHandlerTab();
12165 if (verbose && result)
12167 printf("\nAfter fgRelocateEHRegions()");
12168 fgDispBasicBlocks();
12169 fgDispHandlerTab();
12170 // Make sure that the predecessor lists are accurate
12171 fgDebugCheckBBlist();
12178 #endif // !FEATURE_EH_FUNCLETS
12180 bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12182 bool result = false;
12183 if ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin))
12185 flEdgeWeightMin = newWeight;
12190 // We allow for a small amount of inaccuracy in block weight counts.
12191 if (flEdgeWeightMax < newWeight)
12193 // We have already determined that this edge's weight
12194 // is less than newWeight, so we just allow for the slop
12195 if (newWeight <= (flEdgeWeightMax + slop))
12199 if (flEdgeWeightMax != 0)
12201 // We will raise flEdgeWeightMin and Max towards newWeight
12202 flEdgeWeightMin = flEdgeWeightMax;
12203 flEdgeWeightMax = newWeight;
12206 if (wbUsedSlop != nullptr)
12208 *wbUsedSlop = true;
12214 assert(flEdgeWeightMin > newWeight);
12216 // We have already determined that this edge's weight
12217 // is more than newWeight, so we just allow for the slop
12218 if ((newWeight + slop) >= flEdgeWeightMin)
12222 assert(flEdgeWeightMax != 0);
12224 // We will lower flEdgeWeightMin towards newWeight
12225 flEdgeWeightMin = newWeight;
12227 if (wbUsedSlop != nullptr)
12229 *wbUsedSlop = true;
12234 // If we are returning true then we should have adjusted the range so that
12235 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero.
12236 // Also we should have set wbUsedSlop to true.
12237 if (result == true)
12239 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12241 if (wbUsedSlop != nullptr)
12243 assert(*wbUsedSlop == true);
12249 if (result == false)
12251 result = false; // break here
12258 bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12260 bool result = false;
12261 if ((newWeight >= flEdgeWeightMin) && (newWeight <= flEdgeWeightMax))
12263 flEdgeWeightMax = newWeight;
12268 // We allow for a small amount of inaccuracy in block weight counts.
12269 if (flEdgeWeightMax < newWeight)
12271 // We have already determined that this edge's weight
12272 // is less than newWeight, so we just allow for the slop
12273 if (newWeight <= (flEdgeWeightMax + slop))
12277 if (flEdgeWeightMax != 0)
12279 // We will allow this to raise flEdgeWeightMax towards newWeight
12280 flEdgeWeightMax = newWeight;
12283 if (wbUsedSlop != nullptr)
12285 *wbUsedSlop = true;
12291 assert(flEdgeWeightMin > newWeight);
12293 // We have already determined that this edge's weight
12294 // is more than newWeight, so we just allow for the slop
12295 if ((newWeight + slop) >= flEdgeWeightMin)
12299 assert(flEdgeWeightMax != 0);
12301 // We will allow this to lower flEdgeWeightMin and Max towards newWeight
12302 flEdgeWeightMax = flEdgeWeightMin;
12303 flEdgeWeightMin = newWeight;
12305 if (wbUsedSlop != nullptr)
12307 *wbUsedSlop = true;
12312 // If we are returning true then we should have adjusted the range so that
12313 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero
12314 // Also we should have set wbUsedSlop to true, unless it is NULL
12315 if (result == true)
12317 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12319 assert((wbUsedSlop == nullptr) || (*wbUsedSlop == true));
12324 if (result == false)
12326 result = false; // break here
12334 void Compiler::fgPrintEdgeWeights()
12340 // Print out all of the edge weights
12341 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12343 if (bDst->bbPreds != nullptr)
12345 printf(" Edge weights into BB%02u :", bDst->bbNum);
12346 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12348 bSrc = edge->flBlock;
12349 // This is the control flow edge (bSrc -> bDst)
12351 printf("BB%02u ", bSrc->bbNum);
12353 if (edge->flEdgeWeightMin < BB_MAX_WEIGHT)
12355 printf("(%s", refCntWtd2str(edge->flEdgeWeightMin));
12361 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
12363 if (edge->flEdgeWeightMax < BB_MAX_WEIGHT)
12365 printf("..%s", refCntWtd2str(edge->flEdgeWeightMax));
12373 if (edge->flNext != nullptr)
12384 // return true if there is a possibility that the method has a loop (a backedge is present)
12385 bool Compiler::fgMightHaveLoop()
12387 // Don't use a BlockSet for this temporary bitset of blocks: we don't want to have to call EnsureBasicBlockEpoch()
12388 // and potentially change the block epoch.
12390 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
12391 BitVec BLOCKSET_INIT_NOCOPY(blocksSeen, BitVecOps::MakeEmpty(&blockVecTraits));
12393 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
12395 BitVecOps::AddElemD(&blockVecTraits, blocksSeen, block->bbNum);
12397 AllSuccessorIter succsEnd = block->GetAllSuccs(this).end();
12398 for (AllSuccessorIter succs = block->GetAllSuccs(this).begin(); succs != succsEnd; ++succs)
12400 BasicBlock* succ = (*succs);
12401 if (BitVecOps::IsMember(&blockVecTraits, blocksSeen, succ->bbNum))
12410 void Compiler::fgComputeEdgeWeights()
12415 printf("*************** In fgComputeEdgeWeights()\n");
12419 if (fgIsUsingProfileWeights() == false)
12424 printf("fgComputeEdgeWeights() we do not have any profile data so we are not using the edge weights\n");
12427 fgHaveValidEdgeWeights = false;
12428 fgCalledWeight = BB_UNITY_WEIGHT;
12434 fgDispBasicBlocks();
12442 unsigned iterations = 0;
12443 unsigned goodEdgeCountCurrent = 0;
12444 unsigned goodEdgeCountPrevious = 0;
12445 bool inconsistentProfileData = false;
12446 bool hasIncompleteEdgeWeights = false;
12447 unsigned numEdges = 0;
12448 bool usedSlop = false;
12452 BasicBlock::weight_t returnWeight;
12453 BasicBlock::weight_t slop;
12455 // If we have any blocks that did not have profile derived weight
12456 // we will try to fix their weight up here
12459 do // while (changed)
12465 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12467 if (((bDst->bbFlags & BBF_PROF_WEIGHT) == 0) && (bDst->bbPreds != nullptr))
12469 BasicBlock* bOnlyNext;
12471 // This block does not have a profile derived weight
12473 BasicBlock::weight_t newWeight = BB_MAX_WEIGHT;
12475 if (bDst->countOfInEdges() == 1)
12477 // Only one block flows into bDst
12478 bSrc = bDst->bbPreds->flBlock;
12480 // Does this block flow into only one other block
12481 if (bSrc->bbJumpKind == BBJ_NONE)
12483 bOnlyNext = bSrc->bbNext;
12485 else if (bSrc->bbJumpKind == BBJ_ALWAYS)
12487 bOnlyNext = bSrc->bbJumpDest;
12491 bOnlyNext = nullptr;
12494 if ((bOnlyNext == bDst) && ((bSrc->bbFlags & BBF_PROF_WEIGHT) != 0))
12496 // We know the exact weight of bDst
12497 newWeight = bSrc->bbWeight;
12501 // Does this block flow into only one other block
12502 if (bDst->bbJumpKind == BBJ_NONE)
12504 bOnlyNext = bDst->bbNext;
12506 else if (bDst->bbJumpKind == BBJ_ALWAYS)
12508 bOnlyNext = bDst->bbJumpDest;
12512 bOnlyNext = nullptr;
12515 if ((bOnlyNext != nullptr) && (bOnlyNext->bbPreds != nullptr))
12517 // Does only one block flow into bOnlyNext
12518 if (bOnlyNext->countOfInEdges() == 1)
12520 noway_assert(bOnlyNext->bbPreds->flBlock == bDst);
12522 // We know the exact weight of bDst
12523 newWeight = bOnlyNext->bbWeight;
12527 if ((newWeight != BB_MAX_WEIGHT) && (bDst->bbWeight != newWeight))
12531 bDst->bbWeight = newWeight;
12532 if (newWeight == 0)
12534 bDst->bbFlags |= BBF_RUN_RARELY;
12538 bDst->bbFlags &= ~BBF_RUN_RARELY;
12543 // Sum up the weights of all of the return blocks and throw blocks
12544 // This is used when we have a back-edge into block 1
12546 if (((bDst->bbFlags & BBF_PROF_WEIGHT) != 0) &&
12547 ((bDst->bbJumpKind == BBJ_RETURN) || (bDst->bbJumpKind == BBJ_THROW)))
12549 returnWeight += bDst->bbWeight;
12553 // Generally when we synthesize profile estimates we do it in a way where this algorithm will converge
12554 // but downstream opts that remove conditional branches may create a situation where this is not the case.
12555 // For instance a loop that becomes unreachable creates a sort of 'ring oscillator' (See test b539509)
12556 while (changed && iterations < 10);
12559 if (verbose && modified)
12561 printf("fgComputeEdgeWeights() adjusted the weight of some blocks\n");
12562 fgDispBasicBlocks();
12567 // When we are not using profile data we have already setup fgCalledWeight
12568 // only set it here if we are using profile data
12570 if (fgIsUsingProfileWeights())
12572 // If the first block has one ref then it's weight is the fgCalledWeight
12573 // otherwise we have backedge's into the first block so instead
12574 // we use the sum of the return block weights.
12575 // If the profile data has a 0 for the returnWeoght
12576 // then just use the first block weight rather than the 0
12578 if ((fgFirstBB->countOfInEdges() == 1) || (returnWeight == 0))
12580 fgCalledWeight = fgFirstBB->bbWeight;
12584 fgCalledWeight = returnWeight;
12588 // Now we will compute the initial flEdgeWeightMin and flEdgeWeightMax values
12589 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12591 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
12593 // We subtract out the called count so that bDstWeight is
12594 // the sum of all edges that go into this block from this method.
12596 if (bDst == fgFirstBB)
12598 bDstWeight -= fgCalledWeight;
12601 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12603 bool assignOK = true;
12605 bSrc = edge->flBlock;
12606 // We are processing the control flow edge (bSrc -> bDst)
12611 // If the bSrc or bDst blocks do not have exact profile weights
12612 // then we must reset any values that they currently have
12615 if (((bSrc->bbFlags & BBF_PROF_WEIGHT) == 0) || ((bDst->bbFlags & BBF_PROF_WEIGHT) == 0))
12617 edge->flEdgeWeightMin = BB_ZERO_WEIGHT;
12618 edge->flEdgeWeightMax = BB_MAX_WEIGHT;
12621 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
12622 switch (bSrc->bbJumpKind)
12625 case BBJ_EHCATCHRET:
12627 case BBJ_CALLFINALLY:
12628 // We know the exact edge weight
12629 assignOK &= edge->setEdgeWeightMinChecked(bSrc->bbWeight, slop, &usedSlop);
12630 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
12635 case BBJ_EHFINALLYRET:
12636 case BBJ_EHFILTERRET:
12637 if (edge->flEdgeWeightMax > bSrc->bbWeight)
12639 // The maximum edge weight to block can't be greater than the weight of bSrc
12640 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
12645 // We should never have an edge that starts from one of these jump kinds
12646 noway_assert(!"Unexpected bbJumpKind");
12650 // The maximum edge weight to block can't be greater than the weight of bDst
12651 if (edge->flEdgeWeightMax > bDstWeight)
12653 assignOK &= edge->setEdgeWeightMaxChecked(bDstWeight, slop, &usedSlop);
12658 // Here we have inconsistent profile data
12659 inconsistentProfileData = true;
12660 // No point in continuing
12666 fgEdgeCount = numEdges;
12673 goodEdgeCountPrevious = goodEdgeCountCurrent;
12674 goodEdgeCountCurrent = 0;
12675 hasIncompleteEdgeWeights = false;
12677 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12679 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12681 bool assignOK = true;
12683 // We are processing the control flow edge (bSrc -> bDst)
12684 bSrc = edge->flBlock;
12686 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
12687 if (bSrc->bbJumpKind == BBJ_COND)
12690 flowList* otherEdge;
12691 if (bSrc->bbNext == bDst)
12693 otherEdge = fgGetPredForBlock(bSrc->bbJumpDest, bSrc);
12697 otherEdge = fgGetPredForBlock(bSrc->bbNext, bSrc);
12699 noway_assert(edge->flEdgeWeightMin <= edge->flEdgeWeightMax);
12700 noway_assert(otherEdge->flEdgeWeightMin <= otherEdge->flEdgeWeightMax);
12702 // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down
12703 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
12706 assignOK &= edge->setEdgeWeightMinChecked(edge->flEdgeWeightMin + diff, slop, &usedSlop);
12711 otherEdge->setEdgeWeightMaxChecked(otherEdge->flEdgeWeightMax + diff, slop, &usedSlop);
12714 // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down
12715 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
12719 otherEdge->setEdgeWeightMinChecked(otherEdge->flEdgeWeightMin + diff, slop, &usedSlop);
12723 assignOK &= edge->setEdgeWeightMaxChecked(edge->flEdgeWeightMax + diff, slop, &usedSlop);
12728 // Here we have inconsistent profile data
12729 inconsistentProfileData = true;
12730 // No point in continuing
12734 // Now edge->flEdgeWeightMin and otherEdge->flEdgeWeightMax) should add up to bSrc->bbWeight
12735 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
12736 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
12738 // Now otherEdge->flEdgeWeightMin and edge->flEdgeWeightMax) should add up to bSrc->bbWeight
12739 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
12740 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
12746 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12748 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
12750 if (bDstWeight == BB_MAX_WEIGHT)
12752 inconsistentProfileData = true;
12753 // No point in continuing
12758 // We subtract out the called count so that bDstWeight is
12759 // the sum of all edges that go into this block from this method.
12761 if (bDst == fgFirstBB)
12763 bDstWeight -= fgCalledWeight;
12766 UINT64 minEdgeWeightSum = 0;
12767 UINT64 maxEdgeWeightSum = 0;
12769 // Calculate the sums of the minimum and maximum edge weights
12770 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12772 // We are processing the control flow edge (bSrc -> bDst)
12773 bSrc = edge->flBlock;
12775 maxEdgeWeightSum += edge->flEdgeWeightMax;
12776 minEdgeWeightSum += edge->flEdgeWeightMin;
12779 // maxEdgeWeightSum is the sum of all flEdgeWeightMax values into bDst
12780 // minEdgeWeightSum is the sum of all flEdgeWeightMin values into bDst
12782 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12784 bool assignOK = true;
12786 // We are processing the control flow edge (bSrc -> bDst)
12787 bSrc = edge->flBlock;
12788 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
12790 // otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values
12791 // This can be used to compute a lower bound for our minimum edge weight
12792 noway_assert(maxEdgeWeightSum >= edge->flEdgeWeightMax);
12793 UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->flEdgeWeightMax;
12795 // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values
12796 // This can be used to compute an upper bound for our maximum edge weight
12797 noway_assert(minEdgeWeightSum >= edge->flEdgeWeightMin);
12798 UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->flEdgeWeightMin;
12800 if (bDstWeight >= otherMaxEdgesWeightSum)
12802 // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax value
12803 BasicBlock::weight_t minWeightCalc =
12804 (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum);
12805 if (minWeightCalc > edge->flEdgeWeightMin)
12807 assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, slop, &usedSlop);
12811 if (bDstWeight >= otherMinEdgesWeightSum)
12813 // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin value
12814 BasicBlock::weight_t maxWeightCalc =
12815 (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum);
12816 if (maxWeightCalc < edge->flEdgeWeightMax)
12818 assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, slop, &usedSlop);
12824 // Here we have inconsistent profile data
12825 inconsistentProfileData = true;
12826 // No point in continuing
12830 // When flEdgeWeightMin equals flEdgeWeightMax we have a "good" edge weight
12831 if (edge->flEdgeWeightMin == edge->flEdgeWeightMax)
12833 // Count how many "good" edge weights we have
12834 // Each time through we should have more "good" weights
12835 // We exit the while loop when no longer find any new "good" edges
12836 goodEdgeCountCurrent++;
12840 // Remember that we have seen at least one "Bad" edge weight
12841 // so that we will repeat the while loop again
12842 hasIncompleteEdgeWeights = true;
12848 if (inconsistentProfileData)
12850 hasIncompleteEdgeWeights = true;
12854 if (numEdges == goodEdgeCountCurrent)
12856 noway_assert(hasIncompleteEdgeWeights == false);
12860 } while (hasIncompleteEdgeWeights && (goodEdgeCountCurrent > goodEdgeCountPrevious) && (iterations < 8));
12867 if (inconsistentProfileData)
12869 printf("fgComputeEdgeWeights() found inconsistent profile data, not using the edge weights\n");
12873 if (hasIncompleteEdgeWeights)
12875 printf("fgComputeEdgeWeights() was able to compute exact edge weights for %3d of the %3d edges, using "
12877 goodEdgeCountCurrent, numEdges, iterations);
12881 printf("fgComputeEdgeWeights() was able to compute exact edge weights for all of the %3d edges, using "
12883 numEdges, iterations);
12886 fgPrintEdgeWeights();
12891 fgSlopUsedInEdgeWeights = usedSlop;
12892 fgRangeUsedInEdgeWeights = false;
12894 // See if any edge weight are expressed in [min..max] form
12896 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12898 if (bDst->bbPreds != nullptr)
12900 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12902 bSrc = edge->flBlock;
12903 // This is the control flow edge (bSrc -> bDst)
12905 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
12907 fgRangeUsedInEdgeWeights = true;
12911 if (fgRangeUsedInEdgeWeights)
12918 fgHaveValidEdgeWeights = !inconsistentProfileData;
12919 fgEdgeWeightsComputed = true;
12922 // fgOptimizeBranchToEmptyUnconditional:
12923 // optimize a jump to an empty block which ends in an unconditional branch.
12925 // block: source block
12926 // bDest: destination
12927 // Returns: true if we changed the code
12929 bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest)
12931 bool optimizeJump = true;
12933 assert(bDest->isEmpty());
12934 assert(bDest->bbJumpKind == BBJ_ALWAYS);
12936 // We do not optimize jumps between two different try regions.
12937 // However jumping to a block that is not in any try region is OK
12939 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
12941 optimizeJump = false;
12944 // Don't optimize a jump to a removed block
12945 if (bDest->bbJumpDest->bbFlags & BBF_REMOVED)
12947 optimizeJump = false;
12950 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
12951 // Don't optimize a jump to a finally target. For BB1->BB2->BB3, where
12952 // BB2 is a finally target, if we changed BB1 to jump directly to BB3,
12953 // it would skip the finally target. BB1 might be a BBJ_ALWAYS block part
12954 // of a BBJ_CALLFINALLY/BBJ_ALWAYS pair, so changing the finally target
12955 // would change the unwind behavior.
12956 if (bDest->bbFlags & BBF_FINALLY_TARGET)
12958 optimizeJump = false;
12960 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
12962 // Must optimize jump if bDest has been removed
12964 if (bDest->bbFlags & BBF_REMOVED)
12966 optimizeJump = true;
12969 // If we are optimizing using real profile weights
12970 // then don't optimize a conditional jump to an unconditional jump
12971 // until after we have computed the edge weights
12973 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
12975 fgNeedsUpdateFlowGraph = true;
12976 optimizeJump = false;
12984 printf("\nOptimizing a jump to an unconditional jump (BB%02u -> BB%02u -> BB%02u)\n", block->bbNum,
12985 bDest->bbNum, bDest->bbJumpDest->bbNum);
12990 // When we optimize a branch to branch we need to update the profile weight
12991 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
12993 if (fgHaveValidEdgeWeights && ((bDest->bbFlags & BBF_PROF_WEIGHT) != 0))
12995 flowList* edge1 = fgGetPredForBlock(bDest, block);
12996 noway_assert(edge1 != nullptr);
12998 BasicBlock::weight_t edgeWeight;
13000 if (edge1->flEdgeWeightMin != edge1->flEdgeWeightMax)
13003 // We only have an estimate for the edge weight
13005 edgeWeight = (edge1->flEdgeWeightMin + edge1->flEdgeWeightMax) / 2;
13007 // Clear the profile weight flag
13009 bDest->bbFlags &= ~BBF_PROF_WEIGHT;
13014 // We only have the exact edge weight
13016 edgeWeight = edge1->flEdgeWeightMin;
13020 // Update the bDest->bbWeight
13022 if (bDest->bbWeight > edgeWeight)
13024 bDest->bbWeight -= edgeWeight;
13028 bDest->bbWeight = BB_ZERO_WEIGHT;
13029 bDest->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
13032 flowList* edge2 = fgGetPredForBlock(bDest->bbJumpDest, bDest);
13034 if (edge2 != nullptr)
13037 // Update the edge2 min/max weights
13039 if (edge2->flEdgeWeightMin > edge1->flEdgeWeightMin)
13041 edge2->flEdgeWeightMin -= edge1->flEdgeWeightMin;
13045 edge2->flEdgeWeightMin = BB_ZERO_WEIGHT;
13048 if (edge2->flEdgeWeightMax > edge1->flEdgeWeightMin)
13050 edge2->flEdgeWeightMax -= edge1->flEdgeWeightMin;
13054 edge2->flEdgeWeightMax = BB_ZERO_WEIGHT;
13059 // Optimize the JUMP to empty unconditional JUMP to go to the new target
13060 block->bbJumpDest = bDest->bbJumpDest;
13062 fgAddRefPred(bDest->bbJumpDest, block, fgRemoveRefPred(bDest, block));
13069 // fgOptimizeEmptyBlock:
13070 // Does flow optimization of an empty block (can remove it in some cases)
13073 // block: an empty block
13074 // Returns: true if we changed the code
13076 bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block)
13078 assert(block->isEmpty());
13080 BasicBlock* bPrev = block->bbPrev;
13082 switch (block->bbJumpKind)
13088 /* can never happen */
13089 noway_assert(!"Conditional, switch, or throw block with empty body!");
13092 case BBJ_CALLFINALLY:
13094 case BBJ_EHCATCHRET:
13095 case BBJ_EHFINALLYRET:
13096 case BBJ_EHFILTERRET:
13098 /* leave them as is */
13099 /* some compilers generate multiple returns and put all of them at the end -
13100 * to solve that we need the predecessor list */
13106 // A GOTO cannot be to the next block since that
13107 // should have been fixed by the optimization above
13108 // An exception is made for a jump from Hot to Cold
13109 noway_assert(block->bbJumpDest != block->bbNext || ((bPrev != nullptr) && bPrev->isBBCallAlwaysPair()) ||
13110 fgInDifferentRegions(block, block->bbNext));
13112 /* Cannot remove the first BB */
13118 /* Do not remove a block that jumps to itself - used for while (true){} */
13119 if (block->bbJumpDest == block)
13124 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
13125 if (bPrev->bbJumpKind != BBJ_NONE)
13130 // can't allow fall through into cold code
13131 if (block->bbNext == fgFirstColdBlock)
13136 /* Can fall through since this is similar with removing
13137 * a BBJ_NONE block, only the successor is different */
13143 /* special case if this is the first BB */
13146 assert(block == fgFirstBB);
13150 /* If this block follows a BBJ_CALLFINALLY do not remove it
13151 * (because we don't know who may jump to it) */
13152 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
13158 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13159 /* Don't remove finally targets */
13160 if (block->bbFlags & BBF_FINALLY_TARGET)
13162 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13164 #if FEATURE_EH_FUNCLETS
13165 /* Don't remove an empty block that is in a different EH region
13166 * from its successor block, if the block is the target of a
13167 * catch return. It is required that the return address of a
13168 * catch be in the correct EH region, for re-raise of thread
13169 * abort exceptions to work. Insert a NOP in the empty block
13170 * to ensure we generate code for the block, if we keep it.
13173 BasicBlock* succBlock;
13175 if (block->bbJumpKind == BBJ_ALWAYS)
13177 succBlock = block->bbJumpDest;
13181 succBlock = block->bbNext;
13184 if ((succBlock != nullptr) && !BasicBlock::sameEHRegion(block, succBlock))
13186 // The empty block and the block that follows it are in different
13187 // EH regions. Is this a case where they can't be merged?
13189 bool okToMerge = true; // assume it's ok
13190 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
13192 if (pred->flBlock->bbJumpKind == BBJ_EHCATCHRET)
13194 assert(pred->flBlock->bbJumpDest == block);
13195 okToMerge = false; // we can't get rid of the empty block
13202 // Insert a NOP in the empty block to ensure we generate code
13203 // for the catchret target in the right EH region.
13204 GenTree* nop = new (this, GT_NO_OP) GenTree(GT_NO_OP, TYP_VOID);
13206 if (block->IsLIR())
13208 LIR::AsRange(block).InsertAtEnd(nop);
13212 GenTreePtr nopStmt = fgInsertStmtAtEnd(block, nop);
13213 fgSetStmtSeq(nopStmt);
13214 gtSetStmtInfo(nopStmt);
13220 printf("\nKeeping empty block BB%02u - it is the target of a catch return\n", block->bbNum);
13224 break; // go to the next block
13228 #endif // FEATURE_EH_FUNCLETS
13230 if (!ehCanDeleteEmptyBlock(block))
13232 // We're not allowed to remove this block due to reasons related to the EH table.
13236 /* special case if this is the last BB */
13237 if (block == fgLastBB)
13246 /* Remove the block */
13248 fgRemoveBlock(block, false);
13252 noway_assert(!"Unexpected bbJumpKind");
13258 // fgOptimizeSwitchBranches:
13259 // Does flow optimization for a switch - bypasses jumps to empty unconditional branches,
13260 // and transforms degenerate switch cases like those with 1 or 2 targets
13263 // block: BasicBlock that contains the switch
13264 // Returns: true if we changed the code
13266 bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
13268 assert(block->bbJumpKind == BBJ_SWITCH);
13270 unsigned jmpCnt = block->bbJumpSwt->bbsCount;
13271 BasicBlock** jmpTab = block->bbJumpSwt->bbsDstTab;
13272 BasicBlock* bNewDest; // the new jump target for the current switch case
13274 bool returnvalue = false;
13282 // Do we have a JUMP to an empty unconditional JUMP block?
13283 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
13284 (bDest != bDest->bbJumpDest)) // special case for self jumps
13286 bool optimizeJump = true;
13288 // We do not optimize jumps between two different try regions.
13289 // However jumping to a block that is not in any try region is OK
13291 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
13293 optimizeJump = false;
13296 // If we are optimize using real profile weights
13297 // then don't optimize a switch jump to an unconditional jump
13298 // until after we have computed the edge weights
13300 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
13302 fgNeedsUpdateFlowGraph = true;
13303 optimizeJump = false;
13308 bNewDest = bDest->bbJumpDest;
13312 printf("\nOptimizing a switch jump to an empty block with an unconditional jump (BB%02u -> BB%02u "
13314 block->bbNum, bDest->bbNum, bNewDest->bbNum);
13320 if (bNewDest != bDest)
13323 // When we optimize a branch to branch we need to update the profile weight
13324 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
13326 if (fgIsUsingProfileWeights() && ((bDest->bbFlags & BBF_PROF_WEIGHT) != 0))
13328 if (fgHaveValidEdgeWeights)
13330 flowList* edge = fgGetPredForBlock(bDest, block);
13331 BasicBlock::weight_t branchThroughWeight = edge->flEdgeWeightMin;
13333 if (bDest->bbWeight > branchThroughWeight)
13335 bDest->bbWeight -= branchThroughWeight;
13339 bDest->bbWeight = BB_ZERO_WEIGHT;
13340 bDest->bbFlags |= BBF_RUN_RARELY;
13345 // Update the switch jump table
13346 *jmpTab = bNewDest;
13348 // Maintain, if necessary, the set of unique targets of "block."
13349 UpdateSwitchTableTarget(block, bDest, bNewDest);
13351 fgAddRefPred(bNewDest, block, fgRemoveRefPred(bDest, block));
13353 // we optimized a Switch label - goto REPEAT_SWITCH to follow this new jump
13354 returnvalue = true;
13356 goto REPEAT_SWITCH;
13358 } while (++jmpTab, --jmpCnt);
13360 GenTreeStmt* switchStmt = nullptr;
13361 LIR::Range* blockRange = nullptr;
13363 GenTree* switchTree;
13364 if (block->IsLIR())
13366 blockRange = &LIR::AsRange(block);
13367 switchTree = blockRange->LastNode();
13369 assert(switchTree->OperGet() == GT_SWITCH_TABLE);
13373 switchStmt = block->lastStmt();
13374 switchTree = switchStmt->gtStmtExpr;
13376 assert(switchTree->OperGet() == GT_SWITCH);
13379 noway_assert(switchTree->gtType == TYP_VOID);
13381 // At this point all of the case jump targets have been updated such
13382 // that none of them go to block that is an empty unconditional block
13384 jmpTab = block->bbJumpSwt->bbsDstTab;
13385 jmpCnt = block->bbJumpSwt->bbsCount;
13386 // Now check for two trivial switch jumps.
13388 if (block->NumSucc(this) == 1)
13390 // Use BBJ_ALWAYS for a switch with only a default clause, or with only one unique successor.
13391 BasicBlock* uniqueSucc = jmpTab[0];
13396 printf("\nRemoving a switch jump with a single target (BB%02u)\n", block->bbNum);
13397 printf("BEFORE:\n");
13401 if (block->IsLIR())
13404 unsigned sideEffects;
13405 LIR::ReadOnlyRange switchTreeRange = blockRange->GetTreeRange(switchTree, &isClosed, &sideEffects);
13407 // The switch tree should form a contiguous, side-effect free range by construction. See
13408 // Lowering::LowerSwitch for details.
13410 assert((sideEffects & GTF_ALL_EFFECT) == 0);
13412 blockRange->Delete(this, block, std::move(switchTreeRange));
13416 /* check for SIDE_EFFECTS */
13417 if (switchTree->gtFlags & GTF_SIDE_EFFECT)
13419 /* Extract the side effects from the conditional */
13420 GenTreePtr sideEffList = nullptr;
13422 gtExtractSideEffList(switchTree, &sideEffList);
13424 if (sideEffList == nullptr)
13426 goto NO_SWITCH_SIDE_EFFECT;
13429 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
13434 printf("\nSwitch expression has side effects! Extracting side effects...\n");
13435 gtDispTree(switchTree);
13437 gtDispTree(sideEffList);
13442 /* Replace the conditional statement with the list of side effects */
13443 noway_assert(sideEffList->gtOper != GT_STMT);
13444 noway_assert(sideEffList->gtOper != GT_SWITCH);
13446 switchStmt->gtStmtExpr = sideEffList;
13448 if (fgStmtListThreaded)
13450 /* Update the lclvar ref counts */
13452 fgUpdateRefCntForExtract(switchTree, sideEffList);
13454 /* Update ordering, costs, FP levels, etc. */
13455 gtSetStmtInfo(switchStmt);
13457 /* Re-link the nodes for this statement */
13458 fgSetStmtSeq(switchStmt);
13464 NO_SWITCH_SIDE_EFFECT:
13466 /* conditional has NO side effect - remove it */
13467 fgRemoveStmt(block, switchStmt);
13471 // Change the switch jump into a BBJ_ALWAYS
13472 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
13473 block->bbJumpKind = BBJ_ALWAYS;
13476 for (unsigned i = 1; i < jmpCnt; ++i)
13478 (void)fgRemoveRefPred(jmpTab[i], block);
13484 else if (block->bbJumpSwt->bbsCount == 2 && block->bbJumpSwt->bbsDstTab[1] == block->bbNext)
13486 /* Use a BBJ_COND(switchVal==0) for a switch with only one
13487 significant clause besides the default clause, if the
13488 default clause is bbNext */
13489 GenTree* switchVal = switchTree->gtOp.gtOp1;
13490 noway_assert(genActualTypeIsIntOrI(switchVal->TypeGet()));
13492 // If we are in LIR, remove the jump table from the block.
13493 if (block->IsLIR())
13495 GenTree* jumpTable = switchTree->gtOp.gtOp2;
13496 assert(jumpTable->OperGet() == GT_JMPTABLE);
13497 blockRange->Remove(jumpTable);
13500 // Change the GT_SWITCH(switchVal) into GT_JTRUE(GT_EQ(switchVal==0)).
13501 // Also mark the node as GTF_DONT_CSE as further down JIT is not capable of handling it.
13502 // For example CSE could determine that the expression rooted at GT_EQ is a candidate cse and
13503 // replace it with a COMMA node. In such a case we will end up with GT_JTRUE node pointing to
13504 // a COMMA node which results in noway asserts in fgMorphSmpOp(), optAssertionGen() and rpPredictTreeRegUse().
13505 // For the same reason fgMorphSmpOp() marks GT_JTRUE nodes with RELOP children as GTF_DONT_CSE.
13506 CLANG_FORMAT_COMMENT_ANCHOR;
13511 printf("\nConverting a switch (BB%02u) with only one significant clause besides a default target to a "
13512 "conditional branch\n",
13517 switchTree->ChangeOper(GT_JTRUE);
13518 GenTree* zeroConstNode = gtNewZeroConNode(genActualType(switchVal->TypeGet()));
13519 GenTree* condNode = gtNewOperNode(GT_EQ, TYP_INT, switchVal, zeroConstNode);
13520 switchTree->gtOp.gtOp1 = condNode;
13521 switchTree->gtOp.gtOp1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
13523 if (block->IsLIR())
13525 blockRange->InsertAfter(switchVal, zeroConstNode, condNode);
13529 // Re-link the nodes for this statement.
13530 fgSetStmtSeq(switchStmt);
13533 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
13534 block->bbJumpKind = BBJ_COND;
13538 return returnvalue;
13541 // fgBlockEndFavorsTailDuplication:
13542 // Heuristic function that returns true if this block ends in a statement that looks favorable
13543 // for tail-duplicating its successor (such as assigning a constant to a local).
13545 // block: BasicBlock we are considering duplicating the successor of
13547 // true if it seems like a good idea
13549 bool Compiler::fgBlockEndFavorsTailDuplication(BasicBlock* block)
13551 if (block->isRunRarely())
13556 if (!block->lastStmt())
13562 // Tail duplication tends to pay off when the last statement
13563 // is an assignment of a constant, arraylength, or a relop.
13564 // This is because these statements produce information about values
13565 // that would otherwise be lost at the upcoming merge point.
13567 GenTreeStmt* lastStmt = block->lastStmt();
13568 GenTree* tree = lastStmt->gtStmtExpr;
13569 if (tree->gtOper != GT_ASG)
13574 GenTree* op2 = tree->gtOp.gtOp2;
13575 if (op2->gtOper != GT_ARR_LENGTH && !op2->OperIsConst() && ((op2->OperKind() & GTK_RELOP) == 0))
13583 // fgBlockIsGoodTailDuplicationCandidate:
13584 // Heuristic function that examines a block (presumably one that is a merge point) to determine
13585 // if it should be duplicated.
13587 // target - the tail block (candidate for duplication)
13589 // true if this block seems like a good candidate for duplication
13591 bool Compiler::fgBlockIsGoodTailDuplicationCandidate(BasicBlock* target)
13593 GenTreeStmt* stmt = target->FirstNonPhiDef();
13595 // Here we are looking for blocks with a single statement feeding a conditional branch.
13596 // These blocks are small, and when duplicated onto the tail of blocks that end in
13597 // assignments, there is a high probability of the branch completely going away.
13599 // This is by no means the only kind of tail that it is beneficial to duplicate,
13600 // just the only one we recognize for now.
13602 if (stmt != target->lastStmt())
13607 if (target->bbJumpKind != BBJ_COND)
13612 GenTree* tree = stmt->gtStmtExpr;
13614 if (tree->gtOper != GT_JTRUE)
13619 // must be some kind of relational operator
13620 GenTree* cond = tree->gtOp.gtOp1;
13621 if (!(cond->OperKind() & GTK_RELOP))
13626 // op1 must be some combinations of casts of local or constant
13627 GenTree* op1 = cond->gtOp.gtOp1;
13628 while (op1->gtOper == GT_CAST)
13630 op1 = op1->gtOp.gtOp1;
13632 if (!op1->IsLocal() && !op1->OperIsConst())
13637 // op2 must be some combinations of casts of local or constant
13638 GenTree* op2 = cond->gtOp.gtOp2;
13639 while (op2->gtOper == GT_CAST)
13641 op2 = op2->gtOp.gtOp1;
13643 if (!op2->IsLocal() && !op2->OperIsConst())
13651 // fgOptimizeUncondBranchToSimpleCond:
13652 // For a block which has an unconditional branch, look to see if its target block
13653 // is a good candidate for tail duplication, and if so do that duplication.
13656 // block - block with uncond branch
13657 // target - block which is target of first block
13659 // returns: true if changes were made
13661 bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target)
13663 assert(block->bbJumpKind == BBJ_ALWAYS);
13664 assert(block->bbJumpDest == target);
13666 // TODO-Review: OK if they are in the same region?
13667 if (compHndBBtabCount > 0)
13672 if (!fgBlockIsGoodTailDuplicationCandidate(target))
13677 if (!fgBlockEndFavorsTailDuplication(block))
13682 // NOTE: we do not currently hit this assert because this function is only called when
13683 // `fgUpdateFlowGraph` has been called with `doTailDuplication` set to true, and the
13684 // backend always calls `fgUpdateFlowGraph` with `doTailDuplication` set to false.
13685 assert(!block->IsLIR());
13687 GenTreeStmt* stmt = target->FirstNonPhiDef();
13688 assert(stmt == target->lastStmt());
13690 // Duplicate the target block at the end of this block
13692 GenTree* cloned = gtCloneExpr(stmt->gtStmtExpr);
13693 noway_assert(cloned);
13694 GenTree* jmpStmt = gtNewStmt(cloned);
13696 block->bbJumpKind = BBJ_COND;
13697 block->bbJumpDest = target->bbJumpDest;
13698 fgAddRefPred(block->bbJumpDest, block);
13699 fgRemoveRefPred(target, block);
13701 // add an unconditional block after this block to jump to the target block's fallthrough block
13703 BasicBlock* next = fgNewBBafter(BBJ_ALWAYS, block, true);
13704 next->bbFlags = block->bbFlags | BBF_INTERNAL;
13705 next->bbFlags &= ~(BBF_TRY_BEG | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1 | BBF_HAS_LABEL | BBF_JMP_TARGET |
13706 BBF_FUNCLET_BEG | BBF_LOOP_PREHEADER | BBF_KEEP_BBJ_ALWAYS);
13708 next->bbJumpDest = target->bbNext;
13709 target->bbNext->bbFlags |= BBF_JMP_TARGET;
13710 fgAddRefPred(next, block);
13711 fgAddRefPred(next->bbJumpDest, next);
13716 printf("fgOptimizeUncondBranchToSimpleCond(from BB%02u to cond BB%02u), created new uncond BB%02u\n",
13717 block->bbNum, target->bbNum, next->bbNum);
13721 if (fgStmtListThreaded)
13723 gtSetStmtInfo(jmpStmt);
13726 fgInsertStmtAtEnd(block, jmpStmt);
13731 // fgOptimizeBranchToNext:
13732 // Optimize a block which has a branch to the following block
13734 // block - block with a branch
13735 // bNext - block which is both next and the target of the first block
13736 // bPrev - block which is prior to the first block
13738 // returns: true if changes were made
13740 bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev)
13742 assert(block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS);
13743 assert(block->bbJumpDest == bNext);
13744 assert(block->bbNext = bNext);
13745 assert(block->bbPrev == bPrev);
13747 if (block->bbJumpKind == BBJ_ALWAYS)
13749 // We can't remove it if it is a branch from hot => cold
13750 if (!fgInDifferentRegions(block, bNext))
13752 // We can't remove if it is marked as BBF_KEEP_BBJ_ALWAYS
13753 if (!(block->bbFlags & BBF_KEEP_BBJ_ALWAYS))
13755 // We can't remove if the BBJ_ALWAYS is part of a BBJ_CALLFINALLY pair
13756 if ((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair())
13758 /* the unconditional jump is to the next BB */
13759 block->bbJumpKind = BBJ_NONE;
13760 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
13764 printf("\nRemoving unconditional jump to next block (BB%02u -> BB%02u) (converted BB%02u to "
13766 block->bbNum, bNext->bbNum, block->bbNum);
13776 /* remove the conditional statement at the end of block */
13777 noway_assert(block->bbJumpKind == BBJ_COND);
13778 noway_assert(block->bbTreeList);
13783 printf("\nRemoving conditional jump to next block (BB%02u -> BB%02u)\n", block->bbNum, bNext->bbNum);
13787 if (block->IsLIR())
13789 LIR::Range& blockRange = LIR::AsRange(block);
13790 GenTree* jmp = blockRange.LastNode();
13791 assert(jmp->OperGet() == GT_JTRUE);
13794 unsigned sideEffects;
13795 LIR::ReadOnlyRange jmpRange = blockRange.GetTreeRange(jmp, &isClosed, &sideEffects);
13797 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
13798 // diffs compared to the existing backend.
13799 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
13801 // If the jump and its operands form a contiguous, side-effect-free range,
13803 blockRange.Delete(this, block, std::move(jmpRange));
13807 // Otherwise, just remove the jump node itself.
13808 blockRange.Remove(jmp);
13813 GenTreeStmt* cond = block->lastStmt();
13814 noway_assert(cond->gtStmtExpr->gtOper == GT_JTRUE);
13816 /* check for SIDE_EFFECTS */
13817 if (cond->gtStmtExpr->gtFlags & GTF_SIDE_EFFECT)
13819 /* Extract the side effects from the conditional */
13820 GenTreePtr sideEffList = nullptr;
13822 gtExtractSideEffList(cond->gtStmtExpr, &sideEffList);
13824 if (sideEffList == nullptr)
13827 fgRemoveStmt(block, cond);
13831 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
13835 printf("\nConditional has side effects! Extracting side effects...\n");
13838 gtDispTree(sideEffList);
13843 /* Replace the conditional statement with the list of side effects */
13844 noway_assert(sideEffList->gtOper != GT_STMT);
13845 noway_assert(sideEffList->gtOper != GT_JTRUE);
13847 cond->gtStmtExpr = sideEffList;
13849 if (fgStmtListThreaded)
13851 /* Update the lclvar ref counts */
13853 fgUpdateRefCntForExtract(cond->gtStmtExpr, sideEffList);
13855 /* Update ordering, costs, FP levels, etc. */
13856 gtSetStmtInfo(cond);
13858 /* Re-link the nodes for this statement */
13859 fgSetStmtSeq(cond);
13866 /* conditional has NO side effect - remove it */
13867 fgRemoveStmt(block, cond);
13871 /* Conditional is gone - simply fall into the next block */
13873 block->bbJumpKind = BBJ_NONE;
13874 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
13876 /* Update bbRefs and bbNum - Conditional predecessors to the same
13877 * block are counted twice so we have to remove one of them */
13879 noway_assert(bNext->countOfInEdges() > 1);
13880 fgRemoveRefPred(bNext, block);
13887 /*****************************************************************************
13889 * Function called to optimize an unconditional branch that branches
13890 * to a conditional branch.
13891 * Currently we require that the conditional branch jump back to the
13892 * block that follows the unconditional branch.
13894 * We can improve the code execution and layout by concatenating a copy
13895 * of the conditional branch block at the end of the conditional branch
13896 * and reversing the sense of the branch.
13898 * This is only done when the amount of code to be copied is smaller than
13899 * our calculated threshold in maxDupCostSz.
13903 bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
13905 if (opts.MinOpts())
13910 if (bJump->bbJumpKind != BBJ_ALWAYS)
13915 if (bJump->bbFlags & BBF_KEEP_BBJ_ALWAYS)
13920 // Don't hoist a conditional branch into the scratch block; we'd prefer it stay
13921 // either BBJ_NONE or BBJ_ALWAYS.
13922 if (fgBBisScratch(bJump))
13927 BasicBlock* bDest = bJump->bbJumpDest;
13929 if (bDest->bbJumpKind != BBJ_COND)
13934 if (bDest->bbJumpDest != bJump->bbNext)
13939 // 'bJump' must be in the same try region as the condition, since we're going to insert
13940 // a duplicated condition in 'bJump', and the condition might include exception throwing code.
13941 if (!BasicBlock::sameTryRegion(bJump, bDest))
13946 // do not jump into another try region
13947 BasicBlock* bDestNext = bDest->bbNext;
13948 if (bDestNext->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNext))
13953 // This function is only called by fgReorderBlocks, which we do not run in the backend.
13954 // If we wanted to run block reordering in the backend, we would need to be able to
13955 // calculate cost information for LIR on a per-node basis in order for this function
13957 assert(!bJump->IsLIR());
13958 assert(!bDest->IsLIR());
13961 unsigned estDupCostSz = 0;
13962 for (stmt = bDest->firstStmt(); stmt; stmt = stmt->gtNextStmt)
13964 GenTreePtr expr = stmt->gtStmtExpr;
13966 /* We call gtPrepareCost to measure the cost of duplicating this tree */
13967 gtPrepareCost(expr);
13969 estDupCostSz += expr->gtCostSz;
13972 bool allProfileWeightsAreValid = false;
13973 BasicBlock::weight_t weightJump = bJump->bbWeight;
13974 BasicBlock::weight_t weightDest = bDest->bbWeight;
13975 BasicBlock::weight_t weightNext = bJump->bbNext->bbWeight;
13976 bool rareJump = bJump->isRunRarely();
13977 bool rareDest = bDest->isRunRarely();
13978 bool rareNext = bJump->bbNext->isRunRarely();
13980 // If we have profile data then we calculate the number of time
13981 // the loop will iterate into loopIterations
13982 if (fgIsUsingProfileWeights())
13984 // Only rely upon the profile weight when all three of these blocks
13985 // have either good profile weights or are rarelyRun
13987 if ((bJump->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
13988 (bDest->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
13989 (bJump->bbNext->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)))
13991 allProfileWeightsAreValid = true;
13993 if ((weightJump * 100) < weightDest)
13998 if ((weightNext * 100) < weightDest)
14003 if (((weightDest * 100) < weightJump) && ((weightDest * 100) < weightNext))
14010 unsigned maxDupCostSz = 6;
14013 // Branches between the hot and rarely run regions
14014 // should be minimized. So we allow a larger size
14016 if (rareDest != rareJump)
14021 if (rareDest != rareNext)
14027 // We we are ngen-ing:
14028 // If the uncondional branch is a rarely run block then
14029 // we are willing to have more code expansion since we
14030 // won't be running code from this page
14032 if (opts.eeFlags & CORJIT_FLG_PREJIT)
14040 // If the compare has too high cost then we don't want to dup
14042 bool costIsTooHigh = (estDupCostSz > maxDupCostSz);
14047 printf("\nDuplication of the conditional block BB%02u (always branch from BB%02u) %s, because the cost of "
14048 "duplication (%i) is %s than %i,"
14049 " validProfileWeights = %s\n",
14050 bDest->bbNum, bJump->bbNum, costIsTooHigh ? "not done" : "performed", estDupCostSz,
14051 costIsTooHigh ? "greater" : "less or equal", maxDupCostSz, allProfileWeightsAreValid ? "true" : "false");
14060 /* Looks good - duplicate the conditional block */
14062 GenTree* newStmtList = nullptr; // new stmt list to be added to bJump
14063 GenTree* newStmtLast = nullptr;
14064 bool cloneExprFailed = false;
14066 /* Visit all the statements in bDest */
14068 for (GenTree* curStmt = bDest->bbTreeList; curStmt; curStmt = curStmt->gtNext)
14070 /* Clone/substitute the expression */
14072 stmt = gtCloneExpr(curStmt)->AsStmt();
14074 // cloneExpr doesn't handle everything
14076 if (stmt == nullptr)
14078 cloneExprFailed = true;
14082 /* Append the expression to our list */
14084 if (newStmtList != nullptr)
14086 newStmtLast->gtNext = stmt;
14090 newStmtList = stmt;
14093 stmt->gtPrev = newStmtLast;
14094 newStmtLast = stmt;
14097 if (cloneExprFailed)
14102 noway_assert(newStmtLast != nullptr);
14103 noway_assert(stmt != nullptr);
14104 noway_assert(stmt->gtOper == GT_STMT);
14106 if ((newStmtLast == nullptr) || (stmt == nullptr) || (stmt->gtOper != GT_STMT))
14111 /* Get to the condition node from the statement tree */
14113 GenTreePtr condTree = stmt->gtStmtExpr;
14114 noway_assert(condTree->gtOper == GT_JTRUE);
14116 if (condTree->gtOper != GT_JTRUE)
14122 // Set condTree to the operand to the GT_JTRUE
14124 condTree = condTree->gtOp.gtOp1;
14127 // This condTree has to be a RelOp comparison
14129 if (condTree->OperIsCompare() == false)
14134 // Bump up the ref-counts of any variables in 'stmt'
14135 fgUpdateRefCntForClone(bJump, stmt->gtStmtExpr);
14138 // Find the last statement in the bJump block
14140 GenTreeStmt* lastStmt = nullptr;
14141 for (stmt = bJump->firstStmt(); stmt; stmt = stmt->gtNextStmt)
14145 stmt = bJump->firstStmt();
14147 /* Join the two linked lists */
14148 newStmtLast->gtNext = nullptr;
14150 if (lastStmt != nullptr)
14152 stmt->gtPrev = newStmtLast;
14153 lastStmt->gtNext = newStmtList;
14154 newStmtList->gtPrev = lastStmt;
14158 bJump->bbTreeList = newStmtList;
14159 newStmtList->gtPrev = newStmtLast;
14163 // Reverse the sense of the compare
14165 gtReverseCond(condTree);
14167 bJump->bbJumpKind = BBJ_COND;
14168 bJump->bbJumpDest = bDest->bbNext;
14170 /* Mark the jump dest block as being a jump target */
14171 bJump->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
14173 // We need to update the following flags of the bJump block if they were set in the bbJumpDest block
14174 bJump->bbFlags |= (bJump->bbJumpDest->bbFlags
14175 & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY | BBF_HAS_NULLCHECK | BBF_HAS_IDX_LEN | BBF_HAS_VTABREF));
14177 /* Update bbRefs and bbPreds */
14179 // bJump now falls through into the next block
14181 fgAddRefPred(bJump->bbNext, bJump);
14183 // bJump no longer jumps to bDest
14185 fgRemoveRefPred(bDest, bJump);
14187 // bJump now jumps to bDest->bbNext
14189 fgAddRefPred(bDest->bbNext, bJump);
14191 if (weightJump > 0)
14193 if (allProfileWeightsAreValid)
14195 if (weightDest > weightJump)
14197 bDest->bbWeight = (weightDest - weightJump);
14199 else if (!bDest->isRunRarely())
14201 bDest->bbWeight = BB_UNITY_WEIGHT;
14206 BasicBlock::weight_t newWeightDest = 0;
14207 BasicBlock::weight_t unloopWeightDest = 0;
14209 if (weightDest > weightJump)
14211 newWeightDest = (weightDest - weightJump);
14213 if (weightDest >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2)
14215 newWeightDest = (weightDest * 2) / (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT);
14217 if ((newWeightDest > 0) || (unloopWeightDest > 0))
14219 bDest->bbWeight = Max(newWeightDest, unloopWeightDest);
14227 printf("\nAfter this change in fgOptimizeBranch");
14228 fgDispBasicBlocks(verboseTrees);
14236 /*****************************************************************************
14238 * Function called to optimize switch statements
14241 bool Compiler::fgOptimizeSwitchJumps()
14243 bool result = false; // Our return value
14246 // TODO-CQ: Add switch jump optimizations?
14250 if (!fgHaveValidEdgeWeights)
14253 for (BasicBlock* bSrc = fgFirstBB; bSrc != NULL; bSrc = bSrc->bbNext)
14255 if (bSrc->bbJumpKind == BBJ_SWITCH)
14257 unsigned jumpCnt; jumpCnt = bSrc->bbJumpSwt->bbsCount;
14258 BasicBlock** jumpTab; jumpTab = bSrc->bbJumpSwt->bbsDstTab;
14262 BasicBlock* bDst = *jumpTab;
14263 flowList* edgeToDst = fgGetPredForBlock(bDst, bSrc);
14264 double outRatio = (double) edgeToDst->flEdgeWeightMin / (double) bSrc->bbWeight;
14266 if (outRatio >= 0.60)
14268 // straighten switch here...
14271 while (++jumpTab, --jumpCnt);
14280 #pragma warning(push)
14281 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
14283 /*****************************************************************************
14285 * Function called to reorder the flowgraph of BasicBlocks such that any
14286 * rarely run blocks are placed at the end of the block list.
14287 * If we have profile information we also use that information to reverse
14288 * all conditional jumps that would benefit.
14291 void Compiler::fgReorderBlocks()
14293 noway_assert(opts.compDbgCode == false);
14295 #if FEATURE_EH_FUNCLETS
14296 assert(fgFuncletsCreated);
14297 #endif // FEATURE_EH_FUNCLETS
14299 // We can't relocate anything if we only have one block
14300 if (fgFirstBB->bbNext == nullptr)
14305 bool newRarelyRun = false;
14306 bool movedBlocks = false;
14307 bool optimizedSwitches = false;
14309 // First let us expand the set of run rarely blocks
14310 newRarelyRun |= fgExpandRarelyRunBlocks();
14312 #if !FEATURE_EH_FUNCLETS
14313 movedBlocks |= fgRelocateEHRegions();
14314 #endif // !FEATURE_EH_FUNCLETS
14317 // If we are using profile weights we can change some
14318 // switch jumps into conditional test and jump
14320 if (fgIsUsingProfileWeights())
14323 // Note that this is currently not yet implemented
14325 optimizedSwitches = fgOptimizeSwitchJumps();
14326 if (optimizedSwitches)
14328 fgUpdateFlowGraph();
14335 printf("*************** In fgReorderBlocks()\n");
14337 printf("\nInitial BasicBlocks");
14338 fgDispBasicBlocks(verboseTrees);
14349 // Iterate over every block, remembering our previous block in bPrev
14350 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
14353 // Consider relocating the rarely run blocks such that they are at the end of the method.
14354 // We also consider reversing conditional branches so that they become a not taken forwards branch.
14357 // If block is marked with a BBF_KEEP_BBJ_ALWAYS flag then we don't move the block
14358 if ((block->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
14363 // Finally and handlers blocks are to be kept contiguous.
14364 // TODO-CQ: Allow reordering within the handler region
14365 if (block->hasHndIndex() == true)
14370 bool reorderBlock = true; // This is set to false if we decide not to reorder 'block'
14371 bool isRare = block->isRunRarely();
14372 BasicBlock* bDest = nullptr;
14373 bool forwardBranch = false;
14374 bool backwardBranch = false;
14377 if ((bPrev->bbJumpKind == BBJ_COND) || (bPrev->bbJumpKind == BBJ_ALWAYS))
14379 bDest = bPrev->bbJumpDest;
14380 forwardBranch = fgIsForwardBranch(bPrev);
14381 backwardBranch = !forwardBranch;
14384 // We will look for bPrev as a non rarely run block followed by block as a rarely run block
14386 if (bPrev->isRunRarely())
14388 reorderBlock = false;
14391 // If the weights of the bPrev, block and bDest were all obtained from a profile run
14392 // then we can use them to decide if it is useful to reverse this conditional branch
14394 BasicBlock::weight_t profHotWeight = -1;
14396 if ((bPrev->bbFlags & BBF_PROF_WEIGHT) && (block->bbFlags & BBF_PROF_WEIGHT) &&
14397 ((bDest == nullptr) || (bDest->bbFlags & BBF_PROF_WEIGHT)))
14400 // All blocks have profile information
14404 if (bPrev->bbJumpKind == BBJ_ALWAYS)
14406 // We can pull up the blocks that the unconditional jump branches to
14407 // if the weight of bDest is greater or equal to the weight of block
14408 // also the weight of bDest can't be zero.
14410 if ((bDest->bbWeight < block->bbWeight) || (bDest->bbWeight == 0))
14412 reorderBlock = false;
14417 // If this remains true then we will try to pull up bDest to succeed bPrev
14419 bool moveDestUp = true;
14421 if (fgHaveValidEdgeWeights)
14424 // The edge bPrev -> bDest must have a higher minimum weight
14425 // than every other edge into bDest
14427 flowList* edgeFromPrev = fgGetPredForBlock(bDest, bPrev);
14428 noway_assert(edgeFromPrev != nullptr);
14430 // Examine all of the other edges into bDest
14431 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
14433 if (edge != edgeFromPrev)
14435 if (edge->flEdgeWeightMax >= edgeFromPrev->flEdgeWeightMin)
14437 moveDestUp = false;
14446 // The block bPrev must have a higher weight
14447 // than every other block that goes into bDest
14450 // Examine all of the other edges into bDest
14451 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
14453 BasicBlock* bTemp = edge->flBlock;
14455 if ((bTemp != bPrev) && (bTemp->bbWeight >= bPrev->bbWeight))
14457 moveDestUp = false;
14463 // Are we still good to move bDest up to bPrev?
14467 // We will consider all blocks that have less weight than profHotWeight to be
14468 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
14470 profHotWeight = bDest->bbWeight - 1;
14474 if (block->isRunRarely())
14476 // We will move any rarely run blocks blocks
14481 // We will move all blocks that have a weight less or equal to our fall through block
14482 profHotWeight = block->bbWeight + 1;
14484 // But we won't try to connect with bDest
14489 else // (bPrev->bbJumpKind == BBJ_COND)
14491 noway_assert(bPrev->bbJumpKind == BBJ_COND);
14493 // We will reverse branch if the taken-jump to bDest ratio (i.e. 'takenRatio')
14494 // is more than 51%
14496 // We will setup profHotWeight to be maximum bbWeight that a block
14497 // could have for us not to want to reverse the conditional branch
14499 // We will consider all blocks that have less weight than profHotWeight to be
14500 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
14502 if (fgHaveValidEdgeWeights)
14504 // We have valid edge weights, however even with valid edge weights
14505 // we may have a minimum and maximum range for each edges value
14507 // We will check that the min weight of the bPrev to bDest edge
14508 // is more than twice the max weight of the bPrev to block edge.
14510 // bPrev --> [BB04, weight 31]
14512 // edgeToBlock -------------> O \
14513 // [min=8,max=10] V \
14514 // block --> [BB05, weight 10] \
14516 // edgeToDest ----------------------------> O
14517 // [min=21,max=23] |
14519 // bDest ---------------> [BB08, weight 21]
14521 flowList* edgeToDest = fgGetPredForBlock(bDest, bPrev);
14522 flowList* edgeToBlock = fgGetPredForBlock(block, bPrev);
14523 noway_assert(edgeToDest != nullptr);
14524 noway_assert(edgeToBlock != nullptr);
14526 // Calculate the taken ratio
14527 // A takenRation of 0.10 means taken 10% of the time, not taken 90% of the time
14528 // A takenRation of 0.50 means taken 50% of the time, not taken 50% of the time
14529 // A takenRation of 0.90 means taken 90% of the time, not taken 10% of the time
14531 double takenCount =
14532 ((double)edgeToDest->flEdgeWeightMin + (double)edgeToDest->flEdgeWeightMax) / 2.0;
14533 double notTakenCount =
14534 ((double)edgeToBlock->flEdgeWeightMin + (double)edgeToBlock->flEdgeWeightMax) / 2.0;
14535 double totalCount = takenCount + notTakenCount;
14536 double takenRatio = takenCount / totalCount;
14538 // If the takenRatio is greater or equal to 51% then we will reverse the branch
14539 if (takenRatio < 0.51)
14541 reorderBlock = false;
14545 // set profHotWeight
14546 profHotWeight = (edgeToBlock->flEdgeWeightMin + edgeToBlock->flEdgeWeightMax) / 2 - 1;
14551 // We don't have valid edge weight so we will be more conservative
14552 // We could have bPrev, block or bDest as part of a loop and thus have extra weight
14554 // We will do two checks:
14555 // 1. Check that the weight of bDest is at least two times more than block
14556 // 2. Check that the weight of bPrev is at least three times more than block
14558 // bPrev --> [BB04, weight 31]
14561 // block --> [BB05, weight 10] \
14565 // bDest ---------------> [BB08, weight 21]
14567 // For this case weightDest is calculated as (21+1)/2 or 11
14568 // and weightPrev is calculated as (31+2)/3 also 11
14570 // Generally both weightDest and weightPrev should calculate
14571 // the same value unless bPrev or bDest are part of a loop
14573 BasicBlock::weight_t weightDest =
14574 bDest->isMaxBBWeight() ? bDest->bbWeight : (bDest->bbWeight + 1) / 2;
14575 BasicBlock::weight_t weightPrev =
14576 bPrev->isMaxBBWeight() ? bPrev->bbWeight : (bPrev->bbWeight + 2) / 3;
14578 // select the lower of weightDest and weightPrev
14579 profHotWeight = (weightDest < weightPrev) ? weightDest : weightPrev;
14581 // if the weight of block is greater (or equal) to profHotWeight then we don't reverse the cond
14582 if (block->bbWeight >= profHotWeight)
14584 reorderBlock = false;
14589 else // not a forwardBranch
14591 if (bPrev->bbFallsThrough())
14593 goto CHECK_FOR_RARE;
14596 // Here we should pull up the highest weight block remaining
14597 // and place it here since bPrev does not fall through.
14599 BasicBlock::weight_t highestWeight = 0;
14600 BasicBlock* candidateBlock = nullptr;
14601 BasicBlock* lastNonFallThroughBlock = bPrev;
14602 BasicBlock* bTmp = bPrev->bbNext;
14604 while (bTmp != nullptr)
14606 // Don't try to split a Call/Always pair
14608 if (bTmp->isBBCallAlwaysPair())
14610 // Move bTmp forward
14611 bTmp = bTmp->bbNext;
14615 // Check for loop exit condition
14617 if (bTmp == nullptr)
14623 // if its weight is the highest one we've seen and
14624 // the EH regions allow for us to place bTmp after bPrev
14626 if ((bTmp->bbWeight > highestWeight) && fgEhAllowsMoveBlock(bPrev, bTmp))
14628 // When we have a current candidateBlock that is a conditional (or unconditional) jump
14629 // to bTmp (which is a higher weighted block) then it is better to keep out current
14630 // candidateBlock and have it fall into bTmp
14632 if ((candidateBlock == nullptr) ||
14633 ((candidateBlock->bbJumpKind != BBJ_COND) && (candidateBlock->bbJumpKind != BBJ_ALWAYS)) ||
14634 (candidateBlock->bbJumpDest != bTmp))
14636 // otherwise we have a new candidateBlock
14638 highestWeight = bTmp->bbWeight;
14639 candidateBlock = lastNonFallThroughBlock->bbNext;
14643 if ((bTmp->bbFallsThrough() == false) || (bTmp->bbWeight == 0))
14645 lastNonFallThroughBlock = bTmp;
14648 bTmp = bTmp->bbNext;
14651 // If we didn't find a suitable block then skip this
14652 if (highestWeight == 0)
14654 reorderBlock = false;
14658 noway_assert(candidateBlock != nullptr);
14660 // If the candidateBlock is the same a block then skip this
14661 if (candidateBlock == block)
14663 reorderBlock = false;
14667 // Set bDest to the block that we want to come after bPrev
14668 bDest = candidateBlock;
14670 // set profHotWeight
14671 profHotWeight = highestWeight - 1;
14676 else // we don't have good profile info (or we are falling through)
14681 /* We only want to reorder when we have a rarely run */
14682 /* block right after a normal block, */
14683 /* (bPrev is known to be a normal block at this point) */
14686 reorderBlock = false;
14690 /* If the jump target bDest is also a rarely run block then we don't want to do the reversal */
14691 if (bDest && bDest->isRunRarely())
14693 reorderBlock = false; /* Both block and bDest are rarely run */
14697 // We will move any rarely run blocks blocks
14703 if (reorderBlock == false)
14706 // Check for an unconditional branch to a conditional branch
14707 // which also branches back to our next block
14709 if (fgOptimizeBranch(bPrev))
14711 noway_assert(bPrev->bbJumpKind == BBJ_COND);
14716 // Now we need to determine which blocks should be moved
14718 // We consider one of two choices:
14720 // 1. Moving the fall-through blocks (or rarely run blocks) down to
14721 // later in the method and hopefully connecting the jump dest block
14722 // so that it becomes the fall through block
14724 // And when bDest in not NULL, we also consider:
14726 // 2. Moving the bDest block (or blocks) up to bPrev
14727 // so that it could be used as a fall through block
14729 // We will prefer option #1 if we are able to connect the jump dest
14730 // block as the fall though block otherwise will we try to use option #2
14734 // Consider option #1: relocating blocks starting at 'block'
14735 // to later in flowgraph
14737 // We set bStart to the first block that will be relocated
14738 // and bEnd to the last block that will be relocated
14740 BasicBlock* bStart = block;
14741 BasicBlock* bEnd = bStart;
14742 bNext = bEnd->bbNext;
14743 bool connected_bDest = false;
14745 if ((backwardBranch && !isRare) ||
14746 ((block->bbFlags & BBF_DONT_REMOVE) != 0)) // Don't choose option #1 when block is the start of a try region
14755 // Don't try to split a Call/Always pair
14757 if (bEnd->isBBCallAlwaysPair())
14759 // Move bEnd and bNext forward
14761 bNext = bNext->bbNext;
14765 // Check for loop exit condition
14767 if (bNext == nullptr)
14772 #if FEATURE_EH_FUNCLETS
14773 // Check if we've reached the funclets region, at the end of the function
14774 if (fgFirstFuncletBB == bEnd->bbNext)
14778 #endif // FEATURE_EH_FUNCLETS
14780 if (bNext == bDest)
14782 connected_bDest = true;
14786 // All the blocks must have the same try index
14787 // and must not have the BBF_DONT_REMOVE flag set
14789 if (!BasicBlock::sameTryRegion(bStart, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
14791 // exit the loop, bEnd is now set to the
14792 // last block that we want to relocate
14796 // If we are relocating rarely run blocks..
14799 // ... then all blocks must be rarely run
14800 if (!bNext->isRunRarely())
14802 // exit the loop, bEnd is now set to the
14803 // last block that we want to relocate
14809 // If we are moving blocks that are hot then all
14810 // of the blocks moved must be less than profHotWeight */
14811 if (bNext->bbWeight >= profHotWeight)
14813 // exit the loop, bEnd is now set to the
14814 // last block that we would relocate
14819 // Move bEnd and bNext forward
14821 bNext = bNext->bbNext;
14824 // Set connected_bDest to true if moving blocks [bStart .. bEnd]
14825 // connects with the the jump dest of bPrev (i.e bDest) and
14826 // thus allows bPrev fall through instead of jump.
14827 if (bNext == bDest)
14829 connected_bDest = true;
14833 // Now consider option #2: Moving the jump dest block (or blocks)
14836 // The variables bStart2, bEnd2 and bPrev2 are used for option #2
14838 // We will setup bStart2 to the first block that will be relocated
14839 // and bEnd2 to the last block that will be relocated
14840 // and bPrev2 to be the lexical pred of bDest
14842 // If after this calculation bStart2 is NULL we cannot use option #2,
14843 // otherwise bStart2, bEnd2 and bPrev2 are all non-NULL and we will use option #2
14845 BasicBlock* bStart2 = nullptr;
14846 BasicBlock* bEnd2 = nullptr;
14847 BasicBlock* bPrev2 = nullptr;
14849 // If option #1 didn't connect bDest and bDest isn't NULL
14850 if ((connected_bDest == false) && (bDest != nullptr) &&
14851 // The jump target cannot be moved if it has the BBF_DONT_REMOVE flag set
14852 ((bDest->bbFlags & BBF_DONT_REMOVE) == 0))
14854 // We will consider option #2: relocating blocks starting at 'bDest' to succeed bPrev
14856 // setup bPrev2 to be the lexical pred of bDest
14859 while (bPrev2 != nullptr)
14861 if (bPrev2->bbNext == bDest)
14866 bPrev2 = bPrev2->bbNext;
14869 if ((bPrev2 != nullptr) && fgEhAllowsMoveBlock(bPrev, bDest))
14871 // We have decided that relocating bDest to be after bPrev is best
14872 // Set bStart2 to the first block that will be relocated
14873 // and bEnd2 to the last block that will be relocated
14875 // Assigning to bStart2 selects option #2
14879 bNext = bEnd2->bbNext;
14883 // Don't try to split a Call/Always pair
14885 if (bEnd2->isBBCallAlwaysPair())
14887 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
14888 // Move bEnd2 and bNext forward
14890 bNext = bNext->bbNext;
14893 // Check for the Loop exit conditions
14895 if (bNext == nullptr)
14900 if (bEnd2->bbFallsThrough() == false)
14905 // If we are relocating rarely run blocks..
14906 // All the blocks must have the same try index,
14907 // and must not have the BBF_DONT_REMOVE flag set
14909 if (!BasicBlock::sameTryRegion(bStart2, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
14911 // exit the loop, bEnd2 is now set to the
14912 // last block that we want to relocate
14918 /* ... then all blocks must not be rarely run */
14919 if (bNext->isRunRarely())
14921 // exit the loop, bEnd2 is now set to the
14922 // last block that we want to relocate
14928 // If we are relocating hot blocks
14929 // all blocks moved must be greater than profHotWeight
14930 if (bNext->bbWeight <= profHotWeight)
14932 // exit the loop, bEnd2 is now set to the
14933 // last block that we want to relocate
14938 // Move bEnd2 and bNext forward
14940 bNext = bNext->bbNext;
14945 // If we are using option #1 then ...
14946 if (bStart2 == nullptr)
14948 // Don't use option #1 for a backwards branch
14949 if (bStart == nullptr)
14954 // .... Don't move a set of blocks that are already at the end of the main method
14955 if (bEnd == fgLastBBInMainFunction())
14964 if (bDest != nullptr)
14966 if (bPrev->bbJumpKind == BBJ_COND)
14968 printf("Decided to reverse conditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
14971 else if (bPrev->bbJumpKind == BBJ_ALWAYS)
14973 printf("Decided to straighten unconditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
14978 printf("Decided to place hot code after BB%02u, placed BB%02u after this block ", bPrev->bbNum,
14982 if (profHotWeight > 0)
14984 printf("because of IBC profile data\n");
14988 if (bPrev->bbFallsThrough())
14990 printf("since it falls into a rarely run block\n");
14994 printf("since it is succeeded by a rarely run block\n");
15000 printf("Decided to relocate block(s) after block BB%02u since they are %s block(s)\n", bPrev->bbNum,
15001 block->isRunRarely() ? "rarely run" : "uncommonly run");
15006 // We will set insertAfterBlk to the block the precedes our insertion range
15007 // We will set bStartPrev to be the block that precedes the set of blocks that we are moving
15008 BasicBlock* insertAfterBlk;
15009 BasicBlock* bStartPrev;
15011 if (bStart2 != nullptr)
15013 // Option #2: relocating blocks starting at 'bDest' to follow bPrev
15015 // Update bStart and bEnd so that we can use these two for all later operations
15019 // Set bStartPrev to be the block that comes before bStart
15020 bStartPrev = bPrev2;
15022 // We will move [bStart..bEnd] to immediately after bPrev
15023 insertAfterBlk = bPrev;
15027 // option #1: Moving the fall-through blocks (or rarely run blocks) down to later in the method
15029 // Set bStartPrev to be the block that come before bStart
15030 bStartPrev = bPrev;
15032 // We will move [bStart..bEnd] but we will pick the insert location later
15033 insertAfterBlk = nullptr;
15036 // We are going to move [bStart..bEnd] so they can't be NULL
15037 noway_assert(bStart != nullptr);
15038 noway_assert(bEnd != nullptr);
15040 // bEnd can't be a BBJ_CALLFINALLY unless it is a RETLESS call
15041 noway_assert((bEnd->bbJumpKind != BBJ_CALLFINALLY) || (bEnd->bbFlags & BBF_RETLESS_CALL));
15043 // bStartPrev must be set to the block that precedes bStart
15044 noway_assert(bStartPrev->bbNext == bStart);
15046 // Since we will be unlinking [bStart..bEnd],
15047 // we need to compute and remember if bStart is in each of
15048 // the try and handler regions
15050 bool* fStartIsInTry = nullptr;
15051 bool* fStartIsInHnd = nullptr;
15053 if (compHndBBtabCount > 0)
15055 fStartIsInTry = new (this, CMK_Unknown) bool[compHndBBtabCount];
15056 fStartIsInHnd = new (this, CMK_Unknown) bool[compHndBBtabCount];
15058 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
15060 fStartIsInTry[XTnum] = HBtab->InTryRegionBBRange(bStart);
15061 fStartIsInHnd[XTnum] = HBtab->InHndRegionBBRange(bStart);
15065 /* Temporarily unlink [bStart..bEnd] from the flow graph */
15066 fgUnlinkRange(bStart, bEnd);
15068 if (insertAfterBlk == nullptr)
15070 // Find new location for the unlinked block(s)
15071 // Set insertAfterBlk to the block which will precede the insertion point
15073 if (!bStart->hasTryIndex() && isRare)
15075 // We'll just insert the blocks at the end of the method. If the method
15076 // has funclets, we will insert at the end of the main method but before
15077 // any of the funclets. Note that we create funclets before we call
15078 // fgReorderBlocks().
15080 insertAfterBlk = fgLastBBInMainFunction();
15081 noway_assert(insertAfterBlk != bPrev);
15085 BasicBlock* startBlk;
15086 BasicBlock* lastBlk;
15087 EHblkDsc* ehDsc = ehInitTryBlockRange(bStart, &startBlk, &lastBlk);
15089 BasicBlock* endBlk;
15091 /* Setup startBlk and endBlk as the range to search */
15093 if (ehDsc != nullptr)
15095 endBlk = lastBlk->bbNext;
15098 Multiple (nested) try regions might start from the same BB.
15102 |--- |--- |--- BB01
15106 | |------------ BB05
15108 |------------------- BB07
15110 Now if we want to insert in try2 region, we will start with startBlk=BB01.
15111 The following loop will allow us to start from startBlk==BB04.
15113 while (!BasicBlock::sameTryRegion(startBlk, bStart) && (startBlk != endBlk))
15115 startBlk = startBlk->bbNext;
15118 // startBlk cannot equal endBlk as it must come before endBlk
15119 if (startBlk == endBlk)
15124 // we also can't start searching the try region at bStart
15125 if (startBlk == bStart)
15127 // if bEnd is the last block in the method or
15128 // or if bEnd->bbNext is in a different try region
15129 // then we cannot move the blocks
15131 if ((bEnd->bbNext == nullptr) || !BasicBlock::sameTryRegion(startBlk, bEnd->bbNext))
15136 startBlk = bEnd->bbNext;
15138 // Check that the new startBlk still comes before endBlk
15140 // startBlk cannot equal endBlk as it must come before endBlk
15141 if (startBlk == endBlk)
15146 BasicBlock* tmpBlk = startBlk;
15147 while ((tmpBlk != endBlk) && (tmpBlk != nullptr))
15149 tmpBlk = tmpBlk->bbNext;
15152 // when tmpBlk is NULL that means startBlk is after endBlk
15153 // so there is no way to move bStart..bEnd within the try region
15154 if (tmpBlk == nullptr)
15162 noway_assert(isRare == false);
15164 /* We'll search through the entire main method */
15165 startBlk = fgFirstBB;
15166 endBlk = fgEndBBAfterMainFunction();
15169 // Calculate nearBlk and jumpBlk and then call fgFindInsertPoint()
15170 // to find our insertion block
15173 // If the set of blocks that we are moving ends with a BBJ_ALWAYS to
15174 // another [rarely run] block that comes after bPrev (forward branch)
15175 // then we can set up nearBlk to eliminate this jump sometimes
15177 BasicBlock* nearBlk = nullptr;
15178 BasicBlock* jumpBlk = nullptr;
15180 if ((bEnd->bbJumpKind == BBJ_ALWAYS) && (!isRare || bEnd->bbJumpDest->isRunRarely()) &&
15181 fgIsForwardBranch(bEnd, bPrev))
15183 // Set nearBlk to be the block in [startBlk..endBlk]
15184 // such that nearBlk->bbNext == bEnd->JumpDest
15185 // if no such block exists then set nearBlk to NULL
15186 nearBlk = startBlk;
15190 // We do not want to set nearBlk to bPrev
15191 // since then we will not move [bStart..bEnd]
15193 if (nearBlk != bPrev)
15195 // Check if nearBlk satisfies our requirement
15196 if (nearBlk->bbNext == bEnd->bbJumpDest)
15202 // Did we reach the endBlk?
15203 if (nearBlk == endBlk)
15209 // advance nearBlk to the next block
15210 nearBlk = nearBlk->bbNext;
15212 } while (nearBlk != nullptr);
15215 // if nearBlk is NULL then we set nearBlk to be the
15216 // first block that we want to insert after.
15217 if (nearBlk == nullptr)
15219 if (bDest != nullptr)
15221 // we want to insert after bDest
15226 // we want to insert after bPrev
15231 /* Set insertAfterBlk to the block which we will insert after. */
15234 fgFindInsertPoint(bStart->bbTryIndex,
15235 true, // Insert in the try region.
15236 startBlk, endBlk, nearBlk, jumpBlk, bStart->bbWeight == BB_ZERO_WEIGHT);
15239 /* See if insertAfterBlk is the same as where we started, */
15240 /* or if we could not find any insertion point */
15242 if ((insertAfterBlk == bPrev) || (insertAfterBlk == nullptr))
15245 /* We couldn't move the blocks, so put everything back */
15246 /* relink [bStart .. bEnd] into the flow graph */
15248 bPrev->setNext(bStart);
15251 bEnd->bbNext->bbPrev = bEnd;
15256 if (bStart != bEnd)
15258 printf("Could not relocate blocks (BB%02u .. BB%02u)\n", bStart->bbNum, bEnd->bbNum);
15262 printf("Could not relocate block BB%02u\n", bStart->bbNum);
15271 noway_assert(insertAfterBlk != nullptr);
15272 noway_assert(bStartPrev != nullptr);
15273 noway_assert(bStartPrev != insertAfterBlk);
15276 movedBlocks = true;
15281 if (bStart2 != nullptr)
15289 msg = "rarely run";
15297 printf("Relocated %s ", msg);
15298 if (bStart != bEnd)
15300 printf("blocks (BB%02u .. BB%02u)", bStart->bbNum, bEnd->bbNum);
15304 printf("block BB%02u", bStart->bbNum);
15307 if (bPrev->bbJumpKind == BBJ_COND)
15309 printf(" by reversing conditional jump at BB%02u\n", bPrev->bbNum);
15313 printf("\n", bPrev->bbNum);
15318 if (bPrev->bbJumpKind == BBJ_COND)
15320 /* Reverse the bPrev jump condition */
15321 GenTree* condTest = bPrev->lastStmt();
15323 condTest = condTest->gtStmt.gtStmtExpr;
15324 noway_assert(condTest->gtOper == GT_JTRUE);
15326 condTest->gtOp.gtOp1 = gtReverseCond(condTest->gtOp.gtOp1);
15328 if (bStart2 == nullptr)
15330 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
15331 bPrev->bbJumpDest = bStart;
15332 bStart->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
15336 noway_assert(insertAfterBlk == bPrev);
15337 noway_assert(insertAfterBlk->bbNext == block);
15339 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
15340 bPrev->bbJumpDest = block;
15341 block->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
15345 // If we are moving blocks that are at the end of a try or handler
15346 // we will need to shorten ebdTryLast or ebdHndLast
15348 ehUpdateLastBlocks(bEnd, bStartPrev);
15350 // If we are moving blocks into the end of a try region or handler region
15351 // we will need to extend ebdTryLast or ebdHndLast so the blocks that we
15352 // are moving are part of this try or handler region.
15354 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
15356 // Are we moving blocks to the end of a try region?
15357 if (HBtab->ebdTryLast == insertAfterBlk)
15359 if (fStartIsInTry[XTnum])
15361 // bStart..bEnd is in the try, so extend the try region
15362 fgSetTryEnd(HBtab, bEnd);
15366 // Are we moving blocks to the end of a handler region?
15367 if (HBtab->ebdHndLast == insertAfterBlk)
15369 if (fStartIsInHnd[XTnum])
15371 // bStart..bEnd is in the handler, so extend the handler region
15372 fgSetHndEnd(HBtab, bEnd);
15377 /* We have decided to insert the block(s) after 'insertAfterBlk' */
15378 fgMoveBlocksAfter(bStart, bEnd, insertAfterBlk);
15382 /* We may need to insert an unconditional branch after bPrev to bDest */
15383 fgConnectFallThrough(bPrev, bDest);
15387 /* If bPrev falls through, we must insert a jump to block */
15388 fgConnectFallThrough(bPrev, block);
15391 BasicBlock* bSkip = bEnd->bbNext;
15393 /* If bEnd falls through, we must insert a jump to bNext */
15394 fgConnectFallThrough(bEnd, bNext);
15396 if (bStart2 == nullptr)
15398 /* If insertAfterBlk falls through, we are forced to */
15399 /* add a jump around the block(s) we just inserted */
15400 fgConnectFallThrough(insertAfterBlk, bSkip);
15404 /* We may need to insert an unconditional branch after bPrev2 to bStart */
15405 fgConnectFallThrough(bPrev2, bStart);
15411 printf("\nAfter this change in fgReorderBlocks");
15412 fgDispBasicBlocks(verboseTrees);
15415 fgVerifyHandlerTab();
15417 // Make sure that the predecessor lists are accurate
15418 if (expensiveDebugCheckLevel >= 2)
15420 fgDebugCheckBBlist();
15424 // Set our iteration point 'block' to be the new bPrev->bbNext
15425 // It will be used as the next bPrev
15426 block = bPrev->bbNext;
15428 } // end of for loop(bPrev,block)
15430 bool changed = movedBlocks || newRarelyRun || optimizedSwitches;
15434 fgNeedsUpdateFlowGraph = true;
15436 // Make sure that the predecessor lists are accurate
15437 if (expensiveDebugCheckLevel >= 2)
15439 fgDebugCheckBBlist();
15445 #pragma warning(pop)
15448 /*-------------------------------------------------------------------------
15450 * Walk the basic blocks list to determine the first block to place in the
15451 * cold section. This would be the first of a series of rarely executed blocks
15452 * such that no succeeding blocks are in a try region or an exception handler
15453 * or are rarely executed.
15456 void Compiler::fgDetermineFirstColdBlock()
15461 printf("\n*************** In fgDetermineFirstColdBlock()\n");
15465 // Since we may need to create a new transistion block
15466 // we assert that it is OK to create new blocks.
15468 assert(fgSafeBasicBlockCreation);
15470 fgFirstColdBlock = nullptr;
15472 #if FEATURE_STACK_FP_X87
15473 if (compMayHaveTransitionBlocks)
15475 opts.compProcedureSplitting = false;
15477 // See comment above declaration of compMayHaveTransitionBlocks for comments on this
15478 JITDUMP("Turning off procedure splitting for this method, as it may end up having FP transition blocks\n");
15480 #endif // FEATURE_STACK_FP_X87
15482 if (!opts.compProcedureSplitting)
15484 JITDUMP("No procedure splitting will be done for this method\n");
15489 if ((compHndBBtabCount > 0) && !opts.compProcedureSplittingEH)
15491 JITDUMP("No procedure splitting will be done for this method with EH (by request)\n");
15496 #if FEATURE_EH_FUNCLETS
15497 // TODO-CQ: handle hot/cold splitting in functions with EH (including synchronized methods
15498 // that create EH in methods without explicit EH clauses).
15500 if (compHndBBtabCount > 0)
15502 JITDUMP("No procedure splitting will be done for this method with EH (implementation limitation)\n");
15505 #endif // FEATURE_EH_FUNCLETS
15507 BasicBlock* firstColdBlock = nullptr;
15508 BasicBlock* prevToFirstColdBlock = nullptr;
15512 for (lblk = nullptr, block = fgFirstBB; block != nullptr; lblk = block, block = block->bbNext)
15514 bool blockMustBeInHotSection = false;
15516 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
15517 if (bbIsHandlerBeg(block))
15519 blockMustBeInHotSection = true;
15521 #endif // HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
15523 // Do we have a candidate for the first cold block?
15524 if (firstColdBlock != nullptr)
15526 // We have a candidate for first cold block
15528 // Is this a hot block?
15529 if (blockMustBeInHotSection || (block->isRunRarely() == false))
15531 // We have to restart the search for the first cold block
15532 firstColdBlock = nullptr;
15533 prevToFirstColdBlock = nullptr;
15536 else // (firstColdBlock == NULL)
15538 // We don't have a candidate for first cold block
15540 // Is this a cold block?
15541 if (!blockMustBeInHotSection && (block->isRunRarely() == true))
15544 // If the last block that was hot was a BBJ_COND
15545 // then we will have to add an unconditional jump
15546 // so the code size for block needs be large
15547 // enough to make it worth our while
15549 if ((lblk == nullptr) || (lblk->bbJumpKind != BBJ_COND) || (fgGetCodeEstimate(block) >= 8))
15551 // This block is now a candidate for first cold block
15552 // Also remember the predecessor to this block
15553 firstColdBlock = block;
15554 prevToFirstColdBlock = lblk;
15560 if (firstColdBlock == fgFirstBB)
15562 // If the first block is Cold then we can't move any blocks
15563 // into the cold section
15565 firstColdBlock = nullptr;
15568 if (firstColdBlock != nullptr)
15570 noway_assert(prevToFirstColdBlock != nullptr);
15572 if (prevToFirstColdBlock == nullptr)
15574 return; // To keep Prefast happy
15577 // If we only have one cold block
15578 // then it may not be worth it to move it
15579 // into the Cold section as a jump to the
15580 // Cold section is 5 bytes in size.
15582 if (firstColdBlock->bbNext == nullptr)
15584 // If the size of the cold block is 7 or less
15585 // then we will keep it in the Hot section.
15587 if (fgGetCodeEstimate(firstColdBlock) < 8)
15589 firstColdBlock = nullptr;
15594 // When the last Hot block fall through into the Cold section
15595 // we may need to add a jump
15597 if (prevToFirstColdBlock->bbFallsThrough())
15599 switch (prevToFirstColdBlock->bbJumpKind)
15602 noway_assert(!"Unhandled jumpkind in fgDetermineFirstColdBlock()");
15604 case BBJ_CALLFINALLY:
15605 // A BBJ_CALLFINALLY that falls through is always followed
15606 // by an empty BBJ_ALWAYS.
15608 assert(prevToFirstColdBlock->isBBCallAlwaysPair());
15610 firstColdBlock->bbNext; // Note that this assignment could make firstColdBlock == nullptr
15615 // This is a slightly more complicated case, because we will
15616 // probably need to insert a block to jump to the cold section.
15618 if (firstColdBlock->isEmpty() && (firstColdBlock->bbJumpKind == BBJ_ALWAYS))
15620 // We can just use this block as the transitionBlock
15621 firstColdBlock = firstColdBlock->bbNext;
15622 // Note that this assignment could make firstColdBlock == NULL
15626 BasicBlock* transitionBlock = fgNewBBafter(BBJ_ALWAYS, prevToFirstColdBlock, true);
15627 transitionBlock->bbJumpDest = firstColdBlock;
15628 transitionBlock->inheritWeight(firstColdBlock);
15630 noway_assert(fgComputePredsDone);
15632 // Update the predecessor list for firstColdBlock
15633 fgReplacePred(firstColdBlock, prevToFirstColdBlock, transitionBlock);
15635 // Add prevToFirstColdBlock as a predecessor for transitionBlock
15636 fgAddRefPred(transitionBlock, prevToFirstColdBlock);
15641 // If the block preceding the first cold block is BBJ_NONE,
15642 // convert it to BBJ_ALWAYS to force an explicit jump.
15644 prevToFirstColdBlock->bbJumpDest = firstColdBlock;
15645 prevToFirstColdBlock->bbJumpKind = BBJ_ALWAYS;
15651 if (firstColdBlock != nullptr)
15653 firstColdBlock->bbFlags |= BBF_JMP_TARGET;
15655 for (block = firstColdBlock; block; block = block->bbNext)
15657 block->bbFlags |= BBF_COLD;
15666 if (firstColdBlock)
15668 printf("fgFirstColdBlock is BB%02u.\n", firstColdBlock->bbNum);
15672 printf("fgFirstColdBlock is NULL.\n");
15675 fgDispBasicBlocks();
15678 fgVerifyHandlerTab();
15681 fgFirstColdBlock = firstColdBlock;
15685 #pragma warning(push)
15686 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
15688 /*****************************************************************************
15690 * Function called to "comb" the basic block list.
15691 * Removes any empty blocks, unreachable blocks and redundant jumps.
15692 * Most of those appear after dead store removal and folding of conditionals.
15694 * Returns: true if the flowgraph has been modified
15696 * It also compacts basic blocks
15697 * (consecutive basic blocks that should in fact be one).
15700 * Debuggable code and Min Optimization JIT also introduces basic blocks
15701 * but we do not optimize those!
15704 bool Compiler::fgUpdateFlowGraph(bool doTailDuplication)
15709 printf("\n*************** In fgUpdateFlowGraph()");
15713 /* This should never be called for debuggable code */
15715 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
15720 printf("\nBefore updating the flow graph:\n");
15721 fgDispBasicBlocks(verboseTrees);
15726 /* Walk all the basic blocks - look for unconditional jumps, empty blocks, blocks to compact, etc...
15729 * Once a block is removed the predecessors are not accurate (assuming they were at the beginning)
15730 * For now we will only use the information in bbRefs because it is easier to be updated
15733 bool modified = false;
15739 BasicBlock* block; // the current block
15740 BasicBlock* bPrev = nullptr; // the previous non-worthless block
15741 BasicBlock* bNext; // the successor of the current block
15742 BasicBlock* bDest; // the jump target of the current block
15744 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
15746 /* Some blocks may be already marked removed by other optimizations
15747 * (e.g worthless loop removal), without being explicitly removed
15751 if (block->bbFlags & BBF_REMOVED)
15755 bPrev->setNext(block->bbNext);
15759 /* WEIRD first basic block is removed - should have an assert here */
15760 noway_assert(!"First basic block marked as BBF_REMOVED???");
15762 fgFirstBB = block->bbNext;
15767 /* We jump to the REPEAT label if we performed a change involving the current block
15768 * This is in case there are other optimizations that can show up
15769 * (e.g. - compact 3 blocks in a row)
15770 * If nothing happens, we then finish the iteration and move to the next block
15775 bNext = block->bbNext;
15778 if (block->bbJumpKind == BBJ_ALWAYS)
15780 bDest = block->bbJumpDest;
15781 if (doTailDuplication && fgOptimizeUncondBranchToSimpleCond(block, bDest))
15785 bDest = block->bbJumpDest;
15786 bNext = block->bbNext;
15790 // Remove JUMPS to the following block
15791 // and optimize any JUMPS to JUMPS
15793 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
15795 bDest = block->bbJumpDest;
15796 if (bDest == bNext)
15798 if (fgOptimizeBranchToNext(block, bNext, bPrev))
15807 if (bDest != nullptr)
15809 // Do we have a JUMP to an empty unconditional JUMP block?
15810 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
15811 (bDest != bDest->bbJumpDest)) // special case for self jumps
15813 if (fgOptimizeBranchToEmptyUnconditional(block, bDest))
15821 // Check for a conditional branch that just skips over an empty BBJ_ALWAYS block
15823 if ((block->bbJumpKind == BBJ_COND) && // block is a BBJ_COND block
15824 (bNext != nullptr) && // block is not the last block
15825 (bNext->bbRefs == 1) && // No other block jumps to bNext
15826 (bNext->bbNext == bDest) && // The block after bNext is the BBJ_COND jump dest
15827 (bNext->bbJumpKind == BBJ_ALWAYS) && // The next block is a BBJ_ALWAYS block
15828 bNext->isEmpty() && // and it is an an empty block
15829 (bNext != bNext->bbJumpDest) && // special case for self jumps
15830 (bDest != fgFirstColdBlock))
15832 bool optimizeJump = true;
15834 // We do not optimize jumps between two different try regions.
15835 // However jumping to a block that is not in any try region is OK
15837 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
15839 optimizeJump = false;
15842 // Also consider bNext's try region
15844 if (bNext->hasTryIndex() && !BasicBlock::sameTryRegion(block, bNext))
15846 optimizeJump = false;
15849 // If we are optimizing using real profile weights
15850 // then don't optimize a conditional jump to an unconditional jump
15851 // until after we have computed the edge weights
15853 if (fgIsUsingProfileWeights())
15855 // if block and bdest are in different hot/cold regions we can't do this this optimization
15856 // because we can't allow fall-through into the cold region.
15857 if (!fgEdgeWeightsComputed || fgInDifferentRegions(block, bDest))
15859 fgNeedsUpdateFlowGraph = true;
15860 optimizeJump = false;
15869 printf("\nReversing a conditional jump around an unconditional jump (BB%02u -> BB%02u -> "
15871 block->bbNum, bDest->bbNum, bNext->bbJumpDest->bbNum);
15874 /* Reverse the jump condition */
15876 GenTree* test = block->lastNode();
15877 noway_assert(test->gtOper == GT_JTRUE);
15879 GenTree* cond = gtReverseCond(test->gtOp.gtOp1);
15880 assert(cond == test->gtOp.gtOp1); // Ensure `gtReverseCond` did not create a new node.
15881 test->gtOp.gtOp1 = cond;
15883 // Optimize the Conditional JUMP to go to the new target
15884 block->bbJumpDest = bNext->bbJumpDest;
15886 fgAddRefPred(bNext->bbJumpDest, block, fgRemoveRefPred(bNext->bbJumpDest, bNext));
15889 Unlink bNext from the BasicBlock list; note that we can
15890 do this even though other blocks could jump to it - the
15891 reason is that elsewhere in this function we always
15892 redirect jumps to jumps to jump to the final label,
15893 so even if another block jumps to bNext it won't matter
15894 once we're done since any such jump will be redirected
15895 to the final target by the time we're done here.
15898 fgRemoveRefPred(bNext, block);
15899 fgUnlinkBlock(bNext);
15901 /* Mark the block as removed */
15902 bNext->bbFlags |= BBF_REMOVED;
15904 // If this is the first Cold basic block update fgFirstColdBlock
15905 if (bNext == fgFirstColdBlock)
15907 fgFirstColdBlock = bNext->bbNext;
15911 // If we removed the end of a try region or handler region
15912 // we will need to update ebdTryLast or ebdHndLast.
15916 EHblkDsc* HBtabEnd;
15918 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd;
15921 if ((HBtab->ebdTryLast == bNext) || (HBtab->ebdHndLast == bNext))
15923 fgSkipRmvdBlocks(HBtab);
15927 // we optimized this JUMP - goto REPEAT to catch similar cases
15934 printf("\nAfter reversing the jump:\n");
15935 fgDispBasicBlocks(verboseTrees);
15940 For a rare special case we cannot jump to REPEAT
15941 as jumping to REPEAT will cause us to delete 'block'
15942 because it currently appears to be unreachable. As
15943 it is a self loop that only has a single bbRef (itself)
15944 However since the unlinked bNext has additional bbRefs
15945 (that we will later connect to 'block'), it is not really
15948 if ((bNext->bbRefs > 0) && (bNext->bbJumpDest == block) && (block->bbRefs == 1))
15959 // Update the switch jump table such that it follows jumps to jumps:
15961 if (block->bbJumpKind == BBJ_SWITCH)
15963 if (fgOptimizeSwitchBranches(block))
15971 noway_assert(!(block->bbFlags & BBF_REMOVED));
15973 /* COMPACT blocks if possible */
15975 if (fgCanCompactBlocks(block, bNext))
15977 fgCompactBlocks(block, bNext);
15979 /* we compacted two blocks - goto REPEAT to catch similar cases */
15985 /* Remove unreachable or empty blocks - do not consider blocks marked BBF_DONT_REMOVE or genReturnBB block
15986 * These include first and last block of a TRY, exception handlers and RANGE_CHECK_FAIL THROW blocks */
15988 if ((block->bbFlags & BBF_DONT_REMOVE) == BBF_DONT_REMOVE || block == genReturnBB)
15994 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
15995 // Don't remove the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair.
15996 if (block->countOfInEdges() == 0 && bPrev->bbJumpKind == BBJ_CALLFINALLY)
15998 assert(bPrev->isBBCallAlwaysPair());
15999 noway_assert(!(bPrev->bbFlags & BBF_RETLESS_CALL));
16000 noway_assert(block->bbJumpKind == BBJ_ALWAYS);
16004 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16006 noway_assert(!block->bbCatchTyp);
16007 noway_assert(!(block->bbFlags & BBF_TRY_BEG));
16009 /* Remove unreachable blocks
16011 * We'll look for blocks that have countOfInEdges() = 0 (blocks may become
16012 * unreachable due to a BBJ_ALWAYS introduced by conditional folding for example)
16015 if (block->countOfInEdges() == 0)
16017 /* no references -> unreachable - remove it */
16018 /* For now do not update the bbNum, do it at the end */
16020 fgRemoveBlock(block, true);
16025 /* we removed the current block - the rest of the optimizations won't have a target
16026 * continue with the next one */
16030 else if (block->countOfInEdges() == 1)
16032 switch (block->bbJumpKind)
16036 if (block->bbJumpDest == block)
16038 fgRemoveBlock(block, true);
16043 /* we removed the current block - the rest of the optimizations
16044 * won't have a target so continue with the next block */
16055 noway_assert(!(block->bbFlags & BBF_REMOVED));
16057 /* Remove EMPTY blocks */
16059 if (block->isEmpty())
16061 assert(bPrev == block->bbPrev);
16062 if (fgOptimizeEmptyBlock(block))
16068 /* Have we removed the block? */
16070 if (block->bbFlags & BBF_REMOVED)
16072 /* block was removed - no change to bPrev */
16077 /* Set the predecessor of the last reachable block
16078 * If we removed the current block, the predecessor remains unchanged
16079 * otherwise, since the current block is ok, it becomes the predecessor */
16081 noway_assert(!(block->bbFlags & BBF_REMOVED));
16087 fgNeedsUpdateFlowGraph = false;
16090 if (verbose && modified)
16092 printf("\nAfter updating the flow graph:\n");
16093 fgDispBasicBlocks(verboseTrees);
16094 fgDispHandlerTab();
16097 if (compRationalIRForm)
16099 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
16101 LIR::AsRange(block).CheckLIR(this);
16105 fgVerifyHandlerTab();
16106 // Make sure that the predecessor lists are accurate
16107 fgDebugCheckBBlist();
16108 fgDebugCheckUpdate();
16114 #pragma warning(pop)
16117 /*****************************************************************************
16118 * Check that the flow graph is really updated
16123 void Compiler::fgDebugCheckUpdate()
16125 if (!compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
16130 /* We check for these conditions:
16131 * no unreachable blocks -> no blocks have countOfInEdges() = 0
16132 * no empty blocks -> no blocks have bbTreeList = 0
16133 * no un-imported blocks -> no blocks have BBF_IMPORTED not set (this is
16134 * kind of redundand with the above, but to make sure)
16135 * no un-compacted blocks -> BBJ_NONE followed by block with no jumps to it (countOfInEdges() = 1)
16140 for (prev = nullptr, block = fgFirstBB; block != nullptr; prev = block, block = block->bbNext)
16142 /* no unreachable blocks */
16144 if ((block->countOfInEdges() == 0) && !(block->bbFlags & BBF_DONT_REMOVE)
16145 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16146 // With funclets, we never get rid of the BBJ_ALWAYS part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
16147 // even if we can prove that the finally block never returns.
16148 && (prev == NULL || block->bbJumpKind != BBJ_ALWAYS || !prev->isBBCallAlwaysPair())
16149 #endif // FEATURE_EH_FUNCLETS
16152 noway_assert(!"Unreachable block not removed!");
16155 /* no empty blocks */
16157 if (block->isEmpty() && !(block->bbFlags & BBF_DONT_REMOVE))
16159 switch (block->bbJumpKind)
16161 case BBJ_CALLFINALLY:
16162 case BBJ_EHFINALLYRET:
16163 case BBJ_EHFILTERRET:
16165 /* for BBJ_ALWAYS is probably just a GOTO, but will have to be treated */
16167 case BBJ_EHCATCHRET:
16168 /* These jump kinds are allowed to have empty tree lists */
16172 /* it may be the case that the block had more than one reference to it
16173 * so we couldn't remove it */
16175 if (block->countOfInEdges() == 0)
16177 noway_assert(!"Empty block not removed!");
16183 /* no un-imported blocks */
16185 if (!(block->bbFlags & BBF_IMPORTED))
16187 /* internal blocks do not count */
16189 if (!(block->bbFlags & BBF_INTERNAL))
16191 noway_assert(!"Non IMPORTED block not removed!");
16195 bool prevIsCallAlwaysPair = ((prev != nullptr) && prev->isBBCallAlwaysPair());
16197 // Check for an unnecessary jumps to the next block
16198 bool doAssertOnJumpToNextBlock = false; // unless we have a BBJ_COND or BBJ_ALWAYS we can not assert
16200 if (block->bbJumpKind == BBJ_COND)
16202 // A conditional branch should never jump to the next block
16203 // as it can be folded into a BBJ_NONE;
16204 doAssertOnJumpToNextBlock = true;
16206 else if (block->bbJumpKind == BBJ_ALWAYS)
16208 // Generally we will want to assert if a BBJ_ALWAYS branches to the next block
16209 doAssertOnJumpToNextBlock = true;
16211 // If the BBF_KEEP_BBJ_ALWAYS flag is set we allow it to jump to the next block
16212 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
16214 doAssertOnJumpToNextBlock = false;
16217 // A call/always pair is also allowed to jump to the next block
16218 if (prevIsCallAlwaysPair)
16220 doAssertOnJumpToNextBlock = false;
16223 // We are allowed to have a branch from a hot 'block' to a cold 'bbNext'
16225 if ((block->bbNext != nullptr) && fgInDifferentRegions(block, block->bbNext))
16227 doAssertOnJumpToNextBlock = false;
16231 if (doAssertOnJumpToNextBlock)
16233 if (block->bbJumpDest == block->bbNext)
16235 noway_assert(!"Unnecessary jump to the next block!");
16239 /* Make sure BBF_KEEP_BBJ_ALWAYS is set correctly */
16241 if ((block->bbJumpKind == BBJ_ALWAYS) && prevIsCallAlwaysPair)
16243 noway_assert(block->bbFlags & BBF_KEEP_BBJ_ALWAYS);
16246 /* For a BBJ_CALLFINALLY block we make sure that we are followed by */
16247 /* an BBJ_ALWAYS block with BBF_INTERNAL set */
16248 /* or that it's a BBF_RETLESS_CALL */
16249 if (block->bbJumpKind == BBJ_CALLFINALLY)
16251 assert((block->bbFlags & BBF_RETLESS_CALL) || block->isBBCallAlwaysPair());
16254 /* no un-compacted blocks */
16256 if (fgCanCompactBlocks(block, block->bbNext))
16258 noway_assert(!"Found un-compacted blocks!");
16265 /*****************************************************************************
16266 * We've inserted a new block before 'block' that should be part of the same EH region as 'block'.
16267 * Update the EH table to make this so. Also, set the new block to have the right EH region data
16268 * (copy the bbTryIndex, bbHndIndex, and bbCatchTyp from 'block' to the new predecessor, and clear
16269 * 'bbCatchTyp' from 'block').
16271 void Compiler::fgExtendEHRegionBefore(BasicBlock* block)
16273 assert(block->bbPrev != nullptr);
16275 BasicBlock* bPrev = block->bbPrev;
16277 bPrev->copyEHRegion(block);
16279 // The first block (and only the first block) of a handler has bbCatchTyp set
16280 bPrev->bbCatchTyp = block->bbCatchTyp;
16281 block->bbCatchTyp = BBCT_NONE;
16284 EHblkDsc* HBtabEnd;
16286 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
16288 /* Multiple pointers in EHblkDsc can point to same block. We can not early out after the first match. */
16289 if (HBtab->ebdTryBeg == block)
16294 printf("EH#%u: New first block of try: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16297 HBtab->ebdTryBeg = bPrev;
16298 bPrev->bbFlags |= BBF_TRY_BEG | BBF_DONT_REMOVE | BBF_HAS_LABEL;
16299 // clear the TryBeg flag unless it begins another try region
16300 if (!bbIsTryBeg(block))
16302 block->bbFlags &= ~BBF_TRY_BEG;
16306 if (HBtab->ebdHndBeg == block)
16311 printf("EH#%u: New first block of handler: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16315 // The first block of a handler has an artificial extra refcount. Transfer that to the new block.
16316 assert(block->bbRefs > 0);
16319 HBtab->ebdHndBeg = bPrev;
16320 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
16323 // If this is a handler for a filter, the last block of the filter will end with
16324 // a BBJ_EJFILTERRET block that has a bbJumpDest that jumps to the first block of
16325 // it's handler. So we need to update it to keep things in sync.
16327 if (HBtab->HasFilter())
16329 BasicBlock* bFilterLast = HBtab->BBFilterLast();
16330 assert(bFilterLast != nullptr);
16331 assert(bFilterLast->bbJumpKind == BBJ_EHFILTERRET);
16332 assert(bFilterLast->bbJumpDest == block);
16336 printf("EH#%u: Updating bbJumpDest for filter ret block: BB%02u => BB%02u\n", ehGetIndex(HBtab),
16337 bFilterLast->bbNum, bPrev->bbNum);
16340 // Change the bbJumpDest for bFilterLast from the old first 'block' to the new first 'bPrev'
16341 bFilterLast->bbJumpDest = bPrev;
16345 if (HBtab->HasFilter() && (HBtab->ebdFilter == block))
16350 printf("EH#%u: New first block of filter: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16354 // The first block of a filter has an artificial extra refcount. Transfer that to the new block.
16355 assert(block->bbRefs > 0);
16358 HBtab->ebdFilter = bPrev;
16359 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
16365 /*****************************************************************************
16366 * We've inserted a new block after 'block' that should be part of the same EH region as 'block'.
16367 * Update the EH table to make this so. Also, set the new block to have the right EH region data.
16370 void Compiler::fgExtendEHRegionAfter(BasicBlock* block)
16372 BasicBlock* newBlk = block->bbNext;
16373 assert(newBlk != nullptr);
16375 newBlk->copyEHRegion(block);
16376 newBlk->bbCatchTyp =
16377 BBCT_NONE; // Only the first block of a catch has this set, and 'newBlk' can't be the first block of a catch.
16379 // TODO-Throughput: if the block is not in an EH region, then we don't need to walk the EH table looking for 'last'
16380 // block pointers to update.
16381 ehUpdateLastBlocks(block, newBlk);
16384 /*****************************************************************************
16386 * Insert a BasicBlock before the given block.
16389 BasicBlock* Compiler::fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
16391 // Create a new BasicBlock and chain it in
16393 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
16394 newBlk->bbFlags |= BBF_INTERNAL;
16396 fgInsertBBbefore(block, newBlk);
16398 newBlk->bbRefs = 0;
16400 if (newBlk->bbFallsThrough() && block->isRunRarely())
16402 newBlk->bbSetRunRarely();
16407 fgExtendEHRegionBefore(block);
16411 // When extendRegion is false the caller is responsible for setting these two values
16412 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16413 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16416 // We assume that if the block we are inserting before is in the cold region, then this new
16417 // block will also be in the cold region.
16418 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
16423 /*****************************************************************************
16425 * Insert a BasicBlock after the given block.
16428 BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
16430 // Create a new BasicBlock and chain it in
16432 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
16433 newBlk->bbFlags |= BBF_INTERNAL;
16435 fgInsertBBafter(block, newBlk);
16437 newBlk->bbRefs = 0;
16439 if (block->bbFallsThrough() && block->isRunRarely())
16441 newBlk->bbSetRunRarely();
16446 fgExtendEHRegionAfter(block);
16450 // When extendRegion is false the caller is responsible for setting these two values
16451 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16452 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16455 // If the new block is in the cold region (because the block we are inserting after
16456 // is in the cold region), mark it as such.
16457 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
16462 /*****************************************************************************
16463 * Inserts basic block before existing basic block.
16465 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
16466 * (If insertBeforeBlk is the first block of the funclet region, then 'newBlk' will be the
16467 * new first block of the funclet region.)
16469 void Compiler::fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk)
16471 if (insertBeforeBlk->bbPrev)
16473 fgInsertBBafter(insertBeforeBlk->bbPrev, newBlk);
16477 newBlk->setNext(fgFirstBB);
16479 fgFirstBB = newBlk;
16480 newBlk->bbPrev = nullptr;
16483 #if FEATURE_EH_FUNCLETS
16485 /* Update fgFirstFuncletBB if insertBeforeBlk is the first block of the funclet region. */
16487 if (fgFirstFuncletBB == insertBeforeBlk)
16489 fgFirstFuncletBB = newBlk;
16492 #endif // FEATURE_EH_FUNCLETS
16495 /*****************************************************************************
16496 * Inserts basic block after existing basic block.
16498 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
16499 * (It can't be used to insert a block as the first block of the funclet region).
16501 void Compiler::fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk)
16503 newBlk->bbNext = insertAfterBlk->bbNext;
16505 if (insertAfterBlk->bbNext)
16507 insertAfterBlk->bbNext->bbPrev = newBlk;
16510 insertAfterBlk->bbNext = newBlk;
16511 newBlk->bbPrev = insertAfterBlk;
16513 if (fgLastBB == insertAfterBlk)
16516 assert(fgLastBB->bbNext == nullptr);
16520 // We have two edges (bAlt => bCur) and (bCur => bNext).
16522 // Returns true if the weight of (bAlt => bCur)
16523 // is greater than the weight of (bCur => bNext).
16524 // We compare the edge weights if we have valid edge weights
16525 // otherwise we compare blocks weights.
16527 bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt)
16529 // bCur can't be NULL and must be a fall through bbJumpKind
16530 noway_assert(bCur != nullptr);
16531 noway_assert(bCur->bbFallsThrough());
16532 noway_assert(bAlt != nullptr);
16534 // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND
16535 if ((bAlt->bbJumpKind != BBJ_ALWAYS) && (bAlt->bbJumpKind != BBJ_COND))
16540 // if bAlt doesn't jump to bCur it can't be a better fall through than bCur
16541 if (bAlt->bbJumpDest != bCur)
16546 // Currently bNext is the fall through for bCur
16547 BasicBlock* bNext = bCur->bbNext;
16548 noway_assert(bNext != nullptr);
16550 // We will set result to true if bAlt is a better fall through than bCur
16552 if (fgHaveValidEdgeWeights)
16554 // We will compare the edge weight for our two choices
16555 flowList* edgeFromAlt = fgGetPredForBlock(bCur, bAlt);
16556 flowList* edgeFromCur = fgGetPredForBlock(bNext, bCur);
16557 noway_assert(edgeFromCur != nullptr);
16558 noway_assert(edgeFromAlt != nullptr);
16560 result = (edgeFromAlt->flEdgeWeightMin > edgeFromCur->flEdgeWeightMax);
16564 if (bAlt->bbJumpKind == BBJ_ALWAYS)
16566 // Our result is true if bAlt's weight is more than bCur's weight
16567 result = (bAlt->bbWeight > bCur->bbWeight);
16571 noway_assert(bAlt->bbJumpKind == BBJ_COND);
16572 // Our result is true if bAlt's weight is more than twice bCur's weight
16573 result = (bAlt->bbWeight > (2 * bCur->bbWeight));
16579 //------------------------------------------------------------------------
16580 // fgCheckEHCanInsertAfterBlock: Determine if a block can be inserted after
16581 // 'blk' and legally be put in the EH region specified by 'regionIndex'. This
16582 // can be true if the most nested region the block is in is already 'regionIndex',
16583 // as we'll just extend the most nested region (and any region ending at the same block).
16584 // It can also be true if it is the end of (a set of) EH regions, such that
16585 // inserting the block and properly extending some EH regions (if necessary)
16586 // puts the block in the correct region. We only consider the case of extending
16587 // an EH region after 'blk' (that is, to include 'blk' and the newly insert block);
16588 // we don't consider inserting a block as the the first block of an EH region following 'blk'.
16590 // Consider this example:
16597 // | |--- |--- BB05
16599 // |----------------- BB07
16601 // Passing BB05 and try1/try2/try3 as the region to insert into (as well as putInTryRegion==true)
16602 // will all return 'true'. Here are the cases:
16603 // 1. Insert into try1: the most nested EH region BB05 is in is already try1, so we can insert after
16604 // it and extend try1 (and try2).
16605 // 2. Insert into try2: we can extend try2, but leave try1 alone.
16606 // 3. Insert into try3: we can leave try1 and try2 alone, and put the new block just in try3. Note that
16607 // in this case, after we "loop outwards" in the EH nesting, we get to a place where we're in the middle
16608 // of the try3 region, not at the end of it.
16609 // In all cases, it is possible to put a block after BB05 and put it in any of these three 'try' regions legally.
16611 // Filters are ignored; if 'blk' is in a filter, the answer will be false.
16614 // blk - the BasicBlock we are checking to see if we can insert after.
16615 // regionIndex - the EH region we want to insert a block into. regionIndex is
16616 // in the range [0..compHndBBtabCount]; 0 means "main method".
16617 // putInTryRegion - 'true' if the new block should be inserted in the 'try' region of 'regionIndex'.
16618 // For regionIndex 0 (the "main method"), this should be 'true'.
16621 // 'true' if a block can be inserted after 'blk' and put in EH region 'regionIndex', else 'false'.
16623 bool Compiler::fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion)
16625 assert(blk != nullptr);
16626 assert(regionIndex <= compHndBBtabCount);
16628 if (regionIndex == 0)
16630 assert(putInTryRegion);
16634 unsigned nestedRegionIndex = ehGetMostNestedRegionIndex(blk, &inTryRegion);
16636 bool insertOK = true;
16639 if (nestedRegionIndex == regionIndex)
16641 // This block is in the region we want to be in. We can insert here if it's the right type of region.
16642 // (If we want to be in the 'try' region, but the block is in the handler region, then inserting a
16643 // new block after 'blk' can't put it in the 'try' region, and vice-versa, since we only consider
16644 // extending regions after, not prepending to regions.)
16645 // This check will be 'true' if we are trying to put something in the main function (as putInTryRegion
16646 // must be 'true' if regionIndex is zero, and inTryRegion will also be 'true' if nestedRegionIndex is zero).
16647 insertOK = (putInTryRegion == inTryRegion);
16650 else if (nestedRegionIndex == 0)
16652 // The block is in the main function, but we want to put something in a nested region. We can't do that.
16657 assert(nestedRegionIndex > 0);
16658 EHblkDsc* ehDsc = ehGetDsc(nestedRegionIndex - 1); // ehGetDsc uses [0..compHndBBtabCount) form.
16662 if (blk != ehDsc->ebdTryLast)
16664 // Not the last block? Then it must be somewhere else within the try region, so we can't insert here.
16666 break; // exit the 'for' loop
16671 // We ignore filters.
16672 if (blk != ehDsc->ebdHndLast)
16674 // Not the last block? Then it must be somewhere else within the handler region, so we can't insert
16677 break; // exit the 'for' loop
16681 // Things look good for this region; check the enclosing regions, if any.
16683 nestedRegionIndex =
16684 ehGetEnclosingRegionIndex(nestedRegionIndex - 1,
16685 &inTryRegion); // ehGetEnclosingRegionIndex uses [0..compHndBBtabCount) form.
16687 // Convert to [0..compHndBBtabCount] form.
16688 nestedRegionIndex = (nestedRegionIndex == EHblkDsc::NO_ENCLOSING_INDEX) ? 0 : nestedRegionIndex + 1;
16689 } // end of for(;;)
16694 //------------------------------------------------------------------------
16695 // Finds the block closest to endBlk in the range [startBlk..endBlk) after which a block can be
16696 // inserted easily. Note that endBlk cannot be returned; its predecessor is the last block that can
16697 // be returned. The new block will be put in an EH region described by the arguments regionIndex,
16698 // putInTryRegion, startBlk, and endBlk (explained below), so it must be legal to place to put the
16699 // new block after the insertion location block, give it the specified EH region index, and not break
16700 // EH nesting rules. This function is careful to choose a block in the correct EH region. However,
16701 // it assumes that the new block can ALWAYS be placed at the end (just before endBlk). That means
16702 // that the caller must ensure that is true.
16704 // Below are the possible cases for the arguments to this method:
16705 // 1. putInTryRegion == true and regionIndex > 0:
16706 // Search in the try region indicated by regionIndex.
16707 // 2. putInTryRegion == false and regionIndex > 0:
16708 // a. If startBlk is the first block of a filter and endBlk is the block after the end of the
16709 // filter (that is, the startBlk and endBlk match a filter bounds exactly), then choose a
16710 // location within this filter region. (Note that, due to IL rules, filters do not have any
16711 // EH nested within them.) Otherwise, filters are skipped.
16712 // b. Else, search in the handler region indicated by regionIndex.
16713 // 3. regionIndex = 0:
16714 // Search in the entire main method, excluding all EH regions. In this case, putInTryRegion must be true.
16716 // This method makes sure to find an insertion point which would not cause the inserted block to
16717 // be put inside any inner try/filter/handler regions.
16719 // The actual insertion occurs after the returned block. Note that the returned insertion point might
16720 // be the last block of a more nested EH region, because the new block will be inserted after the insertion
16721 // point, and will not extend the more nested EH region. For example:
16728 // | |--- |--- BB05
16730 // |----------------- BB07
16732 // for regionIndex==try3, putInTryRegion==true, we might return BB05, even though BB05 will have a try index
16733 // for try1 (the most nested 'try' region the block is in). That's because when we insert after BB05, the new
16734 // block will be in the correct, desired EH region, since try1 and try2 regions will not be extended to include
16735 // the inserted block. Furthermore, for regionIndex==try2, putInTryRegion==true, we can also return BB05. In this
16736 // case, when the new block is inserted, the try1 region remains the same, but we need extend region 'try2' to
16737 // include the inserted block. (We also need to check all parent regions as well, just in case any parent regions
16738 // also end on the same block, in which case we would also need to extend the parent regions. This is standard
16739 // procedure when inserting a block at the end of an EH region.)
16741 // If nearBlk is non-nullptr then we return the closest block after nearBlk that will work best.
16743 // We try to find a block in the appropriate region that is not a fallthrough block, so we can insert after it
16744 // without the need to insert a jump around the inserted block.
16746 // Note that regionIndex is numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is, "0" is
16747 // "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
16750 // regionIndex - the region index where the new block will be inserted. Zero means entire method;
16751 // non-zero means either a "try" or a "handler" region, depending on what putInTryRegion says.
16752 // putInTryRegion - 'true' to put the block in the 'try' region corresponding to 'regionIndex', 'false'
16753 // to put the block in the handler region. Should be 'true' if regionIndex==0.
16754 // startBlk - start block of range to search.
16755 // endBlk - end block of range to search (don't include this block in the range). Can be nullptr to indicate
16756 // the end of the function.
16757 // nearBlk - If non-nullptr, try to find an insertion location closely after this block. If nullptr, we insert
16758 // at the best location found towards the end of the acceptable block range.
16759 // jumpBlk - When nearBlk is set, this can be set to the block which jumps to bNext->bbNext (TODO: need to review
16761 // runRarely - true if the block being inserted is expected to be rarely run. This helps determine
16762 // the best place to put the new block, by putting in a place that has the same 'rarely run' characteristic.
16765 // A block with the desired characteristics, so the new block will be inserted after this one.
16766 // If there is no suitable location, return nullptr. This should basically never happen.
16768 BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex,
16769 bool putInTryRegion,
16770 BasicBlock* startBlk,
16771 BasicBlock* endBlk,
16772 BasicBlock* nearBlk,
16773 BasicBlock* jumpBlk,
16776 noway_assert(startBlk != nullptr);
16777 noway_assert(startBlk != endBlk);
16778 noway_assert((regionIndex == 0 && putInTryRegion) || // Search in the main method
16779 (putInTryRegion && regionIndex > 0 &&
16780 startBlk->bbTryIndex == regionIndex) || // Search in the specified try region
16781 (!putInTryRegion && regionIndex > 0 &&
16782 startBlk->bbHndIndex == regionIndex)); // Search in the specified handler region
16785 // Assert that startBlk precedes endBlk in the block list.
16786 // We don't want to use bbNum to assert this condition, as we cannot depend on the block numbers being
16787 // sequential at all times.
16788 for (BasicBlock* b = startBlk; b != endBlk; b = b->bbNext)
16790 assert(b != nullptr); // We reached the end of the block list, but never found endBlk.
16794 JITDUMP("fgFindInsertPoint(regionIndex=%u, putInTryRegion=%s, startBlk=BB%02u, endBlk=BB%02u, nearBlk=BB%02u, "
16795 "jumpBlk=BB%02u, runRarely=%s)\n",
16796 regionIndex, dspBool(putInTryRegion), startBlk->bbNum, (endBlk == nullptr) ? 0 : endBlk->bbNum,
16797 (nearBlk == nullptr) ? 0 : nearBlk->bbNum, (jumpBlk == nullptr) ? 0 : jumpBlk->bbNum, dspBool(runRarely));
16799 bool reachedNear = false; // Have we reached 'nearBlk' in our search? If not, we'll keep searching.
16800 bool inFilter = false; // Are we in a filter region that we need to skip?
16801 BasicBlock* bestBlk =
16802 nullptr; // Set to the best insertion point we've found so far that meets all the EH requirements.
16803 BasicBlock* goodBlk =
16804 nullptr; // Set to an acceptable insertion point that we'll use if we don't find a 'best' option.
16807 if (nearBlk != nullptr)
16809 // Does the nearBlk precede the startBlk?
16810 for (blk = nearBlk; blk != nullptr; blk = blk->bbNext)
16812 if (blk == startBlk)
16814 reachedNear = true;
16817 else if (blk == endBlk)
16824 for (blk = startBlk; blk != endBlk; blk = blk->bbNext)
16826 // The only way (blk == nullptr) could be true is if the caller passed an endBlk that preceded startBlk in the
16827 // block list, or if endBlk isn't in the block list at all. In DEBUG, we'll instead hit the similar
16828 // well-formedness assert earlier in this function.
16829 noway_assert(blk != nullptr);
16831 if (blk == nearBlk)
16833 reachedNear = true;
16836 if (blk->bbCatchTyp == BBCT_FILTER)
16838 // Record the fact that we entered a filter region, so we don't insert into filters...
16839 // Unless the caller actually wanted the block inserted in this exact filter region.
16840 // Detect this by the fact that startBlk and endBlk point to the filter begin and end.
16841 if (putInTryRegion || (blk != startBlk) || (startBlk != ehGetDsc(regionIndex - 1)->ebdFilter) ||
16842 (endBlk != ehGetDsc(regionIndex - 1)->ebdHndBeg))
16847 else if (blk->bbCatchTyp == BBCT_FILTER_HANDLER)
16849 // Record the fact that we exited a filter region.
16853 // Don't insert a block inside this filter region.
16859 // Note that the new block will be inserted AFTER "blk". We check to make sure that doing so
16860 // would put the block in the correct EH region. We make an assumption here that you can
16861 // ALWAYS insert the new block before "endBlk" (that is, at the end of the search range)
16862 // and be in the correct EH region. This is must be guaranteed by the caller (as it is by
16863 // fgNewBBinRegion(), which passes the search range as an exact EH region block range).
16864 // Because of this assumption, we only check the EH information for blocks before the last block.
16865 if (blk->bbNext != endBlk)
16867 // We are in the middle of the search range. We can't insert the new block in
16868 // an inner try or handler region. We can, however, set the insertion
16869 // point to the last block of an EH try/handler region, if the enclosing
16870 // region is the region we wish to insert in. (Since multiple regions can
16871 // end at the same block, we need to search outwards, checking that the
16872 // block is the last block of every EH region out to the region we want
16873 // to insert in.) This is especially useful for putting a call-to-finally
16874 // block on AMD64 immediately after its corresponding 'try' block, so in the
16875 // common case, we'll just fall through to it. For example:
16878 // BB02 -- first block of try
16880 // BB04 -- last block of try
16881 // BB05 -- first block of finally
16883 // BB07 -- last block of handler
16886 // Assume there is only one try/finally, so BB01 and BB08 are in the "main function".
16887 // For AMD64 call-to-finally, we'll want to insert the BBJ_CALLFINALLY in
16888 // the main function, immediately after BB04. This allows us to do that.
16890 if (!fgCheckEHCanInsertAfterBlock(blk, regionIndex, putInTryRegion))
16892 // Can't insert here.
16897 // Look for an insert location:
16898 // 1. We want blocks that don't end with a fall through,
16899 // 2. Also, when blk equals nearBlk we may want to insert here.
16900 if (!blk->bbFallsThrough() || (blk == nearBlk))
16902 bool updateBestBlk = true; // We will probably update the bestBlk
16904 // If blk falls through then we must decide whether to use the nearBlk
16906 if (blk->bbFallsThrough())
16908 noway_assert(blk == nearBlk);
16909 if (jumpBlk != nullptr)
16911 updateBestBlk = fgIsBetterFallThrough(blk, jumpBlk);
16915 updateBestBlk = false;
16919 // If we already have a best block, see if the 'runRarely' flags influences
16920 // our choice. If we want a runRarely insertion point, and the existing best
16921 // block is run rarely but the current block isn't run rarely, then don't
16922 // update the best block.
16923 // TODO-CQ: We should also handle the reverse case, where runRarely is false (we
16924 // want a non-rarely-run block), but bestBlock->isRunRarely() is true. In that
16925 // case, we should update the block, also. Probably what we want is:
16926 // (bestBlk->isRunRarely() != runRarely) && (blk->isRunRarely() == runRarely)
16927 if (updateBestBlk && (bestBlk != nullptr) && runRarely && bestBlk->isRunRarely() && !blk->isRunRarely())
16929 updateBestBlk = false;
16934 // We found a 'best' insertion location, so save it away.
16937 // If we've reached nearBlk, we've satisfied all the criteria,
16944 // If we haven't reached nearBlk, keep looking for a 'best' location, just
16945 // in case we'll find one at or after nearBlk. If no nearBlk was specified,
16946 // we prefer inserting towards the end of the given range, so keep looking
16947 // for more acceptable insertion locations.
16951 // No need to update goodBlk after we have set bestBlk, but we could still find a better
16952 // bestBlk, so keep looking.
16953 if (bestBlk != nullptr)
16958 // Set the current block as a "good enough" insertion point, if it meets certain criteria.
16959 // We'll return this block if we don't find a "best" block in the search range. The block
16960 // can't be a BBJ_CALLFINALLY of a BBJ_CALLFINALLY/BBJ_ALWAYS pair (since we don't want
16961 // to insert anything between these two blocks). Otherwise, we can use it. However,
16962 // if we'd previously chosen a BBJ_COND block, then we'd prefer the "good" block to be
16963 // something else. We keep updating it until we've reached the 'nearBlk', to push it as
16964 // close to endBlk as possible.
16965 if (!blk->isBBCallAlwaysPair())
16967 if (goodBlk == nullptr)
16971 else if ((goodBlk->bbJumpKind == BBJ_COND) || (blk->bbJumpKind != BBJ_COND))
16973 if ((blk == nearBlk) || !reachedNear)
16981 // If we didn't find a non-fall_through block, then insert at the last good block.
16983 if (bestBlk == nullptr)
16993 //------------------------------------------------------------------------
16994 // Creates a new BasicBlock and inserts it in a specific EH region, given by 'tryIndex', 'hndIndex', and 'putInFilter'.
16996 // If 'putInFilter' it true, then the block is inserted in the filter region given by 'hndIndex'. In this case, tryIndex
16997 // must be a less nested EH region (that is, tryIndex > hndIndex).
16999 // Otherwise, the block is inserted in either the try region or the handler region, depending on which one is the inner
17000 // region. In other words, if the try region indicated by tryIndex is nested in the handler region indicated by
17002 // then the new BB will be created in the try region. Vice versa.
17004 // Note that tryIndex and hndIndex are numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is,
17005 // "0" is "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
17007 // To be more specific, this function will create a new BB in one of the following 5 regions (if putInFilter is false):
17008 // 1. When tryIndex = 0 and hndIndex = 0:
17009 // The new BB will be created in the method region.
17010 // 2. When tryIndex != 0 and hndIndex = 0:
17011 // The new BB will be created in the try region indicated by tryIndex.
17012 // 3. When tryIndex == 0 and hndIndex != 0:
17013 // The new BB will be created in the handler region indicated by hndIndex.
17014 // 4. When tryIndex != 0 and hndIndex != 0 and tryIndex < hndIndex:
17015 // In this case, the try region is nested inside the handler region. Therefore, the new BB will be created
17016 // in the try region indicated by tryIndex.
17017 // 5. When tryIndex != 0 and hndIndex != 0 and tryIndex > hndIndex:
17018 // In this case, the handler region is nested inside the try region. Therefore, the new BB will be created
17019 // in the handler region indicated by hndIndex.
17021 // Note that if tryIndex != 0 and hndIndex != 0 then tryIndex must not be equal to hndIndex (this makes sense because
17022 // if they are equal, you are asking to put the new block in both the try and handler, which is impossible).
17024 // The BasicBlock will not be inserted inside an EH region that is more nested than the requested tryIndex/hndIndex
17025 // region (so the function is careful to skip more nested EH regions when searching for a place to put the new block).
17027 // This function cannot be used to insert a block as the first block of any region. It always inserts a block after
17028 // an existing block in the given region.
17030 // If nearBlk is nullptr, or the block is run rarely, then the new block is assumed to be run rarely.
17033 // jumpKind - the jump kind of the new block to create.
17034 // tryIndex - the try region to insert the new block in, described above. This must be a number in the range
17035 // [0..compHndBBtabCount].
17036 // hndIndex - the handler region to insert the new block in, described above. This must be a number in the range
17037 // [0..compHndBBtabCount].
17038 // nearBlk - insert the new block closely after this block, if possible. If nullptr, put the new block anywhere
17039 // in the requested region.
17040 // putInFilter - put the new block in the filter region given by hndIndex, as described above.
17041 // runRarely - 'true' if the new block is run rarely.
17042 // insertAtEnd - 'true' if the block should be inserted at the end of the region. Note: this is currently only
17043 // implemented when inserting into the main function (not into any EH region).
17048 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17051 BasicBlock* nearBlk,
17052 bool putInFilter /* = false */,
17053 bool runRarely /* = false */,
17054 bool insertAtEnd /* = false */)
17056 assert(tryIndex <= compHndBBtabCount);
17057 assert(hndIndex <= compHndBBtabCount);
17059 /* afterBlk is the block which will precede the newBB */
17060 BasicBlock* afterBlk;
17062 // start and end limit for inserting the block
17063 BasicBlock* startBlk = nullptr;
17064 BasicBlock* endBlk = nullptr;
17066 bool putInTryRegion = true;
17067 unsigned regionIndex = 0;
17069 // First, figure out which region (the "try" region or the "handler" region) to put the newBB in.
17070 if ((tryIndex == 0) && (hndIndex == 0))
17072 assert(!putInFilter);
17074 endBlk = fgEndBBAfterMainFunction(); // don't put new BB in funclet region
17076 if (insertAtEnd || (nearBlk == nullptr))
17078 /* We'll just insert the block at the end of the method, before the funclets */
17080 afterBlk = fgLastBBInMainFunction();
17081 goto _FoundAfterBlk;
17085 // We'll search through the entire method
17086 startBlk = fgFirstBB;
17089 noway_assert(regionIndex == 0);
17093 noway_assert(tryIndex > 0 || hndIndex > 0);
17094 PREFIX_ASSUME(tryIndex <= compHndBBtabCount);
17095 PREFIX_ASSUME(hndIndex <= compHndBBtabCount);
17097 // Decide which region to put in, the "try" region or the "handler" region.
17100 noway_assert(hndIndex > 0);
17101 putInTryRegion = false;
17103 else if (hndIndex == 0)
17105 noway_assert(tryIndex > 0);
17106 noway_assert(putInTryRegion);
17107 assert(!putInFilter);
17111 noway_assert(tryIndex > 0 && hndIndex > 0 && tryIndex != hndIndex);
17112 putInTryRegion = (tryIndex < hndIndex);
17115 if (putInTryRegion)
17117 // Try region is the inner region.
17118 // In other words, try region must be nested inside the handler region.
17119 noway_assert(hndIndex == 0 || bbInHandlerRegions(hndIndex - 1, ehGetDsc(tryIndex - 1)->ebdTryBeg));
17120 assert(!putInFilter);
17124 // Handler region is the inner region.
17125 // In other words, handler region must be nested inside the try region.
17126 noway_assert(tryIndex == 0 || bbInTryRegions(tryIndex - 1, ehGetDsc(hndIndex - 1)->ebdHndBeg));
17129 // Figure out the start and end block range to search for an insertion location. Pick the beginning and
17130 // ending blocks of the target EH region (the 'endBlk' is one past the last block of the EH region, to make
17131 // loop iteration easier). Note that, after funclets have been created (for FEATURE_EH_FUNCLETS),
17132 // this linear block range will not include blocks of handlers for try/handler clauses nested within
17133 // this EH region, as those blocks have been extracted as funclets. That is ok, though, because we don't
17134 // want to insert a block in any nested EH region.
17136 if (putInTryRegion)
17138 // We will put the newBB in the try region.
17139 EHblkDsc* ehDsc = ehGetDsc(tryIndex - 1);
17140 startBlk = ehDsc->ebdTryBeg;
17141 endBlk = ehDsc->ebdTryLast->bbNext;
17142 regionIndex = tryIndex;
17144 else if (putInFilter)
17146 // We will put the newBB in the filter region.
17147 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17148 startBlk = ehDsc->ebdFilter;
17149 endBlk = ehDsc->ebdHndBeg;
17150 regionIndex = hndIndex;
17154 // We will put the newBB in the handler region.
17155 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17156 startBlk = ehDsc->ebdHndBeg;
17157 endBlk = ehDsc->ebdHndLast->bbNext;
17158 regionIndex = hndIndex;
17161 noway_assert(regionIndex > 0);
17164 // Now find the insertion point.
17165 afterBlk = fgFindInsertPoint(regionIndex, putInTryRegion, startBlk, endBlk, nearBlk, nullptr, runRarely);
17169 /* We have decided to insert the block after 'afterBlk'. */
17170 noway_assert(afterBlk != nullptr);
17172 JITDUMP("fgNewBBinRegion(jumpKind=%u, tryIndex=%u, hndIndex=%u, putInFilter=%s, runRarely=%s, insertAtEnd=%s): "
17173 "inserting after BB%02u\n",
17174 jumpKind, tryIndex, hndIndex, dspBool(putInFilter), dspBool(runRarely), dspBool(insertAtEnd),
17177 return fgNewBBinRegionWorker(jumpKind, afterBlk, regionIndex, putInTryRegion);
17180 //------------------------------------------------------------------------
17181 // Creates a new BasicBlock and inserts it in the same EH region as 'srcBlk'.
17183 // See the implementation of fgNewBBinRegion() used by this one for more notes.
17186 // jumpKind - the jump kind of the new block to create.
17187 // srcBlk - insert the new block in the same EH region as this block, and closely after it if possible.
17192 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17193 BasicBlock* srcBlk,
17194 bool runRarely /* = false */,
17195 bool insertAtEnd /* = false */)
17197 assert(srcBlk != nullptr);
17199 const unsigned tryIndex = srcBlk->bbTryIndex;
17200 const unsigned hndIndex = srcBlk->bbHndIndex;
17201 bool putInFilter = false;
17203 // Check to see if we need to put the new block in a filter. We do if srcBlk is in a filter.
17204 // This can only be true if there is a handler index, and the handler region is more nested than the
17205 // try region (if any). This is because no EH regions can be nested within a filter.
17206 if (BasicBlock::ehIndexMaybeMoreNested(hndIndex, tryIndex))
17208 assert(hndIndex != 0); // If hndIndex is more nested, we must be in some handler!
17209 putInFilter = ehGetDsc(hndIndex - 1)->InFilterRegionBBRange(srcBlk);
17212 return fgNewBBinRegion(jumpKind, tryIndex, hndIndex, srcBlk, putInFilter, runRarely, insertAtEnd);
17215 //------------------------------------------------------------------------
17216 // Creates a new BasicBlock and inserts it at the end of the function.
17218 // See the implementation of fgNewBBinRegion() used by this one for more notes.
17221 // jumpKind - the jump kind of the new block to create.
17226 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind)
17228 return fgNewBBinRegion(jumpKind, 0, 0, nullptr, /* putInFilter */ false, /* runRarely */ false,
17229 /* insertAtEnd */ true);
17232 //------------------------------------------------------------------------
17233 // Creates a new BasicBlock, and inserts it after 'afterBlk'.
17235 // The block cannot be inserted into a more nested try/handler region than that specified by 'regionIndex'.
17236 // (It is given exactly 'regionIndex'.) Thus, the parameters must be passed to ensure proper EH nesting
17237 // rules are followed.
17240 // jumpKind - the jump kind of the new block to create.
17241 // afterBlk - insert the new block after this one.
17242 // regionIndex - the block will be put in this EH region.
17243 // putInTryRegion - If true, put the new block in the 'try' region corresponding to 'regionIndex', and
17244 // set its handler index to the most nested handler region enclosing that 'try' region.
17245 // Otherwise, put the block in the handler region specified by 'regionIndex', and set its 'try'
17246 // index to the most nested 'try' region enclosing that handler region.
17251 BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind,
17252 BasicBlock* afterBlk,
17253 unsigned regionIndex,
17254 bool putInTryRegion)
17256 /* Insert the new block */
17257 BasicBlock* afterBlkNext = afterBlk->bbNext;
17258 (void)afterBlkNext; // prevent "unused variable" error from GCC
17259 BasicBlock* newBlk = fgNewBBafter(jumpKind, afterBlk, false);
17261 if (putInTryRegion)
17263 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
17264 newBlk->bbTryIndex = (unsigned short)regionIndex;
17265 newBlk->bbHndIndex = bbFindInnermostHandlerRegionContainingTryRegion(regionIndex);
17269 newBlk->bbTryIndex = bbFindInnermostTryRegionContainingHandlerRegion(regionIndex);
17270 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
17271 newBlk->bbHndIndex = (unsigned short)regionIndex;
17274 // We're going to compare for equal try regions (to handle the case of 'mutually protect'
17275 // regions). We need to save off the current try region, otherwise we might change it
17276 // before it gets compared later, thereby making future comparisons fail.
17278 BasicBlock* newTryBeg;
17279 BasicBlock* newTryLast;
17280 (void)ehInitTryBlockRange(newBlk, &newTryBeg, &newTryLast);
17285 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
17287 // Is afterBlk at the end of a try region?
17288 if (HBtab->ebdTryLast == afterBlk)
17290 noway_assert(afterBlkNext == newBlk->bbNext);
17292 bool extendTryRegion = false;
17293 if (newBlk->hasTryIndex())
17295 // We're adding a block after the last block of some try region. Do
17296 // we extend the try region to include the block, or not?
17297 // If the try region is exactly the same as the try region
17298 // associated with the new block (based on the block's try index,
17299 // which represents the innermost try the block is a part of), then
17301 // If the try region is a "parent" try region -- an enclosing try region
17302 // that has the same last block as the new block's try region -- then
17303 // we also extend. For example:
17308 // } /* 2 */ } /* 1 */
17309 // This example is meant to indicate that both try regions 1 and 2 end at
17310 // the same block, and we're extending 2. Thus, we must also extend 1. If we
17311 // only extended 2, we would break proper nesting. (Dev11 bug 137967)
17313 extendTryRegion = HBtab->ebdIsSameTry(newTryBeg, newTryLast) || bbInTryRegions(XTnum, newBlk);
17316 // Does newBlk extend this try region?
17317 if (extendTryRegion)
17319 // Yes, newBlk extends this try region
17321 // newBlk is the now the new try last block
17322 fgSetTryEnd(HBtab, newBlk);
17326 // Is afterBlk at the end of a handler region?
17327 if (HBtab->ebdHndLast == afterBlk)
17329 noway_assert(afterBlkNext == newBlk->bbNext);
17331 // Does newBlk extend this handler region?
17332 bool extendHndRegion = false;
17333 if (newBlk->hasHndIndex())
17335 // We're adding a block after the last block of some handler region. Do
17336 // we extend the handler region to include the block, or not?
17337 // If the handler region is exactly the same as the handler region
17338 // associated with the new block (based on the block's handler index,
17339 // which represents the innermost handler the block is a part of), then
17341 // If the handler region is a "parent" handler region -- an enclosing
17342 // handler region that has the same last block as the new block's handler
17343 // region -- then we also extend. For example:
17348 // } /* 2 */ } /* 1 */
17349 // This example is meant to indicate that both handler regions 1 and 2 end at
17350 // the same block, and we're extending 2. Thus, we must also extend 1. If we
17351 // only extended 2, we would break proper nesting. (Dev11 bug 372051)
17353 extendHndRegion = bbInHandlerRegions(XTnum, newBlk);
17356 if (extendHndRegion)
17358 // Yes, newBlk extends this handler region
17360 // newBlk is now the last block of the handler.
17361 fgSetHndEnd(HBtab, newBlk);
17366 /* If afterBlk falls through, we insert a jump around newBlk */
17367 fgConnectFallThrough(afterBlk, newBlk->bbNext);
17370 fgVerifyHandlerTab();
17376 /*****************************************************************************
17380 unsigned Compiler::acdHelper(SpecialCodeKind codeKind)
17384 case SCK_RNGCHK_FAIL:
17385 return CORINFO_HELP_RNGCHKFAIL;
17386 #if COR_JIT_EE_VERSION > 460
17387 case SCK_ARG_EXCPN:
17388 return CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
17389 case SCK_ARG_RNG_EXCPN:
17390 return CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
17391 #endif // COR_JIT_EE_VERSION
17392 case SCK_DIV_BY_ZERO:
17393 return CORINFO_HELP_THROWDIVZERO;
17394 case SCK_ARITH_EXCPN:
17395 return CORINFO_HELP_OVERFLOW;
17397 assert(!"Bad codeKind");
17402 /*****************************************************************************
17404 * Find/create an added code entry associated with the given block and with
17408 BasicBlock* Compiler::fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth)
17410 // Record that the code will call a THROW_HELPER
17411 // so on Windows Amd64 we can allocate the 4 outgoing
17412 // arg slots on the stack frame if there are no other calls.
17413 compUsesThrowHelper = true;
17415 // For debuggable code, genJumpToThrowHlpBlk() will generate the 'throw'
17416 // code inline. It has to be kept consistent with fgAddCodeRef()
17417 if (opts.compDbgCode)
17422 const static BBjumpKinds jumpKinds[] = {
17423 BBJ_NONE, // SCK_NONE
17424 BBJ_THROW, // SCK_RNGCHK_FAIL
17425 BBJ_ALWAYS, // SCK_PAUSE_EXEC
17426 BBJ_THROW, // SCK_DIV_BY_ZERO
17427 BBJ_THROW, // SCK_ARITH_EXCP, SCK_OVERFLOW
17428 BBJ_THROW, // SCK_ARG_EXCPN
17429 BBJ_THROW, // SCK_ARG_RNG_EXCPN
17432 noway_assert(sizeof(jumpKinds) == SCK_COUNT); // sanity check
17434 /* First look for an existing entry that matches what we're looking for */
17436 AddCodeDsc* add = fgFindExcptnTarget(kind, refData);
17438 if (add) // found it
17440 #ifdef _TARGET_X86_
17441 // If different range checks happen at different stack levels,
17442 // they can't all jump to the same "call @rngChkFailed" AND have
17443 // frameless methods, as the rngChkFailed may need to unwind the
17444 // stack, and we have to be able to report the stack level.
17446 // The following check forces most methods that reference an
17447 // array element in a parameter list to have an EBP frame,
17448 // this restriction could be removed with more careful code
17449 // generation for BBJ_THROW (i.e. range check failed).
17451 if (add->acdStkLvl != stkDepth)
17453 codeGen->setFrameRequired(true);
17455 #endif // _TARGET_X86_
17457 return add->acdDstBlk;
17460 /* We have to allocate a new entry and prepend it to the list */
17462 add = new (this, CMK_Unknown) AddCodeDsc;
17463 add->acdData = refData;
17464 add->acdKind = kind;
17465 add->acdStkLvl = (unsigned short)stkDepth;
17466 noway_assert(add->acdStkLvl == stkDepth);
17467 add->acdNext = fgAddCodeList;
17468 fgAddCodeList = add;
17470 /* Create the target basic block */
17472 BasicBlock* newBlk;
17474 newBlk = add->acdDstBlk = fgNewBBinRegion(jumpKinds[kind], srcBlk, /* runRarely */ true, /* insertAtEnd */ true);
17476 add->acdDstBlk->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
17481 const char* msgWhere = "";
17482 if (!srcBlk->hasTryIndex() && !srcBlk->hasHndIndex())
17484 msgWhere = "non-EH region";
17486 else if (!srcBlk->hasTryIndex())
17488 msgWhere = "handler";
17490 else if (!srcBlk->hasHndIndex())
17494 else if (srcBlk->getTryIndex() < srcBlk->getHndIndex())
17500 msgWhere = "handler";
17506 case SCK_RNGCHK_FAIL:
17507 msg = " for RNGCHK_FAIL";
17509 case SCK_PAUSE_EXEC:
17510 msg = " for PAUSE_EXEC";
17512 case SCK_DIV_BY_ZERO:
17513 msg = " for DIV_BY_ZERO";
17516 msg = " for OVERFLOW";
17518 #if COR_JIT_EE_VERSION > 460
17519 case SCK_ARG_EXCPN:
17520 msg = " for ARG_EXCPN";
17522 case SCK_ARG_RNG_EXCPN:
17523 msg = " for ARG_RNG_EXCPN";
17525 #endif // COR_JIT_EE_VERSION
17531 printf("\nfgAddCodeRef -"
17532 " Add BB in %s%s, new block BB%02u [%08p], stkDepth is %d\n",
17533 msgWhere, msg, add->acdDstBlk->bbNum, dspPtr(add->acdDstBlk), stkDepth);
17538 newBlk->bbTgtStkDepth = stkDepth;
17541 /* Mark the block as added by the compiler and not removable by future flow
17542 graph optimizations. Note that no bbJumpDest points to these blocks. */
17544 newBlk->bbFlags |= BBF_IMPORTED;
17545 newBlk->bbFlags |= BBF_DONT_REMOVE;
17547 /* Remember that we're adding a new basic block */
17549 fgAddCodeModf = true;
17550 fgRngChkThrowAdded = true;
17552 /* Now figure out what code to insert */
17555 int helper = CORINFO_HELP_UNDEF;
17559 case SCK_RNGCHK_FAIL:
17560 helper = CORINFO_HELP_RNGCHKFAIL;
17563 case SCK_DIV_BY_ZERO:
17564 helper = CORINFO_HELP_THROWDIVZERO;
17567 case SCK_ARITH_EXCPN:
17568 helper = CORINFO_HELP_OVERFLOW;
17569 noway_assert(SCK_OVERFLOW == SCK_ARITH_EXCPN);
17572 #if COR_JIT_EE_VERSION > 460
17573 case SCK_ARG_EXCPN:
17574 helper = CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
17577 case SCK_ARG_RNG_EXCPN:
17578 helper = CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
17580 #endif // COR_JIT_EE_VERSION
17582 // case SCK_PAUSE_EXEC:
17583 // noway_assert(!"add code to pause exec");
17586 noway_assert(!"unexpected code addition kind");
17590 noway_assert(helper != CORINFO_HELP_UNDEF);
17592 // Add the appropriate helper call.
17593 tree = gtNewHelperCallNode(helper, TYP_VOID, GTF_EXCEPT);
17595 // There are no args here but fgMorphArgs has side effects
17596 // such as setting the outgoing arg area (which is necessary
17597 // on AMD if there are any calls).
17598 tree = fgMorphArgs(tree);
17600 // Store the tree in the new basic block.
17601 assert(!srcBlk->isEmpty());
17602 if (!srcBlk->IsLIR())
17604 fgInsertStmtAtEnd(newBlk, fgNewStmtFromTree(tree));
17608 LIR::AsRange(newBlk).InsertAtEnd(LIR::SeqTree(this, tree));
17611 return add->acdDstBlk;
17614 /*****************************************************************************
17615 * Finds the block to jump to, to throw a given kind of exception
17616 * We maintain a cache of one AddCodeDsc for each kind, to make searching fast.
17617 * Note : Each block uses the same (maybe shared) block as the jump target for
17618 * a given type of exception
17621 Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData)
17623 if (!(fgExcptnTargetCache[kind] && // Try the cached value first
17624 fgExcptnTargetCache[kind]->acdData == refData))
17626 // Too bad, have to search for the jump target for the exception
17628 AddCodeDsc* add = nullptr;
17630 for (add = fgAddCodeList; add != nullptr; add = add->acdNext)
17632 if (add->acdData == refData && add->acdKind == kind)
17638 fgExcptnTargetCache[kind] = add; // Cache it
17641 return fgExcptnTargetCache[kind];
17644 /*****************************************************************************
17646 * The given basic block contains an array range check; return the label this
17647 * range check is to jump to upon failure.
17650 BasicBlock* Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind)
17655 printf("*** Computing fgRngChkTarget for block BB%02u to stkDepth %d\n", block->bbNum, stkDepth);
17656 if (!block->IsLIR())
17658 gtDispTree(compCurStmt);
17663 /* We attach the target label to the containing try block (if any) */
17664 noway_assert(!compIsForInlining());
17665 return fgAddCodeRef(block, bbThrowIndex(block), kind, stkDepth);
17668 // Sequences the tree.
17669 // prevTree is what gtPrev of the first node in execution order gets set to.
17670 // Returns the first node (execution order) in the sequenced tree.
17671 GenTree* Compiler::fgSetTreeSeq(GenTree* tree, GenTree* prevTree, bool isLIR)
17675 if (prevTree == nullptr)
17679 fgTreeSeqLst = prevTree;
17681 fgTreeSeqBeg = nullptr;
17682 fgSetTreeSeqHelper(tree, isLIR);
17684 GenTree* result = prevTree->gtNext;
17685 if (prevTree == &list)
17687 list.gtNext->gtPrev = nullptr;
17693 /*****************************************************************************
17695 * Assigns sequence numbers to the given tree and its sub-operands, and
17696 * threads all the nodes together via the 'gtNext' and 'gtPrev' fields.
17697 * Uses 'global' - fgTreeSeqLst
17700 void Compiler::fgSetTreeSeqHelper(GenTreePtr tree, bool isLIR)
17705 noway_assert(tree);
17706 assert(!IsUninitialized(tree));
17707 noway_assert(tree->gtOper != GT_STMT);
17709 /* Figure out what kind of a node we have */
17711 oper = tree->OperGet();
17712 kind = tree->OperKind();
17714 /* Is this a leaf/constant node? */
17716 if (kind & (GTK_CONST | GTK_LEAF))
17718 fgSetTreeSeqFinish(tree, isLIR);
17722 /* Is it a 'simple' unary/binary operator? */
17724 if (kind & GTK_SMPOP)
17726 GenTreePtr op1 = tree->gtOp.gtOp1;
17727 GenTreePtr op2 = tree->gtGetOp2();
17729 // Special handling for GT_LIST
17730 if (tree->OperGet() == GT_LIST)
17733 if (tree->gtOp.gtOp2 != nullptr && tree->gtOp.gtOp2->gtOper != GT_LIST)
17735 // This is a special kind of GT_LIST that only occurs under initBlk and copyBlk.
17736 // It is used as a pair, where op1 is the dst and op2 is the src (value or location)
17737 // The use must appear before the def because of the case where a local is cpblk'ed to itself.
17738 // If it were otherwise, upstream stores to the local would appear to be dead.
17739 assert(tree->gtOp.gtOp1->gtOper != GT_LIST);
17740 fgSetTreeSeqHelper(tree->gtOp.gtOp2, isLIR);
17741 fgSetTreeSeqHelper(tree->gtOp.gtOp1, isLIR);
17742 fgSetTreeSeqFinish(tree, isLIR);
17746 // First, handle the list items, which will be linked in forward order.
17747 // As we go, we will link the GT_LIST nodes in reverse order - we will number
17748 // them and update fgTreeSeqList in a subsequent traversal.
17749 GenTreePtr nextList = tree;
17750 GenTreePtr list = nullptr;
17751 while (nextList != nullptr && nextList->OperGet() == GT_LIST)
17754 GenTreePtr listItem = list->gtOp.gtOp1;
17755 fgSetTreeSeqHelper(listItem, isLIR);
17756 nextList = list->gtOp.gtOp2;
17757 if (nextList != nullptr)
17759 nextList->gtNext = list;
17761 list->gtPrev = nextList;
17763 // Next, handle the GT_LIST nodes.
17764 // Note that fgSetTreeSeqFinish() sets the gtNext to null, so we need to capture the nextList
17765 // before we call that method.
17769 assert(list != nullptr);
17771 nextList = list->gtNext;
17772 fgSetTreeSeqFinish(list, isLIR);
17773 } while (list != tree);
17777 /* Special handling for AddrMode */
17778 if (tree->OperIsAddrMode())
17780 bool reverse = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
17783 assert(op1 != nullptr && op2 != nullptr);
17784 fgSetTreeSeqHelper(op2, isLIR);
17786 if (op1 != nullptr)
17788 fgSetTreeSeqHelper(op1, isLIR);
17790 if (!reverse && op2 != nullptr)
17792 fgSetTreeSeqHelper(op2, isLIR);
17795 fgSetTreeSeqFinish(tree, isLIR);
17799 /* Check for a nilary operator */
17801 if (op1 == nullptr)
17803 noway_assert(op2 == nullptr);
17804 fgSetTreeSeqFinish(tree, isLIR);
17808 /* Is this a unary operator?
17809 * Although UNARY GT_IND has a special structure */
17811 if (oper == GT_IND)
17813 /* Visit the indirection first - op2 may point to the
17814 * jump Label for array-index-out-of-range */
17816 fgSetTreeSeqHelper(op1, isLIR);
17817 fgSetTreeSeqFinish(tree, isLIR);
17821 /* Now this is REALLY a unary operator */
17825 /* Visit the (only) operand and we're done */
17827 fgSetTreeSeqHelper(op1, isLIR);
17828 fgSetTreeSeqFinish(tree, isLIR);
17833 For "real" ?: operators, we make sure the order is
17843 if (oper == GT_QMARK)
17845 noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
17847 fgSetTreeSeqHelper(op1, isLIR);
17848 // Here, for the colon, the sequence does not actually represent "order of evaluation":
17849 // one or the other of the branches is executed, not both. Still, to make debugging checks
17850 // work, we want the sequence to match the order in which we'll generate code, which means
17851 // "else" clause then "then" clause.
17852 fgSetTreeSeqHelper(op2->AsColon()->ElseNode(), isLIR);
17853 fgSetTreeSeqHelper(op2, isLIR);
17854 fgSetTreeSeqHelper(op2->AsColon()->ThenNode(), isLIR);
17856 fgSetTreeSeqFinish(tree, isLIR);
17860 if (oper == GT_COLON)
17862 fgSetTreeSeqFinish(tree, isLIR);
17866 /* This is a binary operator */
17868 if (tree->gtFlags & GTF_REVERSE_OPS)
17870 fgSetTreeSeqHelper(op2, isLIR);
17871 fgSetTreeSeqHelper(op1, isLIR);
17875 fgSetTreeSeqHelper(op1, isLIR);
17876 fgSetTreeSeqHelper(op2, isLIR);
17879 fgSetTreeSeqFinish(tree, isLIR);
17883 /* See what kind of a special operator we have here */
17888 noway_assert(tree->gtField.gtFldObj == nullptr);
17893 /* We'll evaluate the 'this' argument value first */
17894 if (tree->gtCall.gtCallObjp)
17896 fgSetTreeSeqHelper(tree->gtCall.gtCallObjp, isLIR);
17899 /* We'll evaluate the arguments next, left to right
17900 * NOTE: setListOrder needs cleanup - eliminate the #ifdef afterwards */
17902 if (tree->gtCall.gtCallArgs)
17904 fgSetTreeSeqHelper(tree->gtCall.gtCallArgs, isLIR);
17907 /* Evaluate the temp register arguments list
17908 * This is a "hidden" list and its only purpose is to
17909 * extend the life of temps until we make the call */
17911 if (tree->gtCall.gtCallLateArgs)
17913 fgSetTreeSeqHelper(tree->gtCall.gtCallLateArgs, isLIR);
17916 if ((tree->gtCall.gtCallType == CT_INDIRECT) && (tree->gtCall.gtCallCookie != nullptr))
17918 fgSetTreeSeqHelper(tree->gtCall.gtCallCookie, isLIR);
17921 if (tree->gtCall.gtCallType == CT_INDIRECT)
17923 fgSetTreeSeqHelper(tree->gtCall.gtCallAddr, isLIR);
17926 if (tree->gtCall.gtControlExpr)
17928 fgSetTreeSeqHelper(tree->gtCall.gtControlExpr, isLIR);
17935 fgSetTreeSeqHelper(tree->gtArrElem.gtArrObj, isLIR);
17938 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
17940 fgSetTreeSeqHelper(tree->gtArrElem.gtArrInds[dim], isLIR);
17945 case GT_ARR_OFFSET:
17946 fgSetTreeSeqHelper(tree->gtArrOffs.gtOffset, isLIR);
17947 fgSetTreeSeqHelper(tree->gtArrOffs.gtIndex, isLIR);
17948 fgSetTreeSeqHelper(tree->gtArrOffs.gtArrObj, isLIR);
17952 // Evaluate the trees left to right
17953 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpLocation, isLIR);
17954 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpValue, isLIR);
17955 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpComparand, isLIR);
17958 case GT_ARR_BOUNDS_CHECK:
17959 #ifdef FEATURE_SIMD
17961 #endif // FEATURE_SIMD
17962 // Evaluate the trees left to right
17963 fgSetTreeSeqHelper(tree->gtBoundsChk.gtArrLen, isLIR);
17964 fgSetTreeSeqHelper(tree->gtBoundsChk.gtIndex, isLIR);
17970 noway_assert(!"unexpected operator");
17975 fgSetTreeSeqFinish(tree, isLIR);
17978 void Compiler::fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR)
17980 // If we are sequencing a node that does not appear in LIR,
17981 // do not add it to the list.
17982 if (isLIR && (((tree->OperGet() == GT_LIST) && !tree->AsArgList()->IsAggregate()) || tree->OperGet() == GT_ARGPLACE))
17987 /* Append to the node list */
17991 tree->gtSeqNum = fgTreeSeqNum;
17995 printf("SetTreeOrder: ");
17996 printTreeID(fgTreeSeqLst);
17997 printf(" followed by ");
18003 fgTreeSeqLst->gtNext = tree;
18004 tree->gtNext = nullptr;
18005 tree->gtPrev = fgTreeSeqLst;
18006 fgTreeSeqLst = tree;
18008 /* Remember the very first node */
18012 fgTreeSeqBeg = tree;
18013 assert(tree->gtSeqNum == 1);
18017 /*****************************************************************************
18019 * Figure out the order in which operators should be evaluated, along with
18020 * other information (such as the register sets trashed by each subtree).
18021 * Also finds blocks that need GC polls and inserts them as needed.
18024 void Compiler::fgSetBlockOrder()
18029 printf("*************** In fgSetBlockOrder()\n");
18034 BasicBlock::s_nMaxTrees = 0;
18037 /* Walk the basic blocks to assign sequence numbers */
18039 /* If we don't compute the doms, then we never mark blocks as loops. */
18040 if (fgDomsComputed)
18042 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18044 /* If this block is a loop header, mark it appropriately */
18046 if (block->isLoopHead())
18048 fgMarkLoopHead(block);
18052 // only enable fully interruptible code for if we're hijacking.
18053 else if (GCPOLL_NONE == opts.compGCPollType)
18055 /* If we don't have the dominators, use an abbreviated test for fully interruptible. If there are
18056 * any back edges, check the source and destination blocks to see if they're GC Safe. If not, then
18057 * go fully interruptible. */
18059 /* XXX Mon 1/21/2008
18060 * Wouldn't it be nice to have a block iterator that can do this loop?
18062 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18064 // true if the edge is forward, or if it is a back edge and either the source and dest are GC safe.
18065 #define EDGE_IS_GC_SAFE(src, dst) \
18066 (((src)->bbNum < (dst)->bbNum) || (((src)->bbFlags | (dst)->bbFlags) & BBF_GC_SAFE_POINT))
18068 bool partiallyInterruptible = true;
18069 switch (block->bbJumpKind)
18073 partiallyInterruptible = EDGE_IS_GC_SAFE(block, block->bbJumpDest);
18079 jumpCnt = block->bbJumpSwt->bbsCount;
18080 BasicBlock** jumpPtr;
18081 jumpPtr = block->bbJumpSwt->bbsDstTab;
18085 partiallyInterruptible &= EDGE_IS_GC_SAFE(block, *jumpPtr);
18086 } while (++jumpPtr, --jumpCnt);
18094 if (!partiallyInterruptible)
18097 // The GC encoding for fully interruptible methods does not
18098 // support more than 1023 pushed arguments, so we can't set
18099 // genInterruptible here when we have 1024 or more pushed args
18101 if (compCanEncodePtrArgCntMax())
18103 genInterruptible = true;
18107 #undef EDGE_IS_GC_SAFE
18111 if (!fgGCPollsCreated)
18116 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18119 #if FEATURE_FASTTAILCALL
18120 #ifndef JIT32_GCENCODER
18121 if (block->endsWithTailCallOrJmp(this, true) && !(block->bbFlags & BBF_GC_SAFE_POINT) &&
18122 optReachWithoutCall(fgFirstBB, block))
18124 // We have a tail call that is reachable without making any other
18125 // 'normal' call that would have counted as a GC Poll. If we were
18126 // using polls, all return blocks meeting this criteria would have
18127 // already added polls and then marked as being GC safe
18128 // (BBF_GC_SAFE_POINT). Thus we can only reach here when *NOT*
18129 // using GC polls, but instead relying on the JIT to generate
18130 // fully-interruptible code.
18131 noway_assert(GCPOLL_NONE == opts.compGCPollType);
18133 // This tail call might combine with other tail calls to form a
18134 // loop. Thus we need to either add a poll, or make the method
18135 // fully interruptible. I chose the later because that's what
18137 genInterruptible = true;
18139 #endif // !JIT32_GCENCODER
18140 #endif // FEATURE_FASTTAILCALL
18142 fgSetBlockOrder(block);
18145 /* Remember that now the tree list is threaded */
18147 fgStmtListThreaded = true;
18152 printf("The biggest BB has %4u tree nodes\n", BasicBlock::s_nMaxTrees);
18154 fgDebugCheckLinks();
18158 /*****************************************************************************/
18160 void Compiler::fgSetStmtSeq(GenTreePtr tree)
18162 GenTree list; // helper node that we use to start the StmtList
18163 // It's located in front of the first node in the list
18165 noway_assert(tree->gtOper == GT_STMT);
18167 /* Assign numbers and next/prev links for this tree */
18170 fgTreeSeqLst = &list;
18171 fgTreeSeqBeg = nullptr;
18173 fgSetTreeSeqHelper(tree->gtStmt.gtStmtExpr, false);
18175 /* Record the address of the first node */
18177 tree->gtStmt.gtStmtList = fgTreeSeqBeg;
18181 if (list.gtNext->gtPrev != &list)
18184 printTreeID(&list);
18185 printf(" != list.next->prev ");
18186 printTreeID(list.gtNext->gtPrev);
18193 for (temp = list.gtNext, last = &list; temp; last = temp, temp = temp->gtNext)
18195 if (temp->gtPrev != last)
18198 printf("->gtPrev = ");
18199 printTreeID(temp->gtPrev);
18200 printf(", but last = ");
18207 gtDispTree(tree->gtStmt.gtStmtExpr);
18210 for (GenTreePtr bad = &list; bad; bad = bad->gtNext)
18212 printf(" entry at ");
18215 printTreeID(bad->gtPrev);
18217 printTreeID(bad->gtNext);
18222 noway_assert(!"Badly linked tree");
18228 /* Fix the first node's 'prev' link */
18230 noway_assert(list.gtNext->gtPrev == &list);
18231 list.gtNext->gtPrev = nullptr;
18234 /* Keep track of the highest # of tree nodes */
18236 if (BasicBlock::s_nMaxTrees < fgTreeSeqNum)
18238 BasicBlock::s_nMaxTrees = fgTreeSeqNum;
18243 /*****************************************************************************/
18245 void Compiler::fgSetBlockOrder(BasicBlock* block)
18249 tree = block->bbTreeList;
18257 fgSetStmtSeq(tree);
18259 /* Are there any more trees in this basic block? */
18261 if (tree->gtNext == nullptr)
18263 /* last statement in the tree list */
18264 noway_assert(block->lastStmt() == tree);
18269 if (block->bbTreeList == tree)
18271 /* first statement in the list */
18272 noway_assert(tree->gtPrev->gtNext == nullptr);
18276 noway_assert(tree->gtPrev->gtNext == tree);
18279 noway_assert(tree->gtNext->gtPrev == tree);
18282 tree = tree->gtNext;
18286 #ifdef LEGACY_BACKEND
18287 /*****************************************************************************
18289 * For GT_INITBLK and GT_COPYBLK, the tree looks like this :
18293 * GT_LIST [size/clsHnd]
18298 * ie. they are ternary operators. However we use nested binary trees so that
18299 * GTF_REVERSE_OPS will be set just like for other binary operators. As the
18300 * operands need to end up in specific registers to issue the "rep stos" or
18301 * the "rep movs" instruction, if we don't allow the order of evaluation of
18302 * the 3 operands to be mixed, we may generate really bad code.
18304 * eg. For "rep stos", [val] has to be in EAX. Then if [size]
18305 * has a division, we will have to spill [val] from EAX. It will be better to
18306 * evaluate [size] and the evaluate [val] into EAX.
18308 * This function stores the operands in the order to be evaluated
18309 * into opsPtr[]. The regsPtr[] contains reg0,reg1,reg2 in the correspondingly
18313 void Compiler::fgOrderBlockOps(GenTreePtr tree,
18317 GenTreePtr* opsPtr, // OUT
18318 regMaskTP* regsPtr) // OUT
18320 assert(tree->OperIsBlkOp());
18322 assert(tree->gtOp.gtOp1 && tree->gtOp.gtOp1->IsList());
18323 assert(tree->gtOp.gtOp1->gtOp.gtOp1 && tree->gtOp.gtOp1->gtOp.gtOp2);
18324 assert(tree->gtOp.gtOp2);
18326 GenTreePtr ops[3] = {
18327 tree->gtOp.gtOp1->gtOp.gtOp1, // Dest address
18328 tree->gtOp.gtOp1->gtOp.gtOp2, // Val / Src address
18329 tree->gtOp.gtOp2 // Size of block
18332 regMaskTP regs[3] = {reg0, reg1, reg2};
18334 static int blockOpsOrder[4][3] =
18335 // tree->gtFlags | tree->gtOp.gtOp1->gtFlags
18337 // ---------------------+----------------------------
18338 {0, 1, 2}, // - | -
18339 {2, 0, 1}, // GTF_REVERSE_OPS | -
18340 {1, 0, 2}, // - | GTF_REVERSE_OPS
18341 {2, 1, 0} // GTF_REVERSE_OPS | GTF_REVERSE_OPS
18345 ((tree->gtFlags & GTF_REVERSE_OPS) != 0) * 1 + ((tree->gtOp.gtOp1->gtFlags & GTF_REVERSE_OPS) != 0) * 2;
18347 assert(orderNum < 4);
18349 int* order = blockOpsOrder[orderNum];
18351 PREFIX_ASSUME(order != NULL);
18353 // Fill in the OUT arrays according to the order we have selected
18355 opsPtr[0] = ops[order[0]];
18356 opsPtr[1] = ops[order[1]];
18357 opsPtr[2] = ops[order[2]];
18359 regsPtr[0] = regs[order[0]];
18360 regsPtr[1] = regs[order[1]];
18361 regsPtr[2] = regs[order[2]];
18363 #endif // LEGACY_BACKEND
18365 //------------------------------------------------------------------------
18366 // fgGetFirstNode: Get the first node in the tree, in execution order
18369 // tree - The top node of the tree of interest
18372 // The first node in execution order, that belongs to tree.
18375 // 'tree' must either be a leaf, or all of its constituent nodes must be contiguous
18376 // in execution order.
18377 // TODO-Cleanup: Add a debug-only method that verifies this.
18380 GenTreePtr Compiler::fgGetFirstNode(GenTreePtr tree)
18382 GenTreePtr child = tree;
18383 while (child->NumChildren() > 0)
18385 if (child->OperIsBinary() && child->IsReverseOp())
18387 child = child->GetChild(1);
18391 child = child->GetChild(0);
18397 // Examine the bbTreeList and return the estimated code size for this block
18398 unsigned Compiler::fgGetCodeEstimate(BasicBlock* block)
18400 unsigned costSz = 0; // estimate of blocks code size cost
18402 switch (block->bbJumpKind)
18408 case BBJ_EHCATCHRET:
18413 case BBJ_CALLFINALLY:
18420 costSz = 1; // We place a int3 after the code for a throw block
18422 case BBJ_EHFINALLYRET:
18423 case BBJ_EHFILTERRET:
18426 case BBJ_RETURN: // return from method
18430 noway_assert(!"Bad bbJumpKind");
18434 GenTreePtr tree = block->FirstNonPhiDef();
18439 noway_assert(tree->gtOper == GT_STMT);
18441 if (tree->gtCostSz < MAX_COST)
18443 costSz += tree->gtCostSz;
18447 // We could walk the tree to find out the real gtCostSz,
18448 // but just using MAX_COST for this trees code size works OK
18449 costSz += tree->gtCostSz;
18452 tree = tree->gtNext;
18459 #if DUMP_FLOWGRAPHS
18461 struct escapeMapping_t
18467 // clang-format off
18468 static escapeMapping_t s_EscapeFileMapping[] =
18481 static escapeMapping_t s_EscapeMapping[] =
18491 const char* Compiler::fgProcessEscapes(const char* nameIn, escapeMapping_t* map)
18493 const char* nameOut = nameIn;
18494 unsigned lengthOut;
18497 bool subsitutionRequired;
18501 subsitutionRequired = false;
18503 while (*pChar != '\0')
18507 while (map[index].ch != 0)
18509 if (*pChar == map[index].ch)
18518 subsitutionRequired = true;
18519 lengthOut += (unsigned)strlen(map[index].sub);
18528 if (subsitutionRequired)
18530 char* newName = (char*) compGetMemA(lengthOut, CMK_DebugOnly);
18534 while (*pChar != '\0')
18538 while (map[index].ch != 0)
18540 if (*pChar == map[index].ch)
18549 strcpy(pDest, map[index].sub);
18550 pDest += strlen(map[index].sub);
18559 nameOut = (const char*) newName;
18565 static void fprintfDouble(FILE* fgxFile, double value)
18567 assert(value >= 0.0);
18569 if ((value >= 0.010) || (value == 0.0))
18571 fprintf(fgxFile, "\"%7.3f\"", value);
18573 else if (value >= 0.00010)
18575 fprintf(fgxFile, "\"%7.5f\"", value);
18579 fprintf(fgxFile, "\"%7E\"", value);
18583 //------------------------------------------------------------------------
18584 // fgOpenFlowGraphFile: Open a file to dump either the xml or dot format flow graph
18587 // wbDontClose - A boolean out argument that indicates whether the caller should close the file
18588 // phase - A phase identifier to indicate which phase is associated with the dump
18589 // type - A (wide) string indicating the type of dump, "dot" or "xml"
18592 // Opens a file to which a flowgraph can be dumped, whose name is based on the current
18595 FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type)
18598 LPCWSTR pattern = nullptr;
18599 LPCWSTR filename = nullptr;
18600 LPCWSTR pathname = nullptr;
18601 const char* escapedString;
18602 bool createDuplicateFgxFiles = true;
18605 if (opts.eeFlags & CORJIT_FLG_PREJIT)
18607 pattern = JitConfig.NgenDumpFg();
18608 filename = JitConfig.NgenDumpFgFile();
18609 pathname = JitConfig.NgenDumpFgDir();
18613 pattern = JitConfig.JitDumpFg();
18614 filename = JitConfig.JitDumpFgFile();
18615 pathname = JitConfig.JitDumpFgDir();
18619 if (fgBBcount <= 1) {
18623 if (pattern == nullptr) {
18627 if (wcslen(pattern) == 0) {
18631 LPCWSTR phasePattern = JitConfig.JitDumpFgPhase();
18632 LPCWSTR phaseName = PhaseShortNames[phase];
18633 if (phasePattern == nullptr)
18635 if (phase != PHASE_DETERMINE_FIRST_COLD_BLOCK)
18640 else if (*phasePattern != W('*'))
18642 if (wcsstr(phasePattern, phaseName) == nullptr)
18648 if (*pattern != W('*'))
18650 bool hasColon = (wcschr(pattern, W(':')) != nullptr);
18654 const char* className = info.compClassName;
18655 if (*pattern == W('*'))
18661 while ((*pattern != W(':')) && (*pattern != W('*')))
18663 if (*pattern != *className) {
18670 if (*pattern == W('*'))
18676 if (*className != 0) {
18681 if (*pattern != W(':')) {
18688 const char* methodName = info.compMethodName;
18689 if (*pattern == W('*'))
18695 while ((*pattern != 0) && (*pattern != W('*')))
18697 if (*pattern != *methodName) {
18704 if (*pattern == W('*'))
18710 if (*methodName != 0) {
18715 if (*pattern != 0) {
18720 if (filename == nullptr)
18722 filename = W("default");
18725 if (wcscmp(filename, W("profiled")) == 0)
18727 if ((fgFirstBB->bbFlags & BBF_PROF_WEIGHT) != 0)
18729 createDuplicateFgxFiles = true;
18730 goto ONE_FILE_PER_METHOD;
18737 if (wcscmp(filename, W("hot")) == 0)
18739 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
18742 createDuplicateFgxFiles = true;
18743 goto ONE_FILE_PER_METHOD;
18750 else if (wcscmp(filename, W("cold")) == 0)
18752 if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
18754 createDuplicateFgxFiles = true;
18755 goto ONE_FILE_PER_METHOD;
18762 else if (wcscmp(filename, W("jit")) == 0)
18764 if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
18766 createDuplicateFgxFiles = true;
18767 goto ONE_FILE_PER_METHOD;
18774 else if (wcscmp(filename, W("all")) == 0)
18776 createDuplicateFgxFiles = true;
18778 ONE_FILE_PER_METHOD:;
18780 escapedString = fgProcessEscapes(info.compFullName, s_EscapeFileMapping);
18781 size_t wCharCount = strlen(escapedString) + wcslen(phaseName) + 1 + strlen("~999") + wcslen(type) + 1;
18782 if (pathname != nullptr)
18784 wCharCount += wcslen(pathname) + 1;
18786 filename = (LPCWSTR) alloca(wCharCount * sizeof(WCHAR));
18787 if (pathname != nullptr)
18789 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S-%s.%s"), pathname, escapedString, phaseName, type);
18793 swprintf_s((LPWSTR)filename, wCharCount, W("%S.%s"), escapedString, type);
18795 fgxFile = _wfopen(filename, W("r")); // Check if this file already exists
18796 if (fgxFile != nullptr)
18798 // For Generic methods we will have both hot and cold versions
18799 if (createDuplicateFgxFiles == false)
18804 // Yes, this filename already exists, so create a different one by appending ~2, ~3, etc...
18805 for (int i = 2; i < 1000; i++)
18808 if (pathname != nullptr)
18810 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S~%d.%s"), pathname, escapedString, i, type);
18814 swprintf_s((LPWSTR)filename, wCharCount, W("%S~%d.%s"), escapedString, i, type);
18816 fgxFile = _wfopen(filename, W("r")); // Check if this file exists
18817 if (fgxFile == nullptr) {
18821 // If we have already created 1000 files with this name then just fail
18822 if (fgxFile != nullptr)
18828 fgxFile = _wfopen(filename, W("a+"));
18829 *wbDontClose = false;
18831 else if (wcscmp(filename, W("stdout")) == 0)
18833 fgxFile = jitstdout;
18834 *wbDontClose = true;
18836 else if (wcscmp(filename, W("stderr")) == 0)
18839 *wbDontClose = true;
18843 LPCWSTR origFilename = filename;
18844 size_t wCharCount = wcslen(origFilename) + wcslen(type) + 2;
18845 if (pathname != nullptr)
18847 wCharCount += wcslen(pathname) + 1;
18849 filename = (LPCWSTR) alloca(wCharCount * sizeof(WCHAR));
18850 if (pathname != nullptr)
18852 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%s.%s"), pathname, origFilename, type);
18856 swprintf_s((LPWSTR)filename, wCharCount, W("%s.%s"), origFilename, type);
18858 fgxFile = _wfopen(filename, W("a+"));
18859 *wbDontClose = false;
18865 //------------------------------------------------------------------------
18866 // fgDumpFlowGraph: Dump the xml or dot format flow graph, if enabled for this phase.
18869 // phase - A phase identifier to indicate which phase is associated with the dump,
18870 // i.e. which phase has just completed.
18873 // True iff a flowgraph has been dumped.
18876 // The xml dumps are the historical mechanism for dumping the flowgraph.
18877 // The dot format can be viewed by:
18878 // - Graphviz (http://www.graphviz.org/)
18879 // - The command "C:\Program Files (x86)\Graphviz2.38\bin\dot.exe" -Tsvg -oFoo.svg -Kdot Foo.dot
18880 // will produce a Foo.svg file that can be opened with any svg-capable browser (e.g. IE).
18881 // - http://rise4fun.com/Agl/
18882 // - Cut and paste the graph from your .dot file, replacing the digraph on the page, and then click the play
18884 // - It will show a rotating '/' and then render the graph in the browser.
18885 // MSAGL has also been open-sourced to https://github.com/Microsoft/automatic-graph-layout.git.
18887 // Here are the config values that control it:
18888 // COMPlus_JitDumpFg A string (ala the COMPlus_JitDump string) indicating what methods to dump flowgraphs
18890 // COMPlus_JitDumpFgDir A path to a directory into which the flowgraphs will be dumped.
18891 // COMPlus_JitDumpFgFile The filename to use. The default is "default.[xml|dot]".
18892 // Note that the new graphs will be appended to this file if it already exists.
18893 // COMPlus_JitDumpFgPhase Phase(s) after which to dump the flowgraph.
18894 // Set to the short name of a phase to see the flowgraph after that phase.
18895 // Leave unset to dump after COLD-BLK (determine first cold block) or set to * for all
18897 // COMPlus_JitDumpFgDot Set to non-zero to emit Dot instead of Xml Flowgraph dump. (Default is xml format.)
18899 bool Compiler::fgDumpFlowGraph(Phases phase)
18901 bool result = false;
18902 bool dontClose = false;
18903 bool createDotFile = false;
18904 if (JitConfig.JitDumpFgDot())
18906 createDotFile = true;
18909 FILE* fgxFile = fgOpenFlowGraphFile(&dontClose, phase, createDotFile ? W("dot") : W("fgx"));
18911 if (fgxFile == nullptr)
18915 bool validWeights = fgHaveValidEdgeWeights;
18916 unsigned calledCount = max(fgCalledWeight, BB_UNITY_WEIGHT) / BB_UNITY_WEIGHT;
18917 double weightDivisor = (double) (calledCount * BB_UNITY_WEIGHT);
18918 const char* escapedString;
18919 const char* regionString = "NONE";
18921 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
18923 regionString="HOT";
18925 else if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
18927 regionString="COLD";
18929 else if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
18931 regionString="JIT";
18936 fprintf(fgxFile, "digraph %s\n{\n", info.compMethodName);
18937 fprintf(fgxFile, "/* Method %d, after phase %s */", Compiler::jitTotalMethodCompiled, PhaseNames[phase]);
18941 fprintf(fgxFile, "<method");
18943 escapedString = fgProcessEscapes(info.compFullName, s_EscapeMapping);
18944 fprintf(fgxFile, "\n name=\"%s\"", escapedString);
18946 escapedString = fgProcessEscapes(info.compClassName, s_EscapeMapping);
18947 fprintf(fgxFile, "\n className=\"%s\"", escapedString);
18949 escapedString = fgProcessEscapes(info.compMethodName, s_EscapeMapping);
18950 fprintf(fgxFile, "\n methodName=\"%s\"", escapedString);
18951 fprintf(fgxFile, "\n ngenRegion=\"%s\"", regionString);
18953 fprintf(fgxFile, "\n bytesOfIL=\"%d\"", info.compILCodeSize);
18954 fprintf(fgxFile, "\n localVarCount=\"%d\"", lvaCount);
18956 if (fgHaveProfileData())
18958 fprintf(fgxFile, "\n calledCount=\"%d\"", calledCount);
18959 fprintf(fgxFile, "\n profileData=\"true\"");
18961 if (compHndBBtabCount > 0)
18963 fprintf(fgxFile, "\n hasEHRegions=\"true\"");
18967 fprintf(fgxFile, "\n hasLoops=\"true\"");
18971 fprintf(fgxFile, "\n validEdgeWeights=\"true\"");
18972 if (!fgSlopUsedInEdgeWeights && !fgRangeUsedInEdgeWeights)
18974 fprintf(fgxFile, "\n exactEdgeWeights=\"true\"");
18977 if (fgFirstColdBlock != nullptr)
18979 fprintf(fgxFile, "\n firstColdBlock=\"%d\"", fgFirstColdBlock->bbNum);
18982 fprintf(fgxFile, ">");
18984 fprintf(fgxFile, "\n <blocks");
18985 fprintf(fgxFile, "\n blockCount=\"%d\"", fgBBcount);
18986 fprintf(fgxFile, ">");
18989 static const char* kindImage[] = { "EHFINALLYRET", "EHFILTERRET", "EHCATCHRET",
18990 "THROW", "RETURN", "NONE", "ALWAYS", "LEAVE",
18991 "CALLFINALLY", "COND", "SWITCH" };
18994 unsigned blockOrdinal;
18995 for (block = fgFirstBB , blockOrdinal = 1;
18997 block = block->bbNext, blockOrdinal++)
19001 // Add constraint edges to try to keep nodes ordered.
19002 // It seems to work best if these edges are all created first.
19003 switch(block->bbJumpKind)
19007 assert(block->bbNext != nullptr);
19008 fprintf(fgxFile, " BB%02u -> BB%02u\n", block->bbNum, block->bbNext->bbNum);
19011 // These may or may not have an edge to the next block.
19012 // Add a transparent edge to keep nodes ordered.
19013 if (block->bbNext != nullptr)
19015 fprintf(fgxFile, " BB%02u -> BB%02u [arrowtail=none,color=transparent]\n", block->bbNum, block->bbNext->bbNum);
19021 fprintf(fgxFile,"\n <block");
19022 fprintf(fgxFile,"\n id=\"%d\"", block->bbNum);
19023 fprintf(fgxFile,"\n ordinal=\"%d\"", blockOrdinal);
19024 fprintf(fgxFile,"\n jumpKind=\"%s\"", kindImage[block->bbJumpKind]);
19025 if (block->hasTryIndex())
19027 fprintf(fgxFile,"\n inTry=\"%s\"", "true");
19029 if (block->hasHndIndex())
19031 fprintf(fgxFile,"\n inHandler=\"%s\"", "true");
19033 if (((fgFirstBB->bbFlags & BBF_PROF_WEIGHT) != 0) &&
19034 ((block->bbFlags & BBF_COLD) == 0) )
19036 fprintf(fgxFile,"\n hot=\"true\"");
19038 if (block->bbFlags & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY))
19040 fprintf(fgxFile,"\n callsNew=\"true\"");
19042 if (block->bbFlags & BBF_LOOP_HEAD)
19044 fprintf(fgxFile,"\n loopHead=\"true\"");
19046 fprintf(fgxFile,"\n weight=");
19047 fprintfDouble(fgxFile, ((double) block->bbWeight) / weightDivisor);
19048 fprintf(fgxFile,"\n codeEstimate=\"%d\"", fgGetCodeEstimate(block));
19049 fprintf(fgxFile,"\n startOffset=\"%d\"", block->bbCodeOffs);
19050 fprintf(fgxFile,"\n endOffset=\"%d\"", block->bbCodeOffsEnd);
19051 fprintf(fgxFile, ">");
19052 fprintf(fgxFile,"\n </block>");
19056 if (!createDotFile)
19058 fprintf(fgxFile, "\n </blocks>");
19060 fprintf(fgxFile, "\n <edges");
19061 fprintf(fgxFile, "\n edgeCount=\"%d\"", fgEdgeCount);
19062 fprintf(fgxFile, ">");
19065 unsigned edgeNum = 1;
19066 BasicBlock* bTarget;
19067 for (bTarget = fgFirstBB; bTarget != nullptr; bTarget = bTarget->bbNext)
19069 double targetWeightDivisor;
19070 if (bTarget->bbWeight == BB_ZERO_WEIGHT)
19072 targetWeightDivisor = 1.0;
19076 targetWeightDivisor = (double) bTarget->bbWeight;
19080 for (edge = bTarget->bbPreds; edge != nullptr; edge = edge->flNext, edgeNum++)
19082 BasicBlock* bSource = edge->flBlock;
19083 double sourceWeightDivisor;
19084 if (bSource->bbWeight == BB_ZERO_WEIGHT)
19086 sourceWeightDivisor = 1.0;
19090 sourceWeightDivisor = (double) bSource->bbWeight;
19094 // Don't duplicate the edges we added above.
19095 if ((bSource->bbNum == (bTarget->bbNum - 1)) &&
19096 ((bSource->bbJumpKind == BBJ_NONE) || (bSource->bbJumpKind == BBJ_COND)))
19100 fprintf(fgxFile, " BB%02u -> BB%02u", bSource->bbNum, bTarget->bbNum);
19101 if ((bSource->bbNum > bTarget->bbNum))
19103 fprintf(fgxFile, "[arrowhead=normal,arrowtail=none,color=green]\n");
19107 fprintf(fgxFile, "\n");
19112 fprintf(fgxFile,"\n <edge");
19113 fprintf(fgxFile,"\n id=\"%d\"", edgeNum);
19114 fprintf(fgxFile,"\n source=\"%d\"", bSource->bbNum);
19115 fprintf(fgxFile,"\n target=\"%d\"", bTarget->bbNum);
19116 if (bSource->bbJumpKind == BBJ_SWITCH)
19118 if (edge->flDupCount >= 2)
19120 fprintf(fgxFile,"\n switchCases=\"%d\"", edge->flDupCount);
19122 if (bSource->bbJumpSwt->getDefault() == bTarget)
19124 fprintf(fgxFile,"\n switchDefault=\"true\"");
19129 unsigned edgeWeight = (edge->flEdgeWeightMin + edge->flEdgeWeightMax) / 2;
19130 fprintf(fgxFile,"\n weight=");
19131 fprintfDouble(fgxFile, ((double) edgeWeight) / weightDivisor);
19133 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
19135 fprintf(fgxFile,"\n minWeight=");
19136 fprintfDouble(fgxFile, ((double) edge->flEdgeWeightMin) / weightDivisor);
19137 fprintf(fgxFile,"\n maxWeight=");
19138 fprintfDouble(fgxFile, ((double) edge->flEdgeWeightMax) / weightDivisor);
19141 if (edgeWeight > 0)
19143 if (edgeWeight < bSource->bbWeight)
19145 fprintf(fgxFile,"\n out=");
19146 fprintfDouble(fgxFile, ((double) edgeWeight) / sourceWeightDivisor );
19148 if (edgeWeight < bTarget->bbWeight)
19150 fprintf(fgxFile,"\n in=");
19151 fprintfDouble(fgxFile, ((double) edgeWeight) / targetWeightDivisor);
19156 if (!createDotFile)
19158 fprintf(fgxFile, ">");
19159 fprintf(fgxFile,"\n </edge>");
19165 fprintf(fgxFile, "}\n");
19169 fprintf(fgxFile, "\n </edges>");
19170 fprintf(fgxFile, "\n</method>\n");
19175 // fgxFile is jitstdout or stderr
19176 fprintf(fgxFile, "\n");
19186 #endif // DUMP_FLOWGRAPHS
19188 /*****************************************************************************/
19191 void Compiler::fgDispReach()
19193 printf("------------------------------------------------\n");
19194 printf("BBnum Reachable by \n");
19195 printf("------------------------------------------------\n");
19197 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
19199 printf("BB%02u : ", block->bbNum);
19200 BLOCKSET_ITER_INIT(this, iter, block->bbReach, bbNum);
19201 while (iter.NextElem(this, &bbNum))
19203 printf("BB%02u ", bbNum);
19209 void Compiler::fgDispDoms()
19211 // Don't bother printing this when we have a large number of BasicBlocks in the method
19212 if (fgBBcount > 256)
19217 printf("------------------------------------------------\n");
19218 printf("BBnum Dominated by\n");
19219 printf("------------------------------------------------\n");
19221 for (unsigned i = 1; i <= fgBBNumMax; ++i)
19223 BasicBlock* current = fgBBInvPostOrder[i];
19224 printf("BB%02u: ", current->bbNum);
19225 while (current != current->bbIDom)
19227 printf("BB%02u ", current->bbNum);
19228 current = current->bbIDom;
19234 /*****************************************************************************/
19236 void Compiler::fgTableDispBasicBlock(BasicBlock* block,
19237 int ibcColWidth /* = 0 */)
19239 unsigned flags = block->bbFlags;
19241 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
19242 int maxBlockNumWidth = CountDigits(bbNumMax);
19243 maxBlockNumWidth = max(maxBlockNumWidth, 2);
19244 int blockNumWidth = CountDigits(block->bbNum);
19245 blockNumWidth = max(blockNumWidth, 2);
19246 int blockNumPadding = maxBlockNumWidth - blockNumWidth;
19248 printf("BB%02u%*s [%08p] %2u",
19250 blockNumPadding, "",
19255 // Display EH 'try' region index
19258 if (block->hasTryIndex())
19260 printf(" %2u", block->getTryIndex());
19268 // Display EH handler region index
19271 if (block->hasHndIndex())
19273 printf(" %2u", block->getHndIndex());
19283 // Display block predecessor list
19287 if (fgCheapPredsValid)
19289 charCnt = block->dspCheapPreds();
19293 charCnt = block->dspPreds();
19298 printf("%*s", 19 - charCnt, "");
19304 // Display block weight
19307 if (block->isMaxBBWeight())
19313 printf("%6s", refCntWtd2str(block->getBBWeight(this)));
19317 // Display optional IBC weight column.
19318 // Note that iColWidth includes one character for a leading space, if there is an IBC column.
19321 if (ibcColWidth > 0)
19323 if (block->bbFlags & BBF_PROF_WEIGHT)
19325 printf("%*u", ibcColWidth, block->bbWeight);
19329 // No IBC data. Just print spaces to align the column.
19330 printf("%*s", ibcColWidth, "");
19337 // Display block IL range
19340 block->dspBlockILRange();
19343 // Display block branch target
19346 if (flags & BBF_REMOVED)
19348 printf( "[removed] ");
19352 switch (block->bbJumpKind)
19355 printf("-> BB%02u%*s ( cond )", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19358 case BBJ_CALLFINALLY:
19359 printf("-> BB%02u%*s (callf )", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19363 if (flags & BBF_KEEP_BBJ_ALWAYS)
19365 printf("-> BB%02u%*s (ALWAYS)", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19369 printf("-> BB%02u%*s (always)", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19374 printf("-> BB%02u%*s (leave )", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19377 case BBJ_EHFINALLYRET:
19378 printf( "%*s (finret)", maxBlockNumWidth - 2, "");
19381 case BBJ_EHFILTERRET:
19382 printf( "%*s (fltret)", maxBlockNumWidth - 2, "");
19385 case BBJ_EHCATCHRET:
19386 printf("-> BB%02u%*s ( cret )", block->bbJumpDest->bbNum, maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19390 printf( "%*s (throw )", maxBlockNumWidth - 2, "");
19394 printf( "%*s (return)", maxBlockNumWidth - 2, "");
19398 printf( "%*s ", maxBlockNumWidth - 2, "");
19405 jumpCnt = block->bbJumpSwt->bbsCount;
19406 BasicBlock** jumpTab;
19407 jumpTab = block->bbJumpSwt->bbsDstTab;
19413 (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',',
19414 (*jumpTab)->bbNum);
19415 switchWidth += 1 /* space/comma */ + 2 /* BB */ + max(CountDigits((*jumpTab)->bbNum), 2);
19417 while (++jumpTab, --jumpCnt);
19419 if (switchWidth < 7)
19421 printf("%*s", 8 - switchWidth, "");
19424 printf(" (switch)");
19432 // Display block EH region and type, including nesting indicator
19435 if (block->hasTryIndex())
19437 printf("T%d ", block->getTryIndex());
19444 if (block->hasHndIndex())
19446 printf("H%d ", block->getHndIndex());
19453 if (flags & BBF_FUNCLET_BEG)
19464 switch (block->bbCatchTyp)
19466 case BBCT_NONE: break;
19467 case BBCT_FAULT: printf("fault "); cnt += 6; break;
19468 case BBCT_FINALLY: printf("finally "); cnt += 8; break;
19469 case BBCT_FILTER: printf("filter "); cnt += 7; break;
19470 case BBCT_FILTER_HANDLER: printf("filtHnd "); cnt += 8; break;
19471 default: printf("catch "); cnt += 6; break;
19474 if (block->bbCatchTyp != BBCT_NONE)
19478 /* brace matching editor workaround to compensate for the preceding line: } */
19481 if (flags & BBF_TRY_BEG)
19483 // Output a brace for every try region that this block opens
19486 EHblkDsc* HBtabEnd;
19488 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount;
19492 if (HBtab->ebdTryBeg == block)
19496 /* brace matching editor workaround to compensate for the preceding line: } */
19502 EHblkDsc* HBtabEnd;
19504 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount;
19508 if (HBtab->ebdTryLast == block)
19511 /* brace matching editor workaround to compensate for the following line: { */
19514 if (HBtab->ebdHndLast == block)
19517 /* brace matching editor workaround to compensate for the following line: { */
19520 if (HBtab->HasFilter() && block->bbNext == HBtab->ebdHndBeg)
19523 /* brace matching editor workaround to compensate for the following line: { */
19535 // Display block flags
19543 /****************************************************************************
19544 Dump blocks from firstBlock to lastBlock.
19547 void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock,
19548 BasicBlock* lastBlock,
19554 #ifdef _TARGET_AMD64_
19556 #endif // _TARGET_AMD64_
19558 // If any block has IBC data, we add an "IBC weight" column just before the 'IL range' column. This column is as
19559 // wide as necessary to accommodate all the various IBC weights. It's at least 4 characters wide, to accommodate
19560 // the "IBC" title and leading space.
19561 int ibcColWidth = 0;
19562 for (block = firstBlock; block != nullptr; block = block->bbNext)
19564 if (block->bbFlags & BBF_PROF_WEIGHT)
19566 int thisIbcWidth = CountDigits(block->bbWeight);
19567 ibcColWidth = max(ibcColWidth, thisIbcWidth);
19570 if (block == lastBlock) {
19574 if (ibcColWidth > 0)
19576 ibcColWidth = max(ibcColWidth, 3) + 1; // + 1 for the leading space
19579 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
19580 int maxBlockNumWidth = CountDigits(bbNumMax);
19581 maxBlockNumWidth = max(maxBlockNumWidth, 2);
19583 padWidth += maxBlockNumWidth - 2; // Account for functions with a large number of blocks.
19586 printf("------%*s------------------------------------%*s-----------------------%*s----------------------------------------\n",
19587 padWidth, "------------",
19588 ibcColWidth, "------------",
19589 maxBlockNumWidth, "----");
19590 printf("BBnum %*sdescAddr ref try hnd %s weight %*s%s [IL range] [jump]%*s [EH region] [flags]\n",
19592 fgCheapPredsValid ? "cheap preds" :
19593 (fgComputePredsDone ? "preds "
19595 ((ibcColWidth > 0) ? ibcColWidth - 3 : 0), "", // Subtract 3 for the width of "IBC", printed next.
19596 ((ibcColWidth > 0) ? "IBC"
19598 maxBlockNumWidth, ""
19600 printf("------%*s------------------------------------%*s-----------------------%*s----------------------------------------\n",
19601 padWidth, "------------",
19602 ibcColWidth, "------------",
19603 maxBlockNumWidth, "----");
19605 for (block = firstBlock;
19607 block = block->bbNext)
19609 // First, do some checking on the bbPrev links
19612 if (block->bbPrev->bbNext != block)
19614 printf("bad prev link\n");
19617 else if (block != fgFirstBB)
19619 printf("bad prev link!\n");
19622 if (block == fgFirstColdBlock)
19624 printf("~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
19625 padWidth, "~~~~~~~~~~~~",
19626 ibcColWidth, "~~~~~~~~~~~~",
19627 maxBlockNumWidth, "~~~~");
19630 #if FEATURE_EH_FUNCLETS
19631 if (block == fgFirstFuncletBB)
19633 printf("++++++%*s++++++++++++++++++++++++++++++++++++%*s+++++++++++++++++++++++%*s++++++++++++++++++++++++++++++++++++++++ funclets follow\n",
19634 padWidth, "++++++++++++",
19635 ibcColWidth, "++++++++++++",
19636 maxBlockNumWidth, "++++");
19638 #endif // FEATURE_EH_FUNCLETS
19640 fgTableDispBasicBlock(block, ibcColWidth);
19642 if (block == lastBlock) {
19647 printf("------%*s------------------------------------%*s-----------------------%*s----------------------------------------\n",
19648 padWidth, "------------",
19649 ibcColWidth, "------------",
19650 maxBlockNumWidth, "----");
19654 fgDumpTrees(firstBlock, lastBlock);
19658 /*****************************************************************************/
19660 void Compiler::fgDispBasicBlocks(bool dumpTrees)
19662 fgDispBasicBlocks(fgFirstBB, nullptr, dumpTrees);
19665 /*****************************************************************************/
19666 // Increment the stmtNum and dump the tree using gtDispTree
19668 void Compiler::fgDumpStmtTree(GenTreePtr stmt, unsigned blkNum)
19670 compCurStmtNum++; // Increment the current stmtNum
19672 printf("\n***** BB%02u, stmt %d\n", blkNum, compCurStmtNum);
19674 if (fgOrder == FGOrderLinear || opts.compDbgInfo)
19680 gtDispTree(stmt->gtStmt.gtStmtExpr);
19684 //------------------------------------------------------------------------
19685 // Compiler::fgDumpBlock: dumps the contents of the given block to stdout.
19688 // block - The block to dump.
19690 void Compiler::fgDumpBlock(BasicBlock* block)
19692 printf("\n------------ ");
19693 block->dspBlockHeader(this);
19695 if (!block->IsLIR())
19697 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
19699 fgDumpStmtTree(stmt, block->bbNum);
19700 if (stmt == block->bbTreeList)
19702 block->bbStmtNum = compCurStmtNum; // Set the block->bbStmtNum
19708 gtDispRange(LIR::AsRange(block));
19712 /*****************************************************************************/
19713 // Walk the BasicBlock list calling fgDumpTree once per Stmt
19715 void Compiler::fgDumpTrees(BasicBlock* firstBlock,
19716 BasicBlock* lastBlock)
19718 compCurStmtNum = 0; // Reset the current stmtNum
19720 /* Walk the basic blocks */
19722 // Note that typically we have already called fgDispBasicBlocks()
19723 // so we don't need to print the preds and succs again here
19725 for (BasicBlock* block = firstBlock; block; block = block->bbNext)
19727 fgDumpBlock(block);
19729 if (block == lastBlock) {
19733 printf("\n-------------------------------------------------------------------------------------------------------------------\n");
19737 /*****************************************************************************
19738 * Try to create as many candidates for GTF_MUL_64RSLT as possible.
19739 * We convert 'intOp1*intOp2' into 'int(long(nop(intOp1))*long(intOp2))'.
19743 Compiler::fgWalkResult Compiler::fgStress64RsltMulCB(GenTreePtr* pTree, fgWalkData* data)
19745 GenTreePtr tree = *pTree;
19746 Compiler* pComp = data->compiler;
19748 if (tree->gtOper != GT_MUL || tree->gtType != TYP_INT || (tree->gtOverflow())) {
19749 return WALK_CONTINUE;
19752 // To ensure optNarrowTree() doesn't fold back to the original tree.
19753 tree->gtOp.gtOp1 = pComp->gtNewOperNode(GT_NOP, TYP_LONG, tree->gtOp.gtOp1);
19754 tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, TYP_LONG);
19755 tree->gtOp.gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp2, TYP_LONG);
19756 tree->gtType = TYP_LONG;
19757 *pTree = pComp->gtNewCastNode(TYP_INT, tree, TYP_INT);
19759 return WALK_SKIP_SUBTREES;
19762 void Compiler::fgStress64RsltMul()
19764 if (!compStressCompile(STRESS_64RSLT_MUL, 20)) {
19768 fgWalkAllTreesPre(fgStress64RsltMulCB, (void*)this);
19772 // This variable is used to generate "traversal labels": one-time constants with which
19773 // we label basic blocks that are members of the basic block list, in order to have a
19774 // fast, high-probability test for membership in that list. Type is "volatile" because
19775 // it's incremented with an atomic operation, which wants a volatile type; "long" so that
19776 // wrap-around to 0 (which I think has the highest probability of accidental collision) is
19777 // postponed a *long* time.
19778 static volatile int bbTraverseLabel = 1;
19780 /*****************************************************************************
19782 * A DEBUG routine to check the consistency of the flowgraph,
19783 * i.e. bbNum, bbRefs, bbPreds have to be up to date.
19785 *****************************************************************************/
19787 void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */,
19788 bool checkBBRefs /* = true */)
19793 printf("*************** In fgDebugCheckBBlist\n");
19797 fgDebugCheckBlockLinks();
19799 if (fgBBcount > 10000 && expensiveDebugCheckLevel < 1)
19801 // The basic block checks are too expensive if there are too many blocks,
19802 // so give up unless we've been told to try hard.
19806 DWORD startTickCount = GetTickCount();
19809 BasicBlock* prevBlock;
19810 BasicBlock* blockPred;
19812 unsigned blockRefs;
19814 #if FEATURE_EH_FUNCLETS
19815 bool reachedFirstFunclet = false;
19816 if (fgFuncletsCreated)
19819 // Make sure that fgFirstFuncletBB is accurate.
19820 // It should be the first basic block in a handler region.
19822 if (fgFirstFuncletBB != nullptr)
19824 assert(fgFirstFuncletBB->hasHndIndex() == true);
19825 assert(fgFirstFuncletBB->bbFlags & BBF_FUNCLET_BEG);
19828 #endif // FEATURE_EH_FUNCLETS
19830 /* Check bbNum, bbRefs and bbPreds */
19831 // First, pick a traversal stamp, and label all the blocks with it.
19832 unsigned curTraversalStamp = unsigned(InterlockedIncrement((LONG*)&bbTraverseLabel));
19833 for (block = fgFirstBB; block; block = block->bbNext)
19835 block->bbTraversalStamp = curTraversalStamp;
19838 for (prevBlock = nullptr, block = fgFirstBB;
19840 prevBlock = block, block = block->bbNext)
19844 /* First basic block has countOfInEdges() >= 1 */
19846 if (block == fgFirstBB)
19848 noway_assert(block->countOfInEdges() >= 1);
19854 // Check that bbNum is sequential
19855 noway_assert(block->bbNext == nullptr || (block->bbNum + 1 == block->bbNext->bbNum));
19858 // If the block is a BBJ_COND, a BBJ_SWITCH or a
19859 // lowered GT_SWITCH_TABLE node then make sure it
19860 // ends with a GT_JTRUE or a GT_SWITCH
19862 if (block->bbJumpKind == BBJ_COND)
19864 noway_assert(block->lastNode()->gtNext == nullptr && block->lastNode()->gtOper == GT_JTRUE);
19866 else if (block->bbJumpKind == BBJ_SWITCH)
19868 #ifndef LEGACY_BACKEND
19869 noway_assert(block->lastNode()->gtNext == nullptr &&
19870 (block->lastNode()->gtOper == GT_SWITCH ||
19871 block->lastNode()->gtOper == GT_SWITCH_TABLE));
19872 #else // LEGACY_BACKEND
19873 noway_assert(block->lastStmt()->gtNext == NULL &&
19874 block->lastStmt()->gtStmtExpr->gtOper == GT_SWITCH);
19875 #endif // LEGACY_BACKEND
19877 else if (!( block->bbJumpKind == BBJ_ALWAYS
19878 || block->bbJumpKind == BBJ_RETURN))
19880 //this block cannot have a poll
19881 noway_assert(!(block->bbFlags & BBF_NEEDS_GCPOLL));
19884 if (block->bbCatchTyp == BBCT_FILTER)
19886 if (!fgCheapPredsValid) // Don't check cheap preds
19888 // A filter has no predecessors
19889 noway_assert(block->bbPreds == nullptr);
19893 #if FEATURE_EH_FUNCLETS
19894 if (fgFuncletsCreated)
19897 // There should be no handler blocks until
19898 // we get to the fgFirstFuncletBB block,
19899 // then every block should be a handler block
19901 if (!reachedFirstFunclet)
19903 if (block == fgFirstFuncletBB)
19905 assert(block->hasHndIndex() == true);
19906 reachedFirstFunclet = true;
19910 assert(block->hasHndIndex() == false);
19913 else // reachedFirstFunclet
19915 assert(block->hasHndIndex() == true);
19918 #endif // FEATURE_EH_FUNCLETS
19920 // Don't check cheap preds.
19921 for (pred = (fgCheapPredsValid ? nullptr : block->bbPreds); pred != nullptr; blockRefs += pred->flDupCount, pred = pred->flNext)
19923 assert(fgComputePredsDone); // If this isn't set, why do we have a preds list?
19925 /* make sure this pred is part of the BB list */
19927 blockPred = pred->flBlock;
19928 noway_assert(blockPred->bbTraversalStamp == curTraversalStamp);
19930 EHblkDsc* ehTryDsc = ehGetBlockTryDsc(block);
19931 if (ehTryDsc != nullptr)
19933 // You can jump to the start of a try
19934 if (ehTryDsc->ebdTryBeg == block) {
19938 // You can jump within the same try region
19939 if (bbInTryRegions(block->getTryIndex(), blockPred)) {
19943 // The catch block can jump back into the middle of the try
19944 if (bbInCatchHandlerRegions(block, blockPred)) {
19948 // The end of a finally region is a BBJ_EHFINALLYRET block (during importing, BBJ_LEAVE) which
19949 // is marked as "returning" to the BBJ_ALWAYS block following the BBJ_CALLFINALLY
19950 // block that does a local call to the finally. This BBJ_ALWAYS is within
19951 // the try region protected by the finally (for x86, ARM), but that's ok.
19952 if (prevBlock->bbJumpKind == BBJ_CALLFINALLY &&
19953 block->bbJumpKind == BBJ_ALWAYS &&
19954 blockPred->bbJumpKind == BBJ_EHFINALLYRET) {
19958 printf("Jump into the middle of try region: BB%02u branches to BB%02u\n", blockPred->bbNum, block->bbNum);
19959 noway_assert(!"Jump into middle of try region");
19964 EHblkDsc* ehHndDsc = ehGetBlockHndDsc(block);
19965 if (ehHndDsc != nullptr)
19967 // You can do a BBJ_EHFINALLYRET or BBJ_EHFILTERRET into a handler region
19968 if ( (blockPred->bbJumpKind == BBJ_EHFINALLYRET)
19969 || (blockPred->bbJumpKind == BBJ_EHFILTERRET)) {
19973 // Our try block can call our finally block
19974 if ((block->bbCatchTyp == BBCT_FINALLY) &&
19975 (blockPred->bbJumpKind == BBJ_CALLFINALLY) &&
19976 ehCallFinallyInCorrectRegion(blockPred, block->getHndIndex()))
19981 // You can jump within the same handler region
19982 if (bbInHandlerRegions(block->getHndIndex(), blockPred)) {
19986 // A filter can jump to the start of the filter handler
19987 if (ehHndDsc->HasFilter()) {
19991 printf("Jump into the middle of handler region: BB%02u branches to BB%02u\n", blockPred->bbNum, block->bbNum);
19992 noway_assert(!"Jump into the middle of handler region");
19997 switch (blockPred->bbJumpKind)
20000 noway_assert(blockPred->bbNext == block || blockPred->bbJumpDest == block);
20004 noway_assert(blockPred->bbNext == block);
20007 case BBJ_CALLFINALLY:
20009 case BBJ_EHCATCHRET:
20010 case BBJ_EHFILTERRET:
20011 noway_assert(blockPred->bbJumpDest == block);
20014 case BBJ_EHFINALLYRET:
20016 // If the current block is a successor to a BBJ_EHFINALLYRET (return from finally),
20017 // then the lexically previous block should be a call to the same finally.
20018 // Verify all of that.
20020 unsigned hndIndex = blockPred->getHndIndex();
20021 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
20022 BasicBlock* finBeg = ehDsc->ebdHndBeg;
20024 // Because there is no bbPrev, we have to search for the lexically previous
20025 // block. We can shorten the search by only looking in places where it is legal
20026 // to have a call to the finally.
20028 BasicBlock* begBlk;
20029 BasicBlock* endBlk;
20030 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
20032 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
20034 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg) {
20038 if (block == bcall->bbNext) {
20043 #if FEATURE_EH_FUNCLETS
20045 if (fgFuncletsCreated)
20047 // There is no easy way to search just the funclets that were pulled out of
20048 // the corresponding try body, so instead we search all the funclets, and if
20049 // we find a potential 'hit' we check if the funclet we're looking at is
20050 // from the correct try region.
20052 for (BasicBlock* bcall = fgFirstFuncletBB; bcall; bcall = bcall->bbNext)
20054 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg) {
20058 if (block != bcall->bbNext) {
20062 if (ehCallFinallyInCorrectRegion(bcall, hndIndex)) {
20068 #endif // FEATURE_EH_FUNCLETS
20070 noway_assert(!"BBJ_EHFINALLYRET predecessor of block that doesn't follow a BBJ_CALLFINALLY!");
20076 noway_assert(!"THROW and RETURN block cannot be in the predecessor list!");
20080 unsigned jumpCnt; jumpCnt = blockPred->bbJumpSwt->bbsCount;
20081 BasicBlock** jumpTab; jumpTab = blockPred->bbJumpSwt->bbsDstTab;
20085 if (block == *jumpTab)
20090 while (++jumpTab, --jumpCnt);
20092 noway_assert(!"SWITCH in the predecessor list with no jump label to BLOCK!");
20096 noway_assert(!"Unexpected bbJumpKind");
20104 /* Check the bbRefs */
20105 noway_assert(!checkBBRefs || block->bbRefs == blockRefs);
20107 /* Check that BBF_HAS_HANDLER is valid bbTryIndex */
20108 if (block->hasTryIndex())
20110 noway_assert(block->getTryIndex() < compHndBBtabCount);
20113 /* Check if BBF_RUN_RARELY is set that we have bbWeight of zero */
20114 if (block->isRunRarely())
20116 noway_assert(block->bbWeight == BB_ZERO_WEIGHT);
20120 noway_assert(block->bbWeight > BB_ZERO_WEIGHT);
20124 // Make sure the one return BB is not changed.
20127 noway_assert(genReturnBB->bbTreeList);
20128 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtOper == GT_STMT);
20129 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtType == TYP_VOID);
20132 // The general encoder/decoder (currently) only reports "this" as a generics context as a stack location,
20133 // so we mark info.compThisArg as lvAddrTaken to ensure that it is not enregistered. Otherwise, it should
20134 // not be address-taken. This variable determines if the address-taken-ness of "thisArg" is "OK".
20135 bool copiedForGenericsCtxt;
20136 #ifndef JIT32_GCENCODER
20137 copiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
20138 #else // JIT32_GCENCODER
20139 copiedForGenericsCtxt = FALSE;
20140 #endif // JIT32_GCENCODER
20142 // This if only in support of the noway_asserts it contains.
20143 if (info.compIsStatic)
20145 // For static method, should have never grabbed the temp.
20146 noway_assert(lvaArg0Var == BAD_VAR_NUM);
20150 // For instance method:
20151 assert(info.compThisArg != BAD_VAR_NUM);
20152 bool compThisArgAddrExposedOK = !lvaTable[info.compThisArg].lvAddrExposed;
20153 #ifndef JIT32_GCENCODER
20154 compThisArgAddrExposedOK = compThisArgAddrExposedOK || copiedForGenericsCtxt;
20155 #endif // !JIT32_GCENCODER
20156 noway_assert(compThisArgAddrExposedOK && // should never expose the address of arg 0 or
20157 !lvaTable[info.compThisArg].lvArgWrite && // write to arg 0.
20159 lvaArg0Var == info.compThisArg || // lvArg0Var should remain 0 if arg0 is not written to or address-exposed.
20160 lvaArg0Var != info.compThisArg &&
20161 (lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvArgWrite || copiedForGenericsCtxt)
20166 /*****************************************************************************
20168 * A DEBUG routine to check the that the exception flags are correctly set.
20170 ****************************************************************************/
20172 void Compiler::fgDebugCheckFlags(GenTreePtr tree)
20174 noway_assert(tree->gtOper != GT_STMT);
20176 genTreeOps oper = tree->OperGet();
20177 unsigned kind = tree->OperKind();
20178 unsigned treeFlags = tree->gtFlags & GTF_ALL_EFFECT;
20179 unsigned chkFlags = 0;
20181 /* Is this a leaf node? */
20183 if (kind & GTK_LEAF)
20188 chkFlags |= GTF_GLOB_REF;
20192 chkFlags |= GTF_ORDER_SIDEEFF;
20200 /* Is it a 'simple' unary/binary operator? */
20202 else if (kind & GTK_SMPOP)
20204 GenTreePtr op1 = tree->gtOp.gtOp1;
20205 GenTreePtr op2 = tree->gtGetOp2();
20207 // During GS work, we make shadow copies for params.
20208 // In gsParamsToShadows(), we create a shadow var of TYP_INT for every small type param.
20209 // Then in gsReplaceShadowParams(), we change the gtLclNum to the shadow var.
20210 // We also change the types of the local var tree and the assignment tree to TYP_INT if necessary.
20211 // However, since we don't morph the tree at this late stage. Manually propagating
20212 // TYP_INT up to the GT_ASG tree is only correct if we don't need to propagate the TYP_INT back up.
20213 // The following checks will ensure this.
20215 // Is the left child of "tree" a GT_ASG?,
20216 if (op1 && op1->gtOper == GT_ASG)
20218 assert(tree->gtType == TYP_VOID || // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
20219 tree->gtOper == GT_COMMA); // (or) If GT_ASG is the left child of a GT_COMMA, the type of the GT_COMMA node will
20220 } // be determined by its right child. So we don't need to propagate TYP_INT up either. We are fine.
20222 // Is the right child of "tree" a GT_ASG?,
20223 if (op2 && op2->gtOper == GT_ASG)
20225 assert(tree->gtType == TYP_VOID); // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
20231 if (op1->OperIsCompare())
20233 noway_assert(op1->gtFlags & GTF_DONT_CSE);
20237 noway_assert( (op1->gtOper == GT_CNS_INT) &&
20238 ((op1->gtIntCon.gtIconVal == 0) || (op1->gtIntCon.gtIconVal == 1)) );
20243 if ((op2 != nullptr) && op2->IsList())
20245 ArrayStack<GenTree *> stack(this);
20246 while ((tree->gtGetOp2() != nullptr) && tree->gtGetOp2()->IsList())
20249 tree = tree->gtGetOp2();
20252 fgDebugCheckFlags(tree);
20254 while (stack.Height() > 0)
20256 tree = stack.Pop();
20257 assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
20258 fgDebugCheckFlags(tree->gtOp.gtOp1);
20259 chkFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
20260 chkFlags |= (tree->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
20261 fgDebugCheckFlagsHelper(tree, (tree->gtFlags & GTF_ALL_EFFECT), chkFlags);
20272 /* Recursively check the subtrees */
20276 fgDebugCheckFlags(op1);
20280 fgDebugCheckFlags(op2);
20285 chkFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
20289 chkFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
20292 // We reuse the value of GTF_REVERSE_OPS for a GT_IND-specific flag,
20293 // so exempt that (unary) operator.
20294 if (tree->OperGet() != GT_IND && tree->gtFlags & GTF_REVERSE_OPS)
20296 /* Must have two operands if GTF_REVERSE is set */
20297 noway_assert(op1 && op2);
20299 /* Make sure that the order of side effects has not been swapped. */
20301 /* However CSE may introduce an assignment after the reverse flag
20302 was set and thus GTF_ASG cannot be considered here. */
20304 /* For a GT_ASG(GT_IND(x), y) we are interested in the side effects of x */
20306 if ((kind & GTK_ASGOP) && (op1->gtOper == GT_IND))
20308 op1p = op1->gtOp.gtOp1;
20315 /* This isn't true any more with the sticky GTF_REVERSE */
20317 // if op1p has side effects, then op2 cannot have side effects
20318 if (op1p->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
20320 if (op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
20322 noway_assert(!(op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG)));
20327 if (kind & GTK_ASGOP)
20329 chkFlags |= GTF_ASG;
20332 /* Note that it is OK for treeFlags not to have a GTF_EXCEPT,
20333 AssertionProp's non-Null may have cleared it */
20334 if (tree->OperMayThrow())
20336 chkFlags |= (treeFlags & GTF_EXCEPT);
20339 if (oper == GT_ADDR &&
20340 (op1->OperIsLocal() ||
20341 op1->gtOper == GT_CLS_VAR ||
20342 (op1->gtOper == GT_IND && op1->gtOp.gtOp1->gtOper == GT_CLS_VAR_ADDR)))
20344 /* &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does.
20345 Similarly for clsVar */
20346 treeFlags |= GTF_GLOB_REF;
20350 /* See what kind of a special operator we have here */
20354 switch (tree->OperGet())
20362 call = tree->AsCall();
20364 chkFlags |= GTF_CALL;
20366 if ((treeFlags & GTF_EXCEPT) && !(chkFlags & GTF_EXCEPT))
20368 switch (eeGetHelperNum(tree->gtCall.gtCallMethHnd))
20370 // Is this a helper call that can throw an exception ?
20371 case CORINFO_HELP_LDIV:
20372 case CORINFO_HELP_LMOD:
20373 case CORINFO_HELP_METHOD_ACCESS_CHECK:
20374 case CORINFO_HELP_FIELD_ACCESS_CHECK:
20375 case CORINFO_HELP_CLASS_ACCESS_CHECK:
20376 case CORINFO_HELP_DELEGATE_SECURITY_CHECK:
20377 chkFlags |= GTF_EXCEPT;
20384 if (call->gtCallObjp)
20386 fgDebugCheckFlags(call->gtCallObjp);
20387 chkFlags |= (call->gtCallObjp->gtFlags & GTF_SIDE_EFFECT);
20389 if (call->gtCallObjp->gtFlags & GTF_ASG)
20391 treeFlags |= GTF_ASG;
20395 for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2)
20397 argx = args->gtOp.gtOp1;
20398 fgDebugCheckFlags(argx);
20400 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
20402 if (argx->gtFlags & GTF_ASG)
20404 treeFlags |= GTF_ASG;
20408 for (args = call->gtCallLateArgs; args; args = args->gtOp.gtOp2)
20410 argx = args->gtOp.gtOp1;
20411 fgDebugCheckFlags(argx);
20413 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
20415 if (argx->gtFlags & GTF_ASG)
20417 treeFlags |= GTF_ASG;
20421 if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != nullptr))
20423 fgDebugCheckFlags(call->gtCallCookie);
20424 chkFlags |= (call->gtCallCookie->gtFlags & GTF_SIDE_EFFECT);
20427 if (call->gtCallType == CT_INDIRECT)
20429 fgDebugCheckFlags(call->gtCallAddr);
20430 chkFlags |= (call->gtCallAddr->gtFlags & GTF_SIDE_EFFECT);
20433 if (call->IsUnmanaged() &&
20434 (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL))
20436 if (call->gtCallArgs->gtOp.gtOp1->OperGet() == GT_NOP)
20438 noway_assert(call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
20439 call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
20443 noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
20444 call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
20454 arrObj = tree->gtArrElem.gtArrObj;
20455 fgDebugCheckFlags(arrObj);
20456 chkFlags |= (arrObj->gtFlags & GTF_ALL_EFFECT);
20458 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
20460 fgDebugCheckFlags(tree->gtArrElem.gtArrInds[dim]);
20461 chkFlags |= tree->gtArrElem.gtArrInds[dim]->gtFlags & GTF_ALL_EFFECT;
20465 case GT_ARR_OFFSET:
20466 fgDebugCheckFlags(tree->gtArrOffs.gtOffset);
20467 chkFlags |= (tree->gtArrOffs.gtOffset->gtFlags & GTF_ALL_EFFECT);
20468 fgDebugCheckFlags(tree->gtArrOffs.gtIndex);
20469 chkFlags |= (tree->gtArrOffs.gtIndex->gtFlags & GTF_ALL_EFFECT);
20470 fgDebugCheckFlags(tree->gtArrOffs.gtArrObj);
20471 chkFlags |= (tree->gtArrOffs.gtArrObj->gtFlags & GTF_ALL_EFFECT);
20479 fgDebugCheckFlagsHelper(tree, treeFlags, chkFlags);
20482 //------------------------------------------------------------------------------
20483 // fgDebugCheckFlagsHelper : Check if all bits that are set in chkFlags are also set in treeFlags.
20487 // tree - Tree whose flags are being checked
20488 // treeFlags - Actual flags on the tree
20489 // chkFlags - Expected flags
20492 // Checking that all bits that are set in treeFlags are also set in chkFlags is currently disabled.
20494 void Compiler::fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags)
20496 if (chkFlags & ~treeFlags)
20498 // Print the tree so we can see it in the log.
20499 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
20500 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
20504 noway_assert(!"Missing flags on tree");
20506 // Print the tree again so we can see it right after we hook up the debugger.
20507 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
20508 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
20512 else if (treeFlags & ~chkFlags)
20516 /* The tree has extra flags set. However, this will happen if we
20517 replace a subtree with something, but don't clear the flags up
20518 the tree. Can't flag this unless we start clearing flags above.
20520 Note: we need this working for GTF_CALL and CSEs, so I'm enabling
20523 if (tree->OperGet() != GT_CALL && (treeFlags & GTF_CALL) && !(chkFlags & GTF_CALL))
20525 // Print the tree so we can see it in the log.
20526 printf("Extra GTF_CALL flags on parent tree [%X]: ", tree);
20527 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
20531 noway_assert(!"Extra flags on tree");
20533 // Print the tree again so we can see it right after we hook up the debugger.
20534 printf("Extra GTF_CALL flags on parent tree [%X]: ", tree);
20535 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
20543 // DEBUG routine to check correctness of the internal gtNext, gtPrev threading of a statement.
20544 // This threading is only valid when fgStmtListThreaded is true.
20545 // This calls an alternate method for FGOrderLinear.
20546 void Compiler::fgDebugCheckNodeLinks(BasicBlock* block, GenTree* node)
20548 // LIR blocks are checked using BasicBlock::CheckLIR().
20549 if (block->IsLIR())
20551 LIR::AsRange(block).CheckLIR(this);
20555 GenTreeStmt* stmt = node->AsStmt();
20557 assert(fgStmtListThreaded);
20559 noway_assert(stmt->gtStmtList);
20561 // The first node's gtPrev must be nullptr (the gtPrev list is not circular).
20562 // The last node's gtNext must be nullptr (the gtNext list is not circular). This is tested if the loop below terminates.
20563 assert(stmt->gtStmtList->gtPrev == nullptr);
20565 for (GenTreePtr tree = stmt->gtStmtList;
20567 tree = tree->gtNext)
20571 noway_assert(tree->gtPrev->gtNext == tree);
20575 noway_assert(tree == stmt->gtStmtList);
20580 noway_assert(tree->gtNext->gtPrev == tree);
20584 noway_assert(tree == stmt->gtStmtExpr);
20587 /* Cross-check gtPrev,gtNext with gtOp for simple trees */
20589 GenTreePtr expectedPrevTree = nullptr;
20591 if (tree->OperIsLeaf())
20593 if (tree->gtOper == GT_CATCH_ARG)
20595 // The GT_CATCH_ARG should always have GTF_ORDER_SIDEEFF set
20596 noway_assert(tree->gtFlags & GTF_ORDER_SIDEEFF);
20597 // The GT_CATCH_ARG has to be the first thing evaluated
20598 noway_assert(stmt == block->FirstNonPhiDef());
20599 noway_assert(stmt->gtStmtList->gtOper == GT_CATCH_ARG);
20600 // The root of the tree should have GTF_ORDER_SIDEEFF set
20601 noway_assert(stmt->gtStmtExpr->gtFlags & GTF_ORDER_SIDEEFF);
20605 if (tree->OperIsUnary() && tree->gtOp.gtOp1)
20607 GenTreePtr lclVarTree;
20608 expectedPrevTree = tree->gtOp.gtOp1;
20610 else if (tree->OperIsBinary() && tree->gtOp.gtOp1)
20612 switch (tree->gtOper)
20615 expectedPrevTree = tree->gtOp.gtOp2->AsColon()->ThenNode(); // "then" operand of the GT_COLON (generated second).
20619 expectedPrevTree = tree->AsColon()->ElseNode(); // "else" branch result (generated first).
20625 // the first child is a GT_LIST, where has op1 is the dst and op2 is the src.
20626 // The read has to occur before the write so make sure REVERSE_OPS is set.
20627 assert(tree->gtOp.gtOp1->gtFlags & GTF_REVERSE_OPS);
20631 if (tree->gtOp.gtOp2)
20633 if (tree->gtFlags & GTF_REVERSE_OPS)
20635 expectedPrevTree = tree->gtOp.gtOp1;
20639 expectedPrevTree = tree->gtOp.gtOp2;
20644 expectedPrevTree = tree->gtOp.gtOp1;
20650 noway_assert(expectedPrevTree == nullptr || // No expectations about the prev node
20651 tree->gtPrev == expectedPrevTree); // The "normal" case
20656 /*****************************************************************************
20658 * A DEBUG routine to check the correctness of the links between GT_STMT nodes
20659 * and ordinary nodes within a statement.
20661 ****************************************************************************/
20663 void Compiler::fgDebugCheckLinks(bool morphTrees)
20665 // This used to be only on for stress, and there was a comment stating that
20666 // it was "quite an expensive operation" but I did not find that to be true.
20667 // Set DO_SANITY_DEBUG_CHECKS to false to revert to that behavior.
20668 const bool DO_SANITY_DEBUG_CHECKS = true;
20670 if (!DO_SANITY_DEBUG_CHECKS &&
20671 !compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
20676 fgDebugCheckBlockLinks();
20678 /* For each basic block check the bbTreeList links */
20679 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
20681 PROCESS_BLOCK_AGAIN:;
20682 if (block->IsLIR())
20684 LIR::AsRange(block).CheckLIR(this);
20688 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
20690 /* Verify that bbTreeList is threaded correctly */
20691 /* Note that for the GT_STMT list, the gtPrev list is circular. The gtNext list is not: gtNext of the last GT_STMT in a block is nullptr. */
20693 noway_assert(stmt->gtPrev);
20695 if (stmt == block->bbTreeList)
20697 noway_assert(stmt->gtPrev->gtNext == nullptr);
20701 noway_assert(stmt->gtPrev->gtNext == stmt);
20706 noway_assert(stmt->gtNext->gtPrev == stmt);
20710 noway_assert(block->lastStmt() == stmt);
20713 /* For each statement check that the exception flags are properly set */
20715 noway_assert(stmt->gtStmtExpr);
20719 gtDispTree(stmt->gtStmtExpr);
20722 fgDebugCheckFlags(stmt->gtStmtExpr);
20724 // Not only will this stress fgMorphBlockStmt(), but we also get all the checks
20725 // done by fgMorphTree()
20729 // If 'stmt' is removed from the block, restart
20730 if (fgMorphBlockStmt(block, stmt DEBUGARG("test morphing")))
20732 goto PROCESS_BLOCK_AGAIN;
20736 /* For each GT_STMT node check that the nodes are threaded correcly - gtStmtList */
20738 if (fgStmtListThreaded)
20740 fgDebugCheckNodeLinks(block, stmt);
20747 // ensure that bbNext and bbPrev are consistent
20748 void Compiler::fgDebugCheckBlockLinks()
20750 assert(fgFirstBB->bbPrev == nullptr);
20752 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
20756 assert(block->bbNext->bbPrev == block);
20760 assert(block == fgLastBB);
20765 assert(block->bbPrev->bbNext == block);
20769 assert(block == fgFirstBB);
20772 // If this is a switch, check that the tables are consistent.
20773 // Note that we don't call GetSwitchDescMap(), because it has the side-effect
20774 // of allocating it if it is not present.
20775 if (block->bbJumpKind == BBJ_SWITCH && m_switchDescMap != nullptr)
20777 SwitchUniqueSuccSet uniqueSuccSet;
20778 if (m_switchDescMap->Lookup(block, &uniqueSuccSet))
20780 // Create a set with all the successors. Don't use BlockSet, so we don't need to worry
20781 // about the BlockSet epoch.
20782 BitVecTraits bitVecTraits(fgBBNumMax + 1, this);
20783 BitVec BITVEC_INIT_NOCOPY(succBlocks, BitVecOps::MakeEmpty(&bitVecTraits));
20784 BasicBlock** jumpTable = block->bbJumpSwt->bbsDstTab;
20785 unsigned jumpCount = block->bbJumpSwt->bbsCount;
20786 for (unsigned i = 0; i < jumpCount; i++)
20788 BitVecOps::AddElemD(&bitVecTraits, succBlocks, jumpTable[i]->bbNum);
20790 // Now we should have a set of unique successors that matches what's in the switchMap.
20791 // First, check the number of entries, then make sure all the blocks in uniqueSuccSet
20792 // are in the BlockSet.
20793 unsigned count = BitVecOps::Count(&bitVecTraits, succBlocks);
20794 assert(uniqueSuccSet.numDistinctSuccs == count);
20795 for (unsigned i = 0; i < uniqueSuccSet.numDistinctSuccs; i++)
20797 assert(BitVecOps::IsMember(&bitVecTraits, succBlocks, uniqueSuccSet.nonDuplicates[i]->bbNum));
20804 /*****************************************************************************/
20806 /*****************************************************************************/
20808 //------------------------------------------------------------------------
20809 // fgCheckForInlineDepthAndRecursion: compute depth of the candidate, and
20810 // check for recursion.
20813 // The depth of the inline candidate. The root method is a depth 0, top-level
20814 // candidates at depth 1, etc.
20817 // We generally disallow recursive inlines by policy. However, they are
20818 // supported by the underlying machinery.
20820 // Likewise the depth limit is a policy consideration, and serves mostly
20821 // as a safeguard to prevent runaway inlining of small methods.
20823 unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo)
20825 BYTE* candidateCode = inlineInfo->inlineCandidateInfo->methInfo.ILCode;
20826 InlineContext* inlineContext = inlineInfo->iciStmt->gtStmt.gtInlineContext;
20827 InlineResult* inlineResult = inlineInfo->inlineResult;
20829 // There should be a context for all candidates.
20830 assert(inlineContext != nullptr);
20833 for (; inlineContext != nullptr; inlineContext = inlineContext->GetParent())
20838 if (inlineContext->GetCode() == candidateCode)
20840 // This inline candidate has the same IL code buffer as an already
20841 // inlined method does.
20842 inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_RECURSIVE);
20846 if (depth > InlineStrategy::IMPLEMENTATION_MAX_INLINE_DEPTH)
20852 inlineResult->NoteInt(InlineObservation::CALLSITE_DEPTH, depth);
20856 /*****************************************************************************
20862 void Compiler::fgInline()
20864 if (!opts.OptEnabled(CLFLG_INLINING)) {
20870 printf("*************** In fgInline()\n");
20874 BasicBlock* block = fgFirstBB;
20875 noway_assert(block != nullptr);
20877 // Set the root inline context on all statements
20878 InlineContext* rootContext = m_inlineStrategy->GetRootContext();
20880 for (; block != nullptr; block = block->bbNext)
20882 for (GenTreeStmt* stmt = block->firstStmt();
20884 stmt = stmt->gtNextStmt)
20886 stmt->gtInlineContext = rootContext;
20890 // Reset block back to start for inlining
20895 /* Make the current basic block address available globally */
20902 for (stmt = block->firstStmt();
20904 stmt = stmt->gtNextStmt)
20906 expr = stmt->gtStmtExpr;
20908 // See if we can expand the inline candidate
20909 if ((expr->gtOper == GT_CALL) && ((expr->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0))
20911 GenTreeCall* call = expr->AsCall();
20912 InlineResult inlineResult(this, call, stmt, "fgInline");
20914 fgMorphStmt = stmt;
20916 fgMorphCallInline(call, &inlineResult);
20918 if (stmt->gtStmtExpr->IsNothingNode())
20920 fgRemoveStmt(block, stmt);
20927 // Look for non-candidates.
20928 fgWalkTreePre(&stmt->gtStmtExpr, fgFindNonInlineCandidate, stmt);
20932 // See if we need to replace the return value place holder.
20933 fgWalkTreePre(&stmt->gtStmtExpr,
20934 fgUpdateInlineReturnExpressionPlaceHolder,
20937 // See if stmt is of the form GT_COMMA(call, nop)
20938 // If yes, we can get rid of GT_COMMA.
20939 if (expr->OperGet() == GT_COMMA &&
20940 expr->gtOp.gtOp1->OperGet() == GT_CALL &&
20941 expr->gtOp.gtOp2->OperGet() == GT_NOP)
20943 stmt->gtStmtExpr = expr->gtOp.gtOp1;
20947 block = block->bbNext;
20953 // Check that we should not have any inline candidate or return value place holder left.
20956 noway_assert(block);
20962 for (stmt = block->firstStmt();
20964 stmt = stmt->gtNextStmt)
20966 // Call Compiler::fgDebugCheckInlineCandidates on each node
20967 fgWalkTreePre(&stmt->gtStmtExpr, fgDebugCheckInlineCandidates);
20970 block = block->bbNext;
20974 fgVerifyHandlerTab();
20978 printf("*************** After fgInline()\n");
20979 fgDispBasicBlocks(true);
20980 fgDispHandlerTab();
20983 if (verbose || fgPrintInlinedMethods)
20985 printf("**************** Inline Tree\n");
20986 m_inlineStrategy->Dump();
20994 //------------------------------------------------------------------------
20995 // fgFindNonInlineCandidate: tree walk helper to ensure that a tree node
20996 // that is not an inline candidate is noted as a failed inline.
20999 // pTree - pointer to pointer tree node being walked
21000 // data - contextual data for the walk
21006 // Invokes fgNoteNonInlineCandidate on the nodes it finds.
21008 Compiler::fgWalkResult Compiler::fgFindNonInlineCandidate(GenTreePtr* pTree,
21011 GenTreePtr tree = *pTree;
21012 if (tree->gtOper == GT_CALL)
21014 Compiler* compiler = data->compiler;
21015 GenTreePtr stmt = (GenTreePtr) data->pCallbackData;
21016 GenTreeCall* call = tree->AsCall();
21018 compiler->fgNoteNonInlineCandidate(stmt, call);
21020 return WALK_CONTINUE;
21023 //------------------------------------------------------------------------
21024 // fgNoteNonInlineCandidate: account for inlining failures in calls
21025 // not marked as inline candidates.
21028 // tree - statement containing the call
21029 // call - the call itself
21032 // Used in debug only to try and place descriptions of inline failures
21033 // into the proper context in the inline tree.
21035 void Compiler::fgNoteNonInlineCandidate(GenTreePtr tree,
21038 InlineResult inlineResult(this, call, nullptr, "fgNotInlineCandidate");
21039 InlineObservation currentObservation = InlineObservation::CALLSITE_NOT_CANDIDATE;
21041 // Try and recover the reason left behind when the jit decided
21042 // this call was not a candidate.
21043 InlineObservation priorObservation = call->gtInlineObservation;
21045 if (InlIsValidObservation(priorObservation))
21047 currentObservation = priorObservation;
21050 // Would like to just call noteFatal here, since this
21051 // observation blocked candidacy, but policy comes into play
21052 // here too. Also note there's no need to re-report these
21053 // failures, since we reported them during the initial
21055 InlineImpact impact = InlGetImpact(currentObservation);
21057 if (impact == InlineImpact::FATAL)
21059 inlineResult.NoteFatal(currentObservation);
21063 inlineResult.Note(currentObservation);
21066 inlineResult.SetReported();
21068 if (call->gtCallType == CT_USER_FUNC)
21070 // Create InlineContext for the failure
21071 m_inlineStrategy->NewFailure(tree, &inlineResult);
21077 #if FEATURE_MULTIREG_RET
21079 /*********************************************************************************
21081 * tree - The node which needs to be converted to a struct pointer.
21083 * Return the pointer by either __replacing__ the tree node with a suitable pointer
21084 * type or __without replacing__ and just returning a subtree or by __modifying__
21087 GenTreePtr Compiler::fgGetStructAsStructPtr(GenTreePtr tree)
21089 noway_assert((tree->gtOper == GT_LCL_VAR) ||
21090 (tree->gtOper == GT_FIELD) ||
21091 (tree->gtOper == GT_IND) ||
21092 (tree->gtOper == GT_OBJ) ||
21093 tree->OperIsSIMD() ||
21094 // tree->gtOper == GT_CALL || cannot get address of call.
21095 // tree->gtOper == GT_MKREFANY || inlining should've been aborted due to mkrefany opcode.
21096 // tree->gtOper == GT_RET_EXPR || cannot happen after fgUpdateInlineReturnExpressionPlaceHolder
21097 (tree->gtOper == GT_COMMA));
21099 switch (tree->OperGet())
21103 return tree->gtOp.gtOp1;
21106 tree->gtOp.gtOp2 = fgGetStructAsStructPtr(tree->gtOp.gtOp2);
21107 tree->gtType = TYP_BYREF;
21111 return gtNewOperNode(GT_ADDR, TYP_BYREF, tree);
21115 /***************************************************************************************************
21116 * child - The inlinee of the retExpr node.
21117 * retClsHnd - The struct class handle of the type of the inlinee.
21119 * Assign the inlinee to a tmp, if it is a call, just assign it to a lclVar, else we can
21120 * use a copyblock to do the assignment.
21122 GenTreePtr Compiler::fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd)
21124 assert(child->gtOper != GT_RET_EXPR && child->gtOper != GT_MKREFANY);
21126 unsigned tmpNum = lvaGrabTemp(false DEBUGARG("RetBuf for struct inline return candidates."));
21127 lvaSetStruct(tmpNum, retClsHnd, false);
21128 var_types structType = lvaTable[tmpNum].lvType;
21130 GenTreePtr dst = gtNewLclvNode(tmpNum, structType);
21132 // If we have a call, we'd like it to be: V00 = call(), but first check if
21133 // we have a ", , , call()" -- this is very defensive as we may never get
21134 // an inlinee that is made of commas. If the inlinee is not a call, then
21135 // we use a copy block to do the assignment.
21136 GenTreePtr src = child;
21137 GenTreePtr lastComma = NULL;
21138 while (src->gtOper == GT_COMMA)
21141 src = src->gtOp.gtOp2;
21144 GenTreePtr newInlinee = NULL;
21145 if (src->gtOper == GT_CALL)
21147 // If inlinee was just a call, new inlinee is v05 = call()
21148 newInlinee = gtNewAssignNode(dst, src);
21150 // When returning a multi-register value in a local var, make sure the variable is
21151 // marked as lvIsMultiRegRet, so it does not get promoted.
21152 if (src->AsCall()->HasMultiRegRetVal())
21154 lvaTable[tmpNum].lvIsMultiRegRet = true;
21157 // If inlinee was comma, but a deeper call, new inlinee is (, , , v05 = call())
21158 if (child->gtOper == GT_COMMA)
21160 lastComma->gtOp.gtOp2 = newInlinee;
21161 newInlinee = child;
21166 // Inlinee is not a call, so just create a copy block to the tmp.
21168 GenTreePtr dstAddr = fgGetStructAsStructPtr(dst);
21169 GenTreePtr srcAddr = fgGetStructAsStructPtr(src);
21170 newInlinee = gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false);
21173 GenTreePtr production = gtNewLclvNode(tmpNum, structType);
21174 return gtNewOperNode(GT_COMMA, structType, newInlinee, production);
21177 /***************************************************************************************************
21178 * tree - The tree pointer that has one of its child nodes as retExpr.
21179 * child - The inlinee child.
21180 * retClsHnd - The struct class handle of the type of the inlinee.
21182 * V04 = call() assignments are okay as we codegen it. Everything else needs to be a copy block or
21183 * would need a temp. For example, a cast(ldobj) will then be, cast(v05 = ldobj, v05); But it is
21184 * a very rare (or impossible) scenario that we'd have a retExpr transform into a ldobj other than
21185 * a lclVar/call. So it is not worthwhile to do pattern matching optimizations like addr(ldobj(op1))
21188 void Compiler::fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd)
21190 // We are okay to have:
21191 // 1. V02 = call();
21192 // 2. copyBlk(dstAddr, srcAddr);
21193 assert(tree->gtOper == GT_ASG);
21195 // We have an assignment, we codegen only V05 = call().
21196 if (child->gtOper == GT_CALL && tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)
21201 GenTreePtr dstAddr = fgGetStructAsStructPtr(tree->gtOp.gtOp1);
21202 GenTreePtr srcAddr = fgGetStructAsStructPtr((child->gtOper == GT_CALL)
21203 ? fgAssignStructInlineeToVar(child, retClsHnd) // Assign to a variable if it is a call.
21204 : child); // Just get the address, if not a call.
21206 tree->CopyFrom(gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false), this);
21209 #endif // FEATURE_MULTIREG_RET
21211 /*****************************************************************************
21212 * Callback to replace the inline return expression place holder (GT_RET_EXPR)
21216 Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTreePtr* pTree,
21219 GenTreePtr tree = *pTree;
21220 Compiler* comp = data->compiler;
21221 CORINFO_CLASS_HANDLE retClsHnd = NO_CLASS_HANDLE;
21223 if (tree->gtOper == GT_RET_EXPR)
21225 // We are going to copy the tree from the inlinee,
21226 // so record the handle now.
21228 if (varTypeIsStruct(tree))
21230 retClsHnd = tree->gtRetExpr.gtRetClsHnd;
21235 // Obtained the expanded inline candidate
21236 GenTreePtr inlineCandidate = tree->gtRetExpr.gtInlineCandidate;
21241 printf("\nReplacing the return expression placeholder ");
21244 printTreeID(inlineCandidate);
21246 // Dump out the old return expression placeholder it will be overwritten by the CopyFrom below
21247 comp->gtDispTree(tree);
21251 tree->CopyFrom(inlineCandidate, comp);
21256 printf("\nInserting the inline return expression\n");
21257 comp->gtDispTree(tree);
21262 while (tree->gtOper == GT_RET_EXPR);
21265 #if FEATURE_MULTIREG_RET
21267 // Did we record a struct return class handle above?
21269 if (retClsHnd != NO_CLASS_HANDLE)
21271 // Is this a type that is returned in multiple registers?
21272 // if so we need to force into into a form we accept.
21273 // i.e. LclVar = call()
21275 if (comp->IsMultiRegReturnedType(retClsHnd))
21277 GenTreePtr parent = data->parent;
21278 // See assert below, we only look one level above for an asg parent.
21279 if (parent->gtOper == GT_ASG)
21281 // Either lhs is a call V05 = call(); or lhs is addr, and asg becomes a copyBlk.
21282 comp->fgAttachStructInlineeToAsg(parent, tree, retClsHnd);
21286 // Just assign the inlinee to a variable to keep it simple.
21287 tree->CopyFrom(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
21294 // Make sure we don't have a tree like so: V05 = (, , , retExpr);
21295 // Since we only look one level above for the parent for '=' and
21296 // do not check if there is a series of COMMAs. See above.
21297 // Importer and FlowGraph will not generate such a tree, so just
21298 // leaving an assert in here. This can be fixed by looking ahead
21299 // when we visit GT_ASG similar to fgAttachStructInlineeToAsg.
21301 if ((tree->gtOper == GT_ASG) && (tree->gtOp.gtOp2->gtOper == GT_COMMA))
21304 for (comma = tree->gtOp.gtOp2;
21305 comma->gtOper == GT_COMMA;
21306 comma = comma->gtOp.gtOp2)
21311 noway_assert(!varTypeIsStruct(comma) ||
21312 comma->gtOper != GT_RET_EXPR ||
21313 !comp->IsMultiRegReturnedType(comma->gtRetExpr.gtRetClsHnd));
21316 #endif // defined(DEBUG)
21317 #endif // FEATURE_MULTIREG_RET
21319 return WALK_CONTINUE;
21324 /*****************************************************************************
21325 * Callback to make sure there is no more GT_RET_EXPR and GTF_CALL_INLINE_CANDIDATE nodes.
21329 Compiler::fgWalkResult Compiler::fgDebugCheckInlineCandidates(GenTreePtr* pTree,
21332 GenTreePtr tree = *pTree;
21333 if (tree->gtOper == GT_CALL)
21335 assert((tree->gtFlags & GTF_CALL_INLINE_CANDIDATE) == 0);
21339 assert(tree->gtOper != GT_RET_EXPR);
21342 return WALK_CONTINUE;
21348 void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call,
21349 InlineResult* inlineResult)
21351 noway_assert(call->gtOper == GT_CALL);
21352 noway_assert((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0);
21353 noway_assert(opts.OptEnabled(CLFLG_INLINING));
21355 // This is the InlineInfo struct representing a method to be inlined.
21356 InlineInfo inlineInfo = {nullptr};
21358 CORINFO_METHOD_HANDLE fncHandle = call->gtCallMethHnd;
21360 inlineInfo.fncHandle = fncHandle;
21361 inlineInfo.iciCall = call;
21362 inlineInfo.iciStmt = fgMorphStmt;
21363 inlineInfo.iciBlock = compCurBB;
21364 inlineInfo.thisDereferencedFirst = false;
21365 inlineInfo.retExpr = nullptr;
21366 inlineInfo.inlineResult = inlineResult;
21367 #ifdef FEATURE_SIMD
21368 inlineInfo.hasSIMDTypeArgLocalOrReturn = false;
21369 #endif // FEATURE_SIMD
21371 InlineCandidateInfo* inlineCandidateInfo = call->gtInlineCandidateInfo;
21372 noway_assert(inlineCandidateInfo);
21373 // Store the link to inlineCandidateInfo into inlineInfo
21374 inlineInfo.inlineCandidateInfo = inlineCandidateInfo;
21376 unsigned inlineDepth = fgCheckInlineDepthAndRecursion(&inlineInfo);
21378 if (inlineResult->IsFailure())
21383 printf("Recursive or deep inline recursion detected. Will not expand this INLINECANDIDATE \n");
21389 // Set the trap to catch all errors (including recoverable ones from the EE)
21394 CORINFO_METHOD_HANDLE fncHandle;
21395 InlineCandidateInfo* inlineCandidateInfo;
21396 InlineInfo* inlineInfo;
21397 } param = {nullptr};
21399 param.pThis = this;
21401 param.fncHandle = fncHandle;
21402 param.inlineCandidateInfo = inlineCandidateInfo;
21403 param.inlineInfo = &inlineInfo;
21404 bool success = eeRunWithErrorTrap<Param>([](Param* pParam)
21406 // Init the local var info of the inlinee
21407 pParam->pThis->impInlineInitVars(pParam->inlineInfo);
21409 if (pParam->inlineInfo->inlineResult->IsCandidate())
21411 /* Clear the temp table */
21412 memset(pParam->inlineInfo->lclTmpNum, -1, sizeof(pParam->inlineInfo->lclTmpNum));
21415 // Prepare the call to jitNativeCode
21418 pParam->inlineInfo->InlinerCompiler = pParam->pThis;
21419 if (pParam->pThis->impInlineInfo == nullptr)
21421 pParam->inlineInfo->InlineRoot = pParam->pThis;
21425 pParam->inlineInfo->InlineRoot = pParam->pThis->impInlineInfo->InlineRoot;
21427 pParam->inlineInfo->argCnt = pParam->inlineCandidateInfo->methInfo.args.totalILArgs();
21428 pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHnd;
21430 JITLOG_THIS(pParam->pThis,
21432 "INLINER: inlineInfo.tokenLookupContextHandle for %s set to 0x%p:\n",
21433 pParam->pThis->eeGetMethodFullName(pParam->fncHandle),
21434 pParam->pThis->dspPtr(pParam->inlineInfo->tokenLookupContextHandle)));
21436 CORJIT_FLAGS compileFlagsForInlinee;
21437 memcpy(&compileFlagsForInlinee, pParam->pThis->opts.jitFlags, sizeof(compileFlagsForInlinee));
21438 compileFlagsForInlinee.corJitFlags &= ~CORJIT_FLG_LOST_WHEN_INLINING;
21439 compileFlagsForInlinee.corJitFlags |= CORJIT_FLG_SKIP_VERIFICATION;
21442 if (pParam->pThis->verbose)
21444 printf("\nInvoking compiler for the inlinee method %s :\n",
21445 pParam->pThis->eeGetMethodFullName(pParam->fncHandle));
21449 int result = jitNativeCode(pParam->fncHandle,
21450 pParam->inlineCandidateInfo->methInfo.scope,
21451 pParam->pThis->info.compCompHnd,
21452 &pParam->inlineCandidateInfo->methInfo,
21453 (void**)pParam->inlineInfo,
21455 &compileFlagsForInlinee,
21456 pParam->inlineInfo);
21458 if (result != CORJIT_OK)
21460 // If we haven't yet determined why this inline fails, use
21461 // a catch-all something bad happened observation.
21462 InlineResult* innerInlineResult = pParam->inlineInfo->inlineResult;
21464 if (!innerInlineResult->IsFailure())
21466 innerInlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_FAILURE);
21476 printf("\nInlining failed due to an exception during invoking the compiler for the inlinee method %s.\n",
21477 eeGetMethodFullName(fncHandle));
21481 // If we haven't yet determined why this inline fails, use
21482 // a catch-all something bad happened observation.
21483 if (!inlineResult->IsFailure())
21485 inlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
21489 if (inlineResult->IsFailure())
21497 printf("\nDone invoking compiler for the inlinee method %s\n",
21498 eeGetMethodFullName(fncHandle));
21502 // If there is non-NULL return, but we haven't set the pInlineInfo->retExpr,
21503 // That means we haven't imported any BB that contains CEE_RET opcode.
21504 // (This could happen for example for a BBJ_THROW block fall through a BBJ_RETURN block which
21505 // causes the BBJ_RETURN block not to be imported at all.)
21506 // Fail the inlining attempt
21507 if (inlineCandidateInfo->fncRetType != TYP_VOID && inlineInfo.retExpr == nullptr)
21512 printf("\nInlining failed because pInlineInfo->retExpr is not set in the inlinee method %s.\n",
21513 eeGetMethodFullName(fncHandle));
21516 inlineResult->NoteFatal(InlineObservation::CALLEE_LACKS_RETURN);
21520 if (inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_SPECULATIVE)
21522 // we defer the call to initClass() until inlining is completed in case it fails. If inlining succeeds,
21523 // we will call initClass().
21524 if (!(info.compCompHnd->initClass(nullptr /* field */, fncHandle /* method */,
21525 inlineCandidateInfo->exactContextHnd /* context */) & CORINFO_INITCLASS_INITIALIZED))
21527 inlineResult->NoteFatal(InlineObservation::CALLEE_CLASS_INIT_FAILURE);
21532 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21533 // The inlining attempt cannot be failed starting from this point.
21534 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21536 // We've successfully obtain the list of inlinee's basic blocks.
21537 // Let's insert it to inliner's basic block list.
21538 fgInsertInlineeBlocks(&inlineInfo);
21542 if (verbose || fgPrintInlinedMethods)
21544 printf("Successfully inlined %s (%d IL bytes) (depth %d) [%s]\n",
21545 eeGetMethodFullName(fncHandle),
21546 inlineCandidateInfo->methInfo.ILCodeSize,
21548 inlineResult->ReasonString());
21553 printf("--------------------------------------------------------------------------------------------\n");
21558 impInlinedCodeSize += inlineCandidateInfo->methInfo.ILCodeSize;
21562 inlineResult->NoteSuccess();
21565 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21566 // The inlining attempt cannot be failed starting from this point.
21567 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21568 void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
21570 GenTreePtr iciCall = pInlineInfo->iciCall;
21571 GenTreePtr iciStmt = pInlineInfo->iciStmt;
21572 BasicBlock* iciBlock = pInlineInfo->iciBlock;
21575 // We can write better assert here. For example, we can check that
21576 // iciBlock contains iciStmt, which in turn contains iciCall.
21577 noway_assert(iciBlock->bbTreeList != nullptr);
21578 noway_assert(iciStmt->gtStmt.gtStmtExpr != nullptr);
21579 noway_assert(iciCall->gtOper == GT_CALL);
21583 GenTreePtr currentDumpStmt = nullptr;
21587 printf("\n\n----------- Statements (and blocks) added due to the inlining of call ");
21588 printTreeID(iciCall);
21589 printf(" -----------\n");
21590 // gtDispTree(iciStmt);
21596 // Create a new inline context and mark the inlined statements with it
21598 InlineContext* calleeContext = m_inlineStrategy->NewSuccess(pInlineInfo);
21600 for (block = InlineeCompiler->fgFirstBB;
21602 block = block->bbNext)
21604 for (GenTreeStmt* stmt = block->firstStmt();
21606 stmt = stmt->gtNextStmt)
21608 stmt->gtInlineContext = calleeContext;
21613 // Prepend statements.
21615 GenTreePtr stmtAfter;
21616 stmtAfter = fgInlinePrependStatements(pInlineInfo);
21621 currentDumpStmt = stmtAfter;
21622 printf("\nInlinee method body:");
21626 if (InlineeCompiler->fgBBcount == 1)
21628 // When fgBBCount is 1 we will always have a non-NULL fgFirstBB
21630 PREFAST_ASSUME(InlineeCompiler->fgFirstBB != nullptr);
21632 // DDB 91389: Don't throw away the (only) inlinee block
21633 // when its return type is not BBJ_RETURN.
21634 // In other words, we need its BBJ_ to perform the right thing.
21635 if (InlineeCompiler->fgFirstBB->bbJumpKind == BBJ_RETURN)
21637 // Inlinee contains just one BB. So just insert its statement list to topBlock.
21638 if (InlineeCompiler->fgFirstBB->bbTreeList)
21640 stmtAfter = fgInsertStmtListAfter(iciBlock,
21642 InlineeCompiler->fgFirstBB->bbTreeList);
21644 // Copy inlinee bbFlags to caller bbFlags.
21645 const unsigned int inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
21646 noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
21647 noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
21648 iciBlock->bbFlags |= inlineeBlockFlags;
21653 noway_assert(currentDumpStmt);
21655 if (currentDumpStmt != stmtAfter)
21659 currentDumpStmt = currentDumpStmt->gtNext;
21663 noway_assert(currentDumpStmt->gtOper == GT_STMT);
21665 gtDispTree(currentDumpStmt);
21668 } while (currentDumpStmt != stmtAfter);
21677 // ======= Inserting inlinee's basic blocks ===============
21680 BasicBlock* topBlock;
21681 BasicBlock* bottomBlock;
21683 topBlock = iciBlock;
21685 bottomBlock = fgNewBBafter(topBlock->bbJumpKind, topBlock, true);
21686 bottomBlock->bbRefs = 1;
21687 bottomBlock->bbJumpDest = topBlock->bbJumpDest;
21688 bottomBlock->inheritWeight(topBlock);
21690 topBlock->bbJumpKind = BBJ_NONE;
21692 // Update block flags
21693 unsigned originalFlags;
21694 originalFlags = topBlock->bbFlags;
21695 noway_assert((originalFlags & BBF_SPLIT_NONEXIST) == 0);
21696 topBlock->bbFlags &= ~(BBF_SPLIT_LOST);
21697 bottomBlock->bbFlags |= originalFlags & BBF_SPLIT_GAINED;
21700 // Split statements between topBlock and bottomBlock
21702 GenTreePtr topBlock_Begin;
21703 GenTreePtr topBlock_End;
21704 GenTreePtr bottomBlock_Begin;
21705 GenTreePtr bottomBlock_End;
21707 topBlock_Begin = nullptr;
21708 topBlock_End = nullptr;
21709 bottomBlock_Begin = nullptr;
21710 bottomBlock_End = nullptr;
21713 // First figure out bottomBlock_Begin
21716 bottomBlock_Begin = stmtAfter->gtNext;
21718 if (topBlock->bbTreeList == nullptr)
21720 // topBlock is empty before the split.
21721 // In this case, both topBlock and bottomBlock should be empty
21722 noway_assert(bottomBlock_Begin == nullptr);
21723 topBlock->bbTreeList = nullptr;
21724 bottomBlock->bbTreeList = nullptr;
21726 else if (topBlock->bbTreeList == bottomBlock_Begin)
21728 noway_assert(bottomBlock_Begin);
21730 // topBlock contains at least one statement before the split.
21731 // And the split is before the first statement.
21732 // In this case, topBlock should be empty, and everything else should be moved to the bottonBlock.
21733 bottomBlock->bbTreeList = topBlock->bbTreeList;
21734 topBlock->bbTreeList = nullptr;
21736 else if (bottomBlock_Begin == nullptr)
21738 noway_assert(topBlock->bbTreeList);
21740 // topBlock contains at least one statement before the split.
21741 // And the split is at the end of the topBlock.
21742 // In this case, everything should be kept in the topBlock, and the bottomBlock should be empty
21744 bottomBlock->bbTreeList = nullptr;
21748 noway_assert(topBlock->bbTreeList);
21749 noway_assert(bottomBlock_Begin);
21751 // This is the normal case where both blocks should contain at least one statement.
21752 topBlock_Begin = topBlock->bbTreeList;
21753 noway_assert(topBlock_Begin);
21754 topBlock_End = bottomBlock_Begin->gtPrev;
21755 noway_assert(topBlock_End);
21756 bottomBlock_End = topBlock->lastStmt();
21757 noway_assert(bottomBlock_End);
21759 // Break the linkage between 2 blocks.
21760 topBlock_End->gtNext = nullptr;
21762 // Fix up all the pointers.
21763 topBlock->bbTreeList = topBlock_Begin;
21764 topBlock->bbTreeList->gtPrev = topBlock_End;
21766 bottomBlock->bbTreeList = bottomBlock_Begin;
21767 bottomBlock->bbTreeList->gtPrev = bottomBlock_End;
21771 // Set the try and handler index and fix the jump types of inlinee's blocks.
21774 bool inheritWeight;
21775 inheritWeight = true; // The firstBB does inherit the weight from the iciBlock
21777 for (block = InlineeCompiler->fgFirstBB;
21779 block = block->bbNext)
21781 noway_assert(!block->hasTryIndex());
21782 noway_assert(!block->hasHndIndex());
21783 block->copyEHRegion(iciBlock);
21784 block->bbFlags |= iciBlock->bbFlags & BBF_BACKWARD_JUMP;
21786 if (iciStmt->gtStmt.gtStmtILoffsx != BAD_IL_OFFSET)
21788 block->bbCodeOffs = jitGetILoffs(iciStmt->gtStmt.gtStmtILoffsx);
21789 block->bbCodeOffsEnd = block->bbCodeOffs + 1; // TODO: is code size of 1 some magic number for inlining?
21793 block->bbCodeOffs = 0; // TODO: why not BAD_IL_OFFSET?
21794 block->bbCodeOffsEnd = 0;
21795 block->bbFlags |= BBF_INTERNAL;
21798 if (block->bbJumpKind == BBJ_RETURN)
21800 inheritWeight = true; // A return block does inherit the weight from the iciBlock
21801 noway_assert((block->bbFlags & BBF_HAS_JMP) == 0);
21804 block->bbJumpKind = BBJ_ALWAYS;
21805 block->bbJumpDest = bottomBlock;
21809 printf("\nConvert bbJumpKind of BB%02u to BBJ_ALWAYS to bottomBlock BB%02u\n",
21810 block->bbNum, bottomBlock->bbNum);
21819 printf("\nConvert bbJumpKind of BB%02u to BBJ_NONE\n", block->bbNum);
21822 block->bbJumpKind = BBJ_NONE;
21827 block->inheritWeight(iciBlock);
21828 inheritWeight = false;
21832 block->modifyBBWeight(iciBlock->bbWeight / 2);
21836 // Insert inlinee's blocks into inliner's block list.
21837 topBlock->setNext(InlineeCompiler->fgFirstBB);
21838 InlineeCompiler->fgLastBB->setNext(bottomBlock);
21841 // Add inlinee's block count to inliner's.
21843 fgBBcount += InlineeCompiler->fgBBcount;
21848 fgDispBasicBlocks(InlineeCompiler->fgFirstBB, InlineeCompiler->fgLastBB, true);
21855 // At this point, we have successully inserted inlinee's code.
21859 // Copy out some flags
21861 compLongUsed |= InlineeCompiler->compLongUsed;
21862 compFloatingPointUsed |= InlineeCompiler->compFloatingPointUsed;
21863 compLocallocUsed |= InlineeCompiler->compLocallocUsed;
21864 compQmarkUsed |= InlineeCompiler->compQmarkUsed;
21865 compUnsafeCastUsed |= InlineeCompiler->compUnsafeCastUsed;
21866 compNeedsGSSecurityCookie |= InlineeCompiler->compNeedsGSSecurityCookie;
21867 compGSReorderStackLayout |= InlineeCompiler->compGSReorderStackLayout;
21869 // Update optMethodFlags
21872 unsigned optMethodFlagsBefore = optMethodFlags;
21875 optMethodFlags |= InlineeCompiler->optMethodFlags;
21878 if (optMethodFlags != optMethodFlagsBefore)
21880 JITDUMP("INLINER: Updating optMethodFlags -- root:%0x callee:%0x new:%0x\n",
21881 optMethodFlagsBefore, InlineeCompiler->optMethodFlags, optMethodFlags);
21885 // If there is non-NULL return, replace the GT_CALL with its return value expression,
21886 // so later it will be picked up by the GT_RET_EXPR node.
21887 if ((pInlineInfo->inlineCandidateInfo->fncRetType != TYP_VOID) || (iciCall->gtCall.gtReturnType == TYP_STRUCT))
21889 noway_assert(pInlineInfo->retExpr);
21893 printf("\nReturn expression for call at ");
21894 printTreeID(iciCall);
21896 gtDispTree(pInlineInfo->retExpr);
21899 // Replace the call with the return expression
21900 iciCall->CopyFrom(pInlineInfo->retExpr, this);
21904 // Detach the GT_CALL node from the original statement by hanging a "nothing" node under it,
21905 // so that fgMorphStmts can remove the statement once we return from here.
21907 iciStmt->gtStmt.gtStmtExpr = gtNewNothingNode();
21910 // Prepend the statements that are needed before the inlined call.
21911 // Return the last statement that is prepended.
21913 GenTreePtr Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
21915 BasicBlock* block = inlineInfo->iciBlock;
21917 GenTreePtr callStmt = inlineInfo->iciStmt;
21918 noway_assert(callStmt->gtOper == GT_STMT);
21919 IL_OFFSETX callILOffset = callStmt->gtStmt.gtStmtILoffsx;
21921 GenTreePtr afterStmt = callStmt; // afterStmt is the place where the new statements should be inserted after.
21922 GenTreePtr newStmt;
21924 GenTreePtr call = inlineInfo->iciCall;
21925 noway_assert(call->gtOper == GT_CALL);
21930 printf("\nfgInlinePrependStatements for iciCall= ");
21936 // Prepend statements for any initialization / side effects
21938 InlArgInfo* inlArgInfo = inlineInfo->inlArgInfo;
21939 InlLclVarInfo* lclVarInfo = inlineInfo->lclVarInfo;
21943 // Create the null check statement (but not appending it to the statement list yet) for the 'this' pointer if necessary.
21944 // The NULL check should be done after "argument setup statements".
21945 // The only reason we move it here is for calling "impInlineFetchArg(0,..." to reserve a temp
21946 // for the "this" pointer.
21947 // Note: Here we no longer do the optimization that was done by thisDereferencedFirst in the old inliner.
21948 // However the assetionProp logic will remove any unecessary null checks that we may have added
21950 GenTreePtr nullcheck = nullptr;
21952 if (call->gtFlags & GTF_CALL_NULLCHECK && !inlineInfo->thisDereferencedFirst)
21954 // Call impInlineFetchArg to "reserve" a temp for the "this" pointer.
21955 nullcheck = gtNewOperNode(GT_IND, TYP_INT,
21956 impInlineFetchArg(0, inlArgInfo, lclVarInfo));
21957 nullcheck->gtFlags |= GTF_EXCEPT;
21959 // The NULL-check statement will be inserted to the statement list after those statements
21960 // that assign arguments to temps and before the actual body of the inlinee method.
21963 /* Treat arguments that had to be assigned to temps */
21964 if (inlineInfo->argCnt)
21970 printf("\nArguments setup:\n");
21974 for (unsigned argNum = 0; argNum < inlineInfo->argCnt; argNum++)
21976 if (inlArgInfo[argNum].argHasTmp)
21978 noway_assert(inlArgInfo[argNum].argIsUsed);
21980 /* argBashTmpNode is non-NULL iff the argument's value was
21981 referenced exactly once by the original IL. This offers an
21982 oppportunity to avoid an intermediate temp and just insert
21983 the original argument tree.
21985 However, if the temp node has been cloned somewhere while
21986 importing (e.g. when handling isinst or dup), or if the IL
21987 took the address of the argument, then argBashTmpNode will
21988 be set (because the value was only explicitly retrieved
21989 once) but the optimization cannot be applied.
21992 GenTreePtr argSingleUseNode = inlArgInfo[argNum].argBashTmpNode;
21994 if (argSingleUseNode &&
21995 !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) &&
21996 !inlArgInfo[argNum].argHasLdargaOp &&
21997 !inlArgInfo[argNum].argHasStargOp)
21999 // Change the temp in-place to the actual argument.
22000 // We currently do not support this for struct arguments, so it must not be a GT_OBJ.
22001 GenTree* argNode = inlArgInfo[argNum].argNode;
22002 assert(argNode->gtOper != GT_OBJ);
22003 argSingleUseNode->CopyFrom(argNode, this);
22008 /* Create the temp assignment for this argument */
22010 CORINFO_CLASS_HANDLE structHnd = DUMMY_INIT(0);
22012 if (varTypeIsStruct(lclVarInfo[argNum].lclTypeInfo))
22014 structHnd = gtGetStructHandleIfPresent(inlArgInfo[argNum].argNode);
22015 noway_assert(structHnd != NO_CLASS_HANDLE);
22018 // Unsafe value cls check is not needed for argTmpNum here since in-linee compiler instance would have
22019 // iterated over these and marked them accordingly.
22020 impAssignTempGen(inlArgInfo[argNum].argTmpNum,
22021 inlArgInfo[argNum].argNode,
22023 (unsigned)CHECK_SPILL_NONE,
22031 gtDispTree(afterStmt);
22037 else if (inlArgInfo[argNum].argIsByRefToStructLocal)
22043 /* The argument is either not used or a const or lcl var */
22045 noway_assert(!inlArgInfo[argNum].argIsUsed ||
22046 inlArgInfo[argNum].argIsInvariant ||
22047 inlArgInfo[argNum].argIsLclVar );
22049 /* Make sure we didnt change argNode's along the way, or else
22050 subsequent uses of the arg would have worked with the bashed value */
22051 if (inlArgInfo[argNum].argIsInvariant)
22053 assert(inlArgInfo[argNum].argNode->OperIsConst() ||
22054 inlArgInfo[argNum].argNode->gtOper == GT_ADDR);
22056 noway_assert((inlArgInfo[argNum].argIsLclVar == 0) ==
22057 (inlArgInfo[argNum].argNode->gtOper != GT_LCL_VAR || (inlArgInfo[argNum].argNode->gtFlags & GTF_GLOB_REF)));
22059 /* If the argument has side effects, append it */
22061 if (inlArgInfo[argNum].argHasSideEff)
22063 noway_assert(inlArgInfo[argNum].argIsUsed == false);
22065 if (inlArgInfo[argNum].argNode->gtOper == GT_OBJ ||
22066 inlArgInfo[argNum].argNode->gtOper == GT_MKREFANY)
22068 // Don't put GT_OBJ node under a GT_COMMA.
22069 // Codegen can't deal with it.
22070 // Just hang the address here in case there are side-effect.
22071 newStmt = gtNewStmt(gtUnusedValNode(inlArgInfo[argNum].argNode->gtOp.gtOp1), callILOffset);
22075 newStmt = gtNewStmt(gtUnusedValNode(inlArgInfo[argNum].argNode), callILOffset);
22077 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22082 gtDispTree(afterStmt);
22091 // Add the CCTOR check if asked for.
22092 // Note: We no longer do the optimization that is done before by staticAccessedFirstUsingHelper in the old inliner.
22093 // Therefore we might prepend redundant call to HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
22094 // before the inlined method body, even if a static field of this type was accessed in the inlinee
22095 // using a helper before any other observable side-effect.
22097 if (inlineInfo->inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_USE_HELPER)
22099 CORINFO_CONTEXT_HANDLE exactContext = inlineInfo->inlineCandidateInfo->exactContextHnd;
22100 CORINFO_CLASS_HANDLE exactClass;
22102 if (((SIZE_T)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
22104 exactClass = CORINFO_CLASS_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
22108 exactClass = info.compCompHnd->getMethodClass(CORINFO_METHOD_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK));
22111 tree = fgGetSharedCCtor(exactClass);
22112 newStmt = gtNewStmt(tree, callILOffset);
22113 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22116 // Insert the nullcheck statement now.
22119 newStmt = gtNewStmt(nullcheck, callILOffset);
22120 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22124 // Now zero-init inlinee locals
22127 CORINFO_METHOD_INFO* InlineeMethodInfo = InlineeCompiler->info.compMethodInfo;
22129 unsigned lclCnt = InlineeMethodInfo->locals.numArgs;
22131 // Does callee contain any zero-init local?
22132 if ((lclCnt != 0) &&
22133 (InlineeMethodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0)
22139 printf("\nZero init inlinee locals:\n");
22143 for (unsigned lclNum = 0; lclNum < lclCnt; lclNum++)
22145 unsigned tmpNum = inlineInfo->lclTmpNum[lclNum];
22147 // Is the local used at all?
22148 if (tmpNum != BAD_VAR_NUM)
22150 var_types lclTyp = (var_types)lvaTable[tmpNum].lvType;
22151 noway_assert(lclTyp == lclVarInfo[lclNum + inlineInfo->argCnt].lclTypeInfo);
22153 if (!varTypeIsStruct(lclTyp))
22155 // Unsafe value cls check is not needed here since in-linee compiler instance would have
22156 // iterated over locals and marked accordingly.
22157 impAssignTempGen(tmpNum,
22158 gtNewZeroConNode(genActualType(lclTyp)),
22160 (unsigned)CHECK_SPILL_NONE,
22167 CORINFO_CLASS_HANDLE structType = lclVarInfo[lclNum + inlineInfo->argCnt].lclVerTypeInfo.GetClassHandle();
22169 tree = gtNewOperNode(GT_ADDR, TYP_BYREF,
22170 gtNewLclvNode(tmpNum, lclTyp));
22172 tree = gtNewBlkOpNode(GT_INITBLK,
22174 gtNewIconNode(0), // Value
22175 gtNewIconNode(info.compCompHnd->getClassSize(structType)), // Size
22178 newStmt = gtNewStmt(tree, callILOffset);
22179 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22185 gtDispTree(afterStmt);
22196 /*****************************************************************************/
22198 Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTreePtr* pTree,
22201 GenTreePtr tree = *pTree;
22203 // If this tree doesn't have the EXCEPT flag set, then there is no
22204 // way any of the child nodes could throw, so we can stop recursing.
22205 if (!(tree->gtFlags & GTF_EXCEPT))
22207 return Compiler::WALK_SKIP_SUBTREES;
22210 switch (tree->gtOper)
22218 if (tree->gtOverflow()) {
22219 return Compiler::WALK_ABORT;
22224 if (tree->gtFlags & GTF_INX_RNGCHK) {
22225 return Compiler::WALK_ABORT;
22229 case GT_ARR_BOUNDS_CHECK:
22230 return Compiler::WALK_ABORT;
22236 return Compiler::WALK_CONTINUE;
22239 /*****************************************************************************/
22241 Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTreePtr* pTree,
22244 GenTreePtr tree = *pTree;
22246 if (tree->gtOper == GT_LCLHEAP) {
22247 return Compiler::WALK_ABORT;
22250 return Compiler::WALK_CONTINUE;
22253 /*****************************************************************************/
22255 Compiler::fgWalkResult Compiler::fgChkQmarkCB(GenTreePtr* pTree,
22258 GenTreePtr tree = *pTree;
22260 if (tree->gtOper == GT_QMARK) {
22261 return Compiler::WALK_ABORT;
22264 return Compiler::WALK_CONTINUE;
22268 void Compiler::fgLclFldAssign(unsigned lclNum)
22270 assert(varTypeIsStruct(lvaTable[lclNum].lvType));
22271 if (lvaTable[lclNum].lvPromoted && lvaTable[lclNum].lvFieldCnt > 1)
22273 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));