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 fgCalledCount = 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
335 #ifdef FEATURE_READYTORUN_COMPILER
336 if (opts.IsReadyToRun())
338 mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd);
340 CORINFO_RESOLVED_TOKEN resolvedToken;
341 resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd);
342 resolvedToken.tokenScope = info.compScopeHnd;
343 resolvedToken.token = currentMethodToken;
344 resolvedToken.tokenType = CORINFO_TOKENKIND_Method;
346 info.compCompHnd->resolveToken(&resolvedToken);
348 arg = impTokenToHandle(&resolvedToken);
353 arg = gtNewIconEmbMethHndNode(info.compMethodHnd);
356 GenTreeArgList* args = gtNewArgList(arg);
357 GenTreePtr call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, 0, args);
360 gtNewIconEmbHndNode((void*)&bbProfileBufferStart->ExecutionCount, nullptr, GTF_ICON_BBC_PTR);
361 GenTreePtr value = gtNewOperNode(GT_IND, TYP_INT, handle);
362 GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, value, gtNewIconNode(0, TYP_INT));
363 relop->gtFlags |= GTF_RELOP_QMARK; // TODO-Cleanup: [Simple] Move this to gtNewQmarkNode
364 GenTreePtr colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call);
365 GenTreePtr cond = gtNewQmarkNode(TYP_VOID, relop, colon);
366 stmt = gtNewStmt(cond);
369 fgEnsureFirstBBisScratch();
371 fgInsertStmtAtEnd(fgFirstBB, stmt);
374 /*****************************************************************************
376 * Create a basic block and append it to the current BB list.
379 BasicBlock* Compiler::fgNewBasicBlock(BBjumpKinds jumpKind)
381 // This method must not be called after the exception table has been
382 // constructed, because it doesn't not provide support for patching
383 // the exception table.
385 noway_assert(compHndBBtabCount == 0);
389 /* Allocate the block descriptor */
391 block = bbNewBasicBlock(jumpKind);
392 noway_assert(block->bbJumpKind == jumpKind);
394 /* Append the block to the end of the global basic block list */
398 fgLastBB->setNext(block);
403 block->bbPrev = nullptr;
411 /*****************************************************************************
413 * Ensures that fgFirstBB is a scratch BasicBlock that we have added.
414 * This can be used to add initialization code (without worrying
415 * about other blocks jumping to it).
417 * Callers have to be careful that they do not mess up the order of things
418 * added to fgEnsureFirstBBisScratch in a way as to change semantics.
421 void Compiler::fgEnsureFirstBBisScratch()
423 // This method does not update predecessor lists and so must only be called before they are computed.
424 assert(!fgComputePredsDone);
426 // Have we already allocated a scratch block?
428 if (fgFirstBBisScratch())
433 assert(fgFirstBBScratch == nullptr);
435 BasicBlock* block = bbNewBasicBlock(BBJ_NONE);
437 if (fgFirstBB != nullptr)
439 // If we have profile data the new block will inherit fgFirstBlock's weight
440 if (fgFirstBB->hasProfileWeight())
442 block->inheritWeight(fgFirstBB);
445 fgInsertBBbefore(fgFirstBB, block);
449 noway_assert(fgLastBB == nullptr);
454 noway_assert(fgLastBB != nullptr);
456 block->bbFlags |= (BBF_INTERNAL | BBF_IMPORTED);
458 fgFirstBBScratch = fgFirstBB;
463 printf("New scratch BB%02u\n", block->bbNum);
468 bool Compiler::fgFirstBBisScratch()
470 if (fgFirstBBScratch != nullptr)
472 assert(fgFirstBBScratch == fgFirstBB);
473 assert(fgFirstBBScratch->bbFlags & BBF_INTERNAL);
474 assert(fgFirstBBScratch->countOfInEdges() == 1);
476 // Normally, the first scratch block is a fall-through block. However, if the block after it was an empty
477 // BBJ_ALWAYS block, it might get removed, and the code that removes it will make the first scratch block
478 // a BBJ_ALWAYS block.
479 assert((fgFirstBBScratch->bbJumpKind == BBJ_NONE) || (fgFirstBBScratch->bbJumpKind == BBJ_ALWAYS));
489 bool Compiler::fgBBisScratch(BasicBlock* block)
491 return fgFirstBBisScratch() && (block == fgFirstBB);
495 // Check to see if block contains a statement but don't spend more than a certain
496 // budget doing this per method compiled.
497 // If the budget is exceeded, return 'answerOnBoundExceeded' as the answer.
499 bool Compiler::fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded /*= true*/)
501 const __int64 maxLinks = 1000000000;
503 assert(stmt->gtOper == GT_STMT);
505 __int64* numTraversed = &JitTls::GetCompiler()->compNumStatementLinksTraversed;
507 if (*numTraversed > maxLinks)
509 return answerOnBoundExceeded;
512 GenTree* curr = block->firstStmt();
522 return curr != nullptr;
526 //------------------------------------------------------------------------
527 // fgInsertStmtAtBeg: Insert the given tree or statement at the start of the given basic block.
530 // block - The block into which 'stmt' will be inserted.
531 // stmt - The statement to be inserted.
534 // Returns the new (potentially) GT_STMT node.
537 // If 'stmt' is not already a statement, a new statement is created from it.
538 // We always insert phi statements at the beginning.
539 // In other cases, if there are any phi assignments and/or an assignment of
540 // the GT_CATCH_ARG, we insert after those.
542 GenTreePtr Compiler::fgInsertStmtAtBeg(BasicBlock* block, GenTreePtr stmt)
544 if (stmt->gtOper != GT_STMT)
546 stmt = gtNewStmt(stmt);
549 GenTreePtr list = block->firstStmt();
551 if (!stmt->IsPhiDefnStmt())
553 GenTreePtr insertBeforeStmt = block->FirstNonPhiDefOrCatchArgAsg();
554 if (insertBeforeStmt != nullptr)
556 return fgInsertStmtBefore(block, insertBeforeStmt, stmt);
558 else if (list != nullptr)
560 return fgInsertStmtAtEnd(block, stmt);
562 // Otherwise, we will simply insert at the beginning, below.
565 /* The new tree will now be the first one of the block */
567 block->bbTreeList = stmt;
570 /* Are there any statements in the block? */
576 /* There is at least one statement already */
579 noway_assert(last && last->gtNext == nullptr);
581 /* Insert the statement in front of the first one */
588 /* The block was completely empty */
596 /*****************************************************************************
598 * Insert the given tree or statement at the end of the given basic block.
599 * Returns the (potentially) new GT_STMT node.
600 * If the block can be a conditional block, use fgInsertStmtNearEnd.
603 GenTreeStmt* Compiler::fgInsertStmtAtEnd(BasicBlock* block, GenTreePtr node)
605 GenTreePtr list = block->firstStmt();
608 if (node->gtOper != GT_STMT)
610 stmt = gtNewStmt(node);
614 stmt = node->AsStmt();
617 assert(stmt->gtNext == nullptr); // We don't set it, and it needs to be this after the insert
623 /* There is at least one statement already */
626 noway_assert(last && last->gtNext == nullptr);
628 /* Append the statement after the last one */
636 /* The block is completely empty */
638 block->bbTreeList = stmt;
645 /*****************************************************************************
647 * Insert the given tree or statement at the end of the given basic block, but before
648 * the GT_JTRUE, if present.
649 * Returns the (potentially) new GT_STMT node.
652 GenTreeStmt* Compiler::fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node)
656 // This routine can only be used when in tree order.
657 assert(fgOrder == FGOrderTree);
659 if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH) || (block->bbJumpKind == BBJ_RETURN))
661 if (node->gtOper != GT_STMT)
663 stmt = gtNewStmt(node);
667 stmt = node->AsStmt();
670 GenTreeStmt* first = block->firstStmt();
672 GenTreeStmt* last = block->lastStmt();
673 noway_assert(last && last->gtNext == nullptr);
674 GenTreePtr after = last->gtPrev;
677 if (block->bbJumpKind == BBJ_COND)
679 noway_assert(last->gtStmtExpr->gtOper == GT_JTRUE);
681 else if (block->bbJumpKind == BBJ_RETURN)
683 noway_assert((last->gtStmtExpr->gtOper == GT_RETURN) || (last->gtStmtExpr->gtOper == GT_JMP) ||
684 // BBJ_RETURN blocks in functions returning void do not get a GT_RETURN node if they
685 // have a .tail prefix (even if canTailCall returns false for these calls)
686 // code:Compiler::impImportBlockCode (search for the RET: label)
687 // Ditto for real tail calls (all code after them has been removed)
688 ((last->gtStmtExpr->gtOper == GT_CALL) &&
689 ((info.compRetType == TYP_VOID) || last->gtStmtExpr->AsCall()->IsTailCall())));
693 noway_assert(block->bbJumpKind == BBJ_SWITCH);
694 noway_assert(last->gtStmtExpr->gtOper == GT_SWITCH);
698 /* Append 'stmt' before 'last' */
705 /* There is only one stmt in the block */
707 block->bbTreeList = stmt;
712 noway_assert(after && (after->gtNext == last));
714 /* Append 'stmt' after 'after' */
716 after->gtNext = stmt;
717 stmt->gtPrev = after;
724 return fgInsertStmtAtEnd(block, node);
728 /*****************************************************************************
730 * Insert the given statement "stmt" after GT_STMT node "insertionPoint".
731 * Returns the newly inserted GT_STMT node.
732 * Note that the gtPrev list of statement nodes is circular, but the gtNext list is not.
735 GenTreePtr Compiler::fgInsertStmtAfter(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt)
737 assert(block->bbTreeList != nullptr);
738 noway_assert(insertionPoint->gtOper == GT_STMT);
739 noway_assert(stmt->gtOper == GT_STMT);
740 assert(fgBlockContainsStatementBounded(block, insertionPoint));
741 assert(!fgBlockContainsStatementBounded(block, stmt, false));
743 if (insertionPoint->gtNext == nullptr)
745 // Ok, we want to insert after the last statement of the block.
746 stmt->gtNext = nullptr;
747 stmt->gtPrev = insertionPoint;
749 insertionPoint->gtNext = stmt;
751 // Update the backward link of the first statement of the block
752 // to point to the new last statement.
753 assert(block->bbTreeList->gtPrev == insertionPoint);
754 block->bbTreeList->gtPrev = stmt;
758 stmt->gtNext = insertionPoint->gtNext;
759 stmt->gtPrev = insertionPoint;
761 insertionPoint->gtNext->gtPrev = stmt;
762 insertionPoint->gtNext = stmt;
768 // Insert the given tree or statement before GT_STMT node "insertionPoint".
769 // Returns the newly inserted GT_STMT node.
771 GenTreePtr Compiler::fgInsertStmtBefore(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt)
773 assert(block->bbTreeList != nullptr);
774 noway_assert(insertionPoint->gtOper == GT_STMT);
775 noway_assert(stmt->gtOper == GT_STMT);
776 assert(fgBlockContainsStatementBounded(block, insertionPoint));
777 assert(!fgBlockContainsStatementBounded(block, stmt, false));
779 if (insertionPoint == block->bbTreeList)
781 // We're inserting before the first statement in the block.
782 GenTreePtr list = block->bbTreeList;
783 GenTreePtr last = list->gtPrev;
788 block->bbTreeList = stmt;
793 stmt->gtNext = insertionPoint;
794 stmt->gtPrev = insertionPoint->gtPrev;
796 insertionPoint->gtPrev->gtNext = stmt;
797 insertionPoint->gtPrev = stmt;
803 /*****************************************************************************
805 * Insert the list of statements stmtList after the stmtAfter in block.
806 * Return the last statement stmtList.
809 GenTreePtr Compiler::fgInsertStmtListAfter(BasicBlock* block, // the block where stmtAfter is in.
810 GenTreePtr stmtAfter, // the statement where stmtList should be inserted
814 // Currently we can handle when stmtAfter and stmtList are non-NULL. This makes everything easy.
815 noway_assert(stmtAfter && stmtAfter->gtOper == GT_STMT);
816 noway_assert(stmtList && stmtList->gtOper == GT_STMT);
818 GenTreePtr stmtLast = stmtList->gtPrev; // Last statement in a non-empty list, circular in the gtPrev list.
819 noway_assert(stmtLast);
820 noway_assert(stmtLast->gtNext == nullptr);
822 GenTreePtr stmtNext = stmtAfter->gtNext;
826 stmtAfter->gtNext = stmtList;
827 stmtList->gtPrev = stmtAfter;
828 block->bbTreeList->gtPrev = stmtLast;
832 stmtAfter->gtNext = stmtList;
833 stmtList->gtPrev = stmtAfter;
835 stmtLast->gtNext = stmtNext;
836 stmtNext->gtPrev = stmtLast;
840 noway_assert(block->bbTreeList == nullptr || block->bbTreeList->gtPrev->gtNext == nullptr);
846 Removes a block from the return block list
848 void Compiler::fgRemoveReturnBlock(BasicBlock* block)
850 if (fgReturnBlocks == nullptr)
855 if (fgReturnBlocks->block == block)
857 // It's the 1st entry, assign new head of list.
858 fgReturnBlocks = fgReturnBlocks->next;
862 for (BasicBlockList* retBlocks = fgReturnBlocks; retBlocks->next != nullptr; retBlocks = retBlocks->next)
864 if (retBlocks->next->block == block)
866 // Found it; splice it out.
867 retBlocks->next = retBlocks->next->next;
873 //------------------------------------------------------------------------
874 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
877 // block -- The block with the predecessor list to operate on.
878 // blockPred -- The predecessor block to find in the predecessor list.
881 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
882 // then returns nullptr.
885 // -- This only works on the full predecessor lists, not the cheap preds lists.
887 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred)
890 noway_assert(blockPred);
891 assert(!fgCheapPredsValid);
895 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
897 if (blockPred == pred->flBlock)
906 //------------------------------------------------------------------------
907 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
908 // Also returns the address of the pointer that points to this edge, to make it possible to remove this edge from the
909 // predecessor list without doing another linear search over the edge list.
912 // block -- The block with the predecessor list to operate on.
913 // blockPred -- The predecessor block to find in the predecessor list.
914 // ptrToPred -- Out parameter: set to the address of the pointer that points to the returned predecessor edge.
917 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
918 // then returns nullptr.
921 // -- This only works on the full predecessor lists, not the cheap preds lists.
923 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred)
928 assert(!fgCheapPredsValid);
930 flowList** predPrevAddr;
933 for (predPrevAddr = &block->bbPreds, pred = *predPrevAddr; pred != nullptr;
934 predPrevAddr = &pred->flNext, pred = *predPrevAddr)
936 if (blockPred == pred->flBlock)
938 *ptrToPred = predPrevAddr;
943 *ptrToPred = nullptr;
947 //------------------------------------------------------------------------
948 // fgSpliceOutPred: Removes a predecessor edge for a block from the predecessor list.
951 // block -- The block with the predecessor list to operate on.
952 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
955 // The flowList edge that was removed.
958 // -- "blockPred" must be a predecessor block of "block".
959 // -- This simply splices out the flowList object. It doesn't update block ref counts, handle duplicate counts, etc.
960 // For that, use fgRemoveRefPred() or fgRemoveAllRefPred().
961 // -- This only works on the full predecessor lists, not the cheap preds lists.
964 // -- This must walk the predecessor list to find the block in question. If the predecessor edge
965 // is found using fgGetPredForBlock(), consider using the version that hands back the predecessor pointer
966 // address instead, to avoid this search.
967 // -- Marks fgModified = true, since the flow graph has changed.
969 flowList* Compiler::fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred)
971 assert(!fgCheapPredsValid);
972 noway_assert(block->bbPreds);
974 flowList* oldEdge = nullptr;
976 // Is this the first block in the pred list?
977 if (blockPred == block->bbPreds->flBlock)
979 oldEdge = block->bbPreds;
980 block->bbPreds = block->bbPreds->flNext;
985 for (pred = block->bbPreds; (pred->flNext != nullptr) && (blockPred != pred->flNext->flBlock);
990 oldEdge = pred->flNext;
991 if (oldEdge == nullptr)
993 noway_assert(!"Should always find the blockPred");
995 pred->flNext = pred->flNext->flNext;
998 // Any changes to the flow graph invalidate the dominator sets.
1004 //------------------------------------------------------------------------
1005 // fgAddRefPred: Increment block->bbRefs by one and add "blockPred" to the predecessor list of "block".
1008 // block -- A block to operate on.
1009 // blockPred -- The predecessor block to add to the predecessor list.
1010 // oldEdge -- Optional (default: nullptr). If non-nullptr, and a new edge is created (and the dup count
1011 // of an existing edge is not just incremented), the edge weights are copied from this edge.
1012 // initializingPreds -- Optional (default: false). Only set to "true" when the initial preds computation is
1016 // The flow edge representing the predecessor.
1019 // -- This only works on the full predecessor lists, not the cheap preds lists.
1022 // -- block->bbRefs is incremented by one to account for the reduction in incoming edges.
1023 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
1024 // the preds themselves aren't touched.
1025 // -- fgModified is set if a new flow edge is created (but not if an existing flow edge dup count is incremented),
1026 // indicating that the flow graph shape has changed.
1028 flowList* Compiler::fgAddRefPred(BasicBlock* block,
1029 BasicBlock* blockPred,
1030 flowList* oldEdge /* = nullptr */,
1031 bool initializingPreds /* = false */)
1033 assert(block != nullptr);
1034 assert(blockPred != nullptr);
1038 if (!fgComputePredsDone && !initializingPreds)
1040 // Why is someone trying to update the preds list when the preds haven't been created?
1041 // Ignore them! This can happen when fgMorph is called before the preds list is created.
1045 assert(!fgCheapPredsValid);
1047 flowList* flow = fgGetPredForBlock(block, blockPred);
1051 noway_assert(flow->flDupCount > 0);
1056 flow = new (this, CMK_FlowList) flowList();
1058 #if MEASURE_BLOCK_SIZE
1059 genFlowNodeCnt += 1;
1060 genFlowNodeSize += sizeof(flowList);
1061 #endif // MEASURE_BLOCK_SIZE
1063 // Any changes to the flow graph invalidate the dominator sets.
1066 // Keep the predecessor list in lowest to highest bbNum order
1067 // This allows us to discover the loops in optFindNaturalLoops
1068 // from innermost to outermost.
1070 // TODO-Throughput: This search is quadratic if you have many jumps
1071 // to the same target. We need to either not bother sorting for
1072 // debuggable code, or sort in optFindNaturalLoops, or better, make
1073 // the code in optFindNaturalLoops not depend on order.
1075 flowList** listp = &block->bbPreds;
1076 while (*listp && ((*listp)->flBlock->bbNum < blockPred->bbNum))
1078 listp = &(*listp)->flNext;
1081 flow->flNext = *listp;
1084 flow->flBlock = blockPred;
1085 flow->flDupCount = 1;
1087 if (fgHaveValidEdgeWeights)
1089 // We are creating an edge from blockPred to block
1090 // and we have already computed the edge weights, so
1091 // we will try to setup this new edge with valid edge weights.
1093 if (oldEdge != nullptr)
1095 // If our caller has given us the old edge weights
1096 // then we will use them.
1098 flow->flEdgeWeightMin = oldEdge->flEdgeWeightMin;
1099 flow->flEdgeWeightMax = oldEdge->flEdgeWeightMax;
1103 // Set the max edge weight to be the minimum of block's or blockPred's weight
1105 flow->flEdgeWeightMax = min(block->bbWeight, blockPred->bbWeight);
1107 // If we are inserting a conditional block the minimum weight is zero,
1108 // otherwise it is the same as the edge's max weight.
1109 if (blockPred->NumSucc() > 1)
1111 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1115 flow->flEdgeWeightMin = flow->flEdgeWeightMax;
1121 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1122 flow->flEdgeWeightMax = BB_MAX_WEIGHT;
1128 //------------------------------------------------------------------------
1129 // fgRemoveRefPred: Decrements the reference count of a predecessor edge from "blockPred" to "block",
1130 // removing the edge if it is no longer necessary.
1133 // block -- A block to operate on.
1134 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1137 // If the flow edge was removed (the predecessor has a "dup count" of 1),
1138 // returns the flow graph edge that was removed. This means "blockPred" is no longer a predecessor of "block".
1139 // Otherwise, returns nullptr. This means that "blockPred" is still a predecessor of "block" (because "blockPred"
1140 // is a switch with multiple cases jumping to "block", or a BBJ_COND with both conditional and fall-through
1141 // paths leading to "block").
1144 // -- "blockPred" must be a predecessor block of "block".
1145 // -- This only works on the full predecessor lists, not the cheap preds lists.
1148 // -- block->bbRefs is decremented by one to account for the reduction in incoming edges.
1149 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
1150 // the preds themselves aren't touched.
1151 // -- fgModified is set if a flow edge is removed (but not if an existing flow edge dup count is decremented),
1152 // indicating that the flow graph shape has changed.
1154 flowList* Compiler::fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred)
1156 noway_assert(block != nullptr);
1157 noway_assert(blockPred != nullptr);
1159 noway_assert(block->countOfInEdges() > 0);
1162 // Do nothing if we haven't calculated the predecessor list yet.
1163 // Yes, this does happen.
1164 // For example the predecessor lists haven't been created yet when we do fgMorph.
1165 // But fgMorph calls fgFoldConditional, which in turn calls fgRemoveRefPred.
1166 if (!fgComputePredsDone)
1171 assert(!fgCheapPredsValid);
1173 flowList** ptrToPred;
1174 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1176 noway_assert(pred->flDupCount > 0);
1180 if (pred->flDupCount == 0)
1182 // Splice out the predecessor edge since it's no longer necessary.
1183 *ptrToPred = pred->flNext;
1185 // Any changes to the flow graph invalidate the dominator sets.
1196 //------------------------------------------------------------------------
1197 // fgRemoveAllRefPreds: Removes a predecessor edge from one block to another, no matter what the "dup count" is.
1200 // block -- A block to operate on.
1201 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1204 // Returns the flow graph edge that was removed. The dup count on the edge is no longer valid.
1207 // -- "blockPred" must be a predecessor block of "block".
1208 // -- This only works on the full predecessor lists, not the cheap preds lists.
1211 // block->bbRefs is decremented to account for the reduction in incoming edges.
1213 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred)
1215 assert(block != nullptr);
1216 assert(blockPred != nullptr);
1217 assert(fgComputePredsDone);
1218 assert(!fgCheapPredsValid);
1219 assert(block->countOfInEdges() > 0);
1221 flowList** ptrToPred;
1222 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1223 assert(pred != nullptr);
1224 assert(pred->flDupCount > 0);
1226 assert(block->bbRefs >= pred->flDupCount);
1227 block->bbRefs -= pred->flDupCount;
1229 // Now splice out the predecessor edge.
1230 *ptrToPred = pred->flNext;
1232 // Any changes to the flow graph invalidate the dominator sets.
1238 //------------------------------------------------------------------------
1239 // fgRemoveAllRefPreds: Remove a predecessor edge, given the address of a pointer to it in the
1240 // predecessor list, no matter what the "dup count" is.
1243 // block -- A block with the predecessor list to operate on.
1244 // ptrToPred -- The address of a pointer to the predecessor to remove.
1247 // The removed predecessor edge. The dup count on the edge is no longer valid.
1250 // -- The predecessor edge must be in the predecessor list for "block".
1251 // -- This only works on the full predecessor lists, not the cheap preds lists.
1254 // block->bbRefs is decremented by the dup count of the predecessor edge, to account for the reduction in incoming
1257 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred)
1259 assert(block != nullptr);
1260 assert(ptrToPred != nullptr);
1261 assert(fgComputePredsDone);
1262 assert(!fgCheapPredsValid);
1263 assert(block->countOfInEdges() > 0);
1265 flowList* pred = *ptrToPred;
1266 assert(pred != nullptr);
1267 assert(pred->flDupCount > 0);
1269 assert(block->bbRefs >= pred->flDupCount);
1270 block->bbRefs -= pred->flDupCount;
1272 // Now splice out the predecessor edge.
1273 *ptrToPred = pred->flNext;
1275 // Any changes to the flow graph invalidate the dominator sets.
1282 Removes all the appearances of block as predecessor of others
1285 void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
1287 assert(!fgCheapPredsValid);
1289 PREFIX_ASSUME(block != nullptr);
1293 switch (block->bbJumpKind)
1295 case BBJ_CALLFINALLY:
1296 if (!(block->bbFlags & BBF_RETLESS_CALL))
1298 assert(block->isBBCallAlwaysPair());
1300 /* The block after the BBJ_CALLFINALLY block is not reachable */
1301 bNext = block->bbNext;
1303 /* bNext is an unreachable BBJ_ALWAYS block */
1304 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
1306 while (bNext->countOfInEdges() > 0)
1308 fgRemoveRefPred(bNext, bNext->bbPreds->flBlock);
1316 case BBJ_EHCATCHRET:
1318 /* Update the predecessor list for 'block->bbJumpDest' and 'block->bbNext' */
1319 fgRemoveRefPred(block->bbJumpDest, block);
1321 if (block->bbJumpKind != BBJ_COND)
1326 /* If BBJ_COND fall through */
1331 /* Update the predecessor list for 'block->bbNext' */
1332 fgRemoveRefPred(block->bbNext, block);
1335 case BBJ_EHFILTERRET:
1337 block->bbJumpDest->bbRefs++; // To compensate the bbRefs-- inside fgRemoveRefPred
1338 fgRemoveRefPred(block->bbJumpDest, block);
1341 case BBJ_EHFINALLYRET:
1343 /* Remove block as the predecessor of the bbNext of all
1344 BBJ_CALLFINALLY blocks calling this finally. No need
1345 to look for BBJ_CALLFINALLY for fault handlers. */
1347 unsigned hndIndex = block->getHndIndex();
1348 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
1350 if (ehDsc->HasFinallyHandler())
1354 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
1356 BasicBlock* finBeg = ehDsc->ebdHndBeg;
1358 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
1360 if ((bcall->bbFlags & BBF_REMOVED) || bcall->bbJumpKind != BBJ_CALLFINALLY ||
1361 bcall->bbJumpDest != finBeg)
1366 assert(bcall->isBBCallAlwaysPair());
1367 fgRemoveRefPred(bcall->bbNext, block);
1379 unsigned jumpCnt = block->bbJumpSwt->bbsCount;
1380 BasicBlock** jumpTab = block->bbJumpSwt->bbsDstTab;
1384 fgRemoveRefPred(*jumpTab, block);
1385 } while (++jumpTab, --jumpCnt);
1391 noway_assert(!"Block doesn't have a valid bbJumpKind!!!!");
1396 /*****************************************************************************
1397 * fgChangeSwitchBlock:
1399 * We have a BBJ_SWITCH jump at 'oldSwitchBlock' and we want to move this
1400 * switch jump over to 'newSwitchBlock'. All of the blocks that are jumped
1401 * to from jumpTab[] need to have their predecessor lists updated by removing
1402 * the 'oldSwitchBlock' and adding 'newSwitchBlock'.
1405 void Compiler::fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock)
1407 noway_assert(oldSwitchBlock != nullptr);
1408 noway_assert(newSwitchBlock != nullptr);
1409 noway_assert(oldSwitchBlock->bbJumpKind == BBJ_SWITCH);
1411 unsigned jumpCnt = oldSwitchBlock->bbJumpSwt->bbsCount;
1412 BasicBlock** jumpTab = oldSwitchBlock->bbJumpSwt->bbsDstTab;
1416 // Walk the switch's jump table, updating the predecessor for each branch.
1417 for (i = 0; i < jumpCnt; i++)
1419 BasicBlock* bJump = jumpTab[i];
1420 noway_assert(bJump != nullptr);
1422 // Note that if there are duplicate branch targets in the switch jump table,
1423 // fgRemoveRefPred()/fgAddRefPred() will do the right thing: the second and
1424 // subsequent duplicates will simply subtract from and add to the duplicate
1425 // count (respectively).
1428 // Remove the old edge [oldSwitchBlock => bJump]
1430 fgRemoveRefPred(bJump, oldSwitchBlock);
1433 // Create the new edge [newSwitchBlock => bJump]
1435 fgAddRefPred(bJump, newSwitchBlock);
1438 if (m_switchDescMap != nullptr)
1440 SwitchUniqueSuccSet uniqueSuccSet;
1442 // If already computed and cached the unique descriptors for the old block, let's
1443 // update those for the new block.
1444 if (m_switchDescMap->Lookup(oldSwitchBlock, &uniqueSuccSet))
1446 m_switchDescMap->Set(newSwitchBlock, uniqueSuccSet);
1450 fgInvalidateSwitchDescMapEntry(newSwitchBlock);
1452 fgInvalidateSwitchDescMapEntry(oldSwitchBlock);
1456 /*****************************************************************************
1457 * fgReplaceSwitchJumpTarget:
1459 * We have a BBJ_SWITCH at 'blockSwitch' and we want to replace all entries
1460 * in the jumpTab[] such that so that jumps that previously went to
1461 * 'oldTarget' now go to 'newTarget'.
1462 * We also must update the predecessor lists for 'oldTarget' and 'newPred'.
1465 void Compiler::fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget)
1467 noway_assert(blockSwitch != nullptr);
1468 noway_assert(newTarget != nullptr);
1469 noway_assert(oldTarget != nullptr);
1470 noway_assert(blockSwitch->bbJumpKind == BBJ_SWITCH);
1472 // For the jump targets values that match oldTarget of our BBJ_SWITCH
1473 // replace predecessor 'blockSwitch' with 'newTarget'
1476 unsigned jumpCnt = blockSwitch->bbJumpSwt->bbsCount;
1477 BasicBlock** jumpTab = blockSwitch->bbJumpSwt->bbsDstTab;
1481 // Walk the switch's jump table looking for blocks to update the preds for
1484 if (jumpTab[i] == oldTarget) // We will update when jumpTab[i] matches
1486 // Remove the old edge [oldTarget from blockSwitch]
1488 fgRemoveAllRefPreds(oldTarget, blockSwitch);
1491 // Change the jumpTab entry to branch to the new location
1493 jumpTab[i] = newTarget;
1496 // Create the new edge [newTarget from blockSwitch]
1498 flowList* newEdge = fgAddRefPred(newTarget, blockSwitch);
1500 // Now set the correct value of newEdge->flDupCount
1501 // and replace any other jumps in jumpTab[] that go to oldTarget.
1506 if (jumpTab[i] == oldTarget)
1509 // We also must update this entry in the jumpTab
1511 jumpTab[i] = newTarget;
1512 newTarget->bbRefs++;
1515 // Increment the flDupCount
1517 newEdge->flDupCount++;
1519 i++; // Check the next entry in jumpTab[]
1522 // Maintain, if necessary, the set of unique targets of "block."
1523 UpdateSwitchTableTarget(blockSwitch, oldTarget, newTarget);
1525 // Make sure the new target has the proper bits set for being a branch target.
1526 newTarget->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
1528 return; // We have replaced the jumps to oldTarget with newTarget
1530 i++; // Check the next entry in jumpTab[] for a match
1532 noway_assert(!"Did not find oldTarget in jumpTab[]");
1535 //------------------------------------------------------------------------
1536 // Compiler::fgReplaceJumpTarget: For a given block, replace the target 'oldTarget' with 'newTarget'.
1539 // block - the block in which a jump target will be replaced.
1540 // newTarget - the new branch target of the block.
1541 // oldTarget - the old branch target of the block.
1544 // 1. Only branches are changed: BBJ_ALWAYS, the non-fallthrough path of BBJ_COND, BBJ_SWITCH, etc.
1545 // We ignore other block types.
1546 // 2. Only the first target found is updated. If there are multiple ways for a block
1547 // to reach 'oldTarget' (e.g., multiple arms of a switch), only the first one found is changed.
1548 // 3. The predecessor lists are not changed.
1549 // 4. The switch table "unique successor" cache is invalidated.
1551 // This function is most useful early, before the full predecessor lists have been computed.
1553 void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget)
1555 assert(block != nullptr);
1557 switch (block->bbJumpKind)
1559 case BBJ_CALLFINALLY:
1562 case BBJ_EHCATCHRET:
1563 case BBJ_EHFILTERRET:
1564 case BBJ_LEAVE: // This function will be called before import, so we still have BBJ_LEAVE
1566 if (block->bbJumpDest == oldTarget)
1568 block->bbJumpDest = newTarget;
1573 case BBJ_EHFINALLYRET:
1580 jumpCnt = block->bbJumpSwt->bbsCount;
1581 BasicBlock** jumpTab;
1582 jumpTab = block->bbJumpSwt->bbsDstTab;
1584 for (unsigned i = 0; i < jumpCnt; i++)
1586 if (jumpTab[i] == oldTarget)
1588 jumpTab[i] = newTarget;
1595 assert(!"Block doesn't have a valid bbJumpKind!!!!");
1601 /*****************************************************************************
1602 * Updates the predecessor list for 'block' by replacing 'oldPred' with 'newPred'.
1603 * Note that a block can only appear once in the preds list (for normal preds, not
1604 * cheap preds): if a predecessor has multiple ways to get to this block, then
1605 * flDupCount will be >1, but the block will still appear exactly once. Thus, this
1606 * function assumes that all branches from the predecessor (practically, that all
1607 * switch cases that target this block) are changed to branch from the new predecessor,
1608 * with the same dup count.
1610 * Note that the block bbRefs is not changed, since 'block' has the same number of
1611 * references as before, just from a different predecessor block.
1614 void Compiler::fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred)
1616 noway_assert(block != nullptr);
1617 noway_assert(oldPred != nullptr);
1618 noway_assert(newPred != nullptr);
1619 assert(!fgCheapPredsValid);
1623 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1625 if (oldPred == pred->flBlock)
1627 pred->flBlock = newPred;
1633 /*****************************************************************************
1635 * Returns true if block b1 dominates block b2.
1638 bool Compiler::fgDominate(BasicBlock* b1, BasicBlock* b2)
1640 noway_assert(fgDomsComputed);
1641 assert(!fgCheapPredsValid);
1644 // If the fgModified flag is false then we made some modifications to
1645 // the flow graph, like adding a new block or changing a conditional branch
1646 // into an unconditional branch.
1648 // We can continue to use the dominator and reachable information to
1649 // unmark loops as long as we haven't renumbered the blocks or we aren't
1650 // asking for information about a new block
1653 if (b2->bbNum > fgDomBBcount)
1660 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1662 if (!fgDominate(b1, pred->flBlock))
1668 return b2->bbPreds != nullptr;
1671 if (b1->bbNum > fgDomBBcount)
1673 // if b1 is a loop preheader and Succ is its only successor, then all predecessors of
1674 // Succ either are b1 itself or are dominated by Succ. Under these conditions, b1
1675 // dominates b2 if and only if Succ dominates b2 (or if b2 == b1, but we already tested
1677 if (b1->bbFlags & BBF_LOOP_PREHEADER)
1679 noway_assert(b1->bbFlags & BBF_INTERNAL);
1680 noway_assert(b1->bbJumpKind == BBJ_NONE);
1681 return fgDominate(b1->bbNext, b2);
1684 // unknown dominators; err on the safe side and return false
1688 /* Check if b1 dominates b2 */
1689 unsigned numA = b1->bbNum;
1690 noway_assert(numA <= fgDomBBcount);
1691 unsigned numB = b2->bbNum;
1692 noway_assert(numB <= fgDomBBcount);
1694 // 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)
1695 // in the dominator tree. Turns out that can be translated as:
1697 // A dom B <-> preorder(A) <= preorder(B) && postorder(A) >= postorder(B)
1699 // where the equality holds when you ask if A dominates itself.
1701 fgDomTreePreOrder[numA] <= fgDomTreePreOrder[numB] && fgDomTreePostOrder[numA] >= fgDomTreePostOrder[numB];
1706 /*****************************************************************************
1708 * Returns true if block b1 can reach block b2.
1711 bool Compiler::fgReachable(BasicBlock* b1, BasicBlock* b2)
1713 noway_assert(fgDomsComputed);
1714 assert(!fgCheapPredsValid);
1717 // If the fgModified flag is false then we made some modifications to
1718 // the flow graph, like adding a new block or changing a conditional branch
1719 // into an unconditional branch.
1721 // We can continue to use the dominator and reachable information to
1722 // unmark loops as long as we haven't renumbered the blocks or we aren't
1723 // asking for information about a new block
1726 if (b2->bbNum > fgDomBBcount)
1733 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1735 if (fgReachable(b1, pred->flBlock))
1744 if (b1->bbNum > fgDomBBcount)
1746 noway_assert(b1->bbJumpKind == BBJ_NONE || b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND);
1748 if (b1->bbFallsThrough() && fgReachable(b1->bbNext, b2))
1753 if (b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND)
1755 return fgReachable(b1->bbJumpDest, b2);
1761 /* Check if b1 can reach b2 */
1762 assert(fgReachabilitySetsValid);
1763 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
1764 return BlockSetOps::IsMember(this, b2->bbReach, b1->bbNum);
1767 /*****************************************************************************
1768 * Update changed flow graph information.
1770 * If the flow graph has changed, we need to recompute various information if we want to use
1774 void Compiler::fgUpdateChangedFlowGraph()
1776 // We need to clear this so we don't hit an assert calling fgRenumberBlocks().
1777 fgDomsComputed = false;
1779 JITDUMP("\nRenumbering the basic blocks for fgUpdateChangeFlowGraph\n");
1783 fgComputeEnterBlocksSet();
1784 fgComputeReachabilitySets();
1788 /*****************************************************************************
1789 * Compute the bbReach sets.
1791 * This can be called to recompute the bbReach sets after the flow graph changes, such as when the
1792 * number of BasicBlocks change (and thus, the BlockSet epoch changes).
1794 * Finally, this also sets the BBF_GC_SAFE_POINT flag on blocks.
1796 * Assumes the predecessor lists are correct.
1798 * TODO-Throughput: This algorithm consumes O(n^2) because we're using dense bitsets to
1799 * represent reachability. While this yields O(1) time queries, it bloats the memory usage
1800 * for large code. We can do better if we try to approach reachability by
1801 * computing the strongly connected components of the flow graph. That way we only need
1802 * linear memory to label every block with its SCC.
1805 void Compiler::fgComputeReachabilitySets()
1807 assert(fgComputePredsDone);
1808 assert(!fgCheapPredsValid);
1811 fgReachabilitySetsValid = false;
1816 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1818 // Initialize the per-block bbReach sets. (Note that we can't just call BlockSetOps::ClearD()
1819 // when re-running this computation, because if the epoch changes, the size and representation of the
1820 // sets might change).
1821 block->bbReach = BlockSetOps::MakeEmpty(this);
1823 /* Mark block as reaching itself */
1824 BlockSetOps::AddElemD(this, block->bbReach, block->bbNum);
1827 /* Find the reachable blocks */
1828 // Also, set BBF_GC_SAFE_POINT.
1831 BlockSet BLOCKSET_INIT_NOCOPY(newReach, BlockSetOps::MakeEmpty(this));
1836 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1838 BlockSetOps::Assign(this, newReach, block->bbReach);
1840 bool predGcSafe = (block->bbPreds != nullptr); // Do all of our predecessor blocks have a GC safe bit?
1842 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1844 BasicBlock* predBlock = pred->flBlock;
1846 /* Union the predecessor's reachability set into newReach */
1847 BlockSetOps::UnionD(this, newReach, predBlock->bbReach);
1849 if (!(predBlock->bbFlags & BBF_GC_SAFE_POINT))
1857 block->bbFlags |= BBF_GC_SAFE_POINT;
1860 if (!BlockSetOps::Equal(this, newReach, block->bbReach))
1862 BlockSetOps::Assign(this, block->bbReach, newReach);
1871 printf("\nAfter computing reachability sets:\n");
1875 fgReachabilitySetsValid = true;
1879 /*****************************************************************************
1880 * Compute the entry blocks set.
1882 * Initialize fgEnterBlks to the set of blocks for which we don't have explicit control
1883 * flow edges. These are the entry basic block and each of the EH handler blocks.
1884 * For ARM, also include the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
1885 * to avoid creating "retless" calls, since we need the BBJ_ALWAYS for the purpose
1886 * of unwinding, even if the call doesn't return (due to an explicit throw, for example).
1889 void Compiler::fgComputeEnterBlocksSet()
1892 fgEnterBlksSetValid = false;
1895 fgEnterBlks = BlockSetOps::MakeEmpty(this);
1897 /* Now set the entry basic block */
1898 BlockSetOps::AddElemD(this, fgEnterBlks, fgFirstBB->bbNum);
1899 assert(fgFirstBB->bbNum == 1);
1901 if (compHndBBtabCount > 0)
1903 /* Also 'or' in the handler basic blocks */
1906 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
1908 if (HBtab->HasFilter())
1910 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdFilter->bbNum);
1912 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdHndBeg->bbNum);
1916 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1917 // TODO-ARM-Cleanup: The ARM code here to prevent creating retless calls by adding the BBJ_ALWAYS
1918 // to the enter blocks is a bit of a compromise, because sometimes the blocks are already reachable,
1919 // and it messes up DFS ordering to have them marked as enter block. We should prevent the
1920 // creation of retless calls some other way.
1921 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
1923 if (block->bbJumpKind == BBJ_CALLFINALLY)
1925 assert(block->isBBCallAlwaysPair());
1927 // Don't remove the BBJ_ALWAYS block that is only here for the unwinder. It might be dead
1928 // if the finally is no-return, so mark it as an entry point.
1929 BlockSetOps::AddElemD(this, fgEnterBlks, block->bbNext->bbNum);
1932 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1937 printf("Enter blocks: ");
1938 BLOCKSET_ITER_INIT(this, iter, fgEnterBlks, bbNum);
1939 while (iter.NextElem(this, &bbNum))
1941 printf("BB%02u ", bbNum);
1948 fgEnterBlksSetValid = true;
1952 /*****************************************************************************
1953 * Remove unreachable blocks.
1955 * Return true if any unreachable blocks were removed.
1958 bool Compiler::fgRemoveUnreachableBlocks()
1960 assert(!fgCheapPredsValid);
1961 assert(fgReachabilitySetsValid);
1963 bool hasLoops = false;
1964 bool hasUnreachableBlocks = false;
1967 /* Record unreachable blocks */
1968 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1970 /* Internal throw blocks are also reachable */
1971 if (fgIsThrowHlpBlk(block))
1975 else if (block == genReturnBB)
1977 // Don't remove statements for the genReturnBB block, as we might have special hookups there.
1978 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
1979 // the profiler hookup needs to have the "void GT_RETURN" statement
1980 // to properly set the info.compProfilerCallback flag.
1985 // If any of the entry blocks can reach this block, then we skip it.
1986 if (!BlockSetOps::IsEmptyIntersection(this, fgEnterBlks, block->bbReach))
1992 // Remove all the code for the block
1993 fgUnreachableBlock(block);
1995 // Make sure that the block was marked as removed */
1996 noway_assert(block->bbFlags & BBF_REMOVED);
1998 // Some blocks mark the end of trys and catches
1999 // and can't be removed. We convert these into
2000 // empty blocks of type BBJ_THROW
2002 if (block->bbFlags & BBF_DONT_REMOVE)
2004 bool bIsBBCallAlwaysPair = block->isBBCallAlwaysPair();
2006 /* Unmark the block as removed, */
2007 /* clear BBF_INTERNAL as well and set BBJ_IMPORTED */
2009 block->bbFlags &= ~(BBF_REMOVED | BBF_INTERNAL | BBF_NEEDS_GCPOLL);
2010 block->bbFlags |= BBF_IMPORTED;
2011 block->bbJumpKind = BBJ_THROW;
2012 block->bbSetRunRarely();
2014 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2015 // If this is a <BBJ_CALLFINALLY, BBJ_ALWAYS> pair, we have to clear BBF_FINALLY_TARGET flag on
2016 // the target node (of BBJ_ALWAYS) since BBJ_CALLFINALLY node is getting converted to a BBJ_THROW.
2017 if (bIsBBCallAlwaysPair)
2019 noway_assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
2020 fgClearFinallyTargetBit(block->bbNext->bbJumpDest);
2022 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2026 /* We have to call fgRemoveBlock next */
2027 hasUnreachableBlocks = true;
2033 // if (block->isRunRarely())
2035 if (block->bbJumpKind == BBJ_RETURN)
2040 /* Set BBF_LOOP_HEAD if we have backwards branches to this block */
2042 unsigned blockNum = block->bbNum;
2043 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
2045 BasicBlock* predBlock = pred->flBlock;
2046 if (blockNum <= predBlock->bbNum)
2048 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
2053 /* If block can reach predBlock then we have a loop head */
2054 if (BlockSetOps::IsMember(this, predBlock->bbReach, blockNum))
2058 /* Set the BBF_LOOP_HEAD flag */
2059 block->bbFlags |= BBF_LOOP_HEAD;
2066 fgHasLoops = hasLoops;
2068 if (hasUnreachableBlocks)
2070 // Now remove the unreachable blocks
2071 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2073 // If we mark the block with BBF_REMOVED then
2074 // we need to call fgRemovedBlock() on it
2076 if (block->bbFlags & BBF_REMOVED)
2078 fgRemoveBlock(block, true);
2080 // When we have a BBJ_CALLFINALLY, BBJ_ALWAYS pair; fgRemoveBlock will remove
2081 // both blocks, so we must advance 1 extra place in the block list
2083 if (block->isBBCallAlwaysPair())
2085 block = block->bbNext;
2091 return hasUnreachableBlocks;
2094 /*****************************************************************************
2096 * Function called to compute the dominator and reachable sets.
2098 * Assumes the predecessor lists are computed and correct.
2101 void Compiler::fgComputeReachability()
2106 printf("*************** In fgComputeReachability\n");
2109 fgVerifyHandlerTab();
2111 // Make sure that the predecessor lists are accurate
2112 assert(fgComputePredsDone);
2113 fgDebugCheckBBlist();
2116 /* Create a list of all BBJ_RETURN blocks. The head of the list is 'fgReturnBlocks'. */
2117 fgReturnBlocks = nullptr;
2119 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2121 // If this is a BBJ_RETURN block, add it to our list of all BBJ_RETURN blocks. This list is only
2122 // used to find return blocks.
2123 if (block->bbJumpKind == BBJ_RETURN)
2125 fgReturnBlocks = new (this, CMK_Reachability) BasicBlockList(block, fgReturnBlocks);
2129 // Compute reachability and then delete blocks determined to be unreachable. If we delete blocks, we
2130 // need to loop, as that might have caused more blocks to become unreachable. This can happen in the
2131 // case where a call to a finally is unreachable and deleted (maybe the call to the finally is
2132 // preceded by a throw or an infinite loop), making the blocks following the finally unreachable.
2133 // However, all EH entry blocks are considered global entry blocks, causing the blocks following the
2134 // call to the finally to stay rooted, until a second round of reachability is done.
2135 // The dominator algorithm expects that all blocks can be reached from the fgEnterBlks set.
2136 unsigned passNum = 1;
2140 // Just to be paranoid, avoid infinite loops; fall back to minopts.
2143 noway_assert(!"Too many unreachable block removal loops");
2146 /* Walk the flow graph, reassign block numbers to keep them in ascending order */
2147 JITDUMP("\nRenumbering the basic blocks for fgComputeReachability pass #%u\n", passNum);
2152 // Compute fgEnterBlks
2155 fgComputeEnterBlocksSet();
2161 fgComputeReachabilitySets();
2164 // Use reachability information to delete unreachable blocks.
2165 // Also, determine if the flow graph has loops and set 'fgHasLoops' accordingly.
2166 // Set the BBF_LOOP_HEAD flag on the block target of backwards branches.
2169 changed = fgRemoveUnreachableBlocks();
2176 printf("\nAfter computing reachability:\n");
2177 fgDispBasicBlocks(verboseTrees);
2181 fgVerifyHandlerTab();
2182 fgDebugCheckBBlist(true);
2186 // Now, compute the dominators
2192 /** In order to be able to compute dominance, we need to first get a DFS reverse post order sort on the basic flow graph
2193 * for the dominance algorithm to operate correctly. The reason why we need the DFS sort is because
2194 * we will build the dominance sets using the partial order induced by the DFS sorting. With this
2195 * precondition not holding true, the algorithm doesn't work properly.
2197 void Compiler::fgDfsInvPostOrder()
2199 // NOTE: This algorithm only pays attention to the actual blocks. It ignores the imaginary entry block.
2201 // visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid
2203 BlockSet BLOCKSET_INIT_NOCOPY(visited, BlockSetOps::MakeEmpty(this));
2205 // We begin by figuring out which basic blocks don't have incoming edges and mark them as
2206 // start nodes. Later on we run the recursive algorithm for each node that we
2207 // mark in this step.
2208 BlockSet_ValRet_T startNodes = fgDomFindStartNodes();
2210 // Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is
2211 // an incoming edge into the block).
2212 assert(fgEnterBlksSetValid);
2214 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2216 // BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2218 // This causes problems on ARM, because we for BBJ_CALLFINALLY/BBJ_ALWAYS pairs, we add the BBJ_ALWAYS
2219 // to the enter blocks set to prevent flow graph optimizations from removing it and creating retless call finallies
2220 // (BBF_RETLESS_CALL). This leads to an incorrect DFS ordering in some cases, because we start the recursive walk
2221 // from the BBJ_ALWAYS, which is reachable from other blocks. A better solution would be to change ARM to avoid
2222 // creating retless calls in a different way, not by adding BBJ_ALWAYS to fgEnterBlks.
2224 // So, let us make sure at least fgFirstBB is still there, even if it participates in a loop.
2225 BlockSetOps::AddElemD(this, startNodes, 1);
2226 assert(fgFirstBB->bbNum == 1);
2228 BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2231 assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum));
2233 // Call the flowgraph DFS traversal helper.
2234 unsigned postIndex = 1;
2235 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2237 // If the block has no predecessors, and we haven't already visited it (because it's in fgEnterBlks but also
2238 // reachable from the first block), go ahead and traverse starting from this block.
2239 if (BlockSetOps::IsMember(this, startNodes, block->bbNum) &&
2240 !BlockSetOps::IsMember(this, visited, block->bbNum))
2242 fgDfsInvPostOrderHelper(block, visited, &postIndex);
2246 // After the DFS reverse postorder is completed, we must have visited all the basic blocks.
2247 noway_assert(postIndex == fgBBcount + 1);
2248 noway_assert(fgBBNumMax == fgBBcount);
2253 printf("\nAfter doing a post order traversal of the BB graph, this is the ordering:\n");
2254 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2256 printf("%02u -> BB%02u\n", i, fgBBInvPostOrder[i]->bbNum);
2263 BlockSet_ValRet_T Compiler::fgDomFindStartNodes()
2268 // startNodes :: A set that represents which basic blocks in the flow graph don't have incoming edges.
2269 // We begin assuming everything is a start block and remove any block that is being referenced by another in its
2272 BlockSet BLOCKSET_INIT_NOCOPY(startNodes, BlockSetOps::MakeFull(this));
2274 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2276 unsigned cSucc = block->NumSucc(this);
2277 for (j = 0; j < cSucc; ++j)
2279 BasicBlock* succ = block->GetSucc(j, this);
2280 BlockSetOps::RemoveElemD(this, startNodes, succ->bbNum);
2287 printf("\nDominator computation start blocks (those blocks with no incoming edges):\n");
2288 BLOCKSET_ITER_INIT(this, iter, startNodes, bbNum);
2289 while (iter.NextElem(this, &bbNum))
2291 printf("BB%02u ", bbNum);
2300 //------------------------------------------------------------------------
2301 // fgDfsInvPostOrderHelper: Helper to assign post-order numbers to blocks.
2304 // block - The starting entry block
2305 // visited - The set of visited blocks
2306 // count - Pointer to the Dfs counter
2309 // Compute a non-recursive DFS traversal of the flow graph using an
2310 // evaluation stack to assign post-order numbers.
2312 void Compiler::fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count)
2314 // Assume we haven't visited this node yet (callers ensure this).
2315 assert(!BlockSetOps::IsMember(this, visited, block->bbNum));
2317 // Allocate a local stack to hold the DFS traversal actions necessary
2318 // to compute pre/post-ordering of the control flowgraph.
2319 ArrayStack<DfsBlockEntry> stack(this);
2321 // Push the first block on the stack to seed the traversal.
2322 stack.Push(DfsBlockEntry(DSS_Pre, block));
2323 // Flag the node we just visited to avoid backtracking.
2324 BlockSetOps::AddElemD(this, visited, block->bbNum);
2326 // The search is terminated once all the actions have been processed.
2327 while (stack.Height() != 0)
2329 DfsBlockEntry current = stack.Pop();
2330 BasicBlock* currentBlock = current.dfsBlock;
2332 if (current.dfsStackState == DSS_Pre)
2334 // This is a pre-visit that corresponds to the first time the
2335 // node is encountered in the spanning tree and receives pre-order
2336 // numberings. By pushing the post-action on the stack here we
2337 // are guaranteed to only process it after all of its successors
2338 // pre and post actions are processed.
2339 stack.Push(DfsBlockEntry(DSS_Post, currentBlock));
2341 unsigned cSucc = currentBlock->NumSucc(this);
2342 for (unsigned j = 0; j < cSucc; ++j)
2344 BasicBlock* succ = currentBlock->GetSucc(j, this);
2346 // If this is a node we haven't seen before, go ahead and process
2347 if (!BlockSetOps::IsMember(this, visited, succ->bbNum))
2349 // Push a pre-visit action for this successor onto the stack and
2350 // mark it as visited in case this block has multiple successors
2351 // to the same node (multi-graph).
2352 stack.Push(DfsBlockEntry(DSS_Pre, succ));
2353 BlockSetOps::AddElemD(this, visited, succ->bbNum);
2359 // This is a post-visit that corresponds to the last time the
2360 // node is visited in the spanning tree and only happens after
2361 // all descendents in the spanning tree have had pre and post
2364 assert(current.dfsStackState == DSS_Post);
2366 unsigned invCount = fgBBcount - *count + 1;
2367 assert(1 <= invCount && invCount <= fgBBNumMax);
2368 fgBBInvPostOrder[invCount] = currentBlock;
2369 currentBlock->bbDfsNum = invCount;
2375 void Compiler::fgComputeDoms()
2377 assert(!fgCheapPredsValid);
2382 printf("*************** In fgComputeDoms\n");
2385 fgVerifyHandlerTab();
2387 // Make sure that the predecessor lists are accurate.
2388 // Also check that the blocks are properly, densely numbered (so calling fgRenumberBlocks is not necessary).
2389 fgDebugCheckBBlist(true);
2391 // Assert things related to the BlockSet epoch.
2392 assert(fgBBcount == fgBBNumMax);
2393 assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);
2396 BlockSet BLOCKSET_INIT_NOCOPY(processedBlks, BlockSetOps::MakeEmpty(this));
2398 fgBBInvPostOrder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1];
2399 memset(fgBBInvPostOrder, 0, sizeof(BasicBlock*) * (fgBBNumMax + 1));
2401 fgDfsInvPostOrder();
2402 noway_assert(fgBBInvPostOrder[0] == nullptr);
2404 // flRoot and bbRoot represent an imaginary unique entry point in the flow graph.
2405 // All the orphaned EH blocks and fgFirstBB will temporarily have its predecessors list
2406 // (with bbRoot as the only basic block in it) set as flRoot.
2407 // Later on, we clear their predecessors and let them to be nullptr again.
2408 // Since we number basic blocks starting at one, the imaginary entry block is conveniently numbered as zero.
2412 bbRoot.bbPreds = nullptr;
2414 bbRoot.bbIDom = &bbRoot;
2415 bbRoot.bbDfsNum = 0;
2417 flRoot.flNext = nullptr;
2418 flRoot.flBlock = &bbRoot;
2420 fgBBInvPostOrder[0] = &bbRoot;
2422 // Mark both bbRoot and fgFirstBB processed
2423 BlockSetOps::AddElemD(this, processedBlks, 0); // bbRoot == block #0
2424 BlockSetOps::AddElemD(this, processedBlks, 1); // fgFirstBB == block #1
2425 assert(fgFirstBB->bbNum == 1);
2427 // Special case fgFirstBB to say its IDom is bbRoot.
2428 fgFirstBB->bbIDom = &bbRoot;
2430 BasicBlock* block = nullptr;
2432 for (block = fgFirstBB->bbNext; block != nullptr; block = block->bbNext)
2434 // If any basic block has no predecessors then we flag it as processed and temporarily
2435 // mark its precedessor list to be flRoot. This makes the flowgraph connected,
2436 // a precondition that is needed by the dominance algorithm to operate properly.
2437 if (block->bbPreds == nullptr)
2439 block->bbPreds = &flRoot;
2440 block->bbIDom = &bbRoot;
2441 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2445 block->bbIDom = nullptr;
2449 // Mark the EH blocks as entry blocks and also flag them as processed.
2450 if (compHndBBtabCount > 0)
2454 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
2456 if (HBtab->HasFilter())
2458 HBtab->ebdFilter->bbIDom = &bbRoot;
2459 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdFilter->bbNum);
2461 HBtab->ebdHndBeg->bbIDom = &bbRoot;
2462 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdHndBeg->bbNum);
2466 // Now proceed to compute the immediate dominators for each basic block.
2467 bool changed = true;
2471 for (unsigned i = 1; i <= fgBBNumMax;
2472 ++i) // Process each actual block; don't process the imaginary predecessor block.
2474 flowList* first = nullptr;
2475 BasicBlock* newidom = nullptr;
2476 block = fgBBInvPostOrder[i];
2478 // If we have a block that has bbRoot as its bbIDom
2479 // it means we flag it as processed and as an entry block so
2480 // in this case we're all set.
2481 if (block->bbIDom == &bbRoot)
2486 // Pick up the first processed predecesor of the current block.
2487 for (first = block->bbPreds; first != nullptr; first = first->flNext)
2489 if (BlockSetOps::IsMember(this, processedBlks, first->flBlock->bbNum))
2494 noway_assert(first != nullptr);
2496 // We assume the first processed predecessor will be the
2497 // immediate dominator and then compute the forward flow analysis.
2498 newidom = first->flBlock;
2499 for (flowList* p = block->bbPreds; p != nullptr; p = p->flNext)
2501 if (p->flBlock == first->flBlock)
2505 if (p->flBlock->bbIDom != nullptr)
2507 // fgIntersectDom is basically the set intersection between
2508 // the dominance sets of the new IDom and the current predecessor
2509 // Since the nodes are ordered in DFS inverse post order and
2510 // IDom induces a tree, fgIntersectDom actually computes
2511 // the lowest common ancestor in the dominator tree.
2512 newidom = fgIntersectDom(p->flBlock, newidom);
2516 // If the Immediate dominator changed, assign the new one
2517 // to the current working basic block.
2518 if (block->bbIDom != newidom)
2520 noway_assert(newidom != nullptr);
2521 block->bbIDom = newidom;
2524 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2528 // As stated before, once we have computed immediate dominance we need to clear
2529 // all the basic blocks whose predecessor list was set to flRoot. This
2530 // reverts that and leaves the blocks the same as before.
2531 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2533 if (block->bbPreds == &flRoot)
2535 block->bbPreds = nullptr;
2539 fgCompDominatedByExceptionalEntryBlocks();
2551 fgDomBBcount = fgBBcount;
2552 assert(fgBBcount == fgBBNumMax);
2553 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
2555 fgDomsComputed = true;
2558 void Compiler::fgBuildDomTree()
2566 printf("\nInside fgBuildDomTree\n");
2570 // domTree :: The dominance tree represented using adjacency lists. We use BasicBlockList to represent edges.
2571 // Indexed by basic block number.
2572 unsigned bbArraySize = fgBBNumMax + 1;
2573 BasicBlockList** domTree = new (this, CMK_DominatorMemory) BasicBlockList*[bbArraySize];
2575 fgDomTreePreOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2576 fgDomTreePostOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2578 // Initialize all the data structures.
2579 for (i = 0; i < bbArraySize; ++i)
2581 domTree[i] = nullptr;
2582 fgDomTreePreOrder[i] = fgDomTreePostOrder[i] = 0;
2585 // Build the dominance tree.
2586 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2588 // If the immediate dominator is not the imaginary root (bbRoot)
2589 // we proceed to append this block to the children of the dominator node.
2590 if (block->bbIDom->bbNum != 0)
2592 int bbNum = block->bbIDom->bbNum;
2593 domTree[bbNum] = new (this, CMK_DominatorMemory) BasicBlockList(block, domTree[bbNum]);
2597 // This means this block had bbRoot set as its IDom. We clear it out
2598 // and convert the tree back to a forest.
2599 block->bbIDom = nullptr;
2606 printf("\nAfter computing the Dominance Tree:\n");
2607 fgDispDomTree(domTree);
2611 // Get the bitset that represents the roots of the dominance tree.
2612 // Something to note here is that the dominance tree has been converted from a forest to a tree
2613 // by using the bbRoot trick on fgComputeDoms. The reason we have a forest instead of a real tree
2614 // is because we treat the EH blocks as entry nodes so the real dominance tree is not necessarily connected.
2615 BlockSet_ValRet_T domTreeEntryNodes = fgDomTreeEntryNodes(domTree);
2617 // The preorder and postorder numbers.
2618 // We start from 1 to match the bbNum ordering.
2619 unsigned preNum = 1;
2620 unsigned postNum = 1;
2622 // There will be nodes in the dominance tree that will not be reachable:
2623 // the catch blocks that return since they don't have any predecessor.
2624 // For that matter we'll keep track of how many nodes we can
2625 // reach and assert at the end that we visited all of them.
2626 unsigned domTreeReachable = fgBBcount;
2628 // Once we have the dominance tree computed, we need to traverse it
2629 // to get the preorder and postorder numbers for each node. The purpose of
2630 // this is to achieve O(1) queries for of the form A dominates B.
2631 for (i = 1; i <= fgBBNumMax; ++i)
2633 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2635 if (domTree[i] == nullptr)
2637 // If this is an entry node but there's no children on this
2638 // node, it means it's unreachable so we decrement the reachable
2644 // Otherwise, we do a DFS traversal of the dominator tree.
2645 fgTraverseDomTree(i, domTree, &preNum, &postNum);
2650 noway_assert(preNum == domTreeReachable + 1);
2651 noway_assert(postNum == domTreeReachable + 1);
2653 // Once we have all the reachable nodes numbered, we proceed to
2654 // assign numbers to the non-reachable ones, just assign incrementing
2655 // values. We must reach fgBBcount at the end.
2657 for (i = 1; i <= fgBBNumMax; ++i)
2659 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2661 if (domTree[i] == nullptr)
2663 fgDomTreePreOrder[i] = preNum++;
2664 fgDomTreePostOrder[i] = postNum++;
2669 noway_assert(preNum == fgBBNumMax + 1);
2670 noway_assert(postNum == fgBBNumMax + 1);
2671 noway_assert(fgDomTreePreOrder[0] == 0); // Unused first element
2672 noway_assert(fgDomTreePostOrder[0] == 0); // Unused first element
2677 printf("\nAfter traversing the dominance tree:\n");
2678 printf("PreOrder:\n");
2679 for (i = 1; i <= fgBBNumMax; ++i)
2681 printf("BB%02u : %02u\n", i, fgDomTreePreOrder[i]);
2683 printf("PostOrder:\n");
2684 for (i = 1; i <= fgBBNumMax; ++i)
2686 printf("BB%02u : %02u\n", i, fgDomTreePostOrder[i]);
2692 BlockSet_ValRet_T Compiler::fgDomTreeEntryNodes(BasicBlockList** domTree)
2694 // domTreeEntryNodes :: Set that represents which basic blocks are roots of the dominator forest.
2696 BlockSet BLOCKSET_INIT_NOCOPY(domTreeEntryNodes, BlockSetOps::MakeFull(this));
2698 // First of all we need to find all the roots of the dominance forest.
2700 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2702 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2704 BlockSetOps::RemoveElemD(this, domTreeEntryNodes, current->block->bbNum);
2708 return domTreeEntryNodes;
2712 void Compiler::fgDispDomTree(BasicBlockList** domTree)
2714 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2716 if (domTree[i] != nullptr)
2718 printf("BB%02u : ", i);
2719 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2721 assert(current->block);
2722 printf("BB%02u ", current->block->bbNum);
2731 //------------------------------------------------------------------------
2732 // fgTraverseDomTree: Assign pre/post-order numbers to the dominator tree.
2735 // bbNum - The basic block number of the starting block
2736 // domTree - The dominator tree (as child block lists)
2737 // preNum - Pointer to the pre-number counter
2738 // postNum - Pointer to the post-number counter
2741 // Runs a non-recursive DFS traversal of the dominator tree using an
2742 // evaluation stack to assign pre-order and post-order numbers.
2743 // These numberings are used to provide constant time lookup for
2744 // ancestor/descendent tests between pairs of nodes in the tree.
2746 void Compiler::fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum)
2748 noway_assert(bbNum <= fgBBNumMax);
2750 // If the block preorder number is not zero it means we already visited
2751 // that node, so we skip it.
2752 if (fgDomTreePreOrder[bbNum] == 0)
2754 // If this is the first time we visit this node, both preorder and postnumber
2755 // values must be zero.
2756 noway_assert(fgDomTreePostOrder[bbNum] == 0);
2758 // Allocate a local stack to hold the Dfs traversal actions necessary
2759 // to compute pre/post-ordering of the dominator tree.
2760 ArrayStack<DfsNumEntry> stack(this);
2762 // Push the first entry number on the stack to seed the traversal.
2763 stack.Push(DfsNumEntry(DSS_Pre, bbNum));
2765 // The search is terminated once all the actions have been processed.
2766 while (stack.Height() != 0)
2768 DfsNumEntry current = stack.Pop();
2769 unsigned currentNum = current.dfsNum;
2771 if (current.dfsStackState == DSS_Pre)
2773 // This pre-visit action corresponds to the first time the
2774 // node is encountered during the spanning traversal.
2775 noway_assert(fgDomTreePreOrder[currentNum] == 0);
2776 noway_assert(fgDomTreePostOrder[currentNum] == 0);
2778 // Assign the preorder number on the first visit.
2779 fgDomTreePreOrder[currentNum] = (*preNum)++;
2781 // Push this nodes post-action on the stack such that all successors
2782 // pre-order visits occur before this nodes post-action. We will assign
2783 // its post-order numbers when we pop off the stack.
2784 stack.Push(DfsNumEntry(DSS_Post, currentNum));
2786 // For each child in the dominator tree process its pre-actions.
2787 for (BasicBlockList* child = domTree[currentNum]; child != nullptr; child = child->next)
2789 unsigned childNum = child->block->bbNum;
2791 // This is a tree so never could have been visited
2792 assert(fgDomTreePreOrder[childNum] == 0);
2794 // Push the successor in the dominator tree for pre-actions.
2795 stack.Push(DfsNumEntry(DSS_Pre, childNum));
2800 // This post-visit action corresponds to the last time the node
2801 // is encountered and only after all descendents in the spanning
2802 // tree have had pre and post-order numbers assigned.
2804 assert(current.dfsStackState == DSS_Post);
2805 assert(fgDomTreePreOrder[currentNum] != 0);
2806 assert(fgDomTreePostOrder[currentNum] == 0);
2808 // Now assign this nodes post-order number.
2809 fgDomTreePostOrder[currentNum] = (*postNum)++;
2815 // This code finds the lowest common ancestor in the
2816 // dominator tree between two basic blocks. The LCA in the Dominance tree
2817 // represents the closest dominator between the two basic blocks. Used to
2818 // adjust the IDom value in fgComputDoms.
2819 BasicBlock* Compiler::fgIntersectDom(BasicBlock* a, BasicBlock* b)
2821 BasicBlock* finger1 = a;
2822 BasicBlock* finger2 = b;
2823 while (finger1 != finger2)
2825 while (finger1->bbDfsNum > finger2->bbDfsNum)
2827 finger1 = finger1->bbIDom;
2829 while (finger2->bbDfsNum > finger1->bbDfsNum)
2831 finger2 = finger2->bbIDom;
2837 // Return a BlockSet containing all the blocks that dominate 'block'.
2838 BlockSet_ValRet_T Compiler::fgGetDominatorSet(BasicBlock* block)
2840 assert(block != nullptr);
2842 BlockSet BLOCKSET_INIT_NOCOPY(domSet, BlockSetOps::MakeEmpty(this));
2846 BlockSetOps::AddElemD(this, domSet, block->bbNum);
2847 if (block == block->bbIDom)
2849 break; // We found a cycle in the IDom list, so we're done.
2851 block = block->bbIDom;
2852 } while (block != nullptr);
2857 /*****************************************************************************
2859 * fgComputeCheapPreds: Function called to compute the BasicBlock::bbCheapPreds lists.
2861 * No other block data is changed (e.g., bbRefs, bbFlags).
2863 * The cheap preds lists are similar to the normal (bbPreds) predecessor lists, but are cheaper to
2864 * compute and store, as follows:
2865 * 1. A flow edge is typed BasicBlockList, which only has a block pointer and 'next' pointer. It doesn't
2866 * have weights or a dup count.
2867 * 2. The preds list for a block is not sorted by block number.
2868 * 3. The predecessors of the block following a BBJ_CALLFINALLY (the corresponding BBJ_ALWAYS,
2869 * for normal, non-retless calls to the finally) are not computed.
2870 * 4. The cheap preds lists will contain duplicates if a single switch table has multiple branches
2871 * to the same block. Thus, we don't spend the time looking for duplicates for every edge we insert.
2873 void Compiler::fgComputeCheapPreds()
2875 noway_assert(!fgComputePredsDone); // We can't do this if we've got the full preds.
2876 noway_assert(fgFirstBB != nullptr);
2883 printf("\n*************** In fgComputeCheapPreds()\n");
2884 fgDispBasicBlocks();
2889 // Clear out the cheap preds lists.
2892 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2894 switch (block->bbJumpKind)
2897 fgAddCheapPred(block->bbJumpDest, block);
2898 fgAddCheapPred(block->bbNext, block);
2901 case BBJ_CALLFINALLY:
2902 case BBJ_LEAVE: // If fgComputeCheapPreds is called before all blocks are imported, BBJ_LEAVE blocks are
2903 // still in the BB list.
2905 case BBJ_EHCATCHRET:
2906 fgAddCheapPred(block->bbJumpDest, block);
2910 fgAddCheapPred(block->bbNext, block);
2913 case BBJ_EHFILTERRET:
2914 // Connect end of filter to catch handler.
2915 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
2916 // fgComputeCheapPreds before fgImport on an ill-formed program; the problem will be detected in
2918 if (block->bbJumpDest != nullptr)
2920 fgAddCheapPred(block->bbJumpDest, block);
2926 jumpCnt = block->bbJumpSwt->bbsCount;
2927 BasicBlock** jumpTab;
2928 jumpTab = block->bbJumpSwt->bbsDstTab;
2932 fgAddCheapPred(*jumpTab, block);
2933 } while (++jumpTab, --jumpCnt);
2937 case BBJ_EHFINALLYRET: // It's expensive to compute the preds for this case, so we don't for the cheap
2944 noway_assert(!"Unexpected bbJumpKind");
2949 fgCheapPredsValid = true;
2954 printf("\n*************** After fgComputeCheapPreds()\n");
2955 fgDispBasicBlocks();
2961 /*****************************************************************************
2962 * Add 'blockPred' to the cheap predecessor list of 'block'.
2965 void Compiler::fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred)
2967 assert(!fgComputePredsDone);
2968 assert(block != nullptr);
2969 assert(blockPred != nullptr);
2971 block->bbCheapPreds = new (this, CMK_FlowList) BasicBlockList(blockPred, block->bbCheapPreds);
2973 #if MEASURE_BLOCK_SIZE
2974 genFlowNodeCnt += 1;
2975 genFlowNodeSize += sizeof(BasicBlockList);
2976 #endif // MEASURE_BLOCK_SIZE
2979 /*****************************************************************************
2980 * Remove 'blockPred' from the cheap predecessor list of 'block'.
2981 * If there are duplicate edges, only remove one of them.
2983 void Compiler::fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred)
2985 assert(!fgComputePredsDone);
2986 assert(fgCheapPredsValid);
2988 flowList* oldEdge = nullptr;
2990 assert(block != nullptr);
2991 assert(blockPred != nullptr);
2992 assert(block->bbCheapPreds != nullptr);
2994 /* Is this the first block in the pred list? */
2995 if (blockPred == block->bbCheapPreds->block)
2997 block->bbCheapPreds = block->bbCheapPreds->next;
3001 BasicBlockList* pred;
3002 for (pred = block->bbCheapPreds; pred->next != nullptr; pred = pred->next)
3004 if (blockPred == pred->next->block)
3009 noway_assert(pred->next != nullptr); // we better have found it!
3010 pred->next = pred->next->next; // splice it out
3014 void Compiler::fgRemovePreds()
3016 C_ASSERT(offsetof(BasicBlock, bbPreds) ==
3017 offsetof(BasicBlock, bbCheapPreds)); // bbPreds and bbCheapPreds are at the same place in a union,
3018 C_ASSERT(sizeof(((BasicBlock*)nullptr)->bbPreds) ==
3019 sizeof(((BasicBlock*)nullptr)->bbCheapPreds)); // and are the same size. So, this function removes both.
3021 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
3023 block->bbPreds = nullptr;
3025 fgComputePredsDone = false;
3026 fgCheapPredsValid = false;
3029 /*****************************************************************************
3031 * Function called to compute the bbPreds lists.
3033 void Compiler::fgComputePreds()
3035 noway_assert(fgFirstBB);
3042 printf("\n*************** In fgComputePreds()\n");
3043 fgDispBasicBlocks();
3048 // reset the refs count for each basic block
3050 for (block = fgFirstBB; block; block = block->bbNext)
3055 /* the first block is always reachable! */
3056 fgFirstBB->bbRefs = 1;
3058 /* Treat the initial block as a jump target */
3059 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3063 for (block = fgFirstBB; block; block = block->bbNext)
3065 switch (block->bbJumpKind)
3067 case BBJ_CALLFINALLY:
3068 if (!(block->bbFlags & BBF_RETLESS_CALL))
3070 assert(block->isBBCallAlwaysPair());
3072 /* Mark the next block as being a jump target,
3073 since the call target will return there */
3074 PREFIX_ASSUME(block->bbNext != nullptr);
3075 block->bbNext->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
3080 case BBJ_LEAVE: // Sometimes fgComputePreds is called before all blocks are imported, so BBJ_LEAVE
3081 // blocks are still in the BB list.
3084 case BBJ_EHCATCHRET:
3086 /* Mark the jump dest block as being a jump target */
3087 block->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3089 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3091 /* Is the next block reachable? */
3093 if (block->bbJumpKind != BBJ_COND)
3098 noway_assert(block->bbNext);
3100 /* Fall through, the next block is also reachable */
3105 fgAddRefPred(block->bbNext, block, nullptr, true);
3108 case BBJ_EHFILTERRET:
3110 // Connect end of filter to catch handler.
3111 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
3112 // fgComputePreds before fgImport on an ill-formed program; the problem will be detected in fgImport.
3113 if (block->bbJumpDest != nullptr)
3115 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3119 case BBJ_EHFINALLYRET:
3121 /* Connect the end of the finally to the successor of
3122 the call to this finally */
3124 if (!block->hasHndIndex())
3126 NO_WAY("endfinally outside a finally/fault block.");
3129 unsigned hndIndex = block->getHndIndex();
3130 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3132 if (!ehDsc->HasFinallyOrFaultHandler())
3134 NO_WAY("endfinally outside a finally/fault block.");
3137 if (ehDsc->HasFinallyHandler())
3139 // Find all BBJ_CALLFINALLY that branched to this finally handler.
3142 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3144 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3145 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3147 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3152 noway_assert(bcall->isBBCallAlwaysPair());
3153 fgAddRefPred(bcall->bbNext, block, nullptr, true);
3165 jumpCnt = block->bbJumpSwt->bbsCount;
3166 BasicBlock** jumpTab;
3167 jumpTab = block->bbJumpSwt->bbsDstTab;
3171 /* Mark the target block as being a jump target */
3172 (*jumpTab)->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3174 fgAddRefPred(*jumpTab, block, nullptr, true);
3175 } while (++jumpTab, --jumpCnt);
3180 noway_assert(!"Unexpected bbJumpKind");
3185 for (unsigned EHnum = 0; EHnum < compHndBBtabCount; EHnum++)
3187 EHblkDsc* ehDsc = ehGetDsc(EHnum);
3189 if (ehDsc->HasFilter())
3191 ehDsc->ebdFilter->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3194 ehDsc->ebdHndBeg->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3198 fgComputePredsDone = true;
3203 printf("\n*************** After fgComputePreds()\n");
3204 fgDispBasicBlocks();
3210 unsigned Compiler::fgNSuccsOfFinallyRet(BasicBlock* block)
3214 fgSuccOfFinallyRetWork(block, ~0, &bb, &res);
3218 BasicBlock* Compiler::fgSuccOfFinallyRet(BasicBlock* block, unsigned i)
3222 fgSuccOfFinallyRetWork(block, i, &bb, &res);
3226 void Compiler::fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres)
3228 assert(block->hasHndIndex()); // Otherwise, endfinally outside a finally/fault block?
3230 unsigned hndIndex = block->getHndIndex();
3231 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3233 assert(ehDsc->HasFinallyOrFaultHandler()); // Otherwise, endfinally outside a finally/fault block.
3236 unsigned succNum = 0;
3238 if (ehDsc->HasFinallyHandler())
3242 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3244 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3246 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3248 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3253 assert(bcall->isBBCallAlwaysPair());
3257 *bres = bcall->bbNext;
3263 assert(i == ~0u || ehDsc->HasFaultHandler()); // Should reach here only for fault blocks.
3270 Compiler::SwitchUniqueSuccSet Compiler::GetDescriptorForSwitch(BasicBlock* switchBlk)
3272 assert(switchBlk->bbJumpKind == BBJ_SWITCH);
3273 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3274 SwitchUniqueSuccSet res;
3275 if (switchMap->Lookup(switchBlk, &res))
3281 // We must compute the descriptor. Find which are dups, by creating a bit set with the unique successors.
3282 // We create a temporary bitset of blocks to compute the unique set of successor blocks,
3283 // since adding a block's number twice leaves just one "copy" in the bitset. Note that
3284 // we specifically don't use the BlockSet type, because doing so would require making a
3285 // call to EnsureBasicBlockEpoch() to make sure the epoch is up-to-date. However, that
3286 // can create a new epoch, thus invalidating all existing BlockSet objects, such as
3287 // reachability information stored in the blocks. To avoid that, we just use a local BitVec.
3289 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
3290 BitVec BITVEC_INIT_NOCOPY(uniqueSuccBlocks, BitVecOps::MakeEmpty(&blockVecTraits));
3291 BasicBlock** jumpTable = switchBlk->bbJumpSwt->bbsDstTab;
3292 unsigned jumpCount = switchBlk->bbJumpSwt->bbsCount;
3293 for (unsigned i = 0; i < jumpCount; i++)
3295 BasicBlock* targ = jumpTable[i];
3296 BitVecOps::AddElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3298 // Now we have a set of unique successors.
3299 unsigned numNonDups = BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks);
3301 typedef BasicBlock* BasicBlockPtr;
3302 BasicBlockPtr* nonDups = new (getAllocator()) BasicBlockPtr[numNonDups];
3304 unsigned nonDupInd = 0;
3305 // At this point, all unique targets are in "uniqueSuccBlocks". As we encounter each,
3306 // add to nonDups, remove from "uniqueSuccBlocks".
3307 for (unsigned i = 0; i < jumpCount; i++)
3309 BasicBlock* targ = jumpTable[i];
3310 if (BitVecOps::IsMember(&blockVecTraits, uniqueSuccBlocks, targ->bbNum))
3312 nonDups[nonDupInd] = targ;
3314 BitVecOps::RemoveElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3318 assert(nonDupInd == numNonDups);
3319 assert(BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks) == 0);
3320 res.numDistinctSuccs = numNonDups;
3321 res.nonDuplicates = nonDups;
3322 switchMap->Set(switchBlk, res);
3327 void Compiler::SwitchUniqueSuccSet::UpdateTarget(IAllocator* alloc,
3328 BasicBlock* switchBlk,
3332 assert(switchBlk->bbJumpKind == BBJ_SWITCH); // Precondition.
3333 unsigned jmpTabCnt = switchBlk->bbJumpSwt->bbsCount;
3334 BasicBlock** jmpTab = switchBlk->bbJumpSwt->bbsDstTab;
3336 // Is "from" still in the switch table (because it had more than one entry before?)
3337 bool fromStillPresent = false;
3338 for (unsigned i = 0; i < jmpTabCnt; i++)
3340 if (jmpTab[i] == from)
3342 fromStillPresent = true;
3347 // Is "to" already in "this"?
3348 bool toAlreadyPresent = false;
3349 for (unsigned i = 0; i < numDistinctSuccs; i++)
3351 if (nonDuplicates[i] == to)
3353 toAlreadyPresent = true;
3359 // If "from" is still present, and "to" is already present, do nothing
3360 // If "from" is still present, and "to" is not, must reallocate to add an entry.
3361 // If "from" is not still present, and "to" is not present, write "to" where "from" was.
3362 // If "from" is not still present, but "to" is present, remove "from".
3363 if (fromStillPresent && toAlreadyPresent)
3367 else if (fromStillPresent && !toAlreadyPresent)
3369 // reallocate to add an entry
3370 typedef BasicBlock* BasicBlockPtr;
3371 BasicBlockPtr* newNonDups = new (alloc) BasicBlockPtr[numDistinctSuccs + 1];
3372 memcpy(newNonDups, nonDuplicates, numDistinctSuccs * sizeof(BasicBlock*));
3373 newNonDups[numDistinctSuccs] = to;
3375 nonDuplicates = newNonDups;
3377 else if (!fromStillPresent && !toAlreadyPresent)
3380 // write "to" where "from" was
3381 bool foundFrom = false;
3383 for (unsigned i = 0; i < numDistinctSuccs; i++)
3385 if (nonDuplicates[i] == from)
3387 nonDuplicates[i] = to;
3398 assert(!fromStillPresent && toAlreadyPresent);
3401 bool foundFrom = false;
3403 for (unsigned i = 0; i < numDistinctSuccs; i++)
3405 if (nonDuplicates[i] == from)
3407 nonDuplicates[i] = nonDuplicates[numDistinctSuccs - 1];
3419 /*****************************************************************************
3421 * Simple utility function to remove an entry for a block in the switch desc
3422 * map. So it can be called from other phases.
3425 void Compiler::fgInvalidateSwitchDescMapEntry(BasicBlock* block)
3427 // Check if map has no entries yet.
3428 if (m_switchDescMap != nullptr)
3430 m_switchDescMap->Remove(block);
3434 void Compiler::UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to)
3436 if (m_switchDescMap == nullptr)
3438 return; // No mappings, nothing to do.
3442 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3443 SwitchUniqueSuccSet* res = switchMap->LookupPointer(switchBlk);
3446 // If no result, nothing to do. Otherwise, update it.
3447 res->UpdateTarget(getAllocator(), switchBlk, from, to);
3451 /*****************************************************************************
3452 * For a block that is in a handler region, find the first block of the most-nested
3453 * handler containing the block.
3455 BasicBlock* Compiler::fgFirstBlockOfHandler(BasicBlock* block)
3457 assert(block->hasHndIndex());
3458 return ehGetDsc(block->getHndIndex())->ebdHndBeg;
3461 /*****************************************************************************
3463 * Function called to find back edges and return blocks and mark them as needing GC Polls. This marks all
3466 void Compiler::fgMarkGCPollBlocks()
3468 if (GCPOLL_NONE == opts.compGCPollType)
3474 /* Check that the flowgraph data (bbNum, bbRefs, bbPreds) is up-to-date */
3475 fgDebugCheckBBlist();
3480 // Return blocks always need GC polls. In addition, all back edges (including those from switch
3481 // statements) need GC polls. The poll is on the block with the outgoing back edge (or ret), rather than
3482 // on the destination or on the edge itself.
3483 for (block = fgFirstBB; block; block = block->bbNext)
3485 bool blockNeedsPoll = false;
3486 switch (block->bbJumpKind)
3490 blockNeedsPoll = (block->bbJumpDest->bbNum <= block->bbNum);
3494 blockNeedsPoll = true;
3499 jumpCnt = block->bbJumpSwt->bbsCount;
3500 BasicBlock** jumpTab;
3501 jumpTab = block->bbJumpSwt->bbsDstTab;
3505 if ((*jumpTab)->bbNum <= block->bbNum)
3507 blockNeedsPoll = true;
3510 } while (++jumpTab, --jumpCnt);
3519 block->bbFlags |= BBF_NEEDS_GCPOLL;
3524 void Compiler::fgInitBlockVarSets()
3526 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3528 block->InitVarSets(this);
3531 // QMarks are much like blocks, and need their VarSets initialized.
3532 assert(!compIsForInlining());
3533 for (unsigned i = 0; i < compQMarks->Size(); i++)
3535 GenTreePtr qmark = compQMarks->Get(i);
3536 // Perhaps the gtOper of a QMark node was changed to something else since it was created and put on this list.
3537 // So can't hurt to check.
3538 if (qmark->OperGet() == GT_QMARK)
3540 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtThenLiveSet, VarSetOps::UninitVal());
3541 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtElseLiveSet, VarSetOps::UninitVal());
3544 fgBBVarSetsInited = true;
3547 /*****************************************************************************
3549 * The following does the final pass on BBF_NEEDS_GCPOLL and then actually creates the GC Polls.
3551 void Compiler::fgCreateGCPolls()
3553 if (GCPOLL_NONE == opts.compGCPollType)
3558 bool createdPollBlocks = false;
3563 printf("*************** In fgCreateGCPolls() for %s\n", info.compFullName);
3567 if (!(opts.MinOpts() || opts.compDbgCode))
3569 // Remove polls from well formed loops with a constant upper bound.
3570 for (unsigned lnum = 0; lnum < optLoopCount; ++lnum)
3572 // Look for constant counted loops that run for a short duration. This logic is very similar to
3573 // what's in code:Compiler::optUnrollLoops, since they have similar constraints. However, this
3574 // logic is much more permissive since we're not doing a complex transformation.
3577 * I feel bad cloning so much logic from optUnrollLoops
3580 // Filter out loops not meeting the obvious preconditions.
3582 if (optLoopTable[lnum].lpFlags & LPFLG_REMOVED)
3587 if (!(optLoopTable[lnum].lpFlags & LPFLG_CONST))
3592 BasicBlock* head = optLoopTable[lnum].lpHead;
3593 BasicBlock* bottom = optLoopTable[lnum].lpBottom;
3595 // Loops dominated by GC_SAFE_POINT won't have this set.
3596 if (!(bottom->bbFlags & BBF_NEEDS_GCPOLL))
3601 /* Get the loop data:
3605 - iterator increment
3606 - increment operation type (i.e. ASG_ADD, ASG_SUB, etc...)
3607 - loop test type (i.e. GT_GE, GT_LT, etc...)
3610 int lbeg = optLoopTable[lnum].lpConstInit;
3611 int llim = optLoopTable[lnum].lpConstLimit();
3612 genTreeOps testOper = optLoopTable[lnum].lpTestOper();
3614 int lvar = optLoopTable[lnum].lpIterVar();
3615 int iterInc = optLoopTable[lnum].lpIterConst();
3616 genTreeOps iterOper = optLoopTable[lnum].lpIterOper();
3618 var_types iterOperType = optLoopTable[lnum].lpIterOperType();
3619 bool unsTest = (optLoopTable[lnum].lpTestTree->gtFlags & GTF_UNSIGNED) != 0;
3620 if (lvaTable[lvar].lvAddrExposed)
3621 { // Can't reason about the value of the iteration variable.
3627 /* Find the number of iterations - the function returns false if not a constant number */
3629 if (!optComputeLoopRep(lbeg, llim, iterInc, iterOper, iterOperType, testOper, unsTest,
3630 // The value here doesn't matter for this variation of the optimization
3636 printf("Could not compute loop iterations for loop from BB%02u to BB%02u", head->bbNum,
3640 (void)head; // suppress gcc error.
3645 /* Forget it if there are too many repetitions or not a constant loop */
3647 static const unsigned ITER_LIMIT = 256;
3648 if (totalIter > ITER_LIMIT)
3653 // It is safe to elminate the poll from this loop.
3654 bottom->bbFlags &= ~BBF_NEEDS_GCPOLL;
3659 printf("Removing poll in block BB%02u because it forms a bounded counted loop\n", bottom->bbNum);
3665 // Final chance to optimize the polls. Move all polls in loops from the bottom of the loop up to the
3666 // loop head. Also eliminate all epilog polls in non-leaf methods. This only works if we have dominator
3670 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3672 if (!(block->bbFlags & BBF_NEEDS_GCPOLL))
3677 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
3679 // make sure that this is loop-like
3680 if (!fgReachable(block->bbJumpDest, block))
3682 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3686 printf("Removing poll in block BB%02u because it is not loop\n", block->bbNum);
3692 else if (!(block->bbJumpKind == BBJ_RETURN || block->bbJumpKind == BBJ_SWITCH))
3694 noway_assert(!"GC Poll on a block that has no control transfer.");
3698 printf("Removing poll in block BB%02u because it is not a jump\n", block->bbNum);
3701 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3705 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3706 // Clean those up now.
3708 if (block->bbFlags & BBF_GC_SAFE_POINT)
3713 printf("Removing poll in return block BB%02u because it is GC Safe\n", block->bbNum);
3716 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3720 if (block->bbJumpKind == BBJ_RETURN)
3722 if (!optReachWithoutCall(fgFirstBB, block))
3724 // check to see if there is a call along the path between the first block and the return
3726 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3730 printf("Removing poll in return block BB%02u because it dominated by a call\n", block->bbNum);
3739 noway_assert(!fgGCPollsCreated);
3741 fgGCPollsCreated = true;
3743 // Walk through the blocks and hunt for a block that has BBF_NEEDS_GCPOLL
3744 for (block = fgFirstBB; block; block = block->bbNext)
3746 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3747 // And if !fgDomsComputed, we won't have cleared them, so skip them now
3748 if (!(block->bbFlags & BBF_NEEDS_GCPOLL) || (block->bbFlags & BBF_GC_SAFE_POINT))
3753 // This block needs a poll. We either just insert a callout or we split the block and inline part of
3754 // the test. This depends on the value of opts.compGCPollType.
3756 // If we're doing GCPOLL_CALL, just insert a GT_CALL node before the last node in the block.
3757 CLANG_FORMAT_COMMENT_ANCHOR;
3760 switch (block->bbJumpKind)
3768 noway_assert(!"Unknown block type for BBF_NEEDS_GCPOLL");
3772 noway_assert(opts.compGCPollType);
3774 GCPollType pollType = opts.compGCPollType;
3775 // pollType is set to either CALL or INLINE at this point. Below is the list of places where we
3776 // can't or don't want to emit an inline check. Check all of those. If after all of that we still
3777 // have INLINE, then emit an inline check.
3779 if (opts.MinOpts() || opts.compDbgCode)
3784 printf("Selecting CALL poll in block BB%02u because of debug/minopts\n", block->bbNum);
3788 // Don't split blocks and create inlined polls unless we're optimizing.
3789 pollType = GCPOLL_CALL;
3791 else if (genReturnBB == block)
3796 printf("Selecting CALL poll in block BB%02u because it is the single return block\n", block->bbNum);
3800 // we don't want to split the single return block
3801 pollType = GCPOLL_CALL;
3803 else if (BBJ_SWITCH == block->bbJumpKind)
3808 printf("Selecting CALL poll in block BB%02u because it is a loop formed by a SWITCH\n", block->bbNum);
3812 // I don't want to deal with all the outgoing edges of a switch block.
3813 pollType = GCPOLL_CALL;
3816 // TODO-Cleanup: potentially don't split if we're in an EH region.
3818 createdPollBlocks |= fgCreateGCPoll(pollType, block);
3821 // If we split a block to create a GC Poll, then rerun fgReorderBlocks to push the rarely run blocks out
3822 // past the epilog. We should never split blocks unless we're optimizing.
3823 if (createdPollBlocks)
3825 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
3830 /*****************************************************************************
3832 * Actually create a GCPoll in the given block. Returns true if it created
3836 bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block)
3838 assert(!(block->bbFlags & BBF_GC_SAFE_POINT));
3839 bool createdPollBlocks;
3842 void* pAddrOfCaptureThreadGlobal;
3844 addrTrap = info.compCompHnd->getAddrOfCaptureThreadGlobal(&pAddrOfCaptureThreadGlobal);
3846 #ifdef ENABLE_FAST_GCPOLL_HELPER
3847 // I never want to split blocks if we've got two indirections here.
3848 // This is a size trade-off assuming the VM has ENABLE_FAST_GCPOLL_HELPER.
3849 // So don't do it when that is off
3850 if (pAddrOfCaptureThreadGlobal != NULL)
3852 pollType = GCPOLL_CALL;
3854 #endif // ENABLE_FAST_GCPOLL_HELPER
3856 if (GCPOLL_CALL == pollType)
3858 createdPollBlocks = false;
3859 GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3860 #if GTF_CALL_REG_SAVE
3861 call->gtCallMoreFlags |= GTF_CALL_REG_SAVE;
3862 #endif // GTF_CALL_REG_SAVE
3864 // for BBJ_ALWAYS I don't need to insert it before the condition. Just append it.
3865 if (block->bbJumpKind == BBJ_ALWAYS)
3867 fgInsertStmtAtEnd(block, call);
3871 GenTreeStmt* newStmt = fgInsertStmtNearEnd(block, call);
3872 // For DDB156656, we need to associate the GC Poll with the IL offset (and therefore sequence
3873 // point) of the tree before which we inserted the poll. One example of when this is a
3884 // If we take the if statement at 1, we encounter a jump at 2. This jumps over the else
3885 // and lands at 4. 4 is where we inserted the gcpoll. However, that is associated with
3886 // the sequence point a 3. Therefore, the debugger displays the wrong source line at the
3887 // gc poll location.
3889 // More formally, if control flow targets an instruction, that instruction must be the
3890 // start of a new sequence point.
3891 if (newStmt->gtNext)
3893 // Is it possible for gtNext to be NULL?
3894 noway_assert(newStmt->gtNext->gtOper == GT_STMT);
3895 newStmt->gtStmtILoffsx = newStmt->gtNextStmt->gtStmtILoffsx;
3899 block->bbFlags |= BBF_GC_SAFE_POINT;
3903 printf("*** creating GC Poll in block BB%02u\n", block->bbNum);
3904 gtDispTreeList(block->bbTreeList);
3910 createdPollBlocks = true;
3911 // if we're doing GCPOLL_INLINE, then:
3912 // 1) Create two new blocks: Poll and Bottom. The original block is called Top.
3914 // I want to create:
3915 // top -> poll -> bottom (lexically)
3916 // so that we jump over poll to get to bottom.
3917 BasicBlock* top = block;
3918 BasicBlock* poll = fgNewBBafter(BBJ_NONE, top, true);
3919 BasicBlock* bottom = fgNewBBafter(top->bbJumpKind, poll, true);
3920 BBjumpKinds oldJumpKind = top->bbJumpKind;
3922 // Update block flags
3923 const unsigned __int64 originalFlags = top->bbFlags | BBF_GC_SAFE_POINT;
3925 // Unlike Fei's inliner from puclr, I'm allowed to split loops.
3926 // And we keep a few other flags...
3927 noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~(BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1))) == 0);
3928 top->bbFlags = originalFlags & (~BBF_SPLIT_LOST | BBF_GC_SAFE_POINT);
3929 bottom->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3930 bottom->inheritWeight(top);
3931 poll->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3933 // 9) Mark Poll as rarely run.
3934 poll->bbSetRunRarely();
3936 // 5) Bottom gets all the outgoing edges and inherited flags of Original.
3937 bottom->bbJumpDest = top->bbJumpDest;
3939 // 2) Add a GC_CALL node to Poll.
3940 GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3941 #if GTF_CALL_REG_SAVE
3942 call->gtCallMoreFlags |= GTF_CALL_REG_SAVE;
3943 #endif // GTF_CALL_REG_SAVE
3944 fgInsertStmtAtEnd(poll, call);
3946 // 3) Remove the last statement from Top and add it to Bottom.
3947 if (oldJumpKind != BBJ_ALWAYS)
3949 // if I'm always jumping to the target, then this is not a condition that needs moving.
3950 GenTreeStmt* stmt = top->firstStmt();
3951 while (stmt->gtNext)
3953 stmt = stmt->gtNextStmt;
3955 fgRemoveStmt(top, stmt);
3956 fgInsertStmtAtEnd(bottom, stmt);
3959 // for BBJ_ALWAYS blocks, bottom is an empty block.
3961 // 4) Create a GT_EQ node that checks against g_TrapReturningThreads. True jumps to Bottom,
3962 // false falls through to poll. Add this to the end of Top. Top is now BBJ_COND. Bottom is
3963 // now a jump target
3964 CLANG_FORMAT_COMMENT_ANCHOR;
3966 #ifdef ENABLE_FAST_GCPOLL_HELPER
3967 // Prefer the fast gc poll helepr over the double indirection
3968 noway_assert(pAddrOfCaptureThreadGlobal == nullptr);
3972 if (pAddrOfCaptureThreadGlobal != nullptr)
3974 trap = gtNewOperNode(GT_IND, TYP_I_IMPL,
3975 gtNewIconHandleNode((size_t)pAddrOfCaptureThreadGlobal, GTF_ICON_PTR_HDL));
3979 trap = gtNewIconHandleNode((size_t)addrTrap, GTF_ICON_PTR_HDL);
3982 GenTreePtr trapRelop = gtNewOperNode(GT_EQ, TYP_INT,
3983 // lhs [g_TrapReturningThreads]
3984 gtNewOperNode(GT_IND, TYP_INT, trap),
3986 gtNewIconNode(0, TYP_INT));
3987 trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE; // Treat reading g_TrapReturningThreads as volatile.
3988 GenTreePtr trapCheck = gtNewOperNode(GT_JTRUE, TYP_VOID, trapRelop);
3989 fgInsertStmtAtEnd(top, trapCheck);
3990 top->bbJumpDest = bottom;
3991 top->bbJumpKind = BBJ_COND;
3992 bottom->bbFlags |= BBF_JMP_TARGET;
3994 // 7) Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor.
3995 fgAddRefPred(bottom, poll);
3996 fgAddRefPred(bottom, top);
3997 fgAddRefPred(poll, top);
3999 // 8) Replace Top with Bottom in the predecessor list of all outgoing edges from Bottom (1 for
4000 // jumps, 2 for conditional branches, N for switches).
4001 switch (oldJumpKind)
4007 // replace predecessor in the fall through block.
4008 noway_assert(bottom->bbNext);
4009 fgReplacePred(bottom->bbNext, top, bottom);
4011 // fall through for the jump target
4015 fgReplacePred(bottom->bbJumpDest, top, bottom);
4018 NO_WAY("SWITCH should be a call rather than an inlined poll.");
4021 NO_WAY("Unknown block type for updating predecessor lists.");
4024 top->bbFlags &= ~BBF_NEEDS_GCPOLL;
4025 noway_assert(!(poll->bbFlags & BBF_NEEDS_GCPOLL));
4026 noway_assert(!(bottom->bbFlags & BBF_NEEDS_GCPOLL));
4028 if (compCurBB == top)
4036 printf("*** creating inlined GC Poll in top block BB%02u\n", top->bbNum);
4037 gtDispTreeList(top->bbTreeList);
4038 printf(" poll block is BB%02u\n", poll->bbNum);
4039 gtDispTreeList(poll->bbTreeList);
4040 printf(" bottom block is BB%02u\n", bottom->bbNum);
4041 gtDispTreeList(bottom->bbTreeList);
4046 return createdPollBlocks;
4049 /*****************************************************************************
4051 * The following helps find a basic block given its PC offset.
4054 void Compiler::fgInitBBLookup()
4056 BasicBlock** dscBBptr;
4057 BasicBlock* tmpBBdesc;
4059 /* Allocate the basic block table */
4061 dscBBptr = fgBBs = new (this, CMK_BasicBlock) BasicBlock*[fgBBcount];
4063 /* Walk all the basic blocks, filling in the table */
4065 for (tmpBBdesc = fgFirstBB; tmpBBdesc; tmpBBdesc = tmpBBdesc->bbNext)
4067 *dscBBptr++ = tmpBBdesc;
4070 noway_assert(dscBBptr == fgBBs + fgBBcount);
4073 BasicBlock* Compiler::fgLookupBB(unsigned addr)
4078 /* Do a binary search */
4080 for (lo = 0, hi = fgBBcount - 1;;)
4090 unsigned mid = (lo + hi) / 2;
4091 BasicBlock* dsc = fgBBs[mid];
4093 // We introduce internal blocks for BBJ_CALLFINALLY. Skip over these.
4095 while (dsc->bbFlags & BBF_INTERNAL)
4100 // We skipped over too many, Set hi back to the original mid - 1
4104 mid = (lo + hi) / 2;
4110 unsigned pos = dsc->bbCodeOffs;
4114 if ((lo == hi) && (lo == (fgBBcount - 1)))
4116 noway_assert(addr == dsc->bbCodeOffsEnd);
4117 return nullptr; // NULL means the end of method
4132 printf("ERROR: Couldn't find basic block at offset %04X\n", addr);
4134 NO_WAY("fgLookupBB failed.");
4137 /*****************************************************************************
4139 * The 'jump target' array uses the following flags to indicate what kind
4140 * of label is present.
4143 #define JT_NONE 0x00 // This IL offset is never used
4144 #define JT_ADDR 0x01 // merely make sure this is an OK address
4145 #define JT_JUMP 0x02 // 'normal' jump target
4146 #define JT_MULTI 0x04 // target of multiple jumps
4148 inline void Compiler::fgMarkJumpTarget(BYTE* jumpTarget, unsigned offs)
4150 /* Make sure we set JT_MULTI if target of multiple jumps */
4152 noway_assert(JT_MULTI == JT_JUMP << 1);
4154 jumpTarget[offs] |= (jumpTarget[offs] & JT_JUMP) << 1 | JT_JUMP;
4157 //------------------------------------------------------------------------
4158 // FgStack: simple stack model for the inlinee's evaluation stack.
4160 // Model the inputs available to various operations in the inline body.
4161 // Tracks constants, arguments, array lengths.
4166 FgStack() : slot0(SLOT_INVALID), slot1(SLOT_INVALID), depth(0)
4181 Push(SLOT_CONSTANT);
4185 Push(SLOT_ARRAYLEN);
4187 void PushArgument(unsigned arg)
4189 Push(SLOT_ARGUMENT + arg);
4191 unsigned GetSlot0() const
4196 unsigned GetSlot1() const
4201 static bool IsConstant(unsigned value)
4203 return value == SLOT_CONSTANT;
4205 static bool IsArrayLen(unsigned value)
4207 return value == SLOT_ARRAYLEN;
4209 static bool IsArgument(unsigned value)
4211 return value >= SLOT_ARGUMENT;
4213 static unsigned SlotTypeToArgNum(unsigned value)
4215 assert(IsArgument(value));
4216 return value - SLOT_ARGUMENT;
4218 bool IsStackTwoDeep() const
4222 bool IsStackOneDeep() const
4226 bool IsStackAtLeastOneDeep() const
4234 SLOT_INVALID = UINT_MAX,
4263 //------------------------------------------------------------------------
4264 // fgFindJumpTargets: walk the IL stream, determining jump target offsets
4267 // codeAddr - base address of the IL code buffer
4268 // codeSize - number of bytes in the IL code buffer
4269 // jumpTarget - [OUT] byte array for flagging jump targets
4272 // If inlining or prejitting the root, this method also makes
4273 // various observations about the method that factor into inline
4276 // May throw an exception if the IL is malformed.
4278 // jumpTarget[N] is set to a JT_* value if IL offset N is a
4279 // jump target in the method.
4281 // Also sets lvAddrExposed and lvHasILStoreOp, ilHasMultipleILStoreOp in lvaTable[].
4284 #pragma warning(push)
4285 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
4288 void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
4290 const BYTE* codeBegp = codeAddr;
4291 const BYTE* codeEndp = codeAddr + codeSize;
4293 bool seenJump = false;
4294 var_types varType = DUMMY_INIT(TYP_UNDEF); // TYP_ type
4295 typeInfo ti; // Verifier type.
4296 bool typeIsNormed = false;
4297 FgStack pushedStack;
4298 const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
4299 const bool makeInlineObservations = (compInlineResult != nullptr);
4300 const bool isInlining = compIsForInlining();
4301 unsigned retBlocks = 0;
4303 if (makeInlineObservations)
4305 // Observe force inline state and code size.
4306 compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
4307 compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
4311 // If inlining, this method should still be a candidate.
4314 assert(compInlineResult->IsCandidate());
4319 // note that we're starting to look at the opcodes.
4320 compInlineResult->Note(InlineObservation::CALLEE_BEGIN_OPCODE_SCAN);
4323 while (codeAddr < codeEndp)
4325 OPCODE opcode = (OPCODE)getU1LittleEndian(codeAddr);
4326 codeAddr += sizeof(__int8);
4328 typeIsNormed = false;
4332 if (opcode >= CEE_COUNT)
4334 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4337 if ((opcode >= CEE_LDARG_0 && opcode <= CEE_STLOC_S) || (opcode >= CEE_LDARG && opcode <= CEE_STLOC))
4342 if (makeInlineObservations && (opcode >= CEE_LDNULL) && (opcode <= CEE_LDC_R8))
4344 pushedStack.PushConstant();
4347 unsigned sz = opcodeSizes[opcode];
4353 if (codeAddr >= codeEndp)
4357 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
4358 codeAddr += sizeof(__int8);
4370 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4376 // There has to be code after the call, otherwise the inlinee is unverifiable.
4380 noway_assert(codeAddr < codeEndp - sz);
4383 // If the method has a call followed by a ret, assume that
4384 // it is a wrapper method.
4385 if (makeInlineObservations)
4387 if ((OPCODE)getU1LittleEndian(codeAddr + sz) == CEE_RET)
4389 compInlineResult->Note(InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER);
4426 if (codeAddr > codeEndp - sz)
4431 // Compute jump target address
4432 signed jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
4434 if (compIsForInlining() && jmpDist == 0 &&
4435 (opcode == CEE_LEAVE || opcode == CEE_LEAVE_S || opcode == CEE_BR || opcode == CEE_BR_S))
4440 unsigned jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
4442 // Make sure target is reasonable
4443 if (jmpAddr >= codeSize)
4445 BADCODE3("code jumps to outer space", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4448 // Mark the jump target
4449 fgMarkJumpTarget(jumpTarget, jmpAddr);
4451 // See if jump might be sensitive to inlining
4452 if (makeInlineObservations && (opcode != CEE_BR_S) && (opcode != CEE_BR))
4454 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4463 if (makeInlineObservations)
4465 compInlineResult->Note(InlineObservation::CALLEE_HAS_SWITCH);
4467 // Fail fast, if we're inlining and can't handle this.
4468 if (isInlining && compInlineResult->IsFailure())
4474 // Make sure we don't go past the end reading the number of cases
4475 if (codeAddr > codeEndp - sizeof(DWORD))
4480 // Read the number of cases
4481 unsigned jmpCnt = getU4LittleEndian(codeAddr);
4482 codeAddr += sizeof(DWORD);
4484 if (jmpCnt > codeSize / sizeof(DWORD))
4489 // Find the end of the switch table
4490 unsigned jmpBase = (unsigned)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
4492 // Make sure there is more code after the switch
4493 if (jmpBase >= codeSize)
4498 // jmpBase is also the target of the default case, so mark it
4499 fgMarkJumpTarget(jumpTarget, jmpBase);
4501 // Process table entries
4504 unsigned jmpAddr = jmpBase + getI4LittleEndian(codeAddr);
4507 if (jmpAddr >= codeSize)
4509 BADCODE3("jump target out of range", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4512 fgMarkJumpTarget(jumpTarget, jmpAddr);
4516 // We've advanced past all the bytes in this instruction
4522 case CEE_CONSTRAINED:
4527 if (codeAddr >= codeEndp)
4537 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4539 if (codeAddr > codeEndp - sz)
4544 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4548 if (varNum < impInlineInfo->argCnt)
4550 impInlineInfo->inlArgInfo[varNum].argHasStargOp = true;
4555 // account for possible hidden param
4556 varNum = compMapILargNum(varNum);
4558 // This check is only intended to prevent an AV. Bad varNum values will later
4559 // be handled properly by the verifier.
4560 if (varNum < lvaTableCnt)
4562 // In non-inline cases, note written-to arguments.
4563 lvaTable[varNum].lvHasILStoreOp = 1;
4573 varNum = (opcode - CEE_STLOC_0);
4579 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4581 if (codeAddr > codeEndp - sz)
4586 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4591 InlLclVarInfo& lclInfo = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt];
4593 if (lclInfo.lclHasStlocOp)
4595 lclInfo.lclHasMultipleStlocOp = 1;
4599 lclInfo.lclHasStlocOp = 1;
4604 varNum += info.compArgsCount;
4606 // This check is only intended to prevent an AV. Bad varNum values will later
4607 // be handled properly by the verifier.
4608 if (varNum < lvaTableCnt)
4610 // In non-inline cases, note written-to locals.
4611 if (lvaTable[varNum].lvHasILStoreOp)
4613 lvaTable[varNum].lvHasMultipleILStoreOp = 1;
4617 lvaTable[varNum].lvHasILStoreOp = 1;
4629 // Handle address-taken args or locals
4630 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4632 if (codeAddr > codeEndp - sz)
4637 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4641 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4643 varType = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclTypeInfo;
4644 ti = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclVerTypeInfo;
4646 impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclHasLdlocaOp = true;
4650 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4652 varType = impInlineInfo->lclVarInfo[varNum].lclTypeInfo;
4653 ti = impInlineInfo->lclVarInfo[varNum].lclVerTypeInfo;
4655 impInlineInfo->inlArgInfo[varNum].argHasLdargaOp = true;
4657 pushedStack.PushArgument(varNum);
4662 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4664 if (varNum >= info.compMethodInfo->locals.numArgs)
4666 BADCODE("bad local number");
4669 varNum += info.compArgsCount;
4673 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4675 if (varNum >= info.compILargsCount)
4677 BADCODE("bad argument number");
4680 varNum = compMapILargNum(varNum); // account for possible hidden param
4683 varType = (var_types)lvaTable[varNum].lvType;
4684 ti = lvaTable[varNum].lvVerTypeInfo;
4686 // Determine if the next instruction will consume
4687 // the address. If so we won't mark this var as
4690 // We will put structs on the stack and changing
4691 // the addrTaken of a local requires an extra pass
4692 // in the morpher so we won't apply this
4693 // optimization to structs.
4695 // Debug code spills for every IL instruction, and
4696 // therefore it will split statements, so we will
4697 // need the address. Note that this optimization
4698 // is based in that we know what trees we will
4699 // generate for this ldfld, and we require that we
4700 // won't need the address of this local at all
4701 noway_assert(varNum < lvaTableCnt);
4703 const bool notStruct = !varTypeIsStruct(&lvaTable[varNum]);
4704 const bool notLastInstr = (codeAddr < codeEndp - sz);
4705 const bool notDebugCode = !opts.compDbgCode;
4707 if (notStruct && notLastInstr && notDebugCode &&
4708 impILConsumesAddr(codeAddr + sz, impTokenLookupContextHandle, info.compScopeHnd))
4710 // We can skip the addrtaken, as next IL instruction consumes
4715 lvaTable[varNum].lvHasLdAddrOp = 1;
4716 if (!info.compIsStatic && (varNum == 0))
4718 // Addr taken on "this" pointer is significant,
4719 // go ahead to mark it as permanently addr-exposed here.
4720 lvaSetVarAddrExposed(0);
4721 // This may be conservative, but probably not very.
4726 typeIsNormed = ti.IsValueClass() && !varTypeIsStruct(varType);
4733 #if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
4736 // We transform this into a set of ldarg's + tail call and
4737 // thus may push more onto the stack than originally thought.
4738 // This doesn't interfere with verification because CEE_JMP
4739 // is never verifiable, and there's nothing unsafe you can
4740 // do with a an IL stack overflow if the JIT is expecting it.
4741 info.compMaxStack = max(info.compMaxStack, info.compILargsCount);
4744 #endif // !_TARGET_X86_ && !_TARGET_ARM_
4746 // If we are inlining, we need to fail for a CEE_JMP opcode, just like
4747 // the list of other opcodes (for all platforms).
4755 // CEE_CALLI should not be inlined because the JIT cannot generate an inlined call frame. If the call
4757 // is a no-marshal CALLI P/Invoke we end up calling the IL stub. We don't NGEN these stubs, so we'll
4759 // JIT an IL stub for a trivial func. It's almost certainly a better choice to leave out the inline
4760 // candidate so we can generate an inlined call frame. It might be nice to call getCallInfo to figure
4762 // what kind of call we have here.
4764 // Consider making this only for not force inline.
4765 if (makeInlineObservations)
4767 // Arguably this should be NoteFatal, but the legacy behavior is
4768 // to ignore this for the prejit root.
4769 compInlineResult->Note(InlineObservation::CALLEE_UNSUPPORTED_OPCODE);
4771 // Fail fast if we're inlining...
4774 assert(compInlineResult->IsFailure());
4784 if (makeInlineObservations)
4786 pushedStack.PushArgument(opcode - CEE_LDARG_0);
4793 if (codeAddr > codeEndp - sz)
4798 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4800 if (makeInlineObservations)
4802 pushedStack.PushArgument(varNum);
4808 if (makeInlineObservations)
4810 pushedStack.PushArrayLen();
4819 if (makeInlineObservations)
4821 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4831 // Skip any remaining operands this opcode may have
4834 // Note the opcode we just saw
4835 if (makeInlineObservations)
4837 InlineObservation obs =
4838 typeIsNormed ? InlineObservation::CALLEE_OPCODE_NORMED : InlineObservation::CALLEE_OPCODE;
4839 compInlineResult->NoteInt(obs, opcode);
4843 if (codeAddr != codeEndp)
4846 BADCODE3("Code ends in the middle of an opcode, or there is a branch past the end of the method",
4847 " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4850 if (makeInlineObservations)
4852 compInlineResult->Note(InlineObservation::CALLEE_END_OPCODE_SCAN);
4854 if (!compInlineResult->UsesLegacyPolicy())
4856 // If there are no return blocks we know it does not return, however if there
4857 // return blocks we don't know it returns as it may be counting unreachable code.
4858 // However we will still make the CALLEE_DOES_NOT_RETURN observation.
4860 compInlineResult->NoteBool(InlineObservation::CALLEE_DOES_NOT_RETURN, retBlocks == 0);
4862 if (retBlocks == 0 && isInlining)
4864 // Mark the call node as "no return" as it can impact caller's code quality.
4865 impInlineInfo->iciCall->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
4869 // Determine if call site is within a try.
4870 if (isInlining && impInlineInfo->iciBlock->hasTryIndex())
4872 compInlineResult->Note(InlineObservation::CALLSITE_IN_TRY_REGION);
4875 // If the inline is viable and discretionary, do the
4876 // profitability screening.
4877 if (compInlineResult->IsDiscretionaryCandidate())
4879 // Make some callsite specific observations that will feed
4880 // into the profitability model.
4881 impMakeDiscretionaryInlineObservations(impInlineInfo, compInlineResult);
4883 // None of those observations should have changed the
4884 // inline's viability.
4885 assert(compInlineResult->IsCandidate());
4889 // Assess profitability...
4890 CORINFO_METHOD_INFO* methodInfo = &impInlineInfo->inlineCandidateInfo->methInfo;
4891 compInlineResult->DetermineProfitability(methodInfo);
4893 if (compInlineResult->IsFailure())
4895 impInlineRoot()->m_inlineStrategy->NoteUnprofitable();
4896 JITDUMP("\n\nInline expansion aborted, inline not profitable\n");
4901 // The inline is still viable.
4902 assert(compInlineResult->IsCandidate());
4907 // Prejit root case. Profitability assessment for this
4908 // is done over in compCompileHelper.
4913 // None of the local vars in the inlinee should have address taken or been written to.
4914 // Therefore we should NOT need to enter this "if" statement.
4915 if (!isInlining && !info.compIsStatic)
4917 fgAdjustForAddressExposedOrWrittenThis();
4922 #pragma warning(pop)
4925 //------------------------------------------------------------------------
4926 // fgAdjustForAddressExposedOrWrittenThis: update var table for cases
4927 // where the this pointer value can change.
4930 // Modifies lvaArg0Var to refer to a temp if the value of 'this' can
4931 // change. The original this (info.compThisArg) then remains
4932 // unmodified in the method. fgAddInternal is reponsible for
4933 // adding the code to copy the initial this into the temp.
4935 void Compiler::fgAdjustForAddressExposedOrWrittenThis()
4937 // Optionally enable adjustment during stress.
4938 if (!tiVerificationNeeded && compStressCompile(STRESS_GENERIC_VARN, 15))
4940 lvaTable[info.compThisArg].lvHasILStoreOp = true;
4943 // If this is exposed or written to, create a temp for the modifiable this
4944 if (lvaTable[info.compThisArg].lvAddrExposed || lvaTable[info.compThisArg].lvHasILStoreOp)
4946 // If there is a "ldarga 0" or "starg 0", grab and use the temp.
4947 lvaArg0Var = lvaGrabTemp(false DEBUGARG("Address-exposed, or written this pointer"));
4948 noway_assert(lvaArg0Var > (unsigned)info.compThisArg);
4949 lvaTable[lvaArg0Var].lvType = lvaTable[info.compThisArg].TypeGet();
4950 lvaTable[lvaArg0Var].lvAddrExposed = lvaTable[info.compThisArg].lvAddrExposed;
4951 lvaTable[lvaArg0Var].lvDoNotEnregister = lvaTable[info.compThisArg].lvDoNotEnregister;
4953 lvaTable[lvaArg0Var].lvVMNeedsStackAddr = lvaTable[info.compThisArg].lvVMNeedsStackAddr;
4954 lvaTable[lvaArg0Var].lvLiveInOutOfHndlr = lvaTable[info.compThisArg].lvLiveInOutOfHndlr;
4955 lvaTable[lvaArg0Var].lvLclFieldExpr = lvaTable[info.compThisArg].lvLclFieldExpr;
4956 lvaTable[lvaArg0Var].lvLiveAcrossUCall = lvaTable[info.compThisArg].lvLiveAcrossUCall;
4958 lvaTable[lvaArg0Var].lvHasILStoreOp = lvaTable[info.compThisArg].lvHasILStoreOp;
4959 lvaTable[lvaArg0Var].lvVerTypeInfo = lvaTable[info.compThisArg].lvVerTypeInfo;
4961 // Clear the TI_FLAG_THIS_PTR in the original 'this' pointer.
4962 noway_assert(lvaTable[lvaArg0Var].lvVerTypeInfo.IsThisPtr());
4963 lvaTable[info.compThisArg].lvVerTypeInfo.ClearThisPtr();
4964 lvaTable[info.compThisArg].lvAddrExposed = false;
4965 lvaTable[info.compThisArg].lvHasILStoreOp = false;
4969 //------------------------------------------------------------------------
4970 // fgObserveInlineConstants: look for operations that might get optimized
4971 // if this method were to be inlined, and report these to the inliner.
4974 // opcode -- MSIL opcode under consideration
4975 // stack -- abstract stack model at this point in the IL
4976 // isInlining -- true if we're inlining (vs compiling a prejit root)
4979 // Currently only invoked on compare and branch opcodes.
4981 // If we're inlining we also look at the argument values supplied by
4982 // the caller at this call site.
4984 // The crude stack model may overestimate stack depth.
4986 void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining)
4988 // We should be able to record inline observations.
4989 assert(compInlineResult != nullptr);
4991 // The stack only has to be 1 deep for BRTRUE/FALSE
4992 bool lookForBranchCases = stack.IsStackAtLeastOneDeep();
4994 if (compInlineResult->UsesLegacyPolicy())
4996 // LegacyPolicy misses cases where the stack is really one
4997 // deep but the model says it's two deep. We need to do
4998 // likewise to preseve old behavior.
4999 lookForBranchCases &= !stack.IsStackTwoDeep();
5002 if (lookForBranchCases)
5004 if (opcode == CEE_BRFALSE || opcode == CEE_BRFALSE_S || opcode == CEE_BRTRUE || opcode == CEE_BRTRUE_S)
5006 unsigned slot0 = stack.GetSlot0();
5007 if (FgStack::IsArgument(slot0))
5009 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
5013 // Check for the double whammy of an incoming constant argument
5014 // feeding a constant test.
5015 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
5016 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5018 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5027 // Remaining cases require at least two things on the stack.
5028 if (!stack.IsStackTwoDeep())
5033 unsigned slot0 = stack.GetSlot0();
5034 unsigned slot1 = stack.GetSlot1();
5036 // Arg feeds constant test
5037 if ((FgStack::IsConstant(slot0) && FgStack::IsArgument(slot1)) ||
5038 (FgStack::IsConstant(slot1) && FgStack::IsArgument(slot0)))
5040 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
5043 // Arg feeds range check
5044 if ((FgStack::IsArrayLen(slot0) && FgStack::IsArgument(slot1)) ||
5045 (FgStack::IsArrayLen(slot1) && FgStack::IsArgument(slot0)))
5047 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK);
5050 // Check for an incoming arg that's a constant
5053 if (FgStack::IsArgument(slot0))
5055 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
5056 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5058 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5062 if (FgStack::IsArgument(slot1))
5064 unsigned varNum = FgStack::SlotTypeToArgNum(slot1);
5065 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5067 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5073 /*****************************************************************************
5075 * Finally link up the bbJumpDest of the blocks together
5078 void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock)
5080 noway_assert(startBlock->bbNum <= endBlock->bbNum);
5082 for (BasicBlock* block = startBlock; block != endBlock->bbNext; block = block->bbNext)
5084 if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0)
5086 block->bbFlags |= BBF_BACKWARD_JUMP;
5091 /*****************************************************************************
5093 * Finally link up the bbJumpDest of the blocks together
5096 void Compiler::fgLinkBasicBlocks()
5098 /* Create the basic block lookup tables */
5102 /* First block is always reachable */
5104 fgFirstBB->bbRefs = 1;
5106 /* Walk all the basic blocks, filling in the target addresses */
5108 for (BasicBlock* curBBdesc = fgFirstBB; curBBdesc; curBBdesc = curBBdesc->bbNext)
5110 switch (curBBdesc->bbJumpKind)
5115 curBBdesc->bbJumpDest = fgLookupBB(curBBdesc->bbJumpOffs);
5116 curBBdesc->bbJumpDest->bbRefs++;
5117 if (curBBdesc->bbJumpDest->bbNum <= curBBdesc->bbNum)
5119 fgMarkBackwardJump(curBBdesc->bbJumpDest, curBBdesc);
5122 /* Is the next block reachable? */
5124 if (curBBdesc->bbJumpKind == BBJ_ALWAYS || curBBdesc->bbJumpKind == BBJ_LEAVE)
5129 if (!curBBdesc->bbNext)
5131 BADCODE("Fall thru the end of a method");
5134 // Fall through, the next block is also reachable
5137 curBBdesc->bbNext->bbRefs++;
5140 case BBJ_EHFINALLYRET:
5141 case BBJ_EHFILTERRET:
5149 jumpCnt = curBBdesc->bbJumpSwt->bbsCount;
5150 BasicBlock** jumpPtr;
5151 jumpPtr = curBBdesc->bbJumpSwt->bbsDstTab;
5155 *jumpPtr = fgLookupBB((unsigned)*(size_t*)jumpPtr);
5156 (*jumpPtr)->bbRefs++;
5157 if ((*jumpPtr)->bbNum <= curBBdesc->bbNum)
5159 fgMarkBackwardJump(*jumpPtr, curBBdesc);
5161 } while (++jumpPtr, --jumpCnt);
5163 /* Default case of CEE_SWITCH (next block), is at end of jumpTab[] */
5165 noway_assert(*(jumpPtr - 1) == curBBdesc->bbNext);
5168 case BBJ_CALLFINALLY: // BBJ_CALLFINALLY and BBJ_EHCATCHRET don't appear until later
5169 case BBJ_EHCATCHRET:
5171 noway_assert(!"Unexpected bbJumpKind");
5177 /*****************************************************************************
5179 * Walk the instrs to create the basic blocks. Returns the number of BBJ_RETURN in method
5182 unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
5185 const BYTE* codeBegp = codeAddr;
5186 const BYTE* codeEndp = codeAddr + codeSize;
5187 bool tailCall = false;
5189 BasicBlock* curBBdesc;
5192 /* Clear the beginning offset for the first BB */
5196 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5198 compResetScopeLists();
5200 // Ignore scopes beginning at offset 0
5201 while (compGetNextEnterScope(0))
5204 while (compGetNextExitScope(0))
5209 BBjumpKinds jmpKind;
5215 unsigned jmpAddr = DUMMY_INIT(BAD_IL_OFFSET);
5216 unsigned bbFlags = 0;
5217 BBswtDesc* swtDsc = nullptr;
5220 opcode = (OPCODE)getU1LittleEndian(codeAddr);
5221 codeAddr += sizeof(__int8);
5226 /* Get the size of additional parameters */
5228 noway_assert(opcode < CEE_COUNT);
5230 sz = opcodeSizes[opcode];
5237 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5239 BADCODE3("jump target between prefix 0xFE and opcode", " at offset %04X",
5240 (IL_OFFSET)(codeAddr - codeBegp));
5243 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
5244 codeAddr += sizeof(__int8);
5247 /* Check to see if we have a jump/return opcode */
5281 // We need to check if we are jumping out of a finally-protected try.
5282 jmpKind = BBJ_LEAVE;
5287 jmpKind = BBJ_ALWAYS;
5292 /* Compute the target address of the jump */
5294 jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
5296 if (compIsForInlining() && jmpDist == 0 && (opcode == CEE_BR || opcode == CEE_BR_S))
5301 jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
5307 unsigned jmpCnt; // # of switch cases (excluding defualt)
5309 BasicBlock** jmpTab;
5310 BasicBlock** jmpPtr;
5312 /* Allocate the switch descriptor */
5314 swtDsc = new (this, CMK_BasicBlock) BBswtDesc;
5316 /* Read the number of entries in the table */
5318 jmpCnt = getU4LittleEndian(codeAddr);
5321 /* Compute the base offset for the opcode */
5323 jmpBase = (IL_OFFSET)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
5325 /* Allocate the jump table */
5327 jmpPtr = jmpTab = new (this, CMK_BasicBlock) BasicBlock*[jmpCnt + 1];
5329 /* Fill in the jump table */
5331 for (unsigned count = jmpCnt; count; count--)
5333 jmpDist = getI4LittleEndian(codeAddr);
5336 // store the offset in the pointer. We change these in fgLinkBasicBlocks().
5337 *jmpPtr++ = (BasicBlock*)(size_t)(jmpBase + jmpDist);
5340 /* Append the default label to the target table */
5342 *jmpPtr++ = (BasicBlock*)(size_t)jmpBase;
5344 /* Make sure we found the right number of labels */
5346 noway_assert(jmpPtr == jmpTab + jmpCnt + 1);
5348 /* Compute the size of the switch opcode operands */
5350 sz = sizeof(DWORD) + jmpCnt * sizeof(DWORD);
5352 /* Fill in the remaining fields of the switch descriptor */
5354 swtDsc->bbsCount = jmpCnt + 1;
5355 swtDsc->bbsDstTab = jmpTab;
5357 /* This is definitely a jump */
5359 jmpKind = BBJ_SWITCH;
5362 #ifndef LEGACY_BACKEND
5363 if (opts.compProcedureSplitting)
5365 // TODO-CQ: We might need to create a switch table; we won't know for sure until much later.
5366 // However, switch tables don't work with hot/cold splitting, currently. The switch table data needs
5367 // a relocation such that if the base (the first block after the prolog) and target of the switch
5368 // branch are put in different sections, the difference stored in the table is updated. However, our
5369 // relocation implementation doesn't support three different pointers (relocation address, base, and
5370 // target). So, we need to change our switch table implementation to be more like
5371 // JIT64: put the table in the code section, in the same hot/cold section as the switch jump itself
5372 // (maybe immediately after the switch jump), and make the "base" address be also in that section,
5373 // probably the address after the switch jump.
5374 opts.compProcedureSplitting = false;
5375 JITDUMP("Turning off procedure splitting for this method, as it might need switch tables; "
5376 "implementation limitation.\n");
5378 #endif // !LEGACY_BACKEND
5383 bbFlags |= BBF_DONT_REMOVE;
5384 jmpKind = BBJ_EHFILTERRET;
5387 case CEE_ENDFINALLY:
5388 jmpKind = BBJ_EHFINALLYRET;
5392 if (compIsForInlining())
5394 // TODO-CQ: We can inline some callees with explicit tail calls if we can guarantee that the calls
5395 // can be dispatched as tail calls from the caller.
5396 compInlineResult->NoteFatal(InlineObservation::CALLEE_EXPLICIT_TAIL_PREFIX);
5404 case CEE_CONSTRAINED:
5407 // fgFindJumpTargets should have ruled out this possibility
5408 // (i.e. a prefix opcodes as last intruction in a block)
5409 noway_assert(codeAddr < codeEndp);
5411 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5413 BADCODE3("jump target between prefix and an opcode", " at offset %04X",
5414 (IL_OFFSET)(codeAddr - codeBegp));
5422 if (compIsForInlining() || // Ignore tail call in the inlinee. Period.
5423 (!tailCall && !compTailCallStress()) // A new BB with BBJ_RETURN would have been created
5425 // after a tailcall statement.
5426 // We need to keep this invariant if we want to stress the tailcall.
5427 // That way, the potential (tail)call statement is always the last
5428 // statement in the block.
5429 // Otherwise, we will assert at the following line in fgMorphCall()
5430 // noway_assert(fgMorphStmt->gtNext == NULL);
5433 // Neither .tailcall prefix, no tailcall stress. So move on.
5437 // Make sure the code sequence is legal for the tail call.
5438 // If so, mark this BB as having a BBJ_RETURN.
5440 if (codeAddr >= codeEndp - sz)
5442 BADCODE3("No code found after the call instruction", " at offset %04X",
5443 (IL_OFFSET)(codeAddr - codeBegp));
5448 bool isCallPopAndRet = false;
5450 // impIsTailCallILPattern uses isRecursive flag to determine whether ret in a fallthrough block is
5451 // allowed. We don't know at this point whether the call is recursive so we conservatively pass
5452 // false. This will only affect explicit tail calls when IL verification is not needed for the
5454 bool isRecursive = false;
5455 if (!impIsTailCallILPattern(tailCall, opcode, codeAddr + sz, codeEndp, isRecursive,
5458 #ifdef _TARGET_AMD64_
5459 BADCODE3("tail call not followed by ret or pop+ret", " at offset %04X",
5460 (IL_OFFSET)(codeAddr - codeBegp));
5462 BADCODE3("tail call not followed by ret", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5463 #endif //_TARGET_AMD64_
5466 #ifdef _TARGET_AMD64_
5467 if (isCallPopAndRet)
5469 // By breaking here, we let pop and ret opcodes to be
5470 // imported after tail call. If tail prefix is honored,
5471 // stmts corresponding to pop and ret will be removed
5472 // in fgMorphCall().
5475 #endif //_TARGET_AMD64_
5479 OPCODE nextOpcode = (OPCODE)getU1LittleEndian(codeAddr + sz);
5481 if (nextOpcode != CEE_RET)
5483 noway_assert(compTailCallStress());
5484 // Next OPCODE is not a CEE_RET, bail the attempt to stress the tailcall.
5485 // (I.e. We will not make a new BB after the "call" statement.)
5491 /* For tail call, we just call CORINFO_HELP_TAILCALL, and it jumps to the
5492 target. So we don't need an epilog - just like CORINFO_HELP_THROW.
5493 Make the block BBJ_RETURN, but we will change it to BBJ_THROW
5494 if the tailness of the call is satisfied.
5495 NOTE : The next instruction is guaranteed to be a CEE_RET
5496 and it will create another BasicBlock. But there may be an
5497 jump directly to that CEE_RET. If we want to avoid creating
5498 an unnecessary block, we need to check if the CEE_RETURN is
5499 the target of a jump.
5505 /* These are equivalent to a return from the current method
5506 But instead of directly returning to the caller we jump and
5507 execute something else in between */
5510 jmpKind = BBJ_RETURN;
5515 jmpKind = BBJ_THROW;
5519 // make certain we did not forget any flow of control instructions
5520 // by checking the 'ctrl' field in opcode.def. First filter out all
5521 // non-ctrl instructions
5522 #define BREAK(name) \
5525 #define NEXT(name) \
5530 #undef RETURN // undef contract RETURN macro
5531 #define RETURN(name)
5533 #define BRANCH(name)
5534 #define COND_BRANCH(name)
5537 #define OPDEF(name, string, pop, push, oprType, opcType, l, s1, s2, ctrl) ctrl(name)
5538 #include "opcode.def"
5551 // These ctrl-flow opcodes don't need any special handling
5552 case CEE_NEWOBJ: // CTRL_CALL
5555 // what's left are forgotten instructions
5557 BADCODE("Unrecognized control Opcode");
5565 /* Jump over the operand */
5571 tailCall = (opcode == CEE_TAILCALL);
5573 /* Make sure a jump target isn't in the middle of our opcode */
5577 IL_OFFSET offs = (IL_OFFSET)(codeAddr - codeBegp) - sz; // offset of the operand
5579 for (unsigned i = 0; i < sz; i++, offs++)
5581 if (jumpTarget[offs] != JT_NONE)
5583 BADCODE3("jump into the middle of an opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5588 /* Compute the offset of the next opcode */
5590 nxtBBoffs = (IL_OFFSET)(codeAddr - codeBegp);
5592 bool foundScope = false;
5594 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5596 while (compGetNextEnterScope(nxtBBoffs))
5600 while (compGetNextExitScope(nxtBBoffs))
5606 /* Do we have a jump? */
5608 if (jmpKind == BBJ_NONE)
5610 /* No jump; make sure we don't fall off the end of the function */
5612 if (codeAddr == codeEndp)
5614 BADCODE3("missing return opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5617 /* If a label follows this opcode, we'll have to make a new BB */
5619 bool makeBlock = (jumpTarget[nxtBBoffs] != JT_NONE);
5621 if (!makeBlock && foundScope)
5627 printf("Splitting at BBoffs = %04u\n", nxtBBoffs);
5638 /* We need to create a new basic block */
5640 curBBdesc = fgNewBasicBlock(jmpKind);
5642 curBBdesc->bbFlags |= bbFlags;
5643 curBBdesc->bbRefs = 0;
5645 curBBdesc->bbCodeOffs = curBBoffs;
5646 curBBdesc->bbCodeOffsEnd = nxtBBoffs;
5648 unsigned profileWeight;
5649 if (fgGetProfileWeightForBasicBlock(curBBoffs, &profileWeight))
5651 curBBdesc->setBBProfileWeight(profileWeight);
5652 if (profileWeight == 0)
5654 curBBdesc->bbSetRunRarely();
5658 // Note that bbNewBasicBlock (called from fgNewBasicBlock) may have
5659 // already marked the block as rarely run. In that case (and when we know
5660 // that the block profile weight is non-zero) we want to unmark that.
5662 curBBdesc->bbFlags &= ~BBF_RUN_RARELY;
5669 curBBdesc->bbJumpSwt = swtDsc;
5675 noway_assert(jmpAddr != DUMMY_INIT(BAD_IL_OFFSET));
5676 curBBdesc->bbJumpOffs = jmpAddr;
5683 DBEXEC(verbose, curBBdesc->dspBlockHeader(this, false, false, false));
5685 /* Remember where the next BB will start */
5687 curBBoffs = nxtBBoffs;
5688 } while (codeAddr < codeEndp);
5690 noway_assert(codeAddr == codeEndp);
5692 /* Finally link up the bbJumpDest of the blocks together */
5694 fgLinkBasicBlocks();
5699 /*****************************************************************************
5701 * Main entry point to discover the basic blocks for the current function.
5704 void Compiler::fgFindBasicBlocks()
5709 printf("*************** In fgFindBasicBlocks() for %s\n", info.compFullName);
5713 /* Allocate the 'jump target' vector
5715 * We need one extra byte as we mark
5716 * jumpTarget[info.compILCodeSize] with JT_ADDR
5717 * when we need to add a dummy block
5718 * to record the end of a try or handler region.
5720 BYTE* jumpTarget = new (this, CMK_Unknown) BYTE[info.compILCodeSize + 1];
5721 memset(jumpTarget, JT_NONE, info.compILCodeSize + 1);
5722 noway_assert(JT_NONE == 0);
5724 /* Walk the instrs to find all jump targets */
5726 fgFindJumpTargets(info.compCode, info.compILCodeSize, jumpTarget);
5727 if (compDonotInline())
5734 /* Are there any exception handlers? */
5736 if (info.compXcptnsCount > 0)
5738 noway_assert(!compIsForInlining());
5740 /* Check and mark all the exception handlers */
5742 for (XTnum = 0; XTnum < info.compXcptnsCount; XTnum++)
5745 CORINFO_EH_CLAUSE clause;
5746 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5747 noway_assert(clause.HandlerLength != (unsigned)-1);
5749 if (clause.TryLength <= 0)
5751 BADCODE("try block length <=0");
5754 /* Mark the 'try' block extent and the handler itself */
5756 if (clause.TryOffset > info.compILCodeSize)
5758 BADCODE("try offset is > codesize");
5760 if (jumpTarget[clause.TryOffset] == JT_NONE)
5762 jumpTarget[clause.TryOffset] = JT_ADDR;
5765 tmpOffset = clause.TryOffset + clause.TryLength;
5766 if (tmpOffset > info.compILCodeSize)
5768 BADCODE("try end is > codesize");
5770 if (jumpTarget[tmpOffset] == JT_NONE)
5772 jumpTarget[tmpOffset] = JT_ADDR;
5775 if (clause.HandlerOffset > info.compILCodeSize)
5777 BADCODE("handler offset > codesize");
5779 if (jumpTarget[clause.HandlerOffset] == JT_NONE)
5781 jumpTarget[clause.HandlerOffset] = JT_ADDR;
5784 tmpOffset = clause.HandlerOffset + clause.HandlerLength;
5785 if (tmpOffset > info.compILCodeSize)
5787 BADCODE("handler end > codesize");
5789 if (jumpTarget[tmpOffset] == JT_NONE)
5791 jumpTarget[tmpOffset] = JT_ADDR;
5794 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5796 if (clause.FilterOffset > info.compILCodeSize)
5798 BADCODE("filter offset > codesize");
5800 if (jumpTarget[clause.FilterOffset] == JT_NONE)
5802 jumpTarget[clause.FilterOffset] = JT_ADDR;
5811 bool anyJumpTargets = false;
5812 printf("Jump targets:\n");
5813 for (unsigned i = 0; i < info.compILCodeSize + 1; i++)
5815 if (jumpTarget[i] == JT_NONE)
5820 anyJumpTargets = true;
5821 printf(" IL_%04x", i);
5823 if (jumpTarget[i] & JT_ADDR)
5827 if (jumpTarget[i] & JT_MULTI)
5833 if (!anyJumpTargets)
5840 /* Now create the basic blocks */
5842 unsigned retBlocks = fgMakeBasicBlocks(info.compCode, info.compILCodeSize, jumpTarget);
5844 if (compIsForInlining())
5848 // If fgFindJumpTargets marked the call as "no return" there
5849 // really should be no BBJ_RETURN blocks in the method.
5851 // Note LegacyPolicy does not mark calls as no return, so if
5852 // it's active, skip the check.
5853 if (!compInlineResult->UsesLegacyPolicy())
5855 bool markedNoReturn = (impInlineInfo->iciCall->gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) != 0;
5856 assert((markedNoReturn && (retBlocks == 0)) || (!markedNoReturn && (retBlocks >= 1)));
5860 if (compInlineResult->IsFailure())
5865 noway_assert(info.compXcptnsCount == 0);
5866 compHndBBtab = impInlineInfo->InlinerCompiler->compHndBBtab;
5867 compHndBBtabAllocCount =
5868 impInlineInfo->InlinerCompiler->compHndBBtabAllocCount; // we probably only use the table, not add to it.
5869 compHndBBtabCount = impInlineInfo->InlinerCompiler->compHndBBtabCount;
5870 info.compXcptnsCount = impInlineInfo->InlinerCompiler->info.compXcptnsCount;
5872 // Use a spill temp for the return value if there are multiple return blocks,
5873 // or if the inlinee has GC ref locals.
5874 if ((info.compRetNativeType != TYP_VOID) && ((retBlocks > 1) || impInlineInfo->HasGcRefLocals()))
5876 // The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp.
5877 lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline return value spill temp"));
5878 lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetNativeType;
5884 /* Mark all blocks within 'try' blocks as such */
5886 if (info.compXcptnsCount == 0)
5891 if (info.compXcptnsCount > MAX_XCPTN_INDEX)
5893 IMPL_LIMITATION("too many exception clauses");
5896 /* Allocate the exception handler table */
5900 /* Assume we don't need to sort the EH table (such that nested try/catch
5901 * appear before their try or handler parent). The EH verifier will notice
5902 * when we do need to sort it.
5905 fgNeedToSortEHTable = false;
5907 verInitEHTree(info.compXcptnsCount);
5908 EHNodeDsc* initRoot = ehnNext; // remember the original root since
5909 // it may get modified during insertion
5911 // Annotate BBs with exception handling information required for generating correct eh code
5912 // as well as checking for correct IL
5916 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
5918 CORINFO_EH_CLAUSE clause;
5919 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5920 noway_assert(clause.HandlerLength != (unsigned)-1); // @DEPRECATED
5925 dispIncomingEHClause(XTnum, clause);
5929 IL_OFFSET tryBegOff = clause.TryOffset;
5930 IL_OFFSET tryEndOff = tryBegOff + clause.TryLength;
5931 IL_OFFSET filterBegOff = 0;
5932 IL_OFFSET hndBegOff = clause.HandlerOffset;
5933 IL_OFFSET hndEndOff = hndBegOff + clause.HandlerLength;
5935 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5937 filterBegOff = clause.FilterOffset;
5940 if (tryEndOff > info.compILCodeSize)
5942 BADCODE3("end of try block beyond end of method for try", " at offset %04X", tryBegOff);
5944 if (hndEndOff > info.compILCodeSize)
5946 BADCODE3("end of hnd block beyond end of method for try", " at offset %04X", tryBegOff);
5949 HBtab->ebdTryBegOffset = tryBegOff;
5950 HBtab->ebdTryEndOffset = tryEndOff;
5951 HBtab->ebdFilterBegOffset = filterBegOff;
5952 HBtab->ebdHndBegOffset = hndBegOff;
5953 HBtab->ebdHndEndOffset = hndEndOff;
5955 /* Convert the various addresses to basic blocks */
5957 BasicBlock* tryBegBB = fgLookupBB(tryBegOff);
5958 BasicBlock* tryEndBB =
5959 fgLookupBB(tryEndOff); // note: this can be NULL if the try region is at the end of the function
5960 BasicBlock* hndBegBB = fgLookupBB(hndBegOff);
5961 BasicBlock* hndEndBB = nullptr;
5962 BasicBlock* filtBB = nullptr;
5966 // Assert that the try/hnd beginning blocks are set up correctly
5968 if (tryBegBB == nullptr)
5970 BADCODE("Try Clause is invalid");
5973 if (hndBegBB == nullptr)
5975 BADCODE("Handler Clause is invalid");
5978 tryBegBB->bbFlags |= BBF_HAS_LABEL;
5979 hndBegBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
5981 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
5982 // This will change the block weight from 0 to 1
5983 // and clear the rarely run flag
5984 hndBegBB->makeBlockHot();
5986 hndBegBB->bbSetRunRarely(); // handler entry points are rarely executed
5989 if (hndEndOff < info.compILCodeSize)
5991 hndEndBB = fgLookupBB(hndEndOff);
5994 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5996 filtBB = HBtab->ebdFilter = fgLookupBB(clause.FilterOffset);
5998 filtBB->bbCatchTyp = BBCT_FILTER;
5999 filtBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
6001 hndBegBB->bbCatchTyp = BBCT_FILTER_HANDLER;
6003 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
6004 // This will change the block weight from 0 to 1
6005 // and clear the rarely run flag
6006 filtBB->makeBlockHot();
6008 filtBB->bbSetRunRarely(); // filter entry points are rarely executed
6011 // Mark all BBs that belong to the filter with the XTnum of the corresponding handler
6012 for (block = filtBB; /**/; block = block->bbNext)
6014 if (block == nullptr)
6016 BADCODE3("Missing endfilter for filter", " at offset %04X", filtBB->bbCodeOffs);
6020 // Still inside the filter
6021 block->setHndIndex(XTnum);
6023 if (block->bbJumpKind == BBJ_EHFILTERRET)
6025 // Mark catch handler as successor.
6026 block->bbJumpDest = hndBegBB;
6027 assert(block->bbJumpDest->bbCatchTyp == BBCT_FILTER_HANDLER);
6032 if (!block->bbNext || block->bbNext != hndBegBB)
6034 BADCODE3("Filter does not immediately precede handler for filter", " at offset %04X",
6035 filtBB->bbCodeOffs);
6040 HBtab->ebdTyp = clause.ClassToken;
6042 /* Set bbCatchTyp as appropriate */
6044 if (clause.Flags & CORINFO_EH_CLAUSE_FINALLY)
6046 hndBegBB->bbCatchTyp = BBCT_FINALLY;
6050 if (clause.Flags & CORINFO_EH_CLAUSE_FAULT)
6052 hndBegBB->bbCatchTyp = BBCT_FAULT;
6056 hndBegBB->bbCatchTyp = clause.ClassToken;
6058 // These values should be non-zero value that will
6059 // not collide with real tokens for bbCatchTyp
6060 if (clause.ClassToken == 0)
6062 BADCODE("Exception catch type is Null");
6065 noway_assert(clause.ClassToken != BBCT_FAULT);
6066 noway_assert(clause.ClassToken != BBCT_FINALLY);
6067 noway_assert(clause.ClassToken != BBCT_FILTER);
6068 noway_assert(clause.ClassToken != BBCT_FILTER_HANDLER);
6073 /* Mark the initial block and last blocks in the 'try' region */
6075 tryBegBB->bbFlags |= BBF_TRY_BEG | BBF_HAS_LABEL;
6077 /* Prevent future optimizations of removing the first block */
6078 /* of a TRY block and the first block of an exception handler */
6080 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
6081 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
6082 hndBegBB->bbRefs++; // The first block of a handler gets an extra, "artificial" reference count.
6084 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
6086 filtBB->bbFlags |= BBF_DONT_REMOVE;
6087 filtBB->bbRefs++; // The first block of a filter gets an extra, "artificial" reference count.
6090 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
6091 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
6094 // Store the info to the table of EH block handlers
6097 HBtab->ebdHandlerType = ToEHHandlerType(clause.Flags);
6099 HBtab->ebdTryBeg = tryBegBB;
6100 HBtab->ebdTryLast = (tryEndBB == nullptr) ? fgLastBB : tryEndBB->bbPrev;
6102 HBtab->ebdHndBeg = hndBegBB;
6103 HBtab->ebdHndLast = (hndEndBB == nullptr) ? fgLastBB : hndEndBB->bbPrev;
6106 // Assert that all of our try/hnd blocks are setup correctly.
6108 if (HBtab->ebdTryLast == nullptr)
6110 BADCODE("Try Clause is invalid");
6113 if (HBtab->ebdHndLast == nullptr)
6115 BADCODE("Handler Clause is invalid");
6119 // Verify that it's legal
6122 verInsertEhNode(&clause, HBtab);
6124 } // end foreach handler table entry
6128 // Next, set things related to nesting that depend on the sorting being complete.
6130 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6132 /* Mark all blocks in the finally/fault or catch clause */
6134 BasicBlock* tryBegBB = HBtab->ebdTryBeg;
6135 BasicBlock* hndBegBB = HBtab->ebdHndBeg;
6137 IL_OFFSET tryBegOff = HBtab->ebdTryBegOffset;
6138 IL_OFFSET tryEndOff = HBtab->ebdTryEndOffset;
6140 IL_OFFSET hndBegOff = HBtab->ebdHndBegOffset;
6141 IL_OFFSET hndEndOff = HBtab->ebdHndEndOffset;
6145 for (block = hndBegBB; block && (block->bbCodeOffs < hndEndOff); block = block->bbNext)
6147 if (!block->hasHndIndex())
6149 block->setHndIndex(XTnum);
6152 // All blocks in a catch handler or filter are rarely run, except the entry
6153 if ((block != hndBegBB) && (hndBegBB->bbCatchTyp != BBCT_FINALLY))
6155 block->bbSetRunRarely();
6159 /* Mark all blocks within the covered range of the try */
6161 for (block = tryBegBB; block && (block->bbCodeOffs < tryEndOff); block = block->bbNext)
6163 /* Mark this BB as belonging to a 'try' block */
6165 if (!block->hasTryIndex())
6167 block->setTryIndex(XTnum);
6171 /* Note: the BB can't span the 'try' block */
6173 if (!(block->bbFlags & BBF_INTERNAL))
6175 noway_assert(tryBegOff <= block->bbCodeOffs);
6176 noway_assert(tryEndOff >= block->bbCodeOffsEnd || tryEndOff == tryBegOff);
6181 /* Init ebdHandlerNestingLevel of current clause, and bump up value for all
6182 * enclosed clauses (which have to be before it in the table).
6183 * Innermost try-finally blocks must precede outermost
6184 * try-finally blocks.
6187 #if !FEATURE_EH_FUNCLETS
6188 HBtab->ebdHandlerNestingLevel = 0;
6189 #endif // !FEATURE_EH_FUNCLETS
6191 HBtab->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6192 HBtab->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6194 noway_assert(XTnum < compHndBBtabCount);
6195 noway_assert(XTnum == ehGetIndex(HBtab));
6197 for (EHblkDsc* xtab = compHndBBtab; xtab < HBtab; xtab++)
6199 #if !FEATURE_EH_FUNCLETS
6200 if (jitIsBetween(xtab->ebdHndBegOffs(), hndBegOff, hndEndOff))
6202 xtab->ebdHandlerNestingLevel++;
6204 #endif // !FEATURE_EH_FUNCLETS
6206 /* If we haven't recorded an enclosing try index for xtab then see
6207 * if this EH region should be recorded. We check if the
6208 * first offset in the xtab lies within our region. If so,
6209 * the last offset also must lie within the region, due to
6210 * nesting rules. verInsertEhNode(), below, will check for proper nesting.
6212 if (xtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6214 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), tryBegOff, tryEndOff);
6217 // Record the enclosing scope link
6218 xtab->ebdEnclosingTryIndex = (unsigned short)XTnum;
6222 /* Do the same for the enclosing handler index.
6224 if (xtab->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6226 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), hndBegOff, hndEndOff);
6229 // Record the enclosing scope link
6230 xtab->ebdEnclosingHndIndex = (unsigned short)XTnum;
6235 } // end foreach handler table entry
6237 #if !FEATURE_EH_FUNCLETS
6240 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
6242 if (ehMaxHndNestingCount <= HBtab->ebdHandlerNestingLevel)
6243 ehMaxHndNestingCount = HBtab->ebdHandlerNestingLevel + 1;
6246 #endif // !FEATURE_EH_FUNCLETS
6249 if (tiVerificationNeeded)
6252 // always run these checks for a debug build
6253 verCheckNestingLevel(initRoot);
6257 // fgNormalizeEH assumes that this test has been passed. And Ssa assumes that fgNormalizeEHTable
6258 // has been run. So do this unless we're in minOpts mode (and always in debug).
6259 if (tiVerificationNeeded || !opts.MinOpts())
6262 fgCheckBasicBlockControlFlow();
6268 JITDUMP("*************** After fgFindBasicBlocks() has created the EH table\n");
6272 // We can't verify the handler table until all the IL legality checks have been done (above), since bad IL
6273 // (such as illegal nesting of regions) will trigger asserts here.
6274 fgVerifyHandlerTab();
6280 /*****************************************************************************
6281 * Check control flow constraints for well formed IL. Bail if any of the constraints
6285 void Compiler::fgCheckBasicBlockControlFlow()
6287 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6291 for (BasicBlock* blk = fgFirstBB; blk; blk = blk->bbNext)
6293 if (blk->bbFlags & BBF_INTERNAL)
6298 switch (blk->bbJumpKind)
6300 case BBJ_NONE: // block flows into the next one (no jump)
6302 fgControlFlowPermitted(blk, blk->bbNext);
6306 case BBJ_ALWAYS: // block does unconditional jump to target
6308 fgControlFlowPermitted(blk, blk->bbJumpDest);
6312 case BBJ_COND: // block conditionally jumps to the target
6314 fgControlFlowPermitted(blk, blk->bbNext);
6316 fgControlFlowPermitted(blk, blk->bbJumpDest);
6320 case BBJ_RETURN: // block ends with 'ret'
6322 if (blk->hasTryIndex() || blk->hasHndIndex())
6324 BADCODE3("Return from a protected block", ". Before offset %04X", blk->bbCodeOffsEnd);
6328 case BBJ_EHFINALLYRET:
6329 case BBJ_EHFILTERRET:
6331 if (!blk->hasHndIndex()) // must be part of a handler
6333 BADCODE3("Missing handler", ". Before offset %04X", blk->bbCodeOffsEnd);
6336 HBtab = ehGetDsc(blk->getHndIndex());
6338 // Endfilter allowed only in a filter block
6339 if (blk->bbJumpKind == BBJ_EHFILTERRET)
6341 if (!HBtab->HasFilter())
6343 BADCODE("Unexpected endfilter");
6346 // endfinally allowed only in a finally/fault block
6347 else if (!HBtab->HasFinallyOrFaultHandler())
6349 BADCODE("Unexpected endfinally");
6352 // The handler block should be the innermost block
6353 // Exception blocks are listed, innermost first.
6354 if (blk->hasTryIndex() && (blk->getTryIndex() < blk->getHndIndex()))
6356 BADCODE("endfinally / endfilter in nested try block");
6361 case BBJ_THROW: // block ends with 'throw'
6362 /* throw is permitted from every BB, so nothing to check */
6363 /* importer makes sure that rethrow is done from a catch */
6366 case BBJ_LEAVE: // block always jumps to the target, maybe out of guarded
6367 // region. Used temporarily until importing
6368 fgControlFlowPermitted(blk, blk->bbJumpDest, TRUE);
6372 case BBJ_SWITCH: // block ends with a switch statement
6375 swtDesc = blk->bbJumpSwt;
6380 for (i = 0; i < swtDesc->bbsCount; i++)
6382 fgControlFlowPermitted(blk, swtDesc->bbsDstTab[i]);
6387 case BBJ_EHCATCHRET: // block ends with a leave out of a catch (only #if FEATURE_EH_FUNCLETS)
6388 case BBJ_CALLFINALLY: // block always calls the target finally
6390 noway_assert(!"Unexpected bbJumpKind"); // these blocks don't get created until importing
6396 /****************************************************************************
6397 * Check that the leave from the block is legal.
6398 * Consider removing this check here if we can do it cheaply during importing
6401 void Compiler::fgControlFlowPermitted(BasicBlock* blkSrc, BasicBlock* blkDest, BOOL isLeave)
6403 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6405 unsigned srcHndBeg, destHndBeg;
6406 unsigned srcHndEnd, destHndEnd;
6407 bool srcInFilter, destInFilter;
6408 bool srcInCatch = false;
6410 EHblkDsc* srcHndTab;
6412 srcHndTab = ehInitHndRange(blkSrc, &srcHndBeg, &srcHndEnd, &srcInFilter);
6413 ehInitHndRange(blkDest, &destHndBeg, &destHndEnd, &destInFilter);
6415 /* Impose the rules for leaving or jumping from handler blocks */
6417 if (blkSrc->hasHndIndex())
6419 srcInCatch = srcHndTab->HasCatchHandler() && srcHndTab->InHndRegionILRange(blkSrc);
6421 /* Are we jumping within the same handler index? */
6422 if (BasicBlock::sameHndRegion(blkSrc, blkDest))
6424 /* Do we have a filter clause? */
6425 if (srcHndTab->HasFilter())
6427 /* filters and catch handlers share same eh index */
6428 /* we need to check for control flow between them. */
6429 if (srcInFilter != destInFilter)
6431 if (!jitIsBetween(blkDest->bbCodeOffs, srcHndBeg, srcHndEnd))
6433 BADCODE3("Illegal control flow between filter and handler", ". Before offset %04X",
6434 blkSrc->bbCodeOffsEnd);
6441 /* The handler indexes of blkSrc and blkDest are different */
6444 /* Any leave instructions must not enter the dest handler from outside*/
6445 if (!jitIsBetween(srcHndBeg, destHndBeg, destHndEnd))
6447 BADCODE3("Illegal use of leave to enter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6452 /* We must use a leave to exit a handler */
6453 BADCODE3("Illegal control flow out of a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6456 /* Do we have a filter clause? */
6457 if (srcHndTab->HasFilter())
6459 /* It is ok to leave from the handler block of a filter, */
6460 /* but not from the filter block of a filter */
6461 if (srcInFilter != destInFilter)
6463 BADCODE3("Illegal to leave a filter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6467 /* We should never leave a finally handler */
6468 if (srcHndTab->HasFinallyHandler())
6470 BADCODE3("Illegal to leave a finally handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6473 /* We should never leave a fault handler */
6474 if (srcHndTab->HasFaultHandler())
6476 BADCODE3("Illegal to leave a fault handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6480 else if (blkDest->hasHndIndex())
6482 /* blkSrc was not inside a handler, but blkDst is inside a handler */
6483 BADCODE3("Illegal control flow into a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6486 /* Are we jumping from a catch handler into the corresponding try? */
6487 /* VB uses this for "on error goto " */
6489 if (isLeave && srcInCatch)
6491 // inspect all handlers containing the jump source
6493 bool bValidJumpToTry = false; // are we jumping in a valid way from a catch to the corresponding try?
6494 bool bCatchHandlerOnly = true; // false if we are jumping out of a non-catch handler
6495 EHblkDsc* ehTableEnd;
6498 for (ehDsc = compHndBBtab, ehTableEnd = compHndBBtab + compHndBBtabCount;
6499 bCatchHandlerOnly && ehDsc < ehTableEnd; ehDsc++)
6501 if (ehDsc->InHndRegionILRange(blkSrc))
6503 if (ehDsc->HasCatchHandler())
6505 if (ehDsc->InTryRegionILRange(blkDest))
6507 // If we already considered the jump for a different try/catch,
6508 // we would have two overlapping try regions with two overlapping catch
6509 // regions, which is illegal.
6510 noway_assert(!bValidJumpToTry);
6512 // Allowed if it is the first instruction of an inner try
6513 // (and all trys in between)
6523 // _tryNestedIllegal:
6535 // leave _tryAgain // Allowed
6537 // leave _tryNestedInner // Allowed
6539 // leave _tryNestedIllegal // Not Allowed
6543 // Note: The leave is allowed also from catches nested inside the catch shown above.
6545 /* The common case where leave is to the corresponding try */
6546 if (ehDsc->ebdIsSameTry(this, blkDest->getTryIndex()) ||
6547 /* Also allowed is a leave to the start of a try which starts in the handler's try */
6548 fgFlowToFirstBlockOfInnerTry(ehDsc->ebdTryBeg, blkDest, false))
6550 bValidJumpToTry = true;
6556 // We are jumping from a handler which is not a catch handler.
6558 // If it's a handler, but not a catch handler, it must be either a finally or fault
6559 if (!ehDsc->HasFinallyOrFaultHandler())
6561 BADCODE3("Handlers must be catch, finally, or fault", ". Before offset %04X",
6562 blkSrc->bbCodeOffsEnd);
6565 // Are we jumping out of this handler?
6566 if (!ehDsc->InHndRegionILRange(blkDest))
6568 bCatchHandlerOnly = false;
6572 else if (ehDsc->InFilterRegionILRange(blkSrc))
6574 // Are we jumping out of a filter?
6575 if (!ehDsc->InFilterRegionILRange(blkDest))
6577 bCatchHandlerOnly = false;
6582 if (bCatchHandlerOnly)
6584 if (bValidJumpToTry)
6591 // This is either the case of a leave to outside the try/catch,
6592 // or a leave to a try not nested in this try/catch.
6593 // The first case is allowed, the second one will be checked
6594 // later when we check the try block rules (it is illegal if we
6595 // jump to the middle of the destination try).
6600 BADCODE3("illegal leave to exit a finally, fault or filter", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6604 /* Check all the try block rules */
6606 IL_OFFSET srcTryBeg;
6607 IL_OFFSET srcTryEnd;
6608 IL_OFFSET destTryBeg;
6609 IL_OFFSET destTryEnd;
6611 ehInitTryRange(blkSrc, &srcTryBeg, &srcTryEnd);
6612 ehInitTryRange(blkDest, &destTryBeg, &destTryEnd);
6614 /* Are we jumping between try indexes? */
6615 if (!BasicBlock::sameTryRegion(blkSrc, blkDest))
6617 // Are we exiting from an inner to outer try?
6618 if (jitIsBetween(srcTryBeg, destTryBeg, destTryEnd) && jitIsBetween(srcTryEnd - 1, destTryBeg, destTryEnd))
6622 BADCODE3("exit from try block without a leave", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6625 else if (jitIsBetween(destTryBeg, srcTryBeg, srcTryEnd))
6627 // check that the dest Try is first instruction of an inner try
6628 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, false))
6630 BADCODE3("control flow into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6633 else // there is no nesting relationship between src and dest
6637 // check that the dest Try is first instruction of an inner try sibling
6638 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, true))
6640 BADCODE3("illegal leave into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6645 BADCODE3("illegal control flow in to/out of try block", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6651 /*****************************************************************************
6652 * Check that blkDest is the first block of an inner try or a sibling
6653 * with no intervening trys in between
6656 bool Compiler::fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling)
6658 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6660 noway_assert(blkDest->hasTryIndex());
6662 unsigned XTnum = blkDest->getTryIndex();
6663 unsigned lastXTnum = blkSrc->hasTryIndex() ? blkSrc->getTryIndex() : compHndBBtabCount;
6664 noway_assert(XTnum < compHndBBtabCount);
6665 noway_assert(lastXTnum <= compHndBBtabCount);
6667 EHblkDsc* HBtab = ehGetDsc(XTnum);
6669 // check that we are not jumping into middle of try
6670 if (HBtab->ebdTryBeg != blkDest)
6677 noway_assert(!BasicBlock::sameTryRegion(blkSrc, blkDest));
6679 // find the l.u.b of the two try ranges
6680 // Set lastXTnum to the l.u.b.
6682 HBtab = ehGetDsc(lastXTnum);
6684 for (lastXTnum++, HBtab++; lastXTnum < compHndBBtabCount; lastXTnum++, HBtab++)
6686 if (jitIsBetweenInclusive(blkDest->bbNum, HBtab->ebdTryBeg->bbNum, HBtab->ebdTryLast->bbNum))
6693 // now check there are no intervening trys between dest and l.u.b
6694 // (it is ok to have intervening trys as long as they all start at
6695 // the same code offset)
6697 HBtab = ehGetDsc(XTnum);
6699 for (XTnum++, HBtab++; XTnum < lastXTnum; XTnum++, HBtab++)
6701 if (HBtab->ebdTryBeg->bbNum < blkDest->bbNum && blkDest->bbNum <= HBtab->ebdTryLast->bbNum)
6710 /*****************************************************************************
6711 * Returns the handler nesting level of the block.
6712 * *pFinallyNesting is set to the nesting level of the inner-most
6713 * finally-protected try the block is in.
6716 unsigned Compiler::fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting)
6718 unsigned curNesting = 0; // How many handlers is the block in
6719 unsigned tryFin = (unsigned)-1; // curNesting when we see innermost finally-protected try
6723 /* We find the block's handler nesting level by walking over the
6724 complete exception table and find enclosing clauses. */
6726 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6728 noway_assert(HBtab->ebdTryBeg && HBtab->ebdHndBeg);
6730 if (HBtab->HasFinallyHandler() && (tryFin == (unsigned)-1) && bbInTryRegions(XTnum, block))
6732 tryFin = curNesting;
6734 else if (bbInHandlerRegions(XTnum, block))
6740 if (tryFin == (unsigned)-1)
6742 tryFin = curNesting;
6745 if (pFinallyNesting)
6747 *pFinallyNesting = curNesting - tryFin;
6753 /*****************************************************************************
6755 * Import the basic blocks of the procedure.
6758 void Compiler::fgImport()
6760 fgHasPostfix = false;
6762 impImport(fgFirstBB);
6764 if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION))
6766 CorInfoMethodRuntimeFlags verFlag;
6767 verFlag = tiIsVerifiableCode ? CORINFO_FLG_VERIFIABLE : CORINFO_FLG_UNVERIFIABLE;
6768 info.compCompHnd->setMethodAttribs(info.compMethodHnd, verFlag);
6772 /*****************************************************************************
6773 * This function returns true if tree is a node with a call
6774 * that unconditionally throws an exception
6777 bool Compiler::fgIsThrow(GenTreePtr tree)
6779 if ((tree->gtOper != GT_CALL) || (tree->gtCall.gtCallType != CT_HELPER))
6784 // TODO-Throughput: Replace all these calls to eeFindHelper() with a table based lookup
6786 if ((tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW)) ||
6787 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VERIFICATION)) ||
6788 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
6789 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
6790 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
6791 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW)) ||
6792 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)))
6794 noway_assert(tree->gtFlags & GTF_CALL);
6795 noway_assert(tree->gtFlags & GTF_EXCEPT);
6799 // TODO-CQ: there are a bunch of managed methods in [mscorlib]System.ThrowHelper
6800 // that would be nice to recognize.
6805 /*****************************************************************************
6806 * This function returns true for blocks that are in different hot-cold regions.
6807 * It returns false when the blocks are both in the same regions
6810 bool Compiler::fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2)
6812 noway_assert(blk1 != nullptr);
6813 noway_assert(blk2 != nullptr);
6815 if (fgFirstColdBlock == nullptr)
6820 // If one block is Hot and the other is Cold then we are in different regions
6821 return ((blk1->bbFlags & BBF_COLD) != (blk2->bbFlags & BBF_COLD));
6824 bool Compiler::fgIsBlockCold(BasicBlock* blk)
6826 noway_assert(blk != nullptr);
6828 if (fgFirstColdBlock == nullptr)
6833 return ((blk->bbFlags & BBF_COLD) != 0);
6836 /*****************************************************************************
6837 * This function returns true if tree is a GT_COMMA node with a call
6838 * that unconditionally throws an exception
6841 bool Compiler::fgIsCommaThrow(GenTreePtr tree, bool forFolding /* = false */)
6843 // Instead of always folding comma throws,
6844 // with stress enabled we only fold half the time
6846 if (forFolding && compStressCompile(STRESS_FOLD, 50))
6848 return false; /* Don't fold */
6851 /* Check for cast of a GT_COMMA with a throw overflow */
6852 if ((tree->gtOper == GT_COMMA) && (tree->gtFlags & GTF_CALL) && (tree->gtFlags & GTF_EXCEPT))
6854 return (fgIsThrow(tree->gtOp.gtOp1));
6859 //------------------------------------------------------------------------
6860 // fgIsIndirOfAddrOfLocal: Determine whether "tree" is an indirection of a local.
6863 // tree - The tree node under consideration
6866 // If "tree" is a indirection (GT_IND, GT_BLK, or GT_OBJ) whose arg is an ADDR,
6867 // whose arg in turn is a LCL_VAR, return that LCL_VAR node, else nullptr.
6870 GenTreePtr Compiler::fgIsIndirOfAddrOfLocal(GenTreePtr tree)
6872 GenTreePtr res = nullptr;
6873 if (tree->OperIsIndir())
6875 GenTreePtr addr = tree->AsIndir()->Addr();
6877 // Post rationalization, we can have Indir(Lea(..) trees. Therefore to recognize
6878 // Indir of addr of a local, skip over Lea in Indir(Lea(base, index, scale, offset))
6879 // to get to base variable.
6880 if (addr->OperGet() == GT_LEA)
6882 // We use this method in backward dataflow after liveness computation - fgInterBlockLocalVarLiveness().
6883 // Therefore it is critical that we don't miss 'uses' of any local. It may seem this method overlooks
6884 // if the index part of the LEA has indir( someAddrOperator ( lclVar ) ) to search for a use but it's
6885 // covered by the fact we're traversing the expression in execution order and we also visit the index.
6886 GenTreeAddrMode* lea = addr->AsAddrMode();
6887 GenTreePtr base = lea->Base();
6889 if (base != nullptr)
6891 if (base->OperGet() == GT_IND)
6893 return fgIsIndirOfAddrOfLocal(base);
6895 // else use base as addr
6900 if (addr->OperGet() == GT_ADDR)
6902 GenTreePtr lclvar = addr->gtOp.gtOp1;
6903 if (lclvar->OperGet() == GT_LCL_VAR)
6908 else if (addr->OperGet() == GT_LCL_VAR_ADDR)
6916 GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper)
6918 bool bNeedClassID = true;
6919 unsigned callFlags = 0;
6921 var_types type = TYP_BYREF;
6923 // This is sort of ugly, as we have knowledge of what the helper is returning.
6924 // We need the return type.
6927 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
6928 bNeedClassID = false;
6931 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
6932 callFlags |= GTF_CALL_HOISTABLE;
6935 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
6936 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
6937 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
6938 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
6939 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
6940 // type = TYP_BYREF;
6943 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
6944 bNeedClassID = false;
6947 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
6948 callFlags |= GTF_CALL_HOISTABLE;
6951 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
6952 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
6953 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
6954 case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
6959 assert(!"unknown shared statics helper");
6963 GenTreeArgList* argList = nullptr;
6965 GenTreePtr opModuleIDArg;
6966 GenTreePtr opClassIDArg;
6974 clsID = info.compCompHnd->getClassDomainID(cls, &pclsID);
6976 moduleID = info.compCompHnd->getClassModuleIdForStatics(cls, nullptr, &pmoduleID);
6978 if (!(callFlags & GTF_CALL_HOISTABLE))
6980 if (info.compCompHnd->getClassAttribs(cls) & CORINFO_FLG_BEFOREFIELDINIT)
6982 callFlags |= GTF_CALL_HOISTABLE;
6988 opModuleIDArg = gtNewIconHandleNode((size_t)pmoduleID, GTF_ICON_CIDMID_HDL);
6989 opModuleIDArg = gtNewOperNode(GT_IND, TYP_I_IMPL, opModuleIDArg);
6990 opModuleIDArg->gtFlags |= GTF_IND_INVARIANT;
6994 opModuleIDArg = gtNewIconNode((size_t)moduleID, TYP_I_IMPL);
7001 opClassIDArg = gtNewIconHandleNode((size_t)pclsID, GTF_ICON_CIDMID_HDL);
7002 opClassIDArg = gtNewOperNode(GT_IND, TYP_INT, opClassIDArg);
7003 opClassIDArg->gtFlags |= GTF_IND_INVARIANT;
7007 opClassIDArg = gtNewIconNode(clsID, TYP_INT);
7010 // call the helper to get the base
7011 argList = gtNewArgList(opModuleIDArg, opClassIDArg);
7015 argList = gtNewArgList(opModuleIDArg);
7018 if (!s_helperCallProperties.NoThrow(helper))
7020 callFlags |= GTF_EXCEPT;
7023 return gtNewHelperCallNode(helper, type, callFlags, argList);
7026 GenTreeCall* Compiler::fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls)
7028 #ifdef FEATURE_READYTORUN_COMPILER
7029 if (opts.IsReadyToRun())
7031 CORINFO_RESOLVED_TOKEN resolvedToken;
7032 memset(&resolvedToken, 0, sizeof(resolvedToken));
7033 resolvedToken.hClass = cls;
7035 return impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_STATIC_BASE, TYP_BYREF);
7039 // Call the shared non gc static helper, as its the fastest
7040 return fgGetStaticsCCtorHelper(cls, info.compCompHnd->getSharedCCtorHelper(cls));
7044 // Returns true unless the address expression could
7045 // never represent a NULL
7047 bool Compiler::fgAddrCouldBeNull(GenTreePtr addr)
7049 if (addr->gtOper == GT_ADDR)
7051 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
7053 GenTreePtr cns1Tree = addr->gtOp.gtOp1;
7054 if (!cns1Tree->IsIconHandle())
7056 // Indirection of some random constant...
7057 // It is safest just to return true
7061 else if (addr->gtOp.gtOp1->OperIsLocalAddr())
7065 return false; // we can't have a null address
7067 else if (addr->gtOper == GT_ADD)
7069 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
7071 GenTreePtr cns1Tree = addr->gtOp.gtOp1;
7072 if (!cns1Tree->IsIconHandle())
7074 if (!fgIsBigOffset(cns1Tree->gtIntCon.gtIconVal))
7076 // Op1 was an ordinary small constant
7077 return fgAddrCouldBeNull(addr->gtOp.gtOp2);
7080 else // Op1 was a handle represented as a constant
7082 // Is Op2 also a constant?
7083 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
7085 GenTreePtr cns2Tree = addr->gtOp.gtOp2;
7086 // Is this an addition of a handle and constant
7087 if (!cns2Tree->IsIconHandle())
7089 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
7091 // Op2 was an ordinary small constant
7092 return false; // we can't have a null address
7100 // Op1 is not a constant
7102 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
7104 GenTreePtr cns2Tree = addr->gtOp.gtOp2;
7105 // Is this an addition of a small constant
7106 if (!cns2Tree->IsIconHandle())
7108 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
7110 // Op2 was an ordinary small constant
7111 return fgAddrCouldBeNull(addr->gtOp.gtOp1);
7117 return true; // default result: addr could be null
7120 /*****************************************************************************
7121 * Optimize the call to the delegate constructor.
7124 GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
7125 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
7126 CORINFO_RESOLVED_TOKEN* ldftnToken)
7128 noway_assert(call->gtCallType == CT_USER_FUNC);
7129 CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
7130 CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getMethodClass(methHnd);
7132 GenTreePtr targetMethod = call->gtCallArgs->Rest()->Current();
7133 noway_assert(targetMethod->TypeGet() == TYP_I_IMPL);
7134 genTreeOps oper = targetMethod->OperGet();
7135 CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
7136 GenTreePtr qmarkNode = nullptr;
7137 if (oper == GT_FTN_ADDR)
7139 targetMethodHnd = targetMethod->gtFptrVal.gtFptrMethod;
7141 else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
7143 GenTreePtr handleNode = targetMethod->gtCall.gtCallArgs->Rest()->Rest()->Current();
7145 if (handleNode->OperGet() == GT_CNS_INT)
7147 // it's a ldvirtftn case, fetch the methodhandle off the helper for ldvirtftn. It's the 3rd arg
7148 targetMethodHnd = CORINFO_METHOD_HANDLE(handleNode->gtIntCon.gtCompileTimeHandle);
7150 // Sometimes the argument to this is the result of a generic dictionary lookup, which shows
7151 // up as a GT_QMARK.
7152 else if (handleNode->OperGet() == GT_QMARK)
7154 qmarkNode = handleNode;
7157 // Sometimes we don't call CORINFO_HELP_VIRTUAL_FUNC_PTR but instead just call
7158 // CORINFO_HELP_RUNTIMEHANDLE_METHOD directly.
7159 else if (oper == GT_QMARK)
7161 qmarkNode = targetMethod;
7165 noway_assert(qmarkNode->OperGet() == GT_QMARK);
7166 // The argument is actually a generic dictionary lookup. For delegate creation it looks
7171 // Arg 1 -> token (has compile time handle)
7175 // In this case I can find the token (which is a method handle) and that is the compile time
7177 noway_assert(qmarkNode->gtOp.gtOp2->OperGet() == GT_COLON);
7178 noway_assert(qmarkNode->gtOp.gtOp2->gtOp.gtOp1->OperGet() == GT_CALL);
7179 GenTreeCall* runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1->AsCall();
7181 // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
7182 GenTreePtr tokenNode = runtimeLookupCall->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
7183 noway_assert(tokenNode->OperGet() == GT_CNS_INT);
7184 targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
7187 #ifdef FEATURE_READYTORUN_COMPILER
7188 if (opts.IsReadyToRun())
7190 if (IsTargetAbi(CORINFO_CORERT_ABI))
7192 if (ldftnToken != nullptr)
7194 GenTreePtr thisPointer = call->gtCallObjp;
7195 GenTreePtr targetObjPointers = call->gtCallArgs->Current();
7196 GenTreeArgList* helperArgs = nullptr;
7197 CORINFO_LOOKUP pLookup;
7198 CORINFO_CONST_LOOKUP entryPoint;
7199 info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup);
7200 if (!pLookup.lookupKind.needsRuntimeLookup)
7202 helperArgs = gtNewArgList(thisPointer, targetObjPointers);
7203 entryPoint = pLookup.constLookup;
7207 assert(oper != GT_FTN_ADDR);
7208 CORINFO_CONST_LOOKUP genericLookup;
7209 info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind,
7210 CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup);
7211 GenTreePtr ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind);
7212 helperArgs = gtNewArgList(thisPointer, targetObjPointers, ctxTree);
7213 entryPoint = genericLookup;
7215 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs);
7216 call->setEntryPoint(entryPoint);
7219 // ReadyToRun has this optimization for a non-virtual function pointers only for now.
7220 else if (oper == GT_FTN_ADDR)
7222 GenTreePtr thisPointer = call->gtCallObjp;
7223 GenTreePtr targetObjPointers = call->gtCallArgs->Current();
7224 GenTreeArgList* helperArgs = gtNewArgList(thisPointer, targetObjPointers);
7226 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs);
7228 CORINFO_LOOKUP entryPoint;
7229 info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint);
7230 assert(!entryPoint.lookupKind.needsRuntimeLookup);
7231 call->setEntryPoint(entryPoint.constLookup);
7236 if (targetMethodHnd != nullptr)
7238 CORINFO_METHOD_HANDLE alternateCtor = nullptr;
7239 DelegateCtorArgs ctorData;
7240 ctorData.pMethod = info.compMethodHnd;
7241 ctorData.pArg3 = nullptr;
7242 ctorData.pArg4 = nullptr;
7243 ctorData.pArg5 = nullptr;
7245 alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
7246 if (alternateCtor != methHnd)
7248 // we erase any inline info that may have been set for generics has it is not needed here,
7249 // and in fact it will pass the wrong info to the inliner code
7250 *ExactContextHnd = nullptr;
7252 call->gtCallMethHnd = alternateCtor;
7254 noway_assert(call->gtCallArgs->Rest()->Rest() == nullptr);
7255 GenTreeArgList* addArgs = nullptr;
7258 GenTreePtr arg5 = gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR);
7259 addArgs = gtNewListNode(arg5, addArgs);
7263 GenTreePtr arg4 = gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR);
7264 addArgs = gtNewListNode(arg4, addArgs);
7268 GenTreePtr arg3 = gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR);
7269 addArgs = gtNewListNode(arg3, addArgs);
7271 call->gtCallArgs->Rest()->Rest() = addArgs;
7277 bool Compiler::fgCastNeeded(GenTreePtr tree, var_types toType)
7280 // If tree is a relop and we need an 4-byte integer
7281 // then we never need to insert a cast
7283 if ((tree->OperKind() & GTK_RELOP) && (genActualType(toType) == TYP_INT))
7291 // Is the tree as GT_CAST or a GT_CALL ?
7293 if (tree->OperGet() == GT_CAST)
7295 fromType = tree->CastToType();
7297 else if (tree->OperGet() == GT_CALL)
7299 fromType = (var_types)tree->gtCall.gtReturnType;
7303 fromType = tree->TypeGet();
7307 // If both types are the same then an additional cast is not necessary
7309 if (toType == fromType)
7314 // If the sign-ness of the two types are different then a cast is necessary
7316 if (varTypeIsUnsigned(toType) != varTypeIsUnsigned(fromType))
7321 // If the from type is the same size or smaller then an additional cast is not necessary
7323 if (genTypeSize(toType) >= genTypeSize(fromType))
7329 // Looks like we will need the cast
7334 // If assigning to a local var, add a cast if the target is
7335 // marked as NormalizedOnStore. Returns true if any change was made
7336 GenTreePtr Compiler::fgDoNormalizeOnStore(GenTreePtr tree)
7339 // Only normalize the stores in the global morph phase
7343 noway_assert(tree->OperGet() == GT_ASG);
7345 GenTreePtr op1 = tree->gtOp.gtOp1;
7346 GenTreePtr op2 = tree->gtOp.gtOp2;
7348 if (op1->gtOper == GT_LCL_VAR && genActualType(op1->TypeGet()) == TYP_INT)
7350 // Small-typed arguments and aliased locals are normalized on load.
7351 // Other small-typed locals are normalized on store.
7352 // If it is an assignment to one of the latter, insert the cast on RHS
7353 unsigned varNum = op1->gtLclVarCommon.gtLclNum;
7354 LclVarDsc* varDsc = &lvaTable[varNum];
7356 if (varDsc->lvNormalizeOnStore())
7358 noway_assert(op1->gtType <= TYP_INT);
7359 op1->gtType = TYP_INT;
7361 if (fgCastNeeded(op2, varDsc->TypeGet()))
7363 op2 = gtNewCastNode(TYP_INT, op2, varDsc->TypeGet());
7364 tree->gtOp.gtOp2 = op2;
7366 // Propagate GTF_COLON_COND
7367 op2->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7376 /*****************************************************************************
7378 * Mark whether the edge "srcBB -> dstBB" forms a loop that will always
7379 * execute a call or not.
7382 inline void Compiler::fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB)
7384 /* Bail if this is not a backward edge */
7386 if (srcBB->bbNum < dstBB->bbNum)
7391 /* Unless we already know that there is a loop without a call here ... */
7393 if (!(dstBB->bbFlags & BBF_LOOP_CALL0))
7395 /* Check whether there is a loop path that doesn't call */
7397 if (optReachWithoutCall(dstBB, srcBB))
7399 dstBB->bbFlags |= BBF_LOOP_CALL0;
7400 dstBB->bbFlags &= ~BBF_LOOP_CALL1;
7404 dstBB->bbFlags |= BBF_LOOP_CALL1;
7407 // if this loop will always call, then we can omit the GC Poll
7408 if ((GCPOLL_NONE != opts.compGCPollType) && (dstBB->bbFlags & BBF_LOOP_CALL1))
7410 srcBB->bbFlags &= ~BBF_NEEDS_GCPOLL;
7414 /*****************************************************************************
7416 * Mark which loops are guaranteed to execute a call.
7419 void Compiler::fgLoopCallMark()
7423 /* If we've already marked all the block, bail */
7425 if (fgLoopCallMarked)
7430 fgLoopCallMarked = true;
7432 /* Walk the blocks, looking for backward edges */
7434 for (block = fgFirstBB; block; block = block->bbNext)
7436 switch (block->bbJumpKind)
7439 case BBJ_CALLFINALLY:
7441 case BBJ_EHCATCHRET:
7442 fgLoopCallTest(block, block->bbJumpDest);
7448 jumpCnt = block->bbJumpSwt->bbsCount;
7449 BasicBlock** jumpPtr;
7450 jumpPtr = block->bbJumpSwt->bbsDstTab;
7454 fgLoopCallTest(block, *jumpPtr);
7455 } while (++jumpPtr, --jumpCnt);
7465 /*****************************************************************************
7467 * Note the fact that the given block is a loop header.
7470 inline void Compiler::fgMarkLoopHead(BasicBlock* block)
7475 printf("fgMarkLoopHead: Checking loop head block BB%02u: ", block->bbNum);
7479 /* Have we decided to generate fully interruptible code already? */
7481 if (genInterruptible)
7486 printf("method is already fully interruptible\n");
7492 /* Is the loop head block known to execute a method call? */
7494 if (block->bbFlags & BBF_GC_SAFE_POINT)
7499 printf("this block will execute a call\n");
7502 // single block loops that contain GC safe points don't need polls.
7503 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
7507 /* Are dominator sets available? */
7511 /* Make sure that we know which loops will always execute calls */
7513 if (!fgLoopCallMarked)
7518 /* Will every trip through our loop execute a call? */
7520 if (block->bbFlags & BBF_LOOP_CALL1)
7525 printf("this block dominates a block that will execute a call\n");
7533 * We have to make this method fully interruptible since we can not
7534 * ensure that this loop will execute a call every time it loops.
7536 * We'll also need to generate a full register map for this method.
7539 assert(!codeGen->isGCTypeFixed());
7541 if (!compCanEncodePtrArgCntMax())
7546 printf("a callsite with more than 1023 pushed args exists\n");
7555 printf("no guaranteed callsite exits, marking method as fully interruptible\n");
7559 // only enable fully interruptible code for if we're hijacking.
7560 if (GCPOLL_NONE == opts.compGCPollType)
7562 genInterruptible = true;
7566 GenTreePtr Compiler::fgGetCritSectOfStaticMethod()
7568 noway_assert(!compIsForInlining());
7570 noway_assert(info.compIsStatic); // This method should only be called for static methods.
7572 GenTreePtr tree = nullptr;
7574 CORINFO_LOOKUP_KIND kind = info.compCompHnd->getLocationOfThisType(info.compMethodHnd);
7576 if (!kind.needsRuntimeLookup)
7578 void *critSect = nullptr, **pCrit = nullptr;
7579 critSect = info.compCompHnd->getMethodSync(info.compMethodHnd, (void**)&pCrit);
7580 noway_assert((!critSect) != (!pCrit));
7582 tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL);
7586 // Collectible types requires that for shared generic code, if we use the generic context paramter
7587 // that we report it. (This is a conservative approach, we could detect some cases particularly when the
7588 // context parameter is this that we don't need the eager reporting logic.)
7589 lvaGenericsContextUseCount++;
7591 switch (kind.runtimeLookupKind)
7593 case CORINFO_LOOKUP_THISOBJ:
7595 noway_assert(!"Should never get this for static method.");
7599 case CORINFO_LOOKUP_CLASSPARAM:
7601 // In this case, the hidden param is the class handle.
7602 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7606 case CORINFO_LOOKUP_METHODPARAM:
7608 // In this case, the hidden param is the method handle.
7609 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7610 // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the class handle
7611 // from the method handle.
7612 tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, 0, gtNewArgList(tree));
7618 noway_assert(!"Unknown LOOKUP_KIND");
7623 noway_assert(tree); // tree should now contain the CORINFO_CLASS_HANDLE for the exact class.
7625 // Given the class handle, get the pointer to the Monitor.
7626 tree = gtNewHelperCallNode(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, TYP_I_IMPL, 0, gtNewArgList(tree));
7633 #if FEATURE_EH_FUNCLETS
7635 /*****************************************************************************
7637 * Add monitor enter/exit calls for synchronized methods, and a try/fault
7638 * to ensure the 'exit' is called if the 'enter' was successful. On x86, we
7639 * generate monitor enter/exit calls and tell the VM the code location of
7640 * these calls. When an exception occurs between those locations, the VM
7641 * automatically releases the lock. For non-x86 platforms, the JIT is
7642 * responsible for creating a try/finally to protect the monitor enter/exit,
7643 * and the VM doesn't need to know anything special about the method during
7644 * exception processing -- it's just a normal try/finally.
7646 * We generate the following code:
7650 * unsigned byte acquired = 0;
7652 * JIT_MonEnterWorker(<lock object>, &acquired);
7654 * *** all the preexisting user code goes here ***
7656 * JIT_MonExitWorker(<lock object>, &acquired);
7658 * JIT_MonExitWorker(<lock object>, &acquired);
7664 * If the lock is actually acquired, then the 'acquired' variable is set to 1
7665 * by the helper call. During normal exit, the finally is called, 'acquired'
7666 * is 1, and the lock is released. If an exception occurs before the lock is
7667 * acquired, but within the 'try' (extremely unlikely, but possible), 'acquired'
7668 * will be 0, and the monitor exit call will quickly return without attempting
7669 * to release the lock. Otherwise, 'acquired' will be 1, and the lock will be
7670 * released during exception processing.
7672 * For synchronized methods, we generate a single return block.
7673 * We can do this without creating additional "step" blocks because "ret" blocks
7674 * must occur at the top-level (of the original code), not nested within any EH
7675 * constructs. From the CLI spec, 12.4.2.8.2.3 "ret": "Shall not be enclosed in any
7676 * protected block, filter, or handler." Also, 3.57: "The ret instruction cannot be
7677 * used to transfer control out of a try, filter, catch, or finally block. From within
7678 * a try or catch, use the leave instruction with a destination of a ret instruction
7679 * that is outside all enclosing exception blocks."
7681 * In addition, we can add a "fault" at the end of a method and be guaranteed that no
7682 * control falls through. From the CLI spec, section 12.4 "Control flow": "Control is not
7683 * permitted to simply fall through the end of a method. All paths shall terminate with one
7684 * of these instructions: ret, throw, jmp, or (tail. followed by call, calli, or callvirt)."
7686 * We only need to worry about "ret" and "throw", as the CLI spec prevents any other
7687 * alternatives. Section 15.4.3.3 "Implementation information" states about exiting
7688 * synchronized methods: "Exiting a synchronized method using a tail. call shall be
7689 * implemented as though the tail. had not been specified." Section 3.37 "jmp" states:
7690 * "The jmp instruction cannot be used to transferred control out of a try, filter,
7691 * catch, fault or finally block; or out of a synchronized region." And, "throw" will
7692 * be handled naturally; no additional work is required.
7695 void Compiler::fgAddSyncMethodEnterExit()
7697 assert((info.compFlags & CORINFO_FLG_SYNCH) != 0);
7699 // We need to do this transformation before funclets are created.
7700 assert(!fgFuncletsCreated);
7702 // Assume we don't need to update the bbPreds lists.
7703 assert(!fgComputePredsDone);
7706 // If we don't support EH, we can't add the EH needed by synchronized methods.
7707 // Of course, we could simply ignore adding the EH constructs, since we don't
7708 // support exceptions being thrown in this mode, but we would still need to add
7709 // the monitor enter/exit, and that doesn't seem worth it for this minor case.
7710 // By the time EH is working, we can just enable the whole thing.
7711 NYI("No support for synchronized methods");
7712 #endif // !FEATURE_EH
7714 // Create a scratch first BB where we can put the new variable initialization.
7715 // Don't put the scratch BB in the protected region.
7717 fgEnsureFirstBBisScratch();
7719 // Create a block for the start of the try region, where the monitor enter call
7722 assert(fgFirstBB->bbFallsThrough());
7724 BasicBlock* tryBegBB = fgNewBBafter(BBJ_NONE, fgFirstBB, false);
7725 BasicBlock* tryNextBB = tryBegBB->bbNext;
7726 BasicBlock* tryLastBB = fgLastBB;
7728 // If we have profile data the new block will inherit the next block's weight
7729 if (tryNextBB->hasProfileWeight())
7731 tryBegBB->inheritWeight(tryNextBB);
7734 // Create a block for the fault.
7736 assert(!tryLastBB->bbFallsThrough());
7737 BasicBlock* faultBB = fgNewBBafter(BBJ_EHFINALLYRET, tryLastBB, false);
7739 assert(tryLastBB->bbNext == faultBB);
7740 assert(faultBB->bbNext == nullptr);
7741 assert(faultBB == fgLastBB);
7743 { // Scope the EH region creation
7745 // Add the new EH region at the end, since it is the least nested,
7746 // and thus should be last.
7749 unsigned XTnew = compHndBBtabCount;
7751 newEntry = fgAddEHTableEntry(XTnew);
7753 // Initialize the new entry
7755 newEntry->ebdHandlerType = EH_HANDLER_FAULT;
7757 newEntry->ebdTryBeg = tryBegBB;
7758 newEntry->ebdTryLast = tryLastBB;
7760 newEntry->ebdHndBeg = faultBB;
7761 newEntry->ebdHndLast = faultBB;
7763 newEntry->ebdTyp = 0; // unused for fault
7765 newEntry->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7766 newEntry->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7768 newEntry->ebdTryBegOffset = tryBegBB->bbCodeOffs;
7769 newEntry->ebdTryEndOffset = tryLastBB->bbCodeOffsEnd;
7770 newEntry->ebdFilterBegOffset = 0;
7771 newEntry->ebdHndBegOffset = 0; // handler doesn't correspond to any IL
7772 newEntry->ebdHndEndOffset = 0; // handler doesn't correspond to any IL
7774 // Set some flags on the new region. This is the same as when we set up
7775 // EH regions in fgFindBasicBlocks(). Note that the try has no enclosing
7776 // handler, and the fault has no enclosing try.
7778 tryBegBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_TRY_BEG | BBF_IMPORTED;
7780 faultBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_IMPORTED;
7781 faultBB->bbCatchTyp = BBCT_FAULT;
7783 tryBegBB->setTryIndex(XTnew);
7784 tryBegBB->clearHndIndex();
7786 faultBB->clearTryIndex();
7787 faultBB->setHndIndex(XTnew);
7789 // Walk the user code blocks and set all blocks that don't already have a try handler
7790 // to point to the new try handler.
7793 for (tmpBB = tryBegBB->bbNext; tmpBB != faultBB; tmpBB = tmpBB->bbNext)
7795 if (!tmpBB->hasTryIndex())
7797 tmpBB->setTryIndex(XTnew);
7801 // Walk the EH table. Make every EH entry that doesn't already have an enclosing
7802 // try index mark this new entry as their enclosing try index.
7807 for (XTnum = 0, HBtab = compHndBBtab; XTnum < XTnew; XTnum++, HBtab++)
7809 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
7811 HBtab->ebdEnclosingTryIndex =
7812 (unsigned short)XTnew; // This EH region wasn't previously nested, but now it is.
7819 JITDUMP("Synchronized method - created additional EH descriptor EH#%u for try/fault wrapping monitor "
7822 fgDispBasicBlocks();
7826 fgVerifyHandlerTab();
7830 // Create a 'monitor acquired' boolean (actually, an unsigned byte: 1 = acquired, 0 = not acquired).
7832 var_types typeMonAcquired = TYP_UBYTE;
7833 this->lvaMonAcquired = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7835 lvaTable[lvaMonAcquired].lvType = typeMonAcquired;
7837 { // Scope the variables of the variable initialization
7839 // Initialize the 'acquired' boolean.
7841 GenTreePtr zero = gtNewZeroConNode(genActualType(typeMonAcquired));
7842 GenTreePtr varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
7843 GenTreePtr initNode = gtNewAssignNode(varNode, zero);
7845 fgInsertStmtAtEnd(fgFirstBB, initNode);
7850 printf("\nSynchronized method - Add 'acquired' initialization in first block BB%02u [%08p]\n", fgFirstBB,
7852 gtDispTree(initNode);
7858 // Make a copy of the 'this' pointer to be used in the handler so it does not inhibit enregistration
7859 // of all uses of the variable.
7860 unsigned lvaCopyThis = 0;
7861 if (!info.compIsStatic)
7863 lvaCopyThis = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7864 lvaTable[lvaCopyThis].lvType = TYP_REF;
7866 GenTreePtr thisNode = gtNewLclvNode(info.compThisArg, TYP_REF);
7867 GenTreePtr copyNode = gtNewLclvNode(lvaCopyThis, TYP_REF);
7868 GenTreePtr initNode = gtNewAssignNode(copyNode, thisNode);
7870 fgInsertStmtAtEnd(tryBegBB, initNode);
7873 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, tryBegBB, true /*enter*/);
7876 fgCreateMonitorTree(lvaMonAcquired, lvaCopyThis, faultBB, false /*exit*/);
7878 // non-exceptional cases
7879 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
7881 if (block->bbJumpKind == BBJ_RETURN)
7883 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, block, false /*exit*/);
7888 // fgCreateMonitorTree: Create tree to execute a monitor enter or exit operation for synchronized methods
7889 // lvaMonAcquired: lvaNum of boolean variable that tracks if monitor has been acquired.
7890 // lvaThisVar: lvaNum of variable being used as 'this' pointer, may not be the original one. Is only used for
7891 // nonstatic methods
7892 // block: block to insert the tree in. It is inserted at the end or in the case of a return, immediately before the
7894 // enter: whether to create a monitor enter or exit
7896 GenTree* Compiler::fgCreateMonitorTree(unsigned lvaMonAcquired, unsigned lvaThisVar, BasicBlock* block, bool enter)
7898 // Insert the expression "enter/exitCrit(this, &acquired)" or "enter/exitCrit(handle, &acquired)"
7900 var_types typeMonAcquired = TYP_UBYTE;
7901 GenTreePtr varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
7902 GenTreePtr varAddrNode = gtNewOperNode(GT_ADDR, TYP_BYREF, varNode);
7905 if (info.compIsStatic)
7907 tree = fgGetCritSectOfStaticMethod();
7908 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER_STATIC : CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, 0,
7909 gtNewArgList(tree, varAddrNode));
7913 tree = gtNewLclvNode(lvaThisVar, TYP_REF);
7914 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT, TYP_VOID, 0,
7915 gtNewArgList(tree, varAddrNode));
7921 printf("\nSynchronized method - Add monitor %s call to block BB%02u [%08p]\n", enter ? "enter" : "exit", block,
7928 if (block->bbJumpKind == BBJ_RETURN && block->lastStmt()->gtStmtExpr->gtOper == GT_RETURN)
7930 GenTree* retNode = block->lastStmt()->gtStmtExpr;
7931 GenTree* retExpr = retNode->gtOp.gtOp1;
7933 if (retExpr != nullptr)
7935 // have to insert this immediately before the GT_RETURN so we transform:
7937 // ret(comma(comma(tmp=...,call mon_exit), tmp)
7940 // Before morph stage, it is possible to have a case of GT_RETURN(TYP_LONG, op1) where op1's type is
7941 // TYP_STRUCT (of 8-bytes) and op1 is call node. See the big comment block in impReturnInstruction()
7942 // for details for the case where info.compRetType is not the same as info.compRetNativeType. For
7943 // this reason pass compMethodInfo->args.retTypeClass which is guaranteed to be a valid class handle
7944 // if the return type is a value class. Note that fgInsertCommFormTemp() in turn uses this class handle
7945 // if the type of op1 is TYP_STRUCT to perform lvaSetStruct() on the new temp that is created, which
7946 // in turn passes it to VM to know the size of value type.
7947 GenTree* temp = fgInsertCommaFormTemp(&retNode->gtOp.gtOp1, info.compMethodInfo->args.retTypeClass);
7949 GenTree* lclVar = retNode->gtOp.gtOp1->gtOp.gtOp2;
7950 retNode->gtOp.gtOp1->gtOp.gtOp2 = gtNewOperNode(GT_COMMA, retExpr->TypeGet(), tree, lclVar);
7954 // Insert this immediately before the GT_RETURN
7955 fgInsertStmtNearEnd(block, tree);
7960 fgInsertStmtAtEnd(block, tree);
7966 // Convert a BBJ_RETURN block in a synchronized method to a BBJ_ALWAYS.
7967 // We've previously added a 'try' block around the original program code using fgAddSyncMethodEnterExit().
7968 // Thus, we put BBJ_RETURN blocks inside a 'try'. In IL this is illegal. Instead, we would
7969 // see a 'leave' inside a 'try' that would get transformed into BBJ_CALLFINALLY/BBJ_ALWAYS blocks
7970 // during importing, and the BBJ_ALWAYS would point at an outer block with the BBJ_RETURN.
7971 // Here, we mimic some of the logic of importing a LEAVE to get the same effect for synchronized methods.
7972 void Compiler::fgConvertSyncReturnToLeave(BasicBlock* block)
7974 assert(!fgFuncletsCreated);
7975 assert(info.compFlags & CORINFO_FLG_SYNCH);
7976 assert(genReturnBB != nullptr);
7977 assert(genReturnBB != block);
7978 assert(fgReturnCount <= 1); // We have a single return for synchronized methods
7979 assert(block->bbJumpKind == BBJ_RETURN);
7980 assert((block->bbFlags & BBF_HAS_JMP) == 0);
7981 assert(block->hasTryIndex());
7982 assert(!block->hasHndIndex());
7983 assert(compHndBBtabCount >= 1);
7985 unsigned tryIndex = block->getTryIndex();
7986 assert(tryIndex == compHndBBtabCount - 1); // The BBJ_RETURN must be at the top-level before we inserted the
7987 // try/finally, which must be the last EH region.
7989 EHblkDsc* ehDsc = ehGetDsc(tryIndex);
7990 assert(ehDsc->ebdEnclosingTryIndex ==
7991 EHblkDsc::NO_ENCLOSING_INDEX); // There are no enclosing regions of the BBJ_RETURN block
7992 assert(ehDsc->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX);
7994 // Convert the BBJ_RETURN to BBJ_ALWAYS, jumping to genReturnBB.
7995 block->bbJumpKind = BBJ_ALWAYS;
7996 block->bbJumpDest = genReturnBB;
7997 block->bbJumpDest->bbRefs++;
8002 printf("Synchronized method - convert block BB%02u to BBJ_ALWAYS [targets BB%02u]\n", block->bbNum,
8003 block->bbJumpDest->bbNum);
8008 #endif // FEATURE_EH_FUNCLETS
8010 //------------------------------------------------------------------------
8011 // fgAddReversePInvokeEnterExit: Add enter/exit calls for reverse PInvoke methods
8019 void Compiler::fgAddReversePInvokeEnterExit()
8021 assert(opts.IsReversePInvoke());
8023 lvaReversePInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Reverse Pinvoke FrameVar"));
8025 LclVarDsc* varDsc = &lvaTable[lvaReversePInvokeFrameVar];
8026 varDsc->lvType = TYP_BLK;
8027 varDsc->lvExactSize = eeGetEEInfo()->sizeOfReversePInvokeFrame;
8031 // Add enter pinvoke exit callout at the start of prolog
8033 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
8035 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, 0, gtNewArgList(tree));
8037 fgEnsureFirstBBisScratch();
8039 fgInsertStmtAtBeg(fgFirstBB, tree);
8044 printf("\nReverse PInvoke method - Add reverse pinvoke enter in first basic block [%08p]\n", dspPtr(fgFirstBB));
8050 // Add reverse pinvoke exit callout at the end of epilog
8052 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
8054 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, 0, gtNewArgList(tree));
8056 assert(genReturnBB != nullptr);
8058 fgInsertStmtAtEnd(genReturnBB, tree);
8063 printf("\nReverse PInvoke method - Add reverse pinvoke exit in return basic block [%08p]\n",
8064 dspPtr(genReturnBB));
8071 /*****************************************************************************
8073 * Return 'true' if there is more than one BBJ_RETURN block.
8076 bool Compiler::fgMoreThanOneReturnBlock()
8078 unsigned retCnt = 0;
8080 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
8082 if (block->bbJumpKind == BBJ_RETURN)
8095 /*****************************************************************************
8097 * Add any internal blocks/trees we may need
8100 void Compiler::fgAddInternal()
8102 noway_assert(!compIsForInlining());
8104 #ifndef LEGACY_BACKEND
8105 // The RyuJIT backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is
8106 // required. Create it here.
8107 if (info.compCallUnmanaged != 0)
8109 fgEnsureFirstBBisScratch();
8110 fgFirstBB->bbFlags |= BBF_DONT_REMOVE;
8112 #endif // !LEGACY_BACKEND
8115 <BUGNUM> VSW441487 </BUGNUM>
8117 The "this" pointer is implicitly used in the following cases:
8118 1. Locking of synchronized methods
8119 2. Dictionary access of shared generics code
8120 3. If a method has "catch(FooException<T>)", the EH code accesses "this" to determine T.
8121 4. Initializing the type from generic methods which require precise cctor semantics
8122 5. Verifier does special handling of "this" in the .ctor
8124 However, we might overwrite it with a "starg 0".
8125 In this case, we will redirect all "ldarg(a)/starg(a) 0" to a temp lvaTable[lvaArg0Var]
8128 if (!info.compIsStatic)
8130 if (lvaArg0Var != info.compThisArg)
8132 // When we're using the general encoder, we mark compThisArg address-taken to ensure that it is not
8133 // enregistered (since the decoder always reports a stack location for "this" for generics
8135 bool lva0CopiedForGenericsCtxt;
8136 #ifndef JIT32_GCENCODER
8137 lva0CopiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
8138 #else // JIT32_GCENCODER
8139 lva0CopiedForGenericsCtxt = false;
8140 #endif // JIT32_GCENCODER
8141 noway_assert(lva0CopiedForGenericsCtxt || !lvaTable[info.compThisArg].lvAddrExposed);
8142 noway_assert(!lvaTable[info.compThisArg].lvHasILStoreOp);
8143 noway_assert(lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvHasILStoreOp ||
8144 lva0CopiedForGenericsCtxt);
8146 var_types thisType = lvaTable[info.compThisArg].TypeGet();
8148 // Now assign the original input "this" to the temp
8152 tree = gtNewLclvNode(lvaArg0Var, thisType);
8154 tree = gtNewAssignNode(tree, // dst
8155 gtNewLclvNode(info.compThisArg, thisType) // src
8158 /* Create a new basic block and stick the assignment in it */
8160 fgEnsureFirstBBisScratch();
8162 fgInsertStmtAtEnd(fgFirstBB, tree);
8167 printf("\nCopy \"this\" to lvaArg0Var in first basic block [%08p]\n", dspPtr(fgFirstBB));
8175 // Grab a temp for the security object.
8176 // (Note: opts.compDbgEnC currently also causes the security object to be generated. See Compiler::compCompile)
8177 if (opts.compNeedSecurityCheck)
8179 noway_assert(lvaSecurityObject == BAD_VAR_NUM);
8180 lvaSecurityObject = lvaGrabTempWithImplicitUse(false DEBUGARG("security check"));
8181 lvaTable[lvaSecurityObject].lvType = TYP_REF;
8184 /* Assume we will generate a single shared return sequence */
8186 ULONG returnWeight = 0;
8191 // We will generate just one epilog (return block)
8192 // when we are asked to generate enter/leave callbacks
8193 // or for methods with PInvoke
8194 // or for methods calling into unmanaged code
8195 // or for synchronized methods.
8197 if (compIsProfilerHookNeeded() || (info.compCallUnmanaged != 0) || opts.IsReversePInvoke() ||
8198 ((info.compFlags & CORINFO_FLG_SYNCH) != 0))
8200 // We will generate only one return block
8201 // We will transform the BBJ_RETURN blocks
8202 // into jumps to the one return block
8205 allProfWeight = false;
8210 // We are allowed to have multiple individual exits
8211 // However we can still decide to have a single return
8214 allProfWeight = true;
8216 // Count the BBJ_RETURN blocks and set the returnWeight to the
8217 // sum of all these blocks.
8220 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
8222 if (block->bbJumpKind == BBJ_RETURN)
8225 // returnCount is the count of BBJ_RETURN blocks in this method
8229 // If all BBJ_RETURN blocks have a valid profiled weights
8230 // then allProfWeight will be true, else it is false
8232 if (!block->hasProfileWeight())
8234 allProfWeight = false;
8237 // returnWeight is the sum of the weights of all BBJ_RETURN blocks
8238 returnWeight += block->bbWeight;
8243 // If we only have one (or zero) return blocks then
8244 // we do not need a special one return block
8246 if (fgReturnCount > 1)
8249 // should we generate a single return block?
8251 if (fgReturnCount > 4)
8253 // Our epilog encoding only supports up to 4 epilogs
8254 // TODO-CQ: support >4 return points for ARM/AMD64, which presumably support any number of epilogs?
8258 else if (compCodeOpt() == SMALL_CODE)
8260 // For the Small_Code case we always generate a
8261 // single return block when we have multiple
8269 #if FEATURE_EH_FUNCLETS
8270 // Add the synchronized method enter/exit calls and try/finally protection. Note
8271 // that this must happen before the one BBJ_RETURN block is created below, so the
8272 // BBJ_RETURN block gets placed at the top-level, not within an EH region. (Otherwise,
8273 // we'd have to be really careful when creating the synchronized method try/finally
8274 // not to include the BBJ_RETURN block.)
8275 if ((info.compFlags & CORINFO_FLG_SYNCH) != 0)
8277 fgAddSyncMethodEnterExit();
8279 #endif // FEATURE_EH_FUNCLETS
8283 genReturnBB = fgNewBBinRegion(BBJ_RETURN);
8284 genReturnBB->bbRefs = 1; // bbRefs gets update later, for now it should be 1
8290 // if we have profile data for all BBJ_RETURN blocks
8291 // then we can set BBF_PROF_WEIGHT for genReturnBB
8293 genReturnBB->bbFlags |= BBF_PROF_WEIGHT;
8298 // We can't rely upon the calculated returnWeight unless
8299 // all of the BBJ_RETURN blocks had valid profile weights
8300 // So we will use the weight of the first block instead
8302 returnWeight = fgFirstBB->bbWeight;
8306 // Set the weight of the oneReturn block
8308 genReturnBB->bbWeight = min(returnWeight, BB_MAX_WEIGHT);
8310 if (returnWeight == 0)
8313 // If necessary set the Run Rarely flag
8315 genReturnBB->bbFlags |= BBF_RUN_RARELY;
8319 // Make sure that the RunRarely flag is clear
8320 // because fgNewBBinRegion will set it to true
8322 genReturnBB->bbFlags &= ~BBF_RUN_RARELY;
8325 genReturnBB->bbFlags |= (BBF_INTERNAL | BBF_DONT_REMOVE);
8327 noway_assert(genReturnBB->bbNext == nullptr);
8332 printf("\n genReturnBB [BB%02u] created\n", genReturnBB->bbNum);
8339 // We don't have a oneReturn block for this method
8341 genReturnBB = nullptr;
8344 // If there is a return value, then create a temp for it. Real returns will store the value in there and
8345 // it'll be reloaded by the single return.
8346 if (genReturnBB && compMethodHasRetVal())
8348 genReturnLocal = lvaGrabTemp(true DEBUGARG("Single return block return value"));
8350 if (compMethodReturnsNativeScalarType())
8352 lvaTable[genReturnLocal].lvType = genActualType(info.compRetNativeType);
8354 else if (compMethodReturnsRetBufAddr())
8356 lvaTable[genReturnLocal].lvType = TYP_BYREF;
8358 else if (compMethodReturnsMultiRegRetType())
8360 lvaTable[genReturnLocal].lvType = TYP_STRUCT;
8361 lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true);
8362 lvaTable[genReturnLocal].lvIsMultiRegRet = true;
8366 assert(!"unreached");
8369 if (varTypeIsFloating(lvaTable[genReturnLocal].lvType))
8371 this->compFloatingPointUsed = true;
8374 if (!varTypeIsFloating(info.compRetType))
8376 lvaTable[genReturnLocal].setPrefReg(REG_INTRET, this);
8381 lvaTable[genReturnLocal].setPrefReg(REG_FLOATRET, this);
8386 // This temporary should not be converted to a double in stress mode,
8387 // because we introduce assigns to it after the stress conversion
8388 lvaTable[genReturnLocal].lvKeepType = 1;
8393 genReturnLocal = BAD_VAR_NUM;
8396 if (info.compCallUnmanaged != 0)
8398 // The P/Invoke helpers only require a frame variable, so only allocate the
8399 // TCB variable if we're not using them.
8400 if (!opts.ShouldUsePInvokeHelpers())
8402 info.compLvFrameListRoot = lvaGrabTemp(false DEBUGARG("Pinvoke FrameListRoot"));
8405 lvaInlinedPInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Pinvoke FrameVar"));
8407 LclVarDsc* varDsc = &lvaTable[lvaInlinedPInvokeFrameVar];
8408 varDsc->addPrefReg(RBM_PINVOKE_TCB, this);
8409 varDsc->lvType = TYP_BLK;
8410 // Make room for the inlined frame.
8411 varDsc->lvExactSize = eeGetEEInfo()->inlinedCallFrameInfo.size;
8412 #if FEATURE_FIXED_OUT_ARGS
8413 // Grab and reserve space for TCB, Frame regs used in PInvoke epilog to pop the inlined frame.
8414 // See genPInvokeMethodEpilog() for use of the grabbed var. This is only necessary if we are
8415 // not using the P/Invoke helpers.
8416 if (!opts.ShouldUsePInvokeHelpers() && compJmpOpUsed)
8418 lvaPInvokeFrameRegSaveVar = lvaGrabTempWithImplicitUse(false DEBUGARG("PInvokeFrameRegSave Var"));
8419 varDsc = &lvaTable[lvaPInvokeFrameRegSaveVar];
8420 varDsc->lvType = TYP_BLK;
8421 varDsc->lvExactSize = 2 * REGSIZE_BYTES;
8426 // Do we need to insert a "JustMyCode" callback?
8428 CORINFO_JUST_MY_CODE_HANDLE* pDbgHandle = nullptr;
8429 CORINFO_JUST_MY_CODE_HANDLE dbgHandle = nullptr;
8430 if (opts.compDbgCode && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB))
8432 dbgHandle = info.compCompHnd->getJustMyCodeHandle(info.compMethodHnd, &pDbgHandle);
8435 #ifdef _TARGET_ARM64_
8436 // TODO-ARM64-NYI: don't do just-my-code
8437 dbgHandle = nullptr;
8438 pDbgHandle = nullptr;
8439 #endif // _TARGET_ARM64_
8441 noway_assert(!dbgHandle || !pDbgHandle);
8443 if (dbgHandle || pDbgHandle)
8445 GenTreePtr guardCheckVal =
8446 gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode(dbgHandle, pDbgHandle, GTF_ICON_TOKEN_HDL));
8447 GenTreePtr guardCheckCond = gtNewOperNode(GT_EQ, TYP_INT, guardCheckVal, gtNewZeroConNode(TYP_INT));
8448 guardCheckCond->gtFlags |= GTF_RELOP_QMARK;
8450 // Create the callback which will yield the final answer
8452 GenTreePtr callback = gtNewHelperCallNode(CORINFO_HELP_DBG_IS_JUST_MY_CODE, TYP_VOID);
8453 callback = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), callback);
8455 // Stick the conditional call at the start of the method
8457 fgEnsureFirstBBisScratch();
8458 fgInsertStmtAtEnd(fgFirstBB, gtNewQmarkNode(TYP_VOID, guardCheckCond, callback));
8461 /* Do we need to call out for security ? */
8463 if (tiSecurityCalloutNeeded)
8465 // We must have grabbed this local.
8466 noway_assert(opts.compNeedSecurityCheck);
8467 noway_assert(lvaSecurityObject != BAD_VAR_NUM);
8471 /* Insert the expression "call JIT_Security_Prolog(MethodHnd, &SecurityObject)" */
8473 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
8475 tree = gtNewHelperCallNode(info.compCompHnd->getSecurityPrologHelper(info.compMethodHnd), TYP_VOID, 0,
8476 gtNewArgList(tree, gtNewOperNode(GT_ADDR, TYP_BYREF,
8477 gtNewLclvNode(lvaSecurityObject, TYP_REF))));
8479 /* Create a new basic block and stick the call in it */
8481 fgEnsureFirstBBisScratch();
8483 fgInsertStmtAtEnd(fgFirstBB, tree);
8488 printf("\ntiSecurityCalloutNeeded - Add call JIT_Security_Prolog(%08p) statement ",
8489 dspPtr(info.compMethodHnd));
8491 printf(" in first basic block [%08p]\n", dspPtr(fgFirstBB));
8498 #if !FEATURE_EH_FUNCLETS
8500 /* Is this a 'synchronized' method? */
8502 if (info.compFlags & CORINFO_FLG_SYNCH)
8504 GenTreePtr tree = NULL;
8506 /* Insert the expression "enterCrit(this)" or "enterCrit(handle)" */
8508 if (info.compIsStatic)
8510 tree = fgGetCritSectOfStaticMethod();
8512 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER_STATIC, TYP_VOID, 0, gtNewArgList(tree));
8516 noway_assert(lvaTable[info.compThisArg].lvType == TYP_REF);
8518 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
8520 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER, TYP_VOID, 0, gtNewArgList(tree));
8523 /* Create a new basic block and stick the call in it */
8525 fgEnsureFirstBBisScratch();
8527 fgInsertStmtAtEnd(fgFirstBB, tree);
8532 printf("\nSynchronized method - Add enterCrit statement in first basic block [%08p]\n", dspPtr(fgFirstBB));
8538 /* We must be generating a single exit point for this to work */
8540 noway_assert(oneReturn);
8541 noway_assert(genReturnBB);
8543 /* Create the expression "exitCrit(this)" or "exitCrit(handle)" */
8545 if (info.compIsStatic)
8547 tree = fgGetCritSectOfStaticMethod();
8549 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, 0, gtNewArgList(tree));
8553 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
8555 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT, TYP_VOID, 0, gtNewArgList(tree));
8558 fgInsertStmtAtEnd(genReturnBB, tree);
8563 printf("\nSynchronized method - Add exit expression ");
8569 // Reset cookies used to track start and end of the protected region in synchronized methods
8570 syncStartEmitCookie = NULL;
8571 syncEndEmitCookie = NULL;
8574 #endif // !FEATURE_EH_FUNCLETS
8576 /* Do we need to do runtime call out to check the security? */
8578 if (tiRuntimeCalloutNeeded)
8582 /* Insert the expression "call verificationRuntimeCheck(MethodHnd)" */
8584 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
8586 tree = gtNewHelperCallNode(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, TYP_VOID, 0, gtNewArgList(tree));
8588 /* Create a new basic block and stick the call in it */
8590 fgEnsureFirstBBisScratch();
8592 fgInsertStmtAtEnd(fgFirstBB, tree);
8597 printf("\ntiRuntimeCalloutNeeded - Call verificationRuntimeCheck(%08p) statement in first basic block "
8599 dspPtr(info.compMethodHnd), dspPtr(fgFirstBB));
8606 if (opts.IsReversePInvoke())
8608 fgAddReversePInvokeEnterExit();
8612 // Add 'return' expression to the return block if we made it as "oneReturn" before.
8619 // Make the 'return' expression.
8622 // make sure to reload the return value as part of the return (it is saved by the "real return").
8623 if (genReturnLocal != BAD_VAR_NUM)
8625 noway_assert(compMethodHasRetVal());
8627 GenTreePtr retTemp = gtNewLclvNode(genReturnLocal, lvaTable[genReturnLocal].TypeGet());
8629 // make sure copy prop ignores this node (make sure it always does a reload from the temp).
8630 retTemp->gtFlags |= GTF_DONT_CSE;
8631 tree = gtNewOperNode(GT_RETURN, retTemp->gtType, retTemp);
8635 noway_assert(info.compRetType == TYP_VOID || varTypeIsStruct(info.compRetType));
8637 tree = new (this, GT_RETURN) GenTreeOp(GT_RETURN, TYP_VOID);
8640 /* Add 'return' expression to the return block */
8642 noway_assert(genReturnBB);
8644 fgInsertStmtAtEnd(genReturnBB, tree);
8649 printf("\noneReturn statement tree ");
8651 printf(" added to genReturnBB [%08p]\n", dspPtr(genReturnBB));
8661 printf("\n*************** After fgAddInternal()\n");
8662 fgDispBasicBlocks();
8668 /*****************************************************************************
8670 * Create a new statement from tree and wire the links up.
8672 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs)
8674 GenTreeStmt* stmt = gtNewStmt(tree, offs);
8676 if (fgStmtListThreaded)
8678 gtSetStmtInfo(stmt);
8683 if (block != nullptr)
8685 fgDebugCheckNodeLinks(block, stmt);
8692 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree)
8694 return fgNewStmtFromTree(tree, nullptr, BAD_IL_OFFSET);
8697 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block)
8699 return fgNewStmtFromTree(tree, block, BAD_IL_OFFSET);
8702 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTreePtr tree, IL_OFFSETX offs)
8704 return fgNewStmtFromTree(tree, nullptr, offs);
8707 //------------------------------------------------------------------------
8708 // fgFindBlockILOffset: Given a block, find the IL offset corresponding to the first statement
8709 // in the block with a legal IL offset. Skip any leading statements that have BAD_IL_OFFSET.
8710 // If no statement has an initialized statement offset (including the case where there are
8711 // no statements in the block), then return BAD_IL_OFFSET. This function is used when
8712 // blocks are split or modified, and we want to maintain the IL offset as much as possible
8713 // to preserve good debugging behavior.
8716 // block - The block to check.
8719 // The first good IL offset of a statement in the block, or BAD_IL_OFFSET if such an IL offset
8722 IL_OFFSET Compiler::fgFindBlockILOffset(BasicBlock* block)
8724 // This function searches for IL offsets in statement nodes, so it can't be used in LIR. We
8725 // could have a similar function for LIR that searches for GT_IL_OFFSET nodes.
8726 assert(!block->IsLIR());
8728 for (GenTree* stmt = block->bbTreeList; stmt != nullptr; stmt = stmt->gtNext)
8730 assert(stmt->IsStatement());
8731 if (stmt->gtStmt.gtStmtILoffsx != BAD_IL_OFFSET)
8733 return jitGetILoffs(stmt->gtStmt.gtStmtILoffsx);
8737 return BAD_IL_OFFSET;
8740 //------------------------------------------------------------------------------
8741 // fgSplitBlockAtEnd - split the given block into two blocks.
8742 // All code in the block stays in the original block.
8743 // Control falls through from original to new block, and
8744 // the new block is returned.
8745 //------------------------------------------------------------------------------
8746 BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr)
8748 // We'd like to use fgNewBBafter(), but we need to update the preds list before linking in the new block.
8749 // (We need the successors of 'curr' to be correct when we do this.)
8750 BasicBlock* newBlock = bbNewBasicBlock(curr->bbJumpKind);
8752 // Start the new block with no refs. When we set the preds below, this will get updated correctly.
8753 newBlock->bbRefs = 0;
8755 // For each successor of the original block, set the new block as their predecessor.
8756 // Note we are using the "rational" version of the successor iterator that does not hide the finallyret arcs.
8757 // Without these arcs, a block 'b' may not be a member of succs(preds(b))
8758 if (curr->bbJumpKind != BBJ_SWITCH)
8760 unsigned numSuccs = curr->NumSucc(this);
8761 for (unsigned i = 0; i < numSuccs; i++)
8763 BasicBlock* succ = curr->GetSucc(i, this);
8764 if (succ != newBlock)
8766 JITDUMP("BB%02u previous predecessor was BB%02u, now is BB%02u\n", succ->bbNum, curr->bbNum,
8768 fgReplacePred(succ, curr, newBlock);
8772 newBlock->bbJumpDest = curr->bbJumpDest;
8773 curr->bbJumpDest = nullptr;
8777 // In the case of a switch statement there's more complicated logic in order to wire up the predecessor lists
8778 // but fortunately there's an existing method that implements this functionality.
8779 newBlock->bbJumpSwt = curr->bbJumpSwt;
8781 fgChangeSwitchBlock(curr, newBlock);
8783 curr->bbJumpSwt = nullptr;
8786 newBlock->inheritWeight(curr);
8788 // Set the new block's flags. Note that the new block isn't BBF_INTERNAL unless the old block is.
8789 newBlock->bbFlags = curr->bbFlags;
8791 // Remove flags that the new block can't have.
8792 newBlock->bbFlags &= ~(BBF_TRY_BEG | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1 | BBF_HAS_LABEL |
8793 BBF_JMP_TARGET | BBF_FUNCLET_BEG | BBF_LOOP_PREHEADER | BBF_KEEP_BBJ_ALWAYS);
8795 // Remove the GC safe bit on the new block. It seems clear that if we split 'curr' at the end,
8796 // such that all the code is left in 'curr', and 'newBlock' just gets the control flow, then
8797 // both 'curr' and 'newBlock' could accurately retain an existing GC safe bit. However, callers
8798 // use this function to split blocks in the middle, or at the beginning, and they don't seem to
8799 // be careful about updating this flag appropriately. So, removing the GC safe bit is simply
8800 // conservative: some functions might end up being fully interruptible that could be partially
8801 // interruptible if we exercised more care here.
8802 newBlock->bbFlags &= ~BBF_GC_SAFE_POINT;
8804 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
8805 newBlock->bbFlags &= ~(BBF_FINALLY_TARGET);
8806 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
8808 // The new block has no code, so we leave bbCodeOffs/bbCodeOffsEnd set to BAD_IL_OFFSET. If a caller
8809 // puts code in the block, then it needs to update these.
8811 // Insert the new block in the block list after the 'curr' block.
8812 fgInsertBBafter(curr, newBlock);
8813 fgExtendEHRegionAfter(curr); // The new block is in the same EH region as the old block.
8815 // Remove flags from the old block that are no longer possible.
8816 curr->bbFlags &= ~(BBF_HAS_JMP | BBF_RETLESS_CALL);
8818 // Default to fallthru, and add the arc for that.
8819 curr->bbJumpKind = BBJ_NONE;
8820 fgAddRefPred(newBlock, curr);
8825 //------------------------------------------------------------------------------
8826 // fgSplitBlockAfterStatement - Split the given block, with all code after
8827 // the given statement going into the second block.
8828 //------------------------------------------------------------------------------
8829 BasicBlock* Compiler::fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt)
8831 assert(!curr->IsLIR()); // No statements in LIR, so you can't use this function.
8833 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8837 newBlock->bbTreeList = stmt->gtNext;
8838 if (newBlock->bbTreeList)
8840 newBlock->bbTreeList->gtPrev = curr->bbTreeList->gtPrev;
8842 curr->bbTreeList->gtPrev = stmt;
8843 stmt->gtNext = nullptr;
8845 // Update the IL offsets of the blocks to match the split.
8847 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
8848 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
8850 // curr->bbCodeOffs remains the same
8851 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8853 IL_OFFSET splitPointILOffset = fgFindBlockILOffset(newBlock);
8855 curr->bbCodeOffsEnd = splitPointILOffset;
8856 newBlock->bbCodeOffs = splitPointILOffset;
8860 assert(curr->bbTreeList == nullptr); // if no tree was given then it better be an empty block
8866 //------------------------------------------------------------------------------
8867 // fgSplitBlockAfterNode - Split the given block, with all code after
8868 // the given node going into the second block.
8869 // This function is only used in LIR.
8870 //------------------------------------------------------------------------------
8871 BasicBlock* Compiler::fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node)
8873 assert(curr->IsLIR());
8875 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8877 if (node != nullptr)
8879 LIR::Range& currBBRange = LIR::AsRange(curr);
8881 if (node != currBBRange.LastNode())
8883 LIR::Range nodesToMove = currBBRange.Remove(node->gtNext, currBBRange.LastNode());
8884 LIR::AsRange(newBlock).InsertAtBeginning(std::move(nodesToMove));
8887 // Update the IL offsets of the blocks to match the split.
8889 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
8890 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
8892 // curr->bbCodeOffs remains the same
8893 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8895 // Search backwards from the end of the current block looking for the IL offset to use
8896 // for the end IL offset for the original block.
8897 IL_OFFSET splitPointILOffset = BAD_IL_OFFSET;
8898 LIR::Range::ReverseIterator riter;
8899 LIR::Range::ReverseIterator riterEnd;
8900 for (riter = currBBRange.rbegin(), riterEnd = currBBRange.rend(); riter != riterEnd; ++riter)
8902 if ((*riter)->gtOper == GT_IL_OFFSET)
8904 GenTreeStmt* stmt = (*riter)->AsStmt();
8905 if (stmt->gtStmtILoffsx != BAD_IL_OFFSET)
8907 splitPointILOffset = jitGetILoffs(stmt->gtStmtILoffsx);
8913 curr->bbCodeOffsEnd = splitPointILOffset;
8915 // Also use this as the beginning offset of the next block. Presumably we could/should
8916 // look to see if the first node is a GT_IL_OFFSET node, and use that instead.
8917 newBlock->bbCodeOffs = splitPointILOffset;
8921 assert(curr->bbTreeList == nullptr); // if no node was given then it better be an empty block
8927 //------------------------------------------------------------------------------
8928 // fgSplitBlockAtBeginning - Split the given block into two blocks.
8929 // Control falls through from original to new block,
8930 // and the new block is returned.
8931 // All code in the original block goes into the new block
8932 //------------------------------------------------------------------------------
8933 BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr)
8935 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
8937 newBlock->bbTreeList = curr->bbTreeList;
8938 curr->bbTreeList = nullptr;
8940 // The new block now has all the code, and the old block has none. Update the
8941 // IL offsets for the block to reflect this.
8943 newBlock->bbCodeOffs = curr->bbCodeOffs;
8944 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
8946 curr->bbCodeOffs = BAD_IL_OFFSET;
8947 curr->bbCodeOffsEnd = BAD_IL_OFFSET;
8952 //------------------------------------------------------------------------
8953 // fgSplitEdge: Splits the edge between a block 'curr' and its successor 'succ' by creating a new block
8954 // that replaces 'succ' as a successor of 'curr', and which branches unconditionally
8955 // to (or falls through to) 'succ'. Note that for a BBJ_COND block 'curr',
8956 // 'succ' might be the fall-through path or the branch path from 'curr'.
8959 // curr - A block which branches conditionally to 'succ'
8960 // succ - The target block
8963 // Returns a new block, that is a successor of 'curr' and which branches unconditionally to 'succ'
8966 // 'curr' must have a bbJumpKind of BBJ_COND or BBJ_SWITCH
8969 // The returned block is empty.
8971 BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ)
8973 assert(curr->bbJumpKind == BBJ_COND || curr->bbJumpKind == BBJ_SWITCH);
8974 assert(fgGetPredForBlock(succ, curr) != nullptr);
8976 BasicBlock* newBlock;
8977 if (succ == curr->bbNext)
8979 // The successor is the fall-through path of a BBJ_COND, or
8980 // an immediately following block of a BBJ_SWITCH (which has
8981 // no fall-through path). For this case, simply insert a new
8982 // fall-through block after 'curr'.
8983 newBlock = fgNewBBafter(BBJ_NONE, curr, true /*extendRegion*/);
8987 newBlock = fgNewBBinRegion(BBJ_ALWAYS, curr, curr->isRunRarely());
8988 // The new block always jumps to 'succ'
8989 newBlock->bbJumpDest = succ;
8991 newBlock->bbFlags |= (curr->bbFlags & succ->bbFlags & (BBF_BACKWARD_JUMP));
8993 JITDUMP("Splitting edge from BB%02u to BB%02u; adding BB%02u\n", curr->bbNum, succ->bbNum, newBlock->bbNum);
8995 if (curr->bbJumpKind == BBJ_COND)
8997 fgReplacePred(succ, curr, newBlock);
8998 if (curr->bbJumpDest == succ)
9000 // Now 'curr' jumps to newBlock
9001 curr->bbJumpDest = newBlock;
9002 newBlock->bbFlags |= BBF_JMP_TARGET;
9004 fgAddRefPred(newBlock, curr);
9008 assert(curr->bbJumpKind == BBJ_SWITCH);
9010 // newBlock replaces 'succ' in the switch.
9011 fgReplaceSwitchJumpTarget(curr, newBlock, succ);
9013 // And 'succ' has 'newBlock' as a new predecessor.
9014 fgAddRefPred(succ, newBlock);
9017 // This isn't accurate, but it is complex to compute a reasonable number so just assume that we take the
9018 // branch 50% of the time.
9019 newBlock->inheritWeightPercentage(curr, 50);
9021 // The bbLiveIn and bbLiveOut are both equal to the bbLiveIn of 'succ'
9022 if (fgLocalVarLivenessDone)
9024 VarSetOps::Assign(this, newBlock->bbLiveIn, succ->bbLiveIn);
9025 VarSetOps::Assign(this, newBlock->bbLiveOut, succ->bbLiveIn);
9031 /*****************************************************************************/
9032 /*****************************************************************************/
9034 void Compiler::fgFindOperOrder()
9039 printf("*************** In fgFindOperOrder()\n");
9046 /* Walk the basic blocks and for each statement determine
9047 * the evaluation order, cost, FP levels, etc... */
9049 for (block = fgFirstBB; block; block = block->bbNext)
9052 for (stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
9054 /* Recursively process the statement */
9057 gtSetStmtInfo(stmt);
9062 //------------------------------------------------------------------------
9063 // fgSimpleLowering: do full walk of all IR, lowering selected operations
9064 // and computing lvaOutgoingArgumentAreaSize.
9067 // Lowers GT_ARR_LENGTH, GT_ARR_BOUNDS_CHECK, and GT_SIMD_CHK.
9069 // For target ABIs with fixed out args area, computes upper bound on
9070 // the size of this area from the calls in the IR.
9072 // Outgoing arg area size is computed here because we want to run it
9073 // after optimization (in case calls are removed) and need to look at
9074 // all possible calls in the method.
9076 void Compiler::fgSimpleLowering()
9078 #if FEATURE_FIXED_OUT_ARGS
9079 unsigned outgoingArgSpaceSize = 0;
9080 #endif // FEATURE_FIXED_OUT_ARGS
9082 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
9084 // Walk the statement trees in this basic block.
9085 compCurBB = block; // Used in fgRngChkTarget.
9087 #ifdef LEGACY_BACKEND
9088 for (GenTreeStmt* stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNextStmt)
9090 for (GenTreePtr tree = stmt->gtStmtList; tree; tree = tree->gtNext)
9093 LIR::Range& range = LIR::AsRange(block);
9094 for (GenTree* tree : range)
9099 switch (tree->OperGet())
9103 GenTreeArrLen* arrLen = tree->AsArrLen();
9104 GenTreePtr arr = arrLen->gtArrLen.ArrRef();
9108 /* Create the expression "*(array_addr + ArrLenOffs)" */
9110 noway_assert(arr->gtNext == tree);
9112 noway_assert(arrLen->ArrLenOffset() == offsetof(CORINFO_Array, length) ||
9113 arrLen->ArrLenOffset() == offsetof(CORINFO_String, stringLen));
9115 if ((arr->gtOper == GT_CNS_INT) && (arr->gtIntCon.gtIconVal == 0))
9117 // If the array is NULL, then we should get a NULL reference
9118 // exception when computing its length. We need to maintain
9119 // an invariant where there is no sum of two constants node, so
9120 // let's simply return an indirection of NULL.
9126 con = gtNewIconNode(arrLen->ArrLenOffset(), TYP_I_IMPL);
9127 con->gtRsvdRegs = RBM_NONE;
9129 add = gtNewOperNode(GT_ADD, TYP_REF, arr, con);
9130 add->gtRsvdRegs = arr->gtRsvdRegs;
9132 #ifdef LEGACY_BACKEND
9133 con->gtCopyFPlvl(arr);
9135 add->gtCopyFPlvl(arr);
9136 add->CopyCosts(arr);
9147 range.InsertAfter(arr, con, add);
9151 // Change to a GT_IND.
9152 tree->ChangeOperUnchecked(GT_IND);
9154 tree->gtOp.gtOp1 = add;
9158 case GT_ARR_BOUNDS_CHECK:
9161 #endif // FEATURE_SIMD
9163 // Add in a call to an error routine.
9164 fgSetRngChkTarget(tree, false);
9168 #if FEATURE_FIXED_OUT_ARGS
9171 GenTreeCall* call = tree->AsCall();
9172 // Fast tail calls use the caller-supplied scratch
9173 // space so have no impact on this method's outgoing arg size.
9174 if (!call->IsFastTailCall())
9176 // Update outgoing arg size to handle this call
9177 const unsigned thisCallOutAreaSize = call->fgArgInfo->GetOutArgSize();
9178 assert(thisCallOutAreaSize >= MIN_ARG_AREA_FOR_CALL);
9180 if (thisCallOutAreaSize > outgoingArgSpaceSize)
9182 outgoingArgSpaceSize = thisCallOutAreaSize;
9183 JITDUMP("Bumping outgoingArgSpaceSize to %u for call [%06d]\n", outgoingArgSpaceSize,
9188 JITDUMP("outgoingArgSpaceSize %u sufficient for call [%06d], which needs %u\n",
9189 outgoingArgSpaceSize, dspTreeID(tree), thisCallOutAreaSize);
9194 JITDUMP("outgoingArgSpaceSize not impacted by fast tail call [%06d]\n", dspTreeID(tree));
9198 #endif // FEATURE_FIXED_OUT_ARGS
9202 // No other operators need processing.
9210 #if FEATURE_FIXED_OUT_ARGS
9211 // Finish computing the outgoing args area size
9213 // Need to make sure the MIN_ARG_AREA_FOR_CALL space is added to the frame if:
9214 // 1. there are calls to THROW_HEPLPER methods.
9215 // 2. we are generating profiling Enter/Leave/TailCall hooks. This will ensure
9216 // that even methods without any calls will have outgoing arg area space allocated.
9218 // An example for these two cases is Windows Amd64, where the ABI requires to have 4 slots for
9219 // the outgoing arg space if the method makes any calls.
9220 if (outgoingArgSpaceSize < MIN_ARG_AREA_FOR_CALL)
9222 if (compUsesThrowHelper || compIsProfilerHookNeeded())
9224 outgoingArgSpaceSize = MIN_ARG_AREA_FOR_CALL;
9225 JITDUMP("Bumping outgoingArgSpaceSize to %u for throw helper or profile hook", outgoingArgSpaceSize);
9229 // If a function has localloc, we will need to move the outgoing arg space when the
9230 // localloc happens. When we do this, we need to maintain stack alignment. To avoid
9231 // leaving alignment-related holes when doing this move, make sure the outgoing
9232 // argument space size is a multiple of the stack alignment by aligning up to the next
9233 // stack alignment boundary.
9234 if (compLocallocUsed)
9236 outgoingArgSpaceSize = (unsigned)roundUp(outgoingArgSpaceSize, STACK_ALIGN);
9237 JITDUMP("Bumping outgoingArgSpaceSize to %u for localloc", outgoingArgSpaceSize);
9240 // Publish the final value and mark it as read only so any update
9241 // attempt later will cause an assert.
9242 lvaOutgoingArgSpaceSize = outgoingArgSpaceSize;
9243 lvaOutgoingArgSpaceSize.MarkAsReadOnly();
9245 #endif // FEATURE_FIXED_OUT_ARGS
9248 if (verbose && fgRngChkThrowAdded)
9250 printf("\nAfter fgSimpleLowering() added some RngChk throw blocks");
9251 fgDispBasicBlocks();
9258 /*****************************************************************************
9261 void Compiler::fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTreePtr clonedTree)
9263 assert(clonedTree->gtOper != GT_STMT);
9265 if (lvaLocalVarRefCounted)
9267 compCurBB = addedToBlock;
9268 fgWalkTreePre(&clonedTree, Compiler::lvaIncRefCntsCB, (void*)this, true);
9272 /*****************************************************************************
9275 void Compiler::fgUpdateRefCntForExtract(GenTreePtr wholeTree, GenTreePtr keptTree)
9277 if (lvaLocalVarRefCounted)
9279 /* Update the refCnts of removed lcl vars - The problem is that
9280 * we have to consider back the side effects trees so we first
9281 * increment all refCnts for side effects then decrement everything
9286 fgWalkTreePre(&keptTree, Compiler::lvaIncRefCntsCB, (void*)this, true);
9289 fgWalkTreePre(&wholeTree, Compiler::lvaDecRefCntsCB, (void*)this, true);
9293 VARSET_VALRET_TP Compiler::fgGetVarBits(GenTreePtr tree)
9295 VARSET_TP VARSET_INIT_NOCOPY(varBits, VarSetOps::MakeEmpty(this));
9297 assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_REG_VAR);
9299 unsigned int lclNum = tree->gtLclVarCommon.gtLclNum;
9300 LclVarDsc* varDsc = lvaTable + lclNum;
9301 if (varDsc->lvTracked)
9303 VarSetOps::AddElemD(this, varBits, varDsc->lvVarIndex);
9305 else if (varDsc->lvType == TYP_STRUCT && varDsc->lvPromoted)
9307 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
9309 noway_assert(lvaTable[i].lvIsStructField);
9310 if (lvaTable[i].lvTracked)
9312 unsigned varIndex = lvaTable[i].lvVarIndex;
9313 noway_assert(varIndex < lvaTrackedCount);
9314 VarSetOps::AddElemD(this, varBits, varIndex);
9321 /*****************************************************************************
9323 * Find and remove any basic blocks that are useless (e.g. they have not been
9324 * imported because they are not reachable, or they have been optimized away).
9327 void Compiler::fgRemoveEmptyBlocks()
9332 /* If we remove any blocks, we'll have to do additional work */
9334 unsigned removedBlks = 0;
9336 for (cur = fgFirstBB; cur != nullptr; cur = nxt)
9338 /* Get hold of the next block (in case we delete 'cur') */
9342 /* Should this block be removed? */
9344 if (!(cur->bbFlags & BBF_IMPORTED))
9346 noway_assert(cur->isEmpty());
9348 if (ehCanDeleteEmptyBlock(cur))
9350 /* Mark the block as removed */
9352 cur->bbFlags |= BBF_REMOVED;
9354 /* Remember that we've removed a block from the list */
9361 printf("BB%02u was not imported, marked as removed (%d)\n", cur->bbNum, removedBlks);
9365 /* Drop the block from the list */
9371 // We were prevented from deleting this block by EH normalization. Mark the block as imported.
9372 cur->bbFlags |= BBF_IMPORTED;
9377 /* If no blocks were removed, we're done */
9379 if (removedBlks == 0)
9384 /* Update all references in the exception handler table.
9385 * Mark the new blocks as non-removable.
9387 * We may have made the entire try block unreachable.
9388 * Check for this case and remove the entry from the EH table.
9393 INDEBUG(unsigned delCnt = 0;)
9395 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
9398 /* If the beginning of the try block was not imported, we
9399 * need to remove the entry from the EH table. */
9401 if (HBtab->ebdTryBeg->bbFlags & BBF_REMOVED)
9403 noway_assert(!(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED));
9407 printf("Beginning of try block (BB%02u) not imported "
9408 "- remove index #%u from the EH table\n",
9409 HBtab->ebdTryBeg->bbNum, XTnum + delCnt);
9414 fgRemoveEHTableEntry(XTnum);
9416 if (XTnum < compHndBBtabCount)
9418 // There are more entries left to process, so do more. Note that
9419 // HBtab now points to the next entry, that we copied down to the
9420 // current slot. XTnum also stays the same.
9424 break; // no more entries (we deleted the last one), so exit the loop
9427 /* At this point we know we have a valid try block */
9430 assert(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED);
9431 assert(HBtab->ebdTryBeg->bbFlags & BBF_DONT_REMOVE);
9433 assert(HBtab->ebdHndBeg->bbFlags & BBF_IMPORTED);
9434 assert(HBtab->ebdHndBeg->bbFlags & BBF_DONT_REMOVE);
9436 if (HBtab->HasFilter())
9438 assert(HBtab->ebdFilter->bbFlags & BBF_IMPORTED);
9439 assert(HBtab->ebdFilter->bbFlags & BBF_DONT_REMOVE);
9443 fgSkipRmvdBlocks(HBtab);
9444 } /* end of the for loop over XTnum */
9446 // Renumber the basic blocks
9447 JITDUMP("\nRenumbering the basic blocks for fgRemoveEmptyBlocks\n");
9451 fgVerifyHandlerTab();
9455 /*****************************************************************************
9457 * Remove a useless statement from a basic block.
9458 * The default is to decrement ref counts of included vars
9462 void Compiler::fgRemoveStmt(BasicBlock* block,
9464 // whether to decrement ref counts for tracked vars in statement
9465 bool updateRefCount)
9468 assert(fgOrder == FGOrderTree);
9470 GenTreeStmt* tree = block->firstStmt();
9471 GenTreeStmt* stmt = node->AsStmt();
9475 stmt->gtStmtExpr->gtOper != GT_NOP) // Don't print if it is a GT_NOP. Too much noise from the inliner.
9477 printf("\nRemoving statement ");
9479 printf(" in BB%02u as useless:\n", block->bbNum);
9484 if (opts.compDbgCode && stmt->gtPrev != stmt && stmt->gtStmtILoffsx != BAD_IL_OFFSET)
9486 /* TODO: For debuggable code, should we remove significant
9487 statement boundaries. Or should we leave a GT_NO_OP in its place? */
9490 /* Is it the first statement in the list? */
9492 GenTreeStmt* firstStmt = block->firstStmt();
9493 if (firstStmt == stmt)
9495 if (firstStmt->gtNext == nullptr)
9497 assert(firstStmt == block->lastStmt());
9499 /* this is the only statement - basic block becomes empty */
9500 block->bbTreeList = nullptr;
9504 block->bbTreeList = tree->gtNext;
9505 block->bbTreeList->gtPrev = tree->gtPrev;
9510 /* Is it the last statement in the list? */
9512 if (stmt == block->lastStmt())
9514 stmt->gtPrev->gtNext = nullptr;
9515 block->bbTreeList->gtPrev = stmt->gtPrev;
9519 tree = stmt->gtPrevStmt;
9522 tree->gtNext = stmt->gtNext;
9523 stmt->gtNext->gtPrev = tree;
9526 fgStmtRemoved = true;
9528 if (optValnumCSE_phase)
9530 optValnumCSE_UnmarkCSEs(stmt->gtStmtExpr, nullptr);
9536 if (fgStmtListThreaded)
9538 fgWalkTreePre(&stmt->gtStmtExpr, Compiler::lvaDecRefCntsCB, (void*)this, true);
9546 if (block->bbTreeList == nullptr)
9548 printf("\nBB%02u becomes empty", block->bbNum);
9555 /******************************************************************************/
9556 // Returns true if the operator is involved in control-flow
9557 // TODO-Cleanup: Move this into genTreeKinds in genTree.h
9559 inline bool OperIsControlFlow(genTreeOps oper)
9573 #if !FEATURE_EH_FUNCLETS
9575 #endif // !FEATURE_EH_FUNCLETS
9583 /******************************************************************************
9584 * Tries to throw away a stmt. The statement can be anywhere in block->bbTreeList.
9585 * Returns true if it did remove the statement.
9588 bool Compiler::fgCheckRemoveStmt(BasicBlock* block, GenTreePtr node)
9590 if (opts.compDbgCode)
9595 GenTreeStmt* stmt = node->AsStmt();
9597 GenTreePtr tree = stmt->gtStmtExpr;
9598 genTreeOps oper = tree->OperGet();
9600 if (OperIsControlFlow(oper) || oper == GT_NO_OP)
9605 // TODO: Use a recursive version of gtNodeHasSideEffects()
9606 if (tree->gtFlags & GTF_SIDE_EFFECT)
9611 fgRemoveStmt(block, stmt);
9615 /****************************************************************************************************
9619 bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext)
9621 if ((block == nullptr) || (bNext == nullptr))
9626 noway_assert(block->bbNext == bNext);
9628 if (block->bbJumpKind != BBJ_NONE)
9633 // If the next block has multiple incoming edges, we can still compact if the first block is empty.
9634 // However, not if it is the beginning of a handler.
9635 if (bNext->countOfInEdges() != 1 &&
9636 (!block->isEmpty() || (block->bbFlags & BBF_FUNCLET_BEG) || (block->bbCatchTyp != BBCT_NONE)))
9641 if (bNext->bbFlags & BBF_DONT_REMOVE)
9646 // Don't compact the first block if it was specially created as a scratch block.
9647 if (fgBBisScratch(block))
9652 #if defined(_TARGET_ARM_)
9653 // We can't compact a finally target block, as we need to generate special code for such blocks during code
9655 if ((bNext->bbFlags & BBF_FINALLY_TARGET) != 0)
9659 // We don't want to compact blocks that are in different Hot/Cold regions
9661 if (fgInDifferentRegions(block, bNext))
9666 // We cannot compact two blocks in different EH regions.
9668 if (fgCanRelocateEHRegions)
9670 if (!BasicBlock::sameEHRegion(block, bNext))
9675 // if there is a switch predecessor don't bother because we'd have to update the uniquesuccs as well
9676 // (if they are valid)
9677 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
9679 if (pred->flBlock->bbJumpKind == BBJ_SWITCH)
9688 /*****************************************************************************************************
9690 * Function called to compact two given blocks in the flowgraph
9691 * Assumes that all necessary checks have been performed,
9692 * i.e. fgCanCompactBlocks returns true.
9694 * Uses for this function - whenever we change links, insert blocks,...
9695 * It will keep the flowgraph data in synch - bbNum, bbRefs, bbPreds
9698 void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext)
9700 noway_assert(block != nullptr);
9701 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
9702 noway_assert(block->bbJumpKind == BBJ_NONE);
9704 noway_assert(bNext == block->bbNext);
9705 noway_assert(bNext != nullptr);
9706 noway_assert((bNext->bbFlags & BBF_REMOVED) == 0);
9707 noway_assert(bNext->countOfInEdges() == 1 || block->isEmpty());
9708 noway_assert(bNext->bbPreds);
9710 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9711 noway_assert((bNext->bbFlags & BBF_FINALLY_TARGET) == 0);
9712 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9714 // Make sure the second block is not the start of a TRY block or an exception handler
9716 noway_assert(bNext->bbCatchTyp == BBCT_NONE);
9717 noway_assert((bNext->bbFlags & BBF_TRY_BEG) == 0);
9718 noway_assert((bNext->bbFlags & BBF_DONT_REMOVE) == 0);
9720 /* both or none must have an exception handler */
9721 noway_assert(block->hasTryIndex() == bNext->hasTryIndex());
9726 printf("\nCompacting blocks BB%02u and BB%02u:\n", block->bbNum, bNext->bbNum);
9730 if (bNext->countOfInEdges() > 1)
9732 JITDUMP("Second block has multiple incoming edges\n");
9734 assert(block->isEmpty());
9735 block->bbFlags |= BBF_JMP_TARGET;
9736 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
9738 fgReplaceJumpTarget(pred->flBlock, block, bNext);
9740 if (pred->flBlock != block)
9742 fgAddRefPred(block, pred->flBlock);
9745 bNext->bbPreds = nullptr;
9749 noway_assert(bNext->bbPreds->flNext == nullptr);
9750 noway_assert(bNext->bbPreds->flBlock == block);
9753 /* Start compacting - move all the statements in the second block to the first block */
9755 // First move any phi definitions of the second block after the phi defs of the first.
9756 // TODO-CQ: This may be the wrong thing to do. If we're compacting blocks, it's because a
9757 // control-flow choice was constant-folded away. So probably phi's need to go away,
9758 // as well, in favor of one of the incoming branches. Or at least be modified.
9760 assert(block->IsLIR() == bNext->IsLIR());
9763 LIR::Range& blockRange = LIR::AsRange(block);
9764 LIR::Range& nextRange = LIR::AsRange(bNext);
9766 // Does the next block have any phis?
9767 GenTree* nextFirstNonPhi = nullptr;
9768 LIR::ReadOnlyRange nextPhis = nextRange.PhiNodes();
9769 if (!nextPhis.IsEmpty())
9771 GenTree* blockLastPhi = blockRange.LastPhiNode();
9772 nextFirstNonPhi = nextPhis.LastNode()->gtNext;
9774 LIR::Range phisToMove = nextRange.Remove(std::move(nextPhis));
9775 blockRange.InsertAfter(blockLastPhi, std::move(phisToMove));
9779 nextFirstNonPhi = nextRange.FirstNode();
9782 // Does the block have any other code?
9783 if (nextFirstNonPhi != nullptr)
9785 LIR::Range nextNodes = nextRange.Remove(nextFirstNonPhi, nextRange.LastNode());
9786 blockRange.InsertAtEnd(std::move(nextNodes));
9791 GenTreePtr blkNonPhi1 = block->FirstNonPhiDef();
9792 GenTreePtr bNextNonPhi1 = bNext->FirstNonPhiDef();
9793 GenTreePtr blkFirst = block->firstStmt();
9794 GenTreePtr bNextFirst = bNext->firstStmt();
9796 // Does the second have any phis?
9797 if (bNextFirst != nullptr && bNextFirst != bNextNonPhi1)
9799 GenTreePtr bNextLast = bNextFirst->gtPrev;
9800 assert(bNextLast->gtNext == nullptr);
9802 // Does "blk" have phis?
9803 if (blkNonPhi1 != blkFirst)
9806 // Insert after the last phi of "block."
9807 // First, bNextPhis after last phi of block.
9808 GenTreePtr blkLastPhi;
9809 if (blkNonPhi1 != nullptr)
9811 blkLastPhi = blkNonPhi1->gtPrev;
9815 blkLastPhi = blkFirst->gtPrev;
9818 blkLastPhi->gtNext = bNextFirst;
9819 bNextFirst->gtPrev = blkLastPhi;
9821 // Now, rest of "block" after last phi of "bNext".
9822 GenTreePtr bNextLastPhi = nullptr;
9823 if (bNextNonPhi1 != nullptr)
9825 bNextLastPhi = bNextNonPhi1->gtPrev;
9829 bNextLastPhi = bNextFirst->gtPrev;
9832 bNextLastPhi->gtNext = blkNonPhi1;
9833 if (blkNonPhi1 != nullptr)
9835 blkNonPhi1->gtPrev = bNextLastPhi;
9839 // block has no non phis, so make the last statement be the last added phi.
9840 blkFirst->gtPrev = bNextLastPhi;
9843 // Now update the bbTreeList of "bNext".
9844 bNext->bbTreeList = bNextNonPhi1;
9845 if (bNextNonPhi1 != nullptr)
9847 bNextNonPhi1->gtPrev = bNextLast;
9852 if (blkFirst != nullptr) // If "block" has no statements, fusion will work fine...
9854 // First, bNextPhis at start of block.
9855 GenTreePtr blkLast = blkFirst->gtPrev;
9856 block->bbTreeList = bNextFirst;
9857 // Now, rest of "block" (if it exists) after last phi of "bNext".
9858 GenTreePtr bNextLastPhi = nullptr;
9859 if (bNextNonPhi1 != nullptr)
9861 // There is a first non phi, so the last phi is before it.
9862 bNextLastPhi = bNextNonPhi1->gtPrev;
9866 // All the statements are phi defns, so the last one is the prev of the first.
9867 bNextLastPhi = bNextFirst->gtPrev;
9869 bNextFirst->gtPrev = blkLast;
9870 bNextLastPhi->gtNext = blkFirst;
9871 blkFirst->gtPrev = bNextLastPhi;
9872 // Now update the bbTreeList of "bNext"
9873 bNext->bbTreeList = bNextNonPhi1;
9874 if (bNextNonPhi1 != nullptr)
9876 bNextNonPhi1->gtPrev = bNextLast;
9882 // Now proceed with the updated bbTreeLists.
9883 GenTreePtr stmtList1 = block->firstStmt();
9884 GenTreePtr stmtList2 = bNext->firstStmt();
9886 /* the block may have an empty list */
9890 GenTreePtr stmtLast1 = block->lastStmt();
9892 /* The second block may be a GOTO statement or something with an empty bbTreeList */
9895 GenTreePtr stmtLast2 = bNext->lastStmt();
9897 /* append list2 to list 1 */
9899 stmtLast1->gtNext = stmtList2;
9900 stmtList2->gtPrev = stmtLast1;
9901 stmtList1->gtPrev = stmtLast2;
9906 /* block was formerly empty and now has bNext's statements */
9907 block->bbTreeList = stmtList2;
9911 // Note we could update the local variable weights here by
9912 // calling lvaMarkLocalVars, with the block and weight adjustment.
9914 // If either block or bNext has a profile weight
9915 // or if both block and bNext have non-zero weights
9916 // then we select the highest weight block.
9918 if (block->hasProfileWeight() || bNext->hasProfileWeight() || (block->bbWeight && bNext->bbWeight))
9920 // We are keeping block so update its fields
9921 // when bNext has a greater weight
9923 if (block->bbWeight < bNext->bbWeight)
9925 block->bbWeight = bNext->bbWeight;
9927 block->bbFlags |= (bNext->bbFlags & BBF_PROF_WEIGHT); // Set the profile weight flag (if necessary)
9928 if (block->bbWeight != 0)
9930 block->bbFlags &= ~BBF_RUN_RARELY; // Clear any RarelyRun flag
9934 // otherwise if either block has a zero weight we select the zero weight
9937 noway_assert((block->bbWeight == BB_ZERO_WEIGHT) || (bNext->bbWeight == BB_ZERO_WEIGHT));
9938 block->bbWeight = BB_ZERO_WEIGHT;
9939 block->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
9942 /* set the right links */
9944 block->bbJumpKind = bNext->bbJumpKind;
9945 VarSetOps::AssignAllowUninitRhs(this, block->bbLiveOut, bNext->bbLiveOut);
9947 // Update the beginning and ending IL offsets (bbCodeOffs and bbCodeOffsEnd).
9948 // Set the beginning IL offset to the minimum, and the ending offset to the maximum, of the respective blocks.
9949 // If one block has an unknown offset, we take the other block.
9950 // We are merging into 'block', so if its values are correct, just leave them alone.
9951 // TODO: we should probably base this on the statements within.
9953 if (block->bbCodeOffs == BAD_IL_OFFSET)
9955 block->bbCodeOffs = bNext->bbCodeOffs; // If they are both BAD_IL_OFFSET, this doesn't change anything.
9957 else if (bNext->bbCodeOffs != BAD_IL_OFFSET)
9959 // The are both valid offsets; compare them.
9960 if (block->bbCodeOffs > bNext->bbCodeOffs)
9962 block->bbCodeOffs = bNext->bbCodeOffs;
9966 if (block->bbCodeOffsEnd == BAD_IL_OFFSET)
9968 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd; // If they are both BAD_IL_OFFSET, this doesn't change anything.
9970 else if (bNext->bbCodeOffsEnd != BAD_IL_OFFSET)
9972 // The are both valid offsets; compare them.
9973 if (block->bbCodeOffsEnd < bNext->bbCodeOffsEnd)
9975 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd;
9979 if (((block->bbFlags & BBF_INTERNAL) != 0) && ((bNext->bbFlags & BBF_INTERNAL) == 0))
9981 // If 'block' is an internal block and 'bNext' isn't, then adjust the flags set on 'block'.
9982 block->bbFlags &= ~BBF_INTERNAL; // Clear the BBF_INTERNAL flag
9983 block->bbFlags |= BBF_IMPORTED; // Set the BBF_IMPORTED flag
9986 /* Update the flags for block with those found in bNext */
9988 block->bbFlags |= (bNext->bbFlags & BBF_COMPACT_UPD);
9990 /* mark bNext as removed */
9992 bNext->bbFlags |= BBF_REMOVED;
9994 /* Unlink bNext and update all the marker pointers if necessary */
9996 fgUnlinkRange(block->bbNext, bNext);
9998 // If bNext was the last block of a try or handler, update the EH table.
10000 ehUpdateForDeletedBlock(bNext);
10002 /* If we're collapsing a block created after the dominators are
10003 computed, rename the block and reuse dominator information from
10005 if (fgDomsComputed && block->bbNum > fgDomBBcount)
10007 BlockSetOps::Assign(this, block->bbReach, bNext->bbReach);
10008 BlockSetOps::ClearD(this, bNext->bbReach);
10010 block->bbIDom = bNext->bbIDom;
10011 bNext->bbIDom = nullptr;
10013 // In this case, there's no need to update the preorder and postorder numbering
10014 // since we're changing the bbNum, this makes the basic block all set.
10015 block->bbNum = bNext->bbNum;
10018 /* Set the jump targets */
10020 switch (bNext->bbJumpKind)
10022 case BBJ_CALLFINALLY:
10023 // Propagate RETLESS property
10024 block->bbFlags |= (bNext->bbFlags & BBF_RETLESS_CALL);
10030 case BBJ_EHCATCHRET:
10031 block->bbJumpDest = bNext->bbJumpDest;
10033 /* Update the predecessor list for 'bNext->bbJumpDest' */
10034 fgReplacePred(bNext->bbJumpDest, bNext, block);
10036 /* Update the predecessor list for 'bNext->bbNext' if it is different than 'bNext->bbJumpDest' */
10037 if (bNext->bbJumpKind == BBJ_COND && bNext->bbJumpDest != bNext->bbNext)
10039 fgReplacePred(bNext->bbNext, bNext, block);
10044 /* Update the predecessor list for 'bNext->bbNext' */
10045 fgReplacePred(bNext->bbNext, bNext, block);
10048 case BBJ_EHFILTERRET:
10049 fgReplacePred(bNext->bbJumpDest, bNext, block);
10052 case BBJ_EHFINALLYRET:
10054 unsigned hndIndex = block->getHndIndex();
10055 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
10057 if (ehDsc->HasFinallyHandler()) // No need to do this for fault handlers
10059 BasicBlock* begBlk;
10060 BasicBlock* endBlk;
10061 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
10063 BasicBlock* finBeg = ehDsc->ebdHndBeg;
10065 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
10067 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
10072 noway_assert(bcall->isBBCallAlwaysPair());
10073 fgReplacePred(bcall->bbNext, bNext, block);
10081 /* no jumps or fall through blocks to set here */
10085 block->bbJumpSwt = bNext->bbJumpSwt;
10086 // We are moving the switch jump from bNext to block. Examine the jump targets
10087 // of the BBJ_SWITCH at bNext and replace the predecessor to 'bNext' with ones to 'block'
10088 fgChangeSwitchBlock(bNext, block);
10092 noway_assert(!"Unexpected bbJumpKind");
10096 fgUpdateLoopsAfterCompacting(block, bNext);
10101 printf("\nAfter compacting:\n");
10102 fgDispBasicBlocks(false);
10107 if (JitConfig.JitSlowDebugChecksEnabled() != 0)
10109 // Make sure that the predecessor lists are accurate
10110 fgDebugCheckBBlist();
10115 void Compiler::fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext)
10117 /* Check if the removed block is not part the loop table */
10118 noway_assert(bNext);
10120 for (unsigned loopNum = 0; loopNum < optLoopCount; loopNum++)
10122 /* Some loops may have been already removed by
10123 * loop unrolling or conditional folding */
10125 if (optLoopTable[loopNum].lpFlags & LPFLG_REMOVED)
10130 /* Check the loop head (i.e. the block preceding the loop) */
10132 if (optLoopTable[loopNum].lpHead == bNext)
10134 optLoopTable[loopNum].lpHead = block;
10137 /* Check the loop bottom */
10139 if (optLoopTable[loopNum].lpBottom == bNext)
10141 optLoopTable[loopNum].lpBottom = block;
10144 /* Check the loop exit */
10146 if (optLoopTable[loopNum].lpExit == bNext)
10148 noway_assert(optLoopTable[loopNum].lpExitCnt == 1);
10149 optLoopTable[loopNum].lpExit = block;
10152 /* Check the loop entry */
10154 if (optLoopTable[loopNum].lpEntry == bNext)
10156 optLoopTable[loopNum].lpEntry = block;
10161 /*****************************************************************************************************
10163 * Function called to remove a block when it is unreachable.
10165 * This function cannot remove the first block.
10168 void Compiler::fgUnreachableBlock(BasicBlock* block)
10170 // genReturnBB should never be removed, as we might have special hookups there.
10171 // Therefore, we should never come here to remove the statements in the genReturnBB block.
10172 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
10173 // the profiler hookup needs to have the "void GT_RETURN" statement
10174 // to properly set the info.compProfilerCallback flag.
10175 noway_assert(block != genReturnBB);
10177 if (block->bbFlags & BBF_REMOVED)
10182 /* Removing an unreachable block */
10187 printf("\nRemoving unreachable BB%02u\n", block->bbNum);
10191 noway_assert(block->bbPrev != nullptr); // Can use this function to remove the first block
10193 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10194 assert(!block->bbPrev->isBBCallAlwaysPair()); // can't remove the BBJ_ALWAYS of a BBJ_CALLFINALLY / BBJ_ALWAYS pair
10195 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10197 /* First walk the statement trees in this basic block and delete each stmt */
10199 /* Make the block publicly available */
10202 if (block->IsLIR())
10204 LIR::Range& blockRange = LIR::AsRange(block);
10205 if (!blockRange.IsEmpty())
10207 blockRange.Delete(this, block, blockRange.FirstNode(), blockRange.LastNode());
10212 // TODO-Cleanup: I'm not sure why this happens -- if the block is unreachable, why does it have phis?
10213 // Anyway, remove any phis.
10215 GenTreePtr firstNonPhi = block->FirstNonPhiDef();
10216 if (block->bbTreeList != firstNonPhi)
10218 if (firstNonPhi != nullptr)
10220 firstNonPhi->gtPrev = block->lastStmt();
10222 block->bbTreeList = firstNonPhi;
10225 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
10227 fgRemoveStmt(block, stmt);
10229 noway_assert(block->bbTreeList == nullptr);
10232 /* Next update the loop table and bbWeights */
10233 optUpdateLoopsBeforeRemoveBlock(block);
10235 /* Mark the block as removed */
10236 block->bbFlags |= BBF_REMOVED;
10238 /* update bbRefs and bbPreds for the blocks reached by this block */
10239 fgRemoveBlockAsPred(block);
10242 /*****************************************************************************************************
10244 * Function called to remove or morph a jump when we jump to the same
10245 * block when both the condition is true or false.
10247 void Compiler::fgRemoveConditionalJump(BasicBlock* block)
10249 noway_assert(block->bbJumpKind == BBJ_COND && block->bbJumpDest == block->bbNext);
10250 assert(compRationalIRForm == block->IsLIR());
10252 flowList* flow = fgGetPredForBlock(block->bbNext, block);
10253 noway_assert(flow->flDupCount == 2);
10255 // Change the BBJ_COND to BBJ_NONE, and adjust the refCount and dupCount.
10256 block->bbJumpKind = BBJ_NONE;
10257 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
10258 --block->bbNext->bbRefs;
10259 --flow->flDupCount;
10262 block->bbJumpDest = nullptr;
10265 printf("Block BB%02u becoming a BBJ_NONE to BB%02u (jump target is the same whether the condition is true or "
10267 block->bbNum, block->bbNext->bbNum);
10271 /* Remove the block jump condition */
10273 if (block->IsLIR())
10275 LIR::Range& blockRange = LIR::AsRange(block);
10277 GenTree* test = blockRange.LastNode();
10278 assert(test->OperIsConditionalJump());
10281 unsigned sideEffects;
10282 LIR::ReadOnlyRange testRange = blockRange.GetTreeRange(test, &isClosed, &sideEffects);
10284 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
10285 // diffs compared to the existing backend.
10286 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
10288 // If the jump and its operands form a contiguous, side-effect-free range,
10290 blockRange.Delete(this, block, std::move(testRange));
10294 // Otherwise, just remove the jump node itself.
10295 blockRange.Remove(test);
10300 GenTreeStmt* test = block->lastStmt();
10301 GenTree* tree = test->gtStmtExpr;
10303 noway_assert(tree->gtOper == GT_JTRUE);
10305 GenTree* sideEffList = nullptr;
10307 if (tree->gtFlags & GTF_SIDE_EFFECT)
10309 gtExtractSideEffList(tree, &sideEffList);
10313 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
10317 printf("Extracted side effects list from condition...\n");
10318 gtDispTree(sideEffList);
10325 // Delete the cond test or replace it with the side effect tree
10326 if (sideEffList == nullptr)
10328 fgRemoveStmt(block, test);
10332 test->gtStmtExpr = sideEffList;
10334 fgMorphBlockStmt(block, test DEBUGARG("fgRemoveConditionalJump"));
10339 /*****************************************************************************************************
10341 * Function to return the last basic block in the main part of the function. With funclets, it is
10342 * the block immediately before the first funclet.
10343 * An inclusive end of the main method.
10346 BasicBlock* Compiler::fgLastBBInMainFunction()
10348 #if FEATURE_EH_FUNCLETS
10350 if (fgFirstFuncletBB != nullptr)
10352 return fgFirstFuncletBB->bbPrev;
10355 #endif // FEATURE_EH_FUNCLETS
10357 assert(fgLastBB->bbNext == nullptr);
10362 /*****************************************************************************************************
10364 * Function to return the first basic block after the main part of the function. With funclets, it is
10365 * the block of the first funclet. Otherwise it is NULL if there are no funclets (fgLastBB->bbNext).
10366 * This is equivalent to fgLastBBInMainFunction()->bbNext
10367 * An exclusive end of the main method.
10370 BasicBlock* Compiler::fgEndBBAfterMainFunction()
10372 #if FEATURE_EH_FUNCLETS
10374 if (fgFirstFuncletBB != nullptr)
10376 return fgFirstFuncletBB;
10379 #endif // FEATURE_EH_FUNCLETS
10381 assert(fgLastBB->bbNext == nullptr);
10386 // Removes the block from the bbPrev/bbNext chain
10387 // Updates fgFirstBB and fgLastBB if necessary
10388 // Does not update fgFirstFuncletBB or fgFirstColdBlock (fgUnlinkRange does)
10390 void Compiler::fgUnlinkBlock(BasicBlock* block)
10394 block->bbPrev->bbNext = block->bbNext;
10397 block->bbNext->bbPrev = block->bbPrev;
10401 fgLastBB = block->bbPrev;
10406 assert(block == fgFirstBB);
10407 assert(block != fgLastBB);
10408 assert((fgFirstBBScratch == nullptr) || (fgFirstBBScratch == fgFirstBB));
10410 fgFirstBB = block->bbNext;
10411 fgFirstBB->bbPrev = nullptr;
10413 if (fgFirstBBScratch != nullptr)
10416 // We had created an initial scratch BB, but now we're deleting it.
10419 printf("Unlinking scratch BB%02u\n", block->bbNum);
10422 fgFirstBBScratch = nullptr;
10427 /*****************************************************************************************************
10429 * Function called to unlink basic block range [bBeg .. bEnd] from the basic block list.
10431 * 'bBeg' can't be the first block.
10434 void Compiler::fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd)
10436 assert(bBeg != nullptr);
10437 assert(bEnd != nullptr);
10439 BasicBlock* bPrev = bBeg->bbPrev;
10440 assert(bPrev != nullptr); // Can't unlink a range starting with the first block
10442 bPrev->setNext(bEnd->bbNext);
10444 /* If we removed the last block in the method then update fgLastBB */
10445 if (fgLastBB == bEnd)
10448 noway_assert(fgLastBB->bbNext == nullptr);
10451 // If bEnd was the first Cold basic block update fgFirstColdBlock
10452 if (fgFirstColdBlock == bEnd)
10454 fgFirstColdBlock = bPrev->bbNext;
10457 #if FEATURE_EH_FUNCLETS
10459 // You can't unlink a range that includes the first funclet block. A range certainly
10460 // can't cross the non-funclet/funclet region. And you can't unlink the first block
10461 // of the first funclet with this, either. (If that's necessary, it could be allowed
10462 // by updating fgFirstFuncletBB to bEnd->bbNext.)
10463 for (BasicBlock* tempBB = bBeg; tempBB != bEnd->bbNext; tempBB = tempBB->bbNext)
10465 assert(tempBB != fgFirstFuncletBB);
10468 #endif // FEATURE_EH_FUNCLETS
10471 /*****************************************************************************************************
10473 * Function called to remove a basic block
10476 void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
10478 BasicBlock* bPrev = block->bbPrev;
10480 /* The block has to be either unreachable or empty */
10482 PREFIX_ASSUME(block != nullptr);
10484 JITDUMP("fgRemoveBlock BB%02u\n", block->bbNum);
10486 // If we've cached any mappings from switch blocks to SwitchDesc's (which contain only the
10487 // *unique* successors of the switch block), invalidate that cache, since an entry in one of
10488 // the SwitchDescs might be removed.
10489 InvalidateUniqueSwitchSuccMap();
10491 noway_assert((block == fgFirstBB) || (bPrev && (bPrev->bbNext == block)));
10492 noway_assert(!(block->bbFlags & BBF_DONT_REMOVE));
10494 // Should never remove a genReturnBB, as we might have special hookups there.
10495 noway_assert(block != genReturnBB);
10497 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10498 // Don't remove a finally target
10499 assert(!(block->bbFlags & BBF_FINALLY_TARGET));
10500 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10504 PREFIX_ASSUME(bPrev != nullptr);
10506 fgUnreachableBlock(block);
10508 /* If this is the last basic block update fgLastBB */
10509 if (block == fgLastBB)
10514 #if FEATURE_EH_FUNCLETS
10515 // If block was the fgFirstFuncletBB then set fgFirstFuncletBB to block->bbNext
10516 if (block == fgFirstFuncletBB)
10518 fgFirstFuncletBB = block->bbNext;
10520 #endif // FEATURE_EH_FUNCLETS
10522 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
10524 // bPrev CALL becomes RETLESS as the BBJ_ALWAYS block is unreachable
10525 bPrev->bbFlags |= BBF_RETLESS_CALL;
10527 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10528 NO_WAY("No retless call finally blocks; need unwind target instead");
10529 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10531 else if (bPrev->bbJumpKind == BBJ_ALWAYS && bPrev->bbJumpDest == block->bbNext &&
10532 !(bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) && (block != fgFirstColdBlock) &&
10533 (block->bbNext != fgFirstColdBlock))
10535 // previous block is a BBJ_ALWAYS to the next block: change to BBJ_NONE.
10536 // Note that we don't do it if bPrev follows a BBJ_CALLFINALLY block (BBF_KEEP_BBJ_ALWAYS),
10537 // because that would violate our invariant that BBJ_CALLFINALLY blocks are followed by
10538 // BBJ_ALWAYS blocks.
10539 bPrev->bbJumpKind = BBJ_NONE;
10540 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
10543 // If this is the first Cold basic block update fgFirstColdBlock
10544 if (block == fgFirstColdBlock)
10546 fgFirstColdBlock = block->bbNext;
10549 /* Unlink this block from the bbNext chain */
10550 fgUnlinkBlock(block);
10552 /* At this point the bbPreds and bbRefs had better be zero */
10553 noway_assert((block->bbRefs == 0) && (block->bbPreds == nullptr));
10555 /* A BBJ_CALLFINALLY is usually paired with a BBJ_ALWAYS.
10556 * If we delete such a BBJ_CALLFINALLY we also delete the BBJ_ALWAYS
10558 if (block->isBBCallAlwaysPair())
10560 BasicBlock* leaveBlk = block->bbNext;
10561 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
10563 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
10564 leaveBlk->bbRefs = 0;
10565 leaveBlk->bbPreds = nullptr;
10567 fgRemoveBlock(leaveBlk, true);
10569 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10570 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
10571 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10573 else if (block->bbJumpKind == BBJ_RETURN)
10575 fgRemoveReturnBlock(block);
10578 else // block is empty
10580 noway_assert(block->isEmpty());
10582 /* The block cannot follow a non-retless BBJ_CALLFINALLY (because we don't know who may jump to it) */
10583 noway_assert((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair());
10585 /* This cannot be the last basic block */
10586 noway_assert(block != fgLastBB);
10591 printf("Removing empty BB%02u\n", block->bbNum);
10596 /* Some extra checks for the empty case */
10598 switch (block->bbJumpKind)
10604 /* Do not remove a block that jumps to itself - used for while (true){} */
10605 noway_assert(block->bbJumpDest != block);
10607 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
10608 noway_assert(bPrev && bPrev->bbJumpKind == BBJ_NONE);
10612 noway_assert(!"Empty block of this type cannot be removed!");
10617 noway_assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS);
10619 /* Who is the "real" successor of this block? */
10621 BasicBlock* succBlock;
10623 if (block->bbJumpKind == BBJ_ALWAYS)
10625 succBlock = block->bbJumpDest;
10629 succBlock = block->bbNext;
10632 bool skipUnmarkLoop = false;
10634 // If block is the backedge for a loop and succBlock precedes block
10635 // then the succBlock becomes the new LOOP HEAD
10636 // NOTE: there's an assumption here that the blocks are numbered in increasing bbNext order.
10637 // NOTE 2: if fgDomsComputed is false, then we can't check reachability. However, if this is
10638 // the case, then the loop structures probably are also invalid, and shouldn't be used. This
10639 // can be the case late in compilation (such as Lower), where remnants of earlier created
10640 // structures exist, but haven't been maintained.
10641 if (block->isLoopHead() && (succBlock->bbNum <= block->bbNum))
10643 succBlock->bbFlags |= BBF_LOOP_HEAD;
10644 if (fgDomsComputed && fgReachable(succBlock, block))
10646 /* Mark all the reachable blocks between 'succBlock' and 'block', excluding 'block' */
10647 optMarkLoopBlocks(succBlock, block, true);
10650 else if (succBlock->isLoopHead() && bPrev && (succBlock->bbNum <= bPrev->bbNum))
10652 skipUnmarkLoop = true;
10655 noway_assert(succBlock);
10657 // If this is the first Cold basic block update fgFirstColdBlock
10658 if (block == fgFirstColdBlock)
10660 fgFirstColdBlock = block->bbNext;
10663 #if FEATURE_EH_FUNCLETS
10664 // Update fgFirstFuncletBB if necessary
10665 if (block == fgFirstFuncletBB)
10667 fgFirstFuncletBB = block->bbNext;
10669 #endif // FEATURE_EH_FUNCLETS
10671 /* First update the loop table and bbWeights */
10672 optUpdateLoopsBeforeRemoveBlock(block, skipUnmarkLoop);
10674 /* Remove the block */
10676 if (bPrev == nullptr)
10678 /* special case if this is the first BB */
10680 noway_assert(block == fgFirstBB);
10682 /* Must be a fall through to next block */
10684 noway_assert(block->bbJumpKind == BBJ_NONE);
10686 /* old block no longer gets the extra ref count for being the first block */
10688 succBlock->bbRefs++;
10690 /* Set the new firstBB */
10691 fgUnlinkBlock(block);
10693 /* Always treat the initial block as a jump target */
10694 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
10698 fgUnlinkBlock(block);
10701 /* mark the block as removed and set the change flag */
10703 block->bbFlags |= BBF_REMOVED;
10705 /* Update bbRefs and bbPreds.
10706 * All blocks jumping to 'block' now jump to 'succBlock'.
10707 * First, remove 'block' from the predecessor list of succBlock.
10710 fgRemoveRefPred(succBlock, block);
10712 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
10714 BasicBlock* predBlock = pred->flBlock;
10716 /* Are we changing a loop backedge into a forward jump? */
10718 if (block->isLoopHead() && (predBlock->bbNum >= block->bbNum) && (predBlock->bbNum <= succBlock->bbNum))
10720 /* First update the loop table and bbWeights */
10721 optUpdateLoopsBeforeRemoveBlock(predBlock);
10724 /* If predBlock is a new predecessor, then add it to succBlock's
10725 predecessor's list. */
10726 if (predBlock->bbJumpKind != BBJ_SWITCH)
10728 // Even if the pred is not a switch, we could have a conditional branch
10729 // to the fallthrough, so duplicate there could be preds
10730 for (unsigned i = 0; i < pred->flDupCount; i++)
10732 fgAddRefPred(succBlock, predBlock);
10736 /* change all jumps to the removed block */
10737 switch (predBlock->bbJumpKind)
10740 noway_assert(!"Unexpected bbJumpKind in fgRemoveBlock()");
10744 noway_assert(predBlock == bPrev);
10745 PREFIX_ASSUME(bPrev != nullptr);
10747 /* In the case of BBJ_ALWAYS we have to change the type of its predecessor */
10748 if (block->bbJumpKind == BBJ_ALWAYS)
10750 /* bPrev now becomes a BBJ_ALWAYS */
10751 bPrev->bbJumpKind = BBJ_ALWAYS;
10752 bPrev->bbJumpDest = succBlock;
10757 /* The links for the direct predecessor case have already been updated above */
10758 if (predBlock->bbJumpDest != block)
10760 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
10764 /* Check if both side of the BBJ_COND now jump to the same block */
10765 if (predBlock->bbNext == succBlock)
10767 // Make sure we are replacing "block" with "succBlock" in predBlock->bbJumpDest.
10768 noway_assert(predBlock->bbJumpDest == block);
10769 predBlock->bbJumpDest = succBlock;
10770 fgRemoveConditionalJump(predBlock);
10774 /* Fall through for the jump case */
10777 case BBJ_CALLFINALLY:
10779 case BBJ_EHCATCHRET:
10780 noway_assert(predBlock->bbJumpDest == block);
10781 predBlock->bbJumpDest = succBlock;
10782 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
10786 // Change any jumps from 'predBlock' (a BBJ_SWITCH) to 'block' to jump to 'succBlock'
10788 // For the jump targets of 'predBlock' (a BBJ_SWITCH) that jump to 'block'
10789 // remove the old predecessor at 'block' from 'predBlock' and
10790 // add the new predecessor at 'succBlock' from 'predBlock'
10792 fgReplaceSwitchJumpTarget(predBlock, succBlock, block);
10798 if (bPrev != nullptr)
10800 switch (bPrev->bbJumpKind)
10802 case BBJ_CALLFINALLY:
10803 // If prev is a BBJ_CALLFINALLY it better be marked as RETLESS
10804 noway_assert(bPrev->bbFlags & BBF_RETLESS_CALL);
10808 // Check for branch to next block. Just make sure the BBJ_ALWAYS block is not
10809 // part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair. We do this here and don't rely on fgUpdateFlowGraph
10810 // because we can be called by ComputeDominators and it expects it to remove this jump to
10811 // the next block. This is the safest fix. We should remove all this BBJ_CALLFINALLY/BBJ_ALWAYS
10814 if ((bPrev->bbJumpDest == bPrev->bbNext) &&
10815 !fgInDifferentRegions(bPrev, bPrev->bbJumpDest)) // We don't remove a branch from Hot -> Cold
10817 if ((bPrev == fgFirstBB) || !bPrev->bbPrev->isBBCallAlwaysPair())
10819 // It's safe to change the jump type
10820 bPrev->bbJumpKind = BBJ_NONE;
10821 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
10827 /* Check for branch to next block */
10828 if (bPrev->bbJumpDest == bPrev->bbNext)
10830 fgRemoveConditionalJump(bPrev);
10838 ehUpdateForDeletedBlock(block);
10842 /*****************************************************************************
10844 * Function called to connect to block that previously had a fall through
10847 BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
10849 BasicBlock* jmpBlk = nullptr;
10851 /* If bSrc is non-NULL */
10853 if (bSrc != nullptr)
10855 /* If bSrc falls through to a block that is not bDst, we will insert a jump to bDst */
10857 if (bSrc->bbFallsThrough() && (bSrc->bbNext != bDst))
10859 switch (bSrc->bbJumpKind)
10863 bSrc->bbJumpKind = BBJ_ALWAYS;
10864 bSrc->bbJumpDest = bDst;
10865 bSrc->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
10869 printf("Block BB%02u ended with a BBJ_NONE, Changed to an unconditional jump to BB%02u\n",
10870 bSrc->bbNum, bSrc->bbJumpDest->bbNum);
10875 case BBJ_CALLFINALLY:
10878 // Add a new block after bSrc which jumps to 'bDst'
10879 jmpBlk = fgNewBBafter(BBJ_ALWAYS, bSrc, true);
10881 if (fgComputePredsDone)
10883 fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc));
10886 // When adding a new jmpBlk we will set the bbWeight and bbFlags
10888 if (fgHaveValidEdgeWeights)
10890 noway_assert(fgComputePredsDone);
10892 flowList* newEdge = fgGetPredForBlock(jmpBlk, bSrc);
10894 jmpBlk->bbWeight = (newEdge->flEdgeWeightMin + newEdge->flEdgeWeightMax) / 2;
10895 if (bSrc->bbWeight == 0)
10897 jmpBlk->bbWeight = 0;
10900 if (jmpBlk->bbWeight == 0)
10902 jmpBlk->bbFlags |= BBF_RUN_RARELY;
10905 BasicBlock::weight_t weightDiff = (newEdge->flEdgeWeightMax - newEdge->flEdgeWeightMin);
10906 BasicBlock::weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst);
10909 // If the [min/max] values for our edge weight is within the slop factor
10910 // then we will set the BBF_PROF_WEIGHT flag for the block
10912 if (weightDiff <= slop)
10914 jmpBlk->bbFlags |= BBF_PROF_WEIGHT;
10919 // We set the bbWeight to the smaller of bSrc->bbWeight or bDst->bbWeight
10920 if (bSrc->bbWeight < bDst->bbWeight)
10922 jmpBlk->bbWeight = bSrc->bbWeight;
10923 jmpBlk->bbFlags |= (bSrc->bbFlags & BBF_RUN_RARELY);
10927 jmpBlk->bbWeight = bDst->bbWeight;
10928 jmpBlk->bbFlags |= (bDst->bbFlags & BBF_RUN_RARELY);
10932 jmpBlk->bbJumpDest = bDst;
10933 jmpBlk->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
10935 if (fgComputePredsDone)
10937 fgReplacePred(bDst, bSrc, jmpBlk);
10941 jmpBlk->bbFlags |= BBF_IMPORTED;
10947 printf("Added an unconditional jump to BB%02u after block BB%02u\n", jmpBlk->bbJumpDest->bbNum,
10954 noway_assert(!"Unexpected bbJumpKind");
10960 // If bSrc is an unconditional branch to the next block
10961 // then change it to a BBJ_NONE block
10963 if ((bSrc->bbJumpKind == BBJ_ALWAYS) && !(bSrc->bbFlags & BBF_KEEP_BBJ_ALWAYS) &&
10964 (bSrc->bbJumpDest == bSrc->bbNext))
10966 bSrc->bbJumpKind = BBJ_NONE;
10967 bSrc->bbFlags &= ~BBF_NEEDS_GCPOLL;
10971 printf("Changed an unconditional jump from BB%02u to the next block BB%02u into a BBJ_NONE block\n",
10972 bSrc->bbNum, bSrc->bbNext->bbNum);
10982 /*****************************************************************************
10983 Walk the flow graph, reassign block numbers to keep them in ascending order.
10984 Returns 'true' if any renumbering was actually done, OR if we change the
10985 maximum number of assigned basic blocks (this can happen if we do inlining,
10986 create a new, high-numbered block, then that block goes away. We go to
10987 renumber the blocks, none of them actually change number, but we shrink the
10988 maximum assigned block number. This affects the block set epoch).
10991 bool Compiler::fgRenumberBlocks()
10993 // If we renumber the blocks the dominator information will be out-of-date
10994 if (fgDomsComputed)
10996 noway_assert(!"Can't call Compiler::fgRenumberBlocks() when fgDomsComputed==true");
11002 printf("\n*************** Before renumbering the basic blocks\n");
11003 fgDispBasicBlocks();
11004 fgDispHandlerTab();
11008 bool renumbered = false;
11009 bool newMaxBBNum = false;
11012 unsigned numStart = 1 + (compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : 0);
11015 for (block = fgFirstBB, num = numStart; block != nullptr; block = block->bbNext, num++)
11017 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
11019 if (block->bbNum != num)
11025 printf("Renumber BB%02u to BB%02u\n", block->bbNum, num);
11028 block->bbNum = num;
11031 if (block->bbNext == nullptr)
11034 fgBBcount = num - numStart + 1;
11035 if (compIsForInlining())
11037 if (impInlineInfo->InlinerCompiler->fgBBNumMax != num)
11039 impInlineInfo->InlinerCompiler->fgBBNumMax = num;
11040 newMaxBBNum = true;
11045 if (fgBBNumMax != num)
11048 newMaxBBNum = true;
11057 printf("\n*************** After renumbering the basic blocks\n");
11060 fgDispBasicBlocks();
11061 fgDispHandlerTab();
11065 printf("=============== No blocks renumbered!\n");
11070 // Now update the BlockSet epoch, which depends on the block numbers.
11071 // If any blocks have been renumbered then create a new BlockSet epoch.
11072 // Even if we have not renumbered any blocks, we might still need to force
11073 // a new BlockSet epoch, for one of several reasons. If there are any new
11074 // blocks with higher numbers than the former maximum numbered block, then we
11075 // need a new epoch with a new size matching the new largest numbered block.
11076 // Also, if the number of blocks is different from the last time we set the
11077 // BlockSet epoch, then we need a new epoch. This wouldn't happen if we
11078 // renumbered blocks after every block addition/deletion, but it might be
11079 // the case that we can change the number of blocks, then set the BlockSet
11080 // epoch without renumbering, then change the number of blocks again, then
11082 if (renumbered || newMaxBBNum)
11084 NewBasicBlockEpoch();
11086 // The key in the unique switch successor map is dependent on the block number, so invalidate that cache.
11087 InvalidateUniqueSwitchSuccMap();
11091 EnsureBasicBlockEpoch();
11094 // Tell our caller if any blocks actually were renumbered.
11095 return renumbered || newMaxBBNum;
11098 /*****************************************************************************
11100 * Is the BasicBlock bJump a forward branch?
11101 * Optionally bSrc can be supplied to indicate that
11102 * bJump must be forward with respect to bSrc
11104 bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc /* = NULL */)
11106 bool result = false;
11108 if ((bJump->bbJumpKind == BBJ_COND) || (bJump->bbJumpKind == BBJ_ALWAYS))
11110 BasicBlock* bDest = bJump->bbJumpDest;
11111 BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc;
11115 bTemp = bTemp->bbNext;
11117 if (bTemp == nullptr)
11122 if (bTemp == bDest)
11133 /*****************************************************************************
11135 * Function called to expand the set of rarely run blocks
11138 bool Compiler::fgExpandRarelyRunBlocks()
11140 bool result = false;
11145 printf("\n*************** In fgExpandRarelyRunBlocks()\n");
11148 const char* reason = nullptr;
11151 // We expand the number of rarely run blocks by observing
11152 // that a block that falls into or jumps to a rarely run block,
11153 // must itself be rarely run and when we have a conditional
11154 // jump in which both branches go to rarely run blocks then
11155 // the block must itself be rarely run
11160 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
11162 if (bPrev->isRunRarely())
11167 /* bPrev is known to be a normal block here */
11168 switch (bPrev->bbJumpKind)
11172 /* Is the jump target rarely run? */
11173 if (bPrev->bbJumpDest->isRunRarely())
11175 INDEBUG(reason = "Unconditional jump to a rarely run block";)
11176 goto NEW_RARELY_RUN;
11180 case BBJ_CALLFINALLY:
11182 // Check for a BBJ_CALLFINALLY followed by a rarely run paired BBJ_ALWAYS
11184 if (bPrev->isBBCallAlwaysPair())
11186 /* Is the next block rarely run? */
11187 if (block->isRunRarely())
11189 INDEBUG(reason = "Call of finally followed by a rarely run block";)
11190 goto NEW_RARELY_RUN;
11197 /* is fall through target rarely run? */
11198 if (block->isRunRarely())
11200 INDEBUG(reason = "Falling into a rarely run block";)
11201 goto NEW_RARELY_RUN;
11207 if (!block->isRunRarely())
11212 /* If both targets of the BBJ_COND are run rarely then don't reorder */
11213 if (bPrev->bbJumpDest->isRunRarely())
11215 /* bPrev should also be marked as run rarely */
11216 if (!bPrev->isRunRarely())
11218 INDEBUG(reason = "Both sides of a conditional jump are rarely run";)
11221 /* If the weight of the block was obtained from a profile run,
11222 than it's more accurate than our static analysis */
11223 if (bPrev->hasProfileWeight())
11230 assert(reason != nullptr);
11233 printf("%s, marking BB%02u as rarely run\n", reason, bPrev->bbNum);
11237 /* Must not have previously been marked */
11238 noway_assert(!bPrev->isRunRarely());
11240 /* Mark bPrev as a new rarely run block */
11241 bPrev->bbSetRunRarely();
11243 BasicBlock* bPrevPrev = nullptr;
11246 if ((bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
11248 // If we've got a BBJ_CALLFINALLY/BBJ_ALWAYS pair, treat the BBJ_CALLFINALLY as an
11249 // additional predecessor for the BBJ_ALWAYS block
11250 tmpbb = bPrev->bbPrev;
11251 noway_assert(tmpbb != nullptr);
11252 #if FEATURE_EH_FUNCLETS
11253 noway_assert(tmpbb->isBBCallAlwaysPair());
11256 if (tmpbb->bbJumpKind == BBJ_CALLFINALLY)
11263 /* Now go back to it's earliest predecessor to see */
11264 /* if it too should now be marked as rarely run */
11265 flowList* pred = bPrev->bbPreds;
11267 if ((pred != nullptr) || (bPrevPrev != nullptr))
11269 // bPrevPrev will be set to the lexically
11270 // earliest predecessor of bPrev.
11272 while (pred != nullptr)
11274 if (bPrevPrev == nullptr)
11276 // Initially we select the first block in the bbPreds list
11277 bPrevPrev = pred->flBlock;
11281 // Walk the flow graph lexically forward from pred->flBlock
11282 // if we find (block == bPrevPrev) then
11283 // pred->flBlock is an earlier predecessor.
11284 for (tmpbb = pred->flBlock; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11286 if (tmpbb == bPrevPrev)
11288 /* We found an ealier predecessor */
11289 bPrevPrev = pred->flBlock;
11292 else if (tmpbb == bPrev)
11294 // We have reached bPrev so stop walking
11295 // as this cannot be an earlier predecessor
11300 // Onto the next predecessor
11301 pred = pred->flNext;
11304 // Walk the flow graph forward from bPrevPrev
11305 // if we don't find (tmpbb == bPrev) then our candidate
11306 // bPrevPrev is lexically after bPrev and we do not
11307 // want to select it as our new block
11309 for (tmpbb = bPrevPrev; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11311 if (tmpbb == bPrev)
11313 // Set up block back to the lexically
11314 // earliest predecessor of pPrev
11329 // Now iterate over every block to see if we can prove that a block is rarely run
11330 // (i.e. when all predecessors to the block are rarely run)
11332 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
11334 // If block is not run rarely, then check to make sure that it has
11335 // at least one non-rarely run block.
11337 if (!block->isRunRarely())
11341 /* Make sure that block has at least one normal predecessor */
11342 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
11344 /* Find the fall through predecessor, if any */
11345 if (!pred->flBlock->isRunRarely())
11354 // If 'block' is the start of a handler or filter then we cannot make it
11355 // rarely run because we may have an exceptional edge that
11358 if (bbIsHandlerBeg(block))
11366 block->bbSetRunRarely();
11372 printf("All branches to BB%02u are from rarely run blocks, marking as rarely run\n", block->bbNum);
11376 // When marking a BBJ_CALLFINALLY as rarely run we also mark
11377 // the BBJ_ALWAYS that comes after it as rarely run
11379 if (block->isBBCallAlwaysPair())
11381 BasicBlock* bNext = block->bbNext;
11382 PREFIX_ASSUME(bNext != nullptr);
11383 bNext->bbSetRunRarely();
11387 printf("Also marking the BBJ_ALWAYS at BB%02u as rarely run\n", bNext->bbNum);
11394 /* COMPACT blocks if possible */
11395 if (bPrev->bbJumpKind == BBJ_NONE)
11397 if (fgCanCompactBlocks(bPrev, block))
11399 fgCompactBlocks(bPrev, block);
11406 // if bPrev->bbWeight is not based upon profile data we can adjust
11407 // the weights of bPrev and block
11409 else if (bPrev->isBBCallAlwaysPair() && // we must have a BBJ_CALLFINALLY and BBK_ALWAYS pair
11410 (bPrev->bbWeight != block->bbWeight) && // the weights are currently different
11411 !bPrev->hasProfileWeight()) // and the BBJ_CALLFINALLY block is not using profiled
11414 if (block->isRunRarely())
11417 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11418 bPrev->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11422 printf("Marking the BBJ_CALLFINALLY block at BB%02u as rarely run because BB%02u is rarely run\n",
11423 bPrev->bbNum, block->bbNum);
11427 else if (bPrev->isRunRarely())
11430 bPrev->bbWeight; // the BBJ_ALWAYS block now has the same weight as the BBJ_CALLFINALLY block
11431 block->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11435 printf("Marking the BBJ_ALWAYS block at BB%02u as rarely run because BB%02u is rarely run\n",
11436 block->bbNum, bPrev->bbNum);
11440 else // Both blocks are hot, bPrev is known not to be using profiled weight
11443 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11445 noway_assert(block->bbWeight == bPrev->bbWeight);
11452 /*****************************************************************************
11454 * Returns true if it is allowable (based upon the EH regions)
11455 * to place block bAfter immediately after bBefore. It is allowable
11456 * if the 'bBefore' and 'bAfter' blocks are in the exact same EH region.
11459 bool Compiler::fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter)
11461 return BasicBlock::sameEHRegion(bBefore, bAfter);
11464 /*****************************************************************************
11466 * Function called to move the range of blocks [bStart .. bEnd].
11467 * The blocks are placed immediately after the insertAfterBlk.
11468 * fgFirstFuncletBB is not updated; that is the responsibility of the caller, if necessary.
11471 void Compiler::fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk)
11473 /* We have decided to insert the block(s) after 'insertAfterBlk' */
11474 CLANG_FORMAT_COMMENT_ANCHOR;
11479 printf("Relocated block%s [BB%02u..BB%02u] inserted after BB%02u%s\n", (bStart == bEnd) ? "" : "s",
11480 bStart->bbNum, bEnd->bbNum, insertAfterBlk->bbNum,
11481 (insertAfterBlk->bbNext == nullptr) ? " at the end of method" : "");
11485 /* relink [bStart .. bEnd] into the flow graph */
11487 bEnd->bbNext = insertAfterBlk->bbNext;
11488 if (insertAfterBlk->bbNext)
11490 insertAfterBlk->bbNext->bbPrev = bEnd;
11492 insertAfterBlk->setNext(bStart);
11494 /* If insertAfterBlk was fgLastBB then update fgLastBB */
11495 if (insertAfterBlk == fgLastBB)
11498 noway_assert(fgLastBB->bbNext == nullptr);
11502 /*****************************************************************************
11504 * Function called to relocate a single range to the end of the method.
11505 * Only an entire consecutive region can be moved and it will be kept together.
11506 * Except for the first block, the range cannot have any blocks that jump into or out of the region.
11507 * When successful we return the bLast block which is the last block that we relocated.
11508 * When unsuccessful we return NULL.
11510 =============================================================
11511 NOTE: This function can invalidate all pointers into the EH table, as well as change the size of the EH table!
11512 =============================================================
11515 BasicBlock* Compiler::fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType)
11517 INDEBUG(const char* reason = "None";)
11519 // Figure out the range of blocks we're going to move
11523 BasicBlock* bStart = nullptr;
11524 BasicBlock* bMiddle = nullptr;
11525 BasicBlock* bLast = nullptr;
11526 BasicBlock* bPrev = nullptr;
11528 #if FEATURE_EH_FUNCLETS
11529 // We don't support moving try regions... yet?
11530 noway_assert(relocateType == FG_RELOCATE_HANDLER);
11531 #endif // FEATURE_EH_FUNCLETS
11533 HBtab = ehGetDsc(regionIndex);
11535 if (relocateType == FG_RELOCATE_TRY)
11537 bStart = HBtab->ebdTryBeg;
11538 bLast = HBtab->ebdTryLast;
11540 else if (relocateType == FG_RELOCATE_HANDLER)
11542 if (HBtab->HasFilter())
11544 // The filter and handler funclets must be moved together, and remain contiguous.
11545 bStart = HBtab->ebdFilter;
11546 bMiddle = HBtab->ebdHndBeg;
11547 bLast = HBtab->ebdHndLast;
11551 bStart = HBtab->ebdHndBeg;
11552 bLast = HBtab->ebdHndLast;
11556 // Our range must contain either all rarely run blocks or all non-rarely run blocks
11557 bool inTheRange = false;
11558 bool validRange = false;
11562 noway_assert(bStart != nullptr && bLast != nullptr);
11563 if (bStart == fgFirstBB)
11565 INDEBUG(reason = "can not relocate first block";)
11569 #if !FEATURE_EH_FUNCLETS
11570 // In the funclets case, we still need to set some information on the handler blocks
11571 if (bLast->bbNext == NULL)
11573 INDEBUG(reason = "region is already at the end of the method";)
11576 #endif // !FEATURE_EH_FUNCLETS
11578 // Walk the block list for this purpose:
11579 // 1. Verify that all the blocks in the range are either all rarely run or not rarely run.
11580 // When creating funclets, we ignore the run rarely flag, as we need to be able to move any blocks
11582 CLANG_FORMAT_COMMENT_ANCHOR;
11584 #if !FEATURE_EH_FUNCLETS
11586 isRare = bStart->isRunRarely();
11587 #endif // !FEATURE_EH_FUNCLETS
11591 if (block == bStart)
11593 noway_assert(inTheRange == false);
11596 else if (block == bLast->bbNext)
11598 noway_assert(inTheRange == true);
11599 inTheRange = false;
11600 break; // we found the end, so we're done
11605 #if !FEATURE_EH_FUNCLETS
11606 // Unless all blocks are (not) run rarely we must return false.
11607 if (isRare != block->isRunRarely())
11609 INDEBUG(reason = "this region contains both rarely run and non-rarely run blocks";)
11612 #endif // !FEATURE_EH_FUNCLETS
11617 if (block == nullptr)
11622 block = block->bbNext;
11624 // Ensure that bStart .. bLast defined a valid range
11625 noway_assert((validRange == true) && (inTheRange == false));
11627 bPrev = bStart->bbPrev;
11628 noway_assert(bPrev != nullptr); // Can't move a range that includes the first block of the function.
11630 JITDUMP("Relocating %s range BB%02u..BB%02u (EH#%u) to end of BBlist\n",
11631 (relocateType == FG_RELOCATE_TRY) ? "try" : "handler", bStart->bbNum, bLast->bbNum, regionIndex);
11636 fgDispBasicBlocks();
11637 fgDispHandlerTab();
11640 if (!FEATURE_EH_FUNCLETS)
11642 // This is really expensive, and quickly becomes O(n^n) with funclets
11643 // so only do it once after we've created them (see fgCreateFunclets)
11644 if (expensiveDebugCheckLevel >= 2)
11646 fgDebugCheckBBlist();
11651 #if FEATURE_EH_FUNCLETS
11653 bStart->bbFlags |= BBF_FUNCLET_BEG; // Mark the start block of the funclet
11655 if (bMiddle != nullptr)
11657 bMiddle->bbFlags |= BBF_FUNCLET_BEG; // Also mark the start block of a filter handler as a funclet
11660 #endif // FEATURE_EH_FUNCLETS
11663 bNext = bLast->bbNext;
11665 /* Temporarily unlink [bStart .. bLast] from the flow graph */
11666 fgUnlinkRange(bStart, bLast);
11668 BasicBlock* insertAfterBlk;
11669 insertAfterBlk = fgLastBB;
11671 #if FEATURE_EH_FUNCLETS
11673 // There are several cases we need to consider when moving an EH range.
11674 // If moving a range X, we must consider its relationship to every other EH
11675 // range A in the table. Note that each entry in the table represents both
11676 // a protected region and a handler region (possibly including a filter region
11677 // that must live before and adjacent to the handler region), so we must
11678 // consider try and handler regions independently. These are the cases:
11679 // 1. A is completely contained within X (where "completely contained" means
11680 // that the 'begin' and 'last' parts of A are strictly between the 'begin'
11681 // and 'end' parts of X, and aren't equal to either, for example, they don't
11682 // share 'last' blocks). In this case, when we move X, A moves with it, and
11683 // the EH table doesn't need to change.
11684 // 2. X is completely contained within A. In this case, X gets extracted from A,
11685 // and the range of A shrinks, but because A is strictly within X, the EH
11686 // table doesn't need to change.
11687 // 3. A and X have exactly the same range. In this case, A is moving with X and
11688 // the EH table doesn't need to change.
11689 // 4. A and X share the 'last' block. There are two sub-cases:
11690 // (a) A is a larger range than X (such that the beginning of A precedes the
11691 // beginning of X): in this case, we are moving the tail of A. We set the
11692 // 'last' block of A to the the block preceding the beginning block of X.
11693 // (b) A is a smaller range than X. Thus, we are moving the entirety of A along
11694 // with X. In this case, nothing in the EH record for A needs to change.
11695 // 5. A and X share the 'beginning' block (but aren't the same range, as in #3).
11696 // This can never happen here, because we are only moving handler ranges (we don't
11697 // move try ranges), and handler regions cannot start at the beginning of a try
11698 // range or handler range and be a subset.
11700 // Note that A and X must properly nest for the table to be well-formed. For example,
11701 // the beginning of A can't be strictly within the range of X (that is, the beginning
11702 // of A isn't shared with the beginning of X) and the end of A outside the range.
11704 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
11706 if (XTnum != regionIndex) // we don't need to update our 'last' pointer
11708 if (HBtab->ebdTryLast == bLast)
11710 // If we moved a set of blocks that were at the end of
11711 // a different try region then we may need to update ebdTryLast
11712 for (block = HBtab->ebdTryBeg; block != nullptr; block = block->bbNext)
11714 if (block == bPrev)
11716 // We were contained within it, so shrink its region by
11717 // setting its 'last'
11718 fgSetTryEnd(HBtab, bPrev);
11721 else if (block == HBtab->ebdTryLast->bbNext)
11723 // bPrev does not come after the TryBeg, thus we are larger, and
11724 // it is moving with us.
11729 if (HBtab->ebdHndLast == bLast)
11731 // If we moved a set of blocks that were at the end of
11732 // a different handler region then we must update ebdHndLast
11733 for (block = HBtab->ebdHndBeg; block != nullptr; block = block->bbNext)
11735 if (block == bPrev)
11737 fgSetHndEnd(HBtab, bPrev);
11740 else if (block == HBtab->ebdHndLast->bbNext)
11742 // bPrev does not come after the HndBeg
11748 } // end exception table iteration
11750 // Insert the block(s) we are moving after fgLastBlock
11751 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
11753 if (fgFirstFuncletBB == nullptr) // The funclet region isn't set yet
11755 fgFirstFuncletBB = bStart;
11759 assert(fgFirstFuncletBB !=
11760 insertAfterBlk->bbNext); // We insert at the end, not at the beginning, of the funclet region.
11763 // These asserts assume we aren't moving try regions (which we might need to do). Only
11764 // try regions can have fall through into or out of the region.
11766 noway_assert(!bPrev->bbFallsThrough()); // There can be no fall through into a filter or handler region
11767 noway_assert(!bLast->bbFallsThrough()); // There can be no fall through out of a handler region
11772 printf("Create funclets: moved region\n");
11773 fgDispHandlerTab();
11776 // We have to wait to do this until we've created all the additional regions
11777 // Because this relies on ebdEnclosingTryIndex and ebdEnclosingHndIndex
11778 if (!FEATURE_EH_FUNCLETS)
11780 // This is really expensive, and quickly becomes O(n^n) with funclets
11781 // so only do it once after we've created them (see fgCreateFunclets)
11782 if (expensiveDebugCheckLevel >= 2)
11784 fgDebugCheckBBlist();
11789 #else // FEATURE_EH_FUNCLETS
11791 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
11793 if (XTnum == regionIndex)
11795 // Don't update our handler's Last info
11799 if (HBtab->ebdTryLast == bLast)
11801 // If we moved a set of blocks that were at the end of
11802 // a different try region then we may need to update ebdTryLast
11803 for (block = HBtab->ebdTryBeg; block != NULL; block = block->bbNext)
11805 if (block == bPrev)
11807 fgSetTryEnd(HBtab, bPrev);
11810 else if (block == HBtab->ebdTryLast->bbNext)
11812 // bPrev does not come after the TryBeg
11817 if (HBtab->ebdHndLast == bLast)
11819 // If we moved a set of blocks that were at the end of
11820 // a different handler region then we must update ebdHndLast
11821 for (block = HBtab->ebdHndBeg; block != NULL; block = block->bbNext)
11823 if (block == bPrev)
11825 fgSetHndEnd(HBtab, bPrev);
11828 else if (block == HBtab->ebdHndLast->bbNext)
11830 // bPrev does not come after the HndBeg
11835 } // end exception table iteration
11837 // We have decided to insert the block(s) after fgLastBlock
11838 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
11840 // If bPrev falls through, we will insert a jump to block
11841 fgConnectFallThrough(bPrev, bStart);
11843 // If bLast falls through, we will insert a jump to bNext
11844 fgConnectFallThrough(bLast, bNext);
11846 #endif // FEATURE_EH_FUNCLETS
11855 printf("*************** Failed fgRelocateEHRange(BB%02u..BB%02u) because %s\n", bStart->bbNum, bLast->bbNum,
11867 #if FEATURE_EH_FUNCLETS
11869 #if defined(_TARGET_ARM_)
11871 /*****************************************************************************
11872 * We just removed a BBJ_CALLFINALLY/BBJ_ALWAYS pair. If this was the only such pair
11873 * targeting the BBJ_ALWAYS target, then we need to clear the BBF_FINALLY_TARGET bit
11874 * so that target can also be removed. 'block' is the finally target. Since we just
11875 * removed the BBJ_ALWAYS, it better have the BBF_FINALLY_TARGET bit set.
11878 void Compiler::fgClearFinallyTargetBit(BasicBlock* block)
11880 assert(fgComputePredsDone);
11881 assert((block->bbFlags & BBF_FINALLY_TARGET) != 0);
11883 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
11885 if (pred->flBlock->bbJumpKind == BBJ_ALWAYS && pred->flBlock->bbJumpDest == block)
11887 BasicBlock* pPrev = pred->flBlock->bbPrev;
11890 if (pPrev->bbJumpKind == BBJ_CALLFINALLY)
11892 // We found a BBJ_CALLFINALLY / BBJ_ALWAYS that still points to this finally target
11899 // Didn't find any BBJ_CALLFINALLY / BBJ_ALWAYS that still points here, so clear the bit
11901 block->bbFlags &= ~BBF_FINALLY_TARGET;
11904 #endif // defined(_TARGET_ARM_)
11906 /*****************************************************************************
11907 * Is this an intra-handler control flow edge?
11909 * 'block' is the head block of a funclet/handler region, or .
11910 * 'predBlock' is a predecessor block of 'block' in the predecessor list.
11912 * 'predBlock' can legally only be one of three things:
11913 * 1. in the same handler region (e.g., the source of a back-edge of a loop from
11914 * 'predBlock' to 'block'), including in nested regions within the handler,
11915 * 2. if 'block' begins a handler that is a filter-handler, 'predBlock' must be in the 'filter' region,
11916 * 3. for other handlers, 'predBlock' must be in the 'try' region corresponding to handler (or any
11917 * region nested in the 'try' region).
11919 * Note that on AMD64/ARM64, the BBJ_CALLFINALLY block that calls a finally handler is not
11920 * within the corresponding 'try' region: it is placed in the corresponding 'try' region's
11921 * parent (which might be the main function body). This is how it is represented to the VM
11922 * (with a special "cloned finally" EH table entry).
11924 * Return 'true' for case #1, and 'false' otherwise.
11926 bool Compiler::fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block)
11928 // Some simple preconditions (as stated above)
11929 assert(!fgFuncletsCreated);
11930 assert(fgGetPredForBlock(block, predBlock) != nullptr);
11931 assert(block->hasHndIndex());
11933 EHblkDsc* xtab = ehGetDsc(block->getHndIndex());
11935 #if FEATURE_EH_CALLFINALLY_THUNKS
11936 if (xtab->HasFinallyHandler())
11938 assert((xtab->ebdHndBeg == block) || // The normal case
11939 ((xtab->ebdHndBeg->bbNext == block) &&
11940 (xtab->ebdHndBeg->bbFlags & BBF_INTERNAL))); // After we've already inserted a header block, and we're
11941 // trying to decide how to split up the predecessor edges.
11942 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
11944 assert(predBlock->bbJumpDest == block);
11946 // A BBJ_CALLFINALLY predecessor of the handler can only come from the corresponding try,
11947 // not from any EH clauses nested in this handler. However, we represent the BBJ_CALLFINALLY
11948 // as being in the 'try' region's parent EH region, which might be the main function body.
11950 unsigned tryIndex = xtab->ebdEnclosingTryIndex;
11951 if (tryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
11953 assert(!predBlock->hasTryIndex());
11957 assert(predBlock->hasTryIndex());
11958 assert(tryIndex == predBlock->getTryIndex());
11959 assert(ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
11964 #endif // FEATURE_EH_CALLFINALLY_THUNKS
11966 assert(predBlock->hasHndIndex() || predBlock->hasTryIndex());
11968 // We could search the try region looking for predBlock by using bbInTryRegions
11969 // but that does a lexical search for the block, and then assumes funclets
11970 // have been created and does a lexical search of all funclets that were pulled
11971 // out of the parent try region.
11972 // First, funclets haven't been created yet, and even if they had been, we shouldn't
11973 // have any funclet directly branching to another funclet (they have to return first).
11974 // So we can safely use CheckIsTryRegion instead of bbInTryRegions.
11975 // Second, I believe the depth of any EH graph will on average be smaller than the
11976 // breadth of the blocks within a try body. Thus it is faster to get our answer by
11977 // looping outward over the region graph. However, I have added asserts, as a
11978 // precaution, to ensure both algorithms agree. The asserts also check that the only
11979 // way to reach the head of a funclet is from the corresponding try body or from
11980 // within the funclet (and *not* any nested funclets).
11982 if (predBlock->hasTryIndex())
11984 // Because the EH clauses are listed inside-out, any nested trys will be at a
11985 // lower index than the current try and if there's no enclosing try, tryIndex
11986 // will terminate at NO_ENCLOSING_INDEX
11988 unsigned tryIndex = predBlock->getTryIndex();
11989 while (tryIndex < block->getHndIndex())
11991 tryIndex = ehGetEnclosingTryIndex(tryIndex);
11993 // tryIndex should enclose predBlock
11994 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
11996 // At this point tryIndex is either block's handler's corresponding try body
11997 // or some outer try region that contains both predBlock & block or
11998 // NO_ENCLOSING_REGION (because there was no try body that encloses both).
11999 if (tryIndex == block->getHndIndex())
12001 assert(xtab->InTryRegionBBRange(predBlock));
12002 assert(!xtab->InHndRegionBBRange(predBlock));
12005 // tryIndex should enclose block (and predBlock as previously asserted)
12006 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(block));
12008 if (xtab->HasFilter())
12010 // The block is a handler. Check if the pred block is from its filter. We only need to
12011 // check the end filter flag, as there is only a single filter for any handler, and we
12012 // already know predBlock is a predecessor of block.
12013 if (predBlock->bbJumpKind == BBJ_EHFILTERRET)
12015 assert(!xtab->InHndRegionBBRange(predBlock));
12019 // It is not in our try region (or filter), so it must be within this handler (or try bodies
12020 // within this handler)
12021 assert(!xtab->InTryRegionBBRange(predBlock));
12022 assert(xtab->InHndRegionBBRange(predBlock));
12026 /*****************************************************************************
12027 * Does this block, first block of a handler region, have any predecessor edges
12028 * that are not from its corresponding try region?
12031 bool Compiler::fgAnyIntraHandlerPreds(BasicBlock* block)
12033 assert(block->hasHndIndex());
12034 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
12038 for (pred = block->bbPreds; pred; pred = pred->flNext)
12040 BasicBlock* predBlock = pred->flBlock;
12042 if (fgIsIntraHandlerPred(predBlock, block))
12044 // We have a predecessor that is not from our try region
12052 /*****************************************************************************
12053 * Introduce a new head block of the handler for the prolog to be put in, ahead
12054 * of the current handler head 'block'.
12055 * Note that this code has some similarities to fgCreateLoopPreHeader().
12058 void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block)
12063 printf("\nCreating funclet prolog header for BB%02u\n", block->bbNum);
12067 assert(block->hasHndIndex());
12068 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
12070 /* Allocate a new basic block */
12072 BasicBlock* newHead = bbNewBasicBlock(BBJ_NONE);
12074 // In fgComputePreds() we set the BBF_JMP_TARGET and BBF_HAS_LABEL for all of the handler entry points
12076 newHead->bbFlags |= (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL);
12077 newHead->inheritWeight(block);
12078 newHead->bbRefs = 0;
12080 fgInsertBBbefore(block, newHead); // insert the new block in the block list
12081 fgExtendEHRegionBefore(block); // Update the EH table to make the prolog block the first block in the block's EH
12084 // fgExtendEHRegionBefore mucks with the bbRefs without updating the pred list, which we will
12085 // do below for this block. So, undo that change.
12086 assert(newHead->bbRefs > 0);
12090 // Distribute the pred list between newHead and block. Incoming edges coming from outside
12091 // the handler go to the prolog. Edges coming from with the handler are back-edges, and
12092 // go to the existing 'block'.
12094 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
12096 BasicBlock* predBlock = pred->flBlock;
12097 if (!fgIsIntraHandlerPred(predBlock, block))
12099 // It's a jump from outside the handler; add it to the newHead preds list and remove
12100 // it from the block preds list.
12102 switch (predBlock->bbJumpKind)
12104 case BBJ_CALLFINALLY:
12105 noway_assert(predBlock->bbJumpDest == block);
12106 predBlock->bbJumpDest = newHead;
12107 fgRemoveRefPred(block, predBlock);
12108 fgAddRefPred(newHead, predBlock);
12112 // The only way into the handler is via a BBJ_CALLFINALLY (to a finally handler), or
12113 // via exception handling.
12114 noway_assert(false);
12120 assert(nullptr == fgGetPredForBlock(block, newHead));
12121 fgAddRefPred(block, newHead);
12123 assert((newHead->bbFlags & (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL)) ==
12124 (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL));
12127 /*****************************************************************************
12129 * Every funclet will have a prolog. That prolog will be inserted as the first instructions
12130 * in the first block of the funclet. If the prolog is also the head block of a loop, we
12131 * would end up with the prolog instructions being executed more than once.
12132 * Check for this by searching the predecessor list for loops, and create a new prolog header
12133 * block when needed. We detect a loop by looking for any predecessor that isn't in the
12134 * handler's try region, since the only way to get into a handler is via that try region.
12137 void Compiler::fgCreateFuncletPrologBlocks()
12139 noway_assert(fgComputePredsDone);
12140 noway_assert(!fgDomsComputed); // this function doesn't maintain the dom sets
12141 assert(!fgFuncletsCreated);
12143 bool prologBlocksCreated = false;
12144 EHblkDsc* HBtabEnd;
12147 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
12149 BasicBlock* head = HBtab->ebdHndBeg;
12151 if (fgAnyIntraHandlerPreds(head))
12153 // We need to create a new block in which to place the prolog, and split the existing
12154 // head block predecessor edges into those that should point to the prolog, and those
12157 // It's arguable that we should just always do this, and not only when we "need to",
12158 // so there aren't two different code paths. However, it's unlikely to be necessary
12159 // for catch handlers because they have an incoming argument (the exception object)
12160 // that needs to get stored or saved, so back-arcs won't normally go to the head. It's
12161 // possible when writing in IL to generate a legal loop (e.g., push an Exception object
12162 // on the stack before jumping back to the catch head), but C# probably won't. This will
12163 // most commonly only be needed for finallys with a do/while loop at the top of the
12166 // Note that we don't check filters. This might be a bug, but filters always have a filter
12167 // object live on entry, so it's at least unlikely (illegal?) that a loop edge targets the
12170 fgInsertFuncletPrologBlock(head);
12171 prologBlocksCreated = true;
12175 if (prologBlocksCreated)
12177 // If we've modified the graph, reset the 'modified' flag, since the dominators haven't
12179 fgModified = false;
12184 JITDUMP("\nAfter fgCreateFuncletPrologBlocks()");
12185 fgDispBasicBlocks();
12186 fgDispHandlerTab();
12189 fgVerifyHandlerTab();
12190 fgDebugCheckBBlist();
12195 /*****************************************************************************
12197 * Function to create funclets out of all EH catch/finally/fault blocks.
12198 * We only move filter and handler blocks, not try blocks.
12201 void Compiler::fgCreateFunclets()
12203 assert(!fgFuncletsCreated);
12208 printf("*************** In fgCreateFunclets()\n");
12212 fgCreateFuncletPrologBlocks();
12216 const unsigned int funcCnt = ehFuncletCount() + 1;
12218 if (!FitsIn<unsigned short>(funcCnt))
12220 IMPL_LIMITATION("Too many funclets");
12223 FuncInfoDsc* funcInfo = new (this, CMK_BasicBlock) FuncInfoDsc[funcCnt];
12225 unsigned short funcIdx;
12227 // Setup the root FuncInfoDsc and prepare to start associating
12228 // FuncInfoDsc's with their corresponding EH region
12229 memset((void*)funcInfo, 0, funcCnt * sizeof(FuncInfoDsc));
12230 assert(funcInfo[0].funKind == FUNC_ROOT);
12233 // Because we iterate from the top to the bottom of the compHndBBtab array, we are iterating
12234 // from most nested (innermost) to least nested (outermost) EH region. It would be reasonable
12235 // to iterate in the opposite order, but the order of funclets shouldn't matter.
12237 // We move every handler region to the end of the function: each handler will become a funclet.
12239 // Note that fgRelocateEHRange() can add new entries to the EH table. However, they will always
12240 // be added *after* the current index, so our iteration here is not invalidated.
12241 // It *can* invalidate the compHndBBtab pointer itself, though, if it gets reallocated!
12243 for (XTnum = 0; XTnum < compHndBBtabCount; XTnum++)
12245 HBtab = ehGetDsc(XTnum); // must re-compute this every loop, since fgRelocateEHRange changes the table
12246 if (HBtab->HasFilter())
12248 assert(funcIdx < funcCnt);
12249 funcInfo[funcIdx].funKind = FUNC_FILTER;
12250 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12253 assert(funcIdx < funcCnt);
12254 funcInfo[funcIdx].funKind = FUNC_HANDLER;
12255 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12256 HBtab->ebdFuncIndex = funcIdx;
12258 fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12261 // We better have populated all of them by now
12262 assert(funcIdx == funcCnt);
12265 compCurrFuncIdx = 0;
12266 compFuncInfos = funcInfo;
12267 compFuncInfoCount = (unsigned short)funcCnt;
12269 fgFuncletsCreated = true;
12274 JITDUMP("\nAfter fgCreateFunclets()");
12275 fgDispBasicBlocks();
12276 fgDispHandlerTab();
12279 fgVerifyHandlerTab();
12280 fgDebugCheckBBlist();
12284 #else // !FEATURE_EH_FUNCLETS
12286 /*****************************************************************************
12288 * Function called to relocate any and all EH regions.
12289 * Only entire consecutive EH regions will be moved and they will be kept together.
12290 * Except for the first block, the range can not have any blocks that jump into or out of the region.
12293 bool Compiler::fgRelocateEHRegions()
12295 bool result = false; // Our return value
12299 printf("*************** In fgRelocateEHRegions()\n");
12302 if (fgCanRelocateEHRegions)
12307 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
12309 // Nested EH regions cannot be moved.
12310 // Also we don't want to relocate an EH region that has a filter
12311 if ((HBtab->ebdHandlerNestingLevel == 0) && !HBtab->HasFilter())
12313 bool movedTry = false;
12315 bool movedHnd = false;
12318 // Only try to move the outermost try region
12319 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
12321 // Move the entire try region if it can be moved
12322 if (HBtab->ebdTryBeg->isRunRarely())
12324 BasicBlock* bTryLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_TRY);
12325 if (bTryLastBB != NULL)
12332 if (verbose && movedTry)
12334 printf("\nAfter relocating an EH try region");
12335 fgDispBasicBlocks();
12336 fgDispHandlerTab();
12338 // Make sure that the predecessor lists are accurate
12339 if (expensiveDebugCheckLevel >= 2)
12341 fgDebugCheckBBlist();
12347 // Currently it is not good to move the rarely run handler regions to the end of the method
12348 // because fgDetermineFirstColdBlock() must put the start of any handler region in the hot
12350 CLANG_FORMAT_COMMENT_ANCHOR;
12353 // Now try to move the entire handler region if it can be moved.
12354 // Don't try to move a finally handler unless we already moved the try region.
12355 if (HBtab->ebdHndBeg->isRunRarely() &&
12356 !HBtab->ebdHndBeg->hasTryIndex() &&
12357 (movedTry || !HBtab->HasFinallyHandler()))
12359 BasicBlock* bHndLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12360 if (bHndLastBB != NULL)
12369 if (verbose && movedHnd)
12371 printf("\nAfter relocating an EH handler region");
12372 fgDispBasicBlocks();
12373 fgDispHandlerTab();
12375 // Make sure that the predecessor lists are accurate
12376 if (expensiveDebugCheckLevel >= 2)
12378 fgDebugCheckBBlist();
12387 fgVerifyHandlerTab();
12389 if (verbose && result)
12391 printf("\nAfter fgRelocateEHRegions()");
12392 fgDispBasicBlocks();
12393 fgDispHandlerTab();
12394 // Make sure that the predecessor lists are accurate
12395 fgDebugCheckBBlist();
12402 #endif // !FEATURE_EH_FUNCLETS
12404 bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12406 bool result = false;
12407 if ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin))
12409 flEdgeWeightMin = newWeight;
12414 // We allow for a small amount of inaccuracy in block weight counts.
12415 if (flEdgeWeightMax < newWeight)
12417 // We have already determined that this edge's weight
12418 // is less than newWeight, so we just allow for the slop
12419 if (newWeight <= (flEdgeWeightMax + slop))
12423 if (flEdgeWeightMax != 0)
12425 // We will raise flEdgeWeightMin and Max towards newWeight
12426 flEdgeWeightMin = flEdgeWeightMax;
12427 flEdgeWeightMax = newWeight;
12430 if (wbUsedSlop != nullptr)
12432 *wbUsedSlop = true;
12438 assert(flEdgeWeightMin > newWeight);
12440 // We have already determined that this edge's weight
12441 // is more than newWeight, so we just allow for the slop
12442 if ((newWeight + slop) >= flEdgeWeightMin)
12446 assert(flEdgeWeightMax != 0);
12448 // We will lower flEdgeWeightMin towards newWeight
12449 flEdgeWeightMin = newWeight;
12451 if (wbUsedSlop != nullptr)
12453 *wbUsedSlop = true;
12458 // If we are returning true then we should have adjusted the range so that
12459 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero.
12460 // Also we should have set wbUsedSlop to true.
12461 if (result == true)
12463 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12465 if (wbUsedSlop != nullptr)
12467 assert(*wbUsedSlop == true);
12473 if (result == false)
12475 result = false; // break here
12482 bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12484 bool result = false;
12485 if ((newWeight >= flEdgeWeightMin) && (newWeight <= flEdgeWeightMax))
12487 flEdgeWeightMax = newWeight;
12492 // We allow for a small amount of inaccuracy in block weight counts.
12493 if (flEdgeWeightMax < newWeight)
12495 // We have already determined that this edge's weight
12496 // is less than newWeight, so we just allow for the slop
12497 if (newWeight <= (flEdgeWeightMax + slop))
12501 if (flEdgeWeightMax != 0)
12503 // We will allow this to raise flEdgeWeightMax towards newWeight
12504 flEdgeWeightMax = newWeight;
12507 if (wbUsedSlop != nullptr)
12509 *wbUsedSlop = true;
12515 assert(flEdgeWeightMin > newWeight);
12517 // We have already determined that this edge's weight
12518 // is more than newWeight, so we just allow for the slop
12519 if ((newWeight + slop) >= flEdgeWeightMin)
12523 assert(flEdgeWeightMax != 0);
12525 // We will allow this to lower flEdgeWeightMin and Max towards newWeight
12526 flEdgeWeightMax = flEdgeWeightMin;
12527 flEdgeWeightMin = newWeight;
12529 if (wbUsedSlop != nullptr)
12531 *wbUsedSlop = true;
12536 // If we are returning true then we should have adjusted the range so that
12537 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero
12538 // Also we should have set wbUsedSlop to true, unless it is NULL
12539 if (result == true)
12541 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12543 assert((wbUsedSlop == nullptr) || (*wbUsedSlop == true));
12548 if (result == false)
12550 result = false; // break here
12558 void Compiler::fgPrintEdgeWeights()
12564 // Print out all of the edge weights
12565 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12567 if (bDst->bbPreds != nullptr)
12569 printf(" Edge weights into BB%02u :", bDst->bbNum);
12570 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12572 bSrc = edge->flBlock;
12573 // This is the control flow edge (bSrc -> bDst)
12575 printf("BB%02u ", bSrc->bbNum);
12577 if (edge->flEdgeWeightMin < BB_MAX_WEIGHT)
12579 printf("(%u", edge->flEdgeWeightMin);
12585 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
12587 if (edge->flEdgeWeightMax < BB_MAX_WEIGHT)
12589 printf("..%u", edge->flEdgeWeightMax);
12597 if (edge->flNext != nullptr)
12608 // return true if there is a possibility that the method has a loop (a backedge is present)
12609 bool Compiler::fgMightHaveLoop()
12611 // Don't use a BlockSet for this temporary bitset of blocks: we don't want to have to call EnsureBasicBlockEpoch()
12612 // and potentially change the block epoch.
12614 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
12615 BitVec BLOCKSET_INIT_NOCOPY(blocksSeen, BitVecOps::MakeEmpty(&blockVecTraits));
12617 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
12619 BitVecOps::AddElemD(&blockVecTraits, blocksSeen, block->bbNum);
12621 AllSuccessorIter succsEnd = block->GetAllSuccs(this).end();
12622 for (AllSuccessorIter succs = block->GetAllSuccs(this).begin(); succs != succsEnd; ++succs)
12624 BasicBlock* succ = (*succs);
12625 if (BitVecOps::IsMember(&blockVecTraits, blocksSeen, succ->bbNum))
12634 void Compiler::fgComputeEdgeWeights()
12639 printf("*************** In fgComputeEdgeWeights()\n");
12643 if (fgIsUsingProfileWeights() == false)
12648 printf("fgComputeEdgeWeights() we do not have any profile data so we are not using the edge weights\n");
12651 fgHaveValidEdgeWeights = false;
12652 fgCalledCount = BB_UNITY_WEIGHT;
12658 fgDispBasicBlocks();
12666 unsigned iterations = 0;
12667 unsigned goodEdgeCountCurrent = 0;
12668 unsigned goodEdgeCountPrevious = 0;
12669 bool inconsistentProfileData = false;
12670 bool hasIncompleteEdgeWeights = false;
12671 unsigned numEdges = 0;
12672 bool usedSlop = false;
12676 BasicBlock::weight_t returnWeight;
12677 BasicBlock::weight_t slop;
12679 // If we have any blocks that did not have profile derived weight
12680 // we will try to fix their weight up here
12683 do // while (changed)
12689 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12691 if (!bDst->hasProfileWeight() && (bDst->bbPreds != nullptr))
12693 BasicBlock* bOnlyNext;
12695 // This block does not have a profile derived weight
12697 BasicBlock::weight_t newWeight = BB_MAX_WEIGHT;
12699 if (bDst->countOfInEdges() == 1)
12701 // Only one block flows into bDst
12702 bSrc = bDst->bbPreds->flBlock;
12704 // Does this block flow into only one other block
12705 if (bSrc->bbJumpKind == BBJ_NONE)
12707 bOnlyNext = bSrc->bbNext;
12709 else if (bSrc->bbJumpKind == BBJ_ALWAYS)
12711 bOnlyNext = bSrc->bbJumpDest;
12715 bOnlyNext = nullptr;
12718 if ((bOnlyNext == bDst) && bSrc->hasProfileWeight())
12720 // We know the exact weight of bDst
12721 newWeight = bSrc->bbWeight;
12725 // Does this block flow into only one other block
12726 if (bDst->bbJumpKind == BBJ_NONE)
12728 bOnlyNext = bDst->bbNext;
12730 else if (bDst->bbJumpKind == BBJ_ALWAYS)
12732 bOnlyNext = bDst->bbJumpDest;
12736 bOnlyNext = nullptr;
12739 if ((bOnlyNext != nullptr) && (bOnlyNext->bbPreds != nullptr))
12741 // Does only one block flow into bOnlyNext
12742 if (bOnlyNext->countOfInEdges() == 1)
12744 noway_assert(bOnlyNext->bbPreds->flBlock == bDst);
12746 // We know the exact weight of bDst
12747 newWeight = bOnlyNext->bbWeight;
12751 if ((newWeight != BB_MAX_WEIGHT) && (bDst->bbWeight != newWeight))
12755 bDst->bbWeight = newWeight;
12756 if (newWeight == 0)
12758 bDst->bbFlags |= BBF_RUN_RARELY;
12762 bDst->bbFlags &= ~BBF_RUN_RARELY;
12767 // Sum up the weights of all of the return blocks and throw blocks
12768 // This is used when we have a back-edge into block 1
12770 if (bDst->hasProfileWeight() && ((bDst->bbJumpKind == BBJ_RETURN) || (bDst->bbJumpKind == BBJ_THROW)))
12772 returnWeight += bDst->bbWeight;
12776 // Generally when we synthesize profile estimates we do it in a way where this algorithm will converge
12777 // but downstream opts that remove conditional branches may create a situation where this is not the case.
12778 // For instance a loop that becomes unreachable creates a sort of 'ring oscillator' (See test b539509)
12779 while (changed && iterations < 10);
12782 if (verbose && modified)
12784 printf("fgComputeEdgeWeights() adjusted the weight of some blocks\n");
12785 fgDispBasicBlocks();
12790 // When we are not using profile data we have already setup fgCalledCount
12791 // only set it here if we are using profile data
12793 if (fgIsUsingProfileWeights())
12795 BasicBlock* firstILBlock = fgFirstBB; // The first block for IL code (i.e. for the IL code at offset 0)
12797 // Do we have an internal block as our first Block?
12798 if (firstILBlock->bbFlags & BBF_INTERNAL)
12800 // Skip past any/all BBF_INTERNAL blocks that may have been added before the first real IL block.
12802 while (firstILBlock->bbFlags & BBF_INTERNAL)
12804 firstILBlock = firstILBlock->bbNext;
12806 // The 'firstILBlock' is now expected to have a profile-derived weight
12807 assert(firstILBlock->hasProfileWeight());
12810 // If the first block only has one ref then we use it's weight for fgCalledCount.
12811 // Otherwise we have backedge's into the first block, so instead we use the sum
12812 // of the return block weights for fgCalledCount.
12814 // If the profile data has a 0 for the returnWeight
12815 // (i.e. the function never returns because it always throws)
12816 // then just use the first block weight rather than 0.
12818 if ((firstILBlock->countOfInEdges() == 1) || (returnWeight == 0))
12820 assert(firstILBlock->hasProfileWeight()); // This should always be a profile-derived weight
12821 fgCalledCount = firstILBlock->bbWeight;
12825 fgCalledCount = returnWeight;
12828 // If we allocated a scratch block as the first BB then we need
12829 // to set its profile-derived weight to be fgCalledCount
12830 if (fgFirstBBisScratch())
12832 fgFirstBB->setBBProfileWeight(fgCalledCount);
12838 printf("We are using the Profile Weights and fgCalledCount is %d.\n", fgCalledCount);
12843 // Now we will compute the initial flEdgeWeightMin and flEdgeWeightMax values
12844 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12846 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
12848 // We subtract out the called count so that bDstWeight is
12849 // the sum of all edges that go into this block from this method.
12851 if (bDst == fgFirstBB)
12853 bDstWeight -= fgCalledCount;
12856 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12858 bool assignOK = true;
12860 bSrc = edge->flBlock;
12861 // We are processing the control flow edge (bSrc -> bDst)
12866 // If the bSrc or bDst blocks do not have exact profile weights
12867 // then we must reset any values that they currently have
12870 if (!bSrc->hasProfileWeight() || !bDst->hasProfileWeight())
12872 edge->flEdgeWeightMin = BB_ZERO_WEIGHT;
12873 edge->flEdgeWeightMax = BB_MAX_WEIGHT;
12876 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
12877 switch (bSrc->bbJumpKind)
12880 case BBJ_EHCATCHRET:
12882 case BBJ_CALLFINALLY:
12883 // We know the exact edge weight
12884 assignOK &= edge->setEdgeWeightMinChecked(bSrc->bbWeight, slop, &usedSlop);
12885 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
12890 case BBJ_EHFINALLYRET:
12891 case BBJ_EHFILTERRET:
12892 if (edge->flEdgeWeightMax > bSrc->bbWeight)
12894 // The maximum edge weight to block can't be greater than the weight of bSrc
12895 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
12900 // We should never have an edge that starts from one of these jump kinds
12901 noway_assert(!"Unexpected bbJumpKind");
12905 // The maximum edge weight to block can't be greater than the weight of bDst
12906 if (edge->flEdgeWeightMax > bDstWeight)
12908 assignOK &= edge->setEdgeWeightMaxChecked(bDstWeight, slop, &usedSlop);
12913 // Here we have inconsistent profile data
12914 inconsistentProfileData = true;
12915 // No point in continuing
12921 fgEdgeCount = numEdges;
12928 goodEdgeCountPrevious = goodEdgeCountCurrent;
12929 goodEdgeCountCurrent = 0;
12930 hasIncompleteEdgeWeights = false;
12932 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
12934 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
12936 bool assignOK = true;
12938 // We are processing the control flow edge (bSrc -> bDst)
12939 bSrc = edge->flBlock;
12941 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
12942 if (bSrc->bbJumpKind == BBJ_COND)
12945 flowList* otherEdge;
12946 if (bSrc->bbNext == bDst)
12948 otherEdge = fgGetPredForBlock(bSrc->bbJumpDest, bSrc);
12952 otherEdge = fgGetPredForBlock(bSrc->bbNext, bSrc);
12954 noway_assert(edge->flEdgeWeightMin <= edge->flEdgeWeightMax);
12955 noway_assert(otherEdge->flEdgeWeightMin <= otherEdge->flEdgeWeightMax);
12957 // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down
12958 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
12961 assignOK &= edge->setEdgeWeightMinChecked(edge->flEdgeWeightMin + diff, slop, &usedSlop);
12966 otherEdge->setEdgeWeightMaxChecked(otherEdge->flEdgeWeightMax + diff, slop, &usedSlop);
12969 // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down
12970 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
12974 otherEdge->setEdgeWeightMinChecked(otherEdge->flEdgeWeightMin + diff, slop, &usedSlop);
12978 assignOK &= edge->setEdgeWeightMaxChecked(edge->flEdgeWeightMax + diff, slop, &usedSlop);
12983 // Here we have inconsistent profile data
12984 inconsistentProfileData = true;
12985 // No point in continuing
12989 // Now edge->flEdgeWeightMin and otherEdge->flEdgeWeightMax) should add up to bSrc->bbWeight
12990 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
12991 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
12993 // Now otherEdge->flEdgeWeightMin and edge->flEdgeWeightMax) should add up to bSrc->bbWeight
12994 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
12995 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
13001 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13003 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
13005 if (bDstWeight == BB_MAX_WEIGHT)
13007 inconsistentProfileData = true;
13008 // No point in continuing
13013 // We subtract out the called count so that bDstWeight is
13014 // the sum of all edges that go into this block from this method.
13016 if (bDst == fgFirstBB)
13018 bDstWeight -= fgCalledCount;
13021 UINT64 minEdgeWeightSum = 0;
13022 UINT64 maxEdgeWeightSum = 0;
13024 // Calculate the sums of the minimum and maximum edge weights
13025 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13027 // We are processing the control flow edge (bSrc -> bDst)
13028 bSrc = edge->flBlock;
13030 maxEdgeWeightSum += edge->flEdgeWeightMax;
13031 minEdgeWeightSum += edge->flEdgeWeightMin;
13034 // maxEdgeWeightSum is the sum of all flEdgeWeightMax values into bDst
13035 // minEdgeWeightSum is the sum of all flEdgeWeightMin values into bDst
13037 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13039 bool assignOK = true;
13041 // We are processing the control flow edge (bSrc -> bDst)
13042 bSrc = edge->flBlock;
13043 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
13045 // otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values
13046 // This can be used to compute a lower bound for our minimum edge weight
13047 noway_assert(maxEdgeWeightSum >= edge->flEdgeWeightMax);
13048 UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->flEdgeWeightMax;
13050 // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values
13051 // This can be used to compute an upper bound for our maximum edge weight
13052 noway_assert(minEdgeWeightSum >= edge->flEdgeWeightMin);
13053 UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->flEdgeWeightMin;
13055 if (bDstWeight >= otherMaxEdgesWeightSum)
13057 // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax value
13058 BasicBlock::weight_t minWeightCalc =
13059 (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum);
13060 if (minWeightCalc > edge->flEdgeWeightMin)
13062 assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, slop, &usedSlop);
13066 if (bDstWeight >= otherMinEdgesWeightSum)
13068 // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin value
13069 BasicBlock::weight_t maxWeightCalc =
13070 (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum);
13071 if (maxWeightCalc < edge->flEdgeWeightMax)
13073 assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, slop, &usedSlop);
13079 // Here we have inconsistent profile data
13080 inconsistentProfileData = true;
13081 // No point in continuing
13085 // When flEdgeWeightMin equals flEdgeWeightMax we have a "good" edge weight
13086 if (edge->flEdgeWeightMin == edge->flEdgeWeightMax)
13088 // Count how many "good" edge weights we have
13089 // Each time through we should have more "good" weights
13090 // We exit the while loop when no longer find any new "good" edges
13091 goodEdgeCountCurrent++;
13095 // Remember that we have seen at least one "Bad" edge weight
13096 // so that we will repeat the while loop again
13097 hasIncompleteEdgeWeights = true;
13103 if (inconsistentProfileData)
13105 hasIncompleteEdgeWeights = true;
13109 if (numEdges == goodEdgeCountCurrent)
13111 noway_assert(hasIncompleteEdgeWeights == false);
13115 } while (hasIncompleteEdgeWeights && (goodEdgeCountCurrent > goodEdgeCountPrevious) && (iterations < 8));
13122 if (inconsistentProfileData)
13124 printf("fgComputeEdgeWeights() found inconsistent profile data, not using the edge weights\n");
13128 if (hasIncompleteEdgeWeights)
13130 printf("fgComputeEdgeWeights() was able to compute exact edge weights for %3d of the %3d edges, using "
13132 goodEdgeCountCurrent, numEdges, iterations);
13136 printf("fgComputeEdgeWeights() was able to compute exact edge weights for all of the %3d edges, using "
13138 numEdges, iterations);
13141 fgPrintEdgeWeights();
13146 fgSlopUsedInEdgeWeights = usedSlop;
13147 fgRangeUsedInEdgeWeights = false;
13149 // See if any edge weight are expressed in [min..max] form
13151 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13153 if (bDst->bbPreds != nullptr)
13155 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13157 bSrc = edge->flBlock;
13158 // This is the control flow edge (bSrc -> bDst)
13160 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
13162 fgRangeUsedInEdgeWeights = true;
13166 if (fgRangeUsedInEdgeWeights)
13173 fgHaveValidEdgeWeights = !inconsistentProfileData;
13174 fgEdgeWeightsComputed = true;
13177 // fgOptimizeBranchToEmptyUnconditional:
13178 // optimize a jump to an empty block which ends in an unconditional branch.
13180 // block: source block
13181 // bDest: destination
13182 // Returns: true if we changed the code
13184 bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest)
13186 bool optimizeJump = true;
13188 assert(bDest->isEmpty());
13189 assert(bDest->bbJumpKind == BBJ_ALWAYS);
13191 // We do not optimize jumps between two different try regions.
13192 // However jumping to a block that is not in any try region is OK
13194 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
13196 optimizeJump = false;
13199 // Don't optimize a jump to a removed block
13200 if (bDest->bbJumpDest->bbFlags & BBF_REMOVED)
13202 optimizeJump = false;
13205 // Don't optimize a jump to a cloned finally
13206 if (bDest->bbFlags & BBF_CLONED_FINALLY_BEGIN)
13208 optimizeJump = false;
13211 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13212 // Don't optimize a jump to a finally target. For BB1->BB2->BB3, where
13213 // BB2 is a finally target, if we changed BB1 to jump directly to BB3,
13214 // it would skip the finally target. BB1 might be a BBJ_ALWAYS block part
13215 // of a BBJ_CALLFINALLY/BBJ_ALWAYS pair, so changing the finally target
13216 // would change the unwind behavior.
13217 if (bDest->bbFlags & BBF_FINALLY_TARGET)
13219 optimizeJump = false;
13221 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13223 // Must optimize jump if bDest has been removed
13225 if (bDest->bbFlags & BBF_REMOVED)
13227 optimizeJump = true;
13230 // If we are optimizing using real profile weights
13231 // then don't optimize a conditional jump to an unconditional jump
13232 // until after we have computed the edge weights
13234 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
13236 fgNeedsUpdateFlowGraph = true;
13237 optimizeJump = false;
13245 printf("\nOptimizing a jump to an unconditional jump (BB%02u -> BB%02u -> BB%02u)\n", block->bbNum,
13246 bDest->bbNum, bDest->bbJumpDest->bbNum);
13251 // When we optimize a branch to branch we need to update the profile weight
13252 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
13254 if (fgHaveValidEdgeWeights && bDest->hasProfileWeight())
13256 flowList* edge1 = fgGetPredForBlock(bDest, block);
13257 noway_assert(edge1 != nullptr);
13259 BasicBlock::weight_t edgeWeight;
13261 if (edge1->flEdgeWeightMin != edge1->flEdgeWeightMax)
13264 // We only have an estimate for the edge weight
13266 edgeWeight = (edge1->flEdgeWeightMin + edge1->flEdgeWeightMax) / 2;
13268 // Clear the profile weight flag
13270 bDest->bbFlags &= ~BBF_PROF_WEIGHT;
13275 // We only have the exact edge weight
13277 edgeWeight = edge1->flEdgeWeightMin;
13281 // Update the bDest->bbWeight
13283 if (bDest->bbWeight > edgeWeight)
13285 bDest->bbWeight -= edgeWeight;
13289 bDest->bbWeight = BB_ZERO_WEIGHT;
13290 bDest->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
13293 flowList* edge2 = fgGetPredForBlock(bDest->bbJumpDest, bDest);
13295 if (edge2 != nullptr)
13298 // Update the edge2 min/max weights
13300 if (edge2->flEdgeWeightMin > edge1->flEdgeWeightMin)
13302 edge2->flEdgeWeightMin -= edge1->flEdgeWeightMin;
13306 edge2->flEdgeWeightMin = BB_ZERO_WEIGHT;
13309 if (edge2->flEdgeWeightMax > edge1->flEdgeWeightMin)
13311 edge2->flEdgeWeightMax -= edge1->flEdgeWeightMin;
13315 edge2->flEdgeWeightMax = BB_ZERO_WEIGHT;
13320 // Optimize the JUMP to empty unconditional JUMP to go to the new target
13321 block->bbJumpDest = bDest->bbJumpDest;
13323 fgAddRefPred(bDest->bbJumpDest, block, fgRemoveRefPred(bDest, block));
13330 // fgOptimizeEmptyBlock:
13331 // Does flow optimization of an empty block (can remove it in some cases)
13334 // block: an empty block
13335 // Returns: true if we changed the code
13337 bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block)
13339 assert(block->isEmpty());
13341 BasicBlock* bPrev = block->bbPrev;
13343 switch (block->bbJumpKind)
13349 /* can never happen */
13350 noway_assert(!"Conditional, switch, or throw block with empty body!");
13353 case BBJ_CALLFINALLY:
13355 case BBJ_EHCATCHRET:
13356 case BBJ_EHFINALLYRET:
13357 case BBJ_EHFILTERRET:
13359 /* leave them as is */
13360 /* some compilers generate multiple returns and put all of them at the end -
13361 * to solve that we need the predecessor list */
13367 // A GOTO cannot be to the next block since that
13368 // should have been fixed by the optimization above
13369 // An exception is made for a jump from Hot to Cold
13370 noway_assert(block->bbJumpDest != block->bbNext || ((bPrev != nullptr) && bPrev->isBBCallAlwaysPair()) ||
13371 fgInDifferentRegions(block, block->bbNext));
13373 /* Cannot remove the first BB */
13379 /* Do not remove a block that jumps to itself - used for while (true){} */
13380 if (block->bbJumpDest == block)
13385 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
13386 if (bPrev->bbJumpKind != BBJ_NONE)
13391 // can't allow fall through into cold code
13392 if (block->bbNext == fgFirstColdBlock)
13397 /* Can fall through since this is similar with removing
13398 * a BBJ_NONE block, only the successor is different */
13404 /* special case if this is the first BB */
13407 assert(block == fgFirstBB);
13411 /* If this block follows a BBJ_CALLFINALLY do not remove it
13412 * (because we don't know who may jump to it) */
13413 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
13419 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13420 /* Don't remove finally targets */
13421 if (block->bbFlags & BBF_FINALLY_TARGET)
13423 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13425 #if FEATURE_EH_FUNCLETS
13426 /* Don't remove an empty block that is in a different EH region
13427 * from its successor block, if the block is the target of a
13428 * catch return. It is required that the return address of a
13429 * catch be in the correct EH region, for re-raise of thread
13430 * abort exceptions to work. Insert a NOP in the empty block
13431 * to ensure we generate code for the block, if we keep it.
13434 BasicBlock* succBlock;
13436 if (block->bbJumpKind == BBJ_ALWAYS)
13438 succBlock = block->bbJumpDest;
13442 succBlock = block->bbNext;
13445 if ((succBlock != nullptr) && !BasicBlock::sameEHRegion(block, succBlock))
13447 // The empty block and the block that follows it are in different
13448 // EH regions. Is this a case where they can't be merged?
13450 bool okToMerge = true; // assume it's ok
13451 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
13453 if (pred->flBlock->bbJumpKind == BBJ_EHCATCHRET)
13455 assert(pred->flBlock->bbJumpDest == block);
13456 okToMerge = false; // we can't get rid of the empty block
13463 // Insert a NOP in the empty block to ensure we generate code
13464 // for the catchret target in the right EH region.
13465 GenTree* nop = new (this, GT_NO_OP) GenTree(GT_NO_OP, TYP_VOID);
13467 if (block->IsLIR())
13469 LIR::AsRange(block).InsertAtEnd(nop);
13473 GenTreePtr nopStmt = fgInsertStmtAtEnd(block, nop);
13474 fgSetStmtSeq(nopStmt);
13475 gtSetStmtInfo(nopStmt);
13481 printf("\nKeeping empty block BB%02u - it is the target of a catch return\n", block->bbNum);
13485 break; // go to the next block
13489 #endif // FEATURE_EH_FUNCLETS
13491 if (!ehCanDeleteEmptyBlock(block))
13493 // We're not allowed to remove this block due to reasons related to the EH table.
13497 /* special case if this is the last BB */
13498 if (block == fgLastBB)
13507 /* Remove the block */
13509 fgRemoveBlock(block, false);
13513 noway_assert(!"Unexpected bbJumpKind");
13519 // fgOptimizeSwitchBranches:
13520 // Does flow optimization for a switch - bypasses jumps to empty unconditional branches,
13521 // and transforms degenerate switch cases like those with 1 or 2 targets
13524 // block: BasicBlock that contains the switch
13525 // Returns: true if we changed the code
13527 bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
13529 assert(block->bbJumpKind == BBJ_SWITCH);
13531 unsigned jmpCnt = block->bbJumpSwt->bbsCount;
13532 BasicBlock** jmpTab = block->bbJumpSwt->bbsDstTab;
13533 BasicBlock* bNewDest; // the new jump target for the current switch case
13535 bool returnvalue = false;
13543 // Do we have a JUMP to an empty unconditional JUMP block?
13544 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
13545 (bDest != bDest->bbJumpDest)) // special case for self jumps
13547 bool optimizeJump = true;
13549 // We do not optimize jumps between two different try regions.
13550 // However jumping to a block that is not in any try region is OK
13552 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
13554 optimizeJump = false;
13557 // If we are optimize using real profile weights
13558 // then don't optimize a switch jump to an unconditional jump
13559 // until after we have computed the edge weights
13561 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
13563 fgNeedsUpdateFlowGraph = true;
13564 optimizeJump = false;
13569 bNewDest = bDest->bbJumpDest;
13573 printf("\nOptimizing a switch jump to an empty block with an unconditional jump (BB%02u -> BB%02u "
13575 block->bbNum, bDest->bbNum, bNewDest->bbNum);
13581 if (bNewDest != bDest)
13584 // When we optimize a branch to branch we need to update the profile weight
13585 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
13587 if (fgIsUsingProfileWeights() && bDest->hasProfileWeight())
13589 if (fgHaveValidEdgeWeights)
13591 flowList* edge = fgGetPredForBlock(bDest, block);
13592 BasicBlock::weight_t branchThroughWeight = edge->flEdgeWeightMin;
13594 if (bDest->bbWeight > branchThroughWeight)
13596 bDest->bbWeight -= branchThroughWeight;
13600 bDest->bbWeight = BB_ZERO_WEIGHT;
13601 bDest->bbFlags |= BBF_RUN_RARELY;
13606 // Update the switch jump table
13607 *jmpTab = bNewDest;
13609 // Maintain, if necessary, the set of unique targets of "block."
13610 UpdateSwitchTableTarget(block, bDest, bNewDest);
13612 fgAddRefPred(bNewDest, block, fgRemoveRefPred(bDest, block));
13614 // we optimized a Switch label - goto REPEAT_SWITCH to follow this new jump
13615 returnvalue = true;
13617 goto REPEAT_SWITCH;
13619 } while (++jmpTab, --jmpCnt);
13621 GenTreeStmt* switchStmt = nullptr;
13622 LIR::Range* blockRange = nullptr;
13624 GenTree* switchTree;
13625 if (block->IsLIR())
13627 blockRange = &LIR::AsRange(block);
13628 switchTree = blockRange->LastNode();
13630 assert(switchTree->OperGet() == GT_SWITCH_TABLE);
13634 switchStmt = block->lastStmt();
13635 switchTree = switchStmt->gtStmtExpr;
13637 assert(switchTree->OperGet() == GT_SWITCH);
13640 noway_assert(switchTree->gtType == TYP_VOID);
13642 // At this point all of the case jump targets have been updated such
13643 // that none of them go to block that is an empty unconditional block
13645 jmpTab = block->bbJumpSwt->bbsDstTab;
13646 jmpCnt = block->bbJumpSwt->bbsCount;
13647 // Now check for two trivial switch jumps.
13649 if (block->NumSucc(this) == 1)
13651 // Use BBJ_ALWAYS for a switch with only a default clause, or with only one unique successor.
13652 BasicBlock* uniqueSucc = jmpTab[0];
13657 printf("\nRemoving a switch jump with a single target (BB%02u)\n", block->bbNum);
13658 printf("BEFORE:\n");
13662 if (block->IsLIR())
13665 unsigned sideEffects;
13666 LIR::ReadOnlyRange switchTreeRange = blockRange->GetTreeRange(switchTree, &isClosed, &sideEffects);
13668 // The switch tree should form a contiguous, side-effect free range by construction. See
13669 // Lowering::LowerSwitch for details.
13671 assert((sideEffects & GTF_ALL_EFFECT) == 0);
13673 blockRange->Delete(this, block, std::move(switchTreeRange));
13677 /* check for SIDE_EFFECTS */
13678 if (switchTree->gtFlags & GTF_SIDE_EFFECT)
13680 /* Extract the side effects from the conditional */
13681 GenTreePtr sideEffList = nullptr;
13683 gtExtractSideEffList(switchTree, &sideEffList);
13685 if (sideEffList == nullptr)
13687 goto NO_SWITCH_SIDE_EFFECT;
13690 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
13695 printf("\nSwitch expression has side effects! Extracting side effects...\n");
13696 gtDispTree(switchTree);
13698 gtDispTree(sideEffList);
13703 /* Replace the conditional statement with the list of side effects */
13704 noway_assert(sideEffList->gtOper != GT_STMT);
13705 noway_assert(sideEffList->gtOper != GT_SWITCH);
13707 switchStmt->gtStmtExpr = sideEffList;
13709 if (fgStmtListThreaded)
13711 /* Update the lclvar ref counts */
13713 fgUpdateRefCntForExtract(switchTree, sideEffList);
13715 /* Update ordering, costs, FP levels, etc. */
13716 gtSetStmtInfo(switchStmt);
13718 /* Re-link the nodes for this statement */
13719 fgSetStmtSeq(switchStmt);
13725 NO_SWITCH_SIDE_EFFECT:
13727 /* conditional has NO side effect - remove it */
13728 fgRemoveStmt(block, switchStmt);
13732 // Change the switch jump into a BBJ_ALWAYS
13733 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
13734 block->bbJumpKind = BBJ_ALWAYS;
13737 for (unsigned i = 1; i < jmpCnt; ++i)
13739 (void)fgRemoveRefPred(jmpTab[i], block);
13745 else if (block->bbJumpSwt->bbsCount == 2 && block->bbJumpSwt->bbsDstTab[1] == block->bbNext)
13747 /* Use a BBJ_COND(switchVal==0) for a switch with only one
13748 significant clause besides the default clause, if the
13749 default clause is bbNext */
13750 GenTree* switchVal = switchTree->gtOp.gtOp1;
13751 noway_assert(genActualTypeIsIntOrI(switchVal->TypeGet()));
13753 #ifndef LEGACY_BACKEND
13754 // If we are in LIR, remove the jump table from the block.
13755 if (block->IsLIR())
13757 GenTree* jumpTable = switchTree->gtOp.gtOp2;
13758 assert(jumpTable->OperGet() == GT_JMPTABLE);
13759 blockRange->Remove(jumpTable);
13763 // Change the GT_SWITCH(switchVal) into GT_JTRUE(GT_EQ(switchVal==0)).
13764 // Also mark the node as GTF_DONT_CSE as further down JIT is not capable of handling it.
13765 // For example CSE could determine that the expression rooted at GT_EQ is a candidate cse and
13766 // replace it with a COMMA node. In such a case we will end up with GT_JTRUE node pointing to
13767 // a COMMA node which results in noway asserts in fgMorphSmpOp(), optAssertionGen() and rpPredictTreeRegUse().
13768 // For the same reason fgMorphSmpOp() marks GT_JTRUE nodes with RELOP children as GTF_DONT_CSE.
13769 CLANG_FORMAT_COMMENT_ANCHOR;
13774 printf("\nConverting a switch (BB%02u) with only one significant clause besides a default target to a "
13775 "conditional branch\n",
13780 switchTree->ChangeOper(GT_JTRUE);
13781 GenTree* zeroConstNode = gtNewZeroConNode(genActualType(switchVal->TypeGet()));
13782 GenTree* condNode = gtNewOperNode(GT_EQ, TYP_INT, switchVal, zeroConstNode);
13783 switchTree->gtOp.gtOp1 = condNode;
13784 switchTree->gtOp.gtOp1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
13786 if (block->IsLIR())
13788 blockRange->InsertAfter(switchVal, zeroConstNode, condNode);
13792 // Re-link the nodes for this statement.
13793 fgSetStmtSeq(switchStmt);
13796 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
13797 block->bbJumpKind = BBJ_COND;
13801 return returnvalue;
13804 // fgBlockEndFavorsTailDuplication:
13805 // Heuristic function that returns true if this block ends in a statement that looks favorable
13806 // for tail-duplicating its successor (such as assigning a constant to a local).
13808 // block: BasicBlock we are considering duplicating the successor of
13810 // true if it seems like a good idea
13812 bool Compiler::fgBlockEndFavorsTailDuplication(BasicBlock* block)
13814 if (block->isRunRarely())
13819 if (!block->lastStmt())
13825 // Tail duplication tends to pay off when the last statement
13826 // is an assignment of a constant, arraylength, or a relop.
13827 // This is because these statements produce information about values
13828 // that would otherwise be lost at the upcoming merge point.
13830 GenTreeStmt* lastStmt = block->lastStmt();
13831 GenTree* tree = lastStmt->gtStmtExpr;
13832 if (tree->gtOper != GT_ASG)
13837 if (tree->OperIsBlkOp())
13842 GenTree* op2 = tree->gtOp.gtOp2;
13843 if (op2->gtOper != GT_ARR_LENGTH && !op2->OperIsConst() && ((op2->OperKind() & GTK_RELOP) == 0))
13851 // fgBlockIsGoodTailDuplicationCandidate:
13852 // Heuristic function that examines a block (presumably one that is a merge point) to determine
13853 // if it should be duplicated.
13855 // target - the tail block (candidate for duplication)
13857 // true if this block seems like a good candidate for duplication
13859 bool Compiler::fgBlockIsGoodTailDuplicationCandidate(BasicBlock* target)
13861 GenTreeStmt* stmt = target->FirstNonPhiDef();
13863 // Here we are looking for blocks with a single statement feeding a conditional branch.
13864 // These blocks are small, and when duplicated onto the tail of blocks that end in
13865 // assignments, there is a high probability of the branch completely going away.
13867 // This is by no means the only kind of tail that it is beneficial to duplicate,
13868 // just the only one we recognize for now.
13870 if (stmt != target->lastStmt())
13875 if (target->bbJumpKind != BBJ_COND)
13880 GenTree* tree = stmt->gtStmtExpr;
13882 if (tree->gtOper != GT_JTRUE)
13887 // must be some kind of relational operator
13888 GenTree* cond = tree->gtOp.gtOp1;
13889 if (!(cond->OperKind() & GTK_RELOP))
13894 // op1 must be some combinations of casts of local or constant
13895 GenTree* op1 = cond->gtOp.gtOp1;
13896 while (op1->gtOper == GT_CAST)
13898 op1 = op1->gtOp.gtOp1;
13900 if (!op1->IsLocal() && !op1->OperIsConst())
13905 // op2 must be some combinations of casts of local or constant
13906 GenTree* op2 = cond->gtOp.gtOp2;
13907 while (op2->gtOper == GT_CAST)
13909 op2 = op2->gtOp.gtOp1;
13911 if (!op2->IsLocal() && !op2->OperIsConst())
13919 // fgOptimizeUncondBranchToSimpleCond:
13920 // For a block which has an unconditional branch, look to see if its target block
13921 // is a good candidate for tail duplication, and if so do that duplication.
13924 // block - block with uncond branch
13925 // target - block which is target of first block
13927 // returns: true if changes were made
13929 bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target)
13931 assert(block->bbJumpKind == BBJ_ALWAYS);
13932 assert(block->bbJumpDest == target);
13934 // TODO-Review: OK if they are in the same region?
13935 if (compHndBBtabCount > 0)
13940 if (!fgBlockIsGoodTailDuplicationCandidate(target))
13945 if (!fgBlockEndFavorsTailDuplication(block))
13950 // NOTE: we do not currently hit this assert because this function is only called when
13951 // `fgUpdateFlowGraph` has been called with `doTailDuplication` set to true, and the
13952 // backend always calls `fgUpdateFlowGraph` with `doTailDuplication` set to false.
13953 assert(!block->IsLIR());
13955 GenTreeStmt* stmt = target->FirstNonPhiDef();
13956 assert(stmt == target->lastStmt());
13958 // Duplicate the target block at the end of this block
13960 GenTree* cloned = gtCloneExpr(stmt->gtStmtExpr);
13961 noway_assert(cloned);
13962 GenTree* jmpStmt = gtNewStmt(cloned);
13964 block->bbJumpKind = BBJ_COND;
13965 block->bbJumpDest = target->bbJumpDest;
13966 fgAddRefPred(block->bbJumpDest, block);
13967 fgRemoveRefPred(target, block);
13969 // add an unconditional block after this block to jump to the target block's fallthrough block
13971 BasicBlock* next = fgNewBBafter(BBJ_ALWAYS, block, true);
13973 // The new block 'next' will inherit its weight from 'block'
13974 next->inheritWeight(block);
13975 next->bbJumpDest = target->bbNext;
13976 target->bbNext->bbFlags |= BBF_JMP_TARGET;
13977 fgAddRefPred(next, block);
13978 fgAddRefPred(next->bbJumpDest, next);
13983 printf("fgOptimizeUncondBranchToSimpleCond(from BB%02u to cond BB%02u), created new uncond BB%02u\n",
13984 block->bbNum, target->bbNum, next->bbNum);
13988 if (fgStmtListThreaded)
13990 gtSetStmtInfo(jmpStmt);
13993 fgInsertStmtAtEnd(block, jmpStmt);
13998 // fgOptimizeBranchToNext:
13999 // Optimize a block which has a branch to the following block
14001 // block - block with a branch
14002 // bNext - block which is both next and the target of the first block
14003 // bPrev - block which is prior to the first block
14005 // returns: true if changes were made
14007 bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev)
14009 assert(block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS);
14010 assert(block->bbJumpDest == bNext);
14011 assert(block->bbNext == bNext);
14012 assert(block->bbPrev == bPrev);
14014 if (block->bbJumpKind == BBJ_ALWAYS)
14016 // We can't remove it if it is a branch from hot => cold
14017 if (!fgInDifferentRegions(block, bNext))
14019 // We can't remove if it is marked as BBF_KEEP_BBJ_ALWAYS
14020 if (!(block->bbFlags & BBF_KEEP_BBJ_ALWAYS))
14022 // We can't remove if the BBJ_ALWAYS is part of a BBJ_CALLFINALLY pair
14023 if ((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair())
14025 /* the unconditional jump is to the next BB */
14026 block->bbJumpKind = BBJ_NONE;
14027 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14031 printf("\nRemoving unconditional jump to next block (BB%02u -> BB%02u) (converted BB%02u to "
14033 block->bbNum, bNext->bbNum, block->bbNum);
14043 /* remove the conditional statement at the end of block */
14044 noway_assert(block->bbJumpKind == BBJ_COND);
14045 noway_assert(block->bbTreeList);
14050 printf("\nRemoving conditional jump to next block (BB%02u -> BB%02u)\n", block->bbNum, bNext->bbNum);
14054 if (block->IsLIR())
14056 LIR::Range& blockRange = LIR::AsRange(block);
14057 GenTree* jmp = blockRange.LastNode();
14058 assert(jmp->OperIsConditionalJump());
14061 unsigned sideEffects;
14062 LIR::ReadOnlyRange jmpRange = blockRange.GetTreeRange(jmp, &isClosed, &sideEffects);
14064 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
14065 // diffs compared to the existing backend.
14066 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
14068 // If the jump and its operands form a contiguous, side-effect-free range,
14070 blockRange.Delete(this, block, std::move(jmpRange));
14074 // Otherwise, just remove the jump node itself.
14075 blockRange.Remove(jmp);
14080 GenTreeStmt* cond = block->lastStmt();
14081 noway_assert(cond->gtStmtExpr->gtOper == GT_JTRUE);
14083 /* check for SIDE_EFFECTS */
14084 if (cond->gtStmtExpr->gtFlags & GTF_SIDE_EFFECT)
14086 /* Extract the side effects from the conditional */
14087 GenTreePtr sideEffList = nullptr;
14089 gtExtractSideEffList(cond->gtStmtExpr, &sideEffList);
14091 if (sideEffList == nullptr)
14094 fgRemoveStmt(block, cond);
14098 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
14102 printf("\nConditional has side effects! Extracting side effects...\n");
14105 gtDispTree(sideEffList);
14110 /* Replace the conditional statement with the list of side effects */
14111 noway_assert(sideEffList->gtOper != GT_STMT);
14112 noway_assert(sideEffList->gtOper != GT_JTRUE);
14114 cond->gtStmtExpr = sideEffList;
14116 if (fgStmtListThreaded)
14118 /* Update the lclvar ref counts */
14120 fgUpdateRefCntForExtract(cond->gtStmtExpr, sideEffList);
14122 /* Update ordering, costs, FP levels, etc. */
14123 gtSetStmtInfo(cond);
14125 /* Re-link the nodes for this statement */
14126 fgSetStmtSeq(cond);
14133 /* conditional has NO side effect - remove it */
14134 fgRemoveStmt(block, cond);
14138 /* Conditional is gone - simply fall into the next block */
14140 block->bbJumpKind = BBJ_NONE;
14141 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14143 /* Update bbRefs and bbNum - Conditional predecessors to the same
14144 * block are counted twice so we have to remove one of them */
14146 noway_assert(bNext->countOfInEdges() > 1);
14147 fgRemoveRefPred(bNext, block);
14154 /*****************************************************************************
14156 * Function called to optimize an unconditional branch that branches
14157 * to a conditional branch.
14158 * Currently we require that the conditional branch jump back to the
14159 * block that follows the unconditional branch.
14161 * We can improve the code execution and layout by concatenating a copy
14162 * of the conditional branch block at the end of the conditional branch
14163 * and reversing the sense of the branch.
14165 * This is only done when the amount of code to be copied is smaller than
14166 * our calculated threshold in maxDupCostSz.
14170 bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
14172 if (opts.MinOpts())
14177 if (bJump->bbJumpKind != BBJ_ALWAYS)
14182 if (bJump->bbFlags & BBF_KEEP_BBJ_ALWAYS)
14187 // Don't hoist a conditional branch into the scratch block; we'd prefer it stay
14188 // either BBJ_NONE or BBJ_ALWAYS.
14189 if (fgBBisScratch(bJump))
14194 BasicBlock* bDest = bJump->bbJumpDest;
14196 if (bDest->bbJumpKind != BBJ_COND)
14201 if (bDest->bbJumpDest != bJump->bbNext)
14206 // 'bJump' must be in the same try region as the condition, since we're going to insert
14207 // a duplicated condition in 'bJump', and the condition might include exception throwing code.
14208 if (!BasicBlock::sameTryRegion(bJump, bDest))
14213 // do not jump into another try region
14214 BasicBlock* bDestNext = bDest->bbNext;
14215 if (bDestNext->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNext))
14220 // This function is only called by fgReorderBlocks, which we do not run in the backend.
14221 // If we wanted to run block reordering in the backend, we would need to be able to
14222 // calculate cost information for LIR on a per-node basis in order for this function
14224 assert(!bJump->IsLIR());
14225 assert(!bDest->IsLIR());
14228 unsigned estDupCostSz = 0;
14229 for (stmt = bDest->firstStmt(); stmt; stmt = stmt->gtNextStmt)
14231 GenTreePtr expr = stmt->gtStmtExpr;
14233 /* We call gtPrepareCost to measure the cost of duplicating this tree */
14234 gtPrepareCost(expr);
14236 estDupCostSz += expr->gtCostSz;
14239 bool allProfileWeightsAreValid = false;
14240 BasicBlock::weight_t weightJump = bJump->bbWeight;
14241 BasicBlock::weight_t weightDest = bDest->bbWeight;
14242 BasicBlock::weight_t weightNext = bJump->bbNext->bbWeight;
14243 bool rareJump = bJump->isRunRarely();
14244 bool rareDest = bDest->isRunRarely();
14245 bool rareNext = bJump->bbNext->isRunRarely();
14247 // If we have profile data then we calculate the number of time
14248 // the loop will iterate into loopIterations
14249 if (fgIsUsingProfileWeights())
14251 // Only rely upon the profile weight when all three of these blocks
14252 // have either good profile weights or are rarelyRun
14254 if ((bJump->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
14255 (bDest->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
14256 (bJump->bbNext->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)))
14258 allProfileWeightsAreValid = true;
14260 if ((weightJump * 100) < weightDest)
14265 if ((weightNext * 100) < weightDest)
14270 if (((weightDest * 100) < weightJump) && ((weightDest * 100) < weightNext))
14277 unsigned maxDupCostSz = 6;
14280 // Branches between the hot and rarely run regions
14281 // should be minimized. So we allow a larger size
14283 if (rareDest != rareJump)
14288 if (rareDest != rareNext)
14294 // We we are ngen-ing:
14295 // If the uncondional branch is a rarely run block then
14296 // we are willing to have more code expansion since we
14297 // won't be running code from this page
14299 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
14307 // If the compare has too high cost then we don't want to dup
14309 bool costIsTooHigh = (estDupCostSz > maxDupCostSz);
14314 printf("\nDuplication of the conditional block BB%02u (always branch from BB%02u) %s, because the cost of "
14315 "duplication (%i) is %s than %i,"
14316 " validProfileWeights = %s\n",
14317 bDest->bbNum, bJump->bbNum, costIsTooHigh ? "not done" : "performed", estDupCostSz,
14318 costIsTooHigh ? "greater" : "less or equal", maxDupCostSz, allProfileWeightsAreValid ? "true" : "false");
14327 /* Looks good - duplicate the conditional block */
14329 GenTree* newStmtList = nullptr; // new stmt list to be added to bJump
14330 GenTree* newStmtLast = nullptr;
14331 bool cloneExprFailed = false;
14333 /* Visit all the statements in bDest */
14335 for (GenTree* curStmt = bDest->bbTreeList; curStmt; curStmt = curStmt->gtNext)
14337 /* Clone/substitute the expression */
14339 stmt = gtCloneExpr(curStmt)->AsStmt();
14341 // cloneExpr doesn't handle everything
14343 if (stmt == nullptr)
14345 cloneExprFailed = true;
14349 /* Append the expression to our list */
14351 if (newStmtList != nullptr)
14353 newStmtLast->gtNext = stmt;
14357 newStmtList = stmt;
14360 stmt->gtPrev = newStmtLast;
14361 newStmtLast = stmt;
14364 if (cloneExprFailed)
14369 noway_assert(newStmtLast != nullptr);
14370 noway_assert(stmt != nullptr);
14371 noway_assert(stmt->gtOper == GT_STMT);
14373 if ((newStmtLast == nullptr) || (stmt == nullptr) || (stmt->gtOper != GT_STMT))
14378 /* Get to the condition node from the statement tree */
14380 GenTreePtr condTree = stmt->gtStmtExpr;
14381 noway_assert(condTree->gtOper == GT_JTRUE);
14383 if (condTree->gtOper != GT_JTRUE)
14389 // Set condTree to the operand to the GT_JTRUE
14391 condTree = condTree->gtOp.gtOp1;
14394 // This condTree has to be a RelOp comparison
14396 if (condTree->OperIsCompare() == false)
14401 // Bump up the ref-counts of any variables in 'stmt'
14402 fgUpdateRefCntForClone(bJump, stmt->gtStmtExpr);
14405 // Find the last statement in the bJump block
14407 GenTreeStmt* lastStmt = nullptr;
14408 for (stmt = bJump->firstStmt(); stmt; stmt = stmt->gtNextStmt)
14412 stmt = bJump->firstStmt();
14414 /* Join the two linked lists */
14415 newStmtLast->gtNext = nullptr;
14417 if (lastStmt != nullptr)
14419 stmt->gtPrev = newStmtLast;
14420 lastStmt->gtNext = newStmtList;
14421 newStmtList->gtPrev = lastStmt;
14425 bJump->bbTreeList = newStmtList;
14426 newStmtList->gtPrev = newStmtLast;
14430 // Reverse the sense of the compare
14432 gtReverseCond(condTree);
14434 // We need to update the following flags of the bJump block if they were set in the bDest block
14436 (bDest->bbFlags & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY | BBF_HAS_NULLCHECK | BBF_HAS_IDX_LEN | BBF_HAS_VTABREF));
14438 bJump->bbJumpKind = BBJ_COND;
14439 bJump->bbJumpDest = bDest->bbNext;
14441 /* Mark the jump dest block as being a jump target */
14442 bJump->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
14444 /* Update bbRefs and bbPreds */
14446 // bJump now falls through into the next block
14448 fgAddRefPred(bJump->bbNext, bJump);
14450 // bJump no longer jumps to bDest
14452 fgRemoveRefPred(bDest, bJump);
14454 // bJump now jumps to bDest->bbNext
14456 fgAddRefPred(bDest->bbNext, bJump);
14458 if (weightJump > 0)
14460 if (allProfileWeightsAreValid)
14462 if (weightDest > weightJump)
14464 bDest->bbWeight = (weightDest - weightJump);
14466 else if (!bDest->isRunRarely())
14468 bDest->bbWeight = BB_UNITY_WEIGHT;
14473 BasicBlock::weight_t newWeightDest = 0;
14474 BasicBlock::weight_t unloopWeightDest = 0;
14476 if (weightDest > weightJump)
14478 newWeightDest = (weightDest - weightJump);
14480 if (weightDest >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2)
14482 newWeightDest = (weightDest * 2) / (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT);
14484 if ((newWeightDest > 0) || (unloopWeightDest > 0))
14486 bDest->bbWeight = Max(newWeightDest, unloopWeightDest);
14494 printf("\nAfter this change in fgOptimizeBranch");
14495 fgDispBasicBlocks(verboseTrees);
14503 /*****************************************************************************
14505 * Function called to optimize switch statements
14508 bool Compiler::fgOptimizeSwitchJumps()
14510 bool result = false; // Our return value
14513 // TODO-CQ: Add switch jump optimizations?
14517 if (!fgHaveValidEdgeWeights)
14520 for (BasicBlock* bSrc = fgFirstBB; bSrc != NULL; bSrc = bSrc->bbNext)
14522 if (bSrc->bbJumpKind == BBJ_SWITCH)
14524 unsigned jumpCnt; jumpCnt = bSrc->bbJumpSwt->bbsCount;
14525 BasicBlock** jumpTab; jumpTab = bSrc->bbJumpSwt->bbsDstTab;
14529 BasicBlock* bDst = *jumpTab;
14530 flowList* edgeToDst = fgGetPredForBlock(bDst, bSrc);
14531 double outRatio = (double) edgeToDst->flEdgeWeightMin / (double) bSrc->bbWeight;
14533 if (outRatio >= 0.60)
14535 // straighten switch here...
14538 while (++jumpTab, --jumpCnt);
14547 #pragma warning(push)
14548 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
14550 /*****************************************************************************
14552 * Function called to reorder the flowgraph of BasicBlocks such that any
14553 * rarely run blocks are placed at the end of the block list.
14554 * If we have profile information we also use that information to reverse
14555 * all conditional jumps that would benefit.
14558 void Compiler::fgReorderBlocks()
14560 noway_assert(opts.compDbgCode == false);
14562 #if FEATURE_EH_FUNCLETS
14563 assert(fgFuncletsCreated);
14564 #endif // FEATURE_EH_FUNCLETS
14566 // We can't relocate anything if we only have one block
14567 if (fgFirstBB->bbNext == nullptr)
14572 bool newRarelyRun = false;
14573 bool movedBlocks = false;
14574 bool optimizedSwitches = false;
14576 // First let us expand the set of run rarely blocks
14577 newRarelyRun |= fgExpandRarelyRunBlocks();
14579 #if !FEATURE_EH_FUNCLETS
14580 movedBlocks |= fgRelocateEHRegions();
14581 #endif // !FEATURE_EH_FUNCLETS
14584 // If we are using profile weights we can change some
14585 // switch jumps into conditional test and jump
14587 if (fgIsUsingProfileWeights())
14590 // Note that this is currently not yet implemented
14592 optimizedSwitches = fgOptimizeSwitchJumps();
14593 if (optimizedSwitches)
14595 fgUpdateFlowGraph();
14602 printf("*************** In fgReorderBlocks()\n");
14604 printf("\nInitial BasicBlocks");
14605 fgDispBasicBlocks(verboseTrees);
14616 // Iterate over every block, remembering our previous block in bPrev
14617 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
14620 // Consider relocating the rarely run blocks such that they are at the end of the method.
14621 // We also consider reversing conditional branches so that they become a not taken forwards branch.
14624 // If block is marked with a BBF_KEEP_BBJ_ALWAYS flag then we don't move the block
14625 if ((block->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
14630 // Finally and handlers blocks are to be kept contiguous.
14631 // TODO-CQ: Allow reordering within the handler region
14632 if (block->hasHndIndex() == true)
14637 bool reorderBlock = true; // This is set to false if we decide not to reorder 'block'
14638 bool isRare = block->isRunRarely();
14639 BasicBlock* bDest = nullptr;
14640 bool forwardBranch = false;
14641 bool backwardBranch = false;
14644 if ((bPrev->bbJumpKind == BBJ_COND) || (bPrev->bbJumpKind == BBJ_ALWAYS))
14646 bDest = bPrev->bbJumpDest;
14647 forwardBranch = fgIsForwardBranch(bPrev);
14648 backwardBranch = !forwardBranch;
14651 // We will look for bPrev as a non rarely run block followed by block as a rarely run block
14653 if (bPrev->isRunRarely())
14655 reorderBlock = false;
14658 // If the weights of the bPrev, block and bDest were all obtained from a profile run
14659 // then we can use them to decide if it is useful to reverse this conditional branch
14661 BasicBlock::weight_t profHotWeight = -1;
14663 if (bPrev->hasProfileWeight() && block->hasProfileWeight() && ((bDest == nullptr) || bDest->hasProfileWeight()))
14666 // All blocks have profile information
14670 if (bPrev->bbJumpKind == BBJ_ALWAYS)
14672 // We can pull up the blocks that the unconditional jump branches to
14673 // if the weight of bDest is greater or equal to the weight of block
14674 // also the weight of bDest can't be zero.
14676 if ((bDest->bbWeight < block->bbWeight) || (bDest->bbWeight == 0))
14678 reorderBlock = false;
14683 // If this remains true then we will try to pull up bDest to succeed bPrev
14685 bool moveDestUp = true;
14687 if (fgHaveValidEdgeWeights)
14690 // The edge bPrev -> bDest must have a higher minimum weight
14691 // than every other edge into bDest
14693 flowList* edgeFromPrev = fgGetPredForBlock(bDest, bPrev);
14694 noway_assert(edgeFromPrev != nullptr);
14696 // Examine all of the other edges into bDest
14697 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
14699 if (edge != edgeFromPrev)
14701 if (edge->flEdgeWeightMax >= edgeFromPrev->flEdgeWeightMin)
14703 moveDestUp = false;
14712 // The block bPrev must have a higher weight
14713 // than every other block that goes into bDest
14716 // Examine all of the other edges into bDest
14717 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
14719 BasicBlock* bTemp = edge->flBlock;
14721 if ((bTemp != bPrev) && (bTemp->bbWeight >= bPrev->bbWeight))
14723 moveDestUp = false;
14729 // Are we still good to move bDest up to bPrev?
14733 // We will consider all blocks that have less weight than profHotWeight to be
14734 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
14736 profHotWeight = bDest->bbWeight - 1;
14740 if (block->isRunRarely())
14742 // We will move any rarely run blocks blocks
14747 // We will move all blocks that have a weight less or equal to our fall through block
14748 profHotWeight = block->bbWeight + 1;
14750 // But we won't try to connect with bDest
14755 else // (bPrev->bbJumpKind == BBJ_COND)
14757 noway_assert(bPrev->bbJumpKind == BBJ_COND);
14759 // We will reverse branch if the taken-jump to bDest ratio (i.e. 'takenRatio')
14760 // is more than 51%
14762 // We will setup profHotWeight to be maximum bbWeight that a block
14763 // could have for us not to want to reverse the conditional branch
14765 // We will consider all blocks that have less weight than profHotWeight to be
14766 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
14768 if (fgHaveValidEdgeWeights)
14770 // We have valid edge weights, however even with valid edge weights
14771 // we may have a minimum and maximum range for each edges value
14773 // We will check that the min weight of the bPrev to bDest edge
14774 // is more than twice the max weight of the bPrev to block edge.
14776 // bPrev --> [BB04, weight 31]
14778 // edgeToBlock -------------> O \
14779 // [min=8,max=10] V \
14780 // block --> [BB05, weight 10] \
14782 // edgeToDest ----------------------------> O
14783 // [min=21,max=23] |
14785 // bDest ---------------> [BB08, weight 21]
14787 flowList* edgeToDest = fgGetPredForBlock(bDest, bPrev);
14788 flowList* edgeToBlock = fgGetPredForBlock(block, bPrev);
14789 noway_assert(edgeToDest != nullptr);
14790 noway_assert(edgeToBlock != nullptr);
14792 // Calculate the taken ratio
14793 // A takenRation of 0.10 means taken 10% of the time, not taken 90% of the time
14794 // A takenRation of 0.50 means taken 50% of the time, not taken 50% of the time
14795 // A takenRation of 0.90 means taken 90% of the time, not taken 10% of the time
14797 double takenCount =
14798 ((double)edgeToDest->flEdgeWeightMin + (double)edgeToDest->flEdgeWeightMax) / 2.0;
14799 double notTakenCount =
14800 ((double)edgeToBlock->flEdgeWeightMin + (double)edgeToBlock->flEdgeWeightMax) / 2.0;
14801 double totalCount = takenCount + notTakenCount;
14802 double takenRatio = takenCount / totalCount;
14804 // If the takenRatio is greater or equal to 51% then we will reverse the branch
14805 if (takenRatio < 0.51)
14807 reorderBlock = false;
14811 // set profHotWeight
14812 profHotWeight = (edgeToBlock->flEdgeWeightMin + edgeToBlock->flEdgeWeightMax) / 2 - 1;
14817 // We don't have valid edge weight so we will be more conservative
14818 // We could have bPrev, block or bDest as part of a loop and thus have extra weight
14820 // We will do two checks:
14821 // 1. Check that the weight of bDest is at least two times more than block
14822 // 2. Check that the weight of bPrev is at least three times more than block
14824 // bPrev --> [BB04, weight 31]
14827 // block --> [BB05, weight 10] \
14831 // bDest ---------------> [BB08, weight 21]
14833 // For this case weightDest is calculated as (21+1)/2 or 11
14834 // and weightPrev is calculated as (31+2)/3 also 11
14836 // Generally both weightDest and weightPrev should calculate
14837 // the same value unless bPrev or bDest are part of a loop
14839 BasicBlock::weight_t weightDest =
14840 bDest->isMaxBBWeight() ? bDest->bbWeight : (bDest->bbWeight + 1) / 2;
14841 BasicBlock::weight_t weightPrev =
14842 bPrev->isMaxBBWeight() ? bPrev->bbWeight : (bPrev->bbWeight + 2) / 3;
14844 // select the lower of weightDest and weightPrev
14845 profHotWeight = (weightDest < weightPrev) ? weightDest : weightPrev;
14847 // if the weight of block is greater (or equal) to profHotWeight then we don't reverse the cond
14848 if (block->bbWeight >= profHotWeight)
14850 reorderBlock = false;
14855 else // not a forwardBranch
14857 if (bPrev->bbFallsThrough())
14859 goto CHECK_FOR_RARE;
14862 // Here we should pull up the highest weight block remaining
14863 // and place it here since bPrev does not fall through.
14865 BasicBlock::weight_t highestWeight = 0;
14866 BasicBlock* candidateBlock = nullptr;
14867 BasicBlock* lastNonFallThroughBlock = bPrev;
14868 BasicBlock* bTmp = bPrev->bbNext;
14870 while (bTmp != nullptr)
14872 // Don't try to split a Call/Always pair
14874 if (bTmp->isBBCallAlwaysPair())
14876 // Move bTmp forward
14877 bTmp = bTmp->bbNext;
14881 // Check for loop exit condition
14883 if (bTmp == nullptr)
14889 // if its weight is the highest one we've seen and
14890 // the EH regions allow for us to place bTmp after bPrev
14892 if ((bTmp->bbWeight > highestWeight) && fgEhAllowsMoveBlock(bPrev, bTmp))
14894 // When we have a current candidateBlock that is a conditional (or unconditional) jump
14895 // to bTmp (which is a higher weighted block) then it is better to keep out current
14896 // candidateBlock and have it fall into bTmp
14898 if ((candidateBlock == nullptr) ||
14899 ((candidateBlock->bbJumpKind != BBJ_COND) && (candidateBlock->bbJumpKind != BBJ_ALWAYS)) ||
14900 (candidateBlock->bbJumpDest != bTmp))
14902 // otherwise we have a new candidateBlock
14904 highestWeight = bTmp->bbWeight;
14905 candidateBlock = lastNonFallThroughBlock->bbNext;
14909 if ((bTmp->bbFallsThrough() == false) || (bTmp->bbWeight == 0))
14911 lastNonFallThroughBlock = bTmp;
14914 bTmp = bTmp->bbNext;
14917 // If we didn't find a suitable block then skip this
14918 if (highestWeight == 0)
14920 reorderBlock = false;
14924 noway_assert(candidateBlock != nullptr);
14926 // If the candidateBlock is the same a block then skip this
14927 if (candidateBlock == block)
14929 reorderBlock = false;
14933 // Set bDest to the block that we want to come after bPrev
14934 bDest = candidateBlock;
14936 // set profHotWeight
14937 profHotWeight = highestWeight - 1;
14942 else // we don't have good profile info (or we are falling through)
14947 /* We only want to reorder when we have a rarely run */
14948 /* block right after a normal block, */
14949 /* (bPrev is known to be a normal block at this point) */
14952 reorderBlock = false;
14956 /* If the jump target bDest is also a rarely run block then we don't want to do the reversal */
14957 if (bDest && bDest->isRunRarely())
14959 reorderBlock = false; /* Both block and bDest are rarely run */
14963 // We will move any rarely run blocks blocks
14969 if (reorderBlock == false)
14972 // Check for an unconditional branch to a conditional branch
14973 // which also branches back to our next block
14975 if (fgOptimizeBranch(bPrev))
14977 noway_assert(bPrev->bbJumpKind == BBJ_COND);
14982 // Now we need to determine which blocks should be moved
14984 // We consider one of two choices:
14986 // 1. Moving the fall-through blocks (or rarely run blocks) down to
14987 // later in the method and hopefully connecting the jump dest block
14988 // so that it becomes the fall through block
14990 // And when bDest in not NULL, we also consider:
14992 // 2. Moving the bDest block (or blocks) up to bPrev
14993 // so that it could be used as a fall through block
14995 // We will prefer option #1 if we are able to connect the jump dest
14996 // block as the fall though block otherwise will we try to use option #2
15000 // Consider option #1: relocating blocks starting at 'block'
15001 // to later in flowgraph
15003 // We set bStart to the first block that will be relocated
15004 // and bEnd to the last block that will be relocated
15006 BasicBlock* bStart = block;
15007 BasicBlock* bEnd = bStart;
15008 bNext = bEnd->bbNext;
15009 bool connected_bDest = false;
15011 if ((backwardBranch && !isRare) ||
15012 ((block->bbFlags & BBF_DONT_REMOVE) != 0)) // Don't choose option #1 when block is the start of a try region
15021 // Don't try to split a Call/Always pair
15023 if (bEnd->isBBCallAlwaysPair())
15025 // Move bEnd and bNext forward
15027 bNext = bNext->bbNext;
15031 // Check for loop exit condition
15033 if (bNext == nullptr)
15038 #if FEATURE_EH_FUNCLETS
15039 // Check if we've reached the funclets region, at the end of the function
15040 if (fgFirstFuncletBB == bEnd->bbNext)
15044 #endif // FEATURE_EH_FUNCLETS
15046 if (bNext == bDest)
15048 connected_bDest = true;
15052 // All the blocks must have the same try index
15053 // and must not have the BBF_DONT_REMOVE flag set
15055 if (!BasicBlock::sameTryRegion(bStart, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
15057 // exit the loop, bEnd is now set to the
15058 // last block that we want to relocate
15062 // If we are relocating rarely run blocks..
15065 // ... then all blocks must be rarely run
15066 if (!bNext->isRunRarely())
15068 // exit the loop, bEnd is now set to the
15069 // last block that we want to relocate
15075 // If we are moving blocks that are hot then all
15076 // of the blocks moved must be less than profHotWeight */
15077 if (bNext->bbWeight >= profHotWeight)
15079 // exit the loop, bEnd is now set to the
15080 // last block that we would relocate
15085 // Move bEnd and bNext forward
15087 bNext = bNext->bbNext;
15090 // Set connected_bDest to true if moving blocks [bStart .. bEnd]
15091 // connects with the the jump dest of bPrev (i.e bDest) and
15092 // thus allows bPrev fall through instead of jump.
15093 if (bNext == bDest)
15095 connected_bDest = true;
15099 // Now consider option #2: Moving the jump dest block (or blocks)
15102 // The variables bStart2, bEnd2 and bPrev2 are used for option #2
15104 // We will setup bStart2 to the first block that will be relocated
15105 // and bEnd2 to the last block that will be relocated
15106 // and bPrev2 to be the lexical pred of bDest
15108 // If after this calculation bStart2 is NULL we cannot use option #2,
15109 // otherwise bStart2, bEnd2 and bPrev2 are all non-NULL and we will use option #2
15111 BasicBlock* bStart2 = nullptr;
15112 BasicBlock* bEnd2 = nullptr;
15113 BasicBlock* bPrev2 = nullptr;
15115 // If option #1 didn't connect bDest and bDest isn't NULL
15116 if ((connected_bDest == false) && (bDest != nullptr) &&
15117 // The jump target cannot be moved if it has the BBF_DONT_REMOVE flag set
15118 ((bDest->bbFlags & BBF_DONT_REMOVE) == 0))
15120 // We will consider option #2: relocating blocks starting at 'bDest' to succeed bPrev
15122 // setup bPrev2 to be the lexical pred of bDest
15125 while (bPrev2 != nullptr)
15127 if (bPrev2->bbNext == bDest)
15132 bPrev2 = bPrev2->bbNext;
15135 if ((bPrev2 != nullptr) && fgEhAllowsMoveBlock(bPrev, bDest))
15137 // We have decided that relocating bDest to be after bPrev is best
15138 // Set bStart2 to the first block that will be relocated
15139 // and bEnd2 to the last block that will be relocated
15141 // Assigning to bStart2 selects option #2
15145 bNext = bEnd2->bbNext;
15149 // Don't try to split a Call/Always pair
15151 if (bEnd2->isBBCallAlwaysPair())
15153 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
15154 // Move bEnd2 and bNext forward
15156 bNext = bNext->bbNext;
15159 // Check for the Loop exit conditions
15161 if (bNext == nullptr)
15166 if (bEnd2->bbFallsThrough() == false)
15171 // If we are relocating rarely run blocks..
15172 // All the blocks must have the same try index,
15173 // and must not have the BBF_DONT_REMOVE flag set
15175 if (!BasicBlock::sameTryRegion(bStart2, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
15177 // exit the loop, bEnd2 is now set to the
15178 // last block that we want to relocate
15184 /* ... then all blocks must not be rarely run */
15185 if (bNext->isRunRarely())
15187 // exit the loop, bEnd2 is now set to the
15188 // last block that we want to relocate
15194 // If we are relocating hot blocks
15195 // all blocks moved must be greater than profHotWeight
15196 if (bNext->bbWeight <= profHotWeight)
15198 // exit the loop, bEnd2 is now set to the
15199 // last block that we want to relocate
15204 // Move bEnd2 and bNext forward
15206 bNext = bNext->bbNext;
15211 // If we are using option #1 then ...
15212 if (bStart2 == nullptr)
15214 // Don't use option #1 for a backwards branch
15215 if (bStart == nullptr)
15220 // .... Don't move a set of blocks that are already at the end of the main method
15221 if (bEnd == fgLastBBInMainFunction())
15230 if (bDest != nullptr)
15232 if (bPrev->bbJumpKind == BBJ_COND)
15234 printf("Decided to reverse conditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
15237 else if (bPrev->bbJumpKind == BBJ_ALWAYS)
15239 printf("Decided to straighten unconditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
15244 printf("Decided to place hot code after BB%02u, placed BB%02u after this block ", bPrev->bbNum,
15248 if (profHotWeight > 0)
15250 printf("because of IBC profile data\n");
15254 if (bPrev->bbFallsThrough())
15256 printf("since it falls into a rarely run block\n");
15260 printf("since it is succeeded by a rarely run block\n");
15266 printf("Decided to relocate block(s) after block BB%02u since they are %s block(s)\n", bPrev->bbNum,
15267 block->isRunRarely() ? "rarely run" : "uncommonly run");
15272 // We will set insertAfterBlk to the block the precedes our insertion range
15273 // We will set bStartPrev to be the block that precedes the set of blocks that we are moving
15274 BasicBlock* insertAfterBlk;
15275 BasicBlock* bStartPrev;
15277 if (bStart2 != nullptr)
15279 // Option #2: relocating blocks starting at 'bDest' to follow bPrev
15281 // Update bStart and bEnd so that we can use these two for all later operations
15285 // Set bStartPrev to be the block that comes before bStart
15286 bStartPrev = bPrev2;
15288 // We will move [bStart..bEnd] to immediately after bPrev
15289 insertAfterBlk = bPrev;
15293 // option #1: Moving the fall-through blocks (or rarely run blocks) down to later in the method
15295 // Set bStartPrev to be the block that come before bStart
15296 bStartPrev = bPrev;
15298 // We will move [bStart..bEnd] but we will pick the insert location later
15299 insertAfterBlk = nullptr;
15302 // We are going to move [bStart..bEnd] so they can't be NULL
15303 noway_assert(bStart != nullptr);
15304 noway_assert(bEnd != nullptr);
15306 // bEnd can't be a BBJ_CALLFINALLY unless it is a RETLESS call
15307 noway_assert((bEnd->bbJumpKind != BBJ_CALLFINALLY) || (bEnd->bbFlags & BBF_RETLESS_CALL));
15309 // bStartPrev must be set to the block that precedes bStart
15310 noway_assert(bStartPrev->bbNext == bStart);
15312 // Since we will be unlinking [bStart..bEnd],
15313 // we need to compute and remember if bStart is in each of
15314 // the try and handler regions
15316 bool* fStartIsInTry = nullptr;
15317 bool* fStartIsInHnd = nullptr;
15319 if (compHndBBtabCount > 0)
15321 fStartIsInTry = new (this, CMK_Unknown) bool[compHndBBtabCount];
15322 fStartIsInHnd = new (this, CMK_Unknown) bool[compHndBBtabCount];
15324 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
15326 fStartIsInTry[XTnum] = HBtab->InTryRegionBBRange(bStart);
15327 fStartIsInHnd[XTnum] = HBtab->InHndRegionBBRange(bStart);
15331 /* Temporarily unlink [bStart..bEnd] from the flow graph */
15332 fgUnlinkRange(bStart, bEnd);
15334 if (insertAfterBlk == nullptr)
15336 // Find new location for the unlinked block(s)
15337 // Set insertAfterBlk to the block which will precede the insertion point
15339 if (!bStart->hasTryIndex() && isRare)
15341 // We'll just insert the blocks at the end of the method. If the method
15342 // has funclets, we will insert at the end of the main method but before
15343 // any of the funclets. Note that we create funclets before we call
15344 // fgReorderBlocks().
15346 insertAfterBlk = fgLastBBInMainFunction();
15347 noway_assert(insertAfterBlk != bPrev);
15351 BasicBlock* startBlk;
15352 BasicBlock* lastBlk;
15353 EHblkDsc* ehDsc = ehInitTryBlockRange(bStart, &startBlk, &lastBlk);
15355 BasicBlock* endBlk;
15357 /* Setup startBlk and endBlk as the range to search */
15359 if (ehDsc != nullptr)
15361 endBlk = lastBlk->bbNext;
15364 Multiple (nested) try regions might start from the same BB.
15368 |--- |--- |--- BB01
15372 | |------------ BB05
15374 |------------------- BB07
15376 Now if we want to insert in try2 region, we will start with startBlk=BB01.
15377 The following loop will allow us to start from startBlk==BB04.
15379 while (!BasicBlock::sameTryRegion(startBlk, bStart) && (startBlk != endBlk))
15381 startBlk = startBlk->bbNext;
15384 // startBlk cannot equal endBlk as it must come before endBlk
15385 if (startBlk == endBlk)
15390 // we also can't start searching the try region at bStart
15391 if (startBlk == bStart)
15393 // if bEnd is the last block in the method or
15394 // or if bEnd->bbNext is in a different try region
15395 // then we cannot move the blocks
15397 if ((bEnd->bbNext == nullptr) || !BasicBlock::sameTryRegion(startBlk, bEnd->bbNext))
15402 startBlk = bEnd->bbNext;
15404 // Check that the new startBlk still comes before endBlk
15406 // startBlk cannot equal endBlk as it must come before endBlk
15407 if (startBlk == endBlk)
15412 BasicBlock* tmpBlk = startBlk;
15413 while ((tmpBlk != endBlk) && (tmpBlk != nullptr))
15415 tmpBlk = tmpBlk->bbNext;
15418 // when tmpBlk is NULL that means startBlk is after endBlk
15419 // so there is no way to move bStart..bEnd within the try region
15420 if (tmpBlk == nullptr)
15428 noway_assert(isRare == false);
15430 /* We'll search through the entire main method */
15431 startBlk = fgFirstBB;
15432 endBlk = fgEndBBAfterMainFunction();
15435 // Calculate nearBlk and jumpBlk and then call fgFindInsertPoint()
15436 // to find our insertion block
15439 // If the set of blocks that we are moving ends with a BBJ_ALWAYS to
15440 // another [rarely run] block that comes after bPrev (forward branch)
15441 // then we can set up nearBlk to eliminate this jump sometimes
15443 BasicBlock* nearBlk = nullptr;
15444 BasicBlock* jumpBlk = nullptr;
15446 if ((bEnd->bbJumpKind == BBJ_ALWAYS) && (!isRare || bEnd->bbJumpDest->isRunRarely()) &&
15447 fgIsForwardBranch(bEnd, bPrev))
15449 // Set nearBlk to be the block in [startBlk..endBlk]
15450 // such that nearBlk->bbNext == bEnd->JumpDest
15451 // if no such block exists then set nearBlk to NULL
15452 nearBlk = startBlk;
15456 // We do not want to set nearBlk to bPrev
15457 // since then we will not move [bStart..bEnd]
15459 if (nearBlk != bPrev)
15461 // Check if nearBlk satisfies our requirement
15462 if (nearBlk->bbNext == bEnd->bbJumpDest)
15468 // Did we reach the endBlk?
15469 if (nearBlk == endBlk)
15475 // advance nearBlk to the next block
15476 nearBlk = nearBlk->bbNext;
15478 } while (nearBlk != nullptr);
15481 // if nearBlk is NULL then we set nearBlk to be the
15482 // first block that we want to insert after.
15483 if (nearBlk == nullptr)
15485 if (bDest != nullptr)
15487 // we want to insert after bDest
15492 // we want to insert after bPrev
15497 /* Set insertAfterBlk to the block which we will insert after. */
15500 fgFindInsertPoint(bStart->bbTryIndex,
15501 true, // Insert in the try region.
15502 startBlk, endBlk, nearBlk, jumpBlk, bStart->bbWeight == BB_ZERO_WEIGHT);
15505 /* See if insertAfterBlk is the same as where we started, */
15506 /* or if we could not find any insertion point */
15508 if ((insertAfterBlk == bPrev) || (insertAfterBlk == nullptr))
15511 /* We couldn't move the blocks, so put everything back */
15512 /* relink [bStart .. bEnd] into the flow graph */
15514 bPrev->setNext(bStart);
15517 bEnd->bbNext->bbPrev = bEnd;
15522 if (bStart != bEnd)
15524 printf("Could not relocate blocks (BB%02u .. BB%02u)\n", bStart->bbNum, bEnd->bbNum);
15528 printf("Could not relocate block BB%02u\n", bStart->bbNum);
15537 noway_assert(insertAfterBlk != nullptr);
15538 noway_assert(bStartPrev != nullptr);
15539 noway_assert(bStartPrev != insertAfterBlk);
15542 movedBlocks = true;
15547 if (bStart2 != nullptr)
15555 msg = "rarely run";
15563 printf("Relocated %s ", msg);
15564 if (bStart != bEnd)
15566 printf("blocks (BB%02u .. BB%02u)", bStart->bbNum, bEnd->bbNum);
15570 printf("block BB%02u", bStart->bbNum);
15573 if (bPrev->bbJumpKind == BBJ_COND)
15575 printf(" by reversing conditional jump at BB%02u\n", bPrev->bbNum);
15579 printf("\n", bPrev->bbNum);
15584 if (bPrev->bbJumpKind == BBJ_COND)
15586 /* Reverse the bPrev jump condition */
15587 GenTree* condTest = bPrev->lastStmt();
15589 condTest = condTest->gtStmt.gtStmtExpr;
15590 noway_assert(condTest->gtOper == GT_JTRUE);
15592 condTest->gtOp.gtOp1 = gtReverseCond(condTest->gtOp.gtOp1);
15594 if (bStart2 == nullptr)
15596 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
15597 bPrev->bbJumpDest = bStart;
15598 bStart->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
15602 noway_assert(insertAfterBlk == bPrev);
15603 noway_assert(insertAfterBlk->bbNext == block);
15605 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
15606 bPrev->bbJumpDest = block;
15607 block->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
15611 // If we are moving blocks that are at the end of a try or handler
15612 // we will need to shorten ebdTryLast or ebdHndLast
15614 ehUpdateLastBlocks(bEnd, bStartPrev);
15616 // If we are moving blocks into the end of a try region or handler region
15617 // we will need to extend ebdTryLast or ebdHndLast so the blocks that we
15618 // are moving are part of this try or handler region.
15620 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
15622 // Are we moving blocks to the end of a try region?
15623 if (HBtab->ebdTryLast == insertAfterBlk)
15625 if (fStartIsInTry[XTnum])
15627 // bStart..bEnd is in the try, so extend the try region
15628 fgSetTryEnd(HBtab, bEnd);
15632 // Are we moving blocks to the end of a handler region?
15633 if (HBtab->ebdHndLast == insertAfterBlk)
15635 if (fStartIsInHnd[XTnum])
15637 // bStart..bEnd is in the handler, so extend the handler region
15638 fgSetHndEnd(HBtab, bEnd);
15643 /* We have decided to insert the block(s) after 'insertAfterBlk' */
15644 fgMoveBlocksAfter(bStart, bEnd, insertAfterBlk);
15648 /* We may need to insert an unconditional branch after bPrev to bDest */
15649 fgConnectFallThrough(bPrev, bDest);
15653 /* If bPrev falls through, we must insert a jump to block */
15654 fgConnectFallThrough(bPrev, block);
15657 BasicBlock* bSkip = bEnd->bbNext;
15659 /* If bEnd falls through, we must insert a jump to bNext */
15660 fgConnectFallThrough(bEnd, bNext);
15662 if (bStart2 == nullptr)
15664 /* If insertAfterBlk falls through, we are forced to */
15665 /* add a jump around the block(s) we just inserted */
15666 fgConnectFallThrough(insertAfterBlk, bSkip);
15670 /* We may need to insert an unconditional branch after bPrev2 to bStart */
15671 fgConnectFallThrough(bPrev2, bStart);
15677 printf("\nAfter this change in fgReorderBlocks");
15678 fgDispBasicBlocks(verboseTrees);
15681 fgVerifyHandlerTab();
15683 // Make sure that the predecessor lists are accurate
15684 if (expensiveDebugCheckLevel >= 2)
15686 fgDebugCheckBBlist();
15690 // Set our iteration point 'block' to be the new bPrev->bbNext
15691 // It will be used as the next bPrev
15692 block = bPrev->bbNext;
15694 } // end of for loop(bPrev,block)
15696 bool changed = movedBlocks || newRarelyRun || optimizedSwitches;
15700 fgNeedsUpdateFlowGraph = true;
15702 // Make sure that the predecessor lists are accurate
15703 if (expensiveDebugCheckLevel >= 2)
15705 fgDebugCheckBBlist();
15711 #pragma warning(pop)
15714 /*-------------------------------------------------------------------------
15716 * Walk the basic blocks list to determine the first block to place in the
15717 * cold section. This would be the first of a series of rarely executed blocks
15718 * such that no succeeding blocks are in a try region or an exception handler
15719 * or are rarely executed.
15722 void Compiler::fgDetermineFirstColdBlock()
15727 printf("\n*************** In fgDetermineFirstColdBlock()\n");
15731 // Since we may need to create a new transistion block
15732 // we assert that it is OK to create new blocks.
15734 assert(fgSafeBasicBlockCreation);
15736 fgFirstColdBlock = nullptr;
15738 #if FEATURE_STACK_FP_X87
15739 if (compMayHaveTransitionBlocks)
15741 opts.compProcedureSplitting = false;
15743 // See comment above declaration of compMayHaveTransitionBlocks for comments on this
15744 JITDUMP("Turning off procedure splitting for this method, as it may end up having FP transition blocks\n");
15746 #endif // FEATURE_STACK_FP_X87
15748 if (!opts.compProcedureSplitting)
15750 JITDUMP("No procedure splitting will be done for this method\n");
15755 if ((compHndBBtabCount > 0) && !opts.compProcedureSplittingEH)
15757 JITDUMP("No procedure splitting will be done for this method with EH (by request)\n");
15762 #if FEATURE_EH_FUNCLETS
15763 // TODO-CQ: handle hot/cold splitting in functions with EH (including synchronized methods
15764 // that create EH in methods without explicit EH clauses).
15766 if (compHndBBtabCount > 0)
15768 JITDUMP("No procedure splitting will be done for this method with EH (implementation limitation)\n");
15771 #endif // FEATURE_EH_FUNCLETS
15773 BasicBlock* firstColdBlock = nullptr;
15774 BasicBlock* prevToFirstColdBlock = nullptr;
15778 for (lblk = nullptr, block = fgFirstBB; block != nullptr; lblk = block, block = block->bbNext)
15780 bool blockMustBeInHotSection = false;
15782 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
15783 if (bbIsHandlerBeg(block))
15785 blockMustBeInHotSection = true;
15787 #endif // HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
15789 // Do we have a candidate for the first cold block?
15790 if (firstColdBlock != nullptr)
15792 // We have a candidate for first cold block
15794 // Is this a hot block?
15795 if (blockMustBeInHotSection || (block->isRunRarely() == false))
15797 // We have to restart the search for the first cold block
15798 firstColdBlock = nullptr;
15799 prevToFirstColdBlock = nullptr;
15802 else // (firstColdBlock == NULL)
15804 // We don't have a candidate for first cold block
15806 // Is this a cold block?
15807 if (!blockMustBeInHotSection && (block->isRunRarely() == true))
15810 // If the last block that was hot was a BBJ_COND
15811 // then we will have to add an unconditional jump
15812 // so the code size for block needs be large
15813 // enough to make it worth our while
15815 if ((lblk == nullptr) || (lblk->bbJumpKind != BBJ_COND) || (fgGetCodeEstimate(block) >= 8))
15817 // This block is now a candidate for first cold block
15818 // Also remember the predecessor to this block
15819 firstColdBlock = block;
15820 prevToFirstColdBlock = lblk;
15826 if (firstColdBlock == fgFirstBB)
15828 // If the first block is Cold then we can't move any blocks
15829 // into the cold section
15831 firstColdBlock = nullptr;
15834 if (firstColdBlock != nullptr)
15836 noway_assert(prevToFirstColdBlock != nullptr);
15838 if (prevToFirstColdBlock == nullptr)
15840 return; // To keep Prefast happy
15843 // If we only have one cold block
15844 // then it may not be worth it to move it
15845 // into the Cold section as a jump to the
15846 // Cold section is 5 bytes in size.
15848 if (firstColdBlock->bbNext == nullptr)
15850 // If the size of the cold block is 7 or less
15851 // then we will keep it in the Hot section.
15853 if (fgGetCodeEstimate(firstColdBlock) < 8)
15855 firstColdBlock = nullptr;
15860 // When the last Hot block fall through into the Cold section
15861 // we may need to add a jump
15863 if (prevToFirstColdBlock->bbFallsThrough())
15865 switch (prevToFirstColdBlock->bbJumpKind)
15868 noway_assert(!"Unhandled jumpkind in fgDetermineFirstColdBlock()");
15870 case BBJ_CALLFINALLY:
15871 // A BBJ_CALLFINALLY that falls through is always followed
15872 // by an empty BBJ_ALWAYS.
15874 assert(prevToFirstColdBlock->isBBCallAlwaysPair());
15876 firstColdBlock->bbNext; // Note that this assignment could make firstColdBlock == nullptr
15881 // This is a slightly more complicated case, because we will
15882 // probably need to insert a block to jump to the cold section.
15884 if (firstColdBlock->isEmpty() && (firstColdBlock->bbJumpKind == BBJ_ALWAYS))
15886 // We can just use this block as the transitionBlock
15887 firstColdBlock = firstColdBlock->bbNext;
15888 // Note that this assignment could make firstColdBlock == NULL
15892 BasicBlock* transitionBlock = fgNewBBafter(BBJ_ALWAYS, prevToFirstColdBlock, true);
15893 transitionBlock->bbJumpDest = firstColdBlock;
15894 transitionBlock->inheritWeight(firstColdBlock);
15896 noway_assert(fgComputePredsDone);
15898 // Update the predecessor list for firstColdBlock
15899 fgReplacePred(firstColdBlock, prevToFirstColdBlock, transitionBlock);
15901 // Add prevToFirstColdBlock as a predecessor for transitionBlock
15902 fgAddRefPred(transitionBlock, prevToFirstColdBlock);
15907 // If the block preceding the first cold block is BBJ_NONE,
15908 // convert it to BBJ_ALWAYS to force an explicit jump.
15910 prevToFirstColdBlock->bbJumpDest = firstColdBlock;
15911 prevToFirstColdBlock->bbJumpKind = BBJ_ALWAYS;
15917 if (firstColdBlock != nullptr)
15919 firstColdBlock->bbFlags |= BBF_JMP_TARGET;
15921 for (block = firstColdBlock; block; block = block->bbNext)
15923 block->bbFlags |= BBF_COLD;
15932 if (firstColdBlock)
15934 printf("fgFirstColdBlock is BB%02u.\n", firstColdBlock->bbNum);
15938 printf("fgFirstColdBlock is NULL.\n");
15941 fgDispBasicBlocks();
15944 fgVerifyHandlerTab();
15947 fgFirstColdBlock = firstColdBlock;
15951 #pragma warning(push)
15952 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
15954 /*****************************************************************************
15956 * Function called to "comb" the basic block list.
15957 * Removes any empty blocks, unreachable blocks and redundant jumps.
15958 * Most of those appear after dead store removal and folding of conditionals.
15960 * Returns: true if the flowgraph has been modified
15962 * It also compacts basic blocks
15963 * (consecutive basic blocks that should in fact be one).
15966 * Debuggable code and Min Optimization JIT also introduces basic blocks
15967 * but we do not optimize those!
15970 bool Compiler::fgUpdateFlowGraph(bool doTailDuplication)
15975 printf("\n*************** In fgUpdateFlowGraph()");
15979 /* This should never be called for debuggable code */
15981 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
15986 printf("\nBefore updating the flow graph:\n");
15987 fgDispBasicBlocks(verboseTrees);
15992 /* Walk all the basic blocks - look for unconditional jumps, empty blocks, blocks to compact, etc...
15995 * Once a block is removed the predecessors are not accurate (assuming they were at the beginning)
15996 * For now we will only use the information in bbRefs because it is easier to be updated
15999 bool modified = false;
16005 BasicBlock* block; // the current block
16006 BasicBlock* bPrev = nullptr; // the previous non-worthless block
16007 BasicBlock* bNext; // the successor of the current block
16008 BasicBlock* bDest; // the jump target of the current block
16010 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
16012 /* Some blocks may be already marked removed by other optimizations
16013 * (e.g worthless loop removal), without being explicitly removed
16017 if (block->bbFlags & BBF_REMOVED)
16021 bPrev->setNext(block->bbNext);
16025 /* WEIRD first basic block is removed - should have an assert here */
16026 noway_assert(!"First basic block marked as BBF_REMOVED???");
16028 fgFirstBB = block->bbNext;
16033 /* We jump to the REPEAT label if we performed a change involving the current block
16034 * This is in case there are other optimizations that can show up
16035 * (e.g. - compact 3 blocks in a row)
16036 * If nothing happens, we then finish the iteration and move to the next block
16041 bNext = block->bbNext;
16044 if (block->bbJumpKind == BBJ_ALWAYS)
16046 bDest = block->bbJumpDest;
16047 if (doTailDuplication && fgOptimizeUncondBranchToSimpleCond(block, bDest))
16051 bDest = block->bbJumpDest;
16052 bNext = block->bbNext;
16056 // Remove JUMPS to the following block
16057 // and optimize any JUMPS to JUMPS
16059 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
16061 bDest = block->bbJumpDest;
16062 if (bDest == bNext)
16064 if (fgOptimizeBranchToNext(block, bNext, bPrev))
16073 if (bDest != nullptr)
16075 // Do we have a JUMP to an empty unconditional JUMP block?
16076 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
16077 (bDest != bDest->bbJumpDest)) // special case for self jumps
16079 if (fgOptimizeBranchToEmptyUnconditional(block, bDest))
16087 // Check for a conditional branch that just skips over an empty BBJ_ALWAYS block
16089 if ((block->bbJumpKind == BBJ_COND) && // block is a BBJ_COND block
16090 (bNext != nullptr) && // block is not the last block
16091 (bNext->bbRefs == 1) && // No other block jumps to bNext
16092 (bNext->bbNext == bDest) && // The block after bNext is the BBJ_COND jump dest
16093 (bNext->bbJumpKind == BBJ_ALWAYS) && // The next block is a BBJ_ALWAYS block
16094 bNext->isEmpty() && // and it is an an empty block
16095 (bNext != bNext->bbJumpDest) && // special case for self jumps
16096 (bDest != fgFirstColdBlock))
16098 bool optimizeJump = true;
16100 // We do not optimize jumps between two different try regions.
16101 // However jumping to a block that is not in any try region is OK
16103 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
16105 optimizeJump = false;
16108 // Also consider bNext's try region
16110 if (bNext->hasTryIndex() && !BasicBlock::sameTryRegion(block, bNext))
16112 optimizeJump = false;
16115 // If we are optimizing using real profile weights
16116 // then don't optimize a conditional jump to an unconditional jump
16117 // until after we have computed the edge weights
16119 if (fgIsUsingProfileWeights())
16121 // if block and bdest are in different hot/cold regions we can't do this this optimization
16122 // because we can't allow fall-through into the cold region.
16123 if (!fgEdgeWeightsComputed || fgInDifferentRegions(block, bDest))
16125 fgNeedsUpdateFlowGraph = true;
16126 optimizeJump = false;
16135 printf("\nReversing a conditional jump around an unconditional jump (BB%02u -> BB%02u -> "
16137 block->bbNum, bDest->bbNum, bNext->bbJumpDest->bbNum);
16140 /* Reverse the jump condition */
16142 GenTree* test = block->lastNode();
16143 noway_assert(test->OperIsConditionalJump());
16145 if (test->OperGet() == GT_JTRUE)
16147 GenTree* cond = gtReverseCond(test->gtOp.gtOp1);
16148 assert(cond == test->gtOp.gtOp1); // Ensure `gtReverseCond` did not create a new node.
16149 test->gtOp.gtOp1 = cond;
16153 gtReverseCond(test);
16156 // Optimize the Conditional JUMP to go to the new target
16157 block->bbJumpDest = bNext->bbJumpDest;
16159 fgAddRefPred(bNext->bbJumpDest, block, fgRemoveRefPred(bNext->bbJumpDest, bNext));
16162 Unlink bNext from the BasicBlock list; note that we can
16163 do this even though other blocks could jump to it - the
16164 reason is that elsewhere in this function we always
16165 redirect jumps to jumps to jump to the final label,
16166 so even if another block jumps to bNext it won't matter
16167 once we're done since any such jump will be redirected
16168 to the final target by the time we're done here.
16171 fgRemoveRefPred(bNext, block);
16172 fgUnlinkBlock(bNext);
16174 /* Mark the block as removed */
16175 bNext->bbFlags |= BBF_REMOVED;
16177 // If this is the first Cold basic block update fgFirstColdBlock
16178 if (bNext == fgFirstColdBlock)
16180 fgFirstColdBlock = bNext->bbNext;
16184 // If we removed the end of a try region or handler region
16185 // we will need to update ebdTryLast or ebdHndLast.
16189 EHblkDsc* HBtabEnd;
16191 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd;
16194 if ((HBtab->ebdTryLast == bNext) || (HBtab->ebdHndLast == bNext))
16196 fgSkipRmvdBlocks(HBtab);
16200 // we optimized this JUMP - goto REPEAT to catch similar cases
16207 printf("\nAfter reversing the jump:\n");
16208 fgDispBasicBlocks(verboseTrees);
16213 For a rare special case we cannot jump to REPEAT
16214 as jumping to REPEAT will cause us to delete 'block'
16215 because it currently appears to be unreachable. As
16216 it is a self loop that only has a single bbRef (itself)
16217 However since the unlinked bNext has additional bbRefs
16218 (that we will later connect to 'block'), it is not really
16221 if ((bNext->bbRefs > 0) && (bNext->bbJumpDest == block) && (block->bbRefs == 1))
16232 // Update the switch jump table such that it follows jumps to jumps:
16234 if (block->bbJumpKind == BBJ_SWITCH)
16236 if (fgOptimizeSwitchBranches(block))
16244 noway_assert(!(block->bbFlags & BBF_REMOVED));
16246 /* COMPACT blocks if possible */
16248 if (fgCanCompactBlocks(block, bNext))
16250 fgCompactBlocks(block, bNext);
16252 /* we compacted two blocks - goto REPEAT to catch similar cases */
16258 /* Remove unreachable or empty blocks - do not consider blocks marked BBF_DONT_REMOVE or genReturnBB block
16259 * These include first and last block of a TRY, exception handlers and RANGE_CHECK_FAIL THROW blocks */
16261 if ((block->bbFlags & BBF_DONT_REMOVE) == BBF_DONT_REMOVE || block == genReturnBB)
16267 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16268 // Don't remove the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair.
16269 if (block->countOfInEdges() == 0 && bPrev->bbJumpKind == BBJ_CALLFINALLY)
16271 assert(bPrev->isBBCallAlwaysPair());
16272 noway_assert(!(bPrev->bbFlags & BBF_RETLESS_CALL));
16273 noway_assert(block->bbJumpKind == BBJ_ALWAYS);
16277 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16279 noway_assert(!block->bbCatchTyp);
16280 noway_assert(!(block->bbFlags & BBF_TRY_BEG));
16282 /* Remove unreachable blocks
16284 * We'll look for blocks that have countOfInEdges() = 0 (blocks may become
16285 * unreachable due to a BBJ_ALWAYS introduced by conditional folding for example)
16288 if (block->countOfInEdges() == 0)
16290 /* no references -> unreachable - remove it */
16291 /* For now do not update the bbNum, do it at the end */
16293 fgRemoveBlock(block, true);
16298 /* we removed the current block - the rest of the optimizations won't have a target
16299 * continue with the next one */
16303 else if (block->countOfInEdges() == 1)
16305 switch (block->bbJumpKind)
16309 if (block->bbJumpDest == block)
16311 fgRemoveBlock(block, true);
16316 /* we removed the current block - the rest of the optimizations
16317 * won't have a target so continue with the next block */
16328 noway_assert(!(block->bbFlags & BBF_REMOVED));
16330 /* Remove EMPTY blocks */
16332 if (block->isEmpty())
16334 assert(bPrev == block->bbPrev);
16335 if (fgOptimizeEmptyBlock(block))
16341 /* Have we removed the block? */
16343 if (block->bbFlags & BBF_REMOVED)
16345 /* block was removed - no change to bPrev */
16350 /* Set the predecessor of the last reachable block
16351 * If we removed the current block, the predecessor remains unchanged
16352 * otherwise, since the current block is ok, it becomes the predecessor */
16354 noway_assert(!(block->bbFlags & BBF_REMOVED));
16360 fgNeedsUpdateFlowGraph = false;
16363 if (verbose && modified)
16365 printf("\nAfter updating the flow graph:\n");
16366 fgDispBasicBlocks(verboseTrees);
16367 fgDispHandlerTab();
16370 if (compRationalIRForm)
16372 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
16374 LIR::AsRange(block).CheckLIR(this);
16378 fgVerifyHandlerTab();
16379 // Make sure that the predecessor lists are accurate
16380 fgDebugCheckBBlist();
16381 fgDebugCheckUpdate();
16387 #pragma warning(pop)
16390 /*****************************************************************************
16391 * Check that the flow graph is really updated
16396 void Compiler::fgDebugCheckUpdate()
16398 if (!compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
16403 /* We check for these conditions:
16404 * no unreachable blocks -> no blocks have countOfInEdges() = 0
16405 * no empty blocks -> no blocks have bbTreeList = 0
16406 * no un-imported blocks -> no blocks have BBF_IMPORTED not set (this is
16407 * kind of redundand with the above, but to make sure)
16408 * no un-compacted blocks -> BBJ_NONE followed by block with no jumps to it (countOfInEdges() = 1)
16413 for (prev = nullptr, block = fgFirstBB; block != nullptr; prev = block, block = block->bbNext)
16415 /* no unreachable blocks */
16417 if ((block->countOfInEdges() == 0) && !(block->bbFlags & BBF_DONT_REMOVE)
16418 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16419 // With funclets, we never get rid of the BBJ_ALWAYS part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
16420 // even if we can prove that the finally block never returns.
16421 && (prev == NULL || block->bbJumpKind != BBJ_ALWAYS || !prev->isBBCallAlwaysPair())
16422 #endif // FEATURE_EH_FUNCLETS
16425 noway_assert(!"Unreachable block not removed!");
16428 /* no empty blocks */
16430 if (block->isEmpty() && !(block->bbFlags & BBF_DONT_REMOVE))
16432 switch (block->bbJumpKind)
16434 case BBJ_CALLFINALLY:
16435 case BBJ_EHFINALLYRET:
16436 case BBJ_EHFILTERRET:
16438 /* for BBJ_ALWAYS is probably just a GOTO, but will have to be treated */
16440 case BBJ_EHCATCHRET:
16441 /* These jump kinds are allowed to have empty tree lists */
16445 /* it may be the case that the block had more than one reference to it
16446 * so we couldn't remove it */
16448 if (block->countOfInEdges() == 0)
16450 noway_assert(!"Empty block not removed!");
16456 /* no un-imported blocks */
16458 if (!(block->bbFlags & BBF_IMPORTED))
16460 /* internal blocks do not count */
16462 if (!(block->bbFlags & BBF_INTERNAL))
16464 noway_assert(!"Non IMPORTED block not removed!");
16468 bool prevIsCallAlwaysPair = ((prev != nullptr) && prev->isBBCallAlwaysPair());
16470 // Check for an unnecessary jumps to the next block
16471 bool doAssertOnJumpToNextBlock = false; // unless we have a BBJ_COND or BBJ_ALWAYS we can not assert
16473 if (block->bbJumpKind == BBJ_COND)
16475 // A conditional branch should never jump to the next block
16476 // as it can be folded into a BBJ_NONE;
16477 doAssertOnJumpToNextBlock = true;
16479 else if (block->bbJumpKind == BBJ_ALWAYS)
16481 // Generally we will want to assert if a BBJ_ALWAYS branches to the next block
16482 doAssertOnJumpToNextBlock = true;
16484 // If the BBF_KEEP_BBJ_ALWAYS flag is set we allow it to jump to the next block
16485 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
16487 doAssertOnJumpToNextBlock = false;
16490 // A call/always pair is also allowed to jump to the next block
16491 if (prevIsCallAlwaysPair)
16493 doAssertOnJumpToNextBlock = false;
16496 // We are allowed to have a branch from a hot 'block' to a cold 'bbNext'
16498 if ((block->bbNext != nullptr) && fgInDifferentRegions(block, block->bbNext))
16500 doAssertOnJumpToNextBlock = false;
16504 if (doAssertOnJumpToNextBlock)
16506 if (block->bbJumpDest == block->bbNext)
16508 noway_assert(!"Unnecessary jump to the next block!");
16512 /* Make sure BBF_KEEP_BBJ_ALWAYS is set correctly */
16514 if ((block->bbJumpKind == BBJ_ALWAYS) && prevIsCallAlwaysPair)
16516 noway_assert(block->bbFlags & BBF_KEEP_BBJ_ALWAYS);
16519 /* For a BBJ_CALLFINALLY block we make sure that we are followed by */
16520 /* an BBJ_ALWAYS block with BBF_INTERNAL set */
16521 /* or that it's a BBF_RETLESS_CALL */
16522 if (block->bbJumpKind == BBJ_CALLFINALLY)
16524 assert((block->bbFlags & BBF_RETLESS_CALL) || block->isBBCallAlwaysPair());
16527 /* no un-compacted blocks */
16529 if (fgCanCompactBlocks(block, block->bbNext))
16531 noway_assert(!"Found un-compacted blocks!");
16538 /*****************************************************************************
16539 * We've inserted a new block before 'block' that should be part of the same EH region as 'block'.
16540 * Update the EH table to make this so. Also, set the new block to have the right EH region data
16541 * (copy the bbTryIndex, bbHndIndex, and bbCatchTyp from 'block' to the new predecessor, and clear
16542 * 'bbCatchTyp' from 'block').
16544 void Compiler::fgExtendEHRegionBefore(BasicBlock* block)
16546 assert(block->bbPrev != nullptr);
16548 BasicBlock* bPrev = block->bbPrev;
16550 bPrev->copyEHRegion(block);
16552 // The first block (and only the first block) of a handler has bbCatchTyp set
16553 bPrev->bbCatchTyp = block->bbCatchTyp;
16554 block->bbCatchTyp = BBCT_NONE;
16557 EHblkDsc* HBtabEnd;
16559 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
16561 /* Multiple pointers in EHblkDsc can point to same block. We can not early out after the first match. */
16562 if (HBtab->ebdTryBeg == block)
16567 printf("EH#%u: New first block of try: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16570 HBtab->ebdTryBeg = bPrev;
16571 bPrev->bbFlags |= BBF_TRY_BEG | BBF_DONT_REMOVE | BBF_HAS_LABEL;
16572 // clear the TryBeg flag unless it begins another try region
16573 if (!bbIsTryBeg(block))
16575 block->bbFlags &= ~BBF_TRY_BEG;
16579 if (HBtab->ebdHndBeg == block)
16584 printf("EH#%u: New first block of handler: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16588 // The first block of a handler has an artificial extra refcount. Transfer that to the new block.
16589 assert(block->bbRefs > 0);
16592 HBtab->ebdHndBeg = bPrev;
16593 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
16596 // If this is a handler for a filter, the last block of the filter will end with
16597 // a BBJ_EJFILTERRET block that has a bbJumpDest that jumps to the first block of
16598 // it's handler. So we need to update it to keep things in sync.
16600 if (HBtab->HasFilter())
16602 BasicBlock* bFilterLast = HBtab->BBFilterLast();
16603 assert(bFilterLast != nullptr);
16604 assert(bFilterLast->bbJumpKind == BBJ_EHFILTERRET);
16605 assert(bFilterLast->bbJumpDest == block);
16609 printf("EH#%u: Updating bbJumpDest for filter ret block: BB%02u => BB%02u\n", ehGetIndex(HBtab),
16610 bFilterLast->bbNum, bPrev->bbNum);
16613 // Change the bbJumpDest for bFilterLast from the old first 'block' to the new first 'bPrev'
16614 bFilterLast->bbJumpDest = bPrev;
16618 if (HBtab->HasFilter() && (HBtab->ebdFilter == block))
16623 printf("EH#%u: New first block of filter: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
16627 // The first block of a filter has an artificial extra refcount. Transfer that to the new block.
16628 assert(block->bbRefs > 0);
16631 HBtab->ebdFilter = bPrev;
16632 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
16638 /*****************************************************************************
16639 * We've inserted a new block after 'block' that should be part of the same EH region as 'block'.
16640 * Update the EH table to make this so. Also, set the new block to have the right EH region data.
16643 void Compiler::fgExtendEHRegionAfter(BasicBlock* block)
16645 BasicBlock* newBlk = block->bbNext;
16646 assert(newBlk != nullptr);
16648 newBlk->copyEHRegion(block);
16649 newBlk->bbCatchTyp =
16650 BBCT_NONE; // Only the first block of a catch has this set, and 'newBlk' can't be the first block of a catch.
16652 // TODO-Throughput: if the block is not in an EH region, then we don't need to walk the EH table looking for 'last'
16653 // block pointers to update.
16654 ehUpdateLastBlocks(block, newBlk);
16657 /*****************************************************************************
16659 * Insert a BasicBlock before the given block.
16662 BasicBlock* Compiler::fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
16664 // Create a new BasicBlock and chain it in
16666 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
16667 newBlk->bbFlags |= BBF_INTERNAL;
16669 fgInsertBBbefore(block, newBlk);
16671 newBlk->bbRefs = 0;
16673 if (newBlk->bbFallsThrough() && block->isRunRarely())
16675 newBlk->bbSetRunRarely();
16680 fgExtendEHRegionBefore(block);
16684 // When extendRegion is false the caller is responsible for setting these two values
16685 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16686 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16689 // We assume that if the block we are inserting before is in the cold region, then this new
16690 // block will also be in the cold region.
16691 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
16696 /*****************************************************************************
16698 * Insert a BasicBlock after the given block.
16701 BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
16703 // Create a new BasicBlock and chain it in
16705 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
16706 newBlk->bbFlags |= BBF_INTERNAL;
16708 fgInsertBBafter(block, newBlk);
16710 newBlk->bbRefs = 0;
16712 if (block->bbFallsThrough() && block->isRunRarely())
16714 newBlk->bbSetRunRarely();
16719 fgExtendEHRegionAfter(block);
16723 // When extendRegion is false the caller is responsible for setting these two values
16724 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16725 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
16728 // If the new block is in the cold region (because the block we are inserting after
16729 // is in the cold region), mark it as such.
16730 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
16735 /*****************************************************************************
16736 * Inserts basic block before existing basic block.
16738 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
16739 * (If insertBeforeBlk is the first block of the funclet region, then 'newBlk' will be the
16740 * new first block of the funclet region.)
16742 void Compiler::fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk)
16744 if (insertBeforeBlk->bbPrev)
16746 fgInsertBBafter(insertBeforeBlk->bbPrev, newBlk);
16750 newBlk->setNext(fgFirstBB);
16752 fgFirstBB = newBlk;
16753 newBlk->bbPrev = nullptr;
16756 #if FEATURE_EH_FUNCLETS
16758 /* Update fgFirstFuncletBB if insertBeforeBlk is the first block of the funclet region. */
16760 if (fgFirstFuncletBB == insertBeforeBlk)
16762 fgFirstFuncletBB = newBlk;
16765 #endif // FEATURE_EH_FUNCLETS
16768 /*****************************************************************************
16769 * Inserts basic block after existing basic block.
16771 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
16772 * (It can't be used to insert a block as the first block of the funclet region).
16774 void Compiler::fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk)
16776 newBlk->bbNext = insertAfterBlk->bbNext;
16778 if (insertAfterBlk->bbNext)
16780 insertAfterBlk->bbNext->bbPrev = newBlk;
16783 insertAfterBlk->bbNext = newBlk;
16784 newBlk->bbPrev = insertAfterBlk;
16786 if (fgLastBB == insertAfterBlk)
16789 assert(fgLastBB->bbNext == nullptr);
16793 // We have two edges (bAlt => bCur) and (bCur => bNext).
16795 // Returns true if the weight of (bAlt => bCur)
16796 // is greater than the weight of (bCur => bNext).
16797 // We compare the edge weights if we have valid edge weights
16798 // otherwise we compare blocks weights.
16800 bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt)
16802 // bCur can't be NULL and must be a fall through bbJumpKind
16803 noway_assert(bCur != nullptr);
16804 noway_assert(bCur->bbFallsThrough());
16805 noway_assert(bAlt != nullptr);
16807 // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND
16808 if ((bAlt->bbJumpKind != BBJ_ALWAYS) && (bAlt->bbJumpKind != BBJ_COND))
16813 // if bAlt doesn't jump to bCur it can't be a better fall through than bCur
16814 if (bAlt->bbJumpDest != bCur)
16819 // Currently bNext is the fall through for bCur
16820 BasicBlock* bNext = bCur->bbNext;
16821 noway_assert(bNext != nullptr);
16823 // We will set result to true if bAlt is a better fall through than bCur
16825 if (fgHaveValidEdgeWeights)
16827 // We will compare the edge weight for our two choices
16828 flowList* edgeFromAlt = fgGetPredForBlock(bCur, bAlt);
16829 flowList* edgeFromCur = fgGetPredForBlock(bNext, bCur);
16830 noway_assert(edgeFromCur != nullptr);
16831 noway_assert(edgeFromAlt != nullptr);
16833 result = (edgeFromAlt->flEdgeWeightMin > edgeFromCur->flEdgeWeightMax);
16837 if (bAlt->bbJumpKind == BBJ_ALWAYS)
16839 // Our result is true if bAlt's weight is more than bCur's weight
16840 result = (bAlt->bbWeight > bCur->bbWeight);
16844 noway_assert(bAlt->bbJumpKind == BBJ_COND);
16845 // Our result is true if bAlt's weight is more than twice bCur's weight
16846 result = (bAlt->bbWeight > (2 * bCur->bbWeight));
16852 //------------------------------------------------------------------------
16853 // fgCheckEHCanInsertAfterBlock: Determine if a block can be inserted after
16854 // 'blk' and legally be put in the EH region specified by 'regionIndex'. This
16855 // can be true if the most nested region the block is in is already 'regionIndex',
16856 // as we'll just extend the most nested region (and any region ending at the same block).
16857 // It can also be true if it is the end of (a set of) EH regions, such that
16858 // inserting the block and properly extending some EH regions (if necessary)
16859 // puts the block in the correct region. We only consider the case of extending
16860 // an EH region after 'blk' (that is, to include 'blk' and the newly insert block);
16861 // we don't consider inserting a block as the the first block of an EH region following 'blk'.
16863 // Consider this example:
16870 // | |--- |--- BB05
16872 // |----------------- BB07
16874 // Passing BB05 and try1/try2/try3 as the region to insert into (as well as putInTryRegion==true)
16875 // will all return 'true'. Here are the cases:
16876 // 1. Insert into try1: the most nested EH region BB05 is in is already try1, so we can insert after
16877 // it and extend try1 (and try2).
16878 // 2. Insert into try2: we can extend try2, but leave try1 alone.
16879 // 3. Insert into try3: we can leave try1 and try2 alone, and put the new block just in try3. Note that
16880 // in this case, after we "loop outwards" in the EH nesting, we get to a place where we're in the middle
16881 // of the try3 region, not at the end of it.
16882 // In all cases, it is possible to put a block after BB05 and put it in any of these three 'try' regions legally.
16884 // Filters are ignored; if 'blk' is in a filter, the answer will be false.
16887 // blk - the BasicBlock we are checking to see if we can insert after.
16888 // regionIndex - the EH region we want to insert a block into. regionIndex is
16889 // in the range [0..compHndBBtabCount]; 0 means "main method".
16890 // putInTryRegion - 'true' if the new block should be inserted in the 'try' region of 'regionIndex'.
16891 // For regionIndex 0 (the "main method"), this should be 'true'.
16894 // 'true' if a block can be inserted after 'blk' and put in EH region 'regionIndex', else 'false'.
16896 bool Compiler::fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion)
16898 assert(blk != nullptr);
16899 assert(regionIndex <= compHndBBtabCount);
16901 if (regionIndex == 0)
16903 assert(putInTryRegion);
16907 unsigned nestedRegionIndex = ehGetMostNestedRegionIndex(blk, &inTryRegion);
16909 bool insertOK = true;
16912 if (nestedRegionIndex == regionIndex)
16914 // This block is in the region we want to be in. We can insert here if it's the right type of region.
16915 // (If we want to be in the 'try' region, but the block is in the handler region, then inserting a
16916 // new block after 'blk' can't put it in the 'try' region, and vice-versa, since we only consider
16917 // extending regions after, not prepending to regions.)
16918 // This check will be 'true' if we are trying to put something in the main function (as putInTryRegion
16919 // must be 'true' if regionIndex is zero, and inTryRegion will also be 'true' if nestedRegionIndex is zero).
16920 insertOK = (putInTryRegion == inTryRegion);
16923 else if (nestedRegionIndex == 0)
16925 // The block is in the main function, but we want to put something in a nested region. We can't do that.
16930 assert(nestedRegionIndex > 0);
16931 EHblkDsc* ehDsc = ehGetDsc(nestedRegionIndex - 1); // ehGetDsc uses [0..compHndBBtabCount) form.
16935 if (blk != ehDsc->ebdTryLast)
16937 // Not the last block? Then it must be somewhere else within the try region, so we can't insert here.
16939 break; // exit the 'for' loop
16944 // We ignore filters.
16945 if (blk != ehDsc->ebdHndLast)
16947 // Not the last block? Then it must be somewhere else within the handler region, so we can't insert
16950 break; // exit the 'for' loop
16954 // Things look good for this region; check the enclosing regions, if any.
16956 nestedRegionIndex =
16957 ehGetEnclosingRegionIndex(nestedRegionIndex - 1,
16958 &inTryRegion); // ehGetEnclosingRegionIndex uses [0..compHndBBtabCount) form.
16960 // Convert to [0..compHndBBtabCount] form.
16961 nestedRegionIndex = (nestedRegionIndex == EHblkDsc::NO_ENCLOSING_INDEX) ? 0 : nestedRegionIndex + 1;
16962 } // end of for(;;)
16967 //------------------------------------------------------------------------
16968 // Finds the block closest to endBlk in the range [startBlk..endBlk) after which a block can be
16969 // inserted easily. Note that endBlk cannot be returned; its predecessor is the last block that can
16970 // be returned. The new block will be put in an EH region described by the arguments regionIndex,
16971 // putInTryRegion, startBlk, and endBlk (explained below), so it must be legal to place to put the
16972 // new block after the insertion location block, give it the specified EH region index, and not break
16973 // EH nesting rules. This function is careful to choose a block in the correct EH region. However,
16974 // it assumes that the new block can ALWAYS be placed at the end (just before endBlk). That means
16975 // that the caller must ensure that is true.
16977 // Below are the possible cases for the arguments to this method:
16978 // 1. putInTryRegion == true and regionIndex > 0:
16979 // Search in the try region indicated by regionIndex.
16980 // 2. putInTryRegion == false and regionIndex > 0:
16981 // a. If startBlk is the first block of a filter and endBlk is the block after the end of the
16982 // filter (that is, the startBlk and endBlk match a filter bounds exactly), then choose a
16983 // location within this filter region. (Note that, due to IL rules, filters do not have any
16984 // EH nested within them.) Otherwise, filters are skipped.
16985 // b. Else, search in the handler region indicated by regionIndex.
16986 // 3. regionIndex = 0:
16987 // Search in the entire main method, excluding all EH regions. In this case, putInTryRegion must be true.
16989 // This method makes sure to find an insertion point which would not cause the inserted block to
16990 // be put inside any inner try/filter/handler regions.
16992 // The actual insertion occurs after the returned block. Note that the returned insertion point might
16993 // be the last block of a more nested EH region, because the new block will be inserted after the insertion
16994 // point, and will not extend the more nested EH region. For example:
17001 // | |--- |--- BB05
17003 // |----------------- BB07
17005 // for regionIndex==try3, putInTryRegion==true, we might return BB05, even though BB05 will have a try index
17006 // for try1 (the most nested 'try' region the block is in). That's because when we insert after BB05, the new
17007 // block will be in the correct, desired EH region, since try1 and try2 regions will not be extended to include
17008 // the inserted block. Furthermore, for regionIndex==try2, putInTryRegion==true, we can also return BB05. In this
17009 // case, when the new block is inserted, the try1 region remains the same, but we need extend region 'try2' to
17010 // include the inserted block. (We also need to check all parent regions as well, just in case any parent regions
17011 // also end on the same block, in which case we would also need to extend the parent regions. This is standard
17012 // procedure when inserting a block at the end of an EH region.)
17014 // If nearBlk is non-nullptr then we return the closest block after nearBlk that will work best.
17016 // We try to find a block in the appropriate region that is not a fallthrough block, so we can insert after it
17017 // without the need to insert a jump around the inserted block.
17019 // Note that regionIndex is numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is, "0" is
17020 // "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
17023 // regionIndex - the region index where the new block will be inserted. Zero means entire method;
17024 // non-zero means either a "try" or a "handler" region, depending on what putInTryRegion says.
17025 // putInTryRegion - 'true' to put the block in the 'try' region corresponding to 'regionIndex', 'false'
17026 // to put the block in the handler region. Should be 'true' if regionIndex==0.
17027 // startBlk - start block of range to search.
17028 // endBlk - end block of range to search (don't include this block in the range). Can be nullptr to indicate
17029 // the end of the function.
17030 // nearBlk - If non-nullptr, try to find an insertion location closely after this block. If nullptr, we insert
17031 // at the best location found towards the end of the acceptable block range.
17032 // jumpBlk - When nearBlk is set, this can be set to the block which jumps to bNext->bbNext (TODO: need to review
17034 // runRarely - true if the block being inserted is expected to be rarely run. This helps determine
17035 // the best place to put the new block, by putting in a place that has the same 'rarely run' characteristic.
17038 // A block with the desired characteristics, so the new block will be inserted after this one.
17039 // If there is no suitable location, return nullptr. This should basically never happen.
17041 BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex,
17042 bool putInTryRegion,
17043 BasicBlock* startBlk,
17044 BasicBlock* endBlk,
17045 BasicBlock* nearBlk,
17046 BasicBlock* jumpBlk,
17049 noway_assert(startBlk != nullptr);
17050 noway_assert(startBlk != endBlk);
17051 noway_assert((regionIndex == 0 && putInTryRegion) || // Search in the main method
17052 (putInTryRegion && regionIndex > 0 &&
17053 startBlk->bbTryIndex == regionIndex) || // Search in the specified try region
17054 (!putInTryRegion && regionIndex > 0 &&
17055 startBlk->bbHndIndex == regionIndex)); // Search in the specified handler region
17058 // Assert that startBlk precedes endBlk in the block list.
17059 // We don't want to use bbNum to assert this condition, as we cannot depend on the block numbers being
17060 // sequential at all times.
17061 for (BasicBlock* b = startBlk; b != endBlk; b = b->bbNext)
17063 assert(b != nullptr); // We reached the end of the block list, but never found endBlk.
17067 JITDUMP("fgFindInsertPoint(regionIndex=%u, putInTryRegion=%s, startBlk=BB%02u, endBlk=BB%02u, nearBlk=BB%02u, "
17068 "jumpBlk=BB%02u, runRarely=%s)\n",
17069 regionIndex, dspBool(putInTryRegion), startBlk->bbNum, (endBlk == nullptr) ? 0 : endBlk->bbNum,
17070 (nearBlk == nullptr) ? 0 : nearBlk->bbNum, (jumpBlk == nullptr) ? 0 : jumpBlk->bbNum, dspBool(runRarely));
17072 bool reachedNear = false; // Have we reached 'nearBlk' in our search? If not, we'll keep searching.
17073 bool inFilter = false; // Are we in a filter region that we need to skip?
17074 BasicBlock* bestBlk =
17075 nullptr; // Set to the best insertion point we've found so far that meets all the EH requirements.
17076 BasicBlock* goodBlk =
17077 nullptr; // Set to an acceptable insertion point that we'll use if we don't find a 'best' option.
17080 if (nearBlk != nullptr)
17082 // Does the nearBlk precede the startBlk?
17083 for (blk = nearBlk; blk != nullptr; blk = blk->bbNext)
17085 if (blk == startBlk)
17087 reachedNear = true;
17090 else if (blk == endBlk)
17097 for (blk = startBlk; blk != endBlk; blk = blk->bbNext)
17099 // The only way (blk == nullptr) could be true is if the caller passed an endBlk that preceded startBlk in the
17100 // block list, or if endBlk isn't in the block list at all. In DEBUG, we'll instead hit the similar
17101 // well-formedness assert earlier in this function.
17102 noway_assert(blk != nullptr);
17104 if (blk == nearBlk)
17106 reachedNear = true;
17109 if (blk->bbCatchTyp == BBCT_FILTER)
17111 // Record the fact that we entered a filter region, so we don't insert into filters...
17112 // Unless the caller actually wanted the block inserted in this exact filter region.
17113 // Detect this by the fact that startBlk and endBlk point to the filter begin and end.
17114 if (putInTryRegion || (blk != startBlk) || (startBlk != ehGetDsc(regionIndex - 1)->ebdFilter) ||
17115 (endBlk != ehGetDsc(regionIndex - 1)->ebdHndBeg))
17120 else if (blk->bbCatchTyp == BBCT_FILTER_HANDLER)
17122 // Record the fact that we exited a filter region.
17126 // Don't insert a block inside this filter region.
17132 // Note that the new block will be inserted AFTER "blk". We check to make sure that doing so
17133 // would put the block in the correct EH region. We make an assumption here that you can
17134 // ALWAYS insert the new block before "endBlk" (that is, at the end of the search range)
17135 // and be in the correct EH region. This is must be guaranteed by the caller (as it is by
17136 // fgNewBBinRegion(), which passes the search range as an exact EH region block range).
17137 // Because of this assumption, we only check the EH information for blocks before the last block.
17138 if (blk->bbNext != endBlk)
17140 // We are in the middle of the search range. We can't insert the new block in
17141 // an inner try or handler region. We can, however, set the insertion
17142 // point to the last block of an EH try/handler region, if the enclosing
17143 // region is the region we wish to insert in. (Since multiple regions can
17144 // end at the same block, we need to search outwards, checking that the
17145 // block is the last block of every EH region out to the region we want
17146 // to insert in.) This is especially useful for putting a call-to-finally
17147 // block on AMD64 immediately after its corresponding 'try' block, so in the
17148 // common case, we'll just fall through to it. For example:
17151 // BB02 -- first block of try
17153 // BB04 -- last block of try
17154 // BB05 -- first block of finally
17156 // BB07 -- last block of handler
17159 // Assume there is only one try/finally, so BB01 and BB08 are in the "main function".
17160 // For AMD64 call-to-finally, we'll want to insert the BBJ_CALLFINALLY in
17161 // the main function, immediately after BB04. This allows us to do that.
17163 if (!fgCheckEHCanInsertAfterBlock(blk, regionIndex, putInTryRegion))
17165 // Can't insert here.
17170 // Look for an insert location:
17171 // 1. We want blocks that don't end with a fall through,
17172 // 2. Also, when blk equals nearBlk we may want to insert here.
17173 if (!blk->bbFallsThrough() || (blk == nearBlk))
17175 bool updateBestBlk = true; // We will probably update the bestBlk
17177 // If blk falls through then we must decide whether to use the nearBlk
17179 if (blk->bbFallsThrough())
17181 noway_assert(blk == nearBlk);
17182 if (jumpBlk != nullptr)
17184 updateBestBlk = fgIsBetterFallThrough(blk, jumpBlk);
17188 updateBestBlk = false;
17192 // If we already have a best block, see if the 'runRarely' flags influences
17193 // our choice. If we want a runRarely insertion point, and the existing best
17194 // block is run rarely but the current block isn't run rarely, then don't
17195 // update the best block.
17196 // TODO-CQ: We should also handle the reverse case, where runRarely is false (we
17197 // want a non-rarely-run block), but bestBlock->isRunRarely() is true. In that
17198 // case, we should update the block, also. Probably what we want is:
17199 // (bestBlk->isRunRarely() != runRarely) && (blk->isRunRarely() == runRarely)
17200 if (updateBestBlk && (bestBlk != nullptr) && runRarely && bestBlk->isRunRarely() && !blk->isRunRarely())
17202 updateBestBlk = false;
17207 // We found a 'best' insertion location, so save it away.
17210 // If we've reached nearBlk, we've satisfied all the criteria,
17217 // If we haven't reached nearBlk, keep looking for a 'best' location, just
17218 // in case we'll find one at or after nearBlk. If no nearBlk was specified,
17219 // we prefer inserting towards the end of the given range, so keep looking
17220 // for more acceptable insertion locations.
17224 // No need to update goodBlk after we have set bestBlk, but we could still find a better
17225 // bestBlk, so keep looking.
17226 if (bestBlk != nullptr)
17231 // Set the current block as a "good enough" insertion point, if it meets certain criteria.
17232 // We'll return this block if we don't find a "best" block in the search range. The block
17233 // can't be a BBJ_CALLFINALLY of a BBJ_CALLFINALLY/BBJ_ALWAYS pair (since we don't want
17234 // to insert anything between these two blocks). Otherwise, we can use it. However,
17235 // if we'd previously chosen a BBJ_COND block, then we'd prefer the "good" block to be
17236 // something else. We keep updating it until we've reached the 'nearBlk', to push it as
17237 // close to endBlk as possible.
17238 if (!blk->isBBCallAlwaysPair())
17240 if (goodBlk == nullptr)
17244 else if ((goodBlk->bbJumpKind == BBJ_COND) || (blk->bbJumpKind != BBJ_COND))
17246 if ((blk == nearBlk) || !reachedNear)
17254 // If we didn't find a non-fall_through block, then insert at the last good block.
17256 if (bestBlk == nullptr)
17266 //------------------------------------------------------------------------
17267 // Creates a new BasicBlock and inserts it in a specific EH region, given by 'tryIndex', 'hndIndex', and 'putInFilter'.
17269 // If 'putInFilter' it true, then the block is inserted in the filter region given by 'hndIndex'. In this case, tryIndex
17270 // must be a less nested EH region (that is, tryIndex > hndIndex).
17272 // Otherwise, the block is inserted in either the try region or the handler region, depending on which one is the inner
17273 // region. In other words, if the try region indicated by tryIndex is nested in the handler region indicated by
17275 // then the new BB will be created in the try region. Vice versa.
17277 // Note that tryIndex and hndIndex are numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is,
17278 // "0" is "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
17280 // To be more specific, this function will create a new BB in one of the following 5 regions (if putInFilter is false):
17281 // 1. When tryIndex = 0 and hndIndex = 0:
17282 // The new BB will be created in the method region.
17283 // 2. When tryIndex != 0 and hndIndex = 0:
17284 // The new BB will be created in the try region indicated by tryIndex.
17285 // 3. When tryIndex == 0 and hndIndex != 0:
17286 // The new BB will be created in the handler region indicated by hndIndex.
17287 // 4. When tryIndex != 0 and hndIndex != 0 and tryIndex < hndIndex:
17288 // In this case, the try region is nested inside the handler region. Therefore, the new BB will be created
17289 // in the try region indicated by tryIndex.
17290 // 5. When tryIndex != 0 and hndIndex != 0 and tryIndex > hndIndex:
17291 // In this case, the handler region is nested inside the try region. Therefore, the new BB will be created
17292 // in the handler region indicated by hndIndex.
17294 // Note that if tryIndex != 0 and hndIndex != 0 then tryIndex must not be equal to hndIndex (this makes sense because
17295 // if they are equal, you are asking to put the new block in both the try and handler, which is impossible).
17297 // The BasicBlock will not be inserted inside an EH region that is more nested than the requested tryIndex/hndIndex
17298 // region (so the function is careful to skip more nested EH regions when searching for a place to put the new block).
17300 // This function cannot be used to insert a block as the first block of any region. It always inserts a block after
17301 // an existing block in the given region.
17303 // If nearBlk is nullptr, or the block is run rarely, then the new block is assumed to be run rarely.
17306 // jumpKind - the jump kind of the new block to create.
17307 // tryIndex - the try region to insert the new block in, described above. This must be a number in the range
17308 // [0..compHndBBtabCount].
17309 // hndIndex - the handler region to insert the new block in, described above. This must be a number in the range
17310 // [0..compHndBBtabCount].
17311 // nearBlk - insert the new block closely after this block, if possible. If nullptr, put the new block anywhere
17312 // in the requested region.
17313 // putInFilter - put the new block in the filter region given by hndIndex, as described above.
17314 // runRarely - 'true' if the new block is run rarely.
17315 // insertAtEnd - 'true' if the block should be inserted at the end of the region. Note: this is currently only
17316 // implemented when inserting into the main function (not into any EH region).
17321 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17324 BasicBlock* nearBlk,
17325 bool putInFilter /* = false */,
17326 bool runRarely /* = false */,
17327 bool insertAtEnd /* = false */)
17329 assert(tryIndex <= compHndBBtabCount);
17330 assert(hndIndex <= compHndBBtabCount);
17332 /* afterBlk is the block which will precede the newBB */
17333 BasicBlock* afterBlk;
17335 // start and end limit for inserting the block
17336 BasicBlock* startBlk = nullptr;
17337 BasicBlock* endBlk = nullptr;
17339 bool putInTryRegion = true;
17340 unsigned regionIndex = 0;
17342 // First, figure out which region (the "try" region or the "handler" region) to put the newBB in.
17343 if ((tryIndex == 0) && (hndIndex == 0))
17345 assert(!putInFilter);
17347 endBlk = fgEndBBAfterMainFunction(); // don't put new BB in funclet region
17349 if (insertAtEnd || (nearBlk == nullptr))
17351 /* We'll just insert the block at the end of the method, before the funclets */
17353 afterBlk = fgLastBBInMainFunction();
17354 goto _FoundAfterBlk;
17358 // We'll search through the entire method
17359 startBlk = fgFirstBB;
17362 noway_assert(regionIndex == 0);
17366 noway_assert(tryIndex > 0 || hndIndex > 0);
17367 PREFIX_ASSUME(tryIndex <= compHndBBtabCount);
17368 PREFIX_ASSUME(hndIndex <= compHndBBtabCount);
17370 // Decide which region to put in, the "try" region or the "handler" region.
17373 noway_assert(hndIndex > 0);
17374 putInTryRegion = false;
17376 else if (hndIndex == 0)
17378 noway_assert(tryIndex > 0);
17379 noway_assert(putInTryRegion);
17380 assert(!putInFilter);
17384 noway_assert(tryIndex > 0 && hndIndex > 0 && tryIndex != hndIndex);
17385 putInTryRegion = (tryIndex < hndIndex);
17388 if (putInTryRegion)
17390 // Try region is the inner region.
17391 // In other words, try region must be nested inside the handler region.
17392 noway_assert(hndIndex == 0 || bbInHandlerRegions(hndIndex - 1, ehGetDsc(tryIndex - 1)->ebdTryBeg));
17393 assert(!putInFilter);
17397 // Handler region is the inner region.
17398 // In other words, handler region must be nested inside the try region.
17399 noway_assert(tryIndex == 0 || bbInTryRegions(tryIndex - 1, ehGetDsc(hndIndex - 1)->ebdHndBeg));
17402 // Figure out the start and end block range to search for an insertion location. Pick the beginning and
17403 // ending blocks of the target EH region (the 'endBlk' is one past the last block of the EH region, to make
17404 // loop iteration easier). Note that, after funclets have been created (for FEATURE_EH_FUNCLETS),
17405 // this linear block range will not include blocks of handlers for try/handler clauses nested within
17406 // this EH region, as those blocks have been extracted as funclets. That is ok, though, because we don't
17407 // want to insert a block in any nested EH region.
17409 if (putInTryRegion)
17411 // We will put the newBB in the try region.
17412 EHblkDsc* ehDsc = ehGetDsc(tryIndex - 1);
17413 startBlk = ehDsc->ebdTryBeg;
17414 endBlk = ehDsc->ebdTryLast->bbNext;
17415 regionIndex = tryIndex;
17417 else if (putInFilter)
17419 // We will put the newBB in the filter region.
17420 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17421 startBlk = ehDsc->ebdFilter;
17422 endBlk = ehDsc->ebdHndBeg;
17423 regionIndex = hndIndex;
17427 // We will put the newBB in the handler region.
17428 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17429 startBlk = ehDsc->ebdHndBeg;
17430 endBlk = ehDsc->ebdHndLast->bbNext;
17431 regionIndex = hndIndex;
17434 noway_assert(regionIndex > 0);
17437 // Now find the insertion point.
17438 afterBlk = fgFindInsertPoint(regionIndex, putInTryRegion, startBlk, endBlk, nearBlk, nullptr, runRarely);
17442 /* We have decided to insert the block after 'afterBlk'. */
17443 noway_assert(afterBlk != nullptr);
17445 JITDUMP("fgNewBBinRegion(jumpKind=%u, tryIndex=%u, hndIndex=%u, putInFilter=%s, runRarely=%s, insertAtEnd=%s): "
17446 "inserting after BB%02u\n",
17447 jumpKind, tryIndex, hndIndex, dspBool(putInFilter), dspBool(runRarely), dspBool(insertAtEnd),
17450 return fgNewBBinRegionWorker(jumpKind, afterBlk, regionIndex, putInTryRegion);
17453 //------------------------------------------------------------------------
17454 // Creates a new BasicBlock and inserts it in the same EH region as 'srcBlk'.
17456 // See the implementation of fgNewBBinRegion() used by this one for more notes.
17459 // jumpKind - the jump kind of the new block to create.
17460 // srcBlk - insert the new block in the same EH region as this block, and closely after it if possible.
17465 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17466 BasicBlock* srcBlk,
17467 bool runRarely /* = false */,
17468 bool insertAtEnd /* = false */)
17470 assert(srcBlk != nullptr);
17472 const unsigned tryIndex = srcBlk->bbTryIndex;
17473 const unsigned hndIndex = srcBlk->bbHndIndex;
17474 bool putInFilter = false;
17476 // Check to see if we need to put the new block in a filter. We do if srcBlk is in a filter.
17477 // This can only be true if there is a handler index, and the handler region is more nested than the
17478 // try region (if any). This is because no EH regions can be nested within a filter.
17479 if (BasicBlock::ehIndexMaybeMoreNested(hndIndex, tryIndex))
17481 assert(hndIndex != 0); // If hndIndex is more nested, we must be in some handler!
17482 putInFilter = ehGetDsc(hndIndex - 1)->InFilterRegionBBRange(srcBlk);
17485 return fgNewBBinRegion(jumpKind, tryIndex, hndIndex, srcBlk, putInFilter, runRarely, insertAtEnd);
17488 //------------------------------------------------------------------------
17489 // Creates a new BasicBlock and inserts it at the end of the function.
17491 // See the implementation of fgNewBBinRegion() used by this one for more notes.
17494 // jumpKind - the jump kind of the new block to create.
17499 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind)
17501 return fgNewBBinRegion(jumpKind, 0, 0, nullptr, /* putInFilter */ false, /* runRarely */ false,
17502 /* insertAtEnd */ true);
17505 //------------------------------------------------------------------------
17506 // Creates a new BasicBlock, and inserts it after 'afterBlk'.
17508 // The block cannot be inserted into a more nested try/handler region than that specified by 'regionIndex'.
17509 // (It is given exactly 'regionIndex'.) Thus, the parameters must be passed to ensure proper EH nesting
17510 // rules are followed.
17513 // jumpKind - the jump kind of the new block to create.
17514 // afterBlk - insert the new block after this one.
17515 // regionIndex - the block will be put in this EH region.
17516 // putInTryRegion - If true, put the new block in the 'try' region corresponding to 'regionIndex', and
17517 // set its handler index to the most nested handler region enclosing that 'try' region.
17518 // Otherwise, put the block in the handler region specified by 'regionIndex', and set its 'try'
17519 // index to the most nested 'try' region enclosing that handler region.
17524 BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind,
17525 BasicBlock* afterBlk,
17526 unsigned regionIndex,
17527 bool putInTryRegion)
17529 /* Insert the new block */
17530 BasicBlock* afterBlkNext = afterBlk->bbNext;
17531 (void)afterBlkNext; // prevent "unused variable" error from GCC
17532 BasicBlock* newBlk = fgNewBBafter(jumpKind, afterBlk, false);
17534 if (putInTryRegion)
17536 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
17537 newBlk->bbTryIndex = (unsigned short)regionIndex;
17538 newBlk->bbHndIndex = bbFindInnermostHandlerRegionContainingTryRegion(regionIndex);
17542 newBlk->bbTryIndex = bbFindInnermostTryRegionContainingHandlerRegion(regionIndex);
17543 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
17544 newBlk->bbHndIndex = (unsigned short)regionIndex;
17547 // We're going to compare for equal try regions (to handle the case of 'mutually protect'
17548 // regions). We need to save off the current try region, otherwise we might change it
17549 // before it gets compared later, thereby making future comparisons fail.
17551 BasicBlock* newTryBeg;
17552 BasicBlock* newTryLast;
17553 (void)ehInitTryBlockRange(newBlk, &newTryBeg, &newTryLast);
17558 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
17560 // Is afterBlk at the end of a try region?
17561 if (HBtab->ebdTryLast == afterBlk)
17563 noway_assert(afterBlkNext == newBlk->bbNext);
17565 bool extendTryRegion = false;
17566 if (newBlk->hasTryIndex())
17568 // We're adding a block after the last block of some try region. Do
17569 // we extend the try region to include the block, or not?
17570 // If the try region is exactly the same as the try region
17571 // associated with the new block (based on the block's try index,
17572 // which represents the innermost try the block is a part of), then
17574 // If the try region is a "parent" try region -- an enclosing try region
17575 // that has the same last block as the new block's try region -- then
17576 // we also extend. For example:
17581 // } /* 2 */ } /* 1 */
17582 // This example is meant to indicate that both try regions 1 and 2 end at
17583 // the same block, and we're extending 2. Thus, we must also extend 1. If we
17584 // only extended 2, we would break proper nesting. (Dev11 bug 137967)
17586 extendTryRegion = HBtab->ebdIsSameTry(newTryBeg, newTryLast) || bbInTryRegions(XTnum, newBlk);
17589 // Does newBlk extend this try region?
17590 if (extendTryRegion)
17592 // Yes, newBlk extends this try region
17594 // newBlk is the now the new try last block
17595 fgSetTryEnd(HBtab, newBlk);
17599 // Is afterBlk at the end of a handler region?
17600 if (HBtab->ebdHndLast == afterBlk)
17602 noway_assert(afterBlkNext == newBlk->bbNext);
17604 // Does newBlk extend this handler region?
17605 bool extendHndRegion = false;
17606 if (newBlk->hasHndIndex())
17608 // We're adding a block after the last block of some handler region. Do
17609 // we extend the handler region to include the block, or not?
17610 // If the handler region is exactly the same as the handler region
17611 // associated with the new block (based on the block's handler index,
17612 // which represents the innermost handler the block is a part of), then
17614 // If the handler region is a "parent" handler region -- an enclosing
17615 // handler region that has the same last block as the new block's handler
17616 // region -- then we also extend. For example:
17621 // } /* 2 */ } /* 1 */
17622 // This example is meant to indicate that both handler regions 1 and 2 end at
17623 // the same block, and we're extending 2. Thus, we must also extend 1. If we
17624 // only extended 2, we would break proper nesting. (Dev11 bug 372051)
17626 extendHndRegion = bbInHandlerRegions(XTnum, newBlk);
17629 if (extendHndRegion)
17631 // Yes, newBlk extends this handler region
17633 // newBlk is now the last block of the handler.
17634 fgSetHndEnd(HBtab, newBlk);
17639 /* If afterBlk falls through, we insert a jump around newBlk */
17640 fgConnectFallThrough(afterBlk, newBlk->bbNext);
17643 fgVerifyHandlerTab();
17649 /*****************************************************************************
17653 unsigned Compiler::acdHelper(SpecialCodeKind codeKind)
17657 case SCK_RNGCHK_FAIL:
17658 return CORINFO_HELP_RNGCHKFAIL;
17659 case SCK_ARG_EXCPN:
17660 return CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
17661 case SCK_ARG_RNG_EXCPN:
17662 return CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
17663 case SCK_DIV_BY_ZERO:
17664 return CORINFO_HELP_THROWDIVZERO;
17665 case SCK_ARITH_EXCPN:
17666 return CORINFO_HELP_OVERFLOW;
17668 assert(!"Bad codeKind");
17673 /*****************************************************************************
17675 * Find/create an added code entry associated with the given block and with
17679 BasicBlock* Compiler::fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth)
17681 // Record that the code will call a THROW_HELPER
17682 // so on Windows Amd64 we can allocate the 4 outgoing
17683 // arg slots on the stack frame if there are no other calls.
17684 compUsesThrowHelper = true;
17686 // For debuggable code, genJumpToThrowHlpBlk() will generate the 'throw'
17687 // code inline. It has to be kept consistent with fgAddCodeRef()
17688 if (opts.compDbgCode)
17693 const static BBjumpKinds jumpKinds[] = {
17694 BBJ_NONE, // SCK_NONE
17695 BBJ_THROW, // SCK_RNGCHK_FAIL
17696 BBJ_ALWAYS, // SCK_PAUSE_EXEC
17697 BBJ_THROW, // SCK_DIV_BY_ZERO
17698 BBJ_THROW, // SCK_ARITH_EXCP, SCK_OVERFLOW
17699 BBJ_THROW, // SCK_ARG_EXCPN
17700 BBJ_THROW, // SCK_ARG_RNG_EXCPN
17703 noway_assert(sizeof(jumpKinds) == SCK_COUNT); // sanity check
17705 /* First look for an existing entry that matches what we're looking for */
17707 AddCodeDsc* add = fgFindExcptnTarget(kind, refData);
17709 if (add) // found it
17711 #ifdef _TARGET_X86_
17712 // If different range checks happen at different stack levels,
17713 // they can't all jump to the same "call @rngChkFailed" AND have
17714 // frameless methods, as the rngChkFailed may need to unwind the
17715 // stack, and we have to be able to report the stack level.
17717 // The following check forces most methods that reference an
17718 // array element in a parameter list to have an EBP frame,
17719 // this restriction could be removed with more careful code
17720 // generation for BBJ_THROW (i.e. range check failed).
17722 // For Linux/x86, we possibly need to insert stack alignment adjustment
17723 // before the first stack argument pushed for every call. But we
17724 // don't know what the stack alignment adjustment will be when
17725 // we morph a tree that calls fgAddCodeRef(), so the stack depth
17726 // number will be incorrect. For now, simply force all functions with
17727 // these helpers to have EBP frames. It might be possible to make
17728 // this less conservative. E.g., for top-level (not nested) calls
17729 // without stack args, the stack pointer hasn't changed and stack
17730 // depth will be known to be zero. Or, figure out a way to update
17731 // or generate all required helpers after all stack alignment
17732 // has been added, and the stack level at each call to fgAddCodeRef()
17733 // is known, or can be recalculated.
17734 CLANG_FORMAT_COMMENT_ANCHOR;
17736 #if defined(UNIX_X86_ABI)
17737 codeGen->setFrameRequired(true);
17738 #else // !defined(UNIX_X86_ABI)
17739 if (add->acdStkLvl != stkDepth)
17741 codeGen->setFrameRequired(true);
17743 #endif // !defined(UNIX_X86_ABI)
17744 #endif // _TARGET_X86_
17746 return add->acdDstBlk;
17749 /* We have to allocate a new entry and prepend it to the list */
17751 add = new (this, CMK_Unknown) AddCodeDsc;
17752 add->acdData = refData;
17753 add->acdKind = kind;
17754 add->acdStkLvl = (unsigned short)stkDepth;
17755 noway_assert(add->acdStkLvl == stkDepth);
17756 add->acdNext = fgAddCodeList;
17757 fgAddCodeList = add;
17759 /* Create the target basic block */
17761 BasicBlock* newBlk;
17763 newBlk = add->acdDstBlk = fgNewBBinRegion(jumpKinds[kind], srcBlk, /* runRarely */ true, /* insertAtEnd */ true);
17765 add->acdDstBlk->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
17770 const char* msgWhere = "";
17771 if (!srcBlk->hasTryIndex() && !srcBlk->hasHndIndex())
17773 msgWhere = "non-EH region";
17775 else if (!srcBlk->hasTryIndex())
17777 msgWhere = "handler";
17779 else if (!srcBlk->hasHndIndex())
17783 else if (srcBlk->getTryIndex() < srcBlk->getHndIndex())
17789 msgWhere = "handler";
17795 case SCK_RNGCHK_FAIL:
17796 msg = " for RNGCHK_FAIL";
17798 case SCK_PAUSE_EXEC:
17799 msg = " for PAUSE_EXEC";
17801 case SCK_DIV_BY_ZERO:
17802 msg = " for DIV_BY_ZERO";
17805 msg = " for OVERFLOW";
17807 case SCK_ARG_EXCPN:
17808 msg = " for ARG_EXCPN";
17810 case SCK_ARG_RNG_EXCPN:
17811 msg = " for ARG_RNG_EXCPN";
17818 printf("\nfgAddCodeRef -"
17819 " Add BB in %s%s, new block BB%02u [%08p], stkDepth is %d\n",
17820 msgWhere, msg, add->acdDstBlk->bbNum, dspPtr(add->acdDstBlk), stkDepth);
17825 newBlk->bbTgtStkDepth = stkDepth;
17828 /* Mark the block as added by the compiler and not removable by future flow
17829 graph optimizations. Note that no bbJumpDest points to these blocks. */
17831 newBlk->bbFlags |= BBF_IMPORTED;
17832 newBlk->bbFlags |= BBF_DONT_REMOVE;
17834 /* Remember that we're adding a new basic block */
17836 fgAddCodeModf = true;
17837 fgRngChkThrowAdded = true;
17839 /* Now figure out what code to insert */
17842 int helper = CORINFO_HELP_UNDEF;
17846 case SCK_RNGCHK_FAIL:
17847 helper = CORINFO_HELP_RNGCHKFAIL;
17850 case SCK_DIV_BY_ZERO:
17851 helper = CORINFO_HELP_THROWDIVZERO;
17854 case SCK_ARITH_EXCPN:
17855 helper = CORINFO_HELP_OVERFLOW;
17856 noway_assert(SCK_OVERFLOW == SCK_ARITH_EXCPN);
17859 case SCK_ARG_EXCPN:
17860 helper = CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
17863 case SCK_ARG_RNG_EXCPN:
17864 helper = CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
17867 // case SCK_PAUSE_EXEC:
17868 // noway_assert(!"add code to pause exec");
17871 noway_assert(!"unexpected code addition kind");
17875 noway_assert(helper != CORINFO_HELP_UNDEF);
17877 // Add the appropriate helper call.
17878 tree = gtNewHelperCallNode(helper, TYP_VOID, GTF_EXCEPT);
17880 // There are no args here but fgMorphArgs has side effects
17881 // such as setting the outgoing arg area (which is necessary
17882 // on AMD if there are any calls).
17883 tree = fgMorphArgs(tree);
17885 // Store the tree in the new basic block.
17886 assert(!srcBlk->isEmpty());
17887 if (!srcBlk->IsLIR())
17889 fgInsertStmtAtEnd(newBlk, fgNewStmtFromTree(tree));
17893 LIR::AsRange(newBlk).InsertAtEnd(LIR::SeqTree(this, tree));
17896 return add->acdDstBlk;
17899 /*****************************************************************************
17900 * Finds the block to jump to, to throw a given kind of exception
17901 * We maintain a cache of one AddCodeDsc for each kind, to make searching fast.
17902 * Note : Each block uses the same (maybe shared) block as the jump target for
17903 * a given type of exception
17906 Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData)
17908 if (!(fgExcptnTargetCache[kind] && // Try the cached value first
17909 fgExcptnTargetCache[kind]->acdData == refData))
17911 // Too bad, have to search for the jump target for the exception
17913 AddCodeDsc* add = nullptr;
17915 for (add = fgAddCodeList; add != nullptr; add = add->acdNext)
17917 if (add->acdData == refData && add->acdKind == kind)
17923 fgExcptnTargetCache[kind] = add; // Cache it
17926 return fgExcptnTargetCache[kind];
17929 /*****************************************************************************
17931 * The given basic block contains an array range check; return the label this
17932 * range check is to jump to upon failure.
17935 BasicBlock* Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind)
17940 printf("*** Computing fgRngChkTarget for block BB%02u to stkDepth %d\n", block->bbNum, stkDepth);
17941 if (!block->IsLIR())
17943 gtDispTree(compCurStmt);
17948 /* We attach the target label to the containing try block (if any) */
17949 noway_assert(!compIsForInlining());
17950 return fgAddCodeRef(block, bbThrowIndex(block), kind, stkDepth);
17953 // Sequences the tree.
17954 // prevTree is what gtPrev of the first node in execution order gets set to.
17955 // Returns the first node (execution order) in the sequenced tree.
17956 GenTree* Compiler::fgSetTreeSeq(GenTree* tree, GenTree* prevTree, bool isLIR)
17960 if (prevTree == nullptr)
17964 fgTreeSeqLst = prevTree;
17966 fgTreeSeqBeg = nullptr;
17967 fgSetTreeSeqHelper(tree, isLIR);
17969 GenTree* result = prevTree->gtNext;
17970 if (prevTree == &list)
17972 list.gtNext->gtPrev = nullptr;
17978 /*****************************************************************************
17980 * Assigns sequence numbers to the given tree and its sub-operands, and
17981 * threads all the nodes together via the 'gtNext' and 'gtPrev' fields.
17982 * Uses 'global' - fgTreeSeqLst
17985 void Compiler::fgSetTreeSeqHelper(GenTreePtr tree, bool isLIR)
17990 noway_assert(tree);
17991 assert(!IsUninitialized(tree));
17992 noway_assert(tree->gtOper != GT_STMT);
17994 /* Figure out what kind of a node we have */
17996 oper = tree->OperGet();
17997 kind = tree->OperKind();
17999 /* Is this a leaf/constant node? */
18001 if (kind & (GTK_CONST | GTK_LEAF))
18003 fgSetTreeSeqFinish(tree, isLIR);
18007 // Special handling for dynamic block ops.
18008 if (tree->OperIsDynBlkOp())
18010 GenTreeDynBlk* dynBlk;
18012 GenTree* asg = tree;
18013 if (tree->OperGet() == GT_ASG)
18015 dynBlk = tree->gtGetOp1()->AsDynBlk();
18016 src = tree->gtGetOp2();
18020 dynBlk = tree->AsDynBlk();
18021 src = dynBlk->Data();
18024 GenTree* sizeNode = dynBlk->gtDynamicSize;
18025 GenTree* dstAddr = dynBlk->Addr();
18026 if (dynBlk->gtEvalSizeFirst)
18028 fgSetTreeSeqHelper(sizeNode, isLIR);
18030 if (tree->gtFlags & GTF_REVERSE_OPS)
18032 fgSetTreeSeqHelper(src, isLIR);
18033 fgSetTreeSeqHelper(dstAddr, isLIR);
18037 fgSetTreeSeqHelper(dstAddr, isLIR);
18038 fgSetTreeSeqHelper(src, isLIR);
18040 if (!dynBlk->gtEvalSizeFirst)
18042 fgSetTreeSeqHelper(sizeNode, isLIR);
18044 fgSetTreeSeqFinish(dynBlk, isLIR);
18045 if (asg != nullptr)
18047 fgSetTreeSeqFinish(asg, isLIR);
18052 /* Is it a 'simple' unary/binary operator? */
18054 if (kind & GTK_SMPOP)
18056 GenTreePtr op1 = tree->gtOp.gtOp1;
18057 GenTreePtr op2 = tree->gtGetOp2IfPresent();
18059 // Special handling for GT_LIST
18060 if (tree->OperGet() == GT_LIST)
18062 // First, handle the list items, which will be linked in forward order.
18063 // As we go, we will link the GT_LIST nodes in reverse order - we will number
18064 // them and update fgTreeSeqList in a subsequent traversal.
18065 GenTreePtr nextList = tree;
18066 GenTreePtr list = nullptr;
18067 while (nextList != nullptr && nextList->OperGet() == GT_LIST)
18070 GenTreePtr listItem = list->gtOp.gtOp1;
18071 fgSetTreeSeqHelper(listItem, isLIR);
18072 nextList = list->gtOp.gtOp2;
18073 if (nextList != nullptr)
18075 nextList->gtNext = list;
18077 list->gtPrev = nextList;
18079 // Next, handle the GT_LIST nodes.
18080 // Note that fgSetTreeSeqFinish() sets the gtNext to null, so we need to capture the nextList
18081 // before we call that method.
18085 assert(list != nullptr);
18087 nextList = list->gtNext;
18088 fgSetTreeSeqFinish(list, isLIR);
18089 } while (list != tree);
18093 /* Special handling for AddrMode */
18094 if (tree->OperIsAddrMode())
18096 bool reverse = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
18099 assert(op1 != nullptr && op2 != nullptr);
18100 fgSetTreeSeqHelper(op2, isLIR);
18102 if (op1 != nullptr)
18104 fgSetTreeSeqHelper(op1, isLIR);
18106 if (!reverse && op2 != nullptr)
18108 fgSetTreeSeqHelper(op2, isLIR);
18111 fgSetTreeSeqFinish(tree, isLIR);
18115 /* Check for a nilary operator */
18117 if (op1 == nullptr)
18119 noway_assert(op2 == nullptr);
18120 fgSetTreeSeqFinish(tree, isLIR);
18124 /* Is this a unary operator?
18125 * Although UNARY GT_IND has a special structure */
18127 if (oper == GT_IND)
18129 /* Visit the indirection first - op2 may point to the
18130 * jump Label for array-index-out-of-range */
18132 fgSetTreeSeqHelper(op1, isLIR);
18133 fgSetTreeSeqFinish(tree, isLIR);
18137 /* Now this is REALLY a unary operator */
18141 /* Visit the (only) operand and we're done */
18143 fgSetTreeSeqHelper(op1, isLIR);
18144 fgSetTreeSeqFinish(tree, isLIR);
18149 For "real" ?: operators, we make sure the order is
18159 if (oper == GT_QMARK)
18161 noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
18163 fgSetTreeSeqHelper(op1, isLIR);
18164 // Here, for the colon, the sequence does not actually represent "order of evaluation":
18165 // one or the other of the branches is executed, not both. Still, to make debugging checks
18166 // work, we want the sequence to match the order in which we'll generate code, which means
18167 // "else" clause then "then" clause.
18168 fgSetTreeSeqHelper(op2->AsColon()->ElseNode(), isLIR);
18169 fgSetTreeSeqHelper(op2, isLIR);
18170 fgSetTreeSeqHelper(op2->AsColon()->ThenNode(), isLIR);
18172 fgSetTreeSeqFinish(tree, isLIR);
18176 if (oper == GT_COLON)
18178 fgSetTreeSeqFinish(tree, isLIR);
18182 /* This is a binary operator */
18184 if (tree->gtFlags & GTF_REVERSE_OPS)
18186 fgSetTreeSeqHelper(op2, isLIR);
18187 fgSetTreeSeqHelper(op1, isLIR);
18191 fgSetTreeSeqHelper(op1, isLIR);
18192 fgSetTreeSeqHelper(op2, isLIR);
18195 fgSetTreeSeqFinish(tree, isLIR);
18199 /* See what kind of a special operator we have here */
18204 noway_assert(tree->gtField.gtFldObj == nullptr);
18209 /* We'll evaluate the 'this' argument value first */
18210 if (tree->gtCall.gtCallObjp)
18212 fgSetTreeSeqHelper(tree->gtCall.gtCallObjp, isLIR);
18215 /* We'll evaluate the arguments next, left to right
18216 * NOTE: setListOrder needs cleanup - eliminate the #ifdef afterwards */
18218 if (tree->gtCall.gtCallArgs)
18220 fgSetTreeSeqHelper(tree->gtCall.gtCallArgs, isLIR);
18223 /* Evaluate the temp register arguments list
18224 * This is a "hidden" list and its only purpose is to
18225 * extend the life of temps until we make the call */
18227 if (tree->gtCall.gtCallLateArgs)
18229 fgSetTreeSeqHelper(tree->gtCall.gtCallLateArgs, isLIR);
18232 if ((tree->gtCall.gtCallType == CT_INDIRECT) && (tree->gtCall.gtCallCookie != nullptr))
18234 fgSetTreeSeqHelper(tree->gtCall.gtCallCookie, isLIR);
18237 if (tree->gtCall.gtCallType == CT_INDIRECT)
18239 fgSetTreeSeqHelper(tree->gtCall.gtCallAddr, isLIR);
18242 if (tree->gtCall.gtControlExpr)
18244 fgSetTreeSeqHelper(tree->gtCall.gtControlExpr, isLIR);
18251 fgSetTreeSeqHelper(tree->gtArrElem.gtArrObj, isLIR);
18254 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
18256 fgSetTreeSeqHelper(tree->gtArrElem.gtArrInds[dim], isLIR);
18261 case GT_ARR_OFFSET:
18262 fgSetTreeSeqHelper(tree->gtArrOffs.gtOffset, isLIR);
18263 fgSetTreeSeqHelper(tree->gtArrOffs.gtIndex, isLIR);
18264 fgSetTreeSeqHelper(tree->gtArrOffs.gtArrObj, isLIR);
18268 // Evaluate the trees left to right
18269 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpLocation, isLIR);
18270 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpValue, isLIR);
18271 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpComparand, isLIR);
18274 case GT_ARR_BOUNDS_CHECK:
18275 #ifdef FEATURE_SIMD
18277 #endif // FEATURE_SIMD
18278 // Evaluate the trees left to right
18279 fgSetTreeSeqHelper(tree->gtBoundsChk.gtIndex, isLIR);
18280 fgSetTreeSeqHelper(tree->gtBoundsChk.gtArrLen, isLIR);
18283 case GT_STORE_DYN_BLK:
18285 noway_assert(!"DYN_BLK nodes should be sequenced as a special case");
18291 noway_assert(!"unexpected operator");
18296 fgSetTreeSeqFinish(tree, isLIR);
18299 void Compiler::fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR)
18301 // If we are sequencing a node that does not appear in LIR,
18302 // do not add it to the list.
18305 if ((tree->OperGet() == GT_LIST) || (tree->OperGet() == GT_ARGPLACE) ||
18306 (tree->OperGet() == GT_FIELD_LIST && !tree->AsFieldList()->IsFieldListHead()))
18312 /* Append to the node list */
18316 tree->gtSeqNum = fgTreeSeqNum;
18320 printf("SetTreeOrder: ");
18321 printTreeID(fgTreeSeqLst);
18322 printf(" followed by ");
18328 fgTreeSeqLst->gtNext = tree;
18329 tree->gtNext = nullptr;
18330 tree->gtPrev = fgTreeSeqLst;
18331 fgTreeSeqLst = tree;
18333 /* Remember the very first node */
18337 fgTreeSeqBeg = tree;
18338 assert(tree->gtSeqNum == 1);
18342 /*****************************************************************************
18344 * Figure out the order in which operators should be evaluated, along with
18345 * other information (such as the register sets trashed by each subtree).
18346 * Also finds blocks that need GC polls and inserts them as needed.
18349 void Compiler::fgSetBlockOrder()
18354 printf("*************** In fgSetBlockOrder()\n");
18359 BasicBlock::s_nMaxTrees = 0;
18362 /* Walk the basic blocks to assign sequence numbers */
18364 /* If we don't compute the doms, then we never mark blocks as loops. */
18365 if (fgDomsComputed)
18367 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18369 /* If this block is a loop header, mark it appropriately */
18371 if (block->isLoopHead())
18373 fgMarkLoopHead(block);
18377 // only enable fully interruptible code for if we're hijacking.
18378 else if (GCPOLL_NONE == opts.compGCPollType)
18380 /* If we don't have the dominators, use an abbreviated test for fully interruptible. If there are
18381 * any back edges, check the source and destination blocks to see if they're GC Safe. If not, then
18382 * go fully interruptible. */
18384 /* XXX Mon 1/21/2008
18385 * Wouldn't it be nice to have a block iterator that can do this loop?
18387 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18389 // true if the edge is forward, or if it is a back edge and either the source and dest are GC safe.
18390 #define EDGE_IS_GC_SAFE(src, dst) \
18391 (((src)->bbNum < (dst)->bbNum) || (((src)->bbFlags | (dst)->bbFlags) & BBF_GC_SAFE_POINT))
18393 bool partiallyInterruptible = true;
18394 switch (block->bbJumpKind)
18398 partiallyInterruptible = EDGE_IS_GC_SAFE(block, block->bbJumpDest);
18404 jumpCnt = block->bbJumpSwt->bbsCount;
18405 BasicBlock** jumpPtr;
18406 jumpPtr = block->bbJumpSwt->bbsDstTab;
18410 partiallyInterruptible &= EDGE_IS_GC_SAFE(block, *jumpPtr);
18411 } while (++jumpPtr, --jumpCnt);
18419 if (!partiallyInterruptible)
18422 // The GC encoding for fully interruptible methods does not
18423 // support more than 1023 pushed arguments, so we can't set
18424 // genInterruptible here when we have 1024 or more pushed args
18426 if (compCanEncodePtrArgCntMax())
18428 genInterruptible = true;
18432 #undef EDGE_IS_GC_SAFE
18436 if (!fgGCPollsCreated)
18441 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18444 #if FEATURE_FASTTAILCALL
18445 #ifndef JIT32_GCENCODER
18446 if (block->endsWithTailCallOrJmp(this, true) && !(block->bbFlags & BBF_GC_SAFE_POINT) &&
18447 optReachWithoutCall(fgFirstBB, block))
18449 // We have a tail call that is reachable without making any other
18450 // 'normal' call that would have counted as a GC Poll. If we were
18451 // using polls, all return blocks meeting this criteria would have
18452 // already added polls and then marked as being GC safe
18453 // (BBF_GC_SAFE_POINT). Thus we can only reach here when *NOT*
18454 // using GC polls, but instead relying on the JIT to generate
18455 // fully-interruptible code.
18456 noway_assert(GCPOLL_NONE == opts.compGCPollType);
18458 // This tail call might combine with other tail calls to form a
18459 // loop. Thus we need to either add a poll, or make the method
18460 // fully interruptible. I chose the later because that's what
18462 genInterruptible = true;
18464 #endif // !JIT32_GCENCODER
18465 #endif // FEATURE_FASTTAILCALL
18467 fgSetBlockOrder(block);
18470 /* Remember that now the tree list is threaded */
18472 fgStmtListThreaded = true;
18477 printf("The biggest BB has %4u tree nodes\n", BasicBlock::s_nMaxTrees);
18479 fgDebugCheckLinks();
18483 /*****************************************************************************/
18485 void Compiler::fgSetStmtSeq(GenTreePtr tree)
18487 GenTree list; // helper node that we use to start the StmtList
18488 // It's located in front of the first node in the list
18490 noway_assert(tree->gtOper == GT_STMT);
18492 /* Assign numbers and next/prev links for this tree */
18495 fgTreeSeqLst = &list;
18496 fgTreeSeqBeg = nullptr;
18498 fgSetTreeSeqHelper(tree->gtStmt.gtStmtExpr, false);
18500 /* Record the address of the first node */
18502 tree->gtStmt.gtStmtList = fgTreeSeqBeg;
18506 if (list.gtNext->gtPrev != &list)
18509 printTreeID(&list);
18510 printf(" != list.next->prev ");
18511 printTreeID(list.gtNext->gtPrev);
18518 for (temp = list.gtNext, last = &list; temp; last = temp, temp = temp->gtNext)
18520 if (temp->gtPrev != last)
18523 printf("->gtPrev = ");
18524 printTreeID(temp->gtPrev);
18525 printf(", but last = ");
18532 gtDispTree(tree->gtStmt.gtStmtExpr);
18535 for (GenTreePtr bad = &list; bad; bad = bad->gtNext)
18537 printf(" entry at ");
18540 printTreeID(bad->gtPrev);
18542 printTreeID(bad->gtNext);
18547 noway_assert(!"Badly linked tree");
18553 /* Fix the first node's 'prev' link */
18555 noway_assert(list.gtNext->gtPrev == &list);
18556 list.gtNext->gtPrev = nullptr;
18559 /* Keep track of the highest # of tree nodes */
18561 if (BasicBlock::s_nMaxTrees < fgTreeSeqNum)
18563 BasicBlock::s_nMaxTrees = fgTreeSeqNum;
18568 /*****************************************************************************/
18570 void Compiler::fgSetBlockOrder(BasicBlock* block)
18574 tree = block->bbTreeList;
18582 fgSetStmtSeq(tree);
18584 /* Are there any more trees in this basic block? */
18586 if (tree->gtNext == nullptr)
18588 /* last statement in the tree list */
18589 noway_assert(block->lastStmt() == tree);
18594 if (block->bbTreeList == tree)
18596 /* first statement in the list */
18597 noway_assert(tree->gtPrev->gtNext == nullptr);
18601 noway_assert(tree->gtPrev->gtNext == tree);
18604 noway_assert(tree->gtNext->gtPrev == tree);
18607 tree = tree->gtNext;
18611 #ifdef LEGACY_BACKEND
18612 //------------------------------------------------------------------------
18613 // fgOrderBlockOps: Get the execution order for a block assignment
18616 // tree - The block assignment
18617 // reg0 - The register for the destination
18618 // reg1 - The register for the source
18619 // reg2 - The register for the size
18620 // opsPtr - An array of 3 GenTreePtr's, an out argument for the operands, in order
18621 // regsPtr - An array of three regMaskTP - an out argument for the registers, in order
18624 // The return values go into the arrays that are passed in, and provide the
18625 // operands and associated registers, in execution order.
18628 // This method is somewhat convoluted in order to preserve old behavior from when
18629 // block assignments had their dst and src in a GT_LIST as op1, and their size as op2.
18630 // The old tree was like this:
18633 // GT_LIST [size/clsHnd]
18635 // [dest] [val/src]
18637 // The new tree looks like this:
18640 // blk/obj [val/src]
18642 // [destAddr] [*size/clsHnd] *only for GT_DYN_BLK
18644 // For the (usual) case of GT_BLK or GT_OBJ, the size is always "evaluated" (i.e.
18645 // instantiated into a register) last. In those cases, the GTF_REVERSE_OPS flag
18646 // on the assignment works as usual.
18647 // In order to preserve previous possible orderings, the order for evaluating
18648 // the size of a GT_DYN_BLK node is controlled by its gtEvalSizeFirst flag. If
18649 // that is set, the size is evaluated first, and then the src and dst are evaluated
18650 // according to the GTF_REVERSE_OPS flag on the assignment.
18652 void Compiler::fgOrderBlockOps(GenTreePtr tree,
18656 GenTreePtr* opsPtr, // OUT
18657 regMaskTP* regsPtr) // OUT
18659 assert(tree->OperIsBlkOp());
18661 GenTreeBlk* destBlk = tree->gtOp.gtOp1->AsBlk();
18662 GenTreePtr destAddr = destBlk->Addr();
18663 GenTreePtr srcPtrOrVal = tree->gtOp.gtOp2;
18664 if (tree->OperIsCopyBlkOp())
18666 assert(srcPtrOrVal->OperIsIndir());
18667 srcPtrOrVal = srcPtrOrVal->AsIndir()->Addr();
18669 GenTreePtr sizeNode = (destBlk->gtOper == GT_DYN_BLK) ? destBlk->AsDynBlk()->gtDynamicSize : nullptr;
18670 noway_assert((sizeNode != nullptr) || ((destBlk->gtFlags & GTF_REVERSE_OPS) == 0));
18671 assert(destAddr != nullptr);
18672 assert(srcPtrOrVal != nullptr);
18674 GenTreePtr ops[3] = {
18675 destAddr, // Dest address
18676 srcPtrOrVal, // Val / Src address
18677 sizeNode // Size of block
18680 regMaskTP regs[3] = {reg0, reg1, reg2};
18682 static int blockOpsOrder[4][3] =
18683 // destBlk->gtEvalSizeFirst | tree->gtFlags
18685 // -------------------------+----------------------------
18686 {0, 1, 2}, // false | -
18687 {2, 0, 1}, // true | -
18688 {1, 0, 2}, // false | GTF_REVERSE_OPS
18689 {2, 1, 0} // true | GTF_REVERSE_OPS
18692 int orderNum = ((destBlk->gtFlags & GTF_REVERSE_OPS) != 0) * 1 + ((tree->gtFlags & GTF_REVERSE_OPS) != 0) * 2;
18694 assert(orderNum < 4);
18696 int* order = blockOpsOrder[orderNum];
18698 PREFIX_ASSUME(order != NULL);
18700 // Fill in the OUT arrays according to the order we have selected
18702 opsPtr[0] = ops[order[0]];
18703 opsPtr[1] = ops[order[1]];
18704 opsPtr[2] = ops[order[2]];
18706 regsPtr[0] = regs[order[0]];
18707 regsPtr[1] = regs[order[1]];
18708 regsPtr[2] = regs[order[2]];
18710 #endif // LEGACY_BACKEND
18712 //------------------------------------------------------------------------
18713 // fgGetFirstNode: Get the first node in the tree, in execution order
18716 // tree - The top node of the tree of interest
18719 // The first node in execution order, that belongs to tree.
18722 // 'tree' must either be a leaf, or all of its constituent nodes must be contiguous
18723 // in execution order.
18724 // TODO-Cleanup: Add a debug-only method that verifies this.
18727 GenTreePtr Compiler::fgGetFirstNode(GenTreePtr tree)
18729 GenTreePtr child = tree;
18730 while (child->NumChildren() > 0)
18732 if (child->OperIsBinary() && child->IsReverseOp())
18734 child = child->GetChild(1);
18738 child = child->GetChild(0);
18744 // Examine the bbTreeList and return the estimated code size for this block
18745 unsigned Compiler::fgGetCodeEstimate(BasicBlock* block)
18747 unsigned costSz = 0; // estimate of blocks code size cost
18749 switch (block->bbJumpKind)
18755 case BBJ_EHCATCHRET:
18760 case BBJ_CALLFINALLY:
18767 costSz = 1; // We place a int3 after the code for a throw block
18769 case BBJ_EHFINALLYRET:
18770 case BBJ_EHFILTERRET:
18773 case BBJ_RETURN: // return from method
18777 noway_assert(!"Bad bbJumpKind");
18781 GenTreePtr tree = block->FirstNonPhiDef();
18786 noway_assert(tree->gtOper == GT_STMT);
18788 if (tree->gtCostSz < MAX_COST)
18790 costSz += tree->gtCostSz;
18794 // We could walk the tree to find out the real gtCostSz,
18795 // but just using MAX_COST for this trees code size works OK
18796 costSz += tree->gtCostSz;
18799 tree = tree->gtNext;
18806 #if DUMP_FLOWGRAPHS
18808 struct escapeMapping_t
18814 // clang-format off
18815 static escapeMapping_t s_EscapeFileMapping[] =
18828 static escapeMapping_t s_EscapeMapping[] =
18838 const char* Compiler::fgProcessEscapes(const char* nameIn, escapeMapping_t* map)
18840 const char* nameOut = nameIn;
18841 unsigned lengthOut;
18844 bool subsitutionRequired;
18848 subsitutionRequired = false;
18850 while (*pChar != '\0')
18854 while (map[index].ch != 0)
18856 if (*pChar == map[index].ch)
18865 subsitutionRequired = true;
18866 lengthOut += (unsigned)strlen(map[index].sub);
18875 if (subsitutionRequired)
18877 char* newName = (char*)compGetMemA(lengthOut, CMK_DebugOnly);
18881 while (*pChar != '\0')
18885 while (map[index].ch != 0)
18887 if (*pChar == map[index].ch)
18896 strcpy(pDest, map[index].sub);
18897 pDest += strlen(map[index].sub);
18906 nameOut = (const char*)newName;
18912 static void fprintfDouble(FILE* fgxFile, double value)
18914 assert(value >= 0.0);
18916 if ((value >= 0.010) || (value == 0.0))
18918 fprintf(fgxFile, "\"%7.3f\"", value);
18920 else if (value >= 0.00010)
18922 fprintf(fgxFile, "\"%7.5f\"", value);
18926 fprintf(fgxFile, "\"%7E\"", value);
18930 //------------------------------------------------------------------------
18931 // fgOpenFlowGraphFile: Open a file to dump either the xml or dot format flow graph
18934 // wbDontClose - A boolean out argument that indicates whether the caller should close the file
18935 // phase - A phase identifier to indicate which phase is associated with the dump
18936 // type - A (wide) string indicating the type of dump, "dot" or "xml"
18939 // Opens a file to which a flowgraph can be dumped, whose name is based on the current
18942 FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type)
18945 LPCWSTR pattern = nullptr;
18946 LPCWSTR filename = nullptr;
18947 LPCWSTR pathname = nullptr;
18948 const char* escapedString;
18949 bool createDuplicateFgxFiles = true;
18952 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
18954 pattern = JitConfig.NgenDumpFg();
18955 filename = JitConfig.NgenDumpFgFile();
18956 pathname = JitConfig.NgenDumpFgDir();
18960 pattern = JitConfig.JitDumpFg();
18961 filename = JitConfig.JitDumpFgFile();
18962 pathname = JitConfig.JitDumpFgDir();
18966 if (fgBBcount <= 1)
18971 if (pattern == nullptr)
18976 if (wcslen(pattern) == 0)
18981 LPCWSTR phasePattern = JitConfig.JitDumpFgPhase();
18982 LPCWSTR phaseName = PhaseShortNames[phase];
18983 if (phasePattern == nullptr)
18985 if (phase != PHASE_DETERMINE_FIRST_COLD_BLOCK)
18990 else if (*phasePattern != W('*'))
18992 if (wcsstr(phasePattern, phaseName) == nullptr)
18998 if (*pattern != W('*'))
19000 bool hasColon = (wcschr(pattern, W(':')) != nullptr);
19004 const char* className = info.compClassName;
19005 if (*pattern == W('*'))
19011 while ((*pattern != W(':')) && (*pattern != W('*')))
19013 if (*pattern != *className)
19021 if (*pattern == W('*'))
19027 if (*className != 0)
19033 if (*pattern != W(':'))
19041 const char* methodName = info.compMethodName;
19042 if (*pattern == W('*'))
19048 while ((*pattern != 0) && (*pattern != W('*')))
19050 if (*pattern != *methodName)
19058 if (*pattern == W('*'))
19064 if (*methodName != 0)
19076 if (filename == nullptr)
19078 filename = W("default");
19081 if (wcscmp(filename, W("profiled")) == 0)
19083 if (fgFirstBB->hasProfileWeight())
19085 createDuplicateFgxFiles = true;
19086 goto ONE_FILE_PER_METHOD;
19093 if (wcscmp(filename, W("hot")) == 0)
19095 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
19098 createDuplicateFgxFiles = true;
19099 goto ONE_FILE_PER_METHOD;
19106 else if (wcscmp(filename, W("cold")) == 0)
19108 if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
19110 createDuplicateFgxFiles = true;
19111 goto ONE_FILE_PER_METHOD;
19118 else if (wcscmp(filename, W("jit")) == 0)
19120 if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
19122 createDuplicateFgxFiles = true;
19123 goto ONE_FILE_PER_METHOD;
19130 else if (wcscmp(filename, W("all")) == 0)
19132 createDuplicateFgxFiles = true;
19134 ONE_FILE_PER_METHOD:;
19136 escapedString = fgProcessEscapes(info.compFullName, s_EscapeFileMapping);
19137 size_t wCharCount = strlen(escapedString) + wcslen(phaseName) + 1 + strlen("~999") + wcslen(type) + 1;
19138 if (pathname != nullptr)
19140 wCharCount += wcslen(pathname) + 1;
19142 filename = (LPCWSTR)alloca(wCharCount * sizeof(WCHAR));
19143 if (pathname != nullptr)
19145 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S-%s.%s"), pathname, escapedString, phaseName, type);
19149 swprintf_s((LPWSTR)filename, wCharCount, W("%S.%s"), escapedString, type);
19151 fgxFile = _wfopen(filename, W("r")); // Check if this file already exists
19152 if (fgxFile != nullptr)
19154 // For Generic methods we will have both hot and cold versions
19155 if (createDuplicateFgxFiles == false)
19160 // Yes, this filename already exists, so create a different one by appending ~2, ~3, etc...
19161 for (int i = 2; i < 1000; i++)
19164 if (pathname != nullptr)
19166 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S~%d.%s"), pathname, escapedString, i, type);
19170 swprintf_s((LPWSTR)filename, wCharCount, W("%S~%d.%s"), escapedString, i, type);
19172 fgxFile = _wfopen(filename, W("r")); // Check if this file exists
19173 if (fgxFile == nullptr)
19178 // If we have already created 1000 files with this name then just fail
19179 if (fgxFile != nullptr)
19185 fgxFile = _wfopen(filename, W("a+"));
19186 *wbDontClose = false;
19188 else if (wcscmp(filename, W("stdout")) == 0)
19190 fgxFile = jitstdout;
19191 *wbDontClose = true;
19193 else if (wcscmp(filename, W("stderr")) == 0)
19196 *wbDontClose = true;
19200 LPCWSTR origFilename = filename;
19201 size_t wCharCount = wcslen(origFilename) + wcslen(type) + 2;
19202 if (pathname != nullptr)
19204 wCharCount += wcslen(pathname) + 1;
19206 filename = (LPCWSTR)alloca(wCharCount * sizeof(WCHAR));
19207 if (pathname != nullptr)
19209 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%s.%s"), pathname, origFilename, type);
19213 swprintf_s((LPWSTR)filename, wCharCount, W("%s.%s"), origFilename, type);
19215 fgxFile = _wfopen(filename, W("a+"));
19216 *wbDontClose = false;
19222 //------------------------------------------------------------------------
19223 // fgDumpFlowGraph: Dump the xml or dot format flow graph, if enabled for this phase.
19226 // phase - A phase identifier to indicate which phase is associated with the dump,
19227 // i.e. which phase has just completed.
19230 // True iff a flowgraph has been dumped.
19233 // The xml dumps are the historical mechanism for dumping the flowgraph.
19234 // The dot format can be viewed by:
19235 // - Graphviz (http://www.graphviz.org/)
19236 // - The command "C:\Program Files (x86)\Graphviz2.38\bin\dot.exe" -Tsvg -oFoo.svg -Kdot Foo.dot
19237 // will produce a Foo.svg file that can be opened with any svg-capable browser (e.g. IE).
19238 // - http://rise4fun.com/Agl/
19239 // - Cut and paste the graph from your .dot file, replacing the digraph on the page, and then click the play
19241 // - It will show a rotating '/' and then render the graph in the browser.
19242 // MSAGL has also been open-sourced to https://github.com/Microsoft/automatic-graph-layout.git.
19244 // Here are the config values that control it:
19245 // COMPlus_JitDumpFg A string (ala the COMPlus_JitDump string) indicating what methods to dump flowgraphs
19247 // COMPlus_JitDumpFgDir A path to a directory into which the flowgraphs will be dumped.
19248 // COMPlus_JitDumpFgFile The filename to use. The default is "default.[xml|dot]".
19249 // Note that the new graphs will be appended to this file if it already exists.
19250 // COMPlus_JitDumpFgPhase Phase(s) after which to dump the flowgraph.
19251 // Set to the short name of a phase to see the flowgraph after that phase.
19252 // Leave unset to dump after COLD-BLK (determine first cold block) or set to * for all
19254 // COMPlus_JitDumpFgDot Set to non-zero to emit Dot instead of Xml Flowgraph dump. (Default is xml format.)
19256 bool Compiler::fgDumpFlowGraph(Phases phase)
19258 bool result = false;
19259 bool dontClose = false;
19260 bool createDotFile = false;
19261 if (JitConfig.JitDumpFgDot())
19263 createDotFile = true;
19266 FILE* fgxFile = fgOpenFlowGraphFile(&dontClose, phase, createDotFile ? W("dot") : W("fgx"));
19268 if (fgxFile == nullptr)
19272 bool validWeights = fgHaveValidEdgeWeights;
19273 unsigned calledCount = max(fgCalledCount, BB_UNITY_WEIGHT) / BB_UNITY_WEIGHT;
19274 double weightDivisor = (double)(calledCount * BB_UNITY_WEIGHT);
19275 const char* escapedString;
19276 const char* regionString = "NONE";
19278 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
19280 regionString = "HOT";
19282 else if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
19284 regionString = "COLD";
19286 else if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
19288 regionString = "JIT";
19293 fprintf(fgxFile, "digraph %s\n{\n", info.compMethodName);
19294 fprintf(fgxFile, "/* Method %d, after phase %s */", Compiler::jitTotalMethodCompiled, PhaseNames[phase]);
19298 fprintf(fgxFile, "<method");
19300 escapedString = fgProcessEscapes(info.compFullName, s_EscapeMapping);
19301 fprintf(fgxFile, "\n name=\"%s\"", escapedString);
19303 escapedString = fgProcessEscapes(info.compClassName, s_EscapeMapping);
19304 fprintf(fgxFile, "\n className=\"%s\"", escapedString);
19306 escapedString = fgProcessEscapes(info.compMethodName, s_EscapeMapping);
19307 fprintf(fgxFile, "\n methodName=\"%s\"", escapedString);
19308 fprintf(fgxFile, "\n ngenRegion=\"%s\"", regionString);
19310 fprintf(fgxFile, "\n bytesOfIL=\"%d\"", info.compILCodeSize);
19311 fprintf(fgxFile, "\n localVarCount=\"%d\"", lvaCount);
19313 if (fgHaveProfileData())
19315 fprintf(fgxFile, "\n calledCount=\"%d\"", calledCount);
19316 fprintf(fgxFile, "\n profileData=\"true\"");
19318 if (compHndBBtabCount > 0)
19320 fprintf(fgxFile, "\n hasEHRegions=\"true\"");
19324 fprintf(fgxFile, "\n hasLoops=\"true\"");
19328 fprintf(fgxFile, "\n validEdgeWeights=\"true\"");
19329 if (!fgSlopUsedInEdgeWeights && !fgRangeUsedInEdgeWeights)
19331 fprintf(fgxFile, "\n exactEdgeWeights=\"true\"");
19334 if (fgFirstColdBlock != nullptr)
19336 fprintf(fgxFile, "\n firstColdBlock=\"%d\"", fgFirstColdBlock->bbNum);
19339 fprintf(fgxFile, ">");
19341 fprintf(fgxFile, "\n <blocks");
19342 fprintf(fgxFile, "\n blockCount=\"%d\"", fgBBcount);
19343 fprintf(fgxFile, ">");
19346 static const char* kindImage[] = {"EHFINALLYRET", "EHFILTERRET", "EHCATCHRET", "THROW", "RETURN", "NONE",
19347 "ALWAYS", "LEAVE", "CALLFINALLY", "COND", "SWITCH"};
19350 unsigned blockOrdinal;
19351 for (block = fgFirstBB, blockOrdinal = 1; block != nullptr; block = block->bbNext, blockOrdinal++)
19355 // Add constraint edges to try to keep nodes ordered.
19356 // It seems to work best if these edges are all created first.
19357 switch (block->bbJumpKind)
19361 assert(block->bbNext != nullptr);
19362 fprintf(fgxFile, " BB%02u -> BB%02u\n", block->bbNum, block->bbNext->bbNum);
19365 // These may or may not have an edge to the next block.
19366 // Add a transparent edge to keep nodes ordered.
19367 if (block->bbNext != nullptr)
19369 fprintf(fgxFile, " BB%02u -> BB%02u [arrowtail=none,color=transparent]\n", block->bbNum,
19370 block->bbNext->bbNum);
19376 fprintf(fgxFile, "\n <block");
19377 fprintf(fgxFile, "\n id=\"%d\"", block->bbNum);
19378 fprintf(fgxFile, "\n ordinal=\"%d\"", blockOrdinal);
19379 fprintf(fgxFile, "\n jumpKind=\"%s\"", kindImage[block->bbJumpKind]);
19380 if (block->hasTryIndex())
19382 fprintf(fgxFile, "\n inTry=\"%s\"", "true");
19384 if (block->hasHndIndex())
19386 fprintf(fgxFile, "\n inHandler=\"%s\"", "true");
19388 if ((fgFirstBB->hasProfileWeight()) && ((block->bbFlags & BBF_COLD) == 0))
19390 fprintf(fgxFile, "\n hot=\"true\"");
19392 if (block->bbFlags & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY))
19394 fprintf(fgxFile, "\n callsNew=\"true\"");
19396 if (block->bbFlags & BBF_LOOP_HEAD)
19398 fprintf(fgxFile, "\n loopHead=\"true\"");
19400 fprintf(fgxFile, "\n weight=");
19401 fprintfDouble(fgxFile, ((double)block->bbWeight) / weightDivisor);
19402 fprintf(fgxFile, "\n codeEstimate=\"%d\"", fgGetCodeEstimate(block));
19403 fprintf(fgxFile, "\n startOffset=\"%d\"", block->bbCodeOffs);
19404 fprintf(fgxFile, "\n endOffset=\"%d\"", block->bbCodeOffsEnd);
19405 fprintf(fgxFile, ">");
19406 fprintf(fgxFile, "\n </block>");
19410 if (!createDotFile)
19412 fprintf(fgxFile, "\n </blocks>");
19414 fprintf(fgxFile, "\n <edges");
19415 fprintf(fgxFile, "\n edgeCount=\"%d\"", fgEdgeCount);
19416 fprintf(fgxFile, ">");
19419 unsigned edgeNum = 1;
19420 BasicBlock* bTarget;
19421 for (bTarget = fgFirstBB; bTarget != nullptr; bTarget = bTarget->bbNext)
19423 double targetWeightDivisor;
19424 if (bTarget->bbWeight == BB_ZERO_WEIGHT)
19426 targetWeightDivisor = 1.0;
19430 targetWeightDivisor = (double)bTarget->bbWeight;
19434 for (edge = bTarget->bbPreds; edge != nullptr; edge = edge->flNext, edgeNum++)
19436 BasicBlock* bSource = edge->flBlock;
19437 double sourceWeightDivisor;
19438 if (bSource->bbWeight == BB_ZERO_WEIGHT)
19440 sourceWeightDivisor = 1.0;
19444 sourceWeightDivisor = (double)bSource->bbWeight;
19448 // Don't duplicate the edges we added above.
19449 if ((bSource->bbNum == (bTarget->bbNum - 1)) &&
19450 ((bSource->bbJumpKind == BBJ_NONE) || (bSource->bbJumpKind == BBJ_COND)))
19454 fprintf(fgxFile, " BB%02u -> BB%02u", bSource->bbNum, bTarget->bbNum);
19455 if ((bSource->bbNum > bTarget->bbNum))
19457 fprintf(fgxFile, "[arrowhead=normal,arrowtail=none,color=green]\n");
19461 fprintf(fgxFile, "\n");
19466 fprintf(fgxFile, "\n <edge");
19467 fprintf(fgxFile, "\n id=\"%d\"", edgeNum);
19468 fprintf(fgxFile, "\n source=\"%d\"", bSource->bbNum);
19469 fprintf(fgxFile, "\n target=\"%d\"", bTarget->bbNum);
19470 if (bSource->bbJumpKind == BBJ_SWITCH)
19472 if (edge->flDupCount >= 2)
19474 fprintf(fgxFile, "\n switchCases=\"%d\"", edge->flDupCount);
19476 if (bSource->bbJumpSwt->getDefault() == bTarget)
19478 fprintf(fgxFile, "\n switchDefault=\"true\"");
19483 unsigned edgeWeight = (edge->flEdgeWeightMin + edge->flEdgeWeightMax) / 2;
19484 fprintf(fgxFile, "\n weight=");
19485 fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor);
19487 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
19489 fprintf(fgxFile, "\n minWeight=");
19490 fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMin) / weightDivisor);
19491 fprintf(fgxFile, "\n maxWeight=");
19492 fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMax) / weightDivisor);
19495 if (edgeWeight > 0)
19497 if (edgeWeight < bSource->bbWeight)
19499 fprintf(fgxFile, "\n out=");
19500 fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor);
19502 if (edgeWeight < bTarget->bbWeight)
19504 fprintf(fgxFile, "\n in=");
19505 fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor);
19510 if (!createDotFile)
19512 fprintf(fgxFile, ">");
19513 fprintf(fgxFile, "\n </edge>");
19519 fprintf(fgxFile, "}\n");
19523 fprintf(fgxFile, "\n </edges>");
19524 fprintf(fgxFile, "\n</method>\n");
19529 // fgxFile is jitstdout or stderr
19530 fprintf(fgxFile, "\n");
19540 #endif // DUMP_FLOWGRAPHS
19542 /*****************************************************************************/
19545 void Compiler::fgDispReach()
19547 printf("------------------------------------------------\n");
19548 printf("BBnum Reachable by \n");
19549 printf("------------------------------------------------\n");
19551 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
19553 printf("BB%02u : ", block->bbNum);
19554 BLOCKSET_ITER_INIT(this, iter, block->bbReach, bbNum);
19555 while (iter.NextElem(this, &bbNum))
19557 printf("BB%02u ", bbNum);
19563 void Compiler::fgDispDoms()
19565 // Don't bother printing this when we have a large number of BasicBlocks in the method
19566 if (fgBBcount > 256)
19571 printf("------------------------------------------------\n");
19572 printf("BBnum Dominated by\n");
19573 printf("------------------------------------------------\n");
19575 for (unsigned i = 1; i <= fgBBNumMax; ++i)
19577 BasicBlock* current = fgBBInvPostOrder[i];
19578 printf("BB%02u: ", current->bbNum);
19579 while (current != current->bbIDom)
19581 printf("BB%02u ", current->bbNum);
19582 current = current->bbIDom;
19588 /*****************************************************************************/
19590 void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 */)
19592 const unsigned __int64 flags = block->bbFlags;
19593 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
19594 int maxBlockNumWidth = CountDigits(bbNumMax);
19595 maxBlockNumWidth = max(maxBlockNumWidth, 2);
19596 int blockNumWidth = CountDigits(block->bbNum);
19597 blockNumWidth = max(blockNumWidth, 2);
19598 int blockNumPadding = maxBlockNumWidth - blockNumWidth;
19600 printf("BB%02u%*s [%08p] %2u", block->bbNum, blockNumPadding, "", dspPtr(block), block->bbRefs);
19603 // Display EH 'try' region index
19606 if (block->hasTryIndex())
19608 printf(" %2u", block->getTryIndex());
19616 // Display EH handler region index
19619 if (block->hasHndIndex())
19621 printf(" %2u", block->getHndIndex());
19631 // Display block predecessor list
19635 if (fgCheapPredsValid)
19637 charCnt = block->dspCheapPreds();
19641 charCnt = block->dspPreds();
19646 printf("%*s", 19 - charCnt, "");
19652 // Display block weight
19655 if (block->isMaxBBWeight())
19661 BasicBlock::weight_t weight = block->getBBWeight(this);
19663 if (weight > 99999) // Is it going to be more than 6 characters?
19665 if (weight <= 99999 * BB_UNITY_WEIGHT)
19667 // print weight in this format ddddd.
19668 printf("%5u.", (weight + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT);
19670 else // print weight in terms of k (i.e. 156k )
19672 // print weight in this format dddddk
19673 BasicBlock::weight_t weightK = weight / 1000;
19674 printf("%5uk", (weightK + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT);
19677 else // print weight in this format ddd.dd
19679 printf("%6s", refCntWtd2str(weight));
19685 // Display optional IBC weight column.
19686 // Note that iColWidth includes one character for a leading space, if there is an IBC column.
19689 if (ibcColWidth > 0)
19691 if (block->hasProfileWeight())
19693 printf("%*u", ibcColWidth, block->bbWeight);
19697 // No IBC data. Just print spaces to align the column.
19698 printf("%*s", ibcColWidth, "");
19705 // Display block IL range
19708 block->dspBlockILRange();
19711 // Display block branch target
19714 if (flags & BBF_REMOVED)
19716 printf("[removed] ");
19720 switch (block->bbJumpKind)
19723 printf("-> BB%02u%*s ( cond )", block->bbJumpDest->bbNum,
19724 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19727 case BBJ_CALLFINALLY:
19728 printf("-> BB%02u%*s (callf )", block->bbJumpDest->bbNum,
19729 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19733 if (flags & BBF_KEEP_BBJ_ALWAYS)
19735 printf("-> BB%02u%*s (ALWAYS)", block->bbJumpDest->bbNum,
19736 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19740 printf("-> BB%02u%*s (always)", block->bbJumpDest->bbNum,
19741 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19746 printf("-> BB%02u%*s (leave )", block->bbJumpDest->bbNum,
19747 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19750 case BBJ_EHFINALLYRET:
19751 printf("%*s (finret)", maxBlockNumWidth - 2, "");
19754 case BBJ_EHFILTERRET:
19755 printf("%*s (fltret)", maxBlockNumWidth - 2, "");
19758 case BBJ_EHCATCHRET:
19759 printf("-> BB%02u%*s ( cret )", block->bbJumpDest->bbNum,
19760 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
19764 printf("%*s (throw )", maxBlockNumWidth - 2, "");
19768 printf("%*s (return)", maxBlockNumWidth - 2, "");
19772 printf("%*s ", maxBlockNumWidth - 2, "");
19779 jumpCnt = block->bbJumpSwt->bbsCount;
19780 BasicBlock** jumpTab;
19781 jumpTab = block->bbJumpSwt->bbsDstTab;
19786 printf("%cBB%02u", (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',', (*jumpTab)->bbNum);
19787 switchWidth += 1 /* space/comma */ + 2 /* BB */ + max(CountDigits((*jumpTab)->bbNum), 2);
19788 } while (++jumpTab, --jumpCnt);
19790 if (switchWidth < 7)
19792 printf("%*s", 8 - switchWidth, "");
19795 printf(" (switch)");
19803 // Display block EH region and type, including nesting indicator
19806 if (block->hasTryIndex())
19808 printf("T%d ", block->getTryIndex());
19815 if (block->hasHndIndex())
19817 printf("H%d ", block->getHndIndex());
19824 if (flags & BBF_FUNCLET_BEG)
19835 switch (block->bbCatchTyp)
19844 printf("finally ");
19851 case BBCT_FILTER_HANDLER:
19852 printf("filtHnd ");
19861 if (block->bbCatchTyp != BBCT_NONE)
19865 /* brace matching editor workaround to compensate for the preceding line: } */
19868 if (flags & BBF_TRY_BEG)
19870 // Output a brace for every try region that this block opens
19873 EHblkDsc* HBtabEnd;
19875 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
19877 if (HBtab->ebdTryBeg == block)
19881 /* brace matching editor workaround to compensate for the preceding line: } */
19887 EHblkDsc* HBtabEnd;
19889 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
19891 if (HBtab->ebdTryLast == block)
19894 /* brace matching editor workaround to compensate for the following line: { */
19897 if (HBtab->ebdHndLast == block)
19900 /* brace matching editor workaround to compensate for the following line: { */
19903 if (HBtab->HasFilter() && block->bbNext == HBtab->ebdHndBeg)
19906 /* brace matching editor workaround to compensate for the following line: { */
19918 // Display block flags
19926 /****************************************************************************
19927 Dump blocks from firstBlock to lastBlock.
19930 void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees)
19935 #ifdef _TARGET_AMD64_
19937 #endif // _TARGET_AMD64_
19939 // If any block has IBC data, we add an "IBC weight" column just before the 'IL range' column. This column is as
19940 // wide as necessary to accommodate all the various IBC weights. It's at least 4 characters wide, to accommodate
19941 // the "IBC" title and leading space.
19942 int ibcColWidth = 0;
19943 for (block = firstBlock; block != nullptr; block = block->bbNext)
19945 if (block->hasProfileWeight())
19947 int thisIbcWidth = CountDigits(block->bbWeight);
19948 ibcColWidth = max(ibcColWidth, thisIbcWidth);
19951 if (block == lastBlock)
19956 if (ibcColWidth > 0)
19958 ibcColWidth = max(ibcColWidth, 3) + 1; // + 1 for the leading space
19961 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
19962 int maxBlockNumWidth = CountDigits(bbNumMax);
19963 maxBlockNumWidth = max(maxBlockNumWidth, 2);
19965 padWidth += maxBlockNumWidth - 2; // Account for functions with a large number of blocks.
19967 // clang-format off
19970 printf("------%*s-------------------------------------%*s-----------------------%*s----------------------------------------\n",
19971 padWidth, "------------",
19972 ibcColWidth, "------------",
19973 maxBlockNumWidth, "----");
19974 printf("BBnum %*sdescAddr ref try hnd %s weight %*s%s [IL range] [jump]%*s [EH region] [flags]\n",
19976 fgCheapPredsValid ? "cheap preds" :
19977 (fgComputePredsDone ? "preds "
19979 ((ibcColWidth > 0) ? ibcColWidth - 3 : 0), "", // Subtract 3 for the width of "IBC", printed next.
19980 ((ibcColWidth > 0) ? "IBC"
19982 maxBlockNumWidth, ""
19984 printf("------%*s-------------------------------------%*s-----------------------%*s----------------------------------------\n",
19985 padWidth, "------------",
19986 ibcColWidth, "------------",
19987 maxBlockNumWidth, "----");
19991 for (block = firstBlock; block; block = block->bbNext)
19993 // First, do some checking on the bbPrev links
19996 if (block->bbPrev->bbNext != block)
19998 printf("bad prev link\n");
20001 else if (block != fgFirstBB)
20003 printf("bad prev link!\n");
20006 if (block == fgFirstColdBlock)
20008 printf("~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~"
20009 "~~~~~~~~~~~~~~~~\n",
20010 padWidth, "~~~~~~~~~~~~", ibcColWidth, "~~~~~~~~~~~~", maxBlockNumWidth, "~~~~");
20013 #if FEATURE_EH_FUNCLETS
20014 if (block == fgFirstFuncletBB)
20016 printf("++++++%*s+++++++++++++++++++++++++++++++++++++%*s+++++++++++++++++++++++%*s++++++++++++++++++++++++"
20017 "++++++++++++++++ funclets follow\n",
20018 padWidth, "++++++++++++", ibcColWidth, "++++++++++++", maxBlockNumWidth, "++++");
20020 #endif // FEATURE_EH_FUNCLETS
20022 fgTableDispBasicBlock(block, ibcColWidth);
20024 if (block == lastBlock)
20030 printf("------%*s-------------------------------------%*s-----------------------%*s--------------------------------"
20032 padWidth, "------------", ibcColWidth, "------------", maxBlockNumWidth, "----");
20036 fgDumpTrees(firstBlock, lastBlock);
20040 /*****************************************************************************/
20042 void Compiler::fgDispBasicBlocks(bool dumpTrees)
20044 fgDispBasicBlocks(fgFirstBB, nullptr, dumpTrees);
20047 /*****************************************************************************/
20048 // Increment the stmtNum and dump the tree using gtDispTree
20050 void Compiler::fgDumpStmtTree(GenTreePtr stmt, unsigned blkNum)
20052 compCurStmtNum++; // Increment the current stmtNum
20054 printf("\n***** BB%02u, stmt %d\n", blkNum, compCurStmtNum);
20056 if (fgOrder == FGOrderLinear || opts.compDbgInfo)
20062 gtDispTree(stmt->gtStmt.gtStmtExpr);
20066 //------------------------------------------------------------------------
20067 // Compiler::fgDumpBlock: dumps the contents of the given block to stdout.
20070 // block - The block to dump.
20072 void Compiler::fgDumpBlock(BasicBlock* block)
20074 printf("\n------------ ");
20075 block->dspBlockHeader(this);
20077 if (!block->IsLIR())
20079 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
20081 fgDumpStmtTree(stmt, block->bbNum);
20082 if (stmt == block->bbTreeList)
20084 block->bbStmtNum = compCurStmtNum; // Set the block->bbStmtNum
20090 gtDispRange(LIR::AsRange(block));
20094 /*****************************************************************************/
20095 // Walk the BasicBlock list calling fgDumpTree once per Stmt
20097 void Compiler::fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock)
20099 compCurStmtNum = 0; // Reset the current stmtNum
20101 /* Walk the basic blocks */
20103 // Note that typically we have already called fgDispBasicBlocks()
20104 // so we don't need to print the preds and succs again here
20106 for (BasicBlock* block = firstBlock; block; block = block->bbNext)
20108 fgDumpBlock(block);
20110 if (block == lastBlock)
20115 printf("\n---------------------------------------------------------------------------------------------------------"
20119 /*****************************************************************************
20120 * Try to create as many candidates for GTF_MUL_64RSLT as possible.
20121 * We convert 'intOp1*intOp2' into 'int(long(nop(intOp1))*long(intOp2))'.
20125 Compiler::fgWalkResult Compiler::fgStress64RsltMulCB(GenTreePtr* pTree, fgWalkData* data)
20127 GenTreePtr tree = *pTree;
20128 Compiler* pComp = data->compiler;
20130 if (tree->gtOper != GT_MUL || tree->gtType != TYP_INT || (tree->gtOverflow()))
20132 return WALK_CONTINUE;
20136 if (pComp->verbose)
20138 printf("STRESS_64RSLT_MUL before:\n");
20139 pComp->gtDispTree(tree);
20143 // To ensure optNarrowTree() doesn't fold back to the original tree.
20144 tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, TYP_LONG);
20145 tree->gtOp.gtOp1 = pComp->gtNewOperNode(GT_NOP, TYP_LONG, tree->gtOp.gtOp1);
20146 tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, TYP_LONG);
20147 tree->gtOp.gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp2, TYP_LONG);
20148 tree->gtType = TYP_LONG;
20149 *pTree = pComp->gtNewCastNode(TYP_INT, tree, TYP_INT);
20152 if (pComp->verbose)
20154 printf("STRESS_64RSLT_MUL after:\n");
20155 pComp->gtDispTree(*pTree);
20159 return WALK_SKIP_SUBTREES;
20162 void Compiler::fgStress64RsltMul()
20164 if (!compStressCompile(STRESS_64RSLT_MUL, 20))
20169 fgWalkAllTreesPre(fgStress64RsltMulCB, (void*)this);
20172 // This variable is used to generate "traversal labels": one-time constants with which
20173 // we label basic blocks that are members of the basic block list, in order to have a
20174 // fast, high-probability test for membership in that list. Type is "volatile" because
20175 // it's incremented with an atomic operation, which wants a volatile type; "long" so that
20176 // wrap-around to 0 (which I think has the highest probability of accidental collision) is
20177 // postponed a *long* time.
20178 static volatile int bbTraverseLabel = 1;
20180 /*****************************************************************************
20182 * A DEBUG routine to check the consistency of the flowgraph,
20183 * i.e. bbNum, bbRefs, bbPreds have to be up to date.
20185 *****************************************************************************/
20187 void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRefs /* = true */)
20192 printf("*************** In fgDebugCheckBBlist\n");
20196 fgDebugCheckBlockLinks();
20198 if (fgBBcount > 10000 && expensiveDebugCheckLevel < 1)
20200 // The basic block checks are too expensive if there are too many blocks,
20201 // so give up unless we've been told to try hard.
20205 DWORD startTickCount = GetTickCount();
20208 BasicBlock* prevBlock;
20209 BasicBlock* blockPred;
20211 unsigned blockRefs;
20213 #if FEATURE_EH_FUNCLETS
20214 bool reachedFirstFunclet = false;
20215 if (fgFuncletsCreated)
20218 // Make sure that fgFirstFuncletBB is accurate.
20219 // It should be the first basic block in a handler region.
20221 if (fgFirstFuncletBB != nullptr)
20223 assert(fgFirstFuncletBB->hasHndIndex() == true);
20224 assert(fgFirstFuncletBB->bbFlags & BBF_FUNCLET_BEG);
20227 #endif // FEATURE_EH_FUNCLETS
20229 /* Check bbNum, bbRefs and bbPreds */
20230 // First, pick a traversal stamp, and label all the blocks with it.
20231 unsigned curTraversalStamp = unsigned(InterlockedIncrement((LONG*)&bbTraverseLabel));
20232 for (block = fgFirstBB; block; block = block->bbNext)
20234 block->bbTraversalStamp = curTraversalStamp;
20237 for (prevBlock = nullptr, block = fgFirstBB; block; prevBlock = block, block = block->bbNext)
20241 /* First basic block has countOfInEdges() >= 1 */
20243 if (block == fgFirstBB)
20245 noway_assert(block->countOfInEdges() >= 1);
20251 // Check that bbNum is sequential
20252 noway_assert(block->bbNext == nullptr || (block->bbNum + 1 == block->bbNext->bbNum));
20255 // If the block is a BBJ_COND, a BBJ_SWITCH or a
20256 // lowered GT_SWITCH_TABLE node then make sure it
20257 // ends with a conditional jump or a GT_SWITCH
20259 if (block->bbJumpKind == BBJ_COND)
20261 noway_assert(block->lastNode()->gtNext == nullptr && block->lastNode()->OperIsConditionalJump());
20263 else if (block->bbJumpKind == BBJ_SWITCH)
20265 #ifndef LEGACY_BACKEND
20266 noway_assert(block->lastNode()->gtNext == nullptr &&
20267 (block->lastNode()->gtOper == GT_SWITCH || block->lastNode()->gtOper == GT_SWITCH_TABLE));
20268 #else // LEGACY_BACKEND
20269 noway_assert(block->lastStmt()->gtNext == NULL && block->lastStmt()->gtStmtExpr->gtOper == GT_SWITCH);
20270 #endif // LEGACY_BACKEND
20272 else if (!(block->bbJumpKind == BBJ_ALWAYS || block->bbJumpKind == BBJ_RETURN))
20274 // this block cannot have a poll
20275 noway_assert(!(block->bbFlags & BBF_NEEDS_GCPOLL));
20278 if (block->bbCatchTyp == BBCT_FILTER)
20280 if (!fgCheapPredsValid) // Don't check cheap preds
20282 // A filter has no predecessors
20283 noway_assert(block->bbPreds == nullptr);
20287 #if FEATURE_EH_FUNCLETS
20288 if (fgFuncletsCreated)
20291 // There should be no handler blocks until
20292 // we get to the fgFirstFuncletBB block,
20293 // then every block should be a handler block
20295 if (!reachedFirstFunclet)
20297 if (block == fgFirstFuncletBB)
20299 assert(block->hasHndIndex() == true);
20300 reachedFirstFunclet = true;
20304 assert(block->hasHndIndex() == false);
20307 else // reachedFirstFunclet
20309 assert(block->hasHndIndex() == true);
20312 #endif // FEATURE_EH_FUNCLETS
20314 // Don't check cheap preds.
20315 for (pred = (fgCheapPredsValid ? nullptr : block->bbPreds); pred != nullptr;
20316 blockRefs += pred->flDupCount, pred = pred->flNext)
20318 assert(fgComputePredsDone); // If this isn't set, why do we have a preds list?
20320 /* make sure this pred is part of the BB list */
20322 blockPred = pred->flBlock;
20323 noway_assert(blockPred->bbTraversalStamp == curTraversalStamp);
20325 EHblkDsc* ehTryDsc = ehGetBlockTryDsc(block);
20326 if (ehTryDsc != nullptr)
20328 // You can jump to the start of a try
20329 if (ehTryDsc->ebdTryBeg == block)
20334 // You can jump within the same try region
20335 if (bbInTryRegions(block->getTryIndex(), blockPred))
20340 // The catch block can jump back into the middle of the try
20341 if (bbInCatchHandlerRegions(block, blockPred))
20346 // The end of a finally region is a BBJ_EHFINALLYRET block (during importing, BBJ_LEAVE) which
20347 // is marked as "returning" to the BBJ_ALWAYS block following the BBJ_CALLFINALLY
20348 // block that does a local call to the finally. This BBJ_ALWAYS is within
20349 // the try region protected by the finally (for x86, ARM), but that's ok.
20350 if (prevBlock->bbJumpKind == BBJ_CALLFINALLY && block->bbJumpKind == BBJ_ALWAYS &&
20351 blockPred->bbJumpKind == BBJ_EHFINALLYRET)
20356 printf("Jump into the middle of try region: BB%02u branches to BB%02u\n", blockPred->bbNum,
20358 noway_assert(!"Jump into middle of try region");
20363 EHblkDsc* ehHndDsc = ehGetBlockHndDsc(block);
20364 if (ehHndDsc != nullptr)
20366 // You can do a BBJ_EHFINALLYRET or BBJ_EHFILTERRET into a handler region
20367 if ((blockPred->bbJumpKind == BBJ_EHFINALLYRET) || (blockPred->bbJumpKind == BBJ_EHFILTERRET))
20372 // Our try block can call our finally block
20373 if ((block->bbCatchTyp == BBCT_FINALLY) && (blockPred->bbJumpKind == BBJ_CALLFINALLY) &&
20374 ehCallFinallyInCorrectRegion(blockPred, block->getHndIndex()))
20379 // You can jump within the same handler region
20380 if (bbInHandlerRegions(block->getHndIndex(), blockPred))
20385 // A filter can jump to the start of the filter handler
20386 if (ehHndDsc->HasFilter())
20391 printf("Jump into the middle of handler region: BB%02u branches to BB%02u\n", blockPred->bbNum,
20393 noway_assert(!"Jump into the middle of handler region");
20398 switch (blockPred->bbJumpKind)
20401 noway_assert(blockPred->bbNext == block || blockPred->bbJumpDest == block);
20405 noway_assert(blockPred->bbNext == block);
20408 case BBJ_CALLFINALLY:
20410 case BBJ_EHCATCHRET:
20411 case BBJ_EHFILTERRET:
20412 noway_assert(blockPred->bbJumpDest == block);
20415 case BBJ_EHFINALLYRET:
20417 // If the current block is a successor to a BBJ_EHFINALLYRET (return from finally),
20418 // then the lexically previous block should be a call to the same finally.
20419 // Verify all of that.
20421 unsigned hndIndex = blockPred->getHndIndex();
20422 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
20423 BasicBlock* finBeg = ehDsc->ebdHndBeg;
20425 // Because there is no bbPrev, we have to search for the lexically previous
20426 // block. We can shorten the search by only looking in places where it is legal
20427 // to have a call to the finally.
20429 BasicBlock* begBlk;
20430 BasicBlock* endBlk;
20431 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
20433 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
20435 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
20440 if (block == bcall->bbNext)
20446 #if FEATURE_EH_FUNCLETS
20448 if (fgFuncletsCreated)
20450 // There is no easy way to search just the funclets that were pulled out of
20451 // the corresponding try body, so instead we search all the funclets, and if
20452 // we find a potential 'hit' we check if the funclet we're looking at is
20453 // from the correct try region.
20455 for (BasicBlock* bcall = fgFirstFuncletBB; bcall; bcall = bcall->bbNext)
20457 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
20462 if (block != bcall->bbNext)
20467 if (ehCallFinallyInCorrectRegion(bcall, hndIndex))
20474 #endif // FEATURE_EH_FUNCLETS
20476 noway_assert(!"BBJ_EHFINALLYRET predecessor of block that doesn't follow a BBJ_CALLFINALLY!");
20482 noway_assert(!"THROW and RETURN block cannot be in the predecessor list!");
20487 jumpCnt = blockPred->bbJumpSwt->bbsCount;
20488 BasicBlock** jumpTab;
20489 jumpTab = blockPred->bbJumpSwt->bbsDstTab;
20493 if (block == *jumpTab)
20497 } while (++jumpTab, --jumpCnt);
20499 noway_assert(!"SWITCH in the predecessor list with no jump label to BLOCK!");
20503 noway_assert(!"Unexpected bbJumpKind");
20510 /* Check the bbRefs */
20511 noway_assert(!checkBBRefs || block->bbRefs == blockRefs);
20513 /* Check that BBF_HAS_HANDLER is valid bbTryIndex */
20514 if (block->hasTryIndex())
20516 noway_assert(block->getTryIndex() < compHndBBtabCount);
20519 /* Check if BBF_RUN_RARELY is set that we have bbWeight of zero */
20520 if (block->isRunRarely())
20522 noway_assert(block->bbWeight == BB_ZERO_WEIGHT);
20526 noway_assert(block->bbWeight > BB_ZERO_WEIGHT);
20530 // Make sure the one return BB is not changed.
20533 noway_assert(genReturnBB->bbTreeList);
20534 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtOper == GT_STMT);
20535 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtType == TYP_VOID);
20538 // The general encoder/decoder (currently) only reports "this" as a generics context as a stack location,
20539 // so we mark info.compThisArg as lvAddrTaken to ensure that it is not enregistered. Otherwise, it should
20540 // not be address-taken. This variable determines if the address-taken-ness of "thisArg" is "OK".
20541 bool copiedForGenericsCtxt;
20542 #ifndef JIT32_GCENCODER
20543 copiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
20544 #else // JIT32_GCENCODER
20545 copiedForGenericsCtxt = FALSE;
20546 #endif // JIT32_GCENCODER
20548 // This if only in support of the noway_asserts it contains.
20549 if (info.compIsStatic)
20551 // For static method, should have never grabbed the temp.
20552 noway_assert(lvaArg0Var == BAD_VAR_NUM);
20556 // For instance method:
20557 assert(info.compThisArg != BAD_VAR_NUM);
20558 bool compThisArgAddrExposedOK = !lvaTable[info.compThisArg].lvAddrExposed;
20560 #ifndef JIT32_GCENCODER
20561 compThisArgAddrExposedOK = compThisArgAddrExposedOK || copiedForGenericsCtxt;
20562 #endif // !JIT32_GCENCODER
20564 // Should never expose the address of arg 0 or write to arg 0.
20565 // In addition, lvArg0Var should remain 0 if arg0 is not
20566 // written to or address-exposed.
20568 compThisArgAddrExposedOK && !lvaTable[info.compThisArg].lvHasILStoreOp &&
20569 (lvaArg0Var == info.compThisArg ||
20570 lvaArg0Var != info.compThisArg &&
20571 (lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvHasILStoreOp || copiedForGenericsCtxt)));
20575 /*****************************************************************************
20577 * A DEBUG routine to check the that the exception flags are correctly set.
20579 ****************************************************************************/
20581 void Compiler::fgDebugCheckFlags(GenTreePtr tree)
20583 noway_assert(tree->gtOper != GT_STMT);
20585 genTreeOps oper = tree->OperGet();
20586 unsigned kind = tree->OperKind();
20587 unsigned treeFlags = tree->gtFlags & GTF_ALL_EFFECT;
20588 unsigned chkFlags = 0;
20590 /* Is this a leaf node? */
20592 if (kind & GTK_LEAF)
20597 chkFlags |= GTF_GLOB_REF;
20601 chkFlags |= GTF_ORDER_SIDEEFF;
20609 /* Is it a 'simple' unary/binary operator? */
20611 else if (kind & GTK_SMPOP)
20613 GenTreePtr op1 = tree->gtOp.gtOp1;
20614 GenTreePtr op2 = tree->gtGetOp2IfPresent();
20616 // During GS work, we make shadow copies for params.
20617 // In gsParamsToShadows(), we create a shadow var of TYP_INT for every small type param.
20618 // Then in gsReplaceShadowParams(), we change the gtLclNum to the shadow var.
20619 // We also change the types of the local var tree and the assignment tree to TYP_INT if necessary.
20620 // However, since we don't morph the tree at this late stage. Manually propagating
20621 // TYP_INT up to the GT_ASG tree is only correct if we don't need to propagate the TYP_INT back up.
20622 // The following checks will ensure this.
20624 // Is the left child of "tree" a GT_ASG?
20626 // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
20627 // (or) If GT_ASG is the left child of a GT_COMMA, the type of the GT_COMMA node will
20628 // be determined by its right child. So we don't need to propagate TYP_INT up either. We are fine.
20629 if (op1 && op1->gtOper == GT_ASG)
20631 assert(tree->gtType == TYP_VOID || tree->gtOper == GT_COMMA);
20634 // Is the right child of "tree" a GT_ASG?
20636 // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
20637 if (op2 && op2->gtOper == GT_ASG)
20639 assert(tree->gtType == TYP_VOID);
20645 if (op1->OperIsCompare())
20647 noway_assert(op1->gtFlags & GTF_DONT_CSE);
20651 noway_assert((op1->gtOper == GT_CNS_INT) &&
20652 ((op1->gtIntCon.gtIconVal == 0) || (op1->gtIntCon.gtIconVal == 1)));
20657 case GT_FIELD_LIST:
20658 if ((op2 != nullptr) && op2->OperIsAnyList())
20660 ArrayStack<GenTree*> stack(this);
20661 while ((tree->gtGetOp2() != nullptr) && tree->gtGetOp2()->OperIsAnyList())
20664 tree = tree->gtGetOp2();
20667 fgDebugCheckFlags(tree);
20669 while (stack.Height() > 0)
20671 tree = stack.Pop();
20672 assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
20673 fgDebugCheckFlags(tree->gtOp.gtOp1);
20674 chkFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
20675 chkFlags |= (tree->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
20676 fgDebugCheckFlagsHelper(tree, (tree->gtFlags & GTF_ALL_EFFECT), chkFlags);
20687 /* Recursively check the subtrees */
20691 fgDebugCheckFlags(op1);
20695 fgDebugCheckFlags(op2);
20700 chkFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
20704 chkFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
20707 // We reuse the value of GTF_REVERSE_OPS for a GT_IND-specific flag,
20708 // so exempt that (unary) operator.
20709 if (tree->OperGet() != GT_IND && tree->gtFlags & GTF_REVERSE_OPS)
20711 /* Must have two operands if GTF_REVERSE is set */
20712 noway_assert(op1 && op2);
20714 /* Make sure that the order of side effects has not been swapped. */
20716 /* However CSE may introduce an assignment after the reverse flag
20717 was set and thus GTF_ASG cannot be considered here. */
20719 /* For a GT_ASG(GT_IND(x), y) we are interested in the side effects of x */
20721 if ((kind & GTK_ASGOP) && (op1->gtOper == GT_IND))
20723 op1p = op1->gtOp.gtOp1;
20730 /* This isn't true any more with the sticky GTF_REVERSE */
20732 // if op1p has side effects, then op2 cannot have side effects
20733 if (op1p->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
20735 if (op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
20737 noway_assert(!(op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG)));
20742 if (kind & GTK_ASGOP)
20744 chkFlags |= GTF_ASG;
20747 /* Note that it is OK for treeFlags not to have a GTF_EXCEPT,
20748 AssertionProp's non-Null may have cleared it */
20749 if (tree->OperMayThrow())
20751 chkFlags |= (treeFlags & GTF_EXCEPT);
20754 if (oper == GT_ADDR && (op1->OperIsLocal() || op1->gtOper == GT_CLS_VAR ||
20755 (op1->gtOper == GT_IND && op1->gtOp.gtOp1->gtOper == GT_CLS_VAR_ADDR)))
20757 /* &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does.
20758 Similarly for clsVar */
20759 treeFlags |= GTF_GLOB_REF;
20763 /* See what kind of a special operator we have here */
20767 switch (tree->OperGet())
20775 call = tree->AsCall();
20777 chkFlags |= GTF_CALL;
20779 if ((treeFlags & GTF_EXCEPT) && !(chkFlags & GTF_EXCEPT))
20781 switch (eeGetHelperNum(call->gtCallMethHnd))
20783 // Is this a helper call that can throw an exception ?
20784 case CORINFO_HELP_LDIV:
20785 case CORINFO_HELP_LMOD:
20786 case CORINFO_HELP_METHOD_ACCESS_CHECK:
20787 case CORINFO_HELP_FIELD_ACCESS_CHECK:
20788 case CORINFO_HELP_CLASS_ACCESS_CHECK:
20789 case CORINFO_HELP_DELEGATE_SECURITY_CHECK:
20790 chkFlags |= GTF_EXCEPT;
20797 if (call->gtCallObjp)
20799 fgDebugCheckFlags(call->gtCallObjp);
20800 chkFlags |= (call->gtCallObjp->gtFlags & GTF_SIDE_EFFECT);
20802 if (call->gtCallObjp->gtFlags & GTF_ASG)
20804 treeFlags |= GTF_ASG;
20808 for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2)
20810 argx = args->gtOp.gtOp1;
20811 fgDebugCheckFlags(argx);
20813 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
20815 if (argx->gtFlags & GTF_ASG)
20817 treeFlags |= GTF_ASG;
20821 for (args = call->gtCallLateArgs; args; args = args->gtOp.gtOp2)
20823 argx = args->gtOp.gtOp1;
20824 fgDebugCheckFlags(argx);
20826 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
20828 if (argx->gtFlags & GTF_ASG)
20830 treeFlags |= GTF_ASG;
20834 if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != nullptr))
20836 fgDebugCheckFlags(call->gtCallCookie);
20837 chkFlags |= (call->gtCallCookie->gtFlags & GTF_SIDE_EFFECT);
20840 if (call->gtCallType == CT_INDIRECT)
20842 fgDebugCheckFlags(call->gtCallAddr);
20843 chkFlags |= (call->gtCallAddr->gtFlags & GTF_SIDE_EFFECT);
20846 if (call->IsUnmanaged() && (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL))
20848 if (call->gtCallArgs->gtOp.gtOp1->OperGet() == GT_NOP)
20850 noway_assert(call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
20851 call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
20855 noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
20856 call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
20866 arrObj = tree->gtArrElem.gtArrObj;
20867 fgDebugCheckFlags(arrObj);
20868 chkFlags |= (arrObj->gtFlags & GTF_ALL_EFFECT);
20870 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
20872 fgDebugCheckFlags(tree->gtArrElem.gtArrInds[dim]);
20873 chkFlags |= tree->gtArrElem.gtArrInds[dim]->gtFlags & GTF_ALL_EFFECT;
20877 case GT_ARR_OFFSET:
20878 fgDebugCheckFlags(tree->gtArrOffs.gtOffset);
20879 chkFlags |= (tree->gtArrOffs.gtOffset->gtFlags & GTF_ALL_EFFECT);
20880 fgDebugCheckFlags(tree->gtArrOffs.gtIndex);
20881 chkFlags |= (tree->gtArrOffs.gtIndex->gtFlags & GTF_ALL_EFFECT);
20882 fgDebugCheckFlags(tree->gtArrOffs.gtArrObj);
20883 chkFlags |= (tree->gtArrOffs.gtArrObj->gtFlags & GTF_ALL_EFFECT);
20891 fgDebugCheckFlagsHelper(tree, treeFlags, chkFlags);
20894 //------------------------------------------------------------------------------
20895 // fgDebugCheckFlagsHelper : Check if all bits that are set in chkFlags are also set in treeFlags.
20899 // tree - Tree whose flags are being checked
20900 // treeFlags - Actual flags on the tree
20901 // chkFlags - Expected flags
20904 // Checking that all bits that are set in treeFlags are also set in chkFlags is currently disabled.
20906 void Compiler::fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags)
20908 if (chkFlags & ~treeFlags)
20910 // Print the tree so we can see it in the log.
20911 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
20912 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
20916 noway_assert(!"Missing flags on tree");
20918 // Print the tree again so we can see it right after we hook up the debugger.
20919 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
20920 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
20924 else if (treeFlags & ~chkFlags)
20928 /* The tree has extra flags set. However, this will happen if we
20929 replace a subtree with something, but don't clear the flags up
20930 the tree. Can't flag this unless we start clearing flags above.
20932 Note: we need this working for GTF_CALL and CSEs, so I'm enabling
20935 if (tree->OperGet() != GT_CALL && (treeFlags & GTF_CALL) && !(chkFlags & GTF_CALL))
20937 // Print the tree so we can see it in the log.
20938 printf("Extra GTF_CALL flags on parent tree [%X]: ", tree);
20939 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
20943 noway_assert(!"Extra flags on tree");
20945 // Print the tree again so we can see it right after we hook up the debugger.
20946 printf("Extra GTF_CALL flags on parent tree [%X]: ", tree);
20947 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
20955 // DEBUG routine to check correctness of the internal gtNext, gtPrev threading of a statement.
20956 // This threading is only valid when fgStmtListThreaded is true.
20957 // This calls an alternate method for FGOrderLinear.
20958 void Compiler::fgDebugCheckNodeLinks(BasicBlock* block, GenTree* node)
20960 // LIR blocks are checked using BasicBlock::CheckLIR().
20961 if (block->IsLIR())
20963 LIR::AsRange(block).CheckLIR(this);
20967 GenTreeStmt* stmt = node->AsStmt();
20969 assert(fgStmtListThreaded);
20971 noway_assert(stmt->gtStmtList);
20973 // The first node's gtPrev must be nullptr (the gtPrev list is not circular).
20974 // The last node's gtNext must be nullptr (the gtNext list is not circular). This is tested if the loop below
20976 assert(stmt->gtStmtList->gtPrev == nullptr);
20978 for (GenTreePtr tree = stmt->gtStmtList; tree != nullptr; tree = tree->gtNext)
20982 noway_assert(tree->gtPrev->gtNext == tree);
20986 noway_assert(tree == stmt->gtStmtList);
20991 noway_assert(tree->gtNext->gtPrev == tree);
20995 noway_assert(tree == stmt->gtStmtExpr);
20998 /* Cross-check gtPrev,gtNext with gtOp for simple trees */
21000 GenTreePtr expectedPrevTree = nullptr;
21002 if (tree->OperIsLeaf())
21004 if (tree->gtOper == GT_CATCH_ARG)
21006 // The GT_CATCH_ARG should always have GTF_ORDER_SIDEEFF set
21007 noway_assert(tree->gtFlags & GTF_ORDER_SIDEEFF);
21008 // The GT_CATCH_ARG has to be the first thing evaluated
21009 noway_assert(stmt == block->FirstNonPhiDef());
21010 noway_assert(stmt->gtStmtList->gtOper == GT_CATCH_ARG);
21011 // The root of the tree should have GTF_ORDER_SIDEEFF set
21012 noway_assert(stmt->gtStmtExpr->gtFlags & GTF_ORDER_SIDEEFF);
21016 if (tree->OperIsUnary() && tree->gtOp.gtOp1)
21018 GenTreePtr lclVarTree;
21019 expectedPrevTree = tree->gtOp.gtOp1;
21021 else if (tree->OperIsBinary() && tree->gtOp.gtOp1)
21023 switch (tree->gtOper)
21027 tree->gtOp.gtOp2->AsColon()->ThenNode(); // "then" operand of the GT_COLON (generated second).
21031 expectedPrevTree = tree->AsColon()->ElseNode(); // "else" branch result (generated first).
21035 if (tree->gtOp.gtOp2)
21037 if (tree->gtFlags & GTF_REVERSE_OPS)
21039 expectedPrevTree = tree->gtOp.gtOp1;
21043 expectedPrevTree = tree->gtOp.gtOp2;
21048 expectedPrevTree = tree->gtOp.gtOp1;
21054 noway_assert(expectedPrevTree == nullptr || // No expectations about the prev node
21055 tree->gtPrev == expectedPrevTree); // The "normal" case
21059 /*****************************************************************************
21061 * A DEBUG routine to check the correctness of the links between GT_STMT nodes
21062 * and ordinary nodes within a statement.
21064 ****************************************************************************/
21066 void Compiler::fgDebugCheckLinks(bool morphTrees)
21068 // This used to be only on for stress, and there was a comment stating that
21069 // it was "quite an expensive operation" but I did not find that to be true.
21070 // Set DO_SANITY_DEBUG_CHECKS to false to revert to that behavior.
21071 const bool DO_SANITY_DEBUG_CHECKS = true;
21073 if (!DO_SANITY_DEBUG_CHECKS && !compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
21078 fgDebugCheckBlockLinks();
21080 /* For each basic block check the bbTreeList links */
21081 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
21083 PROCESS_BLOCK_AGAIN:;
21084 if (block->IsLIR())
21086 LIR::AsRange(block).CheckLIR(this);
21090 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
21092 /* Verify that bbTreeList is threaded correctly */
21093 /* Note that for the GT_STMT list, the gtPrev list is circular. The gtNext list is not: gtNext of the
21094 * last GT_STMT in a block is nullptr. */
21096 noway_assert(stmt->gtPrev);
21098 if (stmt == block->bbTreeList)
21100 noway_assert(stmt->gtPrev->gtNext == nullptr);
21104 noway_assert(stmt->gtPrev->gtNext == stmt);
21109 noway_assert(stmt->gtNext->gtPrev == stmt);
21113 noway_assert(block->lastStmt() == stmt);
21116 /* For each statement check that the exception flags are properly set */
21118 noway_assert(stmt->gtStmtExpr);
21122 gtDispTree(stmt->gtStmtExpr);
21125 fgDebugCheckFlags(stmt->gtStmtExpr);
21127 // Not only will this stress fgMorphBlockStmt(), but we also get all the checks
21128 // done by fgMorphTree()
21132 // If 'stmt' is removed from the block, restart
21133 if (fgMorphBlockStmt(block, stmt DEBUGARG("test morphing")))
21135 goto PROCESS_BLOCK_AGAIN;
21139 /* For each GT_STMT node check that the nodes are threaded correcly - gtStmtList */
21141 if (fgStmtListThreaded)
21143 fgDebugCheckNodeLinks(block, stmt);
21150 // ensure that bbNext and bbPrev are consistent
21151 void Compiler::fgDebugCheckBlockLinks()
21153 assert(fgFirstBB->bbPrev == nullptr);
21155 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
21159 assert(block->bbNext->bbPrev == block);
21163 assert(block == fgLastBB);
21168 assert(block->bbPrev->bbNext == block);
21172 assert(block == fgFirstBB);
21175 // If this is a switch, check that the tables are consistent.
21176 // Note that we don't call GetSwitchDescMap(), because it has the side-effect
21177 // of allocating it if it is not present.
21178 if (block->bbJumpKind == BBJ_SWITCH && m_switchDescMap != nullptr)
21180 SwitchUniqueSuccSet uniqueSuccSet;
21181 if (m_switchDescMap->Lookup(block, &uniqueSuccSet))
21183 // Create a set with all the successors. Don't use BlockSet, so we don't need to worry
21184 // about the BlockSet epoch.
21185 BitVecTraits bitVecTraits(fgBBNumMax + 1, this);
21186 BitVec BITVEC_INIT_NOCOPY(succBlocks, BitVecOps::MakeEmpty(&bitVecTraits));
21187 BasicBlock** jumpTable = block->bbJumpSwt->bbsDstTab;
21188 unsigned jumpCount = block->bbJumpSwt->bbsCount;
21189 for (unsigned i = 0; i < jumpCount; i++)
21191 BitVecOps::AddElemD(&bitVecTraits, succBlocks, jumpTable[i]->bbNum);
21193 // Now we should have a set of unique successors that matches what's in the switchMap.
21194 // First, check the number of entries, then make sure all the blocks in uniqueSuccSet
21195 // are in the BlockSet.
21196 unsigned count = BitVecOps::Count(&bitVecTraits, succBlocks);
21197 assert(uniqueSuccSet.numDistinctSuccs == count);
21198 for (unsigned i = 0; i < uniqueSuccSet.numDistinctSuccs; i++)
21200 assert(BitVecOps::IsMember(&bitVecTraits, succBlocks, uniqueSuccSet.nonDuplicates[i]->bbNum));
21207 /*****************************************************************************/
21209 /*****************************************************************************/
21211 //------------------------------------------------------------------------
21212 // fgCheckForInlineDepthAndRecursion: compute depth of the candidate, and
21213 // check for recursion.
21216 // The depth of the inline candidate. The root method is a depth 0, top-level
21217 // candidates at depth 1, etc.
21220 // We generally disallow recursive inlines by policy. However, they are
21221 // supported by the underlying machinery.
21223 // Likewise the depth limit is a policy consideration, and serves mostly
21224 // as a safeguard to prevent runaway inlining of small methods.
21226 unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo)
21228 BYTE* candidateCode = inlineInfo->inlineCandidateInfo->methInfo.ILCode;
21229 InlineContext* inlineContext = inlineInfo->iciStmt->gtInlineContext;
21230 InlineResult* inlineResult = inlineInfo->inlineResult;
21232 // There should be a context for all candidates.
21233 assert(inlineContext != nullptr);
21236 for (; inlineContext != nullptr; inlineContext = inlineContext->GetParent())
21241 if (inlineContext->GetCode() == candidateCode)
21243 // This inline candidate has the same IL code buffer as an already
21244 // inlined method does.
21245 inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_RECURSIVE);
21249 if (depth > InlineStrategy::IMPLEMENTATION_MAX_INLINE_DEPTH)
21255 inlineResult->NoteInt(InlineObservation::CALLSITE_DEPTH, depth);
21259 /*****************************************************************************
21264 void Compiler::fgInline()
21266 if (!opts.OptEnabled(CLFLG_INLINING))
21274 printf("*************** In fgInline()\n");
21278 BasicBlock* block = fgFirstBB;
21279 noway_assert(block != nullptr);
21281 // Set the root inline context on all statements
21282 InlineContext* rootContext = m_inlineStrategy->GetRootContext();
21284 for (; block != nullptr; block = block->bbNext)
21286 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
21288 stmt->gtInlineContext = rootContext;
21292 // Reset block back to start for inlining
21297 /* Make the current basic block address available globally */
21304 for (stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
21306 expr = stmt->gtStmtExpr;
21308 // See if we can expand the inline candidate
21309 if ((expr->gtOper == GT_CALL) && ((expr->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0))
21311 GenTreeCall* call = expr->AsCall();
21312 InlineResult inlineResult(this, call, stmt, "fgInline");
21314 fgMorphStmt = stmt;
21316 fgMorphCallInline(call, &inlineResult);
21318 if (stmt->gtStmtExpr->IsNothingNode())
21320 fgRemoveStmt(block, stmt);
21327 // Look for non-candidates.
21328 fgWalkTreePre(&stmt->gtStmtExpr, fgFindNonInlineCandidate, stmt);
21332 // See if we need to replace the return value place holder.
21333 // Also, see if this update enables further devirtualization.
21334 fgWalkTreePre(&stmt->gtStmtExpr, fgUpdateInlineReturnExpressionPlaceHolder, (void*)this);
21336 // See if stmt is of the form GT_COMMA(call, nop)
21337 // If yes, we can get rid of GT_COMMA.
21338 if (expr->OperGet() == GT_COMMA && expr->gtOp.gtOp1->OperGet() == GT_CALL &&
21339 expr->gtOp.gtOp2->OperGet() == GT_NOP)
21341 stmt->gtStmtExpr = expr->gtOp.gtOp1;
21345 block = block->bbNext;
21351 // Check that we should not have any inline candidate or return value place holder left.
21354 noway_assert(block);
21360 for (stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
21362 // Call Compiler::fgDebugCheckInlineCandidates on each node
21363 fgWalkTreePre(&stmt->gtStmtExpr, fgDebugCheckInlineCandidates);
21366 block = block->bbNext;
21370 fgVerifyHandlerTab();
21374 printf("*************** After fgInline()\n");
21375 fgDispBasicBlocks(true);
21376 fgDispHandlerTab();
21379 if (verbose || fgPrintInlinedMethods)
21381 printf("**************** Inline Tree\n");
21382 m_inlineStrategy->Dump();
21390 //------------------------------------------------------------------------
21391 // fgFindNonInlineCandidate: tree walk helper to ensure that a tree node
21392 // that is not an inline candidate is noted as a failed inline.
21395 // pTree - pointer to pointer tree node being walked
21396 // data - contextual data for the walk
21402 // Invokes fgNoteNonInlineCandidate on the nodes it finds.
21404 Compiler::fgWalkResult Compiler::fgFindNonInlineCandidate(GenTreePtr* pTree, fgWalkData* data)
21406 GenTreePtr tree = *pTree;
21407 if (tree->gtOper == GT_CALL)
21409 Compiler* compiler = data->compiler;
21410 GenTreeStmt* stmt = (GenTreeStmt*)data->pCallbackData;
21411 GenTreeCall* call = tree->AsCall();
21413 compiler->fgNoteNonInlineCandidate(stmt, call);
21415 return WALK_CONTINUE;
21418 //------------------------------------------------------------------------
21419 // fgNoteNonInlineCandidate: account for inlining failures in calls
21420 // not marked as inline candidates.
21423 // stmt - statement containing the call
21424 // call - the call itself
21427 // Used in debug only to try and place descriptions of inline failures
21428 // into the proper context in the inline tree.
21430 void Compiler::fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call)
21432 InlineResult inlineResult(this, call, nullptr, "fgNotInlineCandidate");
21433 InlineObservation currentObservation = InlineObservation::CALLSITE_NOT_CANDIDATE;
21435 // Try and recover the reason left behind when the jit decided
21436 // this call was not a candidate.
21437 InlineObservation priorObservation = call->gtInlineObservation;
21439 if (InlIsValidObservation(priorObservation))
21441 currentObservation = priorObservation;
21444 // Would like to just call noteFatal here, since this
21445 // observation blocked candidacy, but policy comes into play
21446 // here too. Also note there's no need to re-report these
21447 // failures, since we reported them during the initial
21449 InlineImpact impact = InlGetImpact(currentObservation);
21451 if (impact == InlineImpact::FATAL)
21453 inlineResult.NoteFatal(currentObservation);
21457 inlineResult.Note(currentObservation);
21460 inlineResult.SetReported();
21462 if (call->gtCallType == CT_USER_FUNC)
21464 // Create InlineContext for the failure
21465 m_inlineStrategy->NewFailure(stmt, &inlineResult);
21471 #if FEATURE_MULTIREG_RET
21473 /*********************************************************************************
21475 * tree - The node which needs to be converted to a struct pointer.
21477 * Return the pointer by either __replacing__ the tree node with a suitable pointer
21478 * type or __without replacing__ and just returning a subtree or by __modifying__
21481 GenTreePtr Compiler::fgGetStructAsStructPtr(GenTreePtr tree)
21483 noway_assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_FIELD) || (tree->gtOper == GT_IND) ||
21484 (tree->gtOper == GT_BLK) || (tree->gtOper == GT_OBJ) || tree->OperIsSIMD() ||
21485 // tree->gtOper == GT_CALL || cannot get address of call.
21486 // tree->gtOper == GT_MKREFANY || inlining should've been aborted due to mkrefany opcode.
21487 // tree->gtOper == GT_RET_EXPR || cannot happen after fgUpdateInlineReturnExpressionPlaceHolder
21488 (tree->gtOper == GT_COMMA));
21490 switch (tree->OperGet())
21495 return tree->gtOp.gtOp1;
21498 tree->gtOp.gtOp2 = fgGetStructAsStructPtr(tree->gtOp.gtOp2);
21499 tree->gtType = TYP_BYREF;
21503 return gtNewOperNode(GT_ADDR, TYP_BYREF, tree);
21507 /***************************************************************************************************
21508 * child - The inlinee of the retExpr node.
21509 * retClsHnd - The struct class handle of the type of the inlinee.
21511 * Assign the inlinee to a tmp, if it is a call, just assign it to a lclVar, else we can
21512 * use a copyblock to do the assignment.
21514 GenTreePtr Compiler::fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd)
21516 assert(child->gtOper != GT_RET_EXPR && child->gtOper != GT_MKREFANY);
21518 unsigned tmpNum = lvaGrabTemp(false DEBUGARG("RetBuf for struct inline return candidates."));
21519 lvaSetStruct(tmpNum, retClsHnd, false);
21520 var_types structType = lvaTable[tmpNum].lvType;
21522 GenTreePtr dst = gtNewLclvNode(tmpNum, structType);
21524 // If we have a call, we'd like it to be: V00 = call(), but first check if
21525 // we have a ", , , call()" -- this is very defensive as we may never get
21526 // an inlinee that is made of commas. If the inlinee is not a call, then
21527 // we use a copy block to do the assignment.
21528 GenTreePtr src = child;
21529 GenTreePtr lastComma = nullptr;
21530 while (src->gtOper == GT_COMMA)
21533 src = src->gtOp.gtOp2;
21536 GenTreePtr newInlinee = nullptr;
21537 if (src->gtOper == GT_CALL)
21539 // If inlinee was just a call, new inlinee is v05 = call()
21540 newInlinee = gtNewAssignNode(dst, src);
21542 // When returning a multi-register value in a local var, make sure the variable is
21543 // marked as lvIsMultiRegRet, so it does not get promoted.
21544 if (src->AsCall()->HasMultiRegRetVal())
21546 lvaTable[tmpNum].lvIsMultiRegRet = true;
21549 // If inlinee was comma, but a deeper call, new inlinee is (, , , v05 = call())
21550 if (child->gtOper == GT_COMMA)
21552 lastComma->gtOp.gtOp2 = newInlinee;
21553 newInlinee = child;
21558 // Inlinee is not a call, so just create a copy block to the tmp.
21560 GenTreePtr dstAddr = fgGetStructAsStructPtr(dst);
21561 GenTreePtr srcAddr = fgGetStructAsStructPtr(src);
21562 newInlinee = gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false);
21565 GenTreePtr production = gtNewLclvNode(tmpNum, structType);
21566 return gtNewOperNode(GT_COMMA, structType, newInlinee, production);
21569 /***************************************************************************************************
21570 * tree - The tree pointer that has one of its child nodes as retExpr.
21571 * child - The inlinee child.
21572 * retClsHnd - The struct class handle of the type of the inlinee.
21574 * V04 = call() assignments are okay as we codegen it. Everything else needs to be a copy block or
21575 * would need a temp. For example, a cast(ldobj) will then be, cast(v05 = ldobj, v05); But it is
21576 * a very rare (or impossible) scenario that we'd have a retExpr transform into a ldobj other than
21577 * a lclVar/call. So it is not worthwhile to do pattern matching optimizations like addr(ldobj(op1))
21580 void Compiler::fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd)
21582 // We are okay to have:
21583 // 1. V02 = call();
21584 // 2. copyBlk(dstAddr, srcAddr);
21585 assert(tree->gtOper == GT_ASG);
21587 // We have an assignment, we codegen only V05 = call().
21588 // However, if it is a multireg return on x64/ux we want to assign it to a temp.
21589 if (child->gtOper == GT_CALL && tree->gtOp.gtOp1->gtOper == GT_LCL_VAR && !child->AsCall()->HasMultiRegRetVal())
21594 GenTreePtr dstAddr = fgGetStructAsStructPtr(tree->gtOp.gtOp1);
21595 GenTreePtr srcAddr = fgGetStructAsStructPtr(
21596 (child->gtOper == GT_CALL)
21597 ? fgAssignStructInlineeToVar(child, retClsHnd) // Assign to a variable if it is a call.
21598 : child); // Just get the address, if not a call.
21600 tree->CopyFrom(gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false), this);
21603 #endif // FEATURE_MULTIREG_RET
21605 //------------------------------------------------------------------------
21606 // fgUpdateInlineReturnExpressionPlaceHolder: callback to replace the
21607 // inline return expression placeholder.
21610 // pTree -- pointer to tree to examine for updates
21611 // data -- context data for the tree walk
21614 // fgWalkResult indicating the walk should continue; that
21615 // is we wish to fully explore the tree.
21618 // Looks for GT_RET_EXPR nodes that arose from tree splitting done
21619 // during importation for inline candidates, and replaces them.
21621 // For successful inlines, substitutes the return value expression
21622 // from the inline body for the GT_RET_EXPR.
21624 // For failed inlines, rejoins the original call into the tree from
21625 // whence it was split during importation.
21627 // The code doesn't actually know if the corresponding inline
21628 // succeeded or not; it relies on the fact that gtInlineCandidate
21629 // initially points back at the call and is modified in place to
21630 // the inlinee return expression if the inline is successful (see
21631 // tail end of fgInsertInlineeBlocks for the update of iciCall).
21633 // If the parent of the GT_RET_EXPR is a virtual call,
21634 // devirtualization is attempted. This should only succeed in the
21635 // successful inline case, when the inlinee's return value
21636 // expression provides a better type than the return type of the
21637 // method. Note for failed inlines, the devirtualizer can only go
21638 // by the return type, and any devirtualization that type enabled
21639 // would have already happened during importation.
21641 // If the return type is a struct type and we're on a platform
21642 // where structs can be returned in multiple registers, ensure the
21643 // call has a suitable parent.
21645 Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTreePtr* pTree, fgWalkData* data)
21647 GenTreePtr tree = *pTree;
21648 Compiler* comp = data->compiler;
21649 CORINFO_CLASS_HANDLE retClsHnd = NO_CLASS_HANDLE;
21651 if (tree->gtOper == GT_RET_EXPR)
21653 // We are going to copy the tree from the inlinee,
21654 // so record the handle now.
21656 if (varTypeIsStruct(tree))
21658 retClsHnd = tree->gtRetExpr.gtRetClsHnd;
21663 // Obtained the expanded inline candidate
21664 GenTreePtr inlineCandidate = tree->gtRetExpr.gtInlineCandidate;
21669 printf("\nReplacing the return expression placeholder ");
21672 printTreeID(inlineCandidate);
21674 // Dump out the old return expression placeholder it will be overwritten by the CopyFrom below
21675 comp->gtDispTree(tree);
21679 tree->CopyFrom(inlineCandidate, comp);
21684 printf("\nInserting the inline return expression\n");
21685 comp->gtDispTree(tree);
21689 } while (tree->gtOper == GT_RET_EXPR);
21691 // Now see if this return value expression feeds the 'this'
21692 // object at a virtual call site.
21694 // Note for void returns where the inline failed, the
21695 // GT_RET_EXPR may be top-level.
21697 // May miss cases where there are intermediaries between call
21698 // and this, eg commas.
21699 GenTreePtr parentTree = data->parent;
21701 if ((parentTree != nullptr) && (parentTree->gtOper == GT_CALL))
21703 GenTreeCall* call = parentTree->AsCall();
21704 bool tryLateDevirt = call->IsVirtual() && (call->gtCallObjp == tree);
21707 tryLateDevirt = tryLateDevirt && (JitConfig.JitEnableLateDevirtualization() == 1);
21715 printf("**** Late devirt opportunity\n");
21716 comp->gtDispTree(call);
21720 CORINFO_CALL_INFO x = {};
21721 x.hMethod = call->gtCallMethHnd;
21722 comp->impDevirtualizeCall(call, tree, &x, nullptr);
21727 #if FEATURE_MULTIREG_RET
21729 // Did we record a struct return class handle above?
21731 if (retClsHnd != NO_CLASS_HANDLE)
21733 // Is this a type that is returned in multiple registers?
21734 // if so we need to force into into a form we accept.
21735 // i.e. LclVar = call()
21737 if (comp->IsMultiRegReturnedType(retClsHnd))
21739 GenTreePtr parent = data->parent;
21740 // See assert below, we only look one level above for an asg parent.
21741 if (parent->gtOper == GT_ASG)
21743 // Either lhs is a call V05 = call(); or lhs is addr, and asg becomes a copyBlk.
21744 comp->fgAttachStructInlineeToAsg(parent, tree, retClsHnd);
21748 // Just assign the inlinee to a variable to keep it simple.
21749 tree->CopyFrom(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
21756 // Make sure we don't have a tree like so: V05 = (, , , retExpr);
21757 // Since we only look one level above for the parent for '=' and
21758 // do not check if there is a series of COMMAs. See above.
21759 // Importer and FlowGraph will not generate such a tree, so just
21760 // leaving an assert in here. This can be fixed by looking ahead
21761 // when we visit GT_ASG similar to fgAttachStructInlineeToAsg.
21763 if ((tree->gtOper == GT_ASG) && (tree->gtOp.gtOp2->gtOper == GT_COMMA))
21766 for (comma = tree->gtOp.gtOp2; comma->gtOper == GT_COMMA; comma = comma->gtOp.gtOp2)
21771 noway_assert(!varTypeIsStruct(comma) || comma->gtOper != GT_RET_EXPR ||
21772 !comp->IsMultiRegReturnedType(comma->gtRetExpr.gtRetClsHnd));
21775 #endif // defined(DEBUG)
21776 #endif // FEATURE_MULTIREG_RET
21778 return WALK_CONTINUE;
21783 /*****************************************************************************
21784 * Callback to make sure there is no more GT_RET_EXPR and GTF_CALL_INLINE_CANDIDATE nodes.
21788 Compiler::fgWalkResult Compiler::fgDebugCheckInlineCandidates(GenTreePtr* pTree, fgWalkData* data)
21790 GenTreePtr tree = *pTree;
21791 if (tree->gtOper == GT_CALL)
21793 assert((tree->gtFlags & GTF_CALL_INLINE_CANDIDATE) == 0);
21797 assert(tree->gtOper != GT_RET_EXPR);
21800 return WALK_CONTINUE;
21805 void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineResult)
21807 noway_assert(call->gtOper == GT_CALL);
21808 noway_assert((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0);
21809 noway_assert(opts.OptEnabled(CLFLG_INLINING));
21811 // This is the InlineInfo struct representing a method to be inlined.
21812 InlineInfo inlineInfo;
21813 memset(&inlineInfo, 0, sizeof(inlineInfo));
21814 CORINFO_METHOD_HANDLE fncHandle = call->gtCallMethHnd;
21816 inlineInfo.fncHandle = fncHandle;
21817 inlineInfo.iciCall = call;
21818 inlineInfo.iciStmt = fgMorphStmt;
21819 inlineInfo.iciBlock = compCurBB;
21820 inlineInfo.thisDereferencedFirst = false;
21821 inlineInfo.retExpr = nullptr;
21822 inlineInfo.inlineResult = inlineResult;
21823 #ifdef FEATURE_SIMD
21824 inlineInfo.hasSIMDTypeArgLocalOrReturn = false;
21825 #endif // FEATURE_SIMD
21827 InlineCandidateInfo* inlineCandidateInfo = call->gtInlineCandidateInfo;
21828 noway_assert(inlineCandidateInfo);
21829 // Store the link to inlineCandidateInfo into inlineInfo
21830 inlineInfo.inlineCandidateInfo = inlineCandidateInfo;
21832 unsigned inlineDepth = fgCheckInlineDepthAndRecursion(&inlineInfo);
21834 if (inlineResult->IsFailure())
21839 printf("Recursive or deep inline recursion detected. Will not expand this INLINECANDIDATE \n");
21845 // Set the trap to catch all errors (including recoverable ones from the EE)
21850 CORINFO_METHOD_HANDLE fncHandle;
21851 InlineCandidateInfo* inlineCandidateInfo;
21852 InlineInfo* inlineInfo;
21854 memset(¶m, 0, sizeof(param));
21856 param.pThis = this;
21858 param.fncHandle = fncHandle;
21859 param.inlineCandidateInfo = inlineCandidateInfo;
21860 param.inlineInfo = &inlineInfo;
21861 bool success = eeRunWithErrorTrap<Param>(
21862 [](Param* pParam) {
21863 // Init the local var info of the inlinee
21864 pParam->pThis->impInlineInitVars(pParam->inlineInfo);
21866 if (pParam->inlineInfo->inlineResult->IsCandidate())
21868 /* Clear the temp table */
21869 memset(pParam->inlineInfo->lclTmpNum, -1, sizeof(pParam->inlineInfo->lclTmpNum));
21872 // Prepare the call to jitNativeCode
21875 pParam->inlineInfo->InlinerCompiler = pParam->pThis;
21876 if (pParam->pThis->impInlineInfo == nullptr)
21878 pParam->inlineInfo->InlineRoot = pParam->pThis;
21882 pParam->inlineInfo->InlineRoot = pParam->pThis->impInlineInfo->InlineRoot;
21884 pParam->inlineInfo->argCnt = pParam->inlineCandidateInfo->methInfo.args.totalILArgs();
21885 pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHnd;
21887 JITLOG_THIS(pParam->pThis,
21888 (LL_INFO100000, "INLINER: inlineInfo.tokenLookupContextHandle for %s set to 0x%p:\n",
21889 pParam->pThis->eeGetMethodFullName(pParam->fncHandle),
21890 pParam->pThis->dspPtr(pParam->inlineInfo->tokenLookupContextHandle)));
21892 JitFlags compileFlagsForInlinee = *pParam->pThis->opts.jitFlags;
21894 // The following flags are lost when inlining.
21895 // (This is checked in Compiler::compInitOptions().)
21896 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_BBOPT);
21897 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_BBINSTR);
21898 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_PROF_ENTERLEAVE);
21899 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_EnC);
21900 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_INFO);
21902 compileFlagsForInlinee.Set(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
21905 if (pParam->pThis->verbose)
21907 printf("\nInvoking compiler for the inlinee method %s :\n",
21908 pParam->pThis->eeGetMethodFullName(pParam->fncHandle));
21913 jitNativeCode(pParam->fncHandle, pParam->inlineCandidateInfo->methInfo.scope,
21914 pParam->pThis->info.compCompHnd, &pParam->inlineCandidateInfo->methInfo,
21915 (void**)pParam->inlineInfo, nullptr, &compileFlagsForInlinee, pParam->inlineInfo);
21917 if (result != CORJIT_OK)
21919 // If we haven't yet determined why this inline fails, use
21920 // a catch-all something bad happened observation.
21921 InlineResult* innerInlineResult = pParam->inlineInfo->inlineResult;
21923 if (!innerInlineResult->IsFailure())
21925 innerInlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_FAILURE);
21936 printf("\nInlining failed due to an exception during invoking the compiler for the inlinee method %s.\n",
21937 eeGetMethodFullName(fncHandle));
21941 // If we haven't yet determined why this inline fails, use
21942 // a catch-all something bad happened observation.
21943 if (!inlineResult->IsFailure())
21945 inlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
21949 if (inlineResult->IsFailure())
21957 printf("\nDone invoking compiler for the inlinee method %s\n", eeGetMethodFullName(fncHandle));
21961 // If there is non-NULL return, but we haven't set the pInlineInfo->retExpr,
21962 // That means we haven't imported any BB that contains CEE_RET opcode.
21963 // (This could happen for example for a BBJ_THROW block fall through a BBJ_RETURN block which
21964 // causes the BBJ_RETURN block not to be imported at all.)
21965 // Fail the inlining attempt
21966 if (inlineCandidateInfo->fncRetType != TYP_VOID && inlineInfo.retExpr == nullptr)
21971 printf("\nInlining failed because pInlineInfo->retExpr is not set in the inlinee method %s.\n",
21972 eeGetMethodFullName(fncHandle));
21975 inlineResult->NoteFatal(InlineObservation::CALLEE_LACKS_RETURN);
21979 if (inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_SPECULATIVE)
21981 // we defer the call to initClass() until inlining is completed in case it fails. If inlining succeeds,
21982 // we will call initClass().
21983 if (!(info.compCompHnd->initClass(nullptr /* field */, fncHandle /* method */,
21984 inlineCandidateInfo->exactContextHnd /* context */) &
21985 CORINFO_INITCLASS_INITIALIZED))
21987 inlineResult->NoteFatal(InlineObservation::CALLEE_CLASS_INIT_FAILURE);
21992 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21993 // The inlining attempt cannot be failed starting from this point.
21994 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21996 // We've successfully obtain the list of inlinee's basic blocks.
21997 // Let's insert it to inliner's basic block list.
21998 fgInsertInlineeBlocks(&inlineInfo);
22002 if (verbose || fgPrintInlinedMethods)
22004 printf("Successfully inlined %s (%d IL bytes) (depth %d) [%s]\n", eeGetMethodFullName(fncHandle),
22005 inlineCandidateInfo->methInfo.ILCodeSize, inlineDepth, inlineResult->ReasonString());
22010 printf("--------------------------------------------------------------------------------------------\n");
22015 impInlinedCodeSize += inlineCandidateInfo->methInfo.ILCodeSize;
22019 inlineResult->NoteSuccess();
22022 //------------------------------------------------------------------------
22023 // fgInsertInlineeBlocks: incorporate statements for an inline into the
22027 // inlineInfo -- info for the inline
22030 // The inlining attempt cannot be failed once this method is called.
22032 // Adds all inlinee statements, plus any glue statements needed
22033 // either before or after the inlined call.
22035 // Updates flow graph and assigns weights to inlinee
22036 // blocks. Currently does not attempt to read IBC data for the
22039 // Updates relevant root method status flags (eg optMethodFlags) to
22040 // include information from the inlinee.
22042 // Marks newly added statements with an appropriate inline context.
22044 void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
22046 GenTreeCall* iciCall = pInlineInfo->iciCall;
22047 GenTreeStmt* iciStmt = pInlineInfo->iciStmt;
22048 BasicBlock* iciBlock = pInlineInfo->iciBlock;
22051 // We can write better assert here. For example, we can check that
22052 // iciBlock contains iciStmt, which in turn contains iciCall.
22053 noway_assert(iciBlock->bbTreeList != nullptr);
22054 noway_assert(iciStmt->gtStmtExpr != nullptr);
22055 noway_assert(iciCall->gtOper == GT_CALL);
22059 GenTreePtr currentDumpStmt = nullptr;
22063 printf("\n\n----------- Statements (and blocks) added due to the inlining of call ");
22064 printTreeID(iciCall);
22065 printf(" -----------\n");
22070 // Create a new inline context and mark the inlined statements with it
22071 InlineContext* calleeContext = m_inlineStrategy->NewSuccess(pInlineInfo);
22073 for (block = InlineeCompiler->fgFirstBB; block != nullptr; block = block->bbNext)
22075 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
22077 stmt->gtInlineContext = calleeContext;
22081 // Prepend statements
22082 GenTreePtr stmtAfter = fgInlinePrependStatements(pInlineInfo);
22087 currentDumpStmt = stmtAfter;
22088 printf("\nInlinee method body:");
22092 BasicBlock* topBlock = iciBlock;
22093 BasicBlock* bottomBlock = nullptr;
22095 if (InlineeCompiler->fgBBcount == 1)
22097 // When fgBBCount is 1 we will always have a non-NULL fgFirstBB
22099 PREFAST_ASSUME(InlineeCompiler->fgFirstBB != nullptr);
22101 // DDB 91389: Don't throw away the (only) inlinee block
22102 // when its return type is not BBJ_RETURN.
22103 // In other words, we need its BBJ_ to perform the right thing.
22104 if (InlineeCompiler->fgFirstBB->bbJumpKind == BBJ_RETURN)
22106 // Inlinee contains just one BB. So just insert its statement list to topBlock.
22107 if (InlineeCompiler->fgFirstBB->bbTreeList)
22109 stmtAfter = fgInsertStmtListAfter(iciBlock, stmtAfter, InlineeCompiler->fgFirstBB->bbTreeList);
22111 // Copy inlinee bbFlags to caller bbFlags.
22112 const unsigned __int64 inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
22113 noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
22114 noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
22115 iciBlock->bbFlags |= inlineeBlockFlags;
22121 noway_assert(currentDumpStmt);
22123 if (currentDumpStmt != stmtAfter)
22127 currentDumpStmt = currentDumpStmt->gtNext;
22131 noway_assert(currentDumpStmt->gtOper == GT_STMT);
22133 gtDispTree(currentDumpStmt);
22136 } while (currentDumpStmt != stmtAfter);
22141 // Append statements to null out gc ref locals, if necessary.
22142 fgInlineAppendStatements(pInlineInfo, iciBlock, stmtAfter);
22149 // ======= Inserting inlinee's basic blocks ===============
22152 bottomBlock = fgNewBBafter(topBlock->bbJumpKind, topBlock, true);
22153 bottomBlock->bbRefs = 1;
22154 bottomBlock->bbJumpDest = topBlock->bbJumpDest;
22155 bottomBlock->inheritWeight(topBlock);
22157 topBlock->bbJumpKind = BBJ_NONE;
22159 // Update block flags
22161 const unsigned __int64 originalFlags = topBlock->bbFlags;
22162 noway_assert((originalFlags & BBF_SPLIT_NONEXIST) == 0);
22163 topBlock->bbFlags &= ~(BBF_SPLIT_LOST);
22164 bottomBlock->bbFlags |= originalFlags & BBF_SPLIT_GAINED;
22168 // Split statements between topBlock and bottomBlock
22170 GenTreePtr topBlock_Begin;
22171 GenTreePtr topBlock_End;
22172 GenTreePtr bottomBlock_Begin;
22173 GenTreePtr bottomBlock_End;
22175 topBlock_Begin = nullptr;
22176 topBlock_End = nullptr;
22177 bottomBlock_Begin = nullptr;
22178 bottomBlock_End = nullptr;
22181 // First figure out bottomBlock_Begin
22184 bottomBlock_Begin = stmtAfter->gtNext;
22186 if (topBlock->bbTreeList == nullptr)
22188 // topBlock is empty before the split.
22189 // In this case, both topBlock and bottomBlock should be empty
22190 noway_assert(bottomBlock_Begin == nullptr);
22191 topBlock->bbTreeList = nullptr;
22192 bottomBlock->bbTreeList = nullptr;
22194 else if (topBlock->bbTreeList == bottomBlock_Begin)
22196 noway_assert(bottomBlock_Begin);
22198 // topBlock contains at least one statement before the split.
22199 // And the split is before the first statement.
22200 // In this case, topBlock should be empty, and everything else should be moved to the bottonBlock.
22201 bottomBlock->bbTreeList = topBlock->bbTreeList;
22202 topBlock->bbTreeList = nullptr;
22204 else if (bottomBlock_Begin == nullptr)
22206 noway_assert(topBlock->bbTreeList);
22208 // topBlock contains at least one statement before the split.
22209 // And the split is at the end of the topBlock.
22210 // In this case, everything should be kept in the topBlock, and the bottomBlock should be empty
22212 bottomBlock->bbTreeList = nullptr;
22216 noway_assert(topBlock->bbTreeList);
22217 noway_assert(bottomBlock_Begin);
22219 // This is the normal case where both blocks should contain at least one statement.
22220 topBlock_Begin = topBlock->bbTreeList;
22221 noway_assert(topBlock_Begin);
22222 topBlock_End = bottomBlock_Begin->gtPrev;
22223 noway_assert(topBlock_End);
22224 bottomBlock_End = topBlock->lastStmt();
22225 noway_assert(bottomBlock_End);
22227 // Break the linkage between 2 blocks.
22228 topBlock_End->gtNext = nullptr;
22230 // Fix up all the pointers.
22231 topBlock->bbTreeList = topBlock_Begin;
22232 topBlock->bbTreeList->gtPrev = topBlock_End;
22234 bottomBlock->bbTreeList = bottomBlock_Begin;
22235 bottomBlock->bbTreeList->gtPrev = bottomBlock_End;
22239 // Set the try and handler index and fix the jump types of inlinee's blocks.
22242 bool inheritWeight;
22243 inheritWeight = true; // The firstBB does inherit the weight from the iciBlock
22245 for (block = InlineeCompiler->fgFirstBB; block != nullptr; block = block->bbNext)
22247 noway_assert(!block->hasTryIndex());
22248 noway_assert(!block->hasHndIndex());
22249 block->copyEHRegion(iciBlock);
22250 block->bbFlags |= iciBlock->bbFlags & BBF_BACKWARD_JUMP;
22252 if (iciStmt->gtStmtILoffsx != BAD_IL_OFFSET)
22254 block->bbCodeOffs = jitGetILoffs(iciStmt->gtStmtILoffsx);
22255 block->bbCodeOffsEnd = block->bbCodeOffs + 1; // TODO: is code size of 1 some magic number for inlining?
22259 block->bbCodeOffs = 0; // TODO: why not BAD_IL_OFFSET?
22260 block->bbCodeOffsEnd = 0;
22261 block->bbFlags |= BBF_INTERNAL;
22264 if (block->bbJumpKind == BBJ_RETURN)
22266 inheritWeight = true; // A return block does inherit the weight from the iciBlock
22267 noway_assert((block->bbFlags & BBF_HAS_JMP) == 0);
22270 block->bbJumpKind = BBJ_ALWAYS;
22271 block->bbJumpDest = bottomBlock;
22275 printf("\nConvert bbJumpKind of BB%02u to BBJ_ALWAYS to bottomBlock BB%02u\n", block->bbNum,
22276 bottomBlock->bbNum);
22285 printf("\nConvert bbJumpKind of BB%02u to BBJ_NONE\n", block->bbNum);
22288 block->bbJumpKind = BBJ_NONE;
22293 block->inheritWeight(iciBlock);
22294 inheritWeight = false;
22298 block->modifyBBWeight(iciBlock->bbWeight / 2);
22302 // Insert inlinee's blocks into inliner's block list.
22303 topBlock->setNext(InlineeCompiler->fgFirstBB);
22304 InlineeCompiler->fgLastBB->setNext(bottomBlock);
22307 // Add inlinee's block count to inliner's.
22309 fgBBcount += InlineeCompiler->fgBBcount;
22311 // Append statements to null out gc ref locals, if necessary.
22312 fgInlineAppendStatements(pInlineInfo, bottomBlock, nullptr);
22317 fgDispBasicBlocks(InlineeCompiler->fgFirstBB, InlineeCompiler->fgLastBB, true);
22324 // At this point, we have successully inserted inlinee's code.
22328 // Copy out some flags
22330 compLongUsed |= InlineeCompiler->compLongUsed;
22331 compFloatingPointUsed |= InlineeCompiler->compFloatingPointUsed;
22332 compLocallocUsed |= InlineeCompiler->compLocallocUsed;
22333 compQmarkUsed |= InlineeCompiler->compQmarkUsed;
22334 compUnsafeCastUsed |= InlineeCompiler->compUnsafeCastUsed;
22335 compNeedsGSSecurityCookie |= InlineeCompiler->compNeedsGSSecurityCookie;
22336 compGSReorderStackLayout |= InlineeCompiler->compGSReorderStackLayout;
22338 #ifdef FEATURE_SIMD
22339 if (InlineeCompiler->usesSIMDTypes())
22341 setUsesSIMDTypes(true);
22343 #endif // FEATURE_SIMD
22345 // Update unmanaged call count
22346 info.compCallUnmanaged += InlineeCompiler->info.compCallUnmanaged;
22348 // Update optMethodFlags
22351 unsigned optMethodFlagsBefore = optMethodFlags;
22354 optMethodFlags |= InlineeCompiler->optMethodFlags;
22357 if (optMethodFlags != optMethodFlagsBefore)
22359 JITDUMP("INLINER: Updating optMethodFlags -- root:%0x callee:%0x new:%0x\n", optMethodFlagsBefore,
22360 InlineeCompiler->optMethodFlags, optMethodFlags);
22364 // If there is non-NULL return, replace the GT_CALL with its return value expression,
22365 // so later it will be picked up by the GT_RET_EXPR node.
22366 if ((pInlineInfo->inlineCandidateInfo->fncRetType != TYP_VOID) || (iciCall->gtReturnType == TYP_STRUCT))
22368 noway_assert(pInlineInfo->retExpr);
22372 printf("\nReturn expression for call at ");
22373 printTreeID(iciCall);
22375 gtDispTree(pInlineInfo->retExpr);
22378 // Replace the call with the return expression
22379 iciCall->CopyFrom(pInlineInfo->retExpr, this);
22383 // Detach the GT_CALL node from the original statement by hanging a "nothing" node under it,
22384 // so that fgMorphStmts can remove the statement once we return from here.
22386 iciStmt->gtStmtExpr = gtNewNothingNode();
22389 //------------------------------------------------------------------------
22390 // fgInlinePrependStatements: prepend statements needed to match up
22391 // caller and inlined callee
22394 // inlineInfo -- info for the inline
22397 // The last statement that was added, or the original call if no
22398 // statements were added.
22401 // Statements prepended may include the following:
22402 // * This pointer null check
22403 // * Class initialization
22404 // * Zeroing of must-init locals in the callee
22405 // * Passing of call arguments via temps
22407 // Newly added statements are placed just after the original call
22408 // and are are given the same inline context as the call any calls
22409 // added here will appear to have been part of the immediate caller.
22411 GenTreePtr Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
22413 BasicBlock* block = inlineInfo->iciBlock;
22414 GenTreeStmt* callStmt = inlineInfo->iciStmt;
22415 IL_OFFSETX callILOffset = callStmt->gtStmtILoffsx;
22416 GenTreeStmt* postStmt = callStmt->gtNextStmt;
22417 GenTreePtr afterStmt = callStmt; // afterStmt is the place where the new statements should be inserted after.
22418 GenTreePtr newStmt = nullptr;
22419 GenTreeCall* call = inlineInfo->iciCall->AsCall();
22421 noway_assert(call->gtOper == GT_CALL);
22426 printf("\nfgInlinePrependStatements for iciCall= ");
22432 // Prepend statements for any initialization / side effects
22434 InlArgInfo* inlArgInfo = inlineInfo->inlArgInfo;
22435 InlLclVarInfo* lclVarInfo = inlineInfo->lclVarInfo;
22439 // Create the null check statement (but not appending it to the statement list yet) for the 'this' pointer if
22441 // The NULL check should be done after "argument setup statements".
22442 // The only reason we move it here is for calling "impInlineFetchArg(0,..." to reserve a temp
22443 // for the "this" pointer.
22444 // Note: Here we no longer do the optimization that was done by thisDereferencedFirst in the old inliner.
22445 // However the assetionProp logic will remove any unecessary null checks that we may have added
22447 GenTreePtr nullcheck = nullptr;
22449 if (call->gtFlags & GTF_CALL_NULLCHECK && !inlineInfo->thisDereferencedFirst)
22451 // Call impInlineFetchArg to "reserve" a temp for the "this" pointer.
22452 nullcheck = gtNewOperNode(GT_IND, TYP_INT, impInlineFetchArg(0, inlArgInfo, lclVarInfo));
22453 nullcheck->gtFlags |= GTF_EXCEPT;
22455 // The NULL-check statement will be inserted to the statement list after those statements
22456 // that assign arguments to temps and before the actual body of the inlinee method.
22459 /* Treat arguments that had to be assigned to temps */
22460 if (inlineInfo->argCnt)
22466 printf("\nArguments setup:\n");
22470 for (unsigned argNum = 0; argNum < inlineInfo->argCnt; argNum++)
22472 const InlArgInfo& argInfo = inlArgInfo[argNum];
22473 const bool argIsSingleDef = !argInfo.argHasLdargaOp && !argInfo.argHasStargOp;
22474 GenTree* const argNode = inlArgInfo[argNum].argNode;
22476 if (argInfo.argHasTmp)
22478 noway_assert(argInfo.argIsUsed);
22480 /* argBashTmpNode is non-NULL iff the argument's value was
22481 referenced exactly once by the original IL. This offers an
22482 oppportunity to avoid an intermediate temp and just insert
22483 the original argument tree.
22485 However, if the temp node has been cloned somewhere while
22486 importing (e.g. when handling isinst or dup), or if the IL
22487 took the address of the argument, then argBashTmpNode will
22488 be set (because the value was only explicitly retrieved
22489 once) but the optimization cannot be applied.
22492 GenTreePtr argSingleUseNode = argInfo.argBashTmpNode;
22494 if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) && argIsSingleDef)
22496 // Change the temp in-place to the actual argument.
22497 // We currently do not support this for struct arguments, so it must not be a GT_OBJ.
22498 assert(argNode->gtOper != GT_OBJ);
22499 argSingleUseNode->CopyFrom(argNode, this);
22504 // We're going to assign the argument value to the
22505 // temp we use for it in the inline body.
22506 const unsigned tmpNum = argInfo.argTmpNum;
22507 const var_types argType = lclVarInfo[argNum].lclTypeInfo;
22509 // Create the temp assignment for this argument
22510 CORINFO_CLASS_HANDLE structHnd = DUMMY_INIT(0);
22512 if (varTypeIsStruct(argType))
22514 structHnd = gtGetStructHandleIfPresent(argNode);
22515 noway_assert(structHnd != NO_CLASS_HANDLE);
22518 // Unsafe value cls check is not needed for
22519 // argTmpNum here since in-linee compiler instance
22520 // would have iterated over these and marked them
22522 impAssignTempGen(tmpNum, argNode, structHnd, (unsigned)CHECK_SPILL_NONE, &afterStmt, callILOffset,
22525 // If we know the argument's value can't be
22526 // changed within the method body, try and improve
22527 // the type of the temp.
22528 if (argIsSingleDef && (argType == TYP_REF))
22530 lvaUpdateClass(tmpNum, argNode);
22536 gtDispTree(afterStmt);
22541 else if (argInfo.argIsByRefToStructLocal)
22543 // Do nothing. Arg was directly substituted as we read
22548 /* The argument is either not used or a const or lcl var */
22550 noway_assert(!argInfo.argIsUsed || argInfo.argIsInvariant || argInfo.argIsLclVar);
22552 /* Make sure we didnt change argNode's along the way, or else
22553 subsequent uses of the arg would have worked with the bashed value */
22554 if (argInfo.argIsInvariant)
22556 assert(argNode->OperIsConst() || argNode->gtOper == GT_ADDR);
22558 noway_assert((argInfo.argIsLclVar == 0) ==
22559 (argNode->gtOper != GT_LCL_VAR || (argNode->gtFlags & GTF_GLOB_REF)));
22561 /* If the argument has side effects, append it */
22563 if (argInfo.argHasSideEff)
22565 noway_assert(argInfo.argIsUsed == false);
22567 if (argNode->gtOper == GT_OBJ || argNode->gtOper == GT_MKREFANY)
22569 // Don't put GT_OBJ node under a GT_COMMA.
22570 // Codegen can't deal with it.
22571 // Just hang the address here in case there are side-effect.
22572 newStmt = gtNewStmt(gtUnusedValNode(argNode->gtOp.gtOp1), callILOffset);
22576 newStmt = gtNewStmt(gtUnusedValNode(argNode), callILOffset);
22578 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22583 gtDispTree(afterStmt);
22591 // Add the CCTOR check if asked for.
22592 // Note: We no longer do the optimization that is done before by staticAccessedFirstUsingHelper in the old inliner.
22593 // Therefore we might prepend redundant call to HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
22594 // before the inlined method body, even if a static field of this type was accessed in the inlinee
22595 // using a helper before any other observable side-effect.
22597 if (inlineInfo->inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_USE_HELPER)
22599 CORINFO_CONTEXT_HANDLE exactContext = inlineInfo->inlineCandidateInfo->exactContextHnd;
22600 CORINFO_CLASS_HANDLE exactClass;
22602 if (((SIZE_T)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
22604 exactClass = CORINFO_CLASS_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
22608 exactClass = info.compCompHnd->getMethodClass(
22609 CORINFO_METHOD_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK));
22612 tree = fgGetSharedCCtor(exactClass);
22613 newStmt = gtNewStmt(tree, callILOffset);
22614 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22617 // Insert the nullcheck statement now.
22620 newStmt = gtNewStmt(nullcheck, callILOffset);
22621 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22625 // Now zero-init inlinee locals
22628 CORINFO_METHOD_INFO* InlineeMethodInfo = InlineeCompiler->info.compMethodInfo;
22630 unsigned lclCnt = InlineeMethodInfo->locals.numArgs;
22632 // Does callee contain any zero-init local?
22633 if ((lclCnt != 0) && (InlineeMethodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0)
22639 printf("\nZero init inlinee locals:\n");
22643 for (unsigned lclNum = 0; lclNum < lclCnt; lclNum++)
22645 unsigned tmpNum = inlineInfo->lclTmpNum[lclNum];
22647 // Is the local used at all?
22648 if (tmpNum != BAD_VAR_NUM)
22650 var_types lclTyp = (var_types)lvaTable[tmpNum].lvType;
22651 noway_assert(lclTyp == lclVarInfo[lclNum + inlineInfo->argCnt].lclTypeInfo);
22653 if (!varTypeIsStruct(lclTyp))
22655 // Unsafe value cls check is not needed here since in-linee compiler instance would have
22656 // iterated over locals and marked accordingly.
22657 impAssignTempGen(tmpNum, gtNewZeroConNode(genActualType(lclTyp)), NO_CLASS_HANDLE,
22658 (unsigned)CHECK_SPILL_NONE, &afterStmt, callILOffset, block);
22662 CORINFO_CLASS_HANDLE structType =
22663 lclVarInfo[lclNum + inlineInfo->argCnt].lclVerTypeInfo.GetClassHandle();
22665 tree = gtNewBlkOpNode(gtNewLclvNode(tmpNum, lclTyp), // Dest
22666 gtNewIconNode(0), // Value
22667 info.compCompHnd->getClassSize(structType), // Size
22668 false, // isVolatile
22669 false); // not copyBlock
22671 newStmt = gtNewStmt(tree, callILOffset);
22672 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
22678 gtDispTree(afterStmt);
22685 // Update any newly added statements with the appropriate context.
22686 InlineContext* context = callStmt->gtInlineContext;
22687 assert(context != nullptr);
22688 for (GenTreeStmt* addedStmt = callStmt->gtNextStmt; addedStmt != postStmt; addedStmt = addedStmt->gtNextStmt)
22690 assert(addedStmt->gtInlineContext == nullptr);
22691 addedStmt->gtInlineContext = context;
22697 //------------------------------------------------------------------------
22698 // fgInlineAppendStatements: Append statements that are needed
22699 // after the inlined call.
22702 // inlineInfo - information about the inline
22703 // block - basic block for the new statements
22704 // stmtAfter - (optional) insertion point for mid-block cases
22707 // If the call we're inlining is in tail position then
22708 // we skip nulling the locals, since it can interfere
22709 // with tail calls introduced by the local.
22711 void Compiler::fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreePtr stmtAfter)
22713 // If this inlinee was passed a runtime lookup generic context and
22714 // ignores it, we can decrement the "generic context was used" ref
22715 // count, because we created a new lookup tree and incremented the
22716 // count when we imported the type parameter argument to pass to
22717 // the inlinee. See corresponding logic in impImportCall that
22718 // checks the sig for CORINFO_CALLCONV_PARAMTYPE.
22720 // Does this method require a context (type) parameter?
22721 if ((inlineInfo->inlineCandidateInfo->methInfo.args.callConv & CORINFO_CALLCONV_PARAMTYPE) != 0)
22723 // Did the computation of that parameter require the
22724 // caller to perform a runtime lookup?
22725 if (inlineInfo->inlineCandidateInfo->exactContextNeedsRuntimeLookup)
22727 // Fetch the temp for the generic context as it would
22728 // appear in the inlinee's body.
22729 const unsigned typeCtxtArg = inlineInfo->typeContextArg;
22730 const unsigned tmpNum = inlineInfo->lclTmpNum[typeCtxtArg];
22732 // Was it used in the inline body?
22733 if (tmpNum == BAD_VAR_NUM)
22735 // No -- so the associated runtime lookup is not needed
22736 // and also no longer provides evidence that the generic
22737 // context should be kept alive.
22738 JITDUMP("Inlinee ignores runtime lookup generics context\n");
22739 assert(lvaGenericsContextUseCount > 0);
22740 lvaGenericsContextUseCount--;
22745 // Null out any gc ref locals
22746 if (!inlineInfo->HasGcRefLocals())
22748 // No ref locals, nothing to do.
22749 JITDUMP("fgInlineAppendStatements: no gc ref inline locals.\n");
22753 if (inlineInfo->iciCall->IsImplicitTailCall())
22755 JITDUMP("fgInlineAppendStatements: implicit tail call; skipping nulling.\n");
22759 JITDUMP("fgInlineAppendStatements: nulling out gc ref inlinee locals.\n");
22761 GenTreePtr callStmt = inlineInfo->iciStmt;
22762 IL_OFFSETX callILOffset = callStmt->gtStmt.gtStmtILoffsx;
22763 CORINFO_METHOD_INFO* InlineeMethodInfo = InlineeCompiler->info.compMethodInfo;
22764 const unsigned lclCnt = InlineeMethodInfo->locals.numArgs;
22765 InlLclVarInfo* lclVarInfo = inlineInfo->lclVarInfo;
22766 unsigned gcRefLclCnt = inlineInfo->numberOfGcRefLocals;
22767 const unsigned argCnt = inlineInfo->argCnt;
22769 noway_assert(callStmt->gtOper == GT_STMT);
22771 for (unsigned lclNum = 0; lclNum < lclCnt; lclNum++)
22773 // Is the local a gc ref type? Need to look at the
22774 // inline info for this since we will not have local
22775 // temps for unused inlinee locals.
22776 const var_types lclTyp = lclVarInfo[argCnt + lclNum].lclTypeInfo;
22778 if (!varTypeIsGC(lclTyp))
22780 // Nope, nothing to null out.
22784 // Ensure we're examining just the right number of locals.
22785 assert(gcRefLclCnt > 0);
22788 // Fetch the temp for this inline local
22789 const unsigned tmpNum = inlineInfo->lclTmpNum[lclNum];
22791 // Is the local used at all?
22792 if (tmpNum == BAD_VAR_NUM)
22794 // Nope, nothing to null out.
22798 // Local was used, make sure the type is consistent.
22799 assert(lvaTable[tmpNum].lvType == lclTyp);
22801 // Does the local we're about to null out appear in the return
22802 // expression? If so we somehow messed up and didn't properly
22803 // spill the return value. See impInlineFetchLocal.
22804 GenTreePtr retExpr = inlineInfo->retExpr;
22805 if (retExpr != nullptr)
22807 const bool interferesWithReturn = gtHasRef(inlineInfo->retExpr, tmpNum, false);
22808 noway_assert(!interferesWithReturn);
22811 // Assign null to the local.
22812 GenTreePtr nullExpr = gtNewTempAssign(tmpNum, gtNewZeroConNode(lclTyp));
22813 GenTreePtr nullStmt = gtNewStmt(nullExpr, callILOffset);
22815 if (stmtAfter == nullptr)
22817 stmtAfter = fgInsertStmtAtBeg(block, nullStmt);
22821 stmtAfter = fgInsertStmtAfter(block, stmtAfter, nullStmt);
22827 gtDispTree(nullStmt);
22832 // There should not be any GC ref locals left to null out.
22833 assert(gcRefLclCnt == 0);
22836 /*****************************************************************************/
22838 Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTreePtr* pTree, fgWalkData* data)
22840 GenTreePtr tree = *pTree;
22842 // If this tree doesn't have the EXCEPT flag set, then there is no
22843 // way any of the child nodes could throw, so we can stop recursing.
22844 if (!(tree->gtFlags & GTF_EXCEPT))
22846 return Compiler::WALK_SKIP_SUBTREES;
22849 switch (tree->gtOper)
22857 if (tree->gtOverflow())
22859 return Compiler::WALK_ABORT;
22864 if (tree->gtFlags & GTF_INX_RNGCHK)
22866 return Compiler::WALK_ABORT;
22870 case GT_ARR_BOUNDS_CHECK:
22871 return Compiler::WALK_ABORT;
22877 return Compiler::WALK_CONTINUE;
22880 /*****************************************************************************/
22882 Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTreePtr* pTree, fgWalkData* data)
22884 GenTreePtr tree = *pTree;
22886 if (tree->gtOper == GT_LCLHEAP)
22888 return Compiler::WALK_ABORT;
22891 return Compiler::WALK_CONTINUE;
22894 /*****************************************************************************/
22896 Compiler::fgWalkResult Compiler::fgChkQmarkCB(GenTreePtr* pTree, fgWalkData* data)
22898 GenTreePtr tree = *pTree;
22900 if (tree->gtOper == GT_QMARK)
22902 return Compiler::WALK_ABORT;
22905 return Compiler::WALK_CONTINUE;
22908 void Compiler::fgLclFldAssign(unsigned lclNum)
22910 assert(varTypeIsStruct(lvaTable[lclNum].lvType));
22911 if (lvaTable[lclNum].lvPromoted && lvaTable[lclNum].lvFieldCnt > 1)
22913 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
22917 //------------------------------------------------------------------------
22918 // fgRemoveEmptyFinally: Remove try/finallys where the finally is empty
22921 // Removes all try/finallys in the method with empty finallys.
22922 // These typically arise from inlining empty Dispose methods.
22924 // Converts callfinally to a jump to the finally continuation.
22925 // Removes the finally, and reparents all blocks in the try to the
22926 // enclosing try or method region.
22928 // Currently limited to trivially empty finallys: those with one basic
22929 // block containing only single RETFILT statement. It is possible but
22930 // not likely that more complex-looking finallys will eventually become
22931 // empty (from say subsequent optimization). An SPMI run with
22932 // just the "detection" part of this phase run after optimization
22933 // found only one example where a new empty finally was detected.
22935 void Compiler::fgRemoveEmptyFinally()
22937 JITDUMP("\n*************** In fgRemoveEmptyFinally()\n");
22939 #if FEATURE_EH_FUNCLETS
22940 // We need to do this transformation before funclets are created.
22941 assert(!fgFuncletsCreated);
22942 #endif // FEATURE_EH_FUNCLETS
22944 // Assume we don't need to update the bbPreds lists.
22945 assert(!fgComputePredsDone);
22947 if (compHndBBtabCount == 0)
22949 JITDUMP("No EH in this method, nothing to remove.\n");
22953 if (opts.MinOpts())
22955 JITDUMP("Method compiled with minOpts, no removal.\n");
22959 if (opts.compDbgCode)
22961 JITDUMP("Method compiled with debug codegen, no removal.\n");
22968 printf("\n*************** Before fgRemoveEmptyFinally()\n");
22969 fgDispBasicBlocks();
22970 fgDispHandlerTab();
22975 // Look for finallys or faults that are empty.
22976 unsigned finallyCount = 0;
22977 unsigned emptyCount = 0;
22978 unsigned XTnum = 0;
22979 while (XTnum < compHndBBtabCount)
22981 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
22983 // Check if this is a try/finally. We could also look for empty
22984 // try/fault but presumably those are rare.
22985 if (!HBtab->HasFinallyHandler())
22987 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
22994 // Look at blocks involved.
22995 BasicBlock* const firstBlock = HBtab->ebdHndBeg;
22996 BasicBlock* const lastBlock = HBtab->ebdHndLast;
22998 // Limit for now to finallys that are single blocks.
22999 if (firstBlock != lastBlock)
23001 JITDUMP("EH#%u finally has multiple basic blocks; skipping.\n", XTnum);
23006 // Limit for now to finallys that contain only a GT_RETFILT.
23007 bool isEmpty = true;
23009 for (GenTreeStmt* stmt = firstBlock->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
23011 GenTreePtr stmtExpr = stmt->gtStmtExpr;
23013 if (stmtExpr->gtOper != GT_RETFILT)
23022 JITDUMP("EH#%u finally is not empty; skipping.\n", XTnum);
23027 JITDUMP("EH#%u has empty finally, removing the region.\n", XTnum);
23029 // Find all the call finallys that invoke this finally,
23030 // and modify them to jump to the return point.
23031 BasicBlock* firstCallFinallyRangeBlock = nullptr;
23032 BasicBlock* endCallFinallyRangeBlock = nullptr;
23033 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
23035 BasicBlock* currentBlock = firstCallFinallyRangeBlock;
23037 while (currentBlock != endCallFinallyRangeBlock)
23039 BasicBlock* nextBlock = currentBlock->bbNext;
23041 if ((currentBlock->bbJumpKind == BBJ_CALLFINALLY) && (currentBlock->bbJumpDest == firstBlock))
23043 // Retarget the call finally to jump to the return
23046 // We don't expect to see retless finallys here, since
23047 // the finally is empty.
23048 noway_assert(currentBlock->isBBCallAlwaysPair());
23050 BasicBlock* const leaveBlock = currentBlock->bbNext;
23051 BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
23053 noway_assert(leaveBlock->bbJumpKind == BBJ_ALWAYS);
23055 currentBlock->bbJumpDest = postTryFinallyBlock;
23056 currentBlock->bbJumpKind = BBJ_ALWAYS;
23058 // Ref count updates.
23059 fgAddRefPred(postTryFinallyBlock, currentBlock);
23060 // fgRemoveRefPred(firstBlock, currentBlock);
23062 // Delete the leave block, which should be marked as
23064 assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
23065 nextBlock = leaveBlock->bbNext;
23067 leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
23068 fgRemoveBlock(leaveBlock, true);
23070 // Cleanup the postTryFinallyBlock
23071 fgCleanupContinuation(postTryFinallyBlock);
23073 // Make sure iteration isn't going off the deep end.
23074 assert(leaveBlock != endCallFinallyRangeBlock);
23077 currentBlock = nextBlock;
23080 // Handler block should now be unreferenced, since the only
23081 // explicit references to it were in call finallys.
23082 firstBlock->bbRefs = 0;
23084 // Remove the handler block.
23085 const bool unreachable = true;
23086 firstBlock->bbFlags &= ~BBF_DONT_REMOVE;
23087 fgRemoveBlock(firstBlock, unreachable);
23089 // Find enclosing try region for the try, if any, and update
23090 // the try region. Note the handler region (if any) won't
23092 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
23093 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
23094 assert(firstTryBlock->getTryIndex() == XTnum);
23096 for (BasicBlock* block = firstTryBlock; block != nullptr; block = block->bbNext)
23098 // Look for blocks directly contained in this try, and
23099 // update the try region appropriately.
23101 // Try region for blocks transitively contained (say in a
23102 // child try) will get updated by the subsequent call to
23103 // fgRemoveEHTableEntry.
23104 if (block->getTryIndex() == XTnum)
23106 if (firstBlock->hasTryIndex())
23108 block->setTryIndex(firstBlock->getTryIndex());
23112 block->clearTryIndex();
23116 if (block == firstTryBlock)
23118 assert((block->bbFlags & BBF_TRY_BEG) != 0);
23119 block->bbFlags &= ~BBF_TRY_BEG;
23122 if (block == lastTryBlock)
23128 // Remove the try-finally EH region. This will compact the EH table
23129 // so XTnum now points at the next entry.
23130 fgRemoveEHTableEntry(XTnum);
23135 if (emptyCount > 0)
23137 JITDUMP("fgRemoveEmptyFinally() removed %u try-finally clauses from %u finallys\n", emptyCount, finallyCount);
23138 fgOptimizedFinally = true;
23143 printf("\n*************** After fgRemoveEmptyFinally()\n");
23144 fgDispBasicBlocks();
23145 fgDispHandlerTab();
23149 fgVerifyHandlerTab();
23150 fgDebugCheckBBlist(false, false);
23156 //------------------------------------------------------------------------
23157 // fgRemoveEmptyTry: Optimize try/finallys where the try is empty
23160 // In runtimes where thread abort is not possible, `try {} finally {S}`
23161 // can be optimized to simply `S`. This method looks for such
23162 // cases and removes the try-finally from the EH table, making
23163 // suitable flow, block flag, statement, and region updates.
23165 // This optimization is not legal in runtimes that support thread
23166 // abort because those runtimes ensure that a finally is completely
23167 // executed before continuing to process the thread abort. With
23168 // this optimization, the code block `S` can lose special
23169 // within-finally status and so complete execution is no longer
23172 void Compiler::fgRemoveEmptyTry()
23174 JITDUMP("\n*************** In fgRemoveEmptyTry()\n");
23176 #if FEATURE_EH_FUNCLETS
23177 // We need to do this transformation before funclets are created.
23178 assert(!fgFuncletsCreated);
23179 #endif // FEATURE_EH_FUNCLETS
23181 // Assume we don't need to update the bbPreds lists.
23182 assert(!fgComputePredsDone);
23184 #ifdef FEATURE_CORECLR
23185 bool enableRemoveEmptyTry = true;
23187 // Code in a finally gets special treatment in the presence of
23189 bool enableRemoveEmptyTry = false;
23190 #endif // FEATURE_CORECLR
23193 // Allow override to enable/disable.
23194 enableRemoveEmptyTry = (JitConfig.JitEnableRemoveEmptyTry() == 1);
23197 if (!enableRemoveEmptyTry)
23199 JITDUMP("Empty try removal disabled.\n");
23203 if (compHndBBtabCount == 0)
23205 JITDUMP("No EH in this method, nothing to remove.\n");
23209 if (opts.MinOpts())
23211 JITDUMP("Method compiled with minOpts, no removal.\n");
23215 if (opts.compDbgCode)
23217 JITDUMP("Method compiled with debug codegen, no removal.\n");
23224 printf("\n*************** Before fgRemoveEmptyTry()\n");
23225 fgDispBasicBlocks();
23226 fgDispHandlerTab();
23231 // Look for try-finallys where the try is empty.
23232 unsigned emptyCount = 0;
23233 unsigned XTnum = 0;
23234 while (XTnum < compHndBBtabCount)
23236 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
23238 // Check if this is a try/finally. We could also look for empty
23239 // try/fault but presumably those are rare.
23240 if (!HBtab->HasFinallyHandler())
23242 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
23247 // Examine the try region
23248 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
23249 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
23250 BasicBlock* const firstHandlerBlock = HBtab->ebdHndBeg;
23251 BasicBlock* const lastHandlerBlock = HBtab->ebdHndLast;
23252 BasicBlock* const endHandlerBlock = lastHandlerBlock->bbNext;
23254 assert(firstTryBlock->getTryIndex() == XTnum);
23256 // Limit for now to trys that contain only a callfinally pair
23257 // or branch to same.
23258 if (!firstTryBlock->isEmpty())
23260 JITDUMP("EH#%u first try block BB%02u not empty; skipping.\n", XTnum, firstTryBlock->bbNum);
23265 #if FEATURE_EH_CALLFINALLY_THUNKS
23267 // Look for blocks that are always jumps to a call finally
23268 // pair that targets the finally
23269 if (firstTryBlock->bbJumpKind != BBJ_ALWAYS)
23271 JITDUMP("EH#%u first try block BB%02u not jump to a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum);
23276 BasicBlock* const callFinally = firstTryBlock->bbJumpDest;
23278 // Look for call always pair. Note this will also disqualify
23279 // empty try removal in cases where the finally doesn't
23281 if (!callFinally->isBBCallAlwaysPair() || (callFinally->bbJumpDest != firstHandlerBlock))
23283 JITDUMP("EH#%u first try block BB%02u always jumps but not to a callfinally; skipping.\n", XTnum,
23284 firstTryBlock->bbNum);
23289 // Try itself must be a single block.
23290 if (firstTryBlock != lastTryBlock)
23292 JITDUMP("EH#%u first try block BB%02u not only block in try; skipping.\n", XTnum,
23293 firstTryBlock->bbNext->bbNum);
23299 // Look for call always pair within the try itself. Note this
23300 // will also disqualify empty try removal in cases where the
23301 // finally doesn't return.
23302 if (!firstTryBlock->isBBCallAlwaysPair() || (firstTryBlock->bbJumpDest != firstHandlerBlock))
23304 JITDUMP("EH#%u first try block BB%02u not a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum);
23309 BasicBlock* const callFinally = firstTryBlock;
23311 // Try must be a callalways pair of blocks.
23312 if (firstTryBlock->bbNext != lastTryBlock)
23314 JITDUMP("EH#%u block BB%02u not last block in try; skipping.\n", XTnum, firstTryBlock->bbNext->bbNum);
23319 #endif // FEATURE_EH_CALLFINALLY_THUNKS
23321 JITDUMP("EH#%u has empty try, removing the try region and promoting the finally.\n", XTnum);
23323 // There should be just one callfinally that invokes this
23324 // finally, the one we found above. Verify this.
23325 BasicBlock* firstCallFinallyRangeBlock = nullptr;
23326 BasicBlock* endCallFinallyRangeBlock = nullptr;
23327 bool verifiedSingleCallfinally = true;
23328 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
23330 for (BasicBlock* block = firstCallFinallyRangeBlock; block != endCallFinallyRangeBlock; block = block->bbNext)
23332 if ((block->bbJumpKind == BBJ_CALLFINALLY) && (block->bbJumpDest == firstHandlerBlock))
23334 assert(block->isBBCallAlwaysPair());
23336 if (block != callFinally)
23338 JITDUMP("EH#%u found unexpected callfinally BB%02u; skipping.\n");
23339 verifiedSingleCallfinally = false;
23343 block = block->bbNext;
23347 if (!verifiedSingleCallfinally)
23349 JITDUMP("EH#%u -- unexpectedly -- has multiple callfinallys; skipping.\n");
23351 assert(verifiedSingleCallfinally);
23355 // Time to optimize.
23357 // (1) Convert the callfinally to a normal jump to the handler
23358 callFinally->bbJumpKind = BBJ_ALWAYS;
23360 // Identify the leave block and the continuation
23361 BasicBlock* const leave = callFinally->bbNext;
23362 BasicBlock* const continuation = leave->bbJumpDest;
23364 // (2) Cleanup the leave so it can be deleted by subsequent opts
23365 assert((leave->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
23366 leave->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
23368 // (3) Cleanup the continuation
23369 fgCleanupContinuation(continuation);
23371 // (4) Find enclosing try region for the try, if any, and
23372 // update the try region for the blocks in the try. Note the
23373 // handler region (if any) won't change.
23375 // Kind of overkill to loop here, but hey.
23376 for (BasicBlock* block = firstTryBlock; block != nullptr; block = block->bbNext)
23378 // Look for blocks directly contained in this try, and
23379 // update the try region appropriately.
23381 // The try region for blocks transitively contained (say in a
23382 // child try) will get updated by the subsequent call to
23383 // fgRemoveEHTableEntry.
23384 if (block->getTryIndex() == XTnum)
23386 if (firstHandlerBlock->hasTryIndex())
23388 block->setTryIndex(firstHandlerBlock->getTryIndex());
23392 block->clearTryIndex();
23396 if (block == firstTryBlock)
23398 assert((block->bbFlags & BBF_TRY_BEG) != 0);
23399 block->bbFlags &= ~BBF_TRY_BEG;
23402 if (block == lastTryBlock)
23408 // (5) Update the directly contained handler blocks' handler index.
23409 // Handler index of any nested blocks will update when we
23410 // remove the EH table entry. Change handler exits to jump to
23411 // the continuation. Clear catch type on handler entry.
23412 // Decrement nesting level of enclosed GT_END_LFINs.
23413 for (BasicBlock* block = firstHandlerBlock; block != endHandlerBlock; block = block->bbNext)
23415 if (block == firstHandlerBlock)
23417 block->bbCatchTyp = BBCT_NONE;
23420 if (block->getHndIndex() == XTnum)
23422 if (firstTryBlock->hasHndIndex())
23424 block->setHndIndex(firstTryBlock->getHndIndex());
23428 block->clearHndIndex();
23431 if (block->bbJumpKind == BBJ_EHFINALLYRET)
23433 GenTreeStmt* finallyRet = block->lastStmt();
23434 GenTreePtr finallyRetExpr = finallyRet->gtStmtExpr;
23435 assert(finallyRetExpr->gtOper == GT_RETFILT);
23436 fgRemoveStmt(block, finallyRet);
23437 block->bbJumpKind = BBJ_ALWAYS;
23438 block->bbJumpDest = continuation;
23439 fgAddRefPred(continuation, block);
23443 #if !FEATURE_EH_FUNCLETS
23444 // If we're in a non-funclet model, decrement the nesting
23445 // level of any GT_END_LFIN we find in the handler region,
23446 // since we're removing the enclosing handler.
23447 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
23449 GenTreePtr expr = stmt->gtStmtExpr;
23450 if (expr->gtOper == GT_END_LFIN)
23452 const unsigned nestLevel = expr->gtVal.gtVal1;
23453 assert(nestLevel > 0);
23454 expr->gtVal.gtVal1 = nestLevel - 1;
23457 #endif // !FEATURE_EH_FUNCLETS
23460 // (6) Remove the try-finally EH region. This will compact the
23461 // EH table so XTnum now points at the next entry and will update
23462 // the EH region indices of any nested EH in the (former) handler.
23463 fgRemoveEHTableEntry(XTnum);
23465 // Another one bites the dust...
23469 if (emptyCount > 0)
23471 JITDUMP("fgRemoveEmptyTry() optimized %u empty-try try-finally clauses\n", emptyCount);
23472 fgOptimizedFinally = true;
23477 printf("\n*************** After fgRemoveEmptyTry()\n");
23478 fgDispBasicBlocks();
23479 fgDispHandlerTab();
23483 fgVerifyHandlerTab();
23484 fgDebugCheckBBlist(false, false);
23490 //------------------------------------------------------------------------
23491 // fgCloneFinally: Optimize normal exit path from a try/finally
23494 // Handles finallys that are not enclosed by or enclosing other
23495 // handler regions.
23497 // Converts the "normal exit" callfinally to a jump to a cloned copy
23498 // of the finally, which in turn jumps to the finally continuation.
23500 // If all callfinallys for a given finally are converted to jump to
23501 // the clone, the try-finally is modified into a try-fault,
23502 // distingushable from organic try-faults by handler type
23503 // EH_HANDLER_FAULT_WAS_FINALLY vs the organic EH_HANDLER_FAULT.
23505 // Does not yet handle thread abort. The open issues here are how
23506 // to maintain the proper description of the cloned finally blocks
23507 // as a handler (for thread abort purposes), how to prevent code
23508 // motion in or out of these blocks, and how to report this cloned
23509 // handler to the runtime. Some building blocks for thread abort
23510 // exist (see below) but more work needed.
23512 // The first and last blocks of the cloned finally are marked with
23513 // BBF_CLONED_FINALLY_BEGIN and BBF_CLONED_FINALLY_END. However
23514 // these markers currently can get lost during subsequent
23517 void Compiler::fgCloneFinally()
23519 JITDUMP("\n*************** In fgCloneFinally()\n");
23521 #if FEATURE_EH_FUNCLETS
23522 // We need to do this transformation before funclets are created.
23523 assert(!fgFuncletsCreated);
23524 #endif // FEATURE_EH_FUNCLETS
23526 // Assume we don't need to update the bbPreds lists.
23527 assert(!fgComputePredsDone);
23529 #ifdef FEATURE_CORECLR
23530 bool enableCloning = true;
23532 // Finally cloning currently doesn't provide sufficient protection
23533 // for the cloned code in the presence of thread abort.
23534 bool enableCloning = false;
23535 #endif // FEATURE_CORECLR
23538 // Allow override to enable/disable.
23539 enableCloning = (JitConfig.JitEnableFinallyCloning() == 1);
23542 if (!enableCloning)
23544 JITDUMP("Finally cloning disabled.\n");
23548 if (compHndBBtabCount == 0)
23550 JITDUMP("No EH in this method, no cloning.\n");
23554 if (opts.MinOpts())
23556 JITDUMP("Method compiled with minOpts, no cloning.\n");
23560 if (opts.compDbgCode)
23562 JITDUMP("Method compiled with debug codegen, no cloning.\n");
23569 printf("\n*************** Before fgCloneFinally()\n");
23570 fgDispBasicBlocks();
23571 fgDispHandlerTab();
23575 // Verify try-finally exits look good before we start.
23576 fgDebugCheckTryFinallyExits();
23580 // Look for finallys that are not contained within other handlers,
23581 // and which do not themselves contain EH.
23583 // Note these cases potentially could be handled, but are less
23584 // obviously profitable and require modification of the handler
23586 unsigned XTnum = 0;
23587 EHblkDsc* HBtab = compHndBBtab;
23588 unsigned cloneCount = 0;
23589 for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
23591 // Check if this is a try/finally
23592 if (!HBtab->HasFinallyHandler())
23594 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
23598 // Check if enclosed by another handler.
23599 const unsigned enclosingHandlerRegion = ehGetEnclosingHndIndex(XTnum);
23601 if (enclosingHandlerRegion != EHblkDsc::NO_ENCLOSING_INDEX)
23603 JITDUMP("EH#%u is enclosed by handler EH#%u; skipping.\n", XTnum, enclosingHandlerRegion);
23607 bool containsEH = false;
23608 unsigned exampleEnclosedHandlerRegion = 0;
23610 // Only need to look at lower numbered regions because the
23611 // handler table is ordered by nesting.
23612 for (unsigned i = 0; i < XTnum; i++)
23614 if (ehGetEnclosingHndIndex(i) == XTnum)
23616 exampleEnclosedHandlerRegion = i;
23624 JITDUMP("Finally for EH#%u encloses handler EH#%u; skipping.\n", XTnum, exampleEnclosedHandlerRegion);
23628 // Look at blocks involved.
23629 BasicBlock* const firstBlock = HBtab->ebdHndBeg;
23630 BasicBlock* const lastBlock = HBtab->ebdHndLast;
23631 assert(firstBlock != nullptr);
23632 assert(lastBlock != nullptr);
23633 BasicBlock* nextBlock = lastBlock->bbNext;
23634 unsigned regionBBCount = 0;
23635 unsigned regionStmtCount = 0;
23636 bool hasFinallyRet = false;
23637 bool isAllRare = true;
23638 bool hasSwitch = false;
23640 for (const BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
23642 if (block->bbJumpKind == BBJ_SWITCH)
23650 // Should we compute statement cost here, or is it
23651 // premature...? For now just count statements I guess.
23652 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
23657 hasFinallyRet = hasFinallyRet || (block->bbJumpKind == BBJ_EHFINALLYRET);
23658 isAllRare = isAllRare && block->isRunRarely();
23661 // Skip cloning if the finally has a switch.
23664 JITDUMP("Finally in EH#%u has a switch; skipping.\n", XTnum);
23668 // Skip cloning if the finally must throw.
23669 if (!hasFinallyRet)
23671 JITDUMP("Finally in EH#%u does not return; skipping.\n", XTnum);
23675 // Skip cloning if the finally is rarely run code.
23678 JITDUMP("Finally in EH#%u is run rarely; skipping.\n", XTnum);
23682 // Empirical studies from CoreCLR and CoreFX show that less
23683 // that 1% of finally regions have more than 15
23684 // statements. So, to avoid potentially excessive code growth,
23685 // only clone finallys that have 15 or fewer statements.
23686 const unsigned stmtCountLimit = 15;
23687 if (regionStmtCount > stmtCountLimit)
23689 JITDUMP("Finally in EH#%u has %u statements, limit is %u; skipping.\n", XTnum, regionStmtCount,
23694 JITDUMP("EH#%u is a candidate for finally cloning:"
23695 " %u blocks, %u statements\n",
23696 XTnum, regionBBCount, regionStmtCount);
23698 // Walk the try region backwards looking for the last block
23699 // that transfers control to a callfinally.
23700 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
23701 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
23702 assert(firstTryBlock->getTryIndex() == XTnum);
23703 assert(bbInTryRegions(XTnum, lastTryBlock));
23704 BasicBlock* const beforeTryBlock = firstTryBlock->bbPrev;
23706 BasicBlock* normalCallFinallyBlock = nullptr;
23707 BasicBlock* normalCallFinallyReturn = nullptr;
23708 BasicBlock* cloneInsertAfter = HBtab->ebdTryLast;
23709 bool tryToRelocateCallFinally = false;
23711 for (BasicBlock* block = lastTryBlock; block != beforeTryBlock; block = block->bbPrev)
23713 #if FEATURE_EH_CALLFINALLY_THUNKS
23714 // Look for blocks that are always jumps to a call finally
23715 // pair that targets our finally.
23716 if (block->bbJumpKind != BBJ_ALWAYS)
23721 BasicBlock* const jumpDest = block->bbJumpDest;
23723 if (!jumpDest->isBBCallAlwaysPair() || (jumpDest->bbJumpDest != firstBlock))
23728 // Look for call finally pair directly within the try
23729 if (!block->isBBCallAlwaysPair() || (block->bbJumpDest != firstBlock))
23734 BasicBlock* const jumpDest = block;
23735 #endif // FEATURE_EH_CALLFINALLY_THUNKS
23737 // Found our block.
23738 BasicBlock* const finallyReturnBlock = jumpDest->bbNext;
23739 BasicBlock* const postTryFinallyBlock = finallyReturnBlock->bbJumpDest;
23741 normalCallFinallyBlock = jumpDest;
23742 normalCallFinallyReturn = postTryFinallyBlock;
23744 #if FEATURE_EH_CALLFINALLY_THUNKS
23745 // When there are callfinally thunks, we don't expect to see the
23746 // callfinally within a handler region either.
23747 assert(!jumpDest->hasHndIndex());
23749 // Update the clone insertion point to just after the
23750 // call always pair.
23751 cloneInsertAfter = finallyReturnBlock;
23753 // We will consider moving the callfinally so we can fall
23754 // through from the try into the clone.
23755 tryToRelocateCallFinally = true;
23757 JITDUMP("Chose path to clone: try block BB%02u jumps to callfinally at BB%02u;"
23758 " the call returns to BB%02u which jumps to BB%02u\n",
23759 block->bbNum, jumpDest->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
23761 JITDUMP("Chose path to clone: try block BB%02u is a callfinally;"
23762 " the call returns to BB%02u which jumps to BB%02u\n",
23763 block->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
23764 #endif // FEATURE_EH_CALLFINALLY_THUNKS
23769 // If there is no call to the finally, don't clone.
23770 if (normalCallFinallyBlock == nullptr)
23772 JITDUMP("EH#%u: no calls from the try to the finally, skipping.\n", XTnum);
23776 JITDUMP("Will update callfinally block BB%02u to jump to the clone;"
23777 " clone will jump to BB%02u\n",
23778 normalCallFinallyBlock->bbNum, normalCallFinallyReturn->bbNum);
23780 // If there are multiple callfinallys and we're in the
23781 // callfinally thunk model, all the callfinallys are placed
23782 // just outside the try region. We'd like our chosen
23783 // callfinally to come first after the try, so we can fall out of the try
23785 BasicBlock* firstCallFinallyRangeBlock = nullptr;
23786 BasicBlock* endCallFinallyRangeBlock = nullptr;
23787 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
23789 if (tryToRelocateCallFinally)
23791 BasicBlock* firstCallFinallyBlock = nullptr;
23793 for (BasicBlock* block = firstCallFinallyRangeBlock; block != endCallFinallyRangeBlock;
23794 block = block->bbNext)
23796 if (block->isBBCallAlwaysPair())
23798 if (block->bbJumpDest == firstBlock)
23800 firstCallFinallyBlock = block;
23806 // We better have found at least one call finally.
23807 assert(firstCallFinallyBlock != nullptr);
23809 // If there is more than one callfinally, move the one we are
23810 // going to retarget to be first in the callfinally range.
23811 if (firstCallFinallyBlock != normalCallFinallyBlock)
23813 JITDUMP("Moving callfinally BB%02u to be first in line, before BB%02u\n", normalCallFinallyBlock->bbNum,
23814 firstCallFinallyBlock->bbNum);
23816 BasicBlock* const firstToMove = normalCallFinallyBlock;
23817 BasicBlock* const lastToMove = normalCallFinallyBlock->bbNext;
23818 BasicBlock* const placeToMoveAfter = firstCallFinallyBlock->bbPrev;
23820 fgUnlinkRange(firstToMove, lastToMove);
23821 fgMoveBlocksAfter(firstToMove, lastToMove, placeToMoveAfter);
23825 fgDebugCheckBBlist(false, false);
23826 fgVerifyHandlerTab();
23829 assert(nextBlock == lastBlock->bbNext);
23831 // Update where the callfinally range begins, since we might
23832 // have altered this with callfinally rearrangement, and/or
23833 // the range begin might have been pretty loose to begin with.
23834 firstCallFinallyRangeBlock = normalCallFinallyBlock;
23838 // Clone the finally and retarget the normal return path and
23839 // any other path that happens to share that same return
23840 // point. For instance a construct like:
23842 // try { } catch { } finally { }
23844 // will have two call finally blocks, one for the normal exit
23845 // from the try, and the the other for the exit from the
23846 // catch. They'll both pass the same return point which is the
23847 // statement after the finally, so they can share the clone.
23849 // Clone the finally body, and splice it into the flow graph
23850 // within in the parent region of the try.
23851 const unsigned finallyTryIndex = firstBlock->bbTryIndex;
23852 BasicBlock* insertAfter = nullptr;
23853 BlockToBlockMap blockMap(getAllocator());
23854 bool clonedOk = true;
23855 unsigned cloneBBCount = 0;
23857 for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
23859 BasicBlock* newBlock;
23861 if (block == firstBlock)
23863 // Put first cloned finally block into the approprate
23864 // region, somewhere within or after the range of
23865 // callfinallys, depending on the EH implementation.
23866 const unsigned hndIndex = 0;
23867 BasicBlock* const nearBlk = cloneInsertAfter;
23868 newBlock = fgNewBBinRegion(block->bbJumpKind, finallyTryIndex, hndIndex, nearBlk);
23870 // If the clone ends up just after the finally, adjust
23871 // the stopping point for finally traversal.
23872 if (newBlock->bbNext == nextBlock)
23874 assert(newBlock->bbPrev == lastBlock);
23875 nextBlock = newBlock;
23880 // Put subsequent blocks in the same region...
23881 const bool extendRegion = true;
23882 newBlock = fgNewBBafter(block->bbJumpKind, insertAfter, extendRegion);
23886 assert(cloneBBCount <= regionBBCount);
23888 insertAfter = newBlock;
23889 blockMap.Set(block, newBlock);
23891 clonedOk = BasicBlock::CloneBlockState(this, newBlock, block);
23898 // Update block flags. Note a block can be both first and last.
23899 if (block == firstBlock)
23901 // Mark the block as the start of the cloned finally.
23902 newBlock->bbFlags |= BBF_CLONED_FINALLY_BEGIN;
23905 if (block == lastBlock)
23907 // Mark the block as the end of the cloned finally.
23908 newBlock->bbFlags |= BBF_CLONED_FINALLY_END;
23911 // Make sure clone block state hasn't munged the try region.
23912 assert(newBlock->bbTryIndex == finallyTryIndex);
23914 // Cloned handler block is no longer within the handler.
23915 newBlock->clearHndIndex();
23917 // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them.
23918 assert(newBlock->bbJumpDest == nullptr);
23923 // TODO: cleanup the partial clone?
23924 JITDUMP("Unable to clone the finally; skipping.\n");
23928 // We should have cloned all the finally region blocks.
23929 assert(cloneBBCount == regionBBCount);
23931 JITDUMP("Cloned finally blocks are: BB%2u ... BB%2u\n", blockMap[firstBlock]->bbNum,
23932 blockMap[lastBlock]->bbNum);
23934 // Redirect redirect any branches within the newly-cloned
23935 // finally, and any finally returns to jump to the return
23937 for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
23939 BasicBlock* newBlock = blockMap[block];
23941 if (block->bbJumpKind == BBJ_EHFINALLYRET)
23943 GenTreeStmt* finallyRet = newBlock->lastStmt();
23944 GenTreePtr finallyRetExpr = finallyRet->gtStmtExpr;
23945 assert(finallyRetExpr->gtOper == GT_RETFILT);
23946 fgRemoveStmt(newBlock, finallyRet);
23947 newBlock->bbJumpKind = BBJ_ALWAYS;
23948 newBlock->bbJumpDest = normalCallFinallyReturn;
23950 fgAddRefPred(normalCallFinallyReturn, newBlock);
23954 optCopyBlkDest(block, newBlock);
23955 optRedirectBlock(newBlock, &blockMap);
23959 // Modify the targeting call finallys to branch to the cloned
23960 // finally. Make a note if we see some calls that can't be
23961 // retargeted (since they want to return to other places).
23962 BasicBlock* const firstCloneBlock = blockMap[firstBlock];
23963 bool retargetedAllCalls = true;
23964 BasicBlock* currentBlock = firstCallFinallyRangeBlock;
23966 while (currentBlock != endCallFinallyRangeBlock)
23968 BasicBlock* nextBlockToScan = currentBlock->bbNext;
23970 if (currentBlock->isBBCallAlwaysPair())
23972 if (currentBlock->bbJumpDest == firstBlock)
23974 BasicBlock* const leaveBlock = currentBlock->bbNext;
23975 BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
23977 // Note we must retarget all callfinallies that have this
23978 // continuation, or we can't clean up the continuation
23979 // block properly below, since it will be reachable both
23980 // by the cloned finally and by the called finally.
23981 if (postTryFinallyBlock == normalCallFinallyReturn)
23983 // This call returns to the expected spot, so
23984 // retarget it to branch to the clone.
23985 currentBlock->bbJumpDest = firstCloneBlock;
23986 currentBlock->bbJumpKind = BBJ_ALWAYS;
23988 // Ref count updates.
23989 fgAddRefPred(firstCloneBlock, currentBlock);
23990 // fgRemoveRefPred(firstBlock, currentBlock);
23992 // Delete the leave block, which should be marked as
23994 assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
23995 nextBlock = leaveBlock->bbNext;
23997 leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
23998 fgRemoveBlock(leaveBlock, true);
24000 // Make sure iteration isn't going off the deep end.
24001 assert(leaveBlock != endCallFinallyRangeBlock);
24005 // We can't retarget this call since it
24006 // returns somewhere else.
24007 retargetedAllCalls = false;
24012 currentBlock = nextBlockToScan;
24015 // If we retargeted all calls, modify EH descriptor to be
24016 // try-fault instead of try-finally, and then non-cloned
24017 // finally catch type to be fault.
24018 if (retargetedAllCalls)
24020 JITDUMP("All callfinallys retargeted; changing finally to fault.\n");
24021 HBtab->ebdHandlerType = EH_HANDLER_FAULT_WAS_FINALLY;
24022 firstBlock->bbCatchTyp = BBCT_FAULT;
24026 JITDUMP("Some callfinallys *not* retargeted, so region must remain as a finally.\n");
24029 // Modify first block of cloned finally to be a "normal" block.
24030 BasicBlock* firstClonedBlock = blockMap[firstBlock];
24031 firstClonedBlock->bbCatchTyp = BBCT_NONE;
24033 // Cleanup the continuation
24034 fgCleanupContinuation(normalCallFinallyReturn);
24036 // Todo -- mark cloned blocks as a cloned finally....
24039 JITDUMP("\nDone with EH#%u\n\n", XTnum);
24043 if (cloneCount > 0)
24045 JITDUMP("fgCloneFinally() cloned %u finally handlers\n", cloneCount);
24046 fgOptimizedFinally = true;
24051 printf("\n*************** After fgCloneFinally()\n");
24052 fgDispBasicBlocks();
24053 fgDispHandlerTab();
24057 fgVerifyHandlerTab();
24058 fgDebugCheckBBlist(false, false);
24059 fgDebugCheckTryFinallyExits();
24067 //------------------------------------------------------------------------
24068 // fgDebugCheckTryFinallyExits: validate normal flow from try-finally
24069 // or try-fault-was-finally.
24073 // Normal control flow exiting the try block of a try-finally must
24074 // pass through the finally. This checker attempts to verify that by
24075 // looking at the control flow graph.
24077 // Each path that exits the try of a try-finally (including try-faults
24078 // that were optimized into try-finallys by fgCloneFinally) should
24079 // thus either execute a callfinally to the associated finally or else
24080 // jump to a block with the BBF_CLONED_FINALLY_BEGIN flag set.
24082 // Depending on when this check is done, there may also be an empty
24083 // block along the path.
24085 // Depending on the model for invoking finallys, the callfinallies may
24086 // lie within the try region (callfinally thunks) or in the enclosing
24089 void Compiler::fgDebugCheckTryFinallyExits()
24091 unsigned XTnum = 0;
24092 EHblkDsc* HBtab = compHndBBtab;
24093 unsigned cloneCount = 0;
24094 bool allTryExitsValid = true;
24095 for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
24097 const EHHandlerType handlerType = HBtab->ebdHandlerType;
24098 const bool isFinally = (handlerType == EH_HANDLER_FINALLY);
24099 const bool wasFinally = (handlerType == EH_HANDLER_FAULT_WAS_FINALLY);
24101 // Screen out regions that are or were not finallys.
24102 if (!isFinally && !wasFinally)
24107 // Walk blocks of the try, looking for normal control flow to
24108 // an ancestor region.
24110 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
24111 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
24112 assert(firstTryBlock->getTryIndex() <= XTnum);
24113 assert(lastTryBlock->getTryIndex() <= XTnum);
24114 BasicBlock* const afterTryBlock = lastTryBlock->bbNext;
24115 BasicBlock* const finallyBlock = isFinally ? HBtab->ebdHndBeg : nullptr;
24117 for (BasicBlock* block = firstTryBlock; block != afterTryBlock; block = block->bbNext)
24119 // Only check the directly contained blocks.
24120 assert(block->hasTryIndex());
24122 if (block->getTryIndex() != XTnum)
24127 // Look at each of the normal control flow possibilities.
24128 const unsigned numSuccs = block->NumSucc();
24130 for (unsigned i = 0; i < numSuccs; i++)
24132 BasicBlock* const succBlock = block->GetSucc(i);
24134 if (succBlock->hasTryIndex() && succBlock->getTryIndex() <= XTnum)
24136 // Successor does not exit this try region.
24140 #if FEATURE_EH_CALLFINALLY_THUNKS
24142 // When there are callfinally thunks, callfinallies
24143 // logically "belong" to a child region and the exit
24144 // path validity will be checked when looking at the
24145 // try blocks in that region.
24146 if (block->bbJumpKind == BBJ_CALLFINALLY)
24151 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24153 // Now we know block lies directly within the try of a
24154 // try-finally, and succBlock is in an enclosing
24155 // region (possibly the method region). So this path
24156 // represents flow out of the try and should be
24159 // There are various ways control can properly leave a
24160 // try-finally (or try-fault-was-finally):
24162 // (a1) via a jump to a callfinally (only for finallys, only for call finally thunks)
24163 // (a2) via a callfinally (only for finallys, only for !call finally thunks)
24164 // (b) via a jump to a begin finally clone block
24165 // (c) via a jump to an empty block to (b)
24166 // (d) via a fallthrough to an empty block to (b)
24167 // (e) via the always half of a callfinally pair
24168 // (f) via an always jump clonefinally exit
24169 bool isCallToFinally = false;
24171 #if FEATURE_EH_CALLFINALLY_THUNKS
24172 if (succBlock->bbJumpKind == BBJ_CALLFINALLY)
24175 isCallToFinally = isFinally && (succBlock->bbJumpDest == finallyBlock);
24178 if (block->bbJumpKind == BBJ_CALLFINALLY)
24181 isCallToFinally = isFinally && (block->bbJumpDest == finallyBlock);
24183 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24185 bool isJumpToClonedFinally = false;
24187 if (succBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24190 isJumpToClonedFinally = true;
24192 else if (succBlock->bbJumpKind == BBJ_ALWAYS)
24194 if (succBlock->isEmpty())
24197 BasicBlock* const succSuccBlock = succBlock->bbJumpDest;
24199 if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24201 isJumpToClonedFinally = true;
24205 else if (succBlock->bbJumpKind == BBJ_NONE)
24207 if (succBlock->isEmpty())
24209 BasicBlock* const succSuccBlock = succBlock->bbNext;
24212 if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24214 isJumpToClonedFinally = true;
24219 bool isReturnFromFinally = false;
24221 // Case (e). Ideally we'd have something stronger to
24222 // check here -- eg that we are returning from a call
24223 // to the right finally -- but there are odd cases
24224 // like orphaned second halves of callfinally pairs
24225 // that we need to tolerate.
24226 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
24228 isReturnFromFinally = true;
24232 if (block->bbFlags & BBF_CLONED_FINALLY_END)
24234 isReturnFromFinally = true;
24237 const bool thisExitValid = isCallToFinally || isJumpToClonedFinally || isReturnFromFinally;
24239 if (!thisExitValid)
24241 JITDUMP("fgCheckTryFinallyExitS: EH#%u exit via BB%02u -> BB%02u is invalid\n", XTnum, block->bbNum,
24245 allTryExitsValid = allTryExitsValid & thisExitValid;
24250 if (!allTryExitsValid)
24252 JITDUMP("fgCheckTryFinallyExits: method contains invalid try exit paths\n");
24253 assert(allTryExitsValid);
24259 //------------------------------------------------------------------------
24260 // fgCleanupContinuation: cleanup a finally continuation after a
24261 // finally is removed or converted to normal control flow.
24264 // The continuation is the block targeted by the second half of
24265 // a callfinally/always pair.
24267 // Used by finally cloning, empty try removal, and empty
24268 // finally removal.
24270 // BBF_FINALLY_TARGET bbFlag is left unchanged by this method
24271 // since it cannot be incrementally updated. Proper updates happen
24272 // when fgUpdateFinallyTargetFlags runs after all finally optimizations.
24274 void Compiler::fgCleanupContinuation(BasicBlock* continuation)
24276 // The continuation may be a finalStep block.
24277 // It is now a normal block, so clear the special keep
24279 continuation->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
24281 #if !FEATURE_EH_FUNCLETS
24282 // Remove the GT_END_LFIN from the continuation,
24283 // Note we only expect to see one such statement.
24284 bool foundEndLFin = false;
24285 for (GenTreeStmt* stmt = continuation->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
24287 GenTreePtr expr = stmt->gtStmtExpr;
24288 if (expr->gtOper == GT_END_LFIN)
24290 assert(!foundEndLFin);
24291 fgRemoveStmt(continuation, stmt);
24292 foundEndLFin = true;
24295 assert(foundEndLFin);
24296 #endif // !FEATURE_EH_FUNCLETS
24299 //------------------------------------------------------------------------
24300 // fgUpdateFinallyTargetFlags: recompute BBF_FINALLY_TARGET bits for all blocks
24301 // after finally optimizations have run.
24303 void Compiler::fgUpdateFinallyTargetFlags()
24305 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
24307 // Any fixup required?
24308 if (!fgOptimizedFinally)
24310 JITDUMP("In fgUpdateFinallyTargetFlags - no finally opts, no fixup required\n");
24314 JITDUMP("In fgUpdateFinallyTargetFlags, updating finally target flag bits\n");
24316 // Walk all blocks, and reset the target bits.
24317 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
24319 block->bbFlags &= ~BBF_FINALLY_TARGET;
24322 // Walk all blocks again, and set the target bits.
24323 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
24325 if (block->isBBCallAlwaysPair())
24327 BasicBlock* const leave = block->bbNext;
24328 BasicBlock* const continuation = leave->bbJumpDest;
24330 if ((continuation->bbFlags & BBF_FINALLY_TARGET) == 0)
24332 JITDUMP("Found callfinally BB%02u; setting finally target bit on BB%02u\n", block->bbNum,
24333 continuation->bbNum);
24335 continuation->bbFlags |= BBF_FINALLY_TARGET;
24339 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
24342 //------------------------------------------------------------------------
24343 // fgMergeFinallyChains: tail merge finally invocations
24347 // Looks for common suffixes in chains of finally invocations
24348 // (callfinallys) and merges them. These typically arise from
24349 // try-finallys where there are multiple exit points in the try
24350 // that have the same target.
24352 void Compiler::fgMergeFinallyChains()
24354 JITDUMP("\n*************** In fgMergeFinallyChains()\n");
24356 #if FEATURE_EH_FUNCLETS
24357 // We need to do this transformation before funclets are created.
24358 assert(!fgFuncletsCreated);
24359 #endif // FEATURE_EH_FUNCLETS
24361 // Assume we don't need to update the bbPreds lists.
24362 assert(!fgComputePredsDone);
24364 if (compHndBBtabCount == 0)
24366 JITDUMP("No EH in this method, nothing to merge.\n");
24370 if (opts.MinOpts())
24372 JITDUMP("Method compiled with minOpts, no merging.\n");
24376 if (opts.compDbgCode)
24378 JITDUMP("Method compiled with debug codegen, no merging.\n");
24382 bool enableMergeFinallyChains = true;
24384 #if !FEATURE_EH_FUNCLETS
24385 // For non-funclet models (x86) the callfinallys may contain
24386 // statements and the continuations contain GT_END_LFINs. So no
24387 // merging is possible until the GT_END_LFIN blocks can be merged
24388 // and merging is not safe unless the callfinally blocks are split.
24389 JITDUMP("EH using non-funclet model; merging not yet implemented.\n");
24390 enableMergeFinallyChains = false;
24391 #endif // !FEATURE_EH_FUNCLETS
24393 #if !FEATURE_EH_CALLFINALLY_THUNKS
24394 // For non-thunk EH models (arm32) the callfinallys may contain
24395 // statements, and merging is not safe unless the callfinally
24396 // blocks are split.
24397 JITDUMP("EH using non-callfinally thunk model; merging not yet implemented.\n");
24398 enableMergeFinallyChains = false;
24401 if (!enableMergeFinallyChains)
24403 JITDUMP("fgMergeFinallyChains disabled\n");
24410 printf("\n*************** Before fgMergeFinallyChains()\n");
24411 fgDispBasicBlocks();
24412 fgDispHandlerTab();
24417 // Look for finallys.
24418 bool hasFinally = false;
24419 for (unsigned XTnum = 0; XTnum < compHndBBtabCount; XTnum++)
24421 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
24423 // Check if this is a try/finally.
24424 if (HBtab->HasFinallyHandler())
24433 JITDUMP("Method does not have any try-finallys; no merging.\n");
24437 // Process finallys from outside in, merging as we go. This gives
24438 // us the desired bottom-up tail merge order for callfinally
24439 // chains: outer merges may enable inner merges.
24440 bool canMerge = false;
24441 bool didMerge = false;
24442 BlockToBlockMap continuationMap(getAllocator());
24444 // Note XTnum is signed here so we can count down.
24445 for (int XTnum = compHndBBtabCount - 1; XTnum >= 0; XTnum--)
24447 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
24449 // Screen out non-finallys
24450 if (!HBtab->HasFinallyHandler())
24455 JITDUMP("Examining callfinallys for EH#%d.\n", XTnum);
24457 // Find all the callfinallys that invoke this finally.
24458 BasicBlock* firstCallFinallyRangeBlock = nullptr;
24459 BasicBlock* endCallFinallyRangeBlock = nullptr;
24460 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
24462 // Clear out any stale entries in the continuation map
24463 continuationMap.RemoveAll();
24465 // Build a map from each continuation to the "canonical"
24466 // callfinally for that continuation.
24467 unsigned callFinallyCount = 0;
24468 BasicBlock* const beginHandlerBlock = HBtab->ebdHndBeg;
24470 for (BasicBlock* currentBlock = firstCallFinallyRangeBlock; currentBlock != endCallFinallyRangeBlock;
24471 currentBlock = currentBlock->bbNext)
24473 // Ignore "retless" callfinallys (where the finally doesn't return).
24474 if (currentBlock->isBBCallAlwaysPair() && (currentBlock->bbJumpDest == beginHandlerBlock))
24476 // The callfinally must be empty, so that we can
24477 // safely retarget anything that branches here to
24478 // another callfinally with the same contiuation.
24479 assert(currentBlock->isEmpty());
24481 // This callfinally invokes the finally for this try.
24482 callFinallyCount++;
24484 // Locate the continuation
24485 BasicBlock* const leaveBlock = currentBlock->bbNext;
24486 BasicBlock* const continuationBlock = leaveBlock->bbJumpDest;
24488 // If this is the first time we've seen this
24489 // continuation, register this callfinally as the
24491 if (!continuationMap.Lookup(continuationBlock))
24493 continuationMap.Set(continuationBlock, currentBlock);
24498 // Now we've seen all the callfinallys and their continuations.
24499 JITDUMP("EH#%i has %u callfinallys, %u continuations\n", XTnum, callFinallyCount, continuationMap.GetCount());
24501 // If there are more callfinallys than continuations, some of the
24502 // callfinallys must share a continuation, and we can merge them.
24503 const bool tryMerge = callFinallyCount > continuationMap.GetCount();
24507 JITDUMP("EH#%i does not have any mergeable callfinallys\n", XTnum);
24513 // Walk the callfinally region, looking for blocks that jump
24514 // to a callfinally that invokes this try's finally, and make
24515 // sure they all jump to the appropriate canonical
24517 for (BasicBlock* currentBlock = firstCallFinallyRangeBlock; currentBlock != endCallFinallyRangeBlock;
24518 currentBlock = currentBlock->bbNext)
24520 bool merged = fgRetargetBranchesToCanonicalCallFinally(currentBlock, beginHandlerBlock, continuationMap);
24521 didMerge = didMerge || merged;
24527 JITDUMP("Method had try-finallys, but did not have any mergeable finally chains.\n");
24533 JITDUMP("Method had mergeable try-finallys and some callfinally merges were performed.\n");
24538 printf("\n*************** After fgMergeFinallyChains()\n");
24539 fgDispBasicBlocks();
24540 fgDispHandlerTab();
24548 // We may not end up doing any merges, because we are only
24549 // merging continuations for callfinallys that can
24550 // actually be invoked, and the importer may leave
24551 // unreachable callfinallys around (for instance, if it
24552 // is forced to re-import a leave).
24553 JITDUMP("Method had mergeable try-finallys but no callfinally merges were performed,\n"
24554 "likely the non-canonical callfinallys were unreachable\n");
24559 //------------------------------------------------------------------------
24560 // fgRetargetBranchesToCanonicalCallFinally: find non-canonical callfinally
24561 // invocations and make them canonical.
24564 // block -- block to examine for call finally invocation
24565 // handler -- start of the finally region for the try
24566 // continuationMap -- map giving the canonical callfinally for
24567 // each continuation
24570 // true iff the block's branch was retargeted.
24572 bool Compiler::fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
24573 BasicBlock* handler,
24574 BlockToBlockMap& continuationMap)
24576 // We expect callfinallys to be invoked by a BBJ_ALWAYS at this
24577 // stage in compilation.
24578 if (block->bbJumpKind != BBJ_ALWAYS)
24580 // Possible paranoia assert here -- no flow successor of
24581 // this block should be a callfinally for this try.
24585 // Screen out cases that are not callfinallys to the right
24587 BasicBlock* const callFinally = block->bbJumpDest;
24589 if (!callFinally->isBBCallAlwaysPair())
24594 if (callFinally->bbJumpDest != handler)
24599 // Ok, this is a callfinally that invokes the right handler.
24600 // Get its continuation.
24601 BasicBlock* const leaveBlock = callFinally->bbNext;
24602 BasicBlock* const continuationBlock = leaveBlock->bbJumpDest;
24604 // Find the canonical callfinally for that continuation.
24605 BasicBlock* const canonicalCallFinally = continuationMap[continuationBlock];
24606 assert(canonicalCallFinally != nullptr);
24608 // If the block already jumps to the canoncial call finally, no work needed.
24609 if (block->bbJumpDest == canonicalCallFinally)
24611 JITDUMP("BB%02u already canonical\n", block->bbNum);
24615 // Else, retarget it so that it does...
24616 JITDUMP("Redirecting branch in BB%02u from BB%02u to BB%02u.\n", block->bbNum, callFinally->bbNum,
24617 canonicalCallFinally->bbNum);
24619 block->bbJumpDest = canonicalCallFinally;
24620 fgAddRefPred(canonicalCallFinally, block);
24621 assert(callFinally->bbRefs > 0);
24622 fgRemoveRefPred(callFinally, block);
24627 // FatCalliTransformer transforms calli that can use fat function pointer.
24628 // Fat function pointer is pointer with the second least significant bit set,
24629 // if the bit is set, the pointer (after clearing the bit) actually points to
24630 // a tuple <method pointer, instantiation argument pointer> where
24631 // instantiationArgument is a hidden first argument required by method pointer.
24633 // Fat pointers are used in CoreRT as a replacement for instantiating stubs,
24634 // because CoreRT can't generate stubs in runtime.
24636 // Jit is responsible for the checking the bit, do the regular call if it is not set
24637 // or load hidden argument, fix the pointer and make a call with the fixed pointer and
24638 // the instantiation argument.
24643 // previous statements
24644 // transforming statement
24646 // call with GTF_CALL_M_FAT_POINTER_CHECK flag set in function ptr
24648 // subsequent statements
24654 // previous statements
24655 // } BBJ_NONE check block
24658 // jump to else if function ptr has GTF_CALL_M_FAT_POINTER_CHECK set.
24659 // } BBJ_COND then block, else block
24662 // original statement
24663 // } BBJ_ALWAYS remainder block
24666 // unset GTF_CALL_M_FAT_POINTER_CHECK
24667 // load actual function pointer
24668 // load instantiation argument
24669 // create newArgList = (instantiation argument, original argList)
24670 // call (actual function pointer, newArgList)
24671 // } BBJ_NONE remainder block
24674 // subsequent statements
24677 class FatCalliTransformer
24680 FatCalliTransformer(Compiler* compiler) : compiler(compiler)
24684 //------------------------------------------------------------------------
24685 // Run: run transformation for each block.
24689 for (BasicBlock* block = compiler->fgFirstBB; block != nullptr; block = block->bbNext)
24691 TransformBlock(block);
24696 //------------------------------------------------------------------------
24697 // TransformBlock: look through statements and transform statements with fat pointer calls.
24699 void TransformBlock(BasicBlock* block)
24701 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
24703 if (ContainsFatCalli(stmt))
24705 StatementTransformer stmtTransformer(compiler, block, stmt);
24706 stmtTransformer.Run();
24711 //------------------------------------------------------------------------
24712 // ContainsFatCalli: check does this statement contain fat pointer call.
24714 // Checks fatPointerCandidate in form of call() or lclVar = call().
24717 // true if contains, false otherwise.
24719 bool ContainsFatCalli(GenTreeStmt* stmt)
24721 GenTreePtr fatPointerCandidate = stmt->gtStmtExpr;
24722 if (fatPointerCandidate->OperIsAssignment())
24724 fatPointerCandidate = fatPointerCandidate->gtGetOp2();
24726 return fatPointerCandidate->IsCall() && fatPointerCandidate->AsCall()->IsFatPointerCandidate();
24729 class StatementTransformer
24732 StatementTransformer(Compiler* compiler, BasicBlock* block, GenTreeStmt* stmt)
24733 : compiler(compiler), currBlock(block), stmt(stmt)
24735 remainderBlock = nullptr;
24736 checkBlock = nullptr;
24737 thenBlock = nullptr;
24738 elseBlock = nullptr;
24739 doesReturnValue = stmt->gtStmtExpr->OperIsAssignment();
24740 origCall = GetCall(stmt);
24741 fptrAddress = origCall->gtCallAddr;
24742 pointerType = fptrAddress->TypeGet();
24745 //------------------------------------------------------------------------
24746 // Run: transform the statement as described above.
24756 RemoveOldStatement();
24762 //------------------------------------------------------------------------
24763 // GetCall: find a call in a statement.
24766 // callStmt - the statement with the call inside.
24769 // call tree node pointer.
24770 GenTreeCall* GetCall(GenTreeStmt* callStmt)
24772 GenTreePtr tree = callStmt->gtStmtExpr;
24773 GenTreeCall* call = nullptr;
24774 if (doesReturnValue)
24776 assert(tree->OperIsAssignment());
24777 call = tree->gtGetOp2()->AsCall();
24781 call = tree->AsCall(); // call with void return type.
24786 //------------------------------------------------------------------------
24787 // ClearFatFlag: clear fat pointer candidate flag from the original call.
24789 void ClearFatFlag()
24791 origCall->ClearFatPointerCandidate();
24794 //------------------------------------------------------------------------
24795 // CreateRemainder: split current block at the fat call stmt and
24796 // insert statements after the call into remainderBlock.
24798 void CreateRemainder()
24800 remainderBlock = compiler->fgSplitBlockAfterStatement(currBlock, stmt);
24801 unsigned propagateFlags = currBlock->bbFlags & BBF_GC_SAFE_POINT;
24802 remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | propagateFlags;
24805 //------------------------------------------------------------------------
24806 // CreateCheck: create check block, that checks fat pointer bit set.
24810 checkBlock = CreateAndInsertBasicBlock(BBJ_COND, currBlock);
24811 GenTreePtr fatPointerMask = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, FAT_POINTER_MASK);
24812 GenTreePtr fptrAddressCopy = compiler->gtCloneExpr(fptrAddress);
24813 GenTreePtr fatPointerAnd = compiler->gtNewOperNode(GT_AND, TYP_I_IMPL, fptrAddressCopy, fatPointerMask);
24814 GenTreePtr zero = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, 0);
24815 GenTreePtr fatPointerCmp = compiler->gtNewOperNode(GT_NE, TYP_INT, fatPointerAnd, zero);
24816 GenTreePtr jmpTree = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, fatPointerCmp);
24817 GenTreePtr jmpStmt = compiler->fgNewStmtFromTree(jmpTree, stmt->gtStmt.gtStmtILoffsx);
24818 compiler->fgInsertStmtAtEnd(checkBlock, jmpStmt);
24821 //------------------------------------------------------------------------
24822 // CreateCheck: create then block, that is executed if call address is not fat pointer.
24826 thenBlock = CreateAndInsertBasicBlock(BBJ_ALWAYS, checkBlock);
24827 GenTreePtr nonFatCallStmt = compiler->gtCloneExpr(stmt)->AsStmt();
24828 compiler->fgInsertStmtAtEnd(thenBlock, nonFatCallStmt);
24831 //------------------------------------------------------------------------
24832 // CreateCheck: create else block, that is executed if call address is fat pointer.
24836 elseBlock = CreateAndInsertBasicBlock(BBJ_NONE, thenBlock);
24838 GenTreePtr fixedFptrAddress = GetFixedFptrAddress();
24839 GenTreePtr actualCallAddress = compiler->gtNewOperNode(GT_IND, pointerType, fixedFptrAddress);
24840 GenTreePtr hiddenArgument = GetHiddenArgument(fixedFptrAddress);
24842 GenTreeStmt* fatStmt = CreateFatCallStmt(actualCallAddress, hiddenArgument);
24843 compiler->fgInsertStmtAtEnd(elseBlock, fatStmt);
24846 //------------------------------------------------------------------------
24847 // CreateAndInsertBasicBlock: ask compiler to create new basic block.
24848 // and insert in into the basic block list.
24851 // jumpKind - jump kind for the new basic block
24852 // insertAfter - basic block, after which compiler has to insert the new one.
24855 // new basic block.
24856 BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter)
24858 BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true);
24859 if ((insertAfter->bbFlags & BBF_INTERNAL) == 0)
24861 block->bbFlags &= ~BBF_INTERNAL;
24862 block->bbFlags |= BBF_IMPORTED;
24867 //------------------------------------------------------------------------
24868 // GetFixedFptrAddress: clear fat pointer bit from fat pointer address.
24871 // address without fat pointer bit set.
24872 GenTreePtr GetFixedFptrAddress()
24874 GenTreePtr fptrAddressCopy = compiler->gtCloneExpr(fptrAddress);
24875 GenTreePtr fatPointerMask = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, FAT_POINTER_MASK);
24876 return compiler->gtNewOperNode(GT_XOR, pointerType, fptrAddressCopy, fatPointerMask);
24879 //------------------------------------------------------------------------
24880 // GetHiddenArgument: load hidden argument.
24883 // fixedFptrAddress - pointer to the tuple <methodPointer, instantiationArgumentPointer>
24886 // generic context hidden argument.
24887 GenTreePtr GetHiddenArgument(GenTreePtr fixedFptrAddress)
24889 GenTreePtr fixedFptrAddressCopy = compiler->gtCloneExpr(fixedFptrAddress);
24890 GenTreePtr wordSize = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, genTypeSize(TYP_I_IMPL));
24891 GenTreePtr hiddenArgumentPtrPtr =
24892 compiler->gtNewOperNode(GT_ADD, pointerType, fixedFptrAddressCopy, wordSize);
24893 GenTreePtr hiddenArgumentPtr = compiler->gtNewOperNode(GT_IND, pointerType, hiddenArgumentPtrPtr);
24894 return compiler->gtNewOperNode(GT_IND, fixedFptrAddressCopy->TypeGet(), hiddenArgumentPtr);
24897 //------------------------------------------------------------------------
24898 // CreateFatCallStmt: create call with fixed call address and hidden argument in the args list.
24901 // actualCallAddress - fixed call address
24902 // hiddenArgument - generic context hidden argument
24905 // created call node.
24906 GenTreeStmt* CreateFatCallStmt(GenTreePtr actualCallAddress, GenTreePtr hiddenArgument)
24908 GenTreeStmt* fatStmt = compiler->gtCloneExpr(stmt)->AsStmt();
24909 GenTreePtr fatTree = fatStmt->gtStmtExpr;
24910 GenTreeCall* fatCall = GetCall(fatStmt);
24911 fatCall->gtCallAddr = actualCallAddress;
24912 AddHiddenArgument(fatCall, hiddenArgument);
24916 //------------------------------------------------------------------------
24917 // AddHiddenArgument: add hidden argument to the call argument list.
24920 // fatCall - fat call node
24921 // hiddenArgument - generic context hidden argument
24923 void AddHiddenArgument(GenTreeCall* fatCall, GenTreePtr hiddenArgument)
24925 GenTreeArgList* oldArgs = fatCall->gtCallArgs;
24926 GenTreeArgList* newArgs;
24927 #if USER_ARGS_COME_LAST
24928 if (fatCall->HasRetBufArg())
24930 GenTreePtr retBuffer = oldArgs->Current();
24931 GenTreeArgList* rest = oldArgs->Rest();
24932 newArgs = compiler->gtNewListNode(hiddenArgument, rest);
24933 newArgs = compiler->gtNewListNode(retBuffer, newArgs);
24937 newArgs = compiler->gtNewListNode(hiddenArgument, oldArgs);
24941 AddArgumentToTail(newArgs, hiddenArgument);
24943 fatCall->gtCallArgs = newArgs;
24946 //------------------------------------------------------------------------
24947 // AddArgumentToTail: add hidden argument to the tail of the call argument list.
24950 // argList - fat call node
24951 // hiddenArgument - generic context hidden argument
24953 void AddArgumentToTail(GenTreeArgList* argList, GenTreePtr hiddenArgument)
24955 GenTreeArgList* iterator = argList;
24956 while (iterator->Rest() != nullptr)
24958 iterator = iterator->Rest();
24960 iterator->Rest() = compiler->gtNewArgList(hiddenArgument);
24963 //------------------------------------------------------------------------
24964 // RemoveOldStatement: remove original stmt from current block.
24966 void RemoveOldStatement()
24968 compiler->fgRemoveStmt(currBlock, stmt);
24971 //------------------------------------------------------------------------
24972 // SetWeights: set weights for new blocks.
24976 remainderBlock->inheritWeight(currBlock);
24977 checkBlock->inheritWeight(currBlock);
24978 thenBlock->inheritWeightPercentage(currBlock, HIGH_PROBABILITY);
24979 elseBlock->inheritWeightPercentage(currBlock, 100 - HIGH_PROBABILITY);
24982 //------------------------------------------------------------------------
24983 // ChainFlow: link new blocks into correct cfg.
24987 assert(!compiler->fgComputePredsDone);
24988 checkBlock->bbJumpDest = elseBlock;
24989 thenBlock->bbJumpDest = remainderBlock;
24992 Compiler* compiler;
24993 BasicBlock* currBlock;
24994 BasicBlock* remainderBlock;
24995 BasicBlock* checkBlock;
24996 BasicBlock* thenBlock;
24997 BasicBlock* elseBlock;
24999 GenTreeCall* origCall;
25000 GenTreePtr fptrAddress;
25001 var_types pointerType;
25002 bool doesReturnValue;
25004 const int FAT_POINTER_MASK = 0x2;
25005 const int HIGH_PROBABILITY = 80;
25008 Compiler* compiler;
25013 //------------------------------------------------------------------------
25014 // fgDebugCheckFatPointerCandidates: callback to make sure there are no more GTF_CALL_M_FAT_POINTER_CHECK calls.
25016 Compiler::fgWalkResult Compiler::fgDebugCheckFatPointerCandidates(GenTreePtr* pTree, fgWalkData* data)
25018 GenTreePtr tree = *pTree;
25019 if (tree->IsCall())
25021 assert(!tree->AsCall()->IsFatPointerCandidate());
25023 return WALK_CONTINUE;
25026 //------------------------------------------------------------------------
25027 // CheckNoFatPointerCandidatesLeft: walk through blocks and check that there are no fat pointer candidates left.
25029 void Compiler::CheckNoFatPointerCandidatesLeft()
25031 assert(!doesMethodHaveFatPointer());
25032 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25034 for (GenTreeStmt* stmt = fgFirstBB->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
25036 fgWalkTreePre(&stmt->gtStmtExpr, fgDebugCheckFatPointerCandidates);
25042 //------------------------------------------------------------------------
25043 // fgTransformFatCalli: find and transform fat calls.
25045 void Compiler::fgTransformFatCalli()
25047 assert(IsTargetAbi(CORINFO_CORERT_ABI));
25048 FatCalliTransformer fatCalliTransformer(this);
25049 fatCalliTransformer.Run();
25050 clearMethodHasFatPointer();
25052 CheckNoFatPointerCandidatesLeft();
25056 //------------------------------------------------------------------------
25057 // fgMeasureIR: count and return the number of IR nodes in the function.
25059 unsigned Compiler::fgMeasureIR()
25061 unsigned nodeCount = 0;
25063 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25065 if (!block->IsLIR())
25067 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
25069 fgWalkTreePre(&stmt->gtStmtExpr,
25070 [](GenTree** slot, fgWalkData* data) -> Compiler::fgWalkResult {
25071 (*reinterpret_cast<unsigned*>(data->pCallbackData))++;
25072 return Compiler::WALK_CONTINUE;
25079 for (GenTree* node : LIR::AsRange(block))
25089 //------------------------------------------------------------------------
25090 // fgCompDominatedByExceptionalEntryBlocks: compute blocks that are
25091 // dominated by not normal entry.
25093 void Compiler::fgCompDominatedByExceptionalEntryBlocks()
25095 assert(fgEnterBlksSetValid);
25096 if (BlockSetOps::Count(this, fgEnterBlks) != 1) // There are exception entries.
25098 for (unsigned i = 1; i <= fgBBNumMax; ++i)
25100 BasicBlock* block = fgBBInvPostOrder[i];
25101 if (BlockSetOps::IsMember(this, fgEnterBlks, block->bbNum))
25103 if (fgFirstBB != block) // skip the normal entry.
25105 block->SetDominatedByExceptionalEntryFlag();
25108 else if (block->bbIDom->IsDominatedByExceptionalEntryFlag())
25110 block->SetDominatedByExceptionalEntryFlag();