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
20 #ifndef LEGACY_BACKEND
21 #include "lower.h" // for LowerRange()
24 /*****************************************************************************/
26 void Compiler::fgInit()
30 /* Initialization for fgWalkTreePre() and fgWalkTreePost() */
32 fgFirstBBScratch = nullptr;
35 fgPrintInlinedMethods = JitConfig.JitPrintInlinedMethods() == 1;
38 /* We haven't yet computed the bbPreds lists */
39 fgComputePredsDone = false;
41 /* We haven't yet computed the bbCheapPreds lists */
42 fgCheapPredsValid = false;
44 /* We haven't yet computed the edge weight */
45 fgEdgeWeightsComputed = false;
46 fgHaveValidEdgeWeights = false;
47 fgSlopUsedInEdgeWeights = false;
48 fgRangeUsedInEdgeWeights = true;
49 fgNeedsUpdateFlowGraph = false;
50 fgCalledCount = BB_ZERO_WEIGHT;
52 /* We haven't yet computed the dominator sets */
53 fgDomsComputed = false;
56 fgReachabilitySetsValid = false;
59 /* We don't know yet which loops will always execute calls */
60 fgLoopCallMarked = false;
62 /* We haven't created GC Poll blocks yet. */
63 fgGCPollsCreated = false;
65 /* Initialize the basic block list */
69 fgFirstColdBlock = nullptr;
71 #if FEATURE_EH_FUNCLETS
72 fgFirstFuncletBB = nullptr;
73 fgFuncletsCreated = false;
74 #endif // FEATURE_EH_FUNCLETS
79 fgBBcountAtCodegen = 0;
85 fgBBVarSetsInited = false;
88 // Initialize BlockSet data.
91 fgBBSetCountInSizeTUnits = 0;
93 genReturnBB = nullptr;
95 /* We haven't reached the global morphing phase */
96 fgGlobalMorph = false;
100 fgSafeBasicBlockCreation = true;
103 fgLocalVarLivenessDone = false;
105 /* Statement list is not threaded yet */
107 fgStmtListThreaded = false;
109 // Initialize the logic for adding code. This is used to insert code such
110 // as the code that raises an exception when an array range check fails.
112 fgAddCodeList = nullptr;
113 fgAddCodeModf = false;
115 for (int i = 0; i < SCK_COUNT; i++)
117 fgExcptnTargetCache[i] = nullptr;
120 /* Keep track of the max count of pointer arguments */
125 /* This global flag is set whenever we remove a statement */
126 fgStmtRemoved = false;
128 /* This global flag is set whenever we add a throw block for a RngChk */
129 fgRngChkThrowAdded = false; /* reset flag for fgIsCodeAdded() */
133 /* We will record a list of all BBJ_RETURN blocks here */
134 fgReturnBlocks = nullptr;
136 /* This is set by fgComputeReachability */
137 fgEnterBlks = BlockSetOps::UninitVal();
140 fgEnterBlksSetValid = false;
143 #if !FEATURE_EH_FUNCLETS
144 ehMaxHndNestingCount = 0;
145 #endif // !FEATURE_EH_FUNCLETS
147 /* Init the fgBigOffsetMorphingTemps to be BAD_VAR_NUM. */
148 for (int i = 0; i < TYP_COUNT; i++)
150 fgBigOffsetMorphingTemps[i] = BAD_VAR_NUM;
153 fgNoStructPromotion = false;
154 fgNoStructParamPromotion = false;
156 optValnumCSE_phase = false; // referenced in fgMorphSmpOp()
159 fgNormalizeEHDone = false;
163 if (!compIsForInlining())
165 if ((JitConfig.JitNoStructPromotion() & 1) == 1)
167 fgNoStructPromotion = true;
169 if ((JitConfig.JitNoStructPromotion() & 2) == 2)
171 fgNoStructParamPromotion = true;
176 if (!compIsForInlining())
178 m_promotedStructDeathVars = nullptr;
181 fgPreviousCandidateSIMDFieldAsgStmt = nullptr;
185 bool Compiler::fgHaveProfileData()
187 if (compIsForInlining() || compIsForImportOnly())
192 return (fgProfileBuffer != nullptr);
195 bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weightWB)
197 noway_assert(weightWB != nullptr);
201 unsigned hashSeed = fgStressBBProf();
204 unsigned hash = (info.compMethodHash() * hashSeed) ^ (offset * 1027);
206 // We need to especially stress the procedure splitting codepath. Therefore
207 // one third the time we should return a weight of zero.
208 // Otherwise we should return some random weight (usually between 0 and 288).
209 // The below gives a weight of zero, 44% of the time
215 else if (hash % 11 == 0)
217 weight = (hash % 23) * (hash % 29) * (hash % 31);
221 weight = (hash % 17) * (hash % 19);
224 // The first block is never given a weight of zero
225 if ((offset == 0) && (weight == 0))
227 weight = 1 + (hash % 5);
235 if (fgHaveProfileData() == false)
240 noway_assert(!compIsForInlining());
241 for (unsigned i = 0; i < fgProfileBufferCount; i++)
243 if (fgProfileBuffer[i].ILOffset == offset)
245 weight = fgProfileBuffer[i].ExecutionCount;
256 void Compiler::fgInstrumentMethod()
258 noway_assert(!compIsForInlining());
260 // Count the number of basic blocks in the method
262 int countOfBlocks = 0;
264 for (block = fgFirstBB; (block != nullptr); block = block->bbNext)
266 if (!(block->bbFlags & BBF_IMPORTED) || (block->bbFlags & BBF_INTERNAL))
273 // Allocate the profile buffer
275 ICorJitInfo::ProfileBuffer* bbProfileBufferStart;
277 HRESULT res = info.compCompHnd->allocBBProfileBuffer(countOfBlocks, &bbProfileBufferStart);
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 GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
291 stmt = gtNewStmt(call);
295 noway_assert(!"Error: failed to allocate bbProfileBuffer");
301 // For each BasicBlock (non-Internal)
302 // 1. Assign the blocks bbCodeOffs to the ILOffset field of this blocks profile data.
303 // 2. Add an operation that increments the ExecutionCount field at the beginning of the block.
305 // Each (non-Internal) block has it own ProfileBuffer tuple [ILOffset, ExecutionCount]
306 // To start we initialize our current one with the first one that we allocated
308 ICorJitInfo::ProfileBuffer* bbCurrentBlockProfileBuffer = bbProfileBufferStart;
310 for (block = fgFirstBB; (block != nullptr); block = block->bbNext)
312 if (!(block->bbFlags & BBF_IMPORTED) || (block->bbFlags & BBF_INTERNAL))
317 // Assign the current block's IL offset into the profile data
318 bbCurrentBlockProfileBuffer->ILOffset = block->bbCodeOffs;
319 assert(bbCurrentBlockProfileBuffer->ExecutionCount == 0); // This value should already be zero-ed out
321 size_t addrOfCurrentExecutionCount = (size_t)&bbCurrentBlockProfileBuffer->ExecutionCount;
323 // Read Basic-Block count value
325 gtNewIndOfIconHandleNode(TYP_INT, addrOfCurrentExecutionCount, GTF_ICON_BBC_PTR, false);
327 // Increment value by 1
328 GenTree* rhsNode = gtNewOperNode(GT_ADD, TYP_INT, valueNode, gtNewIconNode(1));
330 // Write new Basic-Block count value
331 GenTree* lhsNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfCurrentExecutionCount, GTF_ICON_BBC_PTR, false);
332 GenTree* asgNode = gtNewAssignNode(lhsNode, rhsNode);
334 fgInsertStmtAtBeg(block, asgNode);
336 // Advance to the next ProfileBuffer tuple [ILOffset, ExecutionCount]
337 bbCurrentBlockProfileBuffer++;
342 // Check that we allocated and initialized the same number of ProfileBuffer tuples
343 noway_assert(countOfBlocks == 0);
345 // Add the method entry callback node
349 #ifdef FEATURE_READYTORUN_COMPILER
350 if (opts.IsReadyToRun())
352 mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd);
354 CORINFO_RESOLVED_TOKEN resolvedToken;
355 resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd);
356 resolvedToken.tokenScope = info.compScopeHnd;
357 resolvedToken.token = currentMethodToken;
358 resolvedToken.tokenType = CORINFO_TOKENKIND_Method;
360 info.compCompHnd->resolveToken(&resolvedToken);
362 arg = impTokenToHandle(&resolvedToken);
367 arg = gtNewIconEmbMethHndNode(info.compMethodHnd);
370 GenTreeArgList* args = gtNewArgList(arg);
371 GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
373 // Get the address of the first blocks ExecutionCount
374 size_t addrOfFirstExecutionCount = (size_t)&bbProfileBufferStart->ExecutionCount;
376 // Read Basic-Block count value
377 GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false);
379 // Compare Basic-Block count value against zero
380 GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT));
381 relop->gtFlags |= GTF_RELOP_QMARK; // TODO-Cleanup: [Simple] Move this to gtNewQmarkNode
382 GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call);
383 GenTree* cond = gtNewQmarkNode(TYP_VOID, relop, colon);
384 stmt = gtNewStmt(cond);
387 fgEnsureFirstBBisScratch();
389 fgInsertStmtAtEnd(fgFirstBB, stmt);
392 /*****************************************************************************
394 * Create a basic block and append it to the current BB list.
397 BasicBlock* Compiler::fgNewBasicBlock(BBjumpKinds jumpKind)
399 // This method must not be called after the exception table has been
400 // constructed, because it doesn't not provide support for patching
401 // the exception table.
403 noway_assert(compHndBBtabCount == 0);
407 /* Allocate the block descriptor */
409 block = bbNewBasicBlock(jumpKind);
410 noway_assert(block->bbJumpKind == jumpKind);
412 /* Append the block to the end of the global basic block list */
416 fgLastBB->setNext(block);
421 block->bbPrev = nullptr;
429 /*****************************************************************************
431 * Ensures that fgFirstBB is a scratch BasicBlock that we have added.
432 * This can be used to add initialization code (without worrying
433 * about other blocks jumping to it).
435 * Callers have to be careful that they do not mess up the order of things
436 * added to fgEnsureFirstBBisScratch in a way as to change semantics.
439 void Compiler::fgEnsureFirstBBisScratch()
441 // This method does not update predecessor lists and so must only be called before they are computed.
442 assert(!fgComputePredsDone);
444 // Have we already allocated a scratch block?
446 if (fgFirstBBisScratch())
451 assert(fgFirstBBScratch == nullptr);
453 BasicBlock* block = bbNewBasicBlock(BBJ_NONE);
455 if (fgFirstBB != nullptr)
457 // If we have profile data the new block will inherit fgFirstBlock's weight
458 if (fgFirstBB->hasProfileWeight())
460 block->inheritWeight(fgFirstBB);
463 fgInsertBBbefore(fgFirstBB, block);
467 noway_assert(fgLastBB == nullptr);
472 noway_assert(fgLastBB != nullptr);
474 block->bbFlags |= (BBF_INTERNAL | BBF_IMPORTED);
476 fgFirstBBScratch = fgFirstBB;
481 printf("New scratch BB%02u\n", block->bbNum);
486 bool Compiler::fgFirstBBisScratch()
488 if (fgFirstBBScratch != nullptr)
490 assert(fgFirstBBScratch == fgFirstBB);
491 assert(fgFirstBBScratch->bbFlags & BBF_INTERNAL);
492 assert(fgFirstBBScratch->countOfInEdges() == 1);
494 // Normally, the first scratch block is a fall-through block. However, if the block after it was an empty
495 // BBJ_ALWAYS block, it might get removed, and the code that removes it will make the first scratch block
496 // a BBJ_ALWAYS block.
497 assert((fgFirstBBScratch->bbJumpKind == BBJ_NONE) || (fgFirstBBScratch->bbJumpKind == BBJ_ALWAYS));
507 bool Compiler::fgBBisScratch(BasicBlock* block)
509 return fgFirstBBisScratch() && (block == fgFirstBB);
513 // Check to see if block contains a statement but don't spend more than a certain
514 // budget doing this per method compiled.
515 // If the budget is exceeded, return 'answerOnBoundExceeded' as the answer.
517 bool Compiler::fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded /*= true*/)
519 const __int64 maxLinks = 1000000000;
521 assert(stmt->gtOper == GT_STMT);
523 __int64* numTraversed = &JitTls::GetCompiler()->compNumStatementLinksTraversed;
525 if (*numTraversed > maxLinks)
527 return answerOnBoundExceeded;
530 GenTree* curr = block->firstStmt();
540 return curr != nullptr;
544 //------------------------------------------------------------------------
545 // fgInsertStmtAtBeg: Insert the given tree or statement at the start of the given basic block.
548 // block - The block into which 'stmt' will be inserted.
549 // stmt - The statement to be inserted.
552 // Returns the new (potentially) GT_STMT node.
555 // If 'stmt' is not already a statement, a new statement is created from it.
556 // We always insert phi statements at the beginning.
557 // In other cases, if there are any phi assignments and/or an assignment of
558 // the GT_CATCH_ARG, we insert after those.
560 GenTree* Compiler::fgInsertStmtAtBeg(BasicBlock* block, GenTree* stmt)
562 if (stmt->gtOper != GT_STMT)
564 stmt = gtNewStmt(stmt);
567 GenTree* list = block->firstStmt();
569 if (!stmt->IsPhiDefnStmt())
571 GenTree* insertBeforeStmt = block->FirstNonPhiDefOrCatchArgAsg();
572 if (insertBeforeStmt != nullptr)
574 return fgInsertStmtBefore(block, insertBeforeStmt, stmt);
576 else if (list != nullptr)
578 return fgInsertStmtAtEnd(block, stmt);
580 // Otherwise, we will simply insert at the beginning, below.
583 /* The new tree will now be the first one of the block */
585 block->bbTreeList = stmt;
588 /* Are there any statements in the block? */
594 /* There is at least one statement already */
597 noway_assert(last && last->gtNext == nullptr);
599 /* Insert the statement in front of the first one */
606 /* The block was completely empty */
614 /*****************************************************************************
616 * Insert the given tree or statement at the end of the given basic block.
617 * Returns the (potentially) new GT_STMT node.
618 * If the block can be a conditional block, use fgInsertStmtNearEnd.
621 GenTreeStmt* Compiler::fgInsertStmtAtEnd(BasicBlock* block, GenTree* node)
623 GenTree* list = block->firstStmt();
626 if (node->gtOper != GT_STMT)
628 stmt = gtNewStmt(node);
632 stmt = node->AsStmt();
635 assert(stmt->gtNext == nullptr); // We don't set it, and it needs to be this after the insert
641 /* There is at least one statement already */
644 noway_assert(last && last->gtNext == nullptr);
646 /* Append the statement after the last one */
654 /* The block is completely empty */
656 block->bbTreeList = stmt;
663 /*****************************************************************************
665 * Insert the given tree or statement at the end of the given basic block, but before
666 * the GT_JTRUE, if present.
667 * Returns the (potentially) new GT_STMT node.
670 GenTreeStmt* Compiler::fgInsertStmtNearEnd(BasicBlock* block, GenTree* node)
674 // This routine can only be used when in tree order.
675 assert(fgOrder == FGOrderTree);
677 if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH) || (block->bbJumpKind == BBJ_RETURN))
679 if (node->gtOper != GT_STMT)
681 stmt = gtNewStmt(node);
685 stmt = node->AsStmt();
688 GenTreeStmt* first = block->firstStmt();
690 GenTreeStmt* last = block->lastStmt();
691 noway_assert(last && last->gtNext == nullptr);
692 GenTree* after = last->gtPrev;
695 if (block->bbJumpKind == BBJ_COND)
697 noway_assert(last->gtStmtExpr->gtOper == GT_JTRUE);
699 else if (block->bbJumpKind == BBJ_RETURN)
701 noway_assert((last->gtStmtExpr->gtOper == GT_RETURN) || (last->gtStmtExpr->gtOper == GT_JMP) ||
702 // BBJ_RETURN blocks in functions returning void do not get a GT_RETURN node if they
703 // have a .tail prefix (even if canTailCall returns false for these calls)
704 // code:Compiler::impImportBlockCode (search for the RET: label)
705 // Ditto for real tail calls (all code after them has been removed)
706 ((last->gtStmtExpr->gtOper == GT_CALL) &&
707 ((info.compRetType == TYP_VOID) || last->gtStmtExpr->AsCall()->IsTailCall())));
711 noway_assert(block->bbJumpKind == BBJ_SWITCH);
712 noway_assert(last->gtStmtExpr->gtOper == GT_SWITCH);
716 /* Append 'stmt' before 'last' */
723 /* There is only one stmt in the block */
725 block->bbTreeList = stmt;
730 noway_assert(after && (after->gtNext == last));
732 /* Append 'stmt' after 'after' */
734 after->gtNext = stmt;
735 stmt->gtPrev = after;
742 return fgInsertStmtAtEnd(block, node);
746 /*****************************************************************************
748 * Insert the given statement "stmt" after GT_STMT node "insertionPoint".
749 * Returns the newly inserted GT_STMT node.
750 * Note that the gtPrev list of statement nodes is circular, but the gtNext list is not.
753 GenTree* Compiler::fgInsertStmtAfter(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt)
755 assert(block->bbTreeList != nullptr);
756 noway_assert(insertionPoint->gtOper == GT_STMT);
757 noway_assert(stmt->gtOper == GT_STMT);
758 assert(fgBlockContainsStatementBounded(block, insertionPoint));
759 assert(!fgBlockContainsStatementBounded(block, stmt, false));
761 if (insertionPoint->gtNext == nullptr)
763 // Ok, we want to insert after the last statement of the block.
764 stmt->gtNext = nullptr;
765 stmt->gtPrev = insertionPoint;
767 insertionPoint->gtNext = stmt;
769 // Update the backward link of the first statement of the block
770 // to point to the new last statement.
771 assert(block->bbTreeList->gtPrev == insertionPoint);
772 block->bbTreeList->gtPrev = stmt;
776 stmt->gtNext = insertionPoint->gtNext;
777 stmt->gtPrev = insertionPoint;
779 insertionPoint->gtNext->gtPrev = stmt;
780 insertionPoint->gtNext = stmt;
786 // Insert the given tree or statement before GT_STMT node "insertionPoint".
787 // Returns the newly inserted GT_STMT node.
789 GenTree* Compiler::fgInsertStmtBefore(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt)
791 assert(block->bbTreeList != nullptr);
792 noway_assert(insertionPoint->gtOper == GT_STMT);
793 noway_assert(stmt->gtOper == GT_STMT);
794 assert(fgBlockContainsStatementBounded(block, insertionPoint));
795 assert(!fgBlockContainsStatementBounded(block, stmt, false));
797 if (insertionPoint == block->bbTreeList)
799 // We're inserting before the first statement in the block.
800 GenTree* list = block->bbTreeList;
801 GenTree* last = list->gtPrev;
806 block->bbTreeList = stmt;
811 stmt->gtNext = insertionPoint;
812 stmt->gtPrev = insertionPoint->gtPrev;
814 insertionPoint->gtPrev->gtNext = stmt;
815 insertionPoint->gtPrev = stmt;
821 /*****************************************************************************
823 * Insert the list of statements stmtList after the stmtAfter in block.
824 * Return the last statement stmtList.
827 GenTree* Compiler::fgInsertStmtListAfter(BasicBlock* block, // the block where stmtAfter is in.
828 GenTree* stmtAfter, // the statement where stmtList should be inserted
832 // Currently we can handle when stmtAfter and stmtList are non-NULL. This makes everything easy.
833 noway_assert(stmtAfter && stmtAfter->gtOper == GT_STMT);
834 noway_assert(stmtList && stmtList->gtOper == GT_STMT);
836 GenTree* stmtLast = stmtList->gtPrev; // Last statement in a non-empty list, circular in the gtPrev list.
837 noway_assert(stmtLast);
838 noway_assert(stmtLast->gtNext == nullptr);
840 GenTree* stmtNext = stmtAfter->gtNext;
844 stmtAfter->gtNext = stmtList;
845 stmtList->gtPrev = stmtAfter;
846 block->bbTreeList->gtPrev = stmtLast;
850 stmtAfter->gtNext = stmtList;
851 stmtList->gtPrev = stmtAfter;
853 stmtLast->gtNext = stmtNext;
854 stmtNext->gtPrev = stmtLast;
858 noway_assert(block->bbTreeList == nullptr || block->bbTreeList->gtPrev->gtNext == nullptr);
864 Removes a block from the return block list
866 void Compiler::fgRemoveReturnBlock(BasicBlock* block)
868 if (fgReturnBlocks == nullptr)
873 if (fgReturnBlocks->block == block)
875 // It's the 1st entry, assign new head of list.
876 fgReturnBlocks = fgReturnBlocks->next;
880 for (BasicBlockList* retBlocks = fgReturnBlocks; retBlocks->next != nullptr; retBlocks = retBlocks->next)
882 if (retBlocks->next->block == block)
884 // Found it; splice it out.
885 retBlocks->next = retBlocks->next->next;
891 //------------------------------------------------------------------------
892 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
895 // block -- The block with the predecessor list to operate on.
896 // blockPred -- The predecessor block to find in the predecessor list.
899 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
900 // then returns nullptr.
903 // -- This only works on the full predecessor lists, not the cheap preds lists.
905 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred)
909 assert(!fgCheapPredsValid);
913 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
915 if (blockPred == pred->flBlock)
924 //------------------------------------------------------------------------
925 // fgGetPredForBlock: Find and return the predecessor edge corresponding to a given predecessor block.
926 // Also returns the address of the pointer that points to this edge, to make it possible to remove this edge from the
927 // predecessor list without doing another linear search over the edge list.
930 // block -- The block with the predecessor list to operate on.
931 // blockPred -- The predecessor block to find in the predecessor list.
932 // ptrToPred -- Out parameter: set to the address of the pointer that points to the returned predecessor edge.
935 // The flowList edge corresponding to "blockPred". If "blockPred" is not in the predecessor list of "block",
936 // then returns nullptr.
939 // -- This only works on the full predecessor lists, not the cheap preds lists.
941 flowList* Compiler::fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred)
946 assert(!fgCheapPredsValid);
948 flowList** predPrevAddr;
951 for (predPrevAddr = &block->bbPreds, pred = *predPrevAddr; pred != nullptr;
952 predPrevAddr = &pred->flNext, pred = *predPrevAddr)
954 if (blockPred == pred->flBlock)
956 *ptrToPred = predPrevAddr;
961 *ptrToPred = nullptr;
965 //------------------------------------------------------------------------
966 // fgSpliceOutPred: Removes a predecessor edge for a block from the predecessor list.
969 // block -- The block with the predecessor list to operate on.
970 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
973 // The flowList edge that was removed.
976 // -- "blockPred" must be a predecessor block of "block".
977 // -- This simply splices out the flowList object. It doesn't update block ref counts, handle duplicate counts, etc.
978 // For that, use fgRemoveRefPred() or fgRemoveAllRefPred().
979 // -- This only works on the full predecessor lists, not the cheap preds lists.
982 // -- This must walk the predecessor list to find the block in question. If the predecessor edge
983 // is found using fgGetPredForBlock(), consider using the version that hands back the predecessor pointer
984 // address instead, to avoid this search.
985 // -- Marks fgModified = true, since the flow graph has changed.
987 flowList* Compiler::fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred)
989 assert(!fgCheapPredsValid);
990 noway_assert(block->bbPreds);
992 flowList* oldEdge = nullptr;
994 // Is this the first block in the pred list?
995 if (blockPred == block->bbPreds->flBlock)
997 oldEdge = block->bbPreds;
998 block->bbPreds = block->bbPreds->flNext;
1003 for (pred = block->bbPreds; (pred->flNext != nullptr) && (blockPred != pred->flNext->flBlock);
1004 pred = pred->flNext)
1008 oldEdge = pred->flNext;
1009 if (oldEdge == nullptr)
1011 noway_assert(!"Should always find the blockPred");
1013 pred->flNext = pred->flNext->flNext;
1016 // Any changes to the flow graph invalidate the dominator sets.
1022 //------------------------------------------------------------------------
1023 // fgAddRefPred: Increment block->bbRefs by one and add "blockPred" to the predecessor list of "block".
1026 // block -- A block to operate on.
1027 // blockPred -- The predecessor block to add to the predecessor list.
1028 // oldEdge -- Optional (default: nullptr). If non-nullptr, and a new edge is created (and the dup count
1029 // of an existing edge is not just incremented), the edge weights are copied from this edge.
1030 // initializingPreds -- Optional (default: false). Only set to "true" when the initial preds computation is
1034 // The flow edge representing the predecessor.
1037 // -- This only works on the full predecessor lists, not the cheap preds lists.
1040 // -- block->bbRefs is incremented by one to account for the reduction in incoming edges.
1041 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
1042 // the preds themselves aren't touched.
1043 // -- fgModified is set if a new flow edge is created (but not if an existing flow edge dup count is incremented),
1044 // indicating that the flow graph shape has changed.
1046 flowList* Compiler::fgAddRefPred(BasicBlock* block,
1047 BasicBlock* blockPred,
1048 flowList* oldEdge /* = nullptr */,
1049 bool initializingPreds /* = false */)
1051 assert(block != nullptr);
1052 assert(blockPred != nullptr);
1056 if (!fgComputePredsDone && !initializingPreds)
1058 // Why is someone trying to update the preds list when the preds haven't been created?
1059 // Ignore them! This can happen when fgMorph is called before the preds list is created.
1063 assert(!fgCheapPredsValid);
1067 // Keep the predecessor list in lowest to highest bbNum order. This allows us to discover the loops in
1068 // optFindNaturalLoops from innermost to outermost.
1070 // TODO-Throughput: Inserting an edge for a block in sorted order requires searching every existing edge.
1071 // Thus, inserting all the edges for a block is quadratic in the number of edges. We need to either
1072 // not bother sorting for debuggable code, or sort in optFindNaturalLoops, or better, make the code in
1073 // optFindNaturalLoops not depend on order. This also requires ensuring that nobody else has taken a
1074 // dependency on this order. Note also that we don't allow duplicates in the list; we maintain a flDupCount
1075 // count of duplication. This also necessitates walking the flow list for every edge we add.
1077 flowList** listp = &block->bbPreds;
1078 while ((*listp != nullptr) && ((*listp)->flBlock->bbNum < blockPred->bbNum))
1080 listp = &(*listp)->flNext;
1083 if ((*listp != nullptr) && ((*listp)->flBlock == blockPred))
1085 // The predecessor block already exists in the flow list; simply add to its duplicate count.
1087 noway_assert(flow->flDupCount > 0);
1092 flow = new (this, CMK_FlowList) flowList();
1094 #if MEASURE_BLOCK_SIZE
1095 genFlowNodeCnt += 1;
1096 genFlowNodeSize += sizeof(flowList);
1097 #endif // MEASURE_BLOCK_SIZE
1099 // Any changes to the flow graph invalidate the dominator sets.
1102 // Insert the new edge in the list in the correct ordered location.
1103 flow->flNext = *listp;
1106 flow->flBlock = blockPred;
1107 flow->flDupCount = 1;
1109 if (fgHaveValidEdgeWeights)
1111 // We are creating an edge from blockPred to block
1112 // and we have already computed the edge weights, so
1113 // we will try to setup this new edge with valid edge weights.
1115 if (oldEdge != nullptr)
1117 // If our caller has given us the old edge weights
1118 // then we will use them.
1120 flow->flEdgeWeightMin = oldEdge->flEdgeWeightMin;
1121 flow->flEdgeWeightMax = oldEdge->flEdgeWeightMax;
1125 // Set the max edge weight to be the minimum of block's or blockPred's weight
1127 flow->flEdgeWeightMax = min(block->bbWeight, blockPred->bbWeight);
1129 // If we are inserting a conditional block the minimum weight is zero,
1130 // otherwise it is the same as the edge's max weight.
1131 if (blockPred->NumSucc() > 1)
1133 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1137 flow->flEdgeWeightMin = flow->flEdgeWeightMax;
1143 flow->flEdgeWeightMin = BB_ZERO_WEIGHT;
1144 flow->flEdgeWeightMax = BB_MAX_WEIGHT;
1150 //------------------------------------------------------------------------
1151 // fgRemoveRefPred: Decrements the reference count of a predecessor edge from "blockPred" to "block",
1152 // removing the edge if it is no longer necessary.
1155 // block -- A block to operate on.
1156 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1159 // If the flow edge was removed (the predecessor has a "dup count" of 1),
1160 // returns the flow graph edge that was removed. This means "blockPred" is no longer a predecessor of "block".
1161 // Otherwise, returns nullptr. This means that "blockPred" is still a predecessor of "block" (because "blockPred"
1162 // is a switch with multiple cases jumping to "block", or a BBJ_COND with both conditional and fall-through
1163 // paths leading to "block").
1166 // -- "blockPred" must be a predecessor block of "block".
1167 // -- This only works on the full predecessor lists, not the cheap preds lists.
1170 // -- block->bbRefs is decremented by one to account for the reduction in incoming edges.
1171 // -- block->bbRefs is adjusted even if preds haven't been computed. If preds haven't been computed,
1172 // the preds themselves aren't touched.
1173 // -- fgModified is set if a flow edge is removed (but not if an existing flow edge dup count is decremented),
1174 // indicating that the flow graph shape has changed.
1176 flowList* Compiler::fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred)
1178 noway_assert(block != nullptr);
1179 noway_assert(blockPred != nullptr);
1181 noway_assert(block->countOfInEdges() > 0);
1184 // Do nothing if we haven't calculated the predecessor list yet.
1185 // Yes, this does happen.
1186 // For example the predecessor lists haven't been created yet when we do fgMorph.
1187 // But fgMorph calls fgFoldConditional, which in turn calls fgRemoveRefPred.
1188 if (!fgComputePredsDone)
1193 assert(!fgCheapPredsValid);
1195 flowList** ptrToPred;
1196 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1198 noway_assert(pred->flDupCount > 0);
1202 if (pred->flDupCount == 0)
1204 // Splice out the predecessor edge since it's no longer necessary.
1205 *ptrToPred = pred->flNext;
1207 // Any changes to the flow graph invalidate the dominator sets.
1218 //------------------------------------------------------------------------
1219 // fgRemoveAllRefPreds: Removes a predecessor edge from one block to another, no matter what the "dup count" is.
1222 // block -- A block to operate on.
1223 // blockPred -- The predecessor block to remove from the predecessor list. It must be a predecessor of "block".
1226 // Returns the flow graph edge that was removed. The dup count on the edge is no longer valid.
1229 // -- "blockPred" must be a predecessor block of "block".
1230 // -- This only works on the full predecessor lists, not the cheap preds lists.
1233 // block->bbRefs is decremented to account for the reduction in incoming edges.
1235 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred)
1237 assert(block != nullptr);
1238 assert(blockPred != nullptr);
1239 assert(fgComputePredsDone);
1240 assert(!fgCheapPredsValid);
1241 assert(block->countOfInEdges() > 0);
1243 flowList** ptrToPred;
1244 flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
1245 assert(pred != nullptr);
1246 assert(pred->flDupCount > 0);
1248 assert(block->bbRefs >= pred->flDupCount);
1249 block->bbRefs -= pred->flDupCount;
1251 // Now splice out the predecessor edge.
1252 *ptrToPred = pred->flNext;
1254 // Any changes to the flow graph invalidate the dominator sets.
1260 //------------------------------------------------------------------------
1261 // fgRemoveAllRefPreds: Remove a predecessor edge, given the address of a pointer to it in the
1262 // predecessor list, no matter what the "dup count" is.
1265 // block -- A block with the predecessor list to operate on.
1266 // ptrToPred -- The address of a pointer to the predecessor to remove.
1269 // The removed predecessor edge. The dup count on the edge is no longer valid.
1272 // -- The predecessor edge must be in the predecessor list for "block".
1273 // -- This only works on the full predecessor lists, not the cheap preds lists.
1276 // block->bbRefs is decremented by the dup count of the predecessor edge, to account for the reduction in incoming
1279 flowList* Compiler::fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred)
1281 assert(block != nullptr);
1282 assert(ptrToPred != nullptr);
1283 assert(fgComputePredsDone);
1284 assert(!fgCheapPredsValid);
1285 assert(block->countOfInEdges() > 0);
1287 flowList* pred = *ptrToPred;
1288 assert(pred != nullptr);
1289 assert(pred->flDupCount > 0);
1291 assert(block->bbRefs >= pred->flDupCount);
1292 block->bbRefs -= pred->flDupCount;
1294 // Now splice out the predecessor edge.
1295 *ptrToPred = pred->flNext;
1297 // Any changes to the flow graph invalidate the dominator sets.
1304 Removes all the appearances of block as predecessor of others
1307 void Compiler::fgRemoveBlockAsPred(BasicBlock* block)
1309 assert(!fgCheapPredsValid);
1311 PREFIX_ASSUME(block != nullptr);
1315 switch (block->bbJumpKind)
1317 case BBJ_CALLFINALLY:
1318 if (!(block->bbFlags & BBF_RETLESS_CALL))
1320 assert(block->isBBCallAlwaysPair());
1322 /* The block after the BBJ_CALLFINALLY block is not reachable */
1323 bNext = block->bbNext;
1325 /* bNext is an unreachable BBJ_ALWAYS block */
1326 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
1328 while (bNext->countOfInEdges() > 0)
1330 fgRemoveRefPred(bNext, bNext->bbPreds->flBlock);
1338 case BBJ_EHCATCHRET:
1340 /* Update the predecessor list for 'block->bbJumpDest' and 'block->bbNext' */
1341 fgRemoveRefPred(block->bbJumpDest, block);
1343 if (block->bbJumpKind != BBJ_COND)
1348 /* If BBJ_COND fall through */
1353 /* Update the predecessor list for 'block->bbNext' */
1354 fgRemoveRefPred(block->bbNext, block);
1357 case BBJ_EHFILTERRET:
1359 block->bbJumpDest->bbRefs++; // To compensate the bbRefs-- inside fgRemoveRefPred
1360 fgRemoveRefPred(block->bbJumpDest, block);
1363 case BBJ_EHFINALLYRET:
1365 /* Remove block as the predecessor of the bbNext of all
1366 BBJ_CALLFINALLY blocks calling this finally. No need
1367 to look for BBJ_CALLFINALLY for fault handlers. */
1369 unsigned hndIndex = block->getHndIndex();
1370 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
1372 if (ehDsc->HasFinallyHandler())
1376 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
1378 BasicBlock* finBeg = ehDsc->ebdHndBeg;
1380 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
1382 if ((bcall->bbFlags & BBF_REMOVED) || bcall->bbJumpKind != BBJ_CALLFINALLY ||
1383 bcall->bbJumpDest != finBeg)
1388 assert(bcall->isBBCallAlwaysPair());
1389 fgRemoveRefPred(bcall->bbNext, block);
1401 unsigned jumpCnt = block->bbJumpSwt->bbsCount;
1402 BasicBlock** jumpTab = block->bbJumpSwt->bbsDstTab;
1406 fgRemoveRefPred(*jumpTab, block);
1407 } while (++jumpTab, --jumpCnt);
1413 noway_assert(!"Block doesn't have a valid bbJumpKind!!!!");
1418 /*****************************************************************************
1419 * fgChangeSwitchBlock:
1421 * We have a BBJ_SWITCH jump at 'oldSwitchBlock' and we want to move this
1422 * switch jump over to 'newSwitchBlock'. All of the blocks that are jumped
1423 * to from jumpTab[] need to have their predecessor lists updated by removing
1424 * the 'oldSwitchBlock' and adding 'newSwitchBlock'.
1427 void Compiler::fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock)
1429 noway_assert(oldSwitchBlock != nullptr);
1430 noway_assert(newSwitchBlock != nullptr);
1431 noway_assert(oldSwitchBlock->bbJumpKind == BBJ_SWITCH);
1433 unsigned jumpCnt = oldSwitchBlock->bbJumpSwt->bbsCount;
1434 BasicBlock** jumpTab = oldSwitchBlock->bbJumpSwt->bbsDstTab;
1438 // Walk the switch's jump table, updating the predecessor for each branch.
1439 for (i = 0; i < jumpCnt; i++)
1441 BasicBlock* bJump = jumpTab[i];
1442 noway_assert(bJump != nullptr);
1444 // Note that if there are duplicate branch targets in the switch jump table,
1445 // fgRemoveRefPred()/fgAddRefPred() will do the right thing: the second and
1446 // subsequent duplicates will simply subtract from and add to the duplicate
1447 // count (respectively).
1450 // Remove the old edge [oldSwitchBlock => bJump]
1452 fgRemoveRefPred(bJump, oldSwitchBlock);
1455 // Create the new edge [newSwitchBlock => bJump]
1457 fgAddRefPred(bJump, newSwitchBlock);
1460 if (m_switchDescMap != nullptr)
1462 SwitchUniqueSuccSet uniqueSuccSet;
1464 // If already computed and cached the unique descriptors for the old block, let's
1465 // update those for the new block.
1466 if (m_switchDescMap->Lookup(oldSwitchBlock, &uniqueSuccSet))
1468 m_switchDescMap->Set(newSwitchBlock, uniqueSuccSet);
1472 fgInvalidateSwitchDescMapEntry(newSwitchBlock);
1474 fgInvalidateSwitchDescMapEntry(oldSwitchBlock);
1478 /*****************************************************************************
1479 * fgReplaceSwitchJumpTarget:
1481 * We have a BBJ_SWITCH at 'blockSwitch' and we want to replace all entries
1482 * in the jumpTab[] such that so that jumps that previously went to
1483 * 'oldTarget' now go to 'newTarget'.
1484 * We also must update the predecessor lists for 'oldTarget' and 'newPred'.
1487 void Compiler::fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget)
1489 noway_assert(blockSwitch != nullptr);
1490 noway_assert(newTarget != nullptr);
1491 noway_assert(oldTarget != nullptr);
1492 noway_assert(blockSwitch->bbJumpKind == BBJ_SWITCH);
1494 // For the jump targets values that match oldTarget of our BBJ_SWITCH
1495 // replace predecessor 'blockSwitch' with 'newTarget'
1498 unsigned jumpCnt = blockSwitch->bbJumpSwt->bbsCount;
1499 BasicBlock** jumpTab = blockSwitch->bbJumpSwt->bbsDstTab;
1503 // Walk the switch's jump table looking for blocks to update the preds for
1506 if (jumpTab[i] == oldTarget) // We will update when jumpTab[i] matches
1508 // Remove the old edge [oldTarget from blockSwitch]
1510 fgRemoveAllRefPreds(oldTarget, blockSwitch);
1513 // Change the jumpTab entry to branch to the new location
1515 jumpTab[i] = newTarget;
1518 // Create the new edge [newTarget from blockSwitch]
1520 flowList* newEdge = fgAddRefPred(newTarget, blockSwitch);
1522 // Now set the correct value of newEdge->flDupCount
1523 // and replace any other jumps in jumpTab[] that go to oldTarget.
1528 if (jumpTab[i] == oldTarget)
1531 // We also must update this entry in the jumpTab
1533 jumpTab[i] = newTarget;
1534 newTarget->bbRefs++;
1537 // Increment the flDupCount
1539 newEdge->flDupCount++;
1541 i++; // Check the next entry in jumpTab[]
1544 // Maintain, if necessary, the set of unique targets of "block."
1545 UpdateSwitchTableTarget(blockSwitch, oldTarget, newTarget);
1547 // Make sure the new target has the proper bits set for being a branch target.
1548 newTarget->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
1550 return; // We have replaced the jumps to oldTarget with newTarget
1552 i++; // Check the next entry in jumpTab[] for a match
1554 noway_assert(!"Did not find oldTarget in jumpTab[]");
1557 //------------------------------------------------------------------------
1558 // Compiler::fgReplaceJumpTarget: For a given block, replace the target 'oldTarget' with 'newTarget'.
1561 // block - the block in which a jump target will be replaced.
1562 // newTarget - the new branch target of the block.
1563 // oldTarget - the old branch target of the block.
1566 // 1. Only branches are changed: BBJ_ALWAYS, the non-fallthrough path of BBJ_COND, BBJ_SWITCH, etc.
1567 // We ignore other block types.
1568 // 2. Only the first target found is updated. If there are multiple ways for a block
1569 // to reach 'oldTarget' (e.g., multiple arms of a switch), only the first one found is changed.
1570 // 3. The predecessor lists are not changed.
1571 // 4. The switch table "unique successor" cache is invalidated.
1573 // This function is most useful early, before the full predecessor lists have been computed.
1575 void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget)
1577 assert(block != nullptr);
1579 switch (block->bbJumpKind)
1581 case BBJ_CALLFINALLY:
1584 case BBJ_EHCATCHRET:
1585 case BBJ_EHFILTERRET:
1586 case BBJ_LEAVE: // This function will be called before import, so we still have BBJ_LEAVE
1588 if (block->bbJumpDest == oldTarget)
1590 block->bbJumpDest = newTarget;
1595 case BBJ_EHFINALLYRET:
1602 jumpCnt = block->bbJumpSwt->bbsCount;
1603 BasicBlock** jumpTab;
1604 jumpTab = block->bbJumpSwt->bbsDstTab;
1606 for (unsigned i = 0; i < jumpCnt; i++)
1608 if (jumpTab[i] == oldTarget)
1610 jumpTab[i] = newTarget;
1617 assert(!"Block doesn't have a valid bbJumpKind!!!!");
1623 /*****************************************************************************
1624 * Updates the predecessor list for 'block' by replacing 'oldPred' with 'newPred'.
1625 * Note that a block can only appear once in the preds list (for normal preds, not
1626 * cheap preds): if a predecessor has multiple ways to get to this block, then
1627 * flDupCount will be >1, but the block will still appear exactly once. Thus, this
1628 * function assumes that all branches from the predecessor (practically, that all
1629 * switch cases that target this block) are changed to branch from the new predecessor,
1630 * with the same dup count.
1632 * Note that the block bbRefs is not changed, since 'block' has the same number of
1633 * references as before, just from a different predecessor block.
1636 void Compiler::fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred)
1638 noway_assert(block != nullptr);
1639 noway_assert(oldPred != nullptr);
1640 noway_assert(newPred != nullptr);
1641 assert(!fgCheapPredsValid);
1645 for (pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1647 if (oldPred == pred->flBlock)
1649 pred->flBlock = newPred;
1655 /*****************************************************************************
1657 * Returns true if block b1 dominates block b2.
1660 bool Compiler::fgDominate(BasicBlock* b1, BasicBlock* b2)
1662 noway_assert(fgDomsComputed);
1663 assert(!fgCheapPredsValid);
1666 // If the fgModified flag is false then we made some modifications to
1667 // the flow graph, like adding a new block or changing a conditional branch
1668 // into an unconditional branch.
1670 // We can continue to use the dominator and reachable information to
1671 // unmark loops as long as we haven't renumbered the blocks or we aren't
1672 // asking for information about a new block
1675 if (b2->bbNum > fgDomBBcount)
1682 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1684 if (!fgDominate(b1, pred->flBlock))
1690 return b2->bbPreds != nullptr;
1693 if (b1->bbNum > fgDomBBcount)
1695 // if b1 is a loop preheader and Succ is its only successor, then all predecessors of
1696 // Succ either are b1 itself or are dominated by Succ. Under these conditions, b1
1697 // dominates b2 if and only if Succ dominates b2 (or if b2 == b1, but we already tested
1699 if (b1->bbFlags & BBF_LOOP_PREHEADER)
1701 noway_assert(b1->bbFlags & BBF_INTERNAL);
1702 noway_assert(b1->bbJumpKind == BBJ_NONE);
1703 return fgDominate(b1->bbNext, b2);
1706 // unknown dominators; err on the safe side and return false
1710 /* Check if b1 dominates b2 */
1711 unsigned numA = b1->bbNum;
1712 noway_assert(numA <= fgDomBBcount);
1713 unsigned numB = b2->bbNum;
1714 noway_assert(numB <= fgDomBBcount);
1716 // 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)
1717 // in the dominator tree. Turns out that can be translated as:
1719 // A dom B <-> preorder(A) <= preorder(B) && postorder(A) >= postorder(B)
1721 // where the equality holds when you ask if A dominates itself.
1723 fgDomTreePreOrder[numA] <= fgDomTreePreOrder[numB] && fgDomTreePostOrder[numA] >= fgDomTreePostOrder[numB];
1728 /*****************************************************************************
1730 * Returns true if block b1 can reach block b2.
1733 bool Compiler::fgReachable(BasicBlock* b1, BasicBlock* b2)
1735 noway_assert(fgDomsComputed);
1736 assert(!fgCheapPredsValid);
1739 // If the fgModified flag is false then we made some modifications to
1740 // the flow graph, like adding a new block or changing a conditional branch
1741 // into an unconditional branch.
1743 // We can continue to use the dominator and reachable information to
1744 // unmark loops as long as we haven't renumbered the blocks or we aren't
1745 // asking for information about a new block
1748 if (b2->bbNum > fgDomBBcount)
1755 for (flowList* pred = b2->bbPreds; pred != nullptr; pred = pred->flNext)
1757 if (fgReachable(b1, pred->flBlock))
1766 if (b1->bbNum > fgDomBBcount)
1768 noway_assert(b1->bbJumpKind == BBJ_NONE || b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND);
1770 if (b1->bbFallsThrough() && fgReachable(b1->bbNext, b2))
1775 if (b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND)
1777 return fgReachable(b1->bbJumpDest, b2);
1783 /* Check if b1 can reach b2 */
1784 assert(fgReachabilitySetsValid);
1785 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
1786 return BlockSetOps::IsMember(this, b2->bbReach, b1->bbNum);
1789 /*****************************************************************************
1790 * Update changed flow graph information.
1792 * If the flow graph has changed, we need to recompute various information if we want to use
1796 void Compiler::fgUpdateChangedFlowGraph()
1798 // We need to clear this so we don't hit an assert calling fgRenumberBlocks().
1799 fgDomsComputed = false;
1801 JITDUMP("\nRenumbering the basic blocks for fgUpdateChangeFlowGraph\n");
1805 fgComputeEnterBlocksSet();
1806 fgComputeReachabilitySets();
1810 /*****************************************************************************
1811 * Compute the bbReach sets.
1813 * This can be called to recompute the bbReach sets after the flow graph changes, such as when the
1814 * number of BasicBlocks change (and thus, the BlockSet epoch changes).
1816 * Finally, this also sets the BBF_GC_SAFE_POINT flag on blocks.
1818 * Assumes the predecessor lists are correct.
1820 * TODO-Throughput: This algorithm consumes O(n^2) because we're using dense bitsets to
1821 * represent reachability. While this yields O(1) time queries, it bloats the memory usage
1822 * for large code. We can do better if we try to approach reachability by
1823 * computing the strongly connected components of the flow graph. That way we only need
1824 * linear memory to label every block with its SCC.
1827 void Compiler::fgComputeReachabilitySets()
1829 assert(fgComputePredsDone);
1830 assert(!fgCheapPredsValid);
1833 fgReachabilitySetsValid = false;
1838 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1840 // Initialize the per-block bbReach sets. It creates a new empty set,
1841 // because the block epoch could change since the previous initialization
1842 // and the old set could have wrong size.
1843 block->bbReach = BlockSetOps::MakeEmpty(this);
1845 /* Mark block as reaching itself */
1846 BlockSetOps::AddElemD(this, block->bbReach, block->bbNum);
1849 /* Find the reachable blocks */
1850 // Also, set BBF_GC_SAFE_POINT.
1853 BlockSet newReach(BlockSetOps::MakeEmpty(this));
1858 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1860 BlockSetOps::Assign(this, newReach, block->bbReach);
1862 bool predGcSafe = (block->bbPreds != nullptr); // Do all of our predecessor blocks have a GC safe bit?
1864 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
1866 BasicBlock* predBlock = pred->flBlock;
1868 /* Union the predecessor's reachability set into newReach */
1869 BlockSetOps::UnionD(this, newReach, predBlock->bbReach);
1871 if (!(predBlock->bbFlags & BBF_GC_SAFE_POINT))
1879 block->bbFlags |= BBF_GC_SAFE_POINT;
1882 if (!BlockSetOps::Equal(this, newReach, block->bbReach))
1884 BlockSetOps::Assign(this, block->bbReach, newReach);
1893 printf("\nAfter computing reachability sets:\n");
1897 fgReachabilitySetsValid = true;
1901 /*****************************************************************************
1902 * Compute the entry blocks set.
1904 * Initialize fgEnterBlks to the set of blocks for which we don't have explicit control
1905 * flow edges. These are the entry basic block and each of the EH handler blocks.
1906 * For ARM, also include the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
1907 * to avoid creating "retless" calls, since we need the BBJ_ALWAYS for the purpose
1908 * of unwinding, even if the call doesn't return (due to an explicit throw, for example).
1911 void Compiler::fgComputeEnterBlocksSet()
1914 fgEnterBlksSetValid = false;
1917 fgEnterBlks = BlockSetOps::MakeEmpty(this);
1919 /* Now set the entry basic block */
1920 BlockSetOps::AddElemD(this, fgEnterBlks, fgFirstBB->bbNum);
1921 assert(fgFirstBB->bbNum == 1);
1923 if (compHndBBtabCount > 0)
1925 /* Also 'or' in the handler basic blocks */
1928 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
1930 if (HBtab->HasFilter())
1932 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdFilter->bbNum);
1934 BlockSetOps::AddElemD(this, fgEnterBlks, HBtab->ebdHndBeg->bbNum);
1938 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1939 // TODO-ARM-Cleanup: The ARM code here to prevent creating retless calls by adding the BBJ_ALWAYS
1940 // to the enter blocks is a bit of a compromise, because sometimes the blocks are already reachable,
1941 // and it messes up DFS ordering to have them marked as enter block. We should prevent the
1942 // creation of retless calls some other way.
1943 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
1945 if (block->bbJumpKind == BBJ_CALLFINALLY)
1947 assert(block->isBBCallAlwaysPair());
1949 // Don't remove the BBJ_ALWAYS block that is only here for the unwinder. It might be dead
1950 // if the finally is no-return, so mark it as an entry point.
1951 BlockSetOps::AddElemD(this, fgEnterBlks, block->bbNext->bbNum);
1954 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1959 printf("Enter blocks: ");
1960 BlockSetOps::Iter iter(this, fgEnterBlks);
1962 while (iter.NextElem(&bbNum))
1964 printf("BB%02u ", bbNum);
1971 fgEnterBlksSetValid = true;
1975 /*****************************************************************************
1976 * Remove unreachable blocks.
1978 * Return true if any unreachable blocks were removed.
1981 bool Compiler::fgRemoveUnreachableBlocks()
1983 assert(!fgCheapPredsValid);
1984 assert(fgReachabilitySetsValid);
1986 bool hasLoops = false;
1987 bool hasUnreachableBlocks = false;
1990 /* Record unreachable blocks */
1991 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
1993 /* Internal throw blocks are also reachable */
1994 if (fgIsThrowHlpBlk(block))
1998 else if (block == genReturnBB)
2000 // Don't remove statements for the genReturnBB block, as we might have special hookups there.
2001 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
2002 // the profiler hookup needs to have the "void GT_RETURN" statement
2003 // to properly set the info.compProfilerCallback flag.
2008 // If any of the entry blocks can reach this block, then we skip it.
2009 if (!BlockSetOps::IsEmptyIntersection(this, fgEnterBlks, block->bbReach))
2015 // Remove all the code for the block
2016 fgUnreachableBlock(block);
2018 // Make sure that the block was marked as removed */
2019 noway_assert(block->bbFlags & BBF_REMOVED);
2021 // Some blocks mark the end of trys and catches
2022 // and can't be removed. We convert these into
2023 // empty blocks of type BBJ_THROW
2025 if (block->bbFlags & BBF_DONT_REMOVE)
2027 bool bIsBBCallAlwaysPair = block->isBBCallAlwaysPair();
2029 /* Unmark the block as removed, */
2030 /* clear BBF_INTERNAL as well and set BBJ_IMPORTED */
2032 block->bbFlags &= ~(BBF_REMOVED | BBF_INTERNAL | BBF_NEEDS_GCPOLL);
2033 block->bbFlags |= BBF_IMPORTED;
2034 block->bbJumpKind = BBJ_THROW;
2035 block->bbSetRunRarely();
2037 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2038 // If this is a <BBJ_CALLFINALLY, BBJ_ALWAYS> pair, we have to clear BBF_FINALLY_TARGET flag on
2039 // the target node (of BBJ_ALWAYS) since BBJ_CALLFINALLY node is getting converted to a BBJ_THROW.
2040 if (bIsBBCallAlwaysPair)
2042 noway_assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
2043 fgClearFinallyTargetBit(block->bbNext->bbJumpDest);
2045 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2049 /* We have to call fgRemoveBlock next */
2050 hasUnreachableBlocks = true;
2056 // if (block->isRunRarely())
2058 if (block->bbJumpKind == BBJ_RETURN)
2063 /* Set BBF_LOOP_HEAD if we have backwards branches to this block */
2065 unsigned blockNum = block->bbNum;
2066 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
2068 BasicBlock* predBlock = pred->flBlock;
2069 if (blockNum <= predBlock->bbNum)
2071 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
2076 /* If block can reach predBlock then we have a loop head */
2077 if (BlockSetOps::IsMember(this, predBlock->bbReach, blockNum))
2081 /* Set the BBF_LOOP_HEAD flag */
2082 block->bbFlags |= BBF_LOOP_HEAD;
2089 fgHasLoops = hasLoops;
2091 if (hasUnreachableBlocks)
2093 // Now remove the unreachable blocks
2094 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2096 // If we mark the block with BBF_REMOVED then
2097 // we need to call fgRemovedBlock() on it
2099 if (block->bbFlags & BBF_REMOVED)
2101 fgRemoveBlock(block, true);
2103 // When we have a BBJ_CALLFINALLY, BBJ_ALWAYS pair; fgRemoveBlock will remove
2104 // both blocks, so we must advance 1 extra place in the block list
2106 if (block->isBBCallAlwaysPair())
2108 block = block->bbNext;
2114 return hasUnreachableBlocks;
2117 /*****************************************************************************
2119 * Function called to compute the dominator and reachable sets.
2121 * Assumes the predecessor lists are computed and correct.
2124 void Compiler::fgComputeReachability()
2129 printf("*************** In fgComputeReachability\n");
2132 fgVerifyHandlerTab();
2134 // Make sure that the predecessor lists are accurate
2135 assert(fgComputePredsDone);
2136 fgDebugCheckBBlist();
2139 /* Create a list of all BBJ_RETURN blocks. The head of the list is 'fgReturnBlocks'. */
2140 fgReturnBlocks = nullptr;
2142 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2144 // If this is a BBJ_RETURN block, add it to our list of all BBJ_RETURN blocks. This list is only
2145 // used to find return blocks.
2146 if (block->bbJumpKind == BBJ_RETURN)
2148 fgReturnBlocks = new (this, CMK_Reachability) BasicBlockList(block, fgReturnBlocks);
2152 // Compute reachability and then delete blocks determined to be unreachable. If we delete blocks, we
2153 // need to loop, as that might have caused more blocks to become unreachable. This can happen in the
2154 // case where a call to a finally is unreachable and deleted (maybe the call to the finally is
2155 // preceded by a throw or an infinite loop), making the blocks following the finally unreachable.
2156 // However, all EH entry blocks are considered global entry blocks, causing the blocks following the
2157 // call to the finally to stay rooted, until a second round of reachability is done.
2158 // The dominator algorithm expects that all blocks can be reached from the fgEnterBlks set.
2159 unsigned passNum = 1;
2163 // Just to be paranoid, avoid infinite loops; fall back to minopts.
2166 noway_assert(!"Too many unreachable block removal loops");
2169 /* Walk the flow graph, reassign block numbers to keep them in ascending order */
2170 JITDUMP("\nRenumbering the basic blocks for fgComputeReachability pass #%u\n", passNum);
2175 // Compute fgEnterBlks
2178 fgComputeEnterBlocksSet();
2184 fgComputeReachabilitySets();
2187 // Use reachability information to delete unreachable blocks.
2188 // Also, determine if the flow graph has loops and set 'fgHasLoops' accordingly.
2189 // Set the BBF_LOOP_HEAD flag on the block target of backwards branches.
2192 changed = fgRemoveUnreachableBlocks();
2199 printf("\nAfter computing reachability:\n");
2200 fgDispBasicBlocks(verboseTrees);
2204 fgVerifyHandlerTab();
2205 fgDebugCheckBBlist(true);
2209 // Now, compute the dominators
2215 /** In order to be able to compute dominance, we need to first get a DFS reverse post order sort on the basic flow graph
2216 * for the dominance algorithm to operate correctly. The reason why we need the DFS sort is because
2217 * we will build the dominance sets using the partial order induced by the DFS sorting. With this
2218 * precondition not holding true, the algorithm doesn't work properly.
2220 void Compiler::fgDfsInvPostOrder()
2222 // NOTE: This algorithm only pays attention to the actual blocks. It ignores the imaginary entry block.
2224 // visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid
2226 BlockSet visited(BlockSetOps::MakeEmpty(this));
2228 // We begin by figuring out which basic blocks don't have incoming edges and mark them as
2229 // start nodes. Later on we run the recursive algorithm for each node that we
2230 // mark in this step.
2231 BlockSet_ValRet_T startNodes = fgDomFindStartNodes();
2233 // Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is
2234 // an incoming edge into the block).
2235 assert(fgEnterBlksSetValid);
2237 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2239 // BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2241 // This causes problems on ARM, because we for BBJ_CALLFINALLY/BBJ_ALWAYS pairs, we add the BBJ_ALWAYS
2242 // to the enter blocks set to prevent flow graph optimizations from removing it and creating retless call finallies
2243 // (BBF_RETLESS_CALL). This leads to an incorrect DFS ordering in some cases, because we start the recursive walk
2244 // from the BBJ_ALWAYS, which is reachable from other blocks. A better solution would be to change ARM to avoid
2245 // creating retless calls in a different way, not by adding BBJ_ALWAYS to fgEnterBlks.
2247 // So, let us make sure at least fgFirstBB is still there, even if it participates in a loop.
2248 BlockSetOps::AddElemD(this, startNodes, 1);
2249 assert(fgFirstBB->bbNum == 1);
2251 BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
2254 assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum));
2256 // Call the flowgraph DFS traversal helper.
2257 unsigned postIndex = 1;
2258 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
2260 // If the block has no predecessors, and we haven't already visited it (because it's in fgEnterBlks but also
2261 // reachable from the first block), go ahead and traverse starting from this block.
2262 if (BlockSetOps::IsMember(this, startNodes, block->bbNum) &&
2263 !BlockSetOps::IsMember(this, visited, block->bbNum))
2265 fgDfsInvPostOrderHelper(block, visited, &postIndex);
2269 // After the DFS reverse postorder is completed, we must have visited all the basic blocks.
2270 noway_assert(postIndex == fgBBcount + 1);
2271 noway_assert(fgBBNumMax == fgBBcount);
2276 printf("\nAfter doing a post order traversal of the BB graph, this is the ordering:\n");
2277 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2279 printf("%02u -> BB%02u\n", i, fgBBInvPostOrder[i]->bbNum);
2286 BlockSet_ValRet_T Compiler::fgDomFindStartNodes()
2291 // startNodes :: A set that represents which basic blocks in the flow graph don't have incoming edges.
2292 // We begin assuming everything is a start block and remove any block that is being referenced by another in its
2295 BlockSet startNodes(BlockSetOps::MakeFull(this));
2297 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2299 unsigned cSucc = block->NumSucc(this);
2300 for (j = 0; j < cSucc; ++j)
2302 BasicBlock* succ = block->GetSucc(j, this);
2303 BlockSetOps::RemoveElemD(this, startNodes, succ->bbNum);
2310 printf("\nDominator computation start blocks (those blocks with no incoming edges):\n");
2311 BlockSetOps::Iter iter(this, startNodes);
2313 while (iter.NextElem(&bbNum))
2315 printf("BB%02u ", bbNum);
2324 //------------------------------------------------------------------------
2325 // fgDfsInvPostOrderHelper: Helper to assign post-order numbers to blocks.
2328 // block - The starting entry block
2329 // visited - The set of visited blocks
2330 // count - Pointer to the Dfs counter
2333 // Compute a non-recursive DFS traversal of the flow graph using an
2334 // evaluation stack to assign post-order numbers.
2336 void Compiler::fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count)
2338 // Assume we haven't visited this node yet (callers ensure this).
2339 assert(!BlockSetOps::IsMember(this, visited, block->bbNum));
2341 // Allocate a local stack to hold the DFS traversal actions necessary
2342 // to compute pre/post-ordering of the control flowgraph.
2343 ArrayStack<DfsBlockEntry> stack(this);
2345 // Push the first block on the stack to seed the traversal.
2346 stack.Push(DfsBlockEntry(DSS_Pre, block));
2347 // Flag the node we just visited to avoid backtracking.
2348 BlockSetOps::AddElemD(this, visited, block->bbNum);
2350 // The search is terminated once all the actions have been processed.
2351 while (stack.Height() != 0)
2353 DfsBlockEntry current = stack.Pop();
2354 BasicBlock* currentBlock = current.dfsBlock;
2356 if (current.dfsStackState == DSS_Pre)
2358 // This is a pre-visit that corresponds to the first time the
2359 // node is encountered in the spanning tree and receives pre-order
2360 // numberings. By pushing the post-action on the stack here we
2361 // are guaranteed to only process it after all of its successors
2362 // pre and post actions are processed.
2363 stack.Push(DfsBlockEntry(DSS_Post, currentBlock));
2365 unsigned cSucc = currentBlock->NumSucc(this);
2366 for (unsigned j = 0; j < cSucc; ++j)
2368 BasicBlock* succ = currentBlock->GetSucc(j, this);
2370 // If this is a node we haven't seen before, go ahead and process
2371 if (!BlockSetOps::IsMember(this, visited, succ->bbNum))
2373 // Push a pre-visit action for this successor onto the stack and
2374 // mark it as visited in case this block has multiple successors
2375 // to the same node (multi-graph).
2376 stack.Push(DfsBlockEntry(DSS_Pre, succ));
2377 BlockSetOps::AddElemD(this, visited, succ->bbNum);
2383 // This is a post-visit that corresponds to the last time the
2384 // node is visited in the spanning tree and only happens after
2385 // all descendents in the spanning tree have had pre and post
2388 assert(current.dfsStackState == DSS_Post);
2390 unsigned invCount = fgBBcount - *count + 1;
2391 assert(1 <= invCount && invCount <= fgBBNumMax);
2392 fgBBInvPostOrder[invCount] = currentBlock;
2393 currentBlock->bbDfsNum = invCount;
2399 void Compiler::fgComputeDoms()
2401 assert(!fgCheapPredsValid);
2406 printf("*************** In fgComputeDoms\n");
2409 fgVerifyHandlerTab();
2411 // Make sure that the predecessor lists are accurate.
2412 // Also check that the blocks are properly, densely numbered (so calling fgRenumberBlocks is not necessary).
2413 fgDebugCheckBBlist(true);
2415 // Assert things related to the BlockSet epoch.
2416 assert(fgBBcount == fgBBNumMax);
2417 assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);
2420 BlockSet processedBlks(BlockSetOps::MakeEmpty(this));
2422 fgBBInvPostOrder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1];
2423 memset(fgBBInvPostOrder, 0, sizeof(BasicBlock*) * (fgBBNumMax + 1));
2425 fgDfsInvPostOrder();
2426 noway_assert(fgBBInvPostOrder[0] == nullptr);
2428 // flRoot and bbRoot represent an imaginary unique entry point in the flow graph.
2429 // All the orphaned EH blocks and fgFirstBB will temporarily have its predecessors list
2430 // (with bbRoot as the only basic block in it) set as flRoot.
2431 // Later on, we clear their predecessors and let them to be nullptr again.
2432 // Since we number basic blocks starting at one, the imaginary entry block is conveniently numbered as zero.
2436 bbRoot.bbPreds = nullptr;
2438 bbRoot.bbIDom = &bbRoot;
2439 bbRoot.bbDfsNum = 0;
2441 flRoot.flNext = nullptr;
2442 flRoot.flBlock = &bbRoot;
2444 fgBBInvPostOrder[0] = &bbRoot;
2446 // Mark both bbRoot and fgFirstBB processed
2447 BlockSetOps::AddElemD(this, processedBlks, 0); // bbRoot == block #0
2448 BlockSetOps::AddElemD(this, processedBlks, 1); // fgFirstBB == block #1
2449 assert(fgFirstBB->bbNum == 1);
2451 // Special case fgFirstBB to say its IDom is bbRoot.
2452 fgFirstBB->bbIDom = &bbRoot;
2454 BasicBlock* block = nullptr;
2456 for (block = fgFirstBB->bbNext; block != nullptr; block = block->bbNext)
2458 // If any basic block has no predecessors then we flag it as processed and temporarily
2459 // mark its precedessor list to be flRoot. This makes the flowgraph connected,
2460 // a precondition that is needed by the dominance algorithm to operate properly.
2461 if (block->bbPreds == nullptr)
2463 block->bbPreds = &flRoot;
2464 block->bbIDom = &bbRoot;
2465 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2469 block->bbIDom = nullptr;
2473 // Mark the EH blocks as entry blocks and also flag them as processed.
2474 if (compHndBBtabCount > 0)
2478 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
2480 if (HBtab->HasFilter())
2482 HBtab->ebdFilter->bbIDom = &bbRoot;
2483 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdFilter->bbNum);
2485 HBtab->ebdHndBeg->bbIDom = &bbRoot;
2486 BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdHndBeg->bbNum);
2490 // Now proceed to compute the immediate dominators for each basic block.
2491 bool changed = true;
2495 for (unsigned i = 1; i <= fgBBNumMax;
2496 ++i) // Process each actual block; don't process the imaginary predecessor block.
2498 flowList* first = nullptr;
2499 BasicBlock* newidom = nullptr;
2500 block = fgBBInvPostOrder[i];
2502 // If we have a block that has bbRoot as its bbIDom
2503 // it means we flag it as processed and as an entry block so
2504 // in this case we're all set.
2505 if (block->bbIDom == &bbRoot)
2510 // Pick up the first processed predecesor of the current block.
2511 for (first = block->bbPreds; first != nullptr; first = first->flNext)
2513 if (BlockSetOps::IsMember(this, processedBlks, first->flBlock->bbNum))
2518 noway_assert(first != nullptr);
2520 // We assume the first processed predecessor will be the
2521 // immediate dominator and then compute the forward flow analysis.
2522 newidom = first->flBlock;
2523 for (flowList* p = block->bbPreds; p != nullptr; p = p->flNext)
2525 if (p->flBlock == first->flBlock)
2529 if (p->flBlock->bbIDom != nullptr)
2531 // fgIntersectDom is basically the set intersection between
2532 // the dominance sets of the new IDom and the current predecessor
2533 // Since the nodes are ordered in DFS inverse post order and
2534 // IDom induces a tree, fgIntersectDom actually computes
2535 // the lowest common ancestor in the dominator tree.
2536 newidom = fgIntersectDom(p->flBlock, newidom);
2540 // If the Immediate dominator changed, assign the new one
2541 // to the current working basic block.
2542 if (block->bbIDom != newidom)
2544 noway_assert(newidom != nullptr);
2545 block->bbIDom = newidom;
2548 BlockSetOps::AddElemD(this, processedBlks, block->bbNum);
2552 // As stated before, once we have computed immediate dominance we need to clear
2553 // all the basic blocks whose predecessor list was set to flRoot. This
2554 // reverts that and leaves the blocks the same as before.
2555 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2557 if (block->bbPreds == &flRoot)
2559 block->bbPreds = nullptr;
2563 fgCompDominatedByExceptionalEntryBlocks();
2575 fgDomBBcount = fgBBcount;
2576 assert(fgBBcount == fgBBNumMax);
2577 assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1);
2579 fgDomsComputed = true;
2582 void Compiler::fgBuildDomTree()
2590 printf("\nInside fgBuildDomTree\n");
2594 // domTree :: The dominance tree represented using adjacency lists. We use BasicBlockList to represent edges.
2595 // Indexed by basic block number.
2596 unsigned bbArraySize = fgBBNumMax + 1;
2597 BasicBlockList** domTree = new (this, CMK_DominatorMemory) BasicBlockList*[bbArraySize];
2599 fgDomTreePreOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2600 fgDomTreePostOrder = new (this, CMK_DominatorMemory) unsigned[bbArraySize];
2602 // Initialize all the data structures.
2603 for (i = 0; i < bbArraySize; ++i)
2605 domTree[i] = nullptr;
2606 fgDomTreePreOrder[i] = fgDomTreePostOrder[i] = 0;
2609 // Build the dominance tree.
2610 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2612 // If the immediate dominator is not the imaginary root (bbRoot)
2613 // we proceed to append this block to the children of the dominator node.
2614 if (block->bbIDom->bbNum != 0)
2616 int bbNum = block->bbIDom->bbNum;
2617 domTree[bbNum] = new (this, CMK_DominatorMemory) BasicBlockList(block, domTree[bbNum]);
2621 // This means this block had bbRoot set as its IDom. We clear it out
2622 // and convert the tree back to a forest.
2623 block->bbIDom = nullptr;
2630 printf("\nAfter computing the Dominance Tree:\n");
2631 fgDispDomTree(domTree);
2635 // Get the bitset that represents the roots of the dominance tree.
2636 // Something to note here is that the dominance tree has been converted from a forest to a tree
2637 // by using the bbRoot trick on fgComputeDoms. The reason we have a forest instead of a real tree
2638 // is because we treat the EH blocks as entry nodes so the real dominance tree is not necessarily connected.
2639 BlockSet_ValRet_T domTreeEntryNodes = fgDomTreeEntryNodes(domTree);
2641 // The preorder and postorder numbers.
2642 // We start from 1 to match the bbNum ordering.
2643 unsigned preNum = 1;
2644 unsigned postNum = 1;
2646 // There will be nodes in the dominance tree that will not be reachable:
2647 // the catch blocks that return since they don't have any predecessor.
2648 // For that matter we'll keep track of how many nodes we can
2649 // reach and assert at the end that we visited all of them.
2650 unsigned domTreeReachable = fgBBcount;
2652 // Once we have the dominance tree computed, we need to traverse it
2653 // to get the preorder and postorder numbers for each node. The purpose of
2654 // this is to achieve O(1) queries for of the form A dominates B.
2655 for (i = 1; i <= fgBBNumMax; ++i)
2657 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2659 if (domTree[i] == nullptr)
2661 // If this is an entry node but there's no children on this
2662 // node, it means it's unreachable so we decrement the reachable
2668 // Otherwise, we do a DFS traversal of the dominator tree.
2669 fgTraverseDomTree(i, domTree, &preNum, &postNum);
2674 noway_assert(preNum == domTreeReachable + 1);
2675 noway_assert(postNum == domTreeReachable + 1);
2677 // Once we have all the reachable nodes numbered, we proceed to
2678 // assign numbers to the non-reachable ones, just assign incrementing
2679 // values. We must reach fgBBcount at the end.
2681 for (i = 1; i <= fgBBNumMax; ++i)
2683 if (BlockSetOps::IsMember(this, domTreeEntryNodes, i))
2685 if (domTree[i] == nullptr)
2687 fgDomTreePreOrder[i] = preNum++;
2688 fgDomTreePostOrder[i] = postNum++;
2693 noway_assert(preNum == fgBBNumMax + 1);
2694 noway_assert(postNum == fgBBNumMax + 1);
2695 noway_assert(fgDomTreePreOrder[0] == 0); // Unused first element
2696 noway_assert(fgDomTreePostOrder[0] == 0); // Unused first element
2701 printf("\nAfter traversing the dominance tree:\n");
2702 printf("PreOrder:\n");
2703 for (i = 1; i <= fgBBNumMax; ++i)
2705 printf("BB%02u : %02u\n", i, fgDomTreePreOrder[i]);
2707 printf("PostOrder:\n");
2708 for (i = 1; i <= fgBBNumMax; ++i)
2710 printf("BB%02u : %02u\n", i, fgDomTreePostOrder[i]);
2716 BlockSet_ValRet_T Compiler::fgDomTreeEntryNodes(BasicBlockList** domTree)
2718 // domTreeEntryNodes :: Set that represents which basic blocks are roots of the dominator forest.
2720 BlockSet domTreeEntryNodes(BlockSetOps::MakeFull(this));
2722 // First of all we need to find all the roots of the dominance forest.
2724 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2726 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2728 BlockSetOps::RemoveElemD(this, domTreeEntryNodes, current->block->bbNum);
2732 return domTreeEntryNodes;
2736 void Compiler::fgDispDomTree(BasicBlockList** domTree)
2738 for (unsigned i = 1; i <= fgBBNumMax; ++i)
2740 if (domTree[i] != nullptr)
2742 printf("BB%02u : ", i);
2743 for (BasicBlockList* current = domTree[i]; current != nullptr; current = current->next)
2745 assert(current->block);
2746 printf("BB%02u ", current->block->bbNum);
2755 //------------------------------------------------------------------------
2756 // fgTraverseDomTree: Assign pre/post-order numbers to the dominator tree.
2759 // bbNum - The basic block number of the starting block
2760 // domTree - The dominator tree (as child block lists)
2761 // preNum - Pointer to the pre-number counter
2762 // postNum - Pointer to the post-number counter
2765 // Runs a non-recursive DFS traversal of the dominator tree using an
2766 // evaluation stack to assign pre-order and post-order numbers.
2767 // These numberings are used to provide constant time lookup for
2768 // ancestor/descendent tests between pairs of nodes in the tree.
2770 void Compiler::fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum)
2772 noway_assert(bbNum <= fgBBNumMax);
2774 // If the block preorder number is not zero it means we already visited
2775 // that node, so we skip it.
2776 if (fgDomTreePreOrder[bbNum] == 0)
2778 // If this is the first time we visit this node, both preorder and postnumber
2779 // values must be zero.
2780 noway_assert(fgDomTreePostOrder[bbNum] == 0);
2782 // Allocate a local stack to hold the Dfs traversal actions necessary
2783 // to compute pre/post-ordering of the dominator tree.
2784 ArrayStack<DfsNumEntry> stack(this);
2786 // Push the first entry number on the stack to seed the traversal.
2787 stack.Push(DfsNumEntry(DSS_Pre, bbNum));
2789 // The search is terminated once all the actions have been processed.
2790 while (stack.Height() != 0)
2792 DfsNumEntry current = stack.Pop();
2793 unsigned currentNum = current.dfsNum;
2795 if (current.dfsStackState == DSS_Pre)
2797 // This pre-visit action corresponds to the first time the
2798 // node is encountered during the spanning traversal.
2799 noway_assert(fgDomTreePreOrder[currentNum] == 0);
2800 noway_assert(fgDomTreePostOrder[currentNum] == 0);
2802 // Assign the preorder number on the first visit.
2803 fgDomTreePreOrder[currentNum] = (*preNum)++;
2805 // Push this nodes post-action on the stack such that all successors
2806 // pre-order visits occur before this nodes post-action. We will assign
2807 // its post-order numbers when we pop off the stack.
2808 stack.Push(DfsNumEntry(DSS_Post, currentNum));
2810 // For each child in the dominator tree process its pre-actions.
2811 for (BasicBlockList* child = domTree[currentNum]; child != nullptr; child = child->next)
2813 unsigned childNum = child->block->bbNum;
2815 // This is a tree so never could have been visited
2816 assert(fgDomTreePreOrder[childNum] == 0);
2818 // Push the successor in the dominator tree for pre-actions.
2819 stack.Push(DfsNumEntry(DSS_Pre, childNum));
2824 // This post-visit action corresponds to the last time the node
2825 // is encountered and only after all descendents in the spanning
2826 // tree have had pre and post-order numbers assigned.
2828 assert(current.dfsStackState == DSS_Post);
2829 assert(fgDomTreePreOrder[currentNum] != 0);
2830 assert(fgDomTreePostOrder[currentNum] == 0);
2832 // Now assign this nodes post-order number.
2833 fgDomTreePostOrder[currentNum] = (*postNum)++;
2839 // This code finds the lowest common ancestor in the
2840 // dominator tree between two basic blocks. The LCA in the Dominance tree
2841 // represents the closest dominator between the two basic blocks. Used to
2842 // adjust the IDom value in fgComputDoms.
2843 BasicBlock* Compiler::fgIntersectDom(BasicBlock* a, BasicBlock* b)
2845 BasicBlock* finger1 = a;
2846 BasicBlock* finger2 = b;
2847 while (finger1 != finger2)
2849 while (finger1->bbDfsNum > finger2->bbDfsNum)
2851 finger1 = finger1->bbIDom;
2853 while (finger2->bbDfsNum > finger1->bbDfsNum)
2855 finger2 = finger2->bbIDom;
2861 // Return a BlockSet containing all the blocks that dominate 'block'.
2862 BlockSet_ValRet_T Compiler::fgGetDominatorSet(BasicBlock* block)
2864 assert(block != nullptr);
2866 BlockSet domSet(BlockSetOps::MakeEmpty(this));
2870 BlockSetOps::AddElemD(this, domSet, block->bbNum);
2871 if (block == block->bbIDom)
2873 break; // We found a cycle in the IDom list, so we're done.
2875 block = block->bbIDom;
2876 } while (block != nullptr);
2881 /*****************************************************************************
2883 * fgComputeCheapPreds: Function called to compute the BasicBlock::bbCheapPreds lists.
2885 * No other block data is changed (e.g., bbRefs, bbFlags).
2887 * The cheap preds lists are similar to the normal (bbPreds) predecessor lists, but are cheaper to
2888 * compute and store, as follows:
2889 * 1. A flow edge is typed BasicBlockList, which only has a block pointer and 'next' pointer. It doesn't
2890 * have weights or a dup count.
2891 * 2. The preds list for a block is not sorted by block number.
2892 * 3. The predecessors of the block following a BBJ_CALLFINALLY (the corresponding BBJ_ALWAYS,
2893 * for normal, non-retless calls to the finally) are not computed.
2894 * 4. The cheap preds lists will contain duplicates if a single switch table has multiple branches
2895 * to the same block. Thus, we don't spend the time looking for duplicates for every edge we insert.
2897 void Compiler::fgComputeCheapPreds()
2899 noway_assert(!fgComputePredsDone); // We can't do this if we've got the full preds.
2900 noway_assert(fgFirstBB != nullptr);
2907 printf("\n*************** In fgComputeCheapPreds()\n");
2908 fgDispBasicBlocks();
2913 // Clear out the cheap preds lists.
2916 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
2918 switch (block->bbJumpKind)
2921 fgAddCheapPred(block->bbJumpDest, block);
2922 fgAddCheapPred(block->bbNext, block);
2925 case BBJ_CALLFINALLY:
2926 case BBJ_LEAVE: // If fgComputeCheapPreds is called before all blocks are imported, BBJ_LEAVE blocks are
2927 // still in the BB list.
2929 case BBJ_EHCATCHRET:
2930 fgAddCheapPred(block->bbJumpDest, block);
2934 fgAddCheapPred(block->bbNext, block);
2937 case BBJ_EHFILTERRET:
2938 // Connect end of filter to catch handler.
2939 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
2940 // fgComputeCheapPreds before fgImport on an ill-formed program; the problem will be detected in
2942 if (block->bbJumpDest != nullptr)
2944 fgAddCheapPred(block->bbJumpDest, block);
2950 jumpCnt = block->bbJumpSwt->bbsCount;
2951 BasicBlock** jumpTab;
2952 jumpTab = block->bbJumpSwt->bbsDstTab;
2956 fgAddCheapPred(*jumpTab, block);
2957 } while (++jumpTab, --jumpCnt);
2961 case BBJ_EHFINALLYRET: // It's expensive to compute the preds for this case, so we don't for the cheap
2968 noway_assert(!"Unexpected bbJumpKind");
2973 fgCheapPredsValid = true;
2978 printf("\n*************** After fgComputeCheapPreds()\n");
2979 fgDispBasicBlocks();
2985 /*****************************************************************************
2986 * Add 'blockPred' to the cheap predecessor list of 'block'.
2989 void Compiler::fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred)
2991 assert(!fgComputePredsDone);
2992 assert(block != nullptr);
2993 assert(blockPred != nullptr);
2995 block->bbCheapPreds = new (this, CMK_FlowList) BasicBlockList(blockPred, block->bbCheapPreds);
2997 #if MEASURE_BLOCK_SIZE
2998 genFlowNodeCnt += 1;
2999 genFlowNodeSize += sizeof(BasicBlockList);
3000 #endif // MEASURE_BLOCK_SIZE
3003 /*****************************************************************************
3004 * Remove 'blockPred' from the cheap predecessor list of 'block'.
3005 * If there are duplicate edges, only remove one of them.
3007 void Compiler::fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred)
3009 assert(!fgComputePredsDone);
3010 assert(fgCheapPredsValid);
3012 flowList* oldEdge = nullptr;
3014 assert(block != nullptr);
3015 assert(blockPred != nullptr);
3016 assert(block->bbCheapPreds != nullptr);
3018 /* Is this the first block in the pred list? */
3019 if (blockPred == block->bbCheapPreds->block)
3021 block->bbCheapPreds = block->bbCheapPreds->next;
3025 BasicBlockList* pred;
3026 for (pred = block->bbCheapPreds; pred->next != nullptr; pred = pred->next)
3028 if (blockPred == pred->next->block)
3033 noway_assert(pred->next != nullptr); // we better have found it!
3034 pred->next = pred->next->next; // splice it out
3038 void Compiler::fgRemovePreds()
3040 C_ASSERT(offsetof(BasicBlock, bbPreds) ==
3041 offsetof(BasicBlock, bbCheapPreds)); // bbPreds and bbCheapPreds are at the same place in a union,
3042 C_ASSERT(sizeof(((BasicBlock*)nullptr)->bbPreds) ==
3043 sizeof(((BasicBlock*)nullptr)->bbCheapPreds)); // and are the same size. So, this function removes both.
3045 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
3047 block->bbPreds = nullptr;
3049 fgComputePredsDone = false;
3050 fgCheapPredsValid = false;
3053 /*****************************************************************************
3055 * Function called to compute the bbPreds lists.
3057 void Compiler::fgComputePreds()
3059 noway_assert(fgFirstBB);
3066 printf("\n*************** In fgComputePreds()\n");
3067 fgDispBasicBlocks();
3072 // reset the refs count for each basic block
3074 for (block = fgFirstBB; block; block = block->bbNext)
3079 /* the first block is always reachable! */
3080 fgFirstBB->bbRefs = 1;
3082 /* Treat the initial block as a jump target */
3083 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3087 for (block = fgFirstBB; block; block = block->bbNext)
3089 switch (block->bbJumpKind)
3091 case BBJ_CALLFINALLY:
3092 if (!(block->bbFlags & BBF_RETLESS_CALL))
3094 assert(block->isBBCallAlwaysPair());
3096 /* Mark the next block as being a jump target,
3097 since the call target will return there */
3098 PREFIX_ASSUME(block->bbNext != nullptr);
3099 block->bbNext->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
3104 case BBJ_LEAVE: // Sometimes fgComputePreds is called before all blocks are imported, so BBJ_LEAVE
3105 // blocks are still in the BB list.
3108 case BBJ_EHCATCHRET:
3110 /* Mark the jump dest block as being a jump target */
3111 block->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3113 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3115 /* Is the next block reachable? */
3117 if (block->bbJumpKind != BBJ_COND)
3122 noway_assert(block->bbNext);
3124 /* Fall through, the next block is also reachable */
3129 fgAddRefPred(block->bbNext, block, nullptr, true);
3132 case BBJ_EHFILTERRET:
3134 // Connect end of filter to catch handler.
3135 // In a well-formed program, this cannot be null. Tolerate here, so that we can call
3136 // fgComputePreds before fgImport on an ill-formed program; the problem will be detected in fgImport.
3137 if (block->bbJumpDest != nullptr)
3139 fgAddRefPred(block->bbJumpDest, block, nullptr, true);
3143 case BBJ_EHFINALLYRET:
3145 /* Connect the end of the finally to the successor of
3146 the call to this finally */
3148 if (!block->hasHndIndex())
3150 NO_WAY("endfinally outside a finally/fault block.");
3153 unsigned hndIndex = block->getHndIndex();
3154 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3156 if (!ehDsc->HasFinallyOrFaultHandler())
3158 NO_WAY("endfinally outside a finally/fault block.");
3161 if (ehDsc->HasFinallyHandler())
3163 // Find all BBJ_CALLFINALLY that branched to this finally handler.
3166 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3168 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3169 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3171 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3176 noway_assert(bcall->isBBCallAlwaysPair());
3177 fgAddRefPred(bcall->bbNext, block, nullptr, true);
3189 jumpCnt = block->bbJumpSwt->bbsCount;
3190 BasicBlock** jumpTab;
3191 jumpTab = block->bbJumpSwt->bbsDstTab;
3195 /* Mark the target block as being a jump target */
3196 (*jumpTab)->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3198 fgAddRefPred(*jumpTab, block, nullptr, true);
3199 } while (++jumpTab, --jumpCnt);
3204 noway_assert(!"Unexpected bbJumpKind");
3209 for (unsigned EHnum = 0; EHnum < compHndBBtabCount; EHnum++)
3211 EHblkDsc* ehDsc = ehGetDsc(EHnum);
3213 if (ehDsc->HasFilter())
3215 ehDsc->ebdFilter->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3217 // The first block of a filter has an artifical extra refcount.
3218 ehDsc->ebdFilter->bbRefs++;
3221 ehDsc->ebdHndBeg->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
3223 // The first block of a handler has an artificial extra refcount.
3224 ehDsc->ebdHndBeg->bbRefs++;
3228 fgComputePredsDone = true;
3233 printf("\n*************** After fgComputePreds()\n");
3234 fgDispBasicBlocks();
3240 unsigned Compiler::fgNSuccsOfFinallyRet(BasicBlock* block)
3244 fgSuccOfFinallyRetWork(block, ~0, &bb, &res);
3248 BasicBlock* Compiler::fgSuccOfFinallyRet(BasicBlock* block, unsigned i)
3252 fgSuccOfFinallyRetWork(block, i, &bb, &res);
3256 void Compiler::fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres)
3258 assert(block->hasHndIndex()); // Otherwise, endfinally outside a finally/fault block?
3260 unsigned hndIndex = block->getHndIndex();
3261 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
3263 assert(ehDsc->HasFinallyOrFaultHandler()); // Otherwise, endfinally outside a finally/fault block.
3266 unsigned succNum = 0;
3268 if (ehDsc->HasFinallyHandler())
3272 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
3274 BasicBlock* finBeg = ehDsc->ebdHndBeg;
3276 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
3278 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
3283 assert(bcall->isBBCallAlwaysPair());
3287 *bres = bcall->bbNext;
3293 assert(i == ~0u || ehDsc->HasFaultHandler()); // Should reach here only for fault blocks.
3300 Compiler::SwitchUniqueSuccSet Compiler::GetDescriptorForSwitch(BasicBlock* switchBlk)
3302 assert(switchBlk->bbJumpKind == BBJ_SWITCH);
3303 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3304 SwitchUniqueSuccSet res;
3305 if (switchMap->Lookup(switchBlk, &res))
3311 // We must compute the descriptor. Find which are dups, by creating a bit set with the unique successors.
3312 // We create a temporary bitset of blocks to compute the unique set of successor blocks,
3313 // since adding a block's number twice leaves just one "copy" in the bitset. Note that
3314 // we specifically don't use the BlockSet type, because doing so would require making a
3315 // call to EnsureBasicBlockEpoch() to make sure the epoch is up-to-date. However, that
3316 // can create a new epoch, thus invalidating all existing BlockSet objects, such as
3317 // reachability information stored in the blocks. To avoid that, we just use a local BitVec.
3319 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
3320 BitVec uniqueSuccBlocks(BitVecOps::MakeEmpty(&blockVecTraits));
3321 BasicBlock** jumpTable = switchBlk->bbJumpSwt->bbsDstTab;
3322 unsigned jumpCount = switchBlk->bbJumpSwt->bbsCount;
3323 for (unsigned i = 0; i < jumpCount; i++)
3325 BasicBlock* targ = jumpTable[i];
3326 BitVecOps::AddElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3328 // Now we have a set of unique successors.
3329 unsigned numNonDups = BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks);
3331 BasicBlock** nonDups = new (getAllocator()) BasicBlock*[numNonDups];
3333 unsigned nonDupInd = 0;
3334 // At this point, all unique targets are in "uniqueSuccBlocks". As we encounter each,
3335 // add to nonDups, remove from "uniqueSuccBlocks".
3336 for (unsigned i = 0; i < jumpCount; i++)
3338 BasicBlock* targ = jumpTable[i];
3339 if (BitVecOps::IsMember(&blockVecTraits, uniqueSuccBlocks, targ->bbNum))
3341 nonDups[nonDupInd] = targ;
3343 BitVecOps::RemoveElemD(&blockVecTraits, uniqueSuccBlocks, targ->bbNum);
3347 assert(nonDupInd == numNonDups);
3348 assert(BitVecOps::Count(&blockVecTraits, uniqueSuccBlocks) == 0);
3349 res.numDistinctSuccs = numNonDups;
3350 res.nonDuplicates = nonDups;
3351 switchMap->Set(switchBlk, res);
3356 void Compiler::SwitchUniqueSuccSet::UpdateTarget(CompAllocator* alloc,
3357 BasicBlock* switchBlk,
3361 assert(switchBlk->bbJumpKind == BBJ_SWITCH); // Precondition.
3362 unsigned jmpTabCnt = switchBlk->bbJumpSwt->bbsCount;
3363 BasicBlock** jmpTab = switchBlk->bbJumpSwt->bbsDstTab;
3365 // Is "from" still in the switch table (because it had more than one entry before?)
3366 bool fromStillPresent = false;
3367 for (unsigned i = 0; i < jmpTabCnt; i++)
3369 if (jmpTab[i] == from)
3371 fromStillPresent = true;
3376 // Is "to" already in "this"?
3377 bool toAlreadyPresent = false;
3378 for (unsigned i = 0; i < numDistinctSuccs; i++)
3380 if (nonDuplicates[i] == to)
3382 toAlreadyPresent = true;
3388 // If "from" is still present, and "to" is already present, do nothing
3389 // If "from" is still present, and "to" is not, must reallocate to add an entry.
3390 // If "from" is not still present, and "to" is not present, write "to" where "from" was.
3391 // If "from" is not still present, but "to" is present, remove "from".
3392 if (fromStillPresent && toAlreadyPresent)
3396 else if (fromStillPresent && !toAlreadyPresent)
3398 // reallocate to add an entry
3399 BasicBlock** newNonDups = new (alloc) BasicBlock*[numDistinctSuccs + 1];
3400 memcpy(newNonDups, nonDuplicates, numDistinctSuccs * sizeof(BasicBlock*));
3401 newNonDups[numDistinctSuccs] = to;
3403 nonDuplicates = newNonDups;
3405 else if (!fromStillPresent && !toAlreadyPresent)
3408 // write "to" where "from" was
3409 bool foundFrom = false;
3411 for (unsigned i = 0; i < numDistinctSuccs; i++)
3413 if (nonDuplicates[i] == from)
3415 nonDuplicates[i] = to;
3426 assert(!fromStillPresent && toAlreadyPresent);
3429 bool foundFrom = false;
3431 for (unsigned i = 0; i < numDistinctSuccs; i++)
3433 if (nonDuplicates[i] == from)
3435 nonDuplicates[i] = nonDuplicates[numDistinctSuccs - 1];
3447 /*****************************************************************************
3449 * Simple utility function to remove an entry for a block in the switch desc
3450 * map. So it can be called from other phases.
3453 void Compiler::fgInvalidateSwitchDescMapEntry(BasicBlock* block)
3455 // Check if map has no entries yet.
3456 if (m_switchDescMap != nullptr)
3458 m_switchDescMap->Remove(block);
3462 void Compiler::UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to)
3464 if (m_switchDescMap == nullptr)
3466 return; // No mappings, nothing to do.
3470 BlockToSwitchDescMap* switchMap = GetSwitchDescMap();
3471 SwitchUniqueSuccSet* res = switchMap->LookupPointer(switchBlk);
3474 // If no result, nothing to do. Otherwise, update it.
3475 res->UpdateTarget(getAllocator(), switchBlk, from, to);
3479 /*****************************************************************************
3480 * For a block that is in a handler region, find the first block of the most-nested
3481 * handler containing the block.
3483 BasicBlock* Compiler::fgFirstBlockOfHandler(BasicBlock* block)
3485 assert(block->hasHndIndex());
3486 return ehGetDsc(block->getHndIndex())->ebdHndBeg;
3489 /*****************************************************************************
3491 * Function called to find back edges and return blocks and mark them as needing GC Polls. This marks all
3494 void Compiler::fgMarkGCPollBlocks()
3496 if (GCPOLL_NONE == opts.compGCPollType)
3502 /* Check that the flowgraph data (bbNum, bbRefs, bbPreds) is up-to-date */
3503 fgDebugCheckBBlist();
3508 // Return blocks always need GC polls. In addition, all back edges (including those from switch
3509 // statements) need GC polls. The poll is on the block with the outgoing back edge (or ret), rather than
3510 // on the destination or on the edge itself.
3511 for (block = fgFirstBB; block; block = block->bbNext)
3513 bool blockNeedsPoll = false;
3514 switch (block->bbJumpKind)
3518 blockNeedsPoll = (block->bbJumpDest->bbNum <= block->bbNum);
3522 blockNeedsPoll = true;
3527 jumpCnt = block->bbJumpSwt->bbsCount;
3528 BasicBlock** jumpTab;
3529 jumpTab = block->bbJumpSwt->bbsDstTab;
3533 if ((*jumpTab)->bbNum <= block->bbNum)
3535 blockNeedsPoll = true;
3538 } while (++jumpTab, --jumpCnt);
3547 block->bbFlags |= BBF_NEEDS_GCPOLL;
3552 void Compiler::fgInitBlockVarSets()
3554 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3556 block->InitVarSets(this);
3559 #ifdef LEGACY_BACKEND
3560 // QMarks are much like blocks, and need their VarSets initialized.
3561 assert(!compIsForInlining());
3562 for (unsigned i = 0; i < compQMarks->Size(); i++)
3564 GenTree* qmark = compQMarks->Get(i);
3565 // Perhaps the gtOper of a QMark node was changed to something else since it was created and put on this list.
3566 // So can't hurt to check.
3567 if (qmark->OperGet() == GT_QMARK)
3569 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtThenLiveSet, VarSetOps::UninitVal());
3570 VarSetOps::AssignAllowUninitRhs(this, qmark->gtQmark.gtElseLiveSet, VarSetOps::UninitVal());
3573 #endif // LEGACY_BACKEND
3574 fgBBVarSetsInited = true;
3577 /*****************************************************************************
3579 * The following does the final pass on BBF_NEEDS_GCPOLL and then actually creates the GC Polls.
3581 void Compiler::fgCreateGCPolls()
3583 if (GCPOLL_NONE == opts.compGCPollType)
3588 bool createdPollBlocks = false;
3593 printf("*************** In fgCreateGCPolls() for %s\n", info.compFullName);
3597 if (!(opts.MinOpts() || opts.compDbgCode))
3599 // Remove polls from well formed loops with a constant upper bound.
3600 for (unsigned lnum = 0; lnum < optLoopCount; ++lnum)
3602 // Look for constant counted loops that run for a short duration. This logic is very similar to
3603 // what's in code:Compiler::optUnrollLoops, since they have similar constraints. However, this
3604 // logic is much more permissive since we're not doing a complex transformation.
3607 * I feel bad cloning so much logic from optUnrollLoops
3610 // Filter out loops not meeting the obvious preconditions.
3612 if (optLoopTable[lnum].lpFlags & LPFLG_REMOVED)
3617 if (!(optLoopTable[lnum].lpFlags & LPFLG_CONST))
3622 BasicBlock* head = optLoopTable[lnum].lpHead;
3623 BasicBlock* bottom = optLoopTable[lnum].lpBottom;
3625 // Loops dominated by GC_SAFE_POINT won't have this set.
3626 if (!(bottom->bbFlags & BBF_NEEDS_GCPOLL))
3631 /* Get the loop data:
3635 - iterator increment
3636 - increment operation type (i.e. ASG_ADD, ASG_SUB, etc...)
3637 - loop test type (i.e. GT_GE, GT_LT, etc...)
3640 int lbeg = optLoopTable[lnum].lpConstInit;
3641 int llim = optLoopTable[lnum].lpConstLimit();
3642 genTreeOps testOper = optLoopTable[lnum].lpTestOper();
3644 int lvar = optLoopTable[lnum].lpIterVar();
3645 int iterInc = optLoopTable[lnum].lpIterConst();
3646 genTreeOps iterOper = optLoopTable[lnum].lpIterOper();
3648 var_types iterOperType = optLoopTable[lnum].lpIterOperType();
3649 bool unsTest = (optLoopTable[lnum].lpTestTree->gtFlags & GTF_UNSIGNED) != 0;
3650 if (lvaTable[lvar].lvAddrExposed)
3651 { // Can't reason about the value of the iteration variable.
3657 /* Find the number of iterations - the function returns false if not a constant number */
3659 if (!optComputeLoopRep(lbeg, llim, iterInc, iterOper, iterOperType, testOper, unsTest,
3660 // The value here doesn't matter for this variation of the optimization
3666 printf("Could not compute loop iterations for loop from BB%02u to BB%02u", head->bbNum,
3670 (void)head; // suppress gcc error.
3675 /* Forget it if there are too many repetitions or not a constant loop */
3677 static const unsigned ITER_LIMIT = 256;
3678 if (totalIter > ITER_LIMIT)
3683 // It is safe to elminate the poll from this loop.
3684 bottom->bbFlags &= ~BBF_NEEDS_GCPOLL;
3689 printf("Removing poll in block BB%02u because it forms a bounded counted loop\n", bottom->bbNum);
3695 // Final chance to optimize the polls. Move all polls in loops from the bottom of the loop up to the
3696 // loop head. Also eliminate all epilog polls in non-leaf methods. This only works if we have dominator
3700 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
3702 if (!(block->bbFlags & BBF_NEEDS_GCPOLL))
3707 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
3709 // make sure that this is loop-like
3710 if (!fgReachable(block->bbJumpDest, block))
3712 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3716 printf("Removing poll in block BB%02u because it is not loop\n", block->bbNum);
3722 else if (!(block->bbJumpKind == BBJ_RETURN || block->bbJumpKind == BBJ_SWITCH))
3724 noway_assert(!"GC Poll on a block that has no control transfer.");
3728 printf("Removing poll in block BB%02u because it is not a jump\n", block->bbNum);
3731 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3735 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3736 // Clean those up now.
3738 if (block->bbFlags & BBF_GC_SAFE_POINT)
3743 printf("Removing poll in return block BB%02u because it is GC Safe\n", block->bbNum);
3746 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3750 if (block->bbJumpKind == BBJ_RETURN)
3752 if (!optReachWithoutCall(fgFirstBB, block))
3754 // check to see if there is a call along the path between the first block and the return
3756 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
3760 printf("Removing poll in return block BB%02u because it dominated by a call\n", block->bbNum);
3769 noway_assert(!fgGCPollsCreated);
3771 fgGCPollsCreated = true;
3773 // Walk through the blocks and hunt for a block that has BBF_NEEDS_GCPOLL
3774 for (block = fgFirstBB; block; block = block->bbNext)
3776 // Because of block compaction, it's possible to end up with a block that is both poll and safe.
3777 // And if !fgDomsComputed, we won't have cleared them, so skip them now
3778 if (!(block->bbFlags & BBF_NEEDS_GCPOLL) || (block->bbFlags & BBF_GC_SAFE_POINT))
3783 // This block needs a poll. We either just insert a callout or we split the block and inline part of
3784 // the test. This depends on the value of opts.compGCPollType.
3786 // If we're doing GCPOLL_CALL, just insert a GT_CALL node before the last node in the block.
3787 CLANG_FORMAT_COMMENT_ANCHOR;
3790 switch (block->bbJumpKind)
3798 noway_assert(!"Unknown block type for BBF_NEEDS_GCPOLL");
3802 noway_assert(opts.compGCPollType);
3804 GCPollType pollType = opts.compGCPollType;
3805 // pollType is set to either CALL or INLINE at this point. Below is the list of places where we
3806 // can't or don't want to emit an inline check. Check all of those. If after all of that we still
3807 // have INLINE, then emit an inline check.
3809 if (opts.MinOpts() || opts.compDbgCode)
3814 printf("Selecting CALL poll in block BB%02u because of debug/minopts\n", block->bbNum);
3818 // Don't split blocks and create inlined polls unless we're optimizing.
3819 pollType = GCPOLL_CALL;
3821 else if (genReturnBB == block)
3826 printf("Selecting CALL poll in block BB%02u because it is the single return block\n", block->bbNum);
3830 // we don't want to split the single return block
3831 pollType = GCPOLL_CALL;
3833 else if (BBJ_SWITCH == block->bbJumpKind)
3838 printf("Selecting CALL poll in block BB%02u because it is a loop formed by a SWITCH\n", block->bbNum);
3842 // I don't want to deal with all the outgoing edges of a switch block.
3843 pollType = GCPOLL_CALL;
3846 // TODO-Cleanup: potentially don't split if we're in an EH region.
3848 createdPollBlocks |= fgCreateGCPoll(pollType, block);
3851 // If we split a block to create a GC Poll, then rerun fgReorderBlocks to push the rarely run blocks out
3852 // past the epilog. We should never split blocks unless we're optimizing.
3853 if (createdPollBlocks)
3855 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
3860 /*****************************************************************************
3862 * Actually create a GCPoll in the given block. Returns true if it created
3866 bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block)
3868 assert(!(block->bbFlags & BBF_GC_SAFE_POINT));
3869 bool createdPollBlocks;
3872 void* pAddrOfCaptureThreadGlobal;
3874 addrTrap = info.compCompHnd->getAddrOfCaptureThreadGlobal(&pAddrOfCaptureThreadGlobal);
3876 #ifdef ENABLE_FAST_GCPOLL_HELPER
3877 // I never want to split blocks if we've got two indirections here.
3878 // This is a size trade-off assuming the VM has ENABLE_FAST_GCPOLL_HELPER.
3879 // So don't do it when that is off
3880 if (pAddrOfCaptureThreadGlobal != NULL)
3882 pollType = GCPOLL_CALL;
3884 #endif // ENABLE_FAST_GCPOLL_HELPER
3886 if (GCPOLL_CALL == pollType)
3888 createdPollBlocks = false;
3889 GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3890 #ifdef LEGACY_BACKEND
3891 call->gtFlags |= GTF_CALL_REG_SAVE;
3892 #endif // LEGACY_BACKEND
3894 // for BBJ_ALWAYS I don't need to insert it before the condition. Just append it.
3895 if (block->bbJumpKind == BBJ_ALWAYS)
3897 fgInsertStmtAtEnd(block, call);
3901 GenTreeStmt* newStmt = fgInsertStmtNearEnd(block, call);
3902 // For DDB156656, we need to associate the GC Poll with the IL offset (and therefore sequence
3903 // point) of the tree before which we inserted the poll. One example of when this is a
3914 // If we take the if statement at 1, we encounter a jump at 2. This jumps over the else
3915 // and lands at 4. 4 is where we inserted the gcpoll. However, that is associated with
3916 // the sequence point a 3. Therefore, the debugger displays the wrong source line at the
3917 // gc poll location.
3919 // More formally, if control flow targets an instruction, that instruction must be the
3920 // start of a new sequence point.
3921 if (newStmt->gtNext)
3923 // Is it possible for gtNext to be NULL?
3924 noway_assert(newStmt->gtNext->gtOper == GT_STMT);
3925 newStmt->gtStmtILoffsx = newStmt->gtNextStmt->gtStmtILoffsx;
3929 block->bbFlags |= BBF_GC_SAFE_POINT;
3933 printf("*** creating GC Poll in block BB%02u\n", block->bbNum);
3934 gtDispTreeList(block->bbTreeList);
3940 createdPollBlocks = true;
3941 // if we're doing GCPOLL_INLINE, then:
3942 // 1) Create two new blocks: Poll and Bottom. The original block is called Top.
3944 // I want to create:
3945 // top -> poll -> bottom (lexically)
3946 // so that we jump over poll to get to bottom.
3947 BasicBlock* top = block;
3948 BasicBlock* poll = fgNewBBafter(BBJ_NONE, top, true);
3949 BasicBlock* bottom = fgNewBBafter(top->bbJumpKind, poll, true);
3950 BBjumpKinds oldJumpKind = top->bbJumpKind;
3952 // Update block flags
3953 const unsigned __int64 originalFlags = top->bbFlags | BBF_GC_SAFE_POINT;
3955 // Unlike Fei's inliner from puclr, I'm allowed to split loops.
3956 // And we keep a few other flags...
3957 noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~(BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1))) == 0);
3958 top->bbFlags = originalFlags & (~BBF_SPLIT_LOST | BBF_GC_SAFE_POINT);
3959 bottom->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3960 bottom->inheritWeight(top);
3961 poll->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT);
3963 // 9) Mark Poll as rarely run.
3964 poll->bbSetRunRarely();
3966 // 5) Bottom gets all the outgoing edges and inherited flags of Original.
3967 bottom->bbJumpDest = top->bbJumpDest;
3969 // 2) Add a GC_CALL node to Poll.
3970 GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID);
3971 #ifdef LEGACY_BACKEND
3972 call->gtFlags |= GTF_CALL_REG_SAVE;
3973 #endif // LEGACY_BACKEND
3974 fgInsertStmtAtEnd(poll, call);
3976 // 3) Remove the last statement from Top and add it to Bottom.
3977 if (oldJumpKind != BBJ_ALWAYS)
3979 // if I'm always jumping to the target, then this is not a condition that needs moving.
3980 GenTreeStmt* stmt = top->firstStmt();
3981 while (stmt->gtNext)
3983 stmt = stmt->gtNextStmt;
3985 fgRemoveStmt(top, stmt);
3986 fgInsertStmtAtEnd(bottom, stmt);
3989 // for BBJ_ALWAYS blocks, bottom is an empty block.
3991 // 4) Create a GT_EQ node that checks against g_TrapReturningThreads. True jumps to Bottom,
3992 // false falls through to poll. Add this to the end of Top. Top is now BBJ_COND. Bottom is
3993 // now a jump target
3994 CLANG_FORMAT_COMMENT_ANCHOR;
3996 #ifdef ENABLE_FAST_GCPOLL_HELPER
3997 // Prefer the fast gc poll helepr over the double indirection
3998 noway_assert(pAddrOfCaptureThreadGlobal == nullptr);
4001 GenTree* value; // The value of g_TrapReturningThreads
4002 if (pAddrOfCaptureThreadGlobal != nullptr)
4004 // Use a double indirection
4006 gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pAddrOfCaptureThreadGlobal, GTF_ICON_PTR_HDL, true);
4008 value = gtNewOperNode(GT_IND, TYP_INT, addr);
4009 // This indirection won't cause an exception.
4010 value->gtFlags |= GTF_IND_NONFAULTING;
4014 // Use a single indirection
4015 value = gtNewIndOfIconHandleNode(TYP_INT, (size_t)addrTrap, GTF_ICON_PTR_HDL, false);
4018 // Treat the reading of g_TrapReturningThreads as volatile.
4019 value->gtFlags |= GTF_IND_VOLATILE;
4021 // Compare for equal to zero
4022 GenTree* trapRelop = gtNewOperNode(GT_EQ, TYP_INT, value, gtNewIconNode(0, TYP_INT));
4024 trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE;
4025 GenTree* trapCheck = gtNewOperNode(GT_JTRUE, TYP_VOID, trapRelop);
4026 fgInsertStmtAtEnd(top, trapCheck);
4027 top->bbJumpDest = bottom;
4028 top->bbJumpKind = BBJ_COND;
4029 bottom->bbFlags |= BBF_JMP_TARGET;
4031 // 7) Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor.
4032 fgAddRefPred(bottom, poll);
4033 fgAddRefPred(bottom, top);
4034 fgAddRefPred(poll, top);
4036 // 8) Replace Top with Bottom in the predecessor list of all outgoing edges from Bottom (1 for
4037 // jumps, 2 for conditional branches, N for switches).
4038 switch (oldJumpKind)
4044 // replace predecessor in the fall through block.
4045 noway_assert(bottom->bbNext);
4046 fgReplacePred(bottom->bbNext, top, bottom);
4048 // fall through for the jump target
4052 fgReplacePred(bottom->bbJumpDest, top, bottom);
4055 NO_WAY("SWITCH should be a call rather than an inlined poll.");
4058 NO_WAY("Unknown block type for updating predecessor lists.");
4061 top->bbFlags &= ~BBF_NEEDS_GCPOLL;
4062 noway_assert(!(poll->bbFlags & BBF_NEEDS_GCPOLL));
4063 noway_assert(!(bottom->bbFlags & BBF_NEEDS_GCPOLL));
4065 if (compCurBB == top)
4073 printf("*** creating inlined GC Poll in top block BB%02u\n", top->bbNum);
4074 gtDispTreeList(top->bbTreeList);
4075 printf(" poll block is BB%02u\n", poll->bbNum);
4076 gtDispTreeList(poll->bbTreeList);
4077 printf(" bottom block is BB%02u\n", bottom->bbNum);
4078 gtDispTreeList(bottom->bbTreeList);
4083 return createdPollBlocks;
4086 /*****************************************************************************
4088 * The following helps find a basic block given its PC offset.
4091 void Compiler::fgInitBBLookup()
4093 BasicBlock** dscBBptr;
4094 BasicBlock* tmpBBdesc;
4096 /* Allocate the basic block table */
4098 dscBBptr = fgBBs = new (this, CMK_BasicBlock) BasicBlock*[fgBBcount];
4100 /* Walk all the basic blocks, filling in the table */
4102 for (tmpBBdesc = fgFirstBB; tmpBBdesc; tmpBBdesc = tmpBBdesc->bbNext)
4104 *dscBBptr++ = tmpBBdesc;
4107 noway_assert(dscBBptr == fgBBs + fgBBcount);
4110 BasicBlock* Compiler::fgLookupBB(unsigned addr)
4115 /* Do a binary search */
4117 for (lo = 0, hi = fgBBcount - 1;;)
4127 unsigned mid = (lo + hi) / 2;
4128 BasicBlock* dsc = fgBBs[mid];
4130 // We introduce internal blocks for BBJ_CALLFINALLY. Skip over these.
4132 while (dsc->bbFlags & BBF_INTERNAL)
4137 // We skipped over too many, Set hi back to the original mid - 1
4141 mid = (lo + hi) / 2;
4147 unsigned pos = dsc->bbCodeOffs;
4151 if ((lo == hi) && (lo == (fgBBcount - 1)))
4153 noway_assert(addr == dsc->bbCodeOffsEnd);
4154 return nullptr; // NULL means the end of method
4169 printf("ERROR: Couldn't find basic block at offset %04X\n", addr);
4171 NO_WAY("fgLookupBB failed.");
4174 /*****************************************************************************
4176 * The 'jump target' array uses the following flags to indicate what kind
4177 * of label is present.
4180 #define JT_NONE 0x00 // This IL offset is never used
4181 #define JT_ADDR 0x01 // merely make sure this is an OK address
4182 #define JT_JUMP 0x02 // 'normal' jump target
4183 #define JT_MULTI 0x04 // target of multiple jumps
4185 inline void Compiler::fgMarkJumpTarget(BYTE* jumpTarget, unsigned offs)
4187 /* Make sure we set JT_MULTI if target of multiple jumps */
4189 noway_assert(JT_MULTI == JT_JUMP << 1);
4191 jumpTarget[offs] |= (jumpTarget[offs] & JT_JUMP) << 1 | JT_JUMP;
4194 //------------------------------------------------------------------------
4195 // FgStack: simple stack model for the inlinee's evaluation stack.
4197 // Model the inputs available to various operations in the inline body.
4198 // Tracks constants, arguments, array lengths.
4203 FgStack() : slot0(SLOT_INVALID), slot1(SLOT_INVALID), depth(0)
4218 Push(SLOT_CONSTANT);
4222 Push(SLOT_ARRAYLEN);
4224 void PushArgument(unsigned arg)
4226 Push(SLOT_ARGUMENT + arg);
4228 unsigned GetSlot0() const
4233 unsigned GetSlot1() const
4238 static bool IsConstant(unsigned value)
4240 return value == SLOT_CONSTANT;
4242 static bool IsArrayLen(unsigned value)
4244 return value == SLOT_ARRAYLEN;
4246 static bool IsArgument(unsigned value)
4248 return value >= SLOT_ARGUMENT;
4250 static unsigned SlotTypeToArgNum(unsigned value)
4252 assert(IsArgument(value));
4253 return value - SLOT_ARGUMENT;
4255 bool IsStackTwoDeep() const
4259 bool IsStackOneDeep() const
4263 bool IsStackAtLeastOneDeep() const
4271 SLOT_INVALID = UINT_MAX,
4300 //------------------------------------------------------------------------
4301 // fgFindJumpTargets: walk the IL stream, determining jump target offsets
4304 // codeAddr - base address of the IL code buffer
4305 // codeSize - number of bytes in the IL code buffer
4306 // jumpTarget - [OUT] byte array for flagging jump targets
4309 // If inlining or prejitting the root, this method also makes
4310 // various observations about the method that factor into inline
4313 // May throw an exception if the IL is malformed.
4315 // jumpTarget[N] is set to a JT_* value if IL offset N is a
4316 // jump target in the method.
4318 // Also sets lvAddrExposed and lvHasILStoreOp, ilHasMultipleILStoreOp in lvaTable[].
4321 #pragma warning(push)
4322 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
4325 void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
4327 const BYTE* codeBegp = codeAddr;
4328 const BYTE* codeEndp = codeAddr + codeSize;
4330 bool seenJump = false;
4331 var_types varType = DUMMY_INIT(TYP_UNDEF); // TYP_ type
4332 typeInfo ti; // Verifier type.
4333 bool typeIsNormed = false;
4334 FgStack pushedStack;
4335 const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
4336 const bool makeInlineObservations = (compInlineResult != nullptr);
4337 const bool isInlining = compIsForInlining();
4338 unsigned retBlocks = 0;
4340 if (makeInlineObservations)
4342 // Observe force inline state and code size.
4343 compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
4344 compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
4346 // Determine if call site is within a try.
4347 if (isInlining && impInlineInfo->iciBlock->hasTryIndex())
4349 compInlineResult->Note(InlineObservation::CALLSITE_IN_TRY_REGION);
4352 // Determine if the call site is in a loop.
4353 if (isInlining && ((impInlineInfo->iciBlock->bbFlags & BBF_BACKWARD_JUMP) != 0))
4355 compInlineResult->Note(InlineObservation::CALLSITE_IN_LOOP);
4360 // If inlining, this method should still be a candidate.
4363 assert(compInlineResult->IsCandidate());
4368 // note that we're starting to look at the opcodes.
4369 compInlineResult->Note(InlineObservation::CALLEE_BEGIN_OPCODE_SCAN);
4372 while (codeAddr < codeEndp)
4374 OPCODE opcode = (OPCODE)getU1LittleEndian(codeAddr);
4375 codeAddr += sizeof(__int8);
4377 typeIsNormed = false;
4381 if ((unsigned)opcode >= CEE_COUNT)
4383 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4386 if ((opcode >= CEE_LDARG_0 && opcode <= CEE_STLOC_S) || (opcode >= CEE_LDARG && opcode <= CEE_STLOC))
4391 if (makeInlineObservations && (opcode >= CEE_LDNULL) && (opcode <= CEE_LDC_R8))
4393 pushedStack.PushConstant();
4396 unsigned sz = opcodeSizes[opcode];
4402 if (codeAddr >= codeEndp)
4406 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
4407 codeAddr += sizeof(__int8);
4419 BADCODE3("Illegal opcode", ": %02X", (int)opcode);
4425 // There has to be code after the call, otherwise the inlinee is unverifiable.
4429 noway_assert(codeAddr < codeEndp - sz);
4432 // If the method has a call followed by a ret, assume that
4433 // it is a wrapper method.
4434 if (makeInlineObservations)
4436 if ((OPCODE)getU1LittleEndian(codeAddr + sz) == CEE_RET)
4438 compInlineResult->Note(InlineObservation::CALLEE_LOOKS_LIKE_WRAPPER);
4475 if (codeAddr > codeEndp - sz)
4480 // Compute jump target address
4481 signed jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
4483 if (compIsForInlining() && jmpDist == 0 &&
4484 (opcode == CEE_LEAVE || opcode == CEE_LEAVE_S || opcode == CEE_BR || opcode == CEE_BR_S))
4489 unsigned jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
4491 // Make sure target is reasonable
4492 if (jmpAddr >= codeSize)
4494 BADCODE3("code jumps to outer space", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4497 // Mark the jump target
4498 fgMarkJumpTarget(jumpTarget, jmpAddr);
4500 // See if jump might be sensitive to inlining
4501 if (makeInlineObservations && (opcode != CEE_BR_S) && (opcode != CEE_BR))
4503 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4512 if (makeInlineObservations)
4514 compInlineResult->Note(InlineObservation::CALLEE_HAS_SWITCH);
4516 // Fail fast, if we're inlining and can't handle this.
4517 if (isInlining && compInlineResult->IsFailure())
4523 // Make sure we don't go past the end reading the number of cases
4524 if (codeAddr > codeEndp - sizeof(DWORD))
4529 // Read the number of cases
4530 unsigned jmpCnt = getU4LittleEndian(codeAddr);
4531 codeAddr += sizeof(DWORD);
4533 if (jmpCnt > codeSize / sizeof(DWORD))
4538 // Find the end of the switch table
4539 unsigned jmpBase = (unsigned)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
4541 // Make sure there is more code after the switch
4542 if (jmpBase >= codeSize)
4547 // jmpBase is also the target of the default case, so mark it
4548 fgMarkJumpTarget(jumpTarget, jmpBase);
4550 // Process table entries
4553 unsigned jmpAddr = jmpBase + getI4LittleEndian(codeAddr);
4556 if (jmpAddr >= codeSize)
4558 BADCODE3("jump target out of range", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4561 fgMarkJumpTarget(jumpTarget, jmpAddr);
4565 // We've advanced past all the bytes in this instruction
4571 case CEE_CONSTRAINED:
4576 if (codeAddr >= codeEndp)
4586 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4588 if (codeAddr > codeEndp - sz)
4593 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4597 if (varNum < impInlineInfo->argCnt)
4599 impInlineInfo->inlArgInfo[varNum].argHasStargOp = true;
4604 // account for possible hidden param
4605 varNum = compMapILargNum(varNum);
4607 // This check is only intended to prevent an AV. Bad varNum values will later
4608 // be handled properly by the verifier.
4609 if (varNum < lvaTableCnt)
4611 // In non-inline cases, note written-to arguments.
4612 lvaTable[varNum].lvHasILStoreOp = 1;
4622 varNum = (opcode - CEE_STLOC_0);
4628 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4630 if (codeAddr > codeEndp - sz)
4635 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4640 InlLclVarInfo& lclInfo = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt];
4642 if (lclInfo.lclHasStlocOp)
4644 lclInfo.lclHasMultipleStlocOp = 1;
4648 lclInfo.lclHasStlocOp = 1;
4653 varNum += info.compArgsCount;
4655 // This check is only intended to prevent an AV. Bad varNum values will later
4656 // be handled properly by the verifier.
4657 if (varNum < lvaTableCnt)
4659 // In non-inline cases, note written-to locals.
4660 if (lvaTable[varNum].lvHasILStoreOp)
4662 lvaTable[varNum].lvHasMultipleILStoreOp = 1;
4666 lvaTable[varNum].lvHasILStoreOp = 1;
4678 // Handle address-taken args or locals
4679 noway_assert(sz == sizeof(BYTE) || sz == sizeof(WORD));
4681 if (codeAddr > codeEndp - sz)
4686 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4690 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4692 varType = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclTypeInfo;
4693 ti = impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclVerTypeInfo;
4695 impInlineInfo->lclVarInfo[varNum + impInlineInfo->argCnt].lclHasLdlocaOp = true;
4699 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4701 varType = impInlineInfo->lclVarInfo[varNum].lclTypeInfo;
4702 ti = impInlineInfo->lclVarInfo[varNum].lclVerTypeInfo;
4704 impInlineInfo->inlArgInfo[varNum].argHasLdargaOp = true;
4706 pushedStack.PushArgument(varNum);
4711 if (opcode == CEE_LDLOCA || opcode == CEE_LDLOCA_S)
4713 if (varNum >= info.compMethodInfo->locals.numArgs)
4715 BADCODE("bad local number");
4718 varNum += info.compArgsCount;
4722 noway_assert(opcode == CEE_LDARGA || opcode == CEE_LDARGA_S);
4724 if (varNum >= info.compILargsCount)
4726 BADCODE("bad argument number");
4729 varNum = compMapILargNum(varNum); // account for possible hidden param
4732 varType = (var_types)lvaTable[varNum].lvType;
4733 ti = lvaTable[varNum].lvVerTypeInfo;
4735 // Determine if the next instruction will consume
4736 // the address. If so we won't mark this var as
4739 // We will put structs on the stack and changing
4740 // the addrTaken of a local requires an extra pass
4741 // in the morpher so we won't apply this
4742 // optimization to structs.
4744 // Debug code spills for every IL instruction, and
4745 // therefore it will split statements, so we will
4746 // need the address. Note that this optimization
4747 // is based in that we know what trees we will
4748 // generate for this ldfld, and we require that we
4749 // won't need the address of this local at all
4750 noway_assert(varNum < lvaTableCnt);
4752 const bool notStruct = !varTypeIsStruct(&lvaTable[varNum]);
4753 const bool notLastInstr = (codeAddr < codeEndp - sz);
4754 const bool notDebugCode = !opts.compDbgCode;
4756 if (notStruct && notLastInstr && notDebugCode &&
4757 impILConsumesAddr(codeAddr + sz, impTokenLookupContextHandle, info.compScopeHnd))
4759 // We can skip the addrtaken, as next IL instruction consumes
4764 lvaTable[varNum].lvHasLdAddrOp = 1;
4765 if (!info.compIsStatic && (varNum == 0))
4767 // Addr taken on "this" pointer is significant,
4768 // go ahead to mark it as permanently addr-exposed here.
4769 lvaSetVarAddrExposed(0);
4770 // This may be conservative, but probably not very.
4775 typeIsNormed = ti.IsValueClass() && !varTypeIsStruct(varType);
4781 // CEE_CALLI should not be inlined if the call indirect target has a calling convention other than
4782 // CORINFO_CALLCONV_DEFAULT. In the case where we have a no-marshal CALLI P/Invoke we end up calling
4783 // the IL stub. We don't NGEN these stubs, so we'll have to JIT an IL stub for a trivial func.
4784 // It's almost certainly a better choice to leave out the inline candidate so we can generate an inlined
4787 // Consider skipping this bail-out for force inlines.
4788 if (makeInlineObservations)
4790 if (codeAddr > codeEndp - sizeof(DWORD))
4795 CORINFO_SIG_INFO calliSig;
4796 eeGetSig(getU4LittleEndian(codeAddr), info.compScopeHnd, impTokenLookupContextHandle, &calliSig);
4798 if (calliSig.getCallConv() != CORINFO_CALLCONV_DEFAULT)
4800 compInlineResult->Note(InlineObservation::CALLEE_UNSUPPORTED_OPCODE);
4802 // Fail fast if we're inlining
4805 assert(compInlineResult->IsFailure());
4815 #if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_)
4818 // We transform this into a set of ldarg's + tail call and
4819 // thus may push more onto the stack than originally thought.
4820 // This doesn't interfere with verification because CEE_JMP
4821 // is never verifiable, and there's nothing unsafe you can
4822 // do with a an IL stack overflow if the JIT is expecting it.
4823 info.compMaxStack = max(info.compMaxStack, info.compILargsCount);
4826 #endif // !_TARGET_X86_ && !_TARGET_ARM_
4828 // If we are inlining, we need to fail for a CEE_JMP opcode, just like
4829 // the list of other opcodes (for all platforms).
4834 if (makeInlineObservations)
4836 // Arguably this should be NoteFatal, but the legacy behavior is
4837 // to ignore this for the prejit root.
4838 compInlineResult->Note(InlineObservation::CALLEE_UNSUPPORTED_OPCODE);
4840 // Fail fast if we're inlining...
4843 assert(compInlineResult->IsFailure());
4851 // We now allow localloc callees to become candidates in some cases.
4852 if (makeInlineObservations)
4854 compInlineResult->Note(InlineObservation::CALLEE_HAS_LOCALLOC);
4855 if (isInlining && compInlineResult->IsFailure())
4866 if (makeInlineObservations)
4868 pushedStack.PushArgument(opcode - CEE_LDARG_0);
4875 if (codeAddr > codeEndp - sz)
4880 varNum = (sz == sizeof(BYTE)) ? getU1LittleEndian(codeAddr) : getU2LittleEndian(codeAddr);
4882 if (makeInlineObservations)
4884 pushedStack.PushArgument(varNum);
4890 if (makeInlineObservations)
4892 pushedStack.PushArrayLen();
4901 if (makeInlineObservations)
4903 fgObserveInlineConstants(opcode, pushedStack, isInlining);
4913 // Skip any remaining operands this opcode may have
4916 // Note the opcode we just saw
4917 if (makeInlineObservations)
4919 InlineObservation obs =
4920 typeIsNormed ? InlineObservation::CALLEE_OPCODE_NORMED : InlineObservation::CALLEE_OPCODE;
4921 compInlineResult->NoteInt(obs, opcode);
4925 if (codeAddr != codeEndp)
4928 BADCODE3("Code ends in the middle of an opcode, or there is a branch past the end of the method",
4929 " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
4932 if (makeInlineObservations)
4934 compInlineResult->Note(InlineObservation::CALLEE_END_OPCODE_SCAN);
4936 // If there are no return blocks we know it does not return, however if there
4937 // return blocks we don't know it returns as it may be counting unreachable code.
4938 // However we will still make the CALLEE_DOES_NOT_RETURN observation.
4940 compInlineResult->NoteBool(InlineObservation::CALLEE_DOES_NOT_RETURN, retBlocks == 0);
4942 if (retBlocks == 0 && isInlining)
4944 // Mark the call node as "no return" as it can impact caller's code quality.
4945 impInlineInfo->iciCall->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
4948 // If the inline is viable and discretionary, do the
4949 // profitability screening.
4950 if (compInlineResult->IsDiscretionaryCandidate())
4952 // Make some callsite specific observations that will feed
4953 // into the profitability model.
4954 impMakeDiscretionaryInlineObservations(impInlineInfo, compInlineResult);
4956 // None of those observations should have changed the
4957 // inline's viability.
4958 assert(compInlineResult->IsCandidate());
4962 // Assess profitability...
4963 CORINFO_METHOD_INFO* methodInfo = &impInlineInfo->inlineCandidateInfo->methInfo;
4964 compInlineResult->DetermineProfitability(methodInfo);
4966 if (compInlineResult->IsFailure())
4968 impInlineRoot()->m_inlineStrategy->NoteUnprofitable();
4969 JITDUMP("\n\nInline expansion aborted, inline not profitable\n");
4974 // The inline is still viable.
4975 assert(compInlineResult->IsCandidate());
4980 // Prejit root case. Profitability assessment for this
4981 // is done over in compCompileHelper.
4986 // None of the local vars in the inlinee should have address taken or been written to.
4987 // Therefore we should NOT need to enter this "if" statement.
4988 if (!isInlining && !info.compIsStatic)
4990 fgAdjustForAddressExposedOrWrittenThis();
4995 #pragma warning(pop)
4998 //------------------------------------------------------------------------
4999 // fgAdjustForAddressExposedOrWrittenThis: update var table for cases
5000 // where the this pointer value can change.
5003 // Modifies lvaArg0Var to refer to a temp if the value of 'this' can
5004 // change. The original this (info.compThisArg) then remains
5005 // unmodified in the method. fgAddInternal is reponsible for
5006 // adding the code to copy the initial this into the temp.
5008 void Compiler::fgAdjustForAddressExposedOrWrittenThis()
5010 // Optionally enable adjustment during stress.
5011 if (!tiVerificationNeeded && compStressCompile(STRESS_GENERIC_VARN, 15))
5013 lvaTable[info.compThisArg].lvHasILStoreOp = true;
5016 // If this is exposed or written to, create a temp for the modifiable this
5017 if (lvaTable[info.compThisArg].lvAddrExposed || lvaTable[info.compThisArg].lvHasILStoreOp)
5019 // If there is a "ldarga 0" or "starg 0", grab and use the temp.
5020 lvaArg0Var = lvaGrabTemp(false DEBUGARG("Address-exposed, or written this pointer"));
5021 noway_assert(lvaArg0Var > (unsigned)info.compThisArg);
5022 lvaTable[lvaArg0Var].lvType = lvaTable[info.compThisArg].TypeGet();
5023 lvaTable[lvaArg0Var].lvAddrExposed = lvaTable[info.compThisArg].lvAddrExposed;
5024 lvaTable[lvaArg0Var].lvDoNotEnregister = lvaTable[info.compThisArg].lvDoNotEnregister;
5026 lvaTable[lvaArg0Var].lvVMNeedsStackAddr = lvaTable[info.compThisArg].lvVMNeedsStackAddr;
5027 lvaTable[lvaArg0Var].lvLiveInOutOfHndlr = lvaTable[info.compThisArg].lvLiveInOutOfHndlr;
5028 lvaTable[lvaArg0Var].lvLclFieldExpr = lvaTable[info.compThisArg].lvLclFieldExpr;
5029 lvaTable[lvaArg0Var].lvLiveAcrossUCall = lvaTable[info.compThisArg].lvLiveAcrossUCall;
5031 lvaTable[lvaArg0Var].lvHasILStoreOp = lvaTable[info.compThisArg].lvHasILStoreOp;
5032 lvaTable[lvaArg0Var].lvVerTypeInfo = lvaTable[info.compThisArg].lvVerTypeInfo;
5034 // Clear the TI_FLAG_THIS_PTR in the original 'this' pointer.
5035 noway_assert(lvaTable[lvaArg0Var].lvVerTypeInfo.IsThisPtr());
5036 lvaTable[info.compThisArg].lvVerTypeInfo.ClearThisPtr();
5037 lvaTable[info.compThisArg].lvAddrExposed = false;
5038 lvaTable[info.compThisArg].lvHasILStoreOp = false;
5042 //------------------------------------------------------------------------
5043 // fgObserveInlineConstants: look for operations that might get optimized
5044 // if this method were to be inlined, and report these to the inliner.
5047 // opcode -- MSIL opcode under consideration
5048 // stack -- abstract stack model at this point in the IL
5049 // isInlining -- true if we're inlining (vs compiling a prejit root)
5052 // Currently only invoked on compare and branch opcodes.
5054 // If we're inlining we also look at the argument values supplied by
5055 // the caller at this call site.
5057 // The crude stack model may overestimate stack depth.
5059 void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining)
5061 // We should be able to record inline observations.
5062 assert(compInlineResult != nullptr);
5064 // The stack only has to be 1 deep for BRTRUE/FALSE
5065 bool lookForBranchCases = stack.IsStackAtLeastOneDeep();
5067 if (lookForBranchCases)
5069 if (opcode == CEE_BRFALSE || opcode == CEE_BRFALSE_S || opcode == CEE_BRTRUE || opcode == CEE_BRTRUE_S)
5071 unsigned slot0 = stack.GetSlot0();
5072 if (FgStack::IsArgument(slot0))
5074 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
5078 // Check for the double whammy of an incoming constant argument
5079 // feeding a constant test.
5080 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
5081 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5083 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5092 // Remaining cases require at least two things on the stack.
5093 if (!stack.IsStackTwoDeep())
5098 unsigned slot0 = stack.GetSlot0();
5099 unsigned slot1 = stack.GetSlot1();
5101 // Arg feeds constant test
5102 if ((FgStack::IsConstant(slot0) && FgStack::IsArgument(slot1)) ||
5103 (FgStack::IsConstant(slot1) && FgStack::IsArgument(slot0)))
5105 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_CONSTANT_TEST);
5108 // Arg feeds range check
5109 if ((FgStack::IsArrayLen(slot0) && FgStack::IsArgument(slot1)) ||
5110 (FgStack::IsArrayLen(slot1) && FgStack::IsArgument(slot0)))
5112 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_RANGE_CHECK);
5115 // Check for an incoming arg that's a constant
5118 if (FgStack::IsArgument(slot0))
5120 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST);
5122 unsigned varNum = FgStack::SlotTypeToArgNum(slot0);
5123 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5125 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5129 if (FgStack::IsArgument(slot1))
5131 compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST);
5133 unsigned varNum = FgStack::SlotTypeToArgNum(slot1);
5134 if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst())
5136 compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST);
5142 /*****************************************************************************
5144 * Finally link up the bbJumpDest of the blocks together
5147 void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock)
5149 noway_assert(startBlock->bbNum <= endBlock->bbNum);
5151 for (BasicBlock* block = startBlock; block != endBlock->bbNext; block = block->bbNext)
5153 if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0)
5155 block->bbFlags |= BBF_BACKWARD_JUMP;
5160 /*****************************************************************************
5162 * Finally link up the bbJumpDest of the blocks together
5165 void Compiler::fgLinkBasicBlocks()
5167 /* Create the basic block lookup tables */
5171 /* First block is always reachable */
5173 fgFirstBB->bbRefs = 1;
5175 /* Walk all the basic blocks, filling in the target addresses */
5177 for (BasicBlock* curBBdesc = fgFirstBB; curBBdesc; curBBdesc = curBBdesc->bbNext)
5179 switch (curBBdesc->bbJumpKind)
5184 curBBdesc->bbJumpDest = fgLookupBB(curBBdesc->bbJumpOffs);
5185 curBBdesc->bbJumpDest->bbRefs++;
5186 if (curBBdesc->bbJumpDest->bbNum <= curBBdesc->bbNum)
5188 fgMarkBackwardJump(curBBdesc->bbJumpDest, curBBdesc);
5191 /* Is the next block reachable? */
5193 if (curBBdesc->bbJumpKind == BBJ_ALWAYS || curBBdesc->bbJumpKind == BBJ_LEAVE)
5198 if (!curBBdesc->bbNext)
5200 BADCODE("Fall thru the end of a method");
5203 // Fall through, the next block is also reachable
5206 curBBdesc->bbNext->bbRefs++;
5209 case BBJ_EHFINALLYRET:
5210 case BBJ_EHFILTERRET:
5218 jumpCnt = curBBdesc->bbJumpSwt->bbsCount;
5219 BasicBlock** jumpPtr;
5220 jumpPtr = curBBdesc->bbJumpSwt->bbsDstTab;
5224 *jumpPtr = fgLookupBB((unsigned)*(size_t*)jumpPtr);
5225 (*jumpPtr)->bbRefs++;
5226 if ((*jumpPtr)->bbNum <= curBBdesc->bbNum)
5228 fgMarkBackwardJump(*jumpPtr, curBBdesc);
5230 } while (++jumpPtr, --jumpCnt);
5232 /* Default case of CEE_SWITCH (next block), is at end of jumpTab[] */
5234 noway_assert(*(jumpPtr - 1) == curBBdesc->bbNext);
5237 case BBJ_CALLFINALLY: // BBJ_CALLFINALLY and BBJ_EHCATCHRET don't appear until later
5238 case BBJ_EHCATCHRET:
5240 noway_assert(!"Unexpected bbJumpKind");
5246 /*****************************************************************************
5248 * Walk the instrs to create the basic blocks. Returns the number of BBJ_RETURN in method
5251 unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
5254 const BYTE* codeBegp = codeAddr;
5255 const BYTE* codeEndp = codeAddr + codeSize;
5256 bool tailCall = false;
5258 BasicBlock* curBBdesc;
5261 /* Clear the beginning offset for the first BB */
5265 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5267 compResetScopeLists();
5269 // Ignore scopes beginning at offset 0
5270 while (compGetNextEnterScope(0))
5273 while (compGetNextExitScope(0))
5278 BBjumpKinds jmpKind;
5284 unsigned jmpAddr = DUMMY_INIT(BAD_IL_OFFSET);
5285 unsigned bbFlags = 0;
5286 BBswtDesc* swtDsc = nullptr;
5289 opcode = (OPCODE)getU1LittleEndian(codeAddr);
5290 codeAddr += sizeof(__int8);
5295 /* Get the size of additional parameters */
5297 noway_assert((unsigned)opcode < CEE_COUNT);
5299 sz = opcodeSizes[opcode];
5306 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5308 BADCODE3("jump target between prefix 0xFE and opcode", " at offset %04X",
5309 (IL_OFFSET)(codeAddr - codeBegp));
5312 opcode = (OPCODE)(256 + getU1LittleEndian(codeAddr));
5313 codeAddr += sizeof(__int8);
5316 /* Check to see if we have a jump/return opcode */
5350 // We need to check if we are jumping out of a finally-protected try.
5351 jmpKind = BBJ_LEAVE;
5356 jmpKind = BBJ_ALWAYS;
5361 /* Compute the target address of the jump */
5363 jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr);
5365 if (compIsForInlining() && jmpDist == 0 && (opcode == CEE_BR || opcode == CEE_BR_S))
5370 jmpAddr = (IL_OFFSET)(codeAddr - codeBegp) + sz + jmpDist;
5376 unsigned jmpCnt; // # of switch cases (excluding defualt)
5378 BasicBlock** jmpTab;
5379 BasicBlock** jmpPtr;
5381 /* Allocate the switch descriptor */
5383 swtDsc = new (this, CMK_BasicBlock) BBswtDesc;
5385 /* Read the number of entries in the table */
5387 jmpCnt = getU4LittleEndian(codeAddr);
5390 /* Compute the base offset for the opcode */
5392 jmpBase = (IL_OFFSET)((codeAddr - codeBegp) + jmpCnt * sizeof(DWORD));
5394 /* Allocate the jump table */
5396 jmpPtr = jmpTab = new (this, CMK_BasicBlock) BasicBlock*[jmpCnt + 1];
5398 /* Fill in the jump table */
5400 for (unsigned count = jmpCnt; count; count--)
5402 jmpDist = getI4LittleEndian(codeAddr);
5405 // store the offset in the pointer. We change these in fgLinkBasicBlocks().
5406 *jmpPtr++ = (BasicBlock*)(size_t)(jmpBase + jmpDist);
5409 /* Append the default label to the target table */
5411 *jmpPtr++ = (BasicBlock*)(size_t)jmpBase;
5413 /* Make sure we found the right number of labels */
5415 noway_assert(jmpPtr == jmpTab + jmpCnt + 1);
5417 /* Compute the size of the switch opcode operands */
5419 sz = sizeof(DWORD) + jmpCnt * sizeof(DWORD);
5421 /* Fill in the remaining fields of the switch descriptor */
5423 swtDsc->bbsCount = jmpCnt + 1;
5424 swtDsc->bbsDstTab = jmpTab;
5426 /* This is definitely a jump */
5428 jmpKind = BBJ_SWITCH;
5431 #ifndef LEGACY_BACKEND
5432 if (opts.compProcedureSplitting)
5434 // TODO-CQ: We might need to create a switch table; we won't know for sure until much later.
5435 // However, switch tables don't work with hot/cold splitting, currently. The switch table data needs
5436 // a relocation such that if the base (the first block after the prolog) and target of the switch
5437 // branch are put in different sections, the difference stored in the table is updated. However, our
5438 // relocation implementation doesn't support three different pointers (relocation address, base, and
5439 // target). So, we need to change our switch table implementation to be more like
5440 // JIT64: put the table in the code section, in the same hot/cold section as the switch jump itself
5441 // (maybe immediately after the switch jump), and make the "base" address be also in that section,
5442 // probably the address after the switch jump.
5443 opts.compProcedureSplitting = false;
5444 JITDUMP("Turning off procedure splitting for this method, as it might need switch tables; "
5445 "implementation limitation.\n");
5447 #endif // !LEGACY_BACKEND
5452 bbFlags |= BBF_DONT_REMOVE;
5453 jmpKind = BBJ_EHFILTERRET;
5456 case CEE_ENDFINALLY:
5457 jmpKind = BBJ_EHFINALLYRET;
5461 if (compIsForInlining())
5463 // TODO-CQ: We can inline some callees with explicit tail calls if we can guarantee that the calls
5464 // can be dispatched as tail calls from the caller.
5465 compInlineResult->NoteFatal(InlineObservation::CALLEE_EXPLICIT_TAIL_PREFIX);
5473 case CEE_CONSTRAINED:
5476 // fgFindJumpTargets should have ruled out this possibility
5477 // (i.e. a prefix opcodes as last intruction in a block)
5478 noway_assert(codeAddr < codeEndp);
5480 if (jumpTarget[codeAddr - codeBegp] != JT_NONE)
5482 BADCODE3("jump target between prefix and an opcode", " at offset %04X",
5483 (IL_OFFSET)(codeAddr - codeBegp));
5491 if (compIsForInlining() || // Ignore tail call in the inlinee. Period.
5492 (!tailCall && !compTailCallStress()) // A new BB with BBJ_RETURN would have been created
5494 // after a tailcall statement.
5495 // We need to keep this invariant if we want to stress the tailcall.
5496 // That way, the potential (tail)call statement is always the last
5497 // statement in the block.
5498 // Otherwise, we will assert at the following line in fgMorphCall()
5499 // noway_assert(fgMorphStmt->gtNext == NULL);
5502 // Neither .tailcall prefix, no tailcall stress. So move on.
5506 // Make sure the code sequence is legal for the tail call.
5507 // If so, mark this BB as having a BBJ_RETURN.
5509 if (codeAddr >= codeEndp - sz)
5511 BADCODE3("No code found after the call instruction", " at offset %04X",
5512 (IL_OFFSET)(codeAddr - codeBegp));
5517 bool isCallPopAndRet = false;
5519 // impIsTailCallILPattern uses isRecursive flag to determine whether ret in a fallthrough block is
5520 // allowed. We don't know at this point whether the call is recursive so we conservatively pass
5521 // false. This will only affect explicit tail calls when IL verification is not needed for the
5523 bool isRecursive = false;
5524 if (!impIsTailCallILPattern(tailCall, opcode, codeAddr + sz, codeEndp, isRecursive,
5527 #if !defined(FEATURE_CORECLR) && defined(_TARGET_AMD64_)
5528 BADCODE3("tail call not followed by ret or pop+ret", " at offset %04X",
5529 (IL_OFFSET)(codeAddr - codeBegp));
5531 BADCODE3("tail call not followed by ret", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5532 #endif // !FEATURE_CORECLR && _TARGET_AMD64_
5535 #if !defined(FEATURE_CORECLR) && defined(_TARGET_AMD64_)
5536 if (isCallPopAndRet)
5538 // By breaking here, we let pop and ret opcodes to be
5539 // imported after tail call. If tail prefix is honored,
5540 // stmts corresponding to pop and ret will be removed
5541 // in fgMorphCall().
5544 #endif // !FEATURE_CORECLR && _TARGET_AMD64_
5548 OPCODE nextOpcode = (OPCODE)getU1LittleEndian(codeAddr + sz);
5550 if (nextOpcode != CEE_RET)
5552 noway_assert(compTailCallStress());
5553 // Next OPCODE is not a CEE_RET, bail the attempt to stress the tailcall.
5554 // (I.e. We will not make a new BB after the "call" statement.)
5560 /* For tail call, we just call CORINFO_HELP_TAILCALL, and it jumps to the
5561 target. So we don't need an epilog - just like CORINFO_HELP_THROW.
5562 Make the block BBJ_RETURN, but we will change it to BBJ_THROW
5563 if the tailness of the call is satisfied.
5564 NOTE : The next instruction is guaranteed to be a CEE_RET
5565 and it will create another BasicBlock. But there may be an
5566 jump directly to that CEE_RET. If we want to avoid creating
5567 an unnecessary block, we need to check if the CEE_RETURN is
5568 the target of a jump.
5574 /* These are equivalent to a return from the current method
5575 But instead of directly returning to the caller we jump and
5576 execute something else in between */
5579 jmpKind = BBJ_RETURN;
5584 jmpKind = BBJ_THROW;
5588 // make certain we did not forget any flow of control instructions
5589 // by checking the 'ctrl' field in opcode.def. First filter out all
5590 // non-ctrl instructions
5591 #define BREAK(name) \
5594 #define NEXT(name) \
5599 #undef RETURN // undef contract RETURN macro
5600 #define RETURN(name)
5602 #define BRANCH(name)
5603 #define COND_BRANCH(name)
5606 #define OPDEF(name, string, pop, push, oprType, opcType, l, s1, s2, ctrl) ctrl(name)
5607 #include "opcode.def"
5620 // These ctrl-flow opcodes don't need any special handling
5621 case CEE_NEWOBJ: // CTRL_CALL
5624 // what's left are forgotten instructions
5626 BADCODE("Unrecognized control Opcode");
5634 /* Jump over the operand */
5640 tailCall = (opcode == CEE_TAILCALL);
5642 /* Make sure a jump target isn't in the middle of our opcode */
5646 IL_OFFSET offs = (IL_OFFSET)(codeAddr - codeBegp) - sz; // offset of the operand
5648 for (unsigned i = 0; i < sz; i++, offs++)
5650 if (jumpTarget[offs] != JT_NONE)
5652 BADCODE3("jump into the middle of an opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5657 /* Compute the offset of the next opcode */
5659 nxtBBoffs = (IL_OFFSET)(codeAddr - codeBegp);
5661 bool foundScope = false;
5663 if (opts.compDbgCode && (info.compVarScopesCount > 0))
5665 while (compGetNextEnterScope(nxtBBoffs))
5669 while (compGetNextExitScope(nxtBBoffs))
5675 /* Do we have a jump? */
5677 if (jmpKind == BBJ_NONE)
5679 /* No jump; make sure we don't fall off the end of the function */
5681 if (codeAddr == codeEndp)
5683 BADCODE3("missing return opcode", " at offset %04X", (IL_OFFSET)(codeAddr - codeBegp));
5686 /* If a label follows this opcode, we'll have to make a new BB */
5688 bool makeBlock = (jumpTarget[nxtBBoffs] != JT_NONE);
5690 if (!makeBlock && foundScope)
5696 printf("Splitting at BBoffs = %04u\n", nxtBBoffs);
5707 /* We need to create a new basic block */
5709 curBBdesc = fgNewBasicBlock(jmpKind);
5711 curBBdesc->bbFlags |= bbFlags;
5712 curBBdesc->bbRefs = 0;
5714 curBBdesc->bbCodeOffs = curBBoffs;
5715 curBBdesc->bbCodeOffsEnd = nxtBBoffs;
5717 unsigned profileWeight;
5718 if (fgGetProfileWeightForBasicBlock(curBBoffs, &profileWeight))
5720 curBBdesc->setBBProfileWeight(profileWeight);
5721 if (profileWeight == 0)
5723 curBBdesc->bbSetRunRarely();
5727 // Note that bbNewBasicBlock (called from fgNewBasicBlock) may have
5728 // already marked the block as rarely run. In that case (and when we know
5729 // that the block profile weight is non-zero) we want to unmark that.
5731 curBBdesc->bbFlags &= ~BBF_RUN_RARELY;
5738 curBBdesc->bbJumpSwt = swtDsc;
5744 noway_assert(jmpAddr != DUMMY_INIT(BAD_IL_OFFSET));
5745 curBBdesc->bbJumpOffs = jmpAddr;
5752 DBEXEC(verbose, curBBdesc->dspBlockHeader(this, false, false, false));
5754 /* Remember where the next BB will start */
5756 curBBoffs = nxtBBoffs;
5757 } while (codeAddr < codeEndp);
5759 noway_assert(codeAddr == codeEndp);
5761 /* Finally link up the bbJumpDest of the blocks together */
5763 fgLinkBasicBlocks();
5768 /*****************************************************************************
5770 * Main entry point to discover the basic blocks for the current function.
5773 void Compiler::fgFindBasicBlocks()
5778 printf("*************** In fgFindBasicBlocks() for %s\n", info.compFullName);
5782 /* Allocate the 'jump target' vector
5784 * We need one extra byte as we mark
5785 * jumpTarget[info.compILCodeSize] with JT_ADDR
5786 * when we need to add a dummy block
5787 * to record the end of a try or handler region.
5789 BYTE* jumpTarget = new (this, CMK_Unknown) BYTE[info.compILCodeSize + 1];
5790 memset(jumpTarget, JT_NONE, info.compILCodeSize + 1);
5791 noway_assert(JT_NONE == 0);
5793 /* Walk the instrs to find all jump targets */
5795 fgFindJumpTargets(info.compCode, info.compILCodeSize, jumpTarget);
5796 if (compDonotInline())
5803 /* Are there any exception handlers? */
5805 if (info.compXcptnsCount > 0)
5807 noway_assert(!compIsForInlining());
5809 /* Check and mark all the exception handlers */
5811 for (XTnum = 0; XTnum < info.compXcptnsCount; XTnum++)
5814 CORINFO_EH_CLAUSE clause;
5815 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5816 noway_assert(clause.HandlerLength != (unsigned)-1);
5818 if (clause.TryLength <= 0)
5820 BADCODE("try block length <=0");
5823 /* Mark the 'try' block extent and the handler itself */
5825 if (clause.TryOffset > info.compILCodeSize)
5827 BADCODE("try offset is > codesize");
5829 if (jumpTarget[clause.TryOffset] == JT_NONE)
5831 jumpTarget[clause.TryOffset] = JT_ADDR;
5834 tmpOffset = clause.TryOffset + clause.TryLength;
5835 if (tmpOffset > info.compILCodeSize)
5837 BADCODE("try end is > codesize");
5839 if (jumpTarget[tmpOffset] == JT_NONE)
5841 jumpTarget[tmpOffset] = JT_ADDR;
5844 if (clause.HandlerOffset > info.compILCodeSize)
5846 BADCODE("handler offset > codesize");
5848 if (jumpTarget[clause.HandlerOffset] == JT_NONE)
5850 jumpTarget[clause.HandlerOffset] = JT_ADDR;
5853 tmpOffset = clause.HandlerOffset + clause.HandlerLength;
5854 if (tmpOffset > info.compILCodeSize)
5856 BADCODE("handler end > codesize");
5858 if (jumpTarget[tmpOffset] == JT_NONE)
5860 jumpTarget[tmpOffset] = JT_ADDR;
5863 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
5865 if (clause.FilterOffset > info.compILCodeSize)
5867 BADCODE("filter offset > codesize");
5869 if (jumpTarget[clause.FilterOffset] == JT_NONE)
5871 jumpTarget[clause.FilterOffset] = JT_ADDR;
5880 bool anyJumpTargets = false;
5881 printf("Jump targets:\n");
5882 for (unsigned i = 0; i < info.compILCodeSize + 1; i++)
5884 if (jumpTarget[i] == JT_NONE)
5889 anyJumpTargets = true;
5890 printf(" IL_%04x", i);
5892 if (jumpTarget[i] & JT_ADDR)
5896 if (jumpTarget[i] & JT_MULTI)
5902 if (!anyJumpTargets)
5909 /* Now create the basic blocks */
5911 unsigned retBlocks = fgMakeBasicBlocks(info.compCode, info.compILCodeSize, jumpTarget);
5913 if (compIsForInlining())
5917 // If fgFindJumpTargets marked the call as "no return" there
5918 // really should be no BBJ_RETURN blocks in the method.
5919 bool markedNoReturn = (impInlineInfo->iciCall->gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) != 0;
5920 assert((markedNoReturn && (retBlocks == 0)) || (!markedNoReturn && (retBlocks >= 1)));
5923 if (compInlineResult->IsFailure())
5928 noway_assert(info.compXcptnsCount == 0);
5929 compHndBBtab = impInlineInfo->InlinerCompiler->compHndBBtab;
5930 compHndBBtabAllocCount =
5931 impInlineInfo->InlinerCompiler->compHndBBtabAllocCount; // we probably only use the table, not add to it.
5932 compHndBBtabCount = impInlineInfo->InlinerCompiler->compHndBBtabCount;
5933 info.compXcptnsCount = impInlineInfo->InlinerCompiler->info.compXcptnsCount;
5935 // Use a spill temp for the return value if there are multiple return blocks,
5936 // or if the inlinee has GC ref locals.
5937 if ((info.compRetNativeType != TYP_VOID) && ((retBlocks > 1) || impInlineInfo->HasGcRefLocals()))
5939 // The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp.
5940 lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline return value spill temp"));
5941 lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetNativeType;
5943 // If the method returns a ref class, set the class of the spill temp
5944 // to the method's return value. We may update this later if it turns
5945 // out we can prove the method returns a more specific type.
5946 if (info.compRetType == TYP_REF)
5948 CORINFO_CLASS_HANDLE retClassHnd = impInlineInfo->inlineCandidateInfo->methInfo.args.retTypeClass;
5949 if (retClassHnd != nullptr)
5951 lvaSetClass(lvaInlineeReturnSpillTemp, retClassHnd);
5959 /* Mark all blocks within 'try' blocks as such */
5961 if (info.compXcptnsCount == 0)
5966 if (info.compXcptnsCount > MAX_XCPTN_INDEX)
5968 IMPL_LIMITATION("too many exception clauses");
5971 /* Allocate the exception handler table */
5975 /* Assume we don't need to sort the EH table (such that nested try/catch
5976 * appear before their try or handler parent). The EH verifier will notice
5977 * when we do need to sort it.
5980 fgNeedToSortEHTable = false;
5982 verInitEHTree(info.compXcptnsCount);
5983 EHNodeDsc* initRoot = ehnNext; // remember the original root since
5984 // it may get modified during insertion
5986 // Annotate BBs with exception handling information required for generating correct eh code
5987 // as well as checking for correct IL
5991 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
5993 CORINFO_EH_CLAUSE clause;
5994 info.compCompHnd->getEHinfo(info.compMethodHnd, XTnum, &clause);
5995 noway_assert(clause.HandlerLength != (unsigned)-1); // @DEPRECATED
6000 dispIncomingEHClause(XTnum, clause);
6004 IL_OFFSET tryBegOff = clause.TryOffset;
6005 IL_OFFSET tryEndOff = tryBegOff + clause.TryLength;
6006 IL_OFFSET filterBegOff = 0;
6007 IL_OFFSET hndBegOff = clause.HandlerOffset;
6008 IL_OFFSET hndEndOff = hndBegOff + clause.HandlerLength;
6010 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
6012 filterBegOff = clause.FilterOffset;
6015 if (tryEndOff > info.compILCodeSize)
6017 BADCODE3("end of try block beyond end of method for try", " at offset %04X", tryBegOff);
6019 if (hndEndOff > info.compILCodeSize)
6021 BADCODE3("end of hnd block beyond end of method for try", " at offset %04X", tryBegOff);
6024 HBtab->ebdTryBegOffset = tryBegOff;
6025 HBtab->ebdTryEndOffset = tryEndOff;
6026 HBtab->ebdFilterBegOffset = filterBegOff;
6027 HBtab->ebdHndBegOffset = hndBegOff;
6028 HBtab->ebdHndEndOffset = hndEndOff;
6030 /* Convert the various addresses to basic blocks */
6032 BasicBlock* tryBegBB = fgLookupBB(tryBegOff);
6033 BasicBlock* tryEndBB =
6034 fgLookupBB(tryEndOff); // note: this can be NULL if the try region is at the end of the function
6035 BasicBlock* hndBegBB = fgLookupBB(hndBegOff);
6036 BasicBlock* hndEndBB = nullptr;
6037 BasicBlock* filtBB = nullptr;
6041 // Assert that the try/hnd beginning blocks are set up correctly
6043 if (tryBegBB == nullptr)
6045 BADCODE("Try Clause is invalid");
6048 if (hndBegBB == nullptr)
6050 BADCODE("Handler Clause is invalid");
6053 tryBegBB->bbFlags |= BBF_HAS_LABEL;
6054 hndBegBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
6056 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
6057 // This will change the block weight from 0 to 1
6058 // and clear the rarely run flag
6059 hndBegBB->makeBlockHot();
6061 hndBegBB->bbSetRunRarely(); // handler entry points are rarely executed
6064 if (hndEndOff < info.compILCodeSize)
6066 hndEndBB = fgLookupBB(hndEndOff);
6069 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
6071 filtBB = HBtab->ebdFilter = fgLookupBB(clause.FilterOffset);
6073 filtBB->bbCatchTyp = BBCT_FILTER;
6074 filtBB->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
6076 hndBegBB->bbCatchTyp = BBCT_FILTER_HANDLER;
6078 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
6079 // This will change the block weight from 0 to 1
6080 // and clear the rarely run flag
6081 filtBB->makeBlockHot();
6083 filtBB->bbSetRunRarely(); // filter entry points are rarely executed
6086 // Mark all BBs that belong to the filter with the XTnum of the corresponding handler
6087 for (block = filtBB; /**/; block = block->bbNext)
6089 if (block == nullptr)
6091 BADCODE3("Missing endfilter for filter", " at offset %04X", filtBB->bbCodeOffs);
6095 // Still inside the filter
6096 block->setHndIndex(XTnum);
6098 if (block->bbJumpKind == BBJ_EHFILTERRET)
6100 // Mark catch handler as successor.
6101 block->bbJumpDest = hndBegBB;
6102 assert(block->bbJumpDest->bbCatchTyp == BBCT_FILTER_HANDLER);
6107 if (!block->bbNext || block->bbNext != hndBegBB)
6109 BADCODE3("Filter does not immediately precede handler for filter", " at offset %04X",
6110 filtBB->bbCodeOffs);
6115 HBtab->ebdTyp = clause.ClassToken;
6117 /* Set bbCatchTyp as appropriate */
6119 if (clause.Flags & CORINFO_EH_CLAUSE_FINALLY)
6121 hndBegBB->bbCatchTyp = BBCT_FINALLY;
6125 if (clause.Flags & CORINFO_EH_CLAUSE_FAULT)
6127 hndBegBB->bbCatchTyp = BBCT_FAULT;
6131 hndBegBB->bbCatchTyp = clause.ClassToken;
6133 // These values should be non-zero value that will
6134 // not collide with real tokens for bbCatchTyp
6135 if (clause.ClassToken == 0)
6137 BADCODE("Exception catch type is Null");
6140 noway_assert(clause.ClassToken != BBCT_FAULT);
6141 noway_assert(clause.ClassToken != BBCT_FINALLY);
6142 noway_assert(clause.ClassToken != BBCT_FILTER);
6143 noway_assert(clause.ClassToken != BBCT_FILTER_HANDLER);
6148 /* Mark the initial block and last blocks in the 'try' region */
6150 tryBegBB->bbFlags |= BBF_TRY_BEG | BBF_HAS_LABEL;
6152 /* Prevent future optimizations of removing the first block */
6153 /* of a TRY block and the first block of an exception handler */
6155 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
6156 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
6157 hndBegBB->bbRefs++; // The first block of a handler gets an extra, "artificial" reference count.
6159 if (clause.Flags & CORINFO_EH_CLAUSE_FILTER)
6161 filtBB->bbFlags |= BBF_DONT_REMOVE;
6162 filtBB->bbRefs++; // The first block of a filter gets an extra, "artificial" reference count.
6165 tryBegBB->bbFlags |= BBF_DONT_REMOVE;
6166 hndBegBB->bbFlags |= BBF_DONT_REMOVE;
6169 // Store the info to the table of EH block handlers
6172 HBtab->ebdHandlerType = ToEHHandlerType(clause.Flags);
6174 HBtab->ebdTryBeg = tryBegBB;
6175 HBtab->ebdTryLast = (tryEndBB == nullptr) ? fgLastBB : tryEndBB->bbPrev;
6177 HBtab->ebdHndBeg = hndBegBB;
6178 HBtab->ebdHndLast = (hndEndBB == nullptr) ? fgLastBB : hndEndBB->bbPrev;
6181 // Assert that all of our try/hnd blocks are setup correctly.
6183 if (HBtab->ebdTryLast == nullptr)
6185 BADCODE("Try Clause is invalid");
6188 if (HBtab->ebdHndLast == nullptr)
6190 BADCODE("Handler Clause is invalid");
6194 // Verify that it's legal
6197 verInsertEhNode(&clause, HBtab);
6199 } // end foreach handler table entry
6203 // Next, set things related to nesting that depend on the sorting being complete.
6205 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6207 /* Mark all blocks in the finally/fault or catch clause */
6209 BasicBlock* tryBegBB = HBtab->ebdTryBeg;
6210 BasicBlock* hndBegBB = HBtab->ebdHndBeg;
6212 IL_OFFSET tryBegOff = HBtab->ebdTryBegOffset;
6213 IL_OFFSET tryEndOff = HBtab->ebdTryEndOffset;
6215 IL_OFFSET hndBegOff = HBtab->ebdHndBegOffset;
6216 IL_OFFSET hndEndOff = HBtab->ebdHndEndOffset;
6220 for (block = hndBegBB; block && (block->bbCodeOffs < hndEndOff); block = block->bbNext)
6222 if (!block->hasHndIndex())
6224 block->setHndIndex(XTnum);
6227 // All blocks in a catch handler or filter are rarely run, except the entry
6228 if ((block != hndBegBB) && (hndBegBB->bbCatchTyp != BBCT_FINALLY))
6230 block->bbSetRunRarely();
6234 /* Mark all blocks within the covered range of the try */
6236 for (block = tryBegBB; block && (block->bbCodeOffs < tryEndOff); block = block->bbNext)
6238 /* Mark this BB as belonging to a 'try' block */
6240 if (!block->hasTryIndex())
6242 block->setTryIndex(XTnum);
6246 /* Note: the BB can't span the 'try' block */
6248 if (!(block->bbFlags & BBF_INTERNAL))
6250 noway_assert(tryBegOff <= block->bbCodeOffs);
6251 noway_assert(tryEndOff >= block->bbCodeOffsEnd || tryEndOff == tryBegOff);
6256 /* Init ebdHandlerNestingLevel of current clause, and bump up value for all
6257 * enclosed clauses (which have to be before it in the table).
6258 * Innermost try-finally blocks must precede outermost
6259 * try-finally blocks.
6262 #if !FEATURE_EH_FUNCLETS
6263 HBtab->ebdHandlerNestingLevel = 0;
6264 #endif // !FEATURE_EH_FUNCLETS
6266 HBtab->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6267 HBtab->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
6269 noway_assert(XTnum < compHndBBtabCount);
6270 noway_assert(XTnum == ehGetIndex(HBtab));
6272 for (EHblkDsc* xtab = compHndBBtab; xtab < HBtab; xtab++)
6274 #if !FEATURE_EH_FUNCLETS
6275 if (jitIsBetween(xtab->ebdHndBegOffs(), hndBegOff, hndEndOff))
6277 xtab->ebdHandlerNestingLevel++;
6279 #endif // !FEATURE_EH_FUNCLETS
6281 /* If we haven't recorded an enclosing try index for xtab then see
6282 * if this EH region should be recorded. We check if the
6283 * first offset in the xtab lies within our region. If so,
6284 * the last offset also must lie within the region, due to
6285 * nesting rules. verInsertEhNode(), below, will check for proper nesting.
6287 if (xtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6289 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), tryBegOff, tryEndOff);
6292 // Record the enclosing scope link
6293 xtab->ebdEnclosingTryIndex = (unsigned short)XTnum;
6297 /* Do the same for the enclosing handler index.
6299 if (xtab->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX)
6301 bool begBetween = jitIsBetween(xtab->ebdTryBegOffs(), hndBegOff, hndEndOff);
6304 // Record the enclosing scope link
6305 xtab->ebdEnclosingHndIndex = (unsigned short)XTnum;
6310 } // end foreach handler table entry
6312 #if !FEATURE_EH_FUNCLETS
6315 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
6317 if (ehMaxHndNestingCount <= HBtab->ebdHandlerNestingLevel)
6318 ehMaxHndNestingCount = HBtab->ebdHandlerNestingLevel + 1;
6321 #endif // !FEATURE_EH_FUNCLETS
6324 if (tiVerificationNeeded)
6327 // always run these checks for a debug build
6328 verCheckNestingLevel(initRoot);
6332 // fgNormalizeEH assumes that this test has been passed. And Ssa assumes that fgNormalizeEHTable
6333 // has been run. So do this unless we're in minOpts mode (and always in debug).
6334 if (tiVerificationNeeded || !opts.MinOpts())
6337 fgCheckBasicBlockControlFlow();
6343 JITDUMP("*************** After fgFindBasicBlocks() has created the EH table\n");
6347 // We can't verify the handler table until all the IL legality checks have been done (above), since bad IL
6348 // (such as illegal nesting of regions) will trigger asserts here.
6349 fgVerifyHandlerTab();
6355 /*****************************************************************************
6356 * Check control flow constraints for well formed IL. Bail if any of the constraints
6360 void Compiler::fgCheckBasicBlockControlFlow()
6362 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6366 for (BasicBlock* blk = fgFirstBB; blk; blk = blk->bbNext)
6368 if (blk->bbFlags & BBF_INTERNAL)
6373 switch (blk->bbJumpKind)
6375 case BBJ_NONE: // block flows into the next one (no jump)
6377 fgControlFlowPermitted(blk, blk->bbNext);
6381 case BBJ_ALWAYS: // block does unconditional jump to target
6383 fgControlFlowPermitted(blk, blk->bbJumpDest);
6387 case BBJ_COND: // block conditionally jumps to the target
6389 fgControlFlowPermitted(blk, blk->bbNext);
6391 fgControlFlowPermitted(blk, blk->bbJumpDest);
6395 case BBJ_RETURN: // block ends with 'ret'
6397 if (blk->hasTryIndex() || blk->hasHndIndex())
6399 BADCODE3("Return from a protected block", ". Before offset %04X", blk->bbCodeOffsEnd);
6403 case BBJ_EHFINALLYRET:
6404 case BBJ_EHFILTERRET:
6406 if (!blk->hasHndIndex()) // must be part of a handler
6408 BADCODE3("Missing handler", ". Before offset %04X", blk->bbCodeOffsEnd);
6411 HBtab = ehGetDsc(blk->getHndIndex());
6413 // Endfilter allowed only in a filter block
6414 if (blk->bbJumpKind == BBJ_EHFILTERRET)
6416 if (!HBtab->HasFilter())
6418 BADCODE("Unexpected endfilter");
6421 // endfinally allowed only in a finally/fault block
6422 else if (!HBtab->HasFinallyOrFaultHandler())
6424 BADCODE("Unexpected endfinally");
6427 // The handler block should be the innermost block
6428 // Exception blocks are listed, innermost first.
6429 if (blk->hasTryIndex() && (blk->getTryIndex() < blk->getHndIndex()))
6431 BADCODE("endfinally / endfilter in nested try block");
6436 case BBJ_THROW: // block ends with 'throw'
6437 /* throw is permitted from every BB, so nothing to check */
6438 /* importer makes sure that rethrow is done from a catch */
6441 case BBJ_LEAVE: // block always jumps to the target, maybe out of guarded
6442 // region. Used temporarily until importing
6443 fgControlFlowPermitted(blk, blk->bbJumpDest, TRUE);
6447 case BBJ_SWITCH: // block ends with a switch statement
6450 swtDesc = blk->bbJumpSwt;
6455 for (i = 0; i < swtDesc->bbsCount; i++)
6457 fgControlFlowPermitted(blk, swtDesc->bbsDstTab[i]);
6462 case BBJ_EHCATCHRET: // block ends with a leave out of a catch (only #if FEATURE_EH_FUNCLETS)
6463 case BBJ_CALLFINALLY: // block always calls the target finally
6465 noway_assert(!"Unexpected bbJumpKind"); // these blocks don't get created until importing
6471 /****************************************************************************
6472 * Check that the leave from the block is legal.
6473 * Consider removing this check here if we can do it cheaply during importing
6476 void Compiler::fgControlFlowPermitted(BasicBlock* blkSrc, BasicBlock* blkDest, BOOL isLeave)
6478 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6480 unsigned srcHndBeg, destHndBeg;
6481 unsigned srcHndEnd, destHndEnd;
6482 bool srcInFilter, destInFilter;
6483 bool srcInCatch = false;
6485 EHblkDsc* srcHndTab;
6487 srcHndTab = ehInitHndRange(blkSrc, &srcHndBeg, &srcHndEnd, &srcInFilter);
6488 ehInitHndRange(blkDest, &destHndBeg, &destHndEnd, &destInFilter);
6490 /* Impose the rules for leaving or jumping from handler blocks */
6492 if (blkSrc->hasHndIndex())
6494 srcInCatch = srcHndTab->HasCatchHandler() && srcHndTab->InHndRegionILRange(blkSrc);
6496 /* Are we jumping within the same handler index? */
6497 if (BasicBlock::sameHndRegion(blkSrc, blkDest))
6499 /* Do we have a filter clause? */
6500 if (srcHndTab->HasFilter())
6502 /* filters and catch handlers share same eh index */
6503 /* we need to check for control flow between them. */
6504 if (srcInFilter != destInFilter)
6506 if (!jitIsBetween(blkDest->bbCodeOffs, srcHndBeg, srcHndEnd))
6508 BADCODE3("Illegal control flow between filter and handler", ". Before offset %04X",
6509 blkSrc->bbCodeOffsEnd);
6516 /* The handler indexes of blkSrc and blkDest are different */
6519 /* Any leave instructions must not enter the dest handler from outside*/
6520 if (!jitIsBetween(srcHndBeg, destHndBeg, destHndEnd))
6522 BADCODE3("Illegal use of leave to enter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6527 /* We must use a leave to exit a handler */
6528 BADCODE3("Illegal control flow out of a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6531 /* Do we have a filter clause? */
6532 if (srcHndTab->HasFilter())
6534 /* It is ok to leave from the handler block of a filter, */
6535 /* but not from the filter block of a filter */
6536 if (srcInFilter != destInFilter)
6538 BADCODE3("Illegal to leave a filter handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6542 /* We should never leave a finally handler */
6543 if (srcHndTab->HasFinallyHandler())
6545 BADCODE3("Illegal to leave a finally handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6548 /* We should never leave a fault handler */
6549 if (srcHndTab->HasFaultHandler())
6551 BADCODE3("Illegal to leave a fault handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6555 else if (blkDest->hasHndIndex())
6557 /* blkSrc was not inside a handler, but blkDst is inside a handler */
6558 BADCODE3("Illegal control flow into a handler", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6561 /* Are we jumping from a catch handler into the corresponding try? */
6562 /* VB uses this for "on error goto " */
6564 if (isLeave && srcInCatch)
6566 // inspect all handlers containing the jump source
6568 bool bValidJumpToTry = false; // are we jumping in a valid way from a catch to the corresponding try?
6569 bool bCatchHandlerOnly = true; // false if we are jumping out of a non-catch handler
6570 EHblkDsc* ehTableEnd;
6573 for (ehDsc = compHndBBtab, ehTableEnd = compHndBBtab + compHndBBtabCount;
6574 bCatchHandlerOnly && ehDsc < ehTableEnd; ehDsc++)
6576 if (ehDsc->InHndRegionILRange(blkSrc))
6578 if (ehDsc->HasCatchHandler())
6580 if (ehDsc->InTryRegionILRange(blkDest))
6582 // If we already considered the jump for a different try/catch,
6583 // we would have two overlapping try regions with two overlapping catch
6584 // regions, which is illegal.
6585 noway_assert(!bValidJumpToTry);
6587 // Allowed if it is the first instruction of an inner try
6588 // (and all trys in between)
6598 // _tryNestedIllegal:
6610 // leave _tryAgain // Allowed
6612 // leave _tryNestedInner // Allowed
6614 // leave _tryNestedIllegal // Not Allowed
6618 // Note: The leave is allowed also from catches nested inside the catch shown above.
6620 /* The common case where leave is to the corresponding try */
6621 if (ehDsc->ebdIsSameTry(this, blkDest->getTryIndex()) ||
6622 /* Also allowed is a leave to the start of a try which starts in the handler's try */
6623 fgFlowToFirstBlockOfInnerTry(ehDsc->ebdTryBeg, blkDest, false))
6625 bValidJumpToTry = true;
6631 // We are jumping from a handler which is not a catch handler.
6633 // If it's a handler, but not a catch handler, it must be either a finally or fault
6634 if (!ehDsc->HasFinallyOrFaultHandler())
6636 BADCODE3("Handlers must be catch, finally, or fault", ". Before offset %04X",
6637 blkSrc->bbCodeOffsEnd);
6640 // Are we jumping out of this handler?
6641 if (!ehDsc->InHndRegionILRange(blkDest))
6643 bCatchHandlerOnly = false;
6647 else if (ehDsc->InFilterRegionILRange(blkSrc))
6649 // Are we jumping out of a filter?
6650 if (!ehDsc->InFilterRegionILRange(blkDest))
6652 bCatchHandlerOnly = false;
6657 if (bCatchHandlerOnly)
6659 if (bValidJumpToTry)
6666 // This is either the case of a leave to outside the try/catch,
6667 // or a leave to a try not nested in this try/catch.
6668 // The first case is allowed, the second one will be checked
6669 // later when we check the try block rules (it is illegal if we
6670 // jump to the middle of the destination try).
6675 BADCODE3("illegal leave to exit a finally, fault or filter", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6679 /* Check all the try block rules */
6681 IL_OFFSET srcTryBeg;
6682 IL_OFFSET srcTryEnd;
6683 IL_OFFSET destTryBeg;
6684 IL_OFFSET destTryEnd;
6686 ehInitTryRange(blkSrc, &srcTryBeg, &srcTryEnd);
6687 ehInitTryRange(blkDest, &destTryBeg, &destTryEnd);
6689 /* Are we jumping between try indexes? */
6690 if (!BasicBlock::sameTryRegion(blkSrc, blkDest))
6692 // Are we exiting from an inner to outer try?
6693 if (jitIsBetween(srcTryBeg, destTryBeg, destTryEnd) && jitIsBetween(srcTryEnd - 1, destTryBeg, destTryEnd))
6697 BADCODE3("exit from try block without a leave", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6700 else if (jitIsBetween(destTryBeg, srcTryBeg, srcTryEnd))
6702 // check that the dest Try is first instruction of an inner try
6703 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, false))
6705 BADCODE3("control flow into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6708 else // there is no nesting relationship between src and dest
6712 // check that the dest Try is first instruction of an inner try sibling
6713 if (!fgFlowToFirstBlockOfInnerTry(blkSrc, blkDest, true))
6715 BADCODE3("illegal leave into middle of try", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6720 BADCODE3("illegal control flow in to/out of try block", ". Before offset %04X", blkSrc->bbCodeOffsEnd);
6726 /*****************************************************************************
6727 * Check that blkDest is the first block of an inner try or a sibling
6728 * with no intervening trys in between
6731 bool Compiler::fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling)
6733 assert(!fgNormalizeEHDone); // These rules aren't quite correct after EH normalization has introduced new blocks
6735 noway_assert(blkDest->hasTryIndex());
6737 unsigned XTnum = blkDest->getTryIndex();
6738 unsigned lastXTnum = blkSrc->hasTryIndex() ? blkSrc->getTryIndex() : compHndBBtabCount;
6739 noway_assert(XTnum < compHndBBtabCount);
6740 noway_assert(lastXTnum <= compHndBBtabCount);
6742 EHblkDsc* HBtab = ehGetDsc(XTnum);
6744 // check that we are not jumping into middle of try
6745 if (HBtab->ebdTryBeg != blkDest)
6752 noway_assert(!BasicBlock::sameTryRegion(blkSrc, blkDest));
6754 // find the l.u.b of the two try ranges
6755 // Set lastXTnum to the l.u.b.
6757 HBtab = ehGetDsc(lastXTnum);
6759 for (lastXTnum++, HBtab++; lastXTnum < compHndBBtabCount; lastXTnum++, HBtab++)
6761 if (jitIsBetweenInclusive(blkDest->bbNum, HBtab->ebdTryBeg->bbNum, HBtab->ebdTryLast->bbNum))
6768 // now check there are no intervening trys between dest and l.u.b
6769 // (it is ok to have intervening trys as long as they all start at
6770 // the same code offset)
6772 HBtab = ehGetDsc(XTnum);
6774 for (XTnum++, HBtab++; XTnum < lastXTnum; XTnum++, HBtab++)
6776 if (HBtab->ebdTryBeg->bbNum < blkDest->bbNum && blkDest->bbNum <= HBtab->ebdTryLast->bbNum)
6785 /*****************************************************************************
6786 * Returns the handler nesting level of the block.
6787 * *pFinallyNesting is set to the nesting level of the inner-most
6788 * finally-protected try the block is in.
6791 unsigned Compiler::fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting)
6793 unsigned curNesting = 0; // How many handlers is the block in
6794 unsigned tryFin = (unsigned)-1; // curNesting when we see innermost finally-protected try
6798 /* We find the block's handler nesting level by walking over the
6799 complete exception table and find enclosing clauses. */
6801 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
6803 noway_assert(HBtab->ebdTryBeg && HBtab->ebdHndBeg);
6805 if (HBtab->HasFinallyHandler() && (tryFin == (unsigned)-1) && bbInTryRegions(XTnum, block))
6807 tryFin = curNesting;
6809 else if (bbInHandlerRegions(XTnum, block))
6815 if (tryFin == (unsigned)-1)
6817 tryFin = curNesting;
6820 if (pFinallyNesting)
6822 *pFinallyNesting = curNesting - tryFin;
6828 /*****************************************************************************
6830 * Import the basic blocks of the procedure.
6833 void Compiler::fgImport()
6835 fgHasPostfix = false;
6837 impImport(fgFirstBB);
6839 if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION))
6841 CorInfoMethodRuntimeFlags verFlag;
6842 verFlag = tiIsVerifiableCode ? CORINFO_FLG_VERIFIABLE : CORINFO_FLG_UNVERIFIABLE;
6843 info.compCompHnd->setMethodAttribs(info.compMethodHnd, verFlag);
6847 /*****************************************************************************
6848 * This function returns true if tree is a node with a call
6849 * that unconditionally throws an exception
6852 bool Compiler::fgIsThrow(GenTree* tree)
6854 if ((tree->gtOper != GT_CALL) || (tree->gtCall.gtCallType != CT_HELPER))
6859 // TODO-Throughput: Replace all these calls to eeFindHelper() with a table based lookup
6861 if ((tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW)) ||
6862 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VERIFICATION)) ||
6863 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
6864 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
6865 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
6866 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW)) ||
6867 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)) ||
6868 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED)) ||
6869 (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED)))
6871 noway_assert(tree->gtFlags & GTF_CALL);
6872 noway_assert(tree->gtFlags & GTF_EXCEPT);
6876 // TODO-CQ: there are a bunch of managed methods in [mscorlib]System.ThrowHelper
6877 // that would be nice to recognize.
6882 /*****************************************************************************
6883 * This function returns true for blocks that are in different hot-cold regions.
6884 * It returns false when the blocks are both in the same regions
6887 bool Compiler::fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2)
6889 noway_assert(blk1 != nullptr);
6890 noway_assert(blk2 != nullptr);
6892 if (fgFirstColdBlock == nullptr)
6897 // If one block is Hot and the other is Cold then we are in different regions
6898 return ((blk1->bbFlags & BBF_COLD) != (blk2->bbFlags & BBF_COLD));
6901 bool Compiler::fgIsBlockCold(BasicBlock* blk)
6903 noway_assert(blk != nullptr);
6905 if (fgFirstColdBlock == nullptr)
6910 return ((blk->bbFlags & BBF_COLD) != 0);
6913 /*****************************************************************************
6914 * This function returns true if tree is a GT_COMMA node with a call
6915 * that unconditionally throws an exception
6918 bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */)
6920 // Instead of always folding comma throws,
6921 // with stress enabled we only fold half the time
6923 if (forFolding && compStressCompile(STRESS_FOLD, 50))
6925 return false; /* Don't fold */
6928 /* Check for cast of a GT_COMMA with a throw overflow */
6929 if ((tree->gtOper == GT_COMMA) && (tree->gtFlags & GTF_CALL) && (tree->gtFlags & GTF_EXCEPT))
6931 return (fgIsThrow(tree->gtOp.gtOp1));
6936 //------------------------------------------------------------------------
6937 // fgIsIndirOfAddrOfLocal: Determine whether "tree" is an indirection of a local.
6940 // tree - The tree node under consideration
6943 // If "tree" is a indirection (GT_IND, GT_BLK, or GT_OBJ) whose arg is an ADDR,
6944 // whose arg in turn is a LCL_VAR, return that LCL_VAR node, else nullptr.
6947 GenTree* Compiler::fgIsIndirOfAddrOfLocal(GenTree* tree)
6949 GenTree* res = nullptr;
6950 if (tree->OperIsIndir())
6952 GenTree* addr = tree->AsIndir()->Addr();
6954 // Post rationalization, we can have Indir(Lea(..) trees. Therefore to recognize
6955 // Indir of addr of a local, skip over Lea in Indir(Lea(base, index, scale, offset))
6956 // to get to base variable.
6957 if (addr->OperGet() == GT_LEA)
6959 // We use this method in backward dataflow after liveness computation - fgInterBlockLocalVarLiveness().
6960 // Therefore it is critical that we don't miss 'uses' of any local. It may seem this method overlooks
6961 // if the index part of the LEA has indir( someAddrOperator ( lclVar ) ) to search for a use but it's
6962 // covered by the fact we're traversing the expression in execution order and we also visit the index.
6963 GenTreeAddrMode* lea = addr->AsAddrMode();
6964 GenTree* base = lea->Base();
6966 if (base != nullptr)
6968 if (base->OperGet() == GT_IND)
6970 return fgIsIndirOfAddrOfLocal(base);
6972 // else use base as addr
6977 if (addr->OperGet() == GT_ADDR)
6979 GenTree* lclvar = addr->gtOp.gtOp1;
6980 if (lclvar->OperGet() == GT_LCL_VAR)
6985 else if (addr->OperGet() == GT_LCL_VAR_ADDR)
6993 GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper)
6995 bool bNeedClassID = true;
6996 unsigned callFlags = 0;
6998 var_types type = TYP_BYREF;
7000 // This is sort of ugly, as we have knowledge of what the helper is returning.
7001 // We need the return type.
7004 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
7005 bNeedClassID = false;
7008 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
7009 callFlags |= GTF_CALL_HOISTABLE;
7012 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
7013 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
7014 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
7015 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
7016 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
7017 // type = TYP_BYREF;
7020 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
7021 bNeedClassID = false;
7024 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
7025 callFlags |= GTF_CALL_HOISTABLE;
7028 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
7029 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
7030 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
7031 case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
7036 assert(!"unknown shared statics helper");
7040 GenTreeArgList* argList = nullptr;
7042 GenTree* opModuleIDArg;
7043 GenTree* opClassIDArg;
7051 clsID = info.compCompHnd->getClassDomainID(cls, &pclsID);
7053 moduleID = info.compCompHnd->getClassModuleIdForStatics(cls, nullptr, &pmoduleID);
7055 if (!(callFlags & GTF_CALL_HOISTABLE))
7057 if (info.compCompHnd->getClassAttribs(cls) & CORINFO_FLG_BEFOREFIELDINIT)
7059 callFlags |= GTF_CALL_HOISTABLE;
7065 opModuleIDArg = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pmoduleID, GTF_ICON_CIDMID_HDL, true);
7069 opModuleIDArg = gtNewIconNode((size_t)moduleID, TYP_I_IMPL);
7076 opClassIDArg = gtNewIndOfIconHandleNode(TYP_INT, (size_t)pclsID, GTF_ICON_CIDMID_HDL, true);
7080 opClassIDArg = gtNewIconNode(clsID, TYP_INT);
7083 // call the helper to get the base
7084 argList = gtNewArgList(opModuleIDArg, opClassIDArg);
7088 argList = gtNewArgList(opModuleIDArg);
7091 GenTreeCall* result = gtNewHelperCallNode(helper, type, argList);
7092 result->gtFlags |= callFlags;
7094 // If we're importing the special EqualityComparer<T>.Default
7095 // intrinsic, flag the helper call. Later during inlining, we can
7096 // remove the helper call if the associated field lookup is unused.
7097 if ((info.compFlags & CORINFO_FLG_JIT_INTRINSIC) != 0)
7099 NamedIntrinsic ni = lookupNamedIntrinsic(info.compMethodHnd);
7100 if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default)
7102 JITDUMP("\nmarking helper call [06%u] as special dce...\n", result->gtTreeID);
7103 result->gtCallMoreFlags |= GTF_CALL_M_HELPER_SPECIAL_DCE;
7110 GenTreeCall* Compiler::fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls)
7112 #ifdef FEATURE_READYTORUN_COMPILER
7113 if (opts.IsReadyToRun())
7115 CORINFO_RESOLVED_TOKEN resolvedToken;
7116 memset(&resolvedToken, 0, sizeof(resolvedToken));
7117 resolvedToken.hClass = cls;
7119 return impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_STATIC_BASE, TYP_BYREF);
7123 // Call the shared non gc static helper, as its the fastest
7124 return fgGetStaticsCCtorHelper(cls, info.compCompHnd->getSharedCCtorHelper(cls));
7127 //------------------------------------------------------------------------------
7128 // fgAddrCouldBeNull : Check whether the address tree can represent null.
7132 // addr - Address to check
7135 // True if address could be null; false otherwise
7137 bool Compiler::fgAddrCouldBeNull(GenTree* addr)
7139 addr = addr->gtEffectiveVal();
7140 if ((addr->gtOper == GT_CNS_INT) && addr->IsIconHandle())
7144 else if (addr->gtOper == GT_LCL_VAR)
7146 unsigned varNum = addr->AsLclVarCommon()->GetLclNum();
7148 if (lvaIsImplicitByRefLocal(varNum))
7153 LclVarDsc* varDsc = &lvaTable[varNum];
7155 if (varDsc->lvStackByref)
7160 else if (addr->gtOper == GT_ADDR)
7162 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
7164 GenTree* cns1Tree = addr->gtOp.gtOp1;
7165 if (!cns1Tree->IsIconHandle())
7167 // Indirection of some random constant...
7168 // It is safest just to return true
7173 return false; // we can't have a null address
7175 else if (addr->gtOper == GT_ADD)
7177 if (addr->gtOp.gtOp1->gtOper == GT_CNS_INT)
7179 GenTree* cns1Tree = addr->gtOp.gtOp1;
7180 if (!cns1Tree->IsIconHandle())
7182 if (!fgIsBigOffset(cns1Tree->gtIntCon.gtIconVal))
7184 // Op1 was an ordinary small constant
7185 return fgAddrCouldBeNull(addr->gtOp.gtOp2);
7188 else // Op1 was a handle represented as a constant
7190 // Is Op2 also a constant?
7191 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
7193 GenTree* cns2Tree = addr->gtOp.gtOp2;
7194 // Is this an addition of a handle and constant
7195 if (!cns2Tree->IsIconHandle())
7197 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
7199 // Op2 was an ordinary small constant
7200 return false; // we can't have a null address
7208 // Op1 is not a constant
7210 if (addr->gtOp.gtOp2->gtOper == GT_CNS_INT)
7212 GenTree* cns2Tree = addr->gtOp.gtOp2;
7213 // Is this an addition of a small constant
7214 if (!cns2Tree->IsIconHandle())
7216 if (!fgIsBigOffset(cns2Tree->gtIntCon.gtIconVal))
7218 // Op2 was an ordinary small constant
7219 return fgAddrCouldBeNull(addr->gtOp.gtOp1);
7225 return true; // default result: addr could be null
7228 /*****************************************************************************
7229 * Optimize the call to the delegate constructor.
7232 GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
7233 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
7234 CORINFO_RESOLVED_TOKEN* ldftnToken)
7236 noway_assert(call->gtCallType == CT_USER_FUNC);
7237 CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
7238 CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getMethodClass(methHnd);
7240 GenTree* targetMethod = call->gtCallArgs->Rest()->Current();
7241 noway_assert(targetMethod->TypeGet() == TYP_I_IMPL);
7242 genTreeOps oper = targetMethod->OperGet();
7243 CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
7244 GenTree* qmarkNode = nullptr;
7245 if (oper == GT_FTN_ADDR)
7247 targetMethodHnd = targetMethod->gtFptrVal.gtFptrMethod;
7249 else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
7251 GenTree* handleNode = targetMethod->gtCall.gtCallArgs->Rest()->Rest()->Current();
7253 if (handleNode->OperGet() == GT_CNS_INT)
7255 // it's a ldvirtftn case, fetch the methodhandle off the helper for ldvirtftn. It's the 3rd arg
7256 targetMethodHnd = CORINFO_METHOD_HANDLE(handleNode->gtIntCon.gtCompileTimeHandle);
7258 // Sometimes the argument to this is the result of a generic dictionary lookup, which shows
7259 // up as a GT_QMARK.
7260 else if (handleNode->OperGet() == GT_QMARK)
7262 qmarkNode = handleNode;
7265 // Sometimes we don't call CORINFO_HELP_VIRTUAL_FUNC_PTR but instead just call
7266 // CORINFO_HELP_RUNTIMEHANDLE_METHOD directly.
7267 else if (oper == GT_QMARK)
7269 qmarkNode = targetMethod;
7273 noway_assert(qmarkNode->OperGet() == GT_QMARK);
7274 // The argument is actually a generic dictionary lookup. For delegate creation it looks
7279 // Arg 1 -> token (has compile time handle)
7283 // In this case I can find the token (which is a method handle) and that is the compile time
7285 noway_assert(qmarkNode->gtOp.gtOp2->OperGet() == GT_COLON);
7286 noway_assert(qmarkNode->gtOp.gtOp2->gtOp.gtOp1->OperGet() == GT_CALL);
7287 GenTreeCall* runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1->AsCall();
7289 // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
7290 GenTree* tokenNode = runtimeLookupCall->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
7291 noway_assert(tokenNode->OperGet() == GT_CNS_INT);
7292 targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
7295 #ifdef FEATURE_READYTORUN_COMPILER
7296 if (opts.IsReadyToRun())
7298 if (IsTargetAbi(CORINFO_CORERT_ABI))
7300 if (ldftnToken != nullptr)
7302 GenTree* thisPointer = call->gtCallObjp;
7303 GenTree* targetObjPointers = call->gtCallArgs->Current();
7304 GenTreeArgList* helperArgs = nullptr;
7305 CORINFO_LOOKUP pLookup;
7306 CORINFO_CONST_LOOKUP entryPoint;
7307 info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup);
7308 if (!pLookup.lookupKind.needsRuntimeLookup)
7310 helperArgs = gtNewArgList(thisPointer, targetObjPointers);
7311 entryPoint = pLookup.constLookup;
7315 assert(oper != GT_FTN_ADDR);
7316 CORINFO_CONST_LOOKUP genericLookup;
7317 info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind,
7318 CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup);
7319 GenTree* ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind);
7320 helperArgs = gtNewArgList(thisPointer, targetObjPointers, ctxTree);
7321 entryPoint = genericLookup;
7323 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
7324 call->setEntryPoint(entryPoint);
7327 // ReadyToRun has this optimization for a non-virtual function pointers only for now.
7328 else if (oper == GT_FTN_ADDR)
7330 GenTree* thisPointer = call->gtCallObjp;
7331 GenTree* targetObjPointers = call->gtCallArgs->Current();
7332 GenTreeArgList* helperArgs = gtNewArgList(thisPointer, targetObjPointers);
7334 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
7336 CORINFO_LOOKUP entryPoint;
7337 info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint);
7338 assert(!entryPoint.lookupKind.needsRuntimeLookup);
7339 call->setEntryPoint(entryPoint.constLookup);
7344 if (targetMethodHnd != nullptr)
7346 CORINFO_METHOD_HANDLE alternateCtor = nullptr;
7347 DelegateCtorArgs ctorData;
7348 ctorData.pMethod = info.compMethodHnd;
7349 ctorData.pArg3 = nullptr;
7350 ctorData.pArg4 = nullptr;
7351 ctorData.pArg5 = nullptr;
7353 alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
7354 if (alternateCtor != methHnd)
7356 // we erase any inline info that may have been set for generics has it is not needed here,
7357 // and in fact it will pass the wrong info to the inliner code
7358 *ExactContextHnd = nullptr;
7360 call->gtCallMethHnd = alternateCtor;
7362 noway_assert(call->gtCallArgs->Rest()->Rest() == nullptr);
7363 GenTreeArgList* addArgs = nullptr;
7366 GenTree* arg5 = gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR);
7367 addArgs = gtNewListNode(arg5, addArgs);
7371 GenTree* arg4 = gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR);
7372 addArgs = gtNewListNode(arg4, addArgs);
7376 GenTree* arg3 = gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR);
7377 addArgs = gtNewListNode(arg3, addArgs);
7379 call->gtCallArgs->Rest()->Rest() = addArgs;
7385 bool Compiler::fgCastNeeded(GenTree* tree, var_types toType)
7388 // If tree is a relop and we need an 4-byte integer
7389 // then we never need to insert a cast
7391 if ((tree->OperKind() & GTK_RELOP) && (genActualType(toType) == TYP_INT))
7399 // Is the tree as GT_CAST or a GT_CALL ?
7401 if (tree->OperGet() == GT_CAST)
7403 fromType = tree->CastToType();
7405 else if (tree->OperGet() == GT_CALL)
7407 fromType = (var_types)tree->gtCall.gtReturnType;
7411 fromType = tree->TypeGet();
7415 // If both types are the same then an additional cast is not necessary
7417 if (toType == fromType)
7422 // If the sign-ness of the two types are different then a cast is necessary
7424 if (varTypeIsUnsigned(toType) != varTypeIsUnsigned(fromType))
7429 // If the from type is the same size or smaller then an additional cast is not necessary
7431 if (genTypeSize(toType) >= genTypeSize(fromType))
7437 // Looks like we will need the cast
7442 // If assigning to a local var, add a cast if the target is
7443 // marked as NormalizedOnStore. Returns true if any change was made
7444 GenTree* Compiler::fgDoNormalizeOnStore(GenTree* tree)
7447 // Only normalize the stores in the global morph phase
7451 noway_assert(tree->OperGet() == GT_ASG);
7453 GenTree* op1 = tree->gtOp.gtOp1;
7454 GenTree* op2 = tree->gtOp.gtOp2;
7456 if (op1->gtOper == GT_LCL_VAR && genActualType(op1->TypeGet()) == TYP_INT)
7458 // Small-typed arguments and aliased locals are normalized on load.
7459 // Other small-typed locals are normalized on store.
7460 // If it is an assignment to one of the latter, insert the cast on RHS
7461 unsigned varNum = op1->gtLclVarCommon.gtLclNum;
7462 LclVarDsc* varDsc = &lvaTable[varNum];
7464 if (varDsc->lvNormalizeOnStore())
7466 noway_assert(op1->gtType <= TYP_INT);
7467 op1->gtType = TYP_INT;
7469 if (fgCastNeeded(op2, varDsc->TypeGet()))
7471 op2 = gtNewCastNode(TYP_INT, op2, false, varDsc->TypeGet());
7472 tree->gtOp.gtOp2 = op2;
7474 // Propagate GTF_COLON_COND
7475 op2->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7484 /*****************************************************************************
7486 * Mark whether the edge "srcBB -> dstBB" forms a loop that will always
7487 * execute a call or not.
7490 inline void Compiler::fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB)
7492 /* Bail if this is not a backward edge */
7494 if (srcBB->bbNum < dstBB->bbNum)
7499 /* Unless we already know that there is a loop without a call here ... */
7501 if (!(dstBB->bbFlags & BBF_LOOP_CALL0))
7503 /* Check whether there is a loop path that doesn't call */
7505 if (optReachWithoutCall(dstBB, srcBB))
7507 dstBB->bbFlags |= BBF_LOOP_CALL0;
7508 dstBB->bbFlags &= ~BBF_LOOP_CALL1;
7512 dstBB->bbFlags |= BBF_LOOP_CALL1;
7515 // if this loop will always call, then we can omit the GC Poll
7516 if ((GCPOLL_NONE != opts.compGCPollType) && (dstBB->bbFlags & BBF_LOOP_CALL1))
7518 srcBB->bbFlags &= ~BBF_NEEDS_GCPOLL;
7522 /*****************************************************************************
7524 * Mark which loops are guaranteed to execute a call.
7527 void Compiler::fgLoopCallMark()
7531 /* If we've already marked all the block, bail */
7533 if (fgLoopCallMarked)
7538 fgLoopCallMarked = true;
7540 /* Walk the blocks, looking for backward edges */
7542 for (block = fgFirstBB; block; block = block->bbNext)
7544 switch (block->bbJumpKind)
7547 case BBJ_CALLFINALLY:
7549 case BBJ_EHCATCHRET:
7550 fgLoopCallTest(block, block->bbJumpDest);
7556 jumpCnt = block->bbJumpSwt->bbsCount;
7557 BasicBlock** jumpPtr;
7558 jumpPtr = block->bbJumpSwt->bbsDstTab;
7562 fgLoopCallTest(block, *jumpPtr);
7563 } while (++jumpPtr, --jumpCnt);
7573 /*****************************************************************************
7575 * Note the fact that the given block is a loop header.
7578 inline void Compiler::fgMarkLoopHead(BasicBlock* block)
7583 printf("fgMarkLoopHead: Checking loop head block BB%02u: ", block->bbNum);
7587 /* Have we decided to generate fully interruptible code already? */
7589 if (genInterruptible)
7594 printf("method is already fully interruptible\n");
7600 /* Is the loop head block known to execute a method call? */
7602 if (block->bbFlags & BBF_GC_SAFE_POINT)
7607 printf("this block will execute a call\n");
7610 // single block loops that contain GC safe points don't need polls.
7611 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
7615 /* Are dominator sets available? */
7619 /* Make sure that we know which loops will always execute calls */
7621 if (!fgLoopCallMarked)
7626 /* Will every trip through our loop execute a call? */
7628 if (block->bbFlags & BBF_LOOP_CALL1)
7633 printf("this block dominates a block that will execute a call\n");
7641 * We have to make this method fully interruptible since we can not
7642 * ensure that this loop will execute a call every time it loops.
7644 * We'll also need to generate a full register map for this method.
7647 assert(!codeGen->isGCTypeFixed());
7649 if (!compCanEncodePtrArgCntMax())
7654 printf("a callsite with more than 1023 pushed args exists\n");
7663 printf("no guaranteed callsite exits, marking method as fully interruptible\n");
7667 // only enable fully interruptible code for if we're hijacking.
7668 if (GCPOLL_NONE == opts.compGCPollType)
7670 genInterruptible = true;
7674 GenTree* Compiler::fgGetCritSectOfStaticMethod()
7676 noway_assert(!compIsForInlining());
7678 noway_assert(info.compIsStatic); // This method should only be called for static methods.
7680 GenTree* tree = nullptr;
7682 CORINFO_LOOKUP_KIND kind = info.compCompHnd->getLocationOfThisType(info.compMethodHnd);
7684 if (!kind.needsRuntimeLookup)
7686 void *critSect = nullptr, **pCrit = nullptr;
7687 critSect = info.compCompHnd->getMethodSync(info.compMethodHnd, (void**)&pCrit);
7688 noway_assert((!critSect) != (!pCrit));
7690 tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL, info.compMethodHnd);
7694 // Collectible types requires that for shared generic code, if we use the generic context paramter
7695 // that we report it. (This is a conservative approach, we could detect some cases particularly when the
7696 // context parameter is this that we don't need the eager reporting logic.)
7697 lvaGenericsContextUseCount++;
7699 switch (kind.runtimeLookupKind)
7701 case CORINFO_LOOKUP_THISOBJ:
7703 noway_assert(!"Should never get this for static method.");
7707 case CORINFO_LOOKUP_CLASSPARAM:
7709 // In this case, the hidden param is the class handle.
7710 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7714 case CORINFO_LOOKUP_METHODPARAM:
7716 // In this case, the hidden param is the method handle.
7717 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
7718 // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the class handle
7719 // from the method handle.
7720 tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, gtNewArgList(tree));
7726 noway_assert(!"Unknown LOOKUP_KIND");
7731 noway_assert(tree); // tree should now contain the CORINFO_CLASS_HANDLE for the exact class.
7733 // Given the class handle, get the pointer to the Monitor.
7734 tree = gtNewHelperCallNode(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, TYP_I_IMPL, gtNewArgList(tree));
7741 #if FEATURE_EH_FUNCLETS
7743 /*****************************************************************************
7745 * Add monitor enter/exit calls for synchronized methods, and a try/fault
7746 * to ensure the 'exit' is called if the 'enter' was successful. On x86, we
7747 * generate monitor enter/exit calls and tell the VM the code location of
7748 * these calls. When an exception occurs between those locations, the VM
7749 * automatically releases the lock. For non-x86 platforms, the JIT is
7750 * responsible for creating a try/finally to protect the monitor enter/exit,
7751 * and the VM doesn't need to know anything special about the method during
7752 * exception processing -- it's just a normal try/finally.
7754 * We generate the following code:
7758 * unsigned byte acquired = 0;
7760 * JIT_MonEnterWorker(<lock object>, &acquired);
7762 * *** all the preexisting user code goes here ***
7764 * JIT_MonExitWorker(<lock object>, &acquired);
7766 * JIT_MonExitWorker(<lock object>, &acquired);
7772 * If the lock is actually acquired, then the 'acquired' variable is set to 1
7773 * by the helper call. During normal exit, the finally is called, 'acquired'
7774 * is 1, and the lock is released. If an exception occurs before the lock is
7775 * acquired, but within the 'try' (extremely unlikely, but possible), 'acquired'
7776 * will be 0, and the monitor exit call will quickly return without attempting
7777 * to release the lock. Otherwise, 'acquired' will be 1, and the lock will be
7778 * released during exception processing.
7780 * For synchronized methods, we generate a single return block.
7781 * We can do this without creating additional "step" blocks because "ret" blocks
7782 * must occur at the top-level (of the original code), not nested within any EH
7783 * constructs. From the CLI spec, 12.4.2.8.2.3 "ret": "Shall not be enclosed in any
7784 * protected block, filter, or handler." Also, 3.57: "The ret instruction cannot be
7785 * used to transfer control out of a try, filter, catch, or finally block. From within
7786 * a try or catch, use the leave instruction with a destination of a ret instruction
7787 * that is outside all enclosing exception blocks."
7789 * In addition, we can add a "fault" at the end of a method and be guaranteed that no
7790 * control falls through. From the CLI spec, section 12.4 "Control flow": "Control is not
7791 * permitted to simply fall through the end of a method. All paths shall terminate with one
7792 * of these instructions: ret, throw, jmp, or (tail. followed by call, calli, or callvirt)."
7794 * We only need to worry about "ret" and "throw", as the CLI spec prevents any other
7795 * alternatives. Section 15.4.3.3 "Implementation information" states about exiting
7796 * synchronized methods: "Exiting a synchronized method using a tail. call shall be
7797 * implemented as though the tail. had not been specified." Section 3.37 "jmp" states:
7798 * "The jmp instruction cannot be used to transferred control out of a try, filter,
7799 * catch, fault or finally block; or out of a synchronized region." And, "throw" will
7800 * be handled naturally; no additional work is required.
7803 void Compiler::fgAddSyncMethodEnterExit()
7805 assert((info.compFlags & CORINFO_FLG_SYNCH) != 0);
7807 // We need to do this transformation before funclets are created.
7808 assert(!fgFuncletsCreated);
7810 // Assume we don't need to update the bbPreds lists.
7811 assert(!fgComputePredsDone);
7814 // If we don't support EH, we can't add the EH needed by synchronized methods.
7815 // Of course, we could simply ignore adding the EH constructs, since we don't
7816 // support exceptions being thrown in this mode, but we would still need to add
7817 // the monitor enter/exit, and that doesn't seem worth it for this minor case.
7818 // By the time EH is working, we can just enable the whole thing.
7819 NYI("No support for synchronized methods");
7820 #endif // !FEATURE_EH
7822 // Create a scratch first BB where we can put the new variable initialization.
7823 // Don't put the scratch BB in the protected region.
7825 fgEnsureFirstBBisScratch();
7827 // Create a block for the start of the try region, where the monitor enter call
7830 assert(fgFirstBB->bbFallsThrough());
7832 BasicBlock* tryBegBB = fgNewBBafter(BBJ_NONE, fgFirstBB, false);
7833 BasicBlock* tryNextBB = tryBegBB->bbNext;
7834 BasicBlock* tryLastBB = fgLastBB;
7836 // If we have profile data the new block will inherit the next block's weight
7837 if (tryNextBB->hasProfileWeight())
7839 tryBegBB->inheritWeight(tryNextBB);
7842 // Create a block for the fault.
7844 assert(!tryLastBB->bbFallsThrough());
7845 BasicBlock* faultBB = fgNewBBafter(BBJ_EHFINALLYRET, tryLastBB, false);
7847 assert(tryLastBB->bbNext == faultBB);
7848 assert(faultBB->bbNext == nullptr);
7849 assert(faultBB == fgLastBB);
7851 { // Scope the EH region creation
7853 // Add the new EH region at the end, since it is the least nested,
7854 // and thus should be last.
7857 unsigned XTnew = compHndBBtabCount;
7859 newEntry = fgAddEHTableEntry(XTnew);
7861 // Initialize the new entry
7863 newEntry->ebdHandlerType = EH_HANDLER_FAULT;
7865 newEntry->ebdTryBeg = tryBegBB;
7866 newEntry->ebdTryLast = tryLastBB;
7868 newEntry->ebdHndBeg = faultBB;
7869 newEntry->ebdHndLast = faultBB;
7871 newEntry->ebdTyp = 0; // unused for fault
7873 newEntry->ebdEnclosingTryIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7874 newEntry->ebdEnclosingHndIndex = EHblkDsc::NO_ENCLOSING_INDEX;
7876 newEntry->ebdTryBegOffset = tryBegBB->bbCodeOffs;
7877 newEntry->ebdTryEndOffset = tryLastBB->bbCodeOffsEnd;
7878 newEntry->ebdFilterBegOffset = 0;
7879 newEntry->ebdHndBegOffset = 0; // handler doesn't correspond to any IL
7880 newEntry->ebdHndEndOffset = 0; // handler doesn't correspond to any IL
7882 // Set some flags on the new region. This is the same as when we set up
7883 // EH regions in fgFindBasicBlocks(). Note that the try has no enclosing
7884 // handler, and the fault has no enclosing try.
7886 tryBegBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_TRY_BEG | BBF_IMPORTED;
7888 faultBB->bbFlags |= BBF_HAS_LABEL | BBF_DONT_REMOVE | BBF_IMPORTED;
7889 faultBB->bbCatchTyp = BBCT_FAULT;
7891 tryBegBB->setTryIndex(XTnew);
7892 tryBegBB->clearHndIndex();
7894 faultBB->clearTryIndex();
7895 faultBB->setHndIndex(XTnew);
7897 // Walk the user code blocks and set all blocks that don't already have a try handler
7898 // to point to the new try handler.
7901 for (tmpBB = tryBegBB->bbNext; tmpBB != faultBB; tmpBB = tmpBB->bbNext)
7903 if (!tmpBB->hasTryIndex())
7905 tmpBB->setTryIndex(XTnew);
7909 // Walk the EH table. Make every EH entry that doesn't already have an enclosing
7910 // try index mark this new entry as their enclosing try index.
7915 for (XTnum = 0, HBtab = compHndBBtab; XTnum < XTnew; XTnum++, HBtab++)
7917 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
7919 HBtab->ebdEnclosingTryIndex =
7920 (unsigned short)XTnew; // This EH region wasn't previously nested, but now it is.
7927 JITDUMP("Synchronized method - created additional EH descriptor EH#%u for try/fault wrapping monitor "
7930 fgDispBasicBlocks();
7934 fgVerifyHandlerTab();
7938 // Create a 'monitor acquired' boolean (actually, an unsigned byte: 1 = acquired, 0 = not acquired).
7940 var_types typeMonAcquired = TYP_UBYTE;
7941 this->lvaMonAcquired = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7943 lvaTable[lvaMonAcquired].lvType = typeMonAcquired;
7945 { // Scope the variables of the variable initialization
7947 // Initialize the 'acquired' boolean.
7949 GenTree* zero = gtNewZeroConNode(genActualType(typeMonAcquired));
7950 GenTree* varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
7951 GenTree* initNode = gtNewAssignNode(varNode, zero);
7953 fgInsertStmtAtEnd(fgFirstBB, initNode);
7958 printf("\nSynchronized method - Add 'acquired' initialization in first block %s\n",
7959 fgFirstBB->dspToString());
7960 gtDispTree(initNode);
7966 // Make a copy of the 'this' pointer to be used in the handler so it does not inhibit enregistration
7967 // of all uses of the variable.
7968 unsigned lvaCopyThis = 0;
7969 if (!info.compIsStatic)
7971 lvaCopyThis = lvaGrabTemp(true DEBUGARG("Synchronized method monitor acquired boolean"));
7972 lvaTable[lvaCopyThis].lvType = TYP_REF;
7974 GenTree* thisNode = gtNewLclvNode(info.compThisArg, TYP_REF);
7975 GenTree* copyNode = gtNewLclvNode(lvaCopyThis, TYP_REF);
7976 GenTree* initNode = gtNewAssignNode(copyNode, thisNode);
7978 fgInsertStmtAtEnd(tryBegBB, initNode);
7981 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, tryBegBB, true /*enter*/);
7984 fgCreateMonitorTree(lvaMonAcquired, lvaCopyThis, faultBB, false /*exit*/);
7986 // non-exceptional cases
7987 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
7989 if (block->bbJumpKind == BBJ_RETURN)
7991 fgCreateMonitorTree(lvaMonAcquired, info.compThisArg, block, false /*exit*/);
7996 // fgCreateMonitorTree: Create tree to execute a monitor enter or exit operation for synchronized methods
7997 // lvaMonAcquired: lvaNum of boolean variable that tracks if monitor has been acquired.
7998 // lvaThisVar: lvaNum of variable being used as 'this' pointer, may not be the original one. Is only used for
7999 // nonstatic methods
8000 // block: block to insert the tree in. It is inserted at the end or in the case of a return, immediately before the
8002 // enter: whether to create a monitor enter or exit
8004 GenTree* Compiler::fgCreateMonitorTree(unsigned lvaMonAcquired, unsigned lvaThisVar, BasicBlock* block, bool enter)
8006 // Insert the expression "enter/exitCrit(this, &acquired)" or "enter/exitCrit(handle, &acquired)"
8008 var_types typeMonAcquired = TYP_UBYTE;
8009 GenTree* varNode = gtNewLclvNode(lvaMonAcquired, typeMonAcquired);
8010 GenTree* varAddrNode = gtNewOperNode(GT_ADDR, TYP_BYREF, varNode);
8013 if (info.compIsStatic)
8015 tree = fgGetCritSectOfStaticMethod();
8016 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER_STATIC : CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID,
8017 gtNewArgList(tree, varAddrNode));
8021 tree = gtNewLclvNode(lvaThisVar, TYP_REF);
8022 tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT, TYP_VOID,
8023 gtNewArgList(tree, varAddrNode));
8029 printf("\nSynchronized method - Add monitor %s call to block %s\n", enter ? "enter" : "exit",
8030 block->dspToString());
8036 if (block->bbJumpKind == BBJ_RETURN && block->lastStmt()->gtStmtExpr->gtOper == GT_RETURN)
8038 GenTree* retNode = block->lastStmt()->gtStmtExpr;
8039 GenTree* retExpr = retNode->gtOp.gtOp1;
8041 if (retExpr != nullptr)
8043 // have to insert this immediately before the GT_RETURN so we transform:
8045 // ret(comma(comma(tmp=...,call mon_exit), tmp)
8048 // Before morph stage, it is possible to have a case of GT_RETURN(TYP_LONG, op1) where op1's type is
8049 // TYP_STRUCT (of 8-bytes) and op1 is call node. See the big comment block in impReturnInstruction()
8050 // for details for the case where info.compRetType is not the same as info.compRetNativeType. For
8051 // this reason pass compMethodInfo->args.retTypeClass which is guaranteed to be a valid class handle
8052 // if the return type is a value class. Note that fgInsertCommFormTemp() in turn uses this class handle
8053 // if the type of op1 is TYP_STRUCT to perform lvaSetStruct() on the new temp that is created, which
8054 // in turn passes it to VM to know the size of value type.
8055 GenTree* temp = fgInsertCommaFormTemp(&retNode->gtOp.gtOp1, info.compMethodInfo->args.retTypeClass);
8057 GenTree* lclVar = retNode->gtOp.gtOp1->gtOp.gtOp2;
8058 retNode->gtOp.gtOp1->gtOp.gtOp2 = gtNewOperNode(GT_COMMA, retExpr->TypeGet(), tree, lclVar);
8062 // Insert this immediately before the GT_RETURN
8063 fgInsertStmtNearEnd(block, tree);
8068 fgInsertStmtAtEnd(block, tree);
8074 // Convert a BBJ_RETURN block in a synchronized method to a BBJ_ALWAYS.
8075 // We've previously added a 'try' block around the original program code using fgAddSyncMethodEnterExit().
8076 // Thus, we put BBJ_RETURN blocks inside a 'try'. In IL this is illegal. Instead, we would
8077 // see a 'leave' inside a 'try' that would get transformed into BBJ_CALLFINALLY/BBJ_ALWAYS blocks
8078 // during importing, and the BBJ_ALWAYS would point at an outer block with the BBJ_RETURN.
8079 // Here, we mimic some of the logic of importing a LEAVE to get the same effect for synchronized methods.
8080 void Compiler::fgConvertSyncReturnToLeave(BasicBlock* block)
8082 assert(!fgFuncletsCreated);
8083 assert(info.compFlags & CORINFO_FLG_SYNCH);
8084 assert(genReturnBB != nullptr);
8085 assert(genReturnBB != block);
8086 assert(fgReturnCount <= 1); // We have a single return for synchronized methods
8087 assert(block->bbJumpKind == BBJ_RETURN);
8088 assert((block->bbFlags & BBF_HAS_JMP) == 0);
8089 assert(block->hasTryIndex());
8090 assert(!block->hasHndIndex());
8091 assert(compHndBBtabCount >= 1);
8093 unsigned tryIndex = block->getTryIndex();
8094 assert(tryIndex == compHndBBtabCount - 1); // The BBJ_RETURN must be at the top-level before we inserted the
8095 // try/finally, which must be the last EH region.
8097 EHblkDsc* ehDsc = ehGetDsc(tryIndex);
8098 assert(ehDsc->ebdEnclosingTryIndex ==
8099 EHblkDsc::NO_ENCLOSING_INDEX); // There are no enclosing regions of the BBJ_RETURN block
8100 assert(ehDsc->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX);
8102 // Convert the BBJ_RETURN to BBJ_ALWAYS, jumping to genReturnBB.
8103 block->bbJumpKind = BBJ_ALWAYS;
8104 block->bbJumpDest = genReturnBB;
8105 block->bbJumpDest->bbRefs++;
8110 printf("Synchronized method - convert block BB%02u to BBJ_ALWAYS [targets BB%02u]\n", block->bbNum,
8111 block->bbJumpDest->bbNum);
8116 #endif // FEATURE_EH_FUNCLETS
8118 //------------------------------------------------------------------------
8119 // fgAddReversePInvokeEnterExit: Add enter/exit calls for reverse PInvoke methods
8127 void Compiler::fgAddReversePInvokeEnterExit()
8129 assert(opts.IsReversePInvoke());
8131 lvaReversePInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Reverse Pinvoke FrameVar"));
8133 LclVarDsc* varDsc = &lvaTable[lvaReversePInvokeFrameVar];
8134 varDsc->lvType = TYP_BLK;
8135 varDsc->lvExactSize = eeGetEEInfo()->sizeOfReversePInvokeFrame;
8139 // Add enter pinvoke exit callout at the start of prolog
8141 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
8143 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, gtNewArgList(tree));
8145 fgEnsureFirstBBisScratch();
8147 fgInsertStmtAtBeg(fgFirstBB, tree);
8152 printf("\nReverse PInvoke method - Add reverse pinvoke enter in first basic block %s\n",
8153 fgFirstBB->dspToString());
8159 // Add reverse pinvoke exit callout at the end of epilog
8161 tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
8163 tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, gtNewArgList(tree));
8165 assert(genReturnBB != nullptr);
8167 fgInsertStmtNearEnd(genReturnBB, tree);
8172 printf("\nReverse PInvoke method - Add reverse pinvoke exit in return basic block %s\n",
8173 genReturnBB->dspToString());
8180 /*****************************************************************************
8182 * Return 'true' if there is more than one BBJ_RETURN block.
8185 bool Compiler::fgMoreThanOneReturnBlock()
8187 unsigned retCnt = 0;
8189 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
8191 if (block->bbJumpKind == BBJ_RETURN)
8206 // Define a helper class for merging return blocks (which we do when the input has
8207 // more than the limit for this configuration).
8209 // Notes: sets fgReturnCount, genReturnBB, and genReturnLocal.
8213 #ifdef JIT32_GCENCODER
8215 // X86 GC encoding has a hard limit of SET_EPILOGCNT_MAX epilogs.
8216 const static unsigned ReturnCountHardLimit = SET_EPILOGCNT_MAX;
8217 #else // JIT32_GCENCODER
8219 // We currently apply a hard limit of '4' to all other targets (see
8220 // the other uses of SET_EPILOGCNT_MAX), though it would be good
8221 // to revisit that decision based on CQ analysis.
8222 const static unsigned ReturnCountHardLimit = 4;
8223 #endif // JIT32_GCENCODER
8228 // As we discover returns, we'll record them in `returnBlocks`, until
8229 // the limit is reached, at which point we'll keep track of the merged
8230 // return blocks in `returnBlocks`.
8231 BasicBlock* returnBlocks[ReturnCountHardLimit];
8233 // Each constant value returned gets its own merged return block that
8234 // returns that constant (up to the limit on number of returns); in
8235 // `returnConstants` we track the constant values returned by these
8236 // merged constant return blocks.
8237 INT64 returnConstants[ReturnCountHardLimit];
8239 // Indicators of where in the lexical block list we'd like to place
8240 // each constant return block.
8241 BasicBlock* insertionPoints[ReturnCountHardLimit];
8243 // Number of return blocks allowed
8244 PhasedVar<unsigned> maxReturns;
8246 // Flag to keep track of when we've hit the limit of returns and are
8247 // actively merging returns together.
8248 bool mergingReturns = false;
8251 MergedReturns(Compiler* comp) : comp(comp)
8253 comp->fgReturnCount = 0;
8256 void SetMaxReturns(unsigned value)
8259 maxReturns.MarkAsReadOnly();
8262 //------------------------------------------------------------------------
8263 // Record: Make note of a return block in the input program.
8266 // returnBlock - Block in the input that has jump kind BBJ_RETURN
8269 // Updates fgReturnCount appropriately, and generates a merged return
8270 // block if necessary. If a constant merged return block is used,
8271 // `returnBlock` is rewritten to jump to it. If a non-constant return
8272 // block is used, `genReturnBB` is set to that block, and `genReturnLocal`
8273 // is set to the lclvar that it returns; morph will need to rewrite
8274 // `returnBlock` to set the local and jump to the return block in such
8275 // cases, which it will do after some key transformations like rewriting
8276 // tail calls and calls that return to hidden buffers. In either of these
8277 // cases, `fgReturnCount` and the merged return block's profile information
8278 // will be updated to reflect or anticipate the rewrite of `returnBlock`.
8280 void Record(BasicBlock* returnBlock)
8282 // Add this return to our tally
8283 unsigned oldReturnCount = comp->fgReturnCount++;
8285 if (!mergingReturns)
8287 if (oldReturnCount < maxReturns)
8289 // No need to merge just yet; simply record this return.
8290 returnBlocks[oldReturnCount] = returnBlock;
8294 // We'e reached our threshold
8295 mergingReturns = true;
8297 // Merge any returns we've already identified
8298 for (unsigned i = 0, searchLimit = 0; i < oldReturnCount; ++i)
8300 BasicBlock* mergedReturnBlock = Merge(returnBlocks[i], searchLimit);
8301 if (returnBlocks[searchLimit] == mergedReturnBlock)
8303 // We've added a new block to the searchable set
8309 // We have too many returns, so merge this one in.
8310 // Search limit is new return count minus one (to exclude this block).
8311 unsigned searchLimit = comp->fgReturnCount - 1;
8312 Merge(returnBlock, searchLimit);
8315 //------------------------------------------------------------------------
8316 // EagerCreate: Force creation of a non-constant merged return block `genReturnBB`.
8319 // The newly-created block which returns `genReturnLocal`.
8321 BasicBlock* EagerCreate()
8323 mergingReturns = true;
8324 return Merge(nullptr, 0);
8327 //------------------------------------------------------------------------
8328 // PlaceReturns: Move any generated const return blocks to an appropriate
8329 // spot in the lexical block list.
8332 // The goal is to set things up favorably for a reasonable layout without
8333 // putting too much burden on fgReorderBlocks; in particular, since that
8334 // method doesn't (currently) shuffle non-profile, non-rare code to create
8335 // fall-through and reduce gotos, this method places each const return
8336 // block immediately after its last predecessor, so that the flow from
8337 // there to it can become fallthrough without requiring any motion to be
8338 // performed by fgReorderBlocks.
8342 if (!mergingReturns)
8344 // No returns generated => no returns to place.
8348 for (unsigned index = 0; index < comp->fgReturnCount; ++index)
8350 BasicBlock* returnBlock = returnBlocks[index];
8351 BasicBlock* genReturnBlock = comp->genReturnBB;
8352 if (returnBlock == genReturnBlock)
8357 BasicBlock* insertionPoint = insertionPoints[index];
8358 assert(insertionPoint != nullptr);
8360 comp->fgUnlinkBlock(returnBlock);
8361 comp->fgMoveBlocksAfter(returnBlock, returnBlock, insertionPoint);
8362 // Treat the merged return block as belonging to the same EH region
8363 // as the insertion point block, to make sure we don't break up
8364 // EH regions; since returning a constant won't throw, this won't
8365 // affect program behavior.
8366 comp->fgExtendEHRegionAfter(insertionPoint);
8371 //------------------------------------------------------------------------
8372 // CreateReturnBB: Create a basic block to serve as a merged return point, stored to
8373 // `returnBlocks` at the given index, and optionally returning the given constant.
8376 // index - Index into `returnBlocks` to store the new block into.
8377 // returnConst - Constant that the new block should return; may be nullptr to
8378 // indicate that the new merged return is for the non-constant case, in which
8379 // case, if the method's return type is non-void, `comp->genReturnLocal` will
8380 // be initialized to a new local of the appropriate type, and the new block will
8384 // The new merged return block.
8386 BasicBlock* CreateReturnBB(unsigned index, GenTreeIntConCommon* returnConst = nullptr)
8388 BasicBlock* newReturnBB = comp->fgNewBBinRegion(BBJ_RETURN);
8389 newReturnBB->bbRefs = 1; // bbRefs gets update later, for now it should be 1
8390 comp->fgReturnCount++;
8392 newReturnBB->bbFlags |= BBF_INTERNAL;
8394 noway_assert(newReturnBB->bbNext == nullptr);
8399 printf("\n newReturnBB [BB%02u] created\n", newReturnBB->bbNum);
8403 // We have profile weight, the weight is zero, and the block is run rarely,
8404 // until we prove otherwise by merging other returns into this one.
8405 newReturnBB->bbFlags |= (BBF_PROF_WEIGHT | BBF_RUN_RARELY);
8406 newReturnBB->bbWeight = 0;
8408 GenTree* returnExpr;
8410 if (returnConst != nullptr)
8412 returnExpr = comp->gtNewOperNode(GT_RETURN, returnConst->gtType, returnConst);
8413 returnConstants[index] = returnConst->IntegralValue();
8415 else if (comp->compMethodHasRetVal())
8417 // There is a return value, so create a temp for it. Real returns will store the value in there and
8418 // it'll be reloaded by the single return.
8419 unsigned returnLocalNum = comp->lvaGrabTemp(true DEBUGARG("Single return block return value"));
8420 comp->genReturnLocal = returnLocalNum;
8421 LclVarDsc& returnLocalDsc = comp->lvaTable[returnLocalNum];
8423 if (comp->compMethodReturnsNativeScalarType())
8425 returnLocalDsc.lvType = genActualType(comp->info.compRetNativeType);
8427 else if (comp->compMethodReturnsRetBufAddr())
8429 returnLocalDsc.lvType = TYP_BYREF;
8431 else if (comp->compMethodReturnsMultiRegRetType())
8433 returnLocalDsc.lvType = TYP_STRUCT;
8434 comp->lvaSetStruct(returnLocalNum, comp->info.compMethodInfo->args.retTypeClass, true);
8435 returnLocalDsc.lvIsMultiRegRet = true;
8439 assert(!"unreached");
8442 if (varTypeIsFloating(returnLocalDsc.lvType))
8444 comp->compFloatingPointUsed = true;
8447 if (!varTypeIsFloating(comp->info.compRetType))
8449 returnLocalDsc.setPrefReg(REG_INTRET, comp);
8454 returnLocalDsc.setPrefReg(REG_FLOATRET, comp);
8459 // This temporary should not be converted to a double in stress mode,
8460 // because we introduce assigns to it after the stress conversion
8461 returnLocalDsc.lvKeepType = 1;
8464 GenTree* retTemp = comp->gtNewLclvNode(returnLocalNum, returnLocalDsc.TypeGet());
8466 // make sure copy prop ignores this node (make sure it always does a reload from the temp).
8467 retTemp->gtFlags |= GTF_DONT_CSE;
8468 returnExpr = comp->gtNewOperNode(GT_RETURN, retTemp->gtType, retTemp);
8473 noway_assert(comp->info.compRetType == TYP_VOID || varTypeIsStruct(comp->info.compRetType));
8474 comp->genReturnLocal = BAD_VAR_NUM;
8476 returnExpr = new (comp, GT_RETURN) GenTreeOp(GT_RETURN, TYP_VOID);
8479 // Add 'return' expression to the return block
8480 comp->fgInsertStmtAtEnd(newReturnBB, returnExpr);
8481 // Flag that this 'return' was generated by return merging so that subsequent
8482 // return block morhping will know to leave it alone.
8483 returnExpr->gtFlags |= GTF_RET_MERGED;
8488 printf("\nmergeReturns statement tree ");
8489 Compiler::printTreeID(returnExpr);
8490 printf(" added to genReturnBB %s\n", newReturnBB->dspToString());
8491 comp->gtDispTree(returnExpr);
8495 assert(index < maxReturns);
8496 returnBlocks[index] = newReturnBB;
8500 //------------------------------------------------------------------------
8501 // Merge: Find or create an appropriate merged return block for the given input block.
8504 // returnBlock - Return block from the input program to find a merged return for.
8505 // May be nullptr to indicate that new block suitable for non-constant
8506 // returns should be generated but no existing block modified.
8507 // searchLimit - Blocks in `returnBlocks` up to but not including index `searchLimit`
8508 // will be checked to see if we already have an appropriate merged return
8509 // block for this case. If a new block must be created, it will be stored
8510 // to `returnBlocks` at index `searchLimit`.
8513 // Merged return block suitable for handling this return value. May be newly-created
8517 // If a constant-valued merged return block is used, `returnBlock` will be rewritten to
8518 // jump to the merged return block and its `GT_RETURN` statement will be removed. If
8519 // a non-constant-valued merged return block is used, `genReturnBB` and `genReturnLocal`
8520 // will be set so that Morph can perform that rewrite, which it will do after some key
8521 // transformations like rewriting tail calls and calls that return to hidden buffers.
8522 // In either of these cases, `fgReturnCount` and the merged return block's profile
8523 // information will be updated to reflect or anticipate the rewrite of `returnBlock`.
8525 BasicBlock* Merge(BasicBlock* returnBlock, unsigned searchLimit)
8527 assert(mergingReturns);
8529 BasicBlock* mergedReturnBlock = nullptr;
8531 // Do not look for mergable constant returns in debug codegen as
8532 // we may lose track of sequence points.
8533 if ((returnBlock != nullptr) && (maxReturns > 1) && !comp->opts.compDbgCode)
8535 // Check to see if this is a constant return so that we can search
8536 // for and/or create a constant return block for it.
8538 GenTreeIntConCommon* retConst = GetReturnConst(returnBlock);
8539 if (retConst != nullptr)
8541 // We have a constant. Now find or create a corresponding return block.
8544 BasicBlock* constReturnBlock = FindConstReturnBlock(retConst, searchLimit, &index);
8546 if (constReturnBlock == nullptr)
8548 // We didn't find a const return block. See if we have space left
8551 // We have already allocated `searchLimit` slots.
8552 unsigned slotsReserved = searchLimit;
8553 if (comp->genReturnBB == nullptr)
8555 // We haven't made a non-const return yet, so we have to reserve
8560 if (slotsReserved < maxReturns)
8562 // We have enough space to allocate a slot for this constant.
8563 constReturnBlock = CreateReturnBB(searchLimit, retConst);
8567 if (constReturnBlock != nullptr)
8569 // Found a constant merged return block.
8570 mergedReturnBlock = constReturnBlock;
8572 // Change BBJ_RETURN to BBJ_ALWAYS targeting const return block.
8573 assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0);
8574 returnBlock->bbJumpKind = BBJ_ALWAYS;
8575 returnBlock->bbJumpDest = constReturnBlock;
8577 // Remove GT_RETURN since constReturnBlock returns the constant.
8578 assert(returnBlock->lastStmt()->gtStmtExpr->OperIs(GT_RETURN));
8579 assert(returnBlock->lastStmt()->gtStmtExpr->gtGetOp1()->IsIntegralConst());
8580 comp->fgRemoveStmt(returnBlock, returnBlock->lastStmt());
8582 // Using 'returnBlock' as the insertion point for 'mergedReturnBlock'
8583 // will give it a chance to use fallthrough rather than BBJ_ALWAYS.
8584 // Resetting this after each merge ensures that any branches to the
8585 // merged return block are lexically forward.
8587 insertionPoints[index] = returnBlock;
8592 if (mergedReturnBlock == nullptr)
8594 // No constant return block for this return; use the general one.
8595 mergedReturnBlock = comp->genReturnBB;
8596 if (mergedReturnBlock == nullptr)
8598 // No general merged return for this function yet; create one.
8599 // There had better still be room left in the array.
8600 assert(searchLimit < maxReturns);
8601 mergedReturnBlock = CreateReturnBB(searchLimit);
8602 comp->genReturnBB = mergedReturnBlock;
8603 // Downstream code expects the `genReturnBB` to always remain
8604 // once created, so that it can redirect flow edges to it.
8605 mergedReturnBlock->bbFlags |= BBF_DONT_REMOVE;
8609 if (returnBlock != nullptr)
8611 // Propagate profile weight and related annotations to the merged block.
8612 // Return weight should never exceed entry weight, so cap it to avoid nonsensical
8613 // hot returns in synthetic profile settings.
8614 mergedReturnBlock->bbWeight =
8615 min(mergedReturnBlock->bbWeight + returnBlock->bbWeight, comp->fgFirstBB->bbWeight);
8616 if (!returnBlock->hasProfileWeight())
8618 mergedReturnBlock->bbFlags &= ~BBF_PROF_WEIGHT;
8620 if (mergedReturnBlock->bbWeight > 0)
8622 mergedReturnBlock->bbFlags &= ~BBF_RUN_RARELY;
8625 // Update fgReturnCount to reflect or anticipate that `returnBlock` will no longer
8626 // be a return point.
8627 comp->fgReturnCount--;
8630 return mergedReturnBlock;
8633 //------------------------------------------------------------------------
8634 // GetReturnConst: If the given block returns an integral constant, return the
8635 // GenTreeIntConCommon that represents the constant.
8638 // returnBlock - Block whose return value is to be inspected.
8641 // GenTreeIntCommon that is the argument of `returnBlock`'s `GT_RETURN` if
8642 // such exists; nullptr otherwise.
8644 static GenTreeIntConCommon* GetReturnConst(BasicBlock* returnBlock)
8646 GenTreeStmt* lastStmt = returnBlock->lastStmt();
8647 if (lastStmt == nullptr)
8652 GenTree* lastExpr = lastStmt->gtStmtExpr;
8653 if (!lastExpr->OperIs(GT_RETURN))
8658 GenTree* retExpr = lastExpr->gtGetOp1();
8659 if ((retExpr == nullptr) || !retExpr->IsIntegralConst())
8664 return retExpr->AsIntConCommon();
8667 //------------------------------------------------------------------------
8668 // FindConstReturnBlock: Scan the already-created merged return blocks, up to `searchLimit`,
8669 // and return the one corresponding to the given const expression if it exists.
8672 // constExpr - GenTreeIntCommon representing the constant return value we're
8674 // searchLimit - Check `returnBlocks`/`returnConstants` up to but not including
8676 // index - [out] Index of return block in the `returnBlocks` array, if found;
8677 // searchLimit otherwise.
8680 // A block that returns the same constant, if one is found; otherwise nullptr.
8682 BasicBlock* FindConstReturnBlock(GenTreeIntConCommon* constExpr, unsigned searchLimit, unsigned* index)
8684 INT64 constVal = constExpr->IntegralValue();
8686 for (unsigned i = 0; i < searchLimit; ++i)
8688 // Need to check both for matching const val and for genReturnBB
8689 // because genReturnBB is used for non-constant returns and its
8690 // corresponding entry in the returnConstants array is garbage.
8691 if (returnConstants[i] == constVal)
8693 BasicBlock* returnBlock = returnBlocks[i];
8695 if (returnBlock == comp->genReturnBB)
8697 // This is the block used for non-constant returns, so
8698 // its returnConstants entry is just garbage; don't be
8708 *index = searchLimit;
8714 /*****************************************************************************
8716 * Add any internal blocks/trees we may need
8719 void Compiler::fgAddInternal()
8721 noway_assert(!compIsForInlining());
8723 #ifndef LEGACY_BACKEND
8724 // The RyuJIT backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is
8725 // required. Create it here.
8726 if (info.compCallUnmanaged != 0)
8728 fgEnsureFirstBBisScratch();
8729 fgFirstBB->bbFlags |= BBF_DONT_REMOVE;
8731 #endif // !LEGACY_BACKEND
8734 <BUGNUM> VSW441487 </BUGNUM>
8736 The "this" pointer is implicitly used in the following cases:
8737 1. Locking of synchronized methods
8738 2. Dictionary access of shared generics code
8739 3. If a method has "catch(FooException<T>)", the EH code accesses "this" to determine T.
8740 4. Initializing the type from generic methods which require precise cctor semantics
8741 5. Verifier does special handling of "this" in the .ctor
8743 However, we might overwrite it with a "starg 0".
8744 In this case, we will redirect all "ldarg(a)/starg(a) 0" to a temp lvaTable[lvaArg0Var]
8747 if (!info.compIsStatic)
8749 if (lvaArg0Var != info.compThisArg)
8751 // When we're using the general encoder, we mark compThisArg address-taken to ensure that it is not
8752 // enregistered (since the decoder always reports a stack location for "this" for generics
8754 bool lva0CopiedForGenericsCtxt;
8755 #ifndef JIT32_GCENCODER
8756 lva0CopiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
8757 #else // JIT32_GCENCODER
8758 lva0CopiedForGenericsCtxt = false;
8759 #endif // JIT32_GCENCODER
8760 noway_assert(lva0CopiedForGenericsCtxt || !lvaTable[info.compThisArg].lvAddrExposed);
8761 noway_assert(!lvaTable[info.compThisArg].lvHasILStoreOp);
8762 noway_assert(lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvHasILStoreOp ||
8763 lva0CopiedForGenericsCtxt);
8765 var_types thisType = lvaTable[info.compThisArg].TypeGet();
8767 // Now assign the original input "this" to the temp
8771 tree = gtNewLclvNode(lvaArg0Var, thisType);
8773 tree = gtNewAssignNode(tree, // dst
8774 gtNewLclvNode(info.compThisArg, thisType) // src
8777 /* Create a new basic block and stick the assignment in it */
8779 fgEnsureFirstBBisScratch();
8781 fgInsertStmtAtEnd(fgFirstBB, tree);
8786 printf("\nCopy \"this\" to lvaArg0Var in first basic block %s\n", fgFirstBB->dspToString());
8794 // Grab a temp for the security object.
8795 // (Note: opts.compDbgEnC currently also causes the security object to be generated. See Compiler::compCompile)
8796 if (opts.compNeedSecurityCheck)
8798 noway_assert(lvaSecurityObject == BAD_VAR_NUM);
8799 lvaSecurityObject = lvaGrabTempWithImplicitUse(false DEBUGARG("security check"));
8800 lvaTable[lvaSecurityObject].lvType = TYP_REF;
8803 // Merge return points if required or beneficial
8804 MergedReturns merger(this);
8806 #if FEATURE_EH_FUNCLETS
8807 // Add the synchronized method enter/exit calls and try/finally protection. Note
8808 // that this must happen before the one BBJ_RETURN block is created below, so the
8809 // BBJ_RETURN block gets placed at the top-level, not within an EH region. (Otherwise,
8810 // we'd have to be really careful when creating the synchronized method try/finally
8811 // not to include the BBJ_RETURN block.)
8812 if ((info.compFlags & CORINFO_FLG_SYNCH) != 0)
8814 fgAddSyncMethodEnterExit();
8816 #endif // FEATURE_EH_FUNCLETS
8819 // We will generate just one epilog (return block)
8820 // when we are asked to generate enter/leave callbacks
8821 // or for methods with PInvoke
8822 // or for methods calling into unmanaged code
8823 // or for synchronized methods.
8825 BasicBlock* lastBlockBeforeGenReturns = fgLastBB;
8826 if (compIsProfilerHookNeeded() || (info.compCallUnmanaged != 0) || opts.IsReversePInvoke() ||
8827 ((info.compFlags & CORINFO_FLG_SYNCH) != 0))
8829 // We will generate only one return block
8830 // We will transform the BBJ_RETURN blocks
8831 // into jumps to the one return block
8833 merger.SetMaxReturns(1);
8835 // Eagerly create the genReturnBB since the lowering of these constructs
8836 // will expect to find it.
8837 BasicBlock* mergedReturn = merger.EagerCreate();
8838 assert(mergedReturn == genReturnBB);
8839 // Assume weight equal to entry weight for this BB.
8840 mergedReturn->bbFlags &= ~BBF_PROF_WEIGHT;
8841 mergedReturn->bbWeight = fgFirstBB->bbWeight;
8842 if (mergedReturn->bbWeight > 0)
8844 mergedReturn->bbFlags &= ~BBF_RUN_RARELY;
8850 // We are allowed to have multiple individual exits
8851 // However we can still decide to have a single return
8853 if (compCodeOpt() == SMALL_CODE)
8855 // For the Small_Code case we always generate a
8856 // single return block when we have multiple
8859 merger.SetMaxReturns(1);
8863 merger.SetMaxReturns(MergedReturns::ReturnCountHardLimit);
8867 // Visit the BBJ_RETURN blocks and merge as necessary.
8869 for (BasicBlock* block = fgFirstBB; block != lastBlockBeforeGenReturns->bbNext; block = block->bbNext)
8871 if ((block->bbJumpKind == BBJ_RETURN) && ((block->bbFlags & BBF_HAS_JMP) == 0))
8873 merger.Record(block);
8877 merger.PlaceReturns();
8879 if (info.compCallUnmanaged != 0)
8881 // The P/Invoke helpers only require a frame variable, so only allocate the
8882 // TCB variable if we're not using them.
8883 if (!opts.ShouldUsePInvokeHelpers())
8885 info.compLvFrameListRoot = lvaGrabTemp(false DEBUGARG("Pinvoke FrameListRoot"));
8888 lvaInlinedPInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Pinvoke FrameVar"));
8890 LclVarDsc* varDsc = &lvaTable[lvaInlinedPInvokeFrameVar];
8891 varDsc->addPrefReg(RBM_PINVOKE_TCB, this);
8892 varDsc->lvType = TYP_BLK;
8893 // Make room for the inlined frame.
8894 varDsc->lvExactSize = eeGetEEInfo()->inlinedCallFrameInfo.size;
8895 #if FEATURE_FIXED_OUT_ARGS
8896 // Grab and reserve space for TCB, Frame regs used in PInvoke epilog to pop the inlined frame.
8897 // See genPInvokeMethodEpilog() for use of the grabbed var. This is only necessary if we are
8898 // not using the P/Invoke helpers.
8899 if (!opts.ShouldUsePInvokeHelpers() && compJmpOpUsed)
8901 lvaPInvokeFrameRegSaveVar = lvaGrabTempWithImplicitUse(false DEBUGARG("PInvokeFrameRegSave Var"));
8902 varDsc = &lvaTable[lvaPInvokeFrameRegSaveVar];
8903 varDsc->lvType = TYP_BLK;
8904 varDsc->lvExactSize = 2 * REGSIZE_BYTES;
8909 // Do we need to insert a "JustMyCode" callback?
8911 CORINFO_JUST_MY_CODE_HANDLE* pDbgHandle = nullptr;
8912 CORINFO_JUST_MY_CODE_HANDLE dbgHandle = nullptr;
8913 if (opts.compDbgCode && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB))
8915 dbgHandle = info.compCompHnd->getJustMyCodeHandle(info.compMethodHnd, &pDbgHandle);
8918 #ifdef _TARGET_ARM64_
8919 // TODO-ARM64-NYI: don't do just-my-code
8920 dbgHandle = nullptr;
8921 pDbgHandle = nullptr;
8922 #endif // _TARGET_ARM64_
8924 noway_assert(!dbgHandle || !pDbgHandle);
8926 if (dbgHandle || pDbgHandle)
8928 GenTree* embNode = gtNewIconEmbHndNode(dbgHandle, pDbgHandle, GTF_ICON_TOKEN_HDL, info.compMethodHnd);
8929 GenTree* guardCheckVal = gtNewOperNode(GT_IND, TYP_INT, embNode);
8930 GenTree* guardCheckCond = gtNewOperNode(GT_EQ, TYP_INT, guardCheckVal, gtNewZeroConNode(TYP_INT));
8931 guardCheckCond->gtFlags |= GTF_RELOP_QMARK;
8933 // Create the callback which will yield the final answer
8935 GenTree* callback = gtNewHelperCallNode(CORINFO_HELP_DBG_IS_JUST_MY_CODE, TYP_VOID);
8936 callback = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), callback);
8938 // Stick the conditional call at the start of the method
8940 fgEnsureFirstBBisScratch();
8941 fgInsertStmtAtEnd(fgFirstBB, gtNewQmarkNode(TYP_VOID, guardCheckCond, callback));
8944 /* Do we need to call out for security ? */
8946 if (tiSecurityCalloutNeeded)
8948 // We must have grabbed this local.
8949 noway_assert(opts.compNeedSecurityCheck);
8950 noway_assert(lvaSecurityObject != BAD_VAR_NUM);
8954 /* Insert the expression "call JIT_Security_Prolog(MethodHnd, &SecurityObject)" */
8956 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
8958 tree = gtNewHelperCallNode(info.compCompHnd->getSecurityPrologHelper(info.compMethodHnd), TYP_VOID,
8959 gtNewArgList(tree, gtNewOperNode(GT_ADDR, TYP_BYREF,
8960 gtNewLclvNode(lvaSecurityObject, TYP_REF))));
8962 /* Create a new basic block and stick the call in it */
8964 fgEnsureFirstBBisScratch();
8966 fgInsertStmtAtEnd(fgFirstBB, tree);
8971 printf("\ntiSecurityCalloutNeeded - Add call JIT_Security_Prolog(%08p) statement ",
8972 dspPtr(info.compMethodHnd));
8974 printf(" in first basic block %s\n", fgFirstBB->dspToString());
8981 #if !FEATURE_EH_FUNCLETS
8983 /* Is this a 'synchronized' method? */
8985 if (info.compFlags & CORINFO_FLG_SYNCH)
8987 GenTree* tree = NULL;
8989 /* Insert the expression "enterCrit(this)" or "enterCrit(handle)" */
8991 if (info.compIsStatic)
8993 tree = fgGetCritSectOfStaticMethod();
8995 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER_STATIC, TYP_VOID, gtNewArgList(tree));
8999 noway_assert(lvaTable[info.compThisArg].lvType == TYP_REF);
9001 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
9003 tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER, TYP_VOID, gtNewArgList(tree));
9006 /* Create a new basic block and stick the call in it */
9008 fgEnsureFirstBBisScratch();
9010 fgInsertStmtAtEnd(fgFirstBB, tree);
9015 printf("\nSynchronized method - Add enterCrit statement in first basic block %s\n",
9016 fgFirstBB->dspToString());
9022 /* We must be generating a single exit point for this to work */
9024 noway_assert(genReturnBB != nullptr);
9026 /* Create the expression "exitCrit(this)" or "exitCrit(handle)" */
9028 if (info.compIsStatic)
9030 tree = fgGetCritSectOfStaticMethod();
9032 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, gtNewArgList(tree));
9036 tree = gtNewLclvNode(info.compThisArg, TYP_REF);
9038 tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT, TYP_VOID, gtNewArgList(tree));
9041 fgInsertStmtNearEnd(genReturnBB, tree);
9046 printf("\nSynchronized method - Add exit expression ");
9052 // Reset cookies used to track start and end of the protected region in synchronized methods
9053 syncStartEmitCookie = NULL;
9054 syncEndEmitCookie = NULL;
9057 #endif // !FEATURE_EH_FUNCLETS
9059 /* Do we need to do runtime call out to check the security? */
9061 if (tiRuntimeCalloutNeeded)
9065 /* Insert the expression "call verificationRuntimeCheck(MethodHnd)" */
9067 tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
9069 tree = gtNewHelperCallNode(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, TYP_VOID, gtNewArgList(tree));
9071 /* Create a new basic block and stick the call in it */
9073 fgEnsureFirstBBisScratch();
9075 fgInsertStmtAtEnd(fgFirstBB, tree);
9080 printf("\ntiRuntimeCalloutNeeded - Call verificationRuntimeCheck(%08p) statement in first basic block %s\n",
9081 dspPtr(info.compMethodHnd), fgFirstBB->dspToString());
9088 if (opts.IsReversePInvoke())
9090 fgAddReversePInvokeEnterExit();
9096 printf("\n*************** After fgAddInternal()\n");
9097 fgDispBasicBlocks();
9103 /*****************************************************************************
9105 * Create a new statement from tree and wire the links up.
9107 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTree* tree, BasicBlock* block, IL_OFFSETX offs)
9109 GenTreeStmt* stmt = gtNewStmt(tree, offs);
9111 if (fgStmtListThreaded)
9113 gtSetStmtInfo(stmt);
9118 if (block != nullptr)
9120 fgDebugCheckNodeLinks(block, stmt);
9127 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTree* tree)
9129 return fgNewStmtFromTree(tree, nullptr, BAD_IL_OFFSET);
9132 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTree* tree, BasicBlock* block)
9134 return fgNewStmtFromTree(tree, block, BAD_IL_OFFSET);
9137 GenTreeStmt* Compiler::fgNewStmtFromTree(GenTree* tree, IL_OFFSETX offs)
9139 return fgNewStmtFromTree(tree, nullptr, offs);
9142 //------------------------------------------------------------------------
9143 // fgFindBlockILOffset: Given a block, find the IL offset corresponding to the first statement
9144 // in the block with a legal IL offset. Skip any leading statements that have BAD_IL_OFFSET.
9145 // If no statement has an initialized statement offset (including the case where there are
9146 // no statements in the block), then return BAD_IL_OFFSET. This function is used when
9147 // blocks are split or modified, and we want to maintain the IL offset as much as possible
9148 // to preserve good debugging behavior.
9151 // block - The block to check.
9154 // The first good IL offset of a statement in the block, or BAD_IL_OFFSET if such an IL offset
9157 IL_OFFSET Compiler::fgFindBlockILOffset(BasicBlock* block)
9159 // This function searches for IL offsets in statement nodes, so it can't be used in LIR. We
9160 // could have a similar function for LIR that searches for GT_IL_OFFSET nodes.
9161 assert(!block->IsLIR());
9163 for (GenTree* stmt = block->bbTreeList; stmt != nullptr; stmt = stmt->gtNext)
9165 assert(stmt->IsStatement());
9166 if (stmt->gtStmt.gtStmtILoffsx != BAD_IL_OFFSET)
9168 return jitGetILoffs(stmt->gtStmt.gtStmtILoffsx);
9172 return BAD_IL_OFFSET;
9175 //------------------------------------------------------------------------------
9176 // fgSplitBlockAtEnd - split the given block into two blocks.
9177 // All code in the block stays in the original block.
9178 // Control falls through from original to new block, and
9179 // the new block is returned.
9180 //------------------------------------------------------------------------------
9181 BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr)
9183 // We'd like to use fgNewBBafter(), but we need to update the preds list before linking in the new block.
9184 // (We need the successors of 'curr' to be correct when we do this.)
9185 BasicBlock* newBlock = bbNewBasicBlock(curr->bbJumpKind);
9187 // Start the new block with no refs. When we set the preds below, this will get updated correctly.
9188 newBlock->bbRefs = 0;
9190 // For each successor of the original block, set the new block as their predecessor.
9191 // Note we are using the "rational" version of the successor iterator that does not hide the finallyret arcs.
9192 // Without these arcs, a block 'b' may not be a member of succs(preds(b))
9193 if (curr->bbJumpKind != BBJ_SWITCH)
9195 unsigned numSuccs = curr->NumSucc(this);
9196 for (unsigned i = 0; i < numSuccs; i++)
9198 BasicBlock* succ = curr->GetSucc(i, this);
9199 if (succ != newBlock)
9201 JITDUMP("BB%02u previous predecessor was BB%02u, now is BB%02u\n", succ->bbNum, curr->bbNum,
9203 fgReplacePred(succ, curr, newBlock);
9207 newBlock->bbJumpDest = curr->bbJumpDest;
9208 curr->bbJumpDest = nullptr;
9212 // In the case of a switch statement there's more complicated logic in order to wire up the predecessor lists
9213 // but fortunately there's an existing method that implements this functionality.
9214 newBlock->bbJumpSwt = curr->bbJumpSwt;
9216 fgChangeSwitchBlock(curr, newBlock);
9218 curr->bbJumpSwt = nullptr;
9221 newBlock->inheritWeight(curr);
9223 // Set the new block's flags. Note that the new block isn't BBF_INTERNAL unless the old block is.
9224 newBlock->bbFlags = curr->bbFlags;
9226 // Remove flags that the new block can't have.
9227 newBlock->bbFlags &= ~(BBF_TRY_BEG | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1 | BBF_HAS_LABEL |
9228 BBF_JMP_TARGET | BBF_FUNCLET_BEG | BBF_LOOP_PREHEADER | BBF_KEEP_BBJ_ALWAYS);
9230 // Remove the GC safe bit on the new block. It seems clear that if we split 'curr' at the end,
9231 // such that all the code is left in 'curr', and 'newBlock' just gets the control flow, then
9232 // both 'curr' and 'newBlock' could accurately retain an existing GC safe bit. However, callers
9233 // use this function to split blocks in the middle, or at the beginning, and they don't seem to
9234 // be careful about updating this flag appropriately. So, removing the GC safe bit is simply
9235 // conservative: some functions might end up being fully interruptible that could be partially
9236 // interruptible if we exercised more care here.
9237 newBlock->bbFlags &= ~BBF_GC_SAFE_POINT;
9239 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9240 newBlock->bbFlags &= ~(BBF_FINALLY_TARGET);
9241 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
9243 // The new block has no code, so we leave bbCodeOffs/bbCodeOffsEnd set to BAD_IL_OFFSET. If a caller
9244 // puts code in the block, then it needs to update these.
9246 // Insert the new block in the block list after the 'curr' block.
9247 fgInsertBBafter(curr, newBlock);
9248 fgExtendEHRegionAfter(curr); // The new block is in the same EH region as the old block.
9250 // Remove flags from the old block that are no longer possible.
9251 curr->bbFlags &= ~(BBF_HAS_JMP | BBF_RETLESS_CALL);
9253 // Default to fallthru, and add the arc for that.
9254 curr->bbJumpKind = BBJ_NONE;
9255 fgAddRefPred(newBlock, curr);
9260 //------------------------------------------------------------------------------
9261 // fgSplitBlockAfterStatement - Split the given block, with all code after
9262 // the given statement going into the second block.
9263 //------------------------------------------------------------------------------
9264 BasicBlock* Compiler::fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt)
9266 assert(!curr->IsLIR()); // No statements in LIR, so you can't use this function.
9268 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
9272 newBlock->bbTreeList = stmt->gtNext;
9273 if (newBlock->bbTreeList)
9275 newBlock->bbTreeList->gtPrev = curr->bbTreeList->gtPrev;
9277 curr->bbTreeList->gtPrev = stmt;
9278 stmt->gtNext = nullptr;
9280 // Update the IL offsets of the blocks to match the split.
9282 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
9283 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
9285 // curr->bbCodeOffs remains the same
9286 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
9288 IL_OFFSET splitPointILOffset = fgFindBlockILOffset(newBlock);
9290 curr->bbCodeOffsEnd = splitPointILOffset;
9291 newBlock->bbCodeOffs = splitPointILOffset;
9295 assert(curr->bbTreeList == nullptr); // if no tree was given then it better be an empty block
9301 //------------------------------------------------------------------------------
9302 // fgSplitBlockAfterNode - Split the given block, with all code after
9303 // the given node going into the second block.
9304 // This function is only used in LIR.
9305 //------------------------------------------------------------------------------
9306 BasicBlock* Compiler::fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node)
9308 assert(curr->IsLIR());
9310 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
9312 if (node != nullptr)
9314 LIR::Range& currBBRange = LIR::AsRange(curr);
9316 if (node != currBBRange.LastNode())
9318 LIR::Range nodesToMove = currBBRange.Remove(node->gtNext, currBBRange.LastNode());
9319 LIR::AsRange(newBlock).InsertAtBeginning(std::move(nodesToMove));
9322 // Update the IL offsets of the blocks to match the split.
9324 assert(newBlock->bbCodeOffs == BAD_IL_OFFSET);
9325 assert(newBlock->bbCodeOffsEnd == BAD_IL_OFFSET);
9327 // curr->bbCodeOffs remains the same
9328 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
9330 // Search backwards from the end of the current block looking for the IL offset to use
9331 // for the end IL offset for the original block.
9332 IL_OFFSET splitPointILOffset = BAD_IL_OFFSET;
9333 LIR::Range::ReverseIterator riter;
9334 LIR::Range::ReverseIterator riterEnd;
9335 for (riter = currBBRange.rbegin(), riterEnd = currBBRange.rend(); riter != riterEnd; ++riter)
9337 if ((*riter)->gtOper == GT_IL_OFFSET)
9339 GenTreeStmt* stmt = (*riter)->AsStmt();
9340 if (stmt->gtStmtILoffsx != BAD_IL_OFFSET)
9342 splitPointILOffset = jitGetILoffs(stmt->gtStmtILoffsx);
9348 curr->bbCodeOffsEnd = splitPointILOffset;
9350 // Also use this as the beginning offset of the next block. Presumably we could/should
9351 // look to see if the first node is a GT_IL_OFFSET node, and use that instead.
9352 newBlock->bbCodeOffs = splitPointILOffset;
9356 assert(curr->bbTreeList == nullptr); // if no node was given then it better be an empty block
9362 //------------------------------------------------------------------------------
9363 // fgSplitBlockAtBeginning - Split the given block into two blocks.
9364 // Control falls through from original to new block,
9365 // and the new block is returned.
9366 // All code in the original block goes into the new block
9367 //------------------------------------------------------------------------------
9368 BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr)
9370 BasicBlock* newBlock = fgSplitBlockAtEnd(curr);
9372 newBlock->bbTreeList = curr->bbTreeList;
9373 curr->bbTreeList = nullptr;
9375 // The new block now has all the code, and the old block has none. Update the
9376 // IL offsets for the block to reflect this.
9378 newBlock->bbCodeOffs = curr->bbCodeOffs;
9379 newBlock->bbCodeOffsEnd = curr->bbCodeOffsEnd;
9381 curr->bbCodeOffs = BAD_IL_OFFSET;
9382 curr->bbCodeOffsEnd = BAD_IL_OFFSET;
9387 //------------------------------------------------------------------------
9388 // fgSplitEdge: Splits the edge between a block 'curr' and its successor 'succ' by creating a new block
9389 // that replaces 'succ' as a successor of 'curr', and which branches unconditionally
9390 // to (or falls through to) 'succ'. Note that for a BBJ_COND block 'curr',
9391 // 'succ' might be the fall-through path or the branch path from 'curr'.
9394 // curr - A block which branches conditionally to 'succ'
9395 // succ - The target block
9398 // Returns a new block, that is a successor of 'curr' and which branches unconditionally to 'succ'
9401 // 'curr' must have a bbJumpKind of BBJ_COND or BBJ_SWITCH
9404 // The returned block is empty.
9406 BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ)
9408 assert(curr->bbJumpKind == BBJ_COND || curr->bbJumpKind == BBJ_SWITCH);
9409 assert(fgGetPredForBlock(succ, curr) != nullptr);
9411 BasicBlock* newBlock;
9412 if (succ == curr->bbNext)
9414 // The successor is the fall-through path of a BBJ_COND, or
9415 // an immediately following block of a BBJ_SWITCH (which has
9416 // no fall-through path). For this case, simply insert a new
9417 // fall-through block after 'curr'.
9418 newBlock = fgNewBBafter(BBJ_NONE, curr, true /*extendRegion*/);
9422 newBlock = fgNewBBinRegion(BBJ_ALWAYS, curr, curr->isRunRarely());
9423 // The new block always jumps to 'succ'
9424 newBlock->bbJumpDest = succ;
9426 newBlock->bbFlags |= (curr->bbFlags & succ->bbFlags & (BBF_BACKWARD_JUMP));
9428 JITDUMP("Splitting edge from BB%02u to BB%02u; adding BB%02u\n", curr->bbNum, succ->bbNum, newBlock->bbNum);
9430 if (curr->bbJumpKind == BBJ_COND)
9432 fgReplacePred(succ, curr, newBlock);
9433 if (curr->bbJumpDest == succ)
9435 // Now 'curr' jumps to newBlock
9436 curr->bbJumpDest = newBlock;
9437 newBlock->bbFlags |= BBF_JMP_TARGET;
9439 fgAddRefPred(newBlock, curr);
9443 assert(curr->bbJumpKind == BBJ_SWITCH);
9445 // newBlock replaces 'succ' in the switch.
9446 fgReplaceSwitchJumpTarget(curr, newBlock, succ);
9448 // And 'succ' has 'newBlock' as a new predecessor.
9449 fgAddRefPred(succ, newBlock);
9452 // This isn't accurate, but it is complex to compute a reasonable number so just assume that we take the
9453 // branch 50% of the time.
9454 newBlock->inheritWeightPercentage(curr, 50);
9456 // The bbLiveIn and bbLiveOut are both equal to the bbLiveIn of 'succ'
9457 if (fgLocalVarLivenessDone)
9459 VarSetOps::Assign(this, newBlock->bbLiveIn, succ->bbLiveIn);
9460 VarSetOps::Assign(this, newBlock->bbLiveOut, succ->bbLiveIn);
9466 /*****************************************************************************/
9467 /*****************************************************************************/
9469 void Compiler::fgFindOperOrder()
9474 printf("*************** In fgFindOperOrder()\n");
9481 /* Walk the basic blocks and for each statement determine
9482 * the evaluation order, cost, FP levels, etc... */
9484 for (block = fgFirstBB; block; block = block->bbNext)
9487 for (stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
9489 /* Recursively process the statement */
9492 gtSetStmtInfo(stmt);
9497 //------------------------------------------------------------------------
9498 // fgSimpleLowering: do full walk of all IR, lowering selected operations
9499 // and computing lvaOutgoingArgumentAreaSize.
9502 // Lowers GT_ARR_LENGTH, GT_ARR_BOUNDS_CHECK, and GT_SIMD_CHK.
9504 // For target ABIs with fixed out args area, computes upper bound on
9505 // the size of this area from the calls in the IR.
9507 // Outgoing arg area size is computed here because we want to run it
9508 // after optimization (in case calls are removed) and need to look at
9509 // all possible calls in the method.
9511 void Compiler::fgSimpleLowering()
9513 #if FEATURE_FIXED_OUT_ARGS
9514 unsigned outgoingArgSpaceSize = 0;
9515 #endif // FEATURE_FIXED_OUT_ARGS
9517 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
9519 // Walk the statement trees in this basic block.
9520 compCurBB = block; // Used in fgRngChkTarget.
9522 #ifdef LEGACY_BACKEND
9523 for (GenTreeStmt* stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNextStmt)
9525 for (GenTree* tree = stmt->gtStmtList; tree; tree = tree->gtNext)
9529 LIR::Range& range = LIR::AsRange(block);
9530 for (GenTree* tree : range)
9535 switch (tree->OperGet())
9539 GenTreeArrLen* arrLen = tree->AsArrLen();
9540 GenTree* arr = arrLen->gtArrLen.ArrRef();
9544 /* Create the expression "*(array_addr + ArrLenOffs)" */
9546 noway_assert(arr->gtNext == tree);
9548 noway_assert(arrLen->ArrLenOffset() == offsetof(CORINFO_Array, length) ||
9549 arrLen->ArrLenOffset() == offsetof(CORINFO_String, stringLen));
9551 if ((arr->gtOper == GT_CNS_INT) && (arr->gtIntCon.gtIconVal == 0))
9553 // If the array is NULL, then we should get a NULL reference
9554 // exception when computing its length. We need to maintain
9555 // an invariant where there is no sum of two constants node, so
9556 // let's simply return an indirection of NULL.
9562 con = gtNewIconNode(arrLen->ArrLenOffset(), TYP_I_IMPL);
9563 con->gtRsvdRegs = RBM_NONE;
9565 add = gtNewOperNode(GT_ADD, TYP_REF, arr, con);
9566 add->gtRsvdRegs = arr->gtRsvdRegs;
9568 #ifdef LEGACY_BACKEND
9569 con->gtCopyFPlvl(arr);
9571 add->gtCopyFPlvl(arr);
9572 add->CopyCosts(arr);
9583 range.InsertAfter(arr, con, add);
9587 // Change to a GT_IND.
9588 tree->ChangeOperUnchecked(GT_IND);
9590 tree->gtOp.gtOp1 = add;
9594 case GT_ARR_BOUNDS_CHECK:
9597 #endif // FEATURE_SIMD
9598 #ifdef FEATURE_HW_INTRINSICS
9599 case GT_HW_INTRINSIC_CHK:
9600 #endif // FEATURE_HW_INTRINSICS
9602 // Add in a call to an error routine.
9603 fgSetRngChkTarget(tree, false);
9607 #if FEATURE_FIXED_OUT_ARGS
9610 GenTreeCall* call = tree->AsCall();
9611 // Fast tail calls use the caller-supplied scratch
9612 // space so have no impact on this method's outgoing arg size.
9613 if (!call->IsFastTailCall())
9615 // Update outgoing arg size to handle this call
9616 const unsigned thisCallOutAreaSize = call->fgArgInfo->GetOutArgSize();
9617 assert(thisCallOutAreaSize >= MIN_ARG_AREA_FOR_CALL);
9619 if (thisCallOutAreaSize > outgoingArgSpaceSize)
9621 outgoingArgSpaceSize = thisCallOutAreaSize;
9622 JITDUMP("Bumping outgoingArgSpaceSize to %u for call [%06d]\n", outgoingArgSpaceSize,
9627 JITDUMP("outgoingArgSpaceSize %u sufficient for call [%06d], which needs %u\n",
9628 outgoingArgSpaceSize, dspTreeID(tree), thisCallOutAreaSize);
9633 JITDUMP("outgoingArgSpaceSize not impacted by fast tail call [%06d]\n", dspTreeID(tree));
9637 #endif // FEATURE_FIXED_OUT_ARGS
9641 // No other operators need processing.
9649 #if FEATURE_FIXED_OUT_ARGS
9650 // Finish computing the outgoing args area size
9652 // Need to make sure the MIN_ARG_AREA_FOR_CALL space is added to the frame if:
9653 // 1. there are calls to THROW_HEPLPER methods.
9654 // 2. we are generating profiling Enter/Leave/TailCall hooks. This will ensure
9655 // that even methods without any calls will have outgoing arg area space allocated.
9657 // An example for these two cases is Windows Amd64, where the ABI requires to have 4 slots for
9658 // the outgoing arg space if the method makes any calls.
9659 if (outgoingArgSpaceSize < MIN_ARG_AREA_FOR_CALL)
9661 if (compUsesThrowHelper || compIsProfilerHookNeeded())
9663 outgoingArgSpaceSize = MIN_ARG_AREA_FOR_CALL;
9664 JITDUMP("Bumping outgoingArgSpaceSize to %u for throw helper or profile hook", outgoingArgSpaceSize);
9668 // If a function has localloc, we will need to move the outgoing arg space when the
9669 // localloc happens. When we do this, we need to maintain stack alignment. To avoid
9670 // leaving alignment-related holes when doing this move, make sure the outgoing
9671 // argument space size is a multiple of the stack alignment by aligning up to the next
9672 // stack alignment boundary.
9673 if (compLocallocUsed)
9675 outgoingArgSpaceSize = (unsigned)roundUp(outgoingArgSpaceSize, STACK_ALIGN);
9676 JITDUMP("Bumping outgoingArgSpaceSize to %u for localloc", outgoingArgSpaceSize);
9679 // Publish the final value and mark it as read only so any update
9680 // attempt later will cause an assert.
9681 lvaOutgoingArgSpaceSize = outgoingArgSpaceSize;
9682 lvaOutgoingArgSpaceSize.MarkAsReadOnly();
9684 #endif // FEATURE_FIXED_OUT_ARGS
9687 if (verbose && fgRngChkThrowAdded)
9689 printf("\nAfter fgSimpleLowering() added some RngChk throw blocks");
9690 fgDispBasicBlocks();
9697 /*****************************************************************************
9700 void Compiler::fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTree* clonedTree)
9702 assert(clonedTree->gtOper != GT_STMT);
9704 if (lvaLocalVarRefCounted)
9706 compCurBB = addedToBlock;
9707 IncLclVarRefCountsVisitor::WalkTree(this, clonedTree);
9711 /*****************************************************************************
9714 void Compiler::fgUpdateRefCntForExtract(GenTree* wholeTree, GenTree* keptTree)
9716 if (lvaLocalVarRefCounted)
9718 /* Update the refCnts of removed lcl vars - The problem is that
9719 * we have to consider back the side effects trees so we first
9720 * increment all refCnts for side effects then decrement everything
9725 IncLclVarRefCountsVisitor::WalkTree(this, keptTree);
9728 DecLclVarRefCountsVisitor::WalkTree(this, wholeTree);
9732 VARSET_VALRET_TP Compiler::fgGetVarBits(GenTree* tree)
9734 VARSET_TP varBits(VarSetOps::MakeEmpty(this));
9736 assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_REG_VAR);
9738 unsigned int lclNum = tree->gtLclVarCommon.gtLclNum;
9739 LclVarDsc* varDsc = lvaTable + lclNum;
9740 if (varDsc->lvTracked)
9742 VarSetOps::AddElemD(this, varBits, varDsc->lvVarIndex);
9744 // We have to check type of root tree, not Local Var descriptor because
9745 // for legacy backend we promote TYP_STRUCT to TYP_INT if it is an unused or
9746 // independently promoted non-argument struct local.
9747 // For more details see Compiler::raAssignVars() method.
9748 else if (tree->gtType == TYP_STRUCT && varDsc->lvPromoted)
9750 #ifndef LEGACY_BACKEND
9751 assert(varDsc->lvType == TYP_STRUCT);
9753 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
9755 noway_assert(lvaTable[i].lvIsStructField);
9756 if (lvaTable[i].lvTracked)
9758 unsigned varIndex = lvaTable[i].lvVarIndex;
9759 noway_assert(varIndex < lvaTrackedCount);
9760 VarSetOps::AddElemD(this, varBits, varIndex);
9767 /*****************************************************************************
9769 * Find and remove any basic blocks that are useless (e.g. they have not been
9770 * imported because they are not reachable, or they have been optimized away).
9773 void Compiler::fgRemoveEmptyBlocks()
9778 /* If we remove any blocks, we'll have to do additional work */
9780 unsigned removedBlks = 0;
9782 for (cur = fgFirstBB; cur != nullptr; cur = nxt)
9784 /* Get hold of the next block (in case we delete 'cur') */
9788 /* Should this block be removed? */
9790 if (!(cur->bbFlags & BBF_IMPORTED))
9792 noway_assert(cur->isEmpty());
9794 if (ehCanDeleteEmptyBlock(cur))
9796 /* Mark the block as removed */
9798 cur->bbFlags |= BBF_REMOVED;
9800 /* Remember that we've removed a block from the list */
9807 printf("BB%02u was not imported, marked as removed (%d)\n", cur->bbNum, removedBlks);
9811 /* Drop the block from the list */
9817 // We were prevented from deleting this block by EH normalization. Mark the block as imported.
9818 cur->bbFlags |= BBF_IMPORTED;
9823 /* If no blocks were removed, we're done */
9825 if (removedBlks == 0)
9830 /* Update all references in the exception handler table.
9831 * Mark the new blocks as non-removable.
9833 * We may have made the entire try block unreachable.
9834 * Check for this case and remove the entry from the EH table.
9839 INDEBUG(unsigned delCnt = 0;)
9841 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
9844 /* If the beginning of the try block was not imported, we
9845 * need to remove the entry from the EH table. */
9847 if (HBtab->ebdTryBeg->bbFlags & BBF_REMOVED)
9849 noway_assert(!(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED));
9853 printf("Beginning of try block (BB%02u) not imported "
9854 "- remove index #%u from the EH table\n",
9855 HBtab->ebdTryBeg->bbNum, XTnum + delCnt);
9860 fgRemoveEHTableEntry(XTnum);
9862 if (XTnum < compHndBBtabCount)
9864 // There are more entries left to process, so do more. Note that
9865 // HBtab now points to the next entry, that we copied down to the
9866 // current slot. XTnum also stays the same.
9870 break; // no more entries (we deleted the last one), so exit the loop
9873 /* At this point we know we have a valid try block */
9876 assert(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED);
9877 assert(HBtab->ebdTryBeg->bbFlags & BBF_DONT_REMOVE);
9879 assert(HBtab->ebdHndBeg->bbFlags & BBF_IMPORTED);
9880 assert(HBtab->ebdHndBeg->bbFlags & BBF_DONT_REMOVE);
9882 if (HBtab->HasFilter())
9884 assert(HBtab->ebdFilter->bbFlags & BBF_IMPORTED);
9885 assert(HBtab->ebdFilter->bbFlags & BBF_DONT_REMOVE);
9889 fgSkipRmvdBlocks(HBtab);
9890 } /* end of the for loop over XTnum */
9892 // Renumber the basic blocks
9893 JITDUMP("\nRenumbering the basic blocks for fgRemoveEmptyBlocks\n");
9897 fgVerifyHandlerTab();
9901 /*****************************************************************************
9903 * Remove a useless statement from a basic block.
9904 * The default is to decrement ref counts of included vars
9908 void Compiler::fgRemoveStmt(BasicBlock* block,
9910 // whether to decrement ref counts for tracked vars in statement
9911 bool updateRefCount)
9914 assert(fgOrder == FGOrderTree);
9916 GenTreeStmt* tree = block->firstStmt();
9917 GenTreeStmt* stmt = node->AsStmt();
9921 stmt->gtStmtExpr->gtOper != GT_NOP) // Don't print if it is a GT_NOP. Too much noise from the inliner.
9923 printf("\nRemoving statement ");
9925 printf(" in BB%02u as useless:\n", block->bbNum);
9930 if (opts.compDbgCode && stmt->gtPrev != stmt && stmt->gtStmtILoffsx != BAD_IL_OFFSET)
9932 /* TODO: For debuggable code, should we remove significant
9933 statement boundaries. Or should we leave a GT_NO_OP in its place? */
9936 /* Is it the first statement in the list? */
9938 GenTreeStmt* firstStmt = block->firstStmt();
9939 if (firstStmt == stmt)
9941 if (firstStmt->gtNext == nullptr)
9943 assert(firstStmt == block->lastStmt());
9945 /* this is the only statement - basic block becomes empty */
9946 block->bbTreeList = nullptr;
9950 block->bbTreeList = tree->gtNext;
9951 block->bbTreeList->gtPrev = tree->gtPrev;
9956 /* Is it the last statement in the list? */
9958 if (stmt == block->lastStmt())
9960 stmt->gtPrev->gtNext = nullptr;
9961 block->bbTreeList->gtPrev = stmt->gtPrev;
9965 tree = stmt->gtPrevStmt;
9968 tree->gtNext = stmt->gtNext;
9969 stmt->gtNext->gtPrev = tree;
9972 fgStmtRemoved = true;
9974 noway_assert(!optValnumCSE_phase);
9978 if (fgStmtListThreaded)
9980 DecLclVarRefCountsVisitor::WalkTree(this, stmt->gtStmtExpr);
9987 if (block->bbTreeList == nullptr)
9989 printf("\nBB%02u becomes empty", block->bbNum);
9996 /******************************************************************************/
9997 // Returns true if the operator is involved in control-flow
9998 // TODO-Cleanup: Move this into genTreeKinds in genTree.h
10000 inline bool OperIsControlFlow(genTreeOps oper)
10015 #if !FEATURE_EH_FUNCLETS
10017 #endif // !FEATURE_EH_FUNCLETS
10025 /******************************************************************************
10026 * Tries to throw away a stmt. The statement can be anywhere in block->bbTreeList.
10027 * Returns true if it did remove the statement.
10030 bool Compiler::fgCheckRemoveStmt(BasicBlock* block, GenTree* node)
10032 if (opts.compDbgCode)
10037 GenTreeStmt* stmt = node->AsStmt();
10039 GenTree* tree = stmt->gtStmtExpr;
10040 genTreeOps oper = tree->OperGet();
10042 if (OperIsControlFlow(oper) || GenTree::OperIsHWIntrinsic(oper) || oper == GT_NO_OP)
10047 // TODO: Use a recursive version of gtNodeHasSideEffects()
10048 if (tree->gtFlags & GTF_SIDE_EFFECT)
10053 fgRemoveStmt(block, stmt);
10057 /****************************************************************************************************
10061 bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext)
10063 if ((block == nullptr) || (bNext == nullptr))
10068 noway_assert(block->bbNext == bNext);
10070 if (block->bbJumpKind != BBJ_NONE)
10075 // If the next block has multiple incoming edges, we can still compact if the first block is empty.
10076 // However, not if it is the beginning of a handler.
10077 if (bNext->countOfInEdges() != 1 &&
10078 (!block->isEmpty() || (block->bbFlags & BBF_FUNCLET_BEG) || (block->bbCatchTyp != BBCT_NONE)))
10083 if (bNext->bbFlags & BBF_DONT_REMOVE)
10088 // Don't compact the first block if it was specially created as a scratch block.
10089 if (fgBBisScratch(block))
10094 #if defined(_TARGET_ARM_)
10095 // We can't compact a finally target block, as we need to generate special code for such blocks during code
10097 if ((bNext->bbFlags & BBF_FINALLY_TARGET) != 0)
10101 // We don't want to compact blocks that are in different Hot/Cold regions
10103 if (fgInDifferentRegions(block, bNext))
10108 // We cannot compact two blocks in different EH regions.
10110 if (fgCanRelocateEHRegions)
10112 if (!BasicBlock::sameEHRegion(block, bNext))
10117 // if there is a switch predecessor don't bother because we'd have to update the uniquesuccs as well
10118 // (if they are valid)
10119 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
10121 if (pred->flBlock->bbJumpKind == BBJ_SWITCH)
10130 /*****************************************************************************************************
10132 * Function called to compact two given blocks in the flowgraph
10133 * Assumes that all necessary checks have been performed,
10134 * i.e. fgCanCompactBlocks returns true.
10136 * Uses for this function - whenever we change links, insert blocks,...
10137 * It will keep the flowgraph data in synch - bbNum, bbRefs, bbPreds
10140 void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext)
10142 noway_assert(block != nullptr);
10143 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
10144 noway_assert(block->bbJumpKind == BBJ_NONE);
10146 noway_assert(bNext == block->bbNext);
10147 noway_assert(bNext != nullptr);
10148 noway_assert((bNext->bbFlags & BBF_REMOVED) == 0);
10149 noway_assert(bNext->countOfInEdges() == 1 || block->isEmpty());
10150 noway_assert(bNext->bbPreds);
10152 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10153 noway_assert((bNext->bbFlags & BBF_FINALLY_TARGET) == 0);
10154 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10156 // Make sure the second block is not the start of a TRY block or an exception handler
10158 noway_assert(bNext->bbCatchTyp == BBCT_NONE);
10159 noway_assert((bNext->bbFlags & BBF_TRY_BEG) == 0);
10160 noway_assert((bNext->bbFlags & BBF_DONT_REMOVE) == 0);
10162 /* both or none must have an exception handler */
10163 noway_assert(block->hasTryIndex() == bNext->hasTryIndex());
10168 printf("\nCompacting blocks BB%02u and BB%02u:\n", block->bbNum, bNext->bbNum);
10172 if (bNext->countOfInEdges() > 1)
10174 JITDUMP("Second block has multiple incoming edges\n");
10176 assert(block->isEmpty());
10177 block->bbFlags |= BBF_JMP_TARGET;
10178 for (flowList* pred = bNext->bbPreds; pred; pred = pred->flNext)
10180 fgReplaceJumpTarget(pred->flBlock, block, bNext);
10182 if (pred->flBlock != block)
10184 fgAddRefPred(block, pred->flBlock);
10187 bNext->bbPreds = nullptr;
10191 noway_assert(bNext->bbPreds->flNext == nullptr);
10192 noway_assert(bNext->bbPreds->flBlock == block);
10195 /* Start compacting - move all the statements in the second block to the first block */
10197 // First move any phi definitions of the second block after the phi defs of the first.
10198 // TODO-CQ: This may be the wrong thing to do. If we're compacting blocks, it's because a
10199 // control-flow choice was constant-folded away. So probably phi's need to go away,
10200 // as well, in favor of one of the incoming branches. Or at least be modified.
10202 assert(block->IsLIR() == bNext->IsLIR());
10203 if (block->IsLIR())
10205 LIR::Range& blockRange = LIR::AsRange(block);
10206 LIR::Range& nextRange = LIR::AsRange(bNext);
10208 // Does the next block have any phis?
10209 GenTree* nextFirstNonPhi = nullptr;
10210 LIR::ReadOnlyRange nextPhis = nextRange.PhiNodes();
10211 if (!nextPhis.IsEmpty())
10213 GenTree* blockLastPhi = blockRange.LastPhiNode();
10214 nextFirstNonPhi = nextPhis.LastNode()->gtNext;
10216 LIR::Range phisToMove = nextRange.Remove(std::move(nextPhis));
10217 blockRange.InsertAfter(blockLastPhi, std::move(phisToMove));
10221 nextFirstNonPhi = nextRange.FirstNode();
10224 // Does the block have any other code?
10225 if (nextFirstNonPhi != nullptr)
10227 LIR::Range nextNodes = nextRange.Remove(nextFirstNonPhi, nextRange.LastNode());
10228 blockRange.InsertAtEnd(std::move(nextNodes));
10233 GenTree* blkNonPhi1 = block->FirstNonPhiDef();
10234 GenTree* bNextNonPhi1 = bNext->FirstNonPhiDef();
10235 GenTree* blkFirst = block->firstStmt();
10236 GenTree* bNextFirst = bNext->firstStmt();
10238 // Does the second have any phis?
10239 if (bNextFirst != nullptr && bNextFirst != bNextNonPhi1)
10241 GenTree* bNextLast = bNextFirst->gtPrev;
10242 assert(bNextLast->gtNext == nullptr);
10244 // Does "blk" have phis?
10245 if (blkNonPhi1 != blkFirst)
10248 // Insert after the last phi of "block."
10249 // First, bNextPhis after last phi of block.
10250 GenTree* blkLastPhi;
10251 if (blkNonPhi1 != nullptr)
10253 blkLastPhi = blkNonPhi1->gtPrev;
10257 blkLastPhi = blkFirst->gtPrev;
10260 blkLastPhi->gtNext = bNextFirst;
10261 bNextFirst->gtPrev = blkLastPhi;
10263 // Now, rest of "block" after last phi of "bNext".
10264 GenTree* bNextLastPhi = nullptr;
10265 if (bNextNonPhi1 != nullptr)
10267 bNextLastPhi = bNextNonPhi1->gtPrev;
10271 bNextLastPhi = bNextFirst->gtPrev;
10274 bNextLastPhi->gtNext = blkNonPhi1;
10275 if (blkNonPhi1 != nullptr)
10277 blkNonPhi1->gtPrev = bNextLastPhi;
10281 // block has no non phis, so make the last statement be the last added phi.
10282 blkFirst->gtPrev = bNextLastPhi;
10285 // Now update the bbTreeList of "bNext".
10286 bNext->bbTreeList = bNextNonPhi1;
10287 if (bNextNonPhi1 != nullptr)
10289 bNextNonPhi1->gtPrev = bNextLast;
10294 if (blkFirst != nullptr) // If "block" has no statements, fusion will work fine...
10296 // First, bNextPhis at start of block.
10297 GenTree* blkLast = blkFirst->gtPrev;
10298 block->bbTreeList = bNextFirst;
10299 // Now, rest of "block" (if it exists) after last phi of "bNext".
10300 GenTree* bNextLastPhi = nullptr;
10301 if (bNextNonPhi1 != nullptr)
10303 // There is a first non phi, so the last phi is before it.
10304 bNextLastPhi = bNextNonPhi1->gtPrev;
10308 // All the statements are phi defns, so the last one is the prev of the first.
10309 bNextLastPhi = bNextFirst->gtPrev;
10311 bNextFirst->gtPrev = blkLast;
10312 bNextLastPhi->gtNext = blkFirst;
10313 blkFirst->gtPrev = bNextLastPhi;
10314 // Now update the bbTreeList of "bNext"
10315 bNext->bbTreeList = bNextNonPhi1;
10316 if (bNextNonPhi1 != nullptr)
10318 bNextNonPhi1->gtPrev = bNextLast;
10324 // Now proceed with the updated bbTreeLists.
10325 GenTree* stmtList1 = block->firstStmt();
10326 GenTree* stmtList2 = bNext->firstStmt();
10328 /* the block may have an empty list */
10332 GenTree* stmtLast1 = block->lastStmt();
10334 /* The second block may be a GOTO statement or something with an empty bbTreeList */
10337 GenTree* stmtLast2 = bNext->lastStmt();
10339 /* append list2 to list 1 */
10341 stmtLast1->gtNext = stmtList2;
10342 stmtList2->gtPrev = stmtLast1;
10343 stmtList1->gtPrev = stmtLast2;
10348 /* block was formerly empty and now has bNext's statements */
10349 block->bbTreeList = stmtList2;
10353 // Note we could update the local variable weights here by
10354 // calling lvaMarkLocalVars, with the block and weight adjustment.
10356 // If either block or bNext has a profile weight
10357 // or if both block and bNext have non-zero weights
10358 // then we select the highest weight block.
10360 if (block->hasProfileWeight() || bNext->hasProfileWeight() || (block->bbWeight && bNext->bbWeight))
10362 // We are keeping block so update its fields
10363 // when bNext has a greater weight
10365 if (block->bbWeight < bNext->bbWeight)
10367 block->bbWeight = bNext->bbWeight;
10369 block->bbFlags |= (bNext->bbFlags & BBF_PROF_WEIGHT); // Set the profile weight flag (if necessary)
10370 if (block->bbWeight != 0)
10372 block->bbFlags &= ~BBF_RUN_RARELY; // Clear any RarelyRun flag
10376 // otherwise if either block has a zero weight we select the zero weight
10379 noway_assert((block->bbWeight == BB_ZERO_WEIGHT) || (bNext->bbWeight == BB_ZERO_WEIGHT));
10380 block->bbWeight = BB_ZERO_WEIGHT;
10381 block->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
10384 /* set the right links */
10386 block->bbJumpKind = bNext->bbJumpKind;
10387 VarSetOps::AssignAllowUninitRhs(this, block->bbLiveOut, bNext->bbLiveOut);
10389 // Update the beginning and ending IL offsets (bbCodeOffs and bbCodeOffsEnd).
10390 // Set the beginning IL offset to the minimum, and the ending offset to the maximum, of the respective blocks.
10391 // If one block has an unknown offset, we take the other block.
10392 // We are merging into 'block', so if its values are correct, just leave them alone.
10393 // TODO: we should probably base this on the statements within.
10395 if (block->bbCodeOffs == BAD_IL_OFFSET)
10397 block->bbCodeOffs = bNext->bbCodeOffs; // If they are both BAD_IL_OFFSET, this doesn't change anything.
10399 else if (bNext->bbCodeOffs != BAD_IL_OFFSET)
10401 // The are both valid offsets; compare them.
10402 if (block->bbCodeOffs > bNext->bbCodeOffs)
10404 block->bbCodeOffs = bNext->bbCodeOffs;
10408 if (block->bbCodeOffsEnd == BAD_IL_OFFSET)
10410 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd; // If they are both BAD_IL_OFFSET, this doesn't change anything.
10412 else if (bNext->bbCodeOffsEnd != BAD_IL_OFFSET)
10414 // The are both valid offsets; compare them.
10415 if (block->bbCodeOffsEnd < bNext->bbCodeOffsEnd)
10417 block->bbCodeOffsEnd = bNext->bbCodeOffsEnd;
10421 if (((block->bbFlags & BBF_INTERNAL) != 0) && ((bNext->bbFlags & BBF_INTERNAL) == 0))
10423 // If 'block' is an internal block and 'bNext' isn't, then adjust the flags set on 'block'.
10424 block->bbFlags &= ~BBF_INTERNAL; // Clear the BBF_INTERNAL flag
10425 block->bbFlags |= BBF_IMPORTED; // Set the BBF_IMPORTED flag
10428 /* Update the flags for block with those found in bNext */
10430 block->bbFlags |= (bNext->bbFlags & BBF_COMPACT_UPD);
10432 /* mark bNext as removed */
10434 bNext->bbFlags |= BBF_REMOVED;
10436 /* Unlink bNext and update all the marker pointers if necessary */
10438 fgUnlinkRange(block->bbNext, bNext);
10440 // If bNext was the last block of a try or handler, update the EH table.
10442 ehUpdateForDeletedBlock(bNext);
10444 /* If we're collapsing a block created after the dominators are
10445 computed, rename the block and reuse dominator information from
10447 if (fgDomsComputed && block->bbNum > fgDomBBcount)
10449 BlockSetOps::Assign(this, block->bbReach, bNext->bbReach);
10450 BlockSetOps::ClearD(this, bNext->bbReach);
10452 block->bbIDom = bNext->bbIDom;
10453 bNext->bbIDom = nullptr;
10455 // In this case, there's no need to update the preorder and postorder numbering
10456 // since we're changing the bbNum, this makes the basic block all set.
10457 block->bbNum = bNext->bbNum;
10460 /* Set the jump targets */
10462 switch (bNext->bbJumpKind)
10464 case BBJ_CALLFINALLY:
10465 // Propagate RETLESS property
10466 block->bbFlags |= (bNext->bbFlags & BBF_RETLESS_CALL);
10472 case BBJ_EHCATCHRET:
10473 block->bbJumpDest = bNext->bbJumpDest;
10475 /* Update the predecessor list for 'bNext->bbJumpDest' */
10476 fgReplacePred(bNext->bbJumpDest, bNext, block);
10478 /* Update the predecessor list for 'bNext->bbNext' if it is different than 'bNext->bbJumpDest' */
10479 if (bNext->bbJumpKind == BBJ_COND && bNext->bbJumpDest != bNext->bbNext)
10481 fgReplacePred(bNext->bbNext, bNext, block);
10486 /* Update the predecessor list for 'bNext->bbNext' */
10487 fgReplacePred(bNext->bbNext, bNext, block);
10490 case BBJ_EHFILTERRET:
10491 fgReplacePred(bNext->bbJumpDest, bNext, block);
10494 case BBJ_EHFINALLYRET:
10496 unsigned hndIndex = block->getHndIndex();
10497 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
10499 if (ehDsc->HasFinallyHandler()) // No need to do this for fault handlers
10501 BasicBlock* begBlk;
10502 BasicBlock* endBlk;
10503 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
10505 BasicBlock* finBeg = ehDsc->ebdHndBeg;
10507 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
10509 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
10514 noway_assert(bcall->isBBCallAlwaysPair());
10515 fgReplacePred(bcall->bbNext, bNext, block);
10523 /* no jumps or fall through blocks to set here */
10527 block->bbJumpSwt = bNext->bbJumpSwt;
10528 // We are moving the switch jump from bNext to block. Examine the jump targets
10529 // of the BBJ_SWITCH at bNext and replace the predecessor to 'bNext' with ones to 'block'
10530 fgChangeSwitchBlock(bNext, block);
10534 noway_assert(!"Unexpected bbJumpKind");
10538 fgUpdateLoopsAfterCompacting(block, bNext);
10543 printf("\nAfter compacting:\n");
10544 fgDispBasicBlocks(false);
10549 if (JitConfig.JitSlowDebugChecksEnabled() != 0)
10551 // Make sure that the predecessor lists are accurate
10552 fgDebugCheckBBlist();
10557 void Compiler::fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext)
10559 /* Check if the removed block is not part the loop table */
10560 noway_assert(bNext);
10562 for (unsigned loopNum = 0; loopNum < optLoopCount; loopNum++)
10564 /* Some loops may have been already removed by
10565 * loop unrolling or conditional folding */
10567 if (optLoopTable[loopNum].lpFlags & LPFLG_REMOVED)
10572 /* Check the loop head (i.e. the block preceding the loop) */
10574 if (optLoopTable[loopNum].lpHead == bNext)
10576 optLoopTable[loopNum].lpHead = block;
10579 /* Check the loop bottom */
10581 if (optLoopTable[loopNum].lpBottom == bNext)
10583 optLoopTable[loopNum].lpBottom = block;
10586 /* Check the loop exit */
10588 if (optLoopTable[loopNum].lpExit == bNext)
10590 noway_assert(optLoopTable[loopNum].lpExitCnt == 1);
10591 optLoopTable[loopNum].lpExit = block;
10594 /* Check the loop entry */
10596 if (optLoopTable[loopNum].lpEntry == bNext)
10598 optLoopTable[loopNum].lpEntry = block;
10603 /*****************************************************************************************************
10605 * Function called to remove a block when it is unreachable.
10607 * This function cannot remove the first block.
10610 void Compiler::fgUnreachableBlock(BasicBlock* block)
10612 // genReturnBB should never be removed, as we might have special hookups there.
10613 // Therefore, we should never come here to remove the statements in the genReturnBB block.
10614 // For example, <BUGNUM> in VSW 364383, </BUGNUM>
10615 // the profiler hookup needs to have the "void GT_RETURN" statement
10616 // to properly set the info.compProfilerCallback flag.
10617 noway_assert(block != genReturnBB);
10619 if (block->bbFlags & BBF_REMOVED)
10624 /* Removing an unreachable block */
10629 printf("\nRemoving unreachable BB%02u\n", block->bbNum);
10633 noway_assert(block->bbPrev != nullptr); // Can use this function to remove the first block
10635 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10636 assert(!block->bbPrev->isBBCallAlwaysPair()); // can't remove the BBJ_ALWAYS of a BBJ_CALLFINALLY / BBJ_ALWAYS pair
10637 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10639 /* First walk the statement trees in this basic block and delete each stmt */
10641 /* Make the block publicly available */
10644 if (block->IsLIR())
10646 LIR::Range& blockRange = LIR::AsRange(block);
10647 if (!blockRange.IsEmpty())
10649 blockRange.Delete(this, block, blockRange.FirstNode(), blockRange.LastNode());
10654 // TODO-Cleanup: I'm not sure why this happens -- if the block is unreachable, why does it have phis?
10655 // Anyway, remove any phis.
10657 GenTree* firstNonPhi = block->FirstNonPhiDef();
10658 if (block->bbTreeList != firstNonPhi)
10660 if (firstNonPhi != nullptr)
10662 firstNonPhi->gtPrev = block->lastStmt();
10664 block->bbTreeList = firstNonPhi;
10667 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
10669 fgRemoveStmt(block, stmt);
10671 noway_assert(block->bbTreeList == nullptr);
10674 /* Next update the loop table and bbWeights */
10675 optUpdateLoopsBeforeRemoveBlock(block);
10677 /* Mark the block as removed */
10678 block->bbFlags |= BBF_REMOVED;
10680 /* update bbRefs and bbPreds for the blocks reached by this block */
10681 fgRemoveBlockAsPred(block);
10684 /*****************************************************************************************************
10686 * Function called to remove or morph a jump when we jump to the same
10687 * block when both the condition is true or false.
10689 void Compiler::fgRemoveConditionalJump(BasicBlock* block)
10691 noway_assert(block->bbJumpKind == BBJ_COND && block->bbJumpDest == block->bbNext);
10692 assert(compRationalIRForm == block->IsLIR());
10694 flowList* flow = fgGetPredForBlock(block->bbNext, block);
10695 noway_assert(flow->flDupCount == 2);
10697 // Change the BBJ_COND to BBJ_NONE, and adjust the refCount and dupCount.
10698 block->bbJumpKind = BBJ_NONE;
10699 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
10700 --block->bbNext->bbRefs;
10701 --flow->flDupCount;
10704 block->bbJumpDest = nullptr;
10707 printf("Block BB%02u becoming a BBJ_NONE to BB%02u (jump target is the same whether the condition is true or "
10709 block->bbNum, block->bbNext->bbNum);
10713 /* Remove the block jump condition */
10715 if (block->IsLIR())
10717 LIR::Range& blockRange = LIR::AsRange(block);
10719 GenTree* test = blockRange.LastNode();
10720 assert(test->OperIsConditionalJump());
10723 unsigned sideEffects;
10724 LIR::ReadOnlyRange testRange = blockRange.GetTreeRange(test, &isClosed, &sideEffects);
10726 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
10727 // diffs compared to the existing backend.
10728 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
10730 // If the jump and its operands form a contiguous, side-effect-free range,
10732 blockRange.Delete(this, block, std::move(testRange));
10736 // Otherwise, just remove the jump node itself.
10737 blockRange.Remove(test, true);
10742 GenTreeStmt* test = block->lastStmt();
10743 GenTree* tree = test->gtStmtExpr;
10745 noway_assert(tree->gtOper == GT_JTRUE);
10747 GenTree* sideEffList = nullptr;
10749 if (tree->gtFlags & GTF_SIDE_EFFECT)
10751 gtExtractSideEffList(tree, &sideEffList);
10755 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
10759 printf("Extracted side effects list from condition...\n");
10760 gtDispTree(sideEffList);
10767 // Delete the cond test or replace it with the side effect tree
10768 if (sideEffList == nullptr)
10770 fgRemoveStmt(block, test);
10774 test->gtStmtExpr = sideEffList;
10776 fgMorphBlockStmt(block, test DEBUGARG("fgRemoveConditionalJump"));
10781 /*****************************************************************************************************
10783 * Function to return the last basic block in the main part of the function. With funclets, it is
10784 * the block immediately before the first funclet.
10785 * An inclusive end of the main method.
10788 BasicBlock* Compiler::fgLastBBInMainFunction()
10790 #if FEATURE_EH_FUNCLETS
10792 if (fgFirstFuncletBB != nullptr)
10794 return fgFirstFuncletBB->bbPrev;
10797 #endif // FEATURE_EH_FUNCLETS
10799 assert(fgLastBB->bbNext == nullptr);
10804 /*****************************************************************************************************
10806 * Function to return the first basic block after the main part of the function. With funclets, it is
10807 * the block of the first funclet. Otherwise it is NULL if there are no funclets (fgLastBB->bbNext).
10808 * This is equivalent to fgLastBBInMainFunction()->bbNext
10809 * An exclusive end of the main method.
10812 BasicBlock* Compiler::fgEndBBAfterMainFunction()
10814 #if FEATURE_EH_FUNCLETS
10816 if (fgFirstFuncletBB != nullptr)
10818 return fgFirstFuncletBB;
10821 #endif // FEATURE_EH_FUNCLETS
10823 assert(fgLastBB->bbNext == nullptr);
10828 // Removes the block from the bbPrev/bbNext chain
10829 // Updates fgFirstBB and fgLastBB if necessary
10830 // Does not update fgFirstFuncletBB or fgFirstColdBlock (fgUnlinkRange does)
10832 void Compiler::fgUnlinkBlock(BasicBlock* block)
10836 block->bbPrev->bbNext = block->bbNext;
10839 block->bbNext->bbPrev = block->bbPrev;
10843 fgLastBB = block->bbPrev;
10848 assert(block == fgFirstBB);
10849 assert(block != fgLastBB);
10850 assert((fgFirstBBScratch == nullptr) || (fgFirstBBScratch == fgFirstBB));
10852 fgFirstBB = block->bbNext;
10853 fgFirstBB->bbPrev = nullptr;
10855 if (fgFirstBBScratch != nullptr)
10858 // We had created an initial scratch BB, but now we're deleting it.
10861 printf("Unlinking scratch BB%02u\n", block->bbNum);
10864 fgFirstBBScratch = nullptr;
10869 /*****************************************************************************************************
10871 * Function called to unlink basic block range [bBeg .. bEnd] from the basic block list.
10873 * 'bBeg' can't be the first block.
10876 void Compiler::fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd)
10878 assert(bBeg != nullptr);
10879 assert(bEnd != nullptr);
10881 BasicBlock* bPrev = bBeg->bbPrev;
10882 assert(bPrev != nullptr); // Can't unlink a range starting with the first block
10884 bPrev->setNext(bEnd->bbNext);
10886 /* If we removed the last block in the method then update fgLastBB */
10887 if (fgLastBB == bEnd)
10890 noway_assert(fgLastBB->bbNext == nullptr);
10893 // If bEnd was the first Cold basic block update fgFirstColdBlock
10894 if (fgFirstColdBlock == bEnd)
10896 fgFirstColdBlock = bPrev->bbNext;
10899 #if FEATURE_EH_FUNCLETS
10901 // You can't unlink a range that includes the first funclet block. A range certainly
10902 // can't cross the non-funclet/funclet region. And you can't unlink the first block
10903 // of the first funclet with this, either. (If that's necessary, it could be allowed
10904 // by updating fgFirstFuncletBB to bEnd->bbNext.)
10905 for (BasicBlock* tempBB = bBeg; tempBB != bEnd->bbNext; tempBB = tempBB->bbNext)
10907 assert(tempBB != fgFirstFuncletBB);
10910 #endif // FEATURE_EH_FUNCLETS
10913 /*****************************************************************************************************
10915 * Function called to remove a basic block
10918 void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
10920 BasicBlock* bPrev = block->bbPrev;
10922 /* The block has to be either unreachable or empty */
10924 PREFIX_ASSUME(block != nullptr);
10926 JITDUMP("fgRemoveBlock BB%02u\n", block->bbNum);
10928 // If we've cached any mappings from switch blocks to SwitchDesc's (which contain only the
10929 // *unique* successors of the switch block), invalidate that cache, since an entry in one of
10930 // the SwitchDescs might be removed.
10931 InvalidateUniqueSwitchSuccMap();
10933 noway_assert((block == fgFirstBB) || (bPrev && (bPrev->bbNext == block)));
10934 noway_assert(!(block->bbFlags & BBF_DONT_REMOVE));
10936 // Should never remove a genReturnBB, as we might have special hookups there.
10937 noway_assert(block != genReturnBB);
10939 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10940 // Don't remove a finally target
10941 assert(!(block->bbFlags & BBF_FINALLY_TARGET));
10942 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10946 PREFIX_ASSUME(bPrev != nullptr);
10948 fgUnreachableBlock(block);
10950 /* If this is the last basic block update fgLastBB */
10951 if (block == fgLastBB)
10956 #if FEATURE_EH_FUNCLETS
10957 // If block was the fgFirstFuncletBB then set fgFirstFuncletBB to block->bbNext
10958 if (block == fgFirstFuncletBB)
10960 fgFirstFuncletBB = block->bbNext;
10962 #endif // FEATURE_EH_FUNCLETS
10964 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
10966 // bPrev CALL becomes RETLESS as the BBJ_ALWAYS block is unreachable
10967 bPrev->bbFlags |= BBF_RETLESS_CALL;
10969 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10970 NO_WAY("No retless call finally blocks; need unwind target instead");
10971 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
10973 else if (bPrev->bbJumpKind == BBJ_ALWAYS && bPrev->bbJumpDest == block->bbNext &&
10974 !(bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) && (block != fgFirstColdBlock) &&
10975 (block->bbNext != fgFirstColdBlock))
10977 // previous block is a BBJ_ALWAYS to the next block: change to BBJ_NONE.
10978 // Note that we don't do it if bPrev follows a BBJ_CALLFINALLY block (BBF_KEEP_BBJ_ALWAYS),
10979 // because that would violate our invariant that BBJ_CALLFINALLY blocks are followed by
10980 // BBJ_ALWAYS blocks.
10981 bPrev->bbJumpKind = BBJ_NONE;
10982 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
10985 // If this is the first Cold basic block update fgFirstColdBlock
10986 if (block == fgFirstColdBlock)
10988 fgFirstColdBlock = block->bbNext;
10991 /* Unlink this block from the bbNext chain */
10992 fgUnlinkBlock(block);
10994 /* At this point the bbPreds and bbRefs had better be zero */
10995 noway_assert((block->bbRefs == 0) && (block->bbPreds == nullptr));
10997 /* A BBJ_CALLFINALLY is usually paired with a BBJ_ALWAYS.
10998 * If we delete such a BBJ_CALLFINALLY we also delete the BBJ_ALWAYS
11000 if (block->isBBCallAlwaysPair())
11002 BasicBlock* leaveBlk = block->bbNext;
11003 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
11005 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
11006 leaveBlk->bbRefs = 0;
11007 leaveBlk->bbPreds = nullptr;
11009 fgRemoveBlock(leaveBlk, true);
11011 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
11012 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
11013 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
11015 else if (block->bbJumpKind == BBJ_RETURN)
11017 fgRemoveReturnBlock(block);
11020 else // block is empty
11022 noway_assert(block->isEmpty());
11024 /* The block cannot follow a non-retless BBJ_CALLFINALLY (because we don't know who may jump to it) */
11025 noway_assert((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair());
11027 /* This cannot be the last basic block */
11028 noway_assert(block != fgLastBB);
11033 printf("Removing empty BB%02u\n", block->bbNum);
11038 /* Some extra checks for the empty case */
11040 switch (block->bbJumpKind)
11046 /* Do not remove a block that jumps to itself - used for while (true){} */
11047 noway_assert(block->bbJumpDest != block);
11049 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
11050 noway_assert(bPrev && bPrev->bbJumpKind == BBJ_NONE);
11054 noway_assert(!"Empty block of this type cannot be removed!");
11059 noway_assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS);
11061 /* Who is the "real" successor of this block? */
11063 BasicBlock* succBlock;
11065 if (block->bbJumpKind == BBJ_ALWAYS)
11067 succBlock = block->bbJumpDest;
11071 succBlock = block->bbNext;
11074 bool skipUnmarkLoop = false;
11076 // If block is the backedge for a loop and succBlock precedes block
11077 // then the succBlock becomes the new LOOP HEAD
11078 // NOTE: there's an assumption here that the blocks are numbered in increasing bbNext order.
11079 // NOTE 2: if fgDomsComputed is false, then we can't check reachability. However, if this is
11080 // the case, then the loop structures probably are also invalid, and shouldn't be used. This
11081 // can be the case late in compilation (such as Lower), where remnants of earlier created
11082 // structures exist, but haven't been maintained.
11083 if (block->isLoopHead() && (succBlock->bbNum <= block->bbNum))
11085 succBlock->bbFlags |= BBF_LOOP_HEAD;
11086 if (fgDomsComputed && fgReachable(succBlock, block))
11088 /* Mark all the reachable blocks between 'succBlock' and 'block', excluding 'block' */
11089 optMarkLoopBlocks(succBlock, block, true);
11092 else if (succBlock->isLoopHead() && bPrev && (succBlock->bbNum <= bPrev->bbNum))
11094 skipUnmarkLoop = true;
11097 noway_assert(succBlock);
11099 // If this is the first Cold basic block update fgFirstColdBlock
11100 if (block == fgFirstColdBlock)
11102 fgFirstColdBlock = block->bbNext;
11105 #if FEATURE_EH_FUNCLETS
11106 // Update fgFirstFuncletBB if necessary
11107 if (block == fgFirstFuncletBB)
11109 fgFirstFuncletBB = block->bbNext;
11111 #endif // FEATURE_EH_FUNCLETS
11113 /* First update the loop table and bbWeights */
11114 optUpdateLoopsBeforeRemoveBlock(block, skipUnmarkLoop);
11116 /* Remove the block */
11118 if (bPrev == nullptr)
11120 /* special case if this is the first BB */
11122 noway_assert(block == fgFirstBB);
11124 /* Must be a fall through to next block */
11126 noway_assert(block->bbJumpKind == BBJ_NONE);
11128 /* old block no longer gets the extra ref count for being the first block */
11130 succBlock->bbRefs++;
11132 /* Set the new firstBB */
11133 fgUnlinkBlock(block);
11135 /* Always treat the initial block as a jump target */
11136 fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
11140 fgUnlinkBlock(block);
11143 /* mark the block as removed and set the change flag */
11145 block->bbFlags |= BBF_REMOVED;
11147 /* Update bbRefs and bbPreds.
11148 * All blocks jumping to 'block' now jump to 'succBlock'.
11149 * First, remove 'block' from the predecessor list of succBlock.
11152 fgRemoveRefPred(succBlock, block);
11154 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
11156 BasicBlock* predBlock = pred->flBlock;
11158 /* Are we changing a loop backedge into a forward jump? */
11160 if (block->isLoopHead() && (predBlock->bbNum >= block->bbNum) && (predBlock->bbNum <= succBlock->bbNum))
11162 /* First update the loop table and bbWeights */
11163 optUpdateLoopsBeforeRemoveBlock(predBlock);
11166 /* If predBlock is a new predecessor, then add it to succBlock's
11167 predecessor's list. */
11168 if (predBlock->bbJumpKind != BBJ_SWITCH)
11170 // Even if the pred is not a switch, we could have a conditional branch
11171 // to the fallthrough, so duplicate there could be preds
11172 for (unsigned i = 0; i < pred->flDupCount; i++)
11174 fgAddRefPred(succBlock, predBlock);
11178 /* change all jumps to the removed block */
11179 switch (predBlock->bbJumpKind)
11182 noway_assert(!"Unexpected bbJumpKind in fgRemoveBlock()");
11186 noway_assert(predBlock == bPrev);
11187 PREFIX_ASSUME(bPrev != nullptr);
11189 /* In the case of BBJ_ALWAYS we have to change the type of its predecessor */
11190 if (block->bbJumpKind == BBJ_ALWAYS)
11192 /* bPrev now becomes a BBJ_ALWAYS */
11193 bPrev->bbJumpKind = BBJ_ALWAYS;
11194 bPrev->bbJumpDest = succBlock;
11199 /* The links for the direct predecessor case have already been updated above */
11200 if (predBlock->bbJumpDest != block)
11202 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
11206 /* Check if both side of the BBJ_COND now jump to the same block */
11207 if (predBlock->bbNext == succBlock)
11209 // Make sure we are replacing "block" with "succBlock" in predBlock->bbJumpDest.
11210 noway_assert(predBlock->bbJumpDest == block);
11211 predBlock->bbJumpDest = succBlock;
11212 fgRemoveConditionalJump(predBlock);
11216 /* Fall through for the jump case */
11219 case BBJ_CALLFINALLY:
11221 case BBJ_EHCATCHRET:
11222 noway_assert(predBlock->bbJumpDest == block);
11223 predBlock->bbJumpDest = succBlock;
11224 succBlock->bbFlags |= BBF_HAS_LABEL | BBF_JMP_TARGET;
11228 // Change any jumps from 'predBlock' (a BBJ_SWITCH) to 'block' to jump to 'succBlock'
11230 // For the jump targets of 'predBlock' (a BBJ_SWITCH) that jump to 'block'
11231 // remove the old predecessor at 'block' from 'predBlock' and
11232 // add the new predecessor at 'succBlock' from 'predBlock'
11234 fgReplaceSwitchJumpTarget(predBlock, succBlock, block);
11240 if (bPrev != nullptr)
11242 switch (bPrev->bbJumpKind)
11244 case BBJ_CALLFINALLY:
11245 // If prev is a BBJ_CALLFINALLY it better be marked as RETLESS
11246 noway_assert(bPrev->bbFlags & BBF_RETLESS_CALL);
11250 // Check for branch to next block. Just make sure the BBJ_ALWAYS block is not
11251 // part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair. We do this here and don't rely on fgUpdateFlowGraph
11252 // because we can be called by ComputeDominators and it expects it to remove this jump to
11253 // the next block. This is the safest fix. We should remove all this BBJ_CALLFINALLY/BBJ_ALWAYS
11256 if ((bPrev->bbJumpDest == bPrev->bbNext) &&
11257 !fgInDifferentRegions(bPrev, bPrev->bbJumpDest)) // We don't remove a branch from Hot -> Cold
11259 if ((bPrev == fgFirstBB) || !bPrev->bbPrev->isBBCallAlwaysPair())
11261 // It's safe to change the jump type
11262 bPrev->bbJumpKind = BBJ_NONE;
11263 bPrev->bbFlags &= ~BBF_NEEDS_GCPOLL;
11269 /* Check for branch to next block */
11270 if (bPrev->bbJumpDest == bPrev->bbNext)
11272 fgRemoveConditionalJump(bPrev);
11280 ehUpdateForDeletedBlock(block);
11284 /*****************************************************************************
11286 * Function called to connect to block that previously had a fall through
11289 BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
11291 BasicBlock* jmpBlk = nullptr;
11293 /* If bSrc is non-NULL */
11295 if (bSrc != nullptr)
11297 /* If bSrc falls through to a block that is not bDst, we will insert a jump to bDst */
11299 if (bSrc->bbFallsThrough() && (bSrc->bbNext != bDst))
11301 switch (bSrc->bbJumpKind)
11305 bSrc->bbJumpKind = BBJ_ALWAYS;
11306 bSrc->bbJumpDest = bDst;
11307 bSrc->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
11311 printf("Block BB%02u ended with a BBJ_NONE, Changed to an unconditional jump to BB%02u\n",
11312 bSrc->bbNum, bSrc->bbJumpDest->bbNum);
11317 case BBJ_CALLFINALLY:
11320 // Add a new block after bSrc which jumps to 'bDst'
11321 jmpBlk = fgNewBBafter(BBJ_ALWAYS, bSrc, true);
11323 if (fgComputePredsDone)
11325 fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc));
11328 // When adding a new jmpBlk we will set the bbWeight and bbFlags
11330 if (fgHaveValidEdgeWeights)
11332 noway_assert(fgComputePredsDone);
11334 flowList* newEdge = fgGetPredForBlock(jmpBlk, bSrc);
11336 jmpBlk->bbWeight = (newEdge->flEdgeWeightMin + newEdge->flEdgeWeightMax) / 2;
11337 if (bSrc->bbWeight == 0)
11339 jmpBlk->bbWeight = 0;
11342 if (jmpBlk->bbWeight == 0)
11344 jmpBlk->bbFlags |= BBF_RUN_RARELY;
11347 BasicBlock::weight_t weightDiff = (newEdge->flEdgeWeightMax - newEdge->flEdgeWeightMin);
11348 BasicBlock::weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst);
11351 // If the [min/max] values for our edge weight is within the slop factor
11352 // then we will set the BBF_PROF_WEIGHT flag for the block
11354 if (weightDiff <= slop)
11356 jmpBlk->bbFlags |= BBF_PROF_WEIGHT;
11361 // We set the bbWeight to the smaller of bSrc->bbWeight or bDst->bbWeight
11362 if (bSrc->bbWeight < bDst->bbWeight)
11364 jmpBlk->bbWeight = bSrc->bbWeight;
11365 jmpBlk->bbFlags |= (bSrc->bbFlags & BBF_RUN_RARELY);
11369 jmpBlk->bbWeight = bDst->bbWeight;
11370 jmpBlk->bbFlags |= (bDst->bbFlags & BBF_RUN_RARELY);
11374 jmpBlk->bbJumpDest = bDst;
11375 jmpBlk->bbJumpDest->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
11377 if (fgComputePredsDone)
11379 fgReplacePred(bDst, bSrc, jmpBlk);
11383 jmpBlk->bbFlags |= BBF_IMPORTED;
11389 printf("Added an unconditional jump to BB%02u after block BB%02u\n", jmpBlk->bbJumpDest->bbNum,
11396 noway_assert(!"Unexpected bbJumpKind");
11402 // If bSrc is an unconditional branch to the next block
11403 // then change it to a BBJ_NONE block
11405 if ((bSrc->bbJumpKind == BBJ_ALWAYS) && !(bSrc->bbFlags & BBF_KEEP_BBJ_ALWAYS) &&
11406 (bSrc->bbJumpDest == bSrc->bbNext))
11408 bSrc->bbJumpKind = BBJ_NONE;
11409 bSrc->bbFlags &= ~BBF_NEEDS_GCPOLL;
11413 printf("Changed an unconditional jump from BB%02u to the next block BB%02u into a BBJ_NONE block\n",
11414 bSrc->bbNum, bSrc->bbNext->bbNum);
11424 /*****************************************************************************
11425 Walk the flow graph, reassign block numbers to keep them in ascending order.
11426 Returns 'true' if any renumbering was actually done, OR if we change the
11427 maximum number of assigned basic blocks (this can happen if we do inlining,
11428 create a new, high-numbered block, then that block goes away. We go to
11429 renumber the blocks, none of them actually change number, but we shrink the
11430 maximum assigned block number. This affects the block set epoch).
11433 bool Compiler::fgRenumberBlocks()
11435 // If we renumber the blocks the dominator information will be out-of-date
11436 if (fgDomsComputed)
11438 noway_assert(!"Can't call Compiler::fgRenumberBlocks() when fgDomsComputed==true");
11444 printf("\n*************** Before renumbering the basic blocks\n");
11445 fgDispBasicBlocks();
11446 fgDispHandlerTab();
11450 bool renumbered = false;
11451 bool newMaxBBNum = false;
11454 unsigned numStart = 1 + (compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : 0);
11457 for (block = fgFirstBB, num = numStart; block != nullptr; block = block->bbNext, num++)
11459 noway_assert((block->bbFlags & BBF_REMOVED) == 0);
11461 if (block->bbNum != num)
11467 printf("Renumber BB%02u to BB%02u\n", block->bbNum, num);
11470 block->bbNum = num;
11473 if (block->bbNext == nullptr)
11476 fgBBcount = num - numStart + 1;
11477 if (compIsForInlining())
11479 if (impInlineInfo->InlinerCompiler->fgBBNumMax != num)
11481 impInlineInfo->InlinerCompiler->fgBBNumMax = num;
11482 newMaxBBNum = true;
11487 if (fgBBNumMax != num)
11490 newMaxBBNum = true;
11499 printf("\n*************** After renumbering the basic blocks\n");
11502 fgDispBasicBlocks();
11503 fgDispHandlerTab();
11507 printf("=============== No blocks renumbered!\n");
11512 // Now update the BlockSet epoch, which depends on the block numbers.
11513 // If any blocks have been renumbered then create a new BlockSet epoch.
11514 // Even if we have not renumbered any blocks, we might still need to force
11515 // a new BlockSet epoch, for one of several reasons. If there are any new
11516 // blocks with higher numbers than the former maximum numbered block, then we
11517 // need a new epoch with a new size matching the new largest numbered block.
11518 // Also, if the number of blocks is different from the last time we set the
11519 // BlockSet epoch, then we need a new epoch. This wouldn't happen if we
11520 // renumbered blocks after every block addition/deletion, but it might be
11521 // the case that we can change the number of blocks, then set the BlockSet
11522 // epoch without renumbering, then change the number of blocks again, then
11524 if (renumbered || newMaxBBNum)
11526 NewBasicBlockEpoch();
11528 // The key in the unique switch successor map is dependent on the block number, so invalidate that cache.
11529 InvalidateUniqueSwitchSuccMap();
11533 EnsureBasicBlockEpoch();
11536 // Tell our caller if any blocks actually were renumbered.
11537 return renumbered || newMaxBBNum;
11540 /*****************************************************************************
11542 * Is the BasicBlock bJump a forward branch?
11543 * Optionally bSrc can be supplied to indicate that
11544 * bJump must be forward with respect to bSrc
11546 bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc /* = NULL */)
11548 bool result = false;
11550 if ((bJump->bbJumpKind == BBJ_COND) || (bJump->bbJumpKind == BBJ_ALWAYS))
11552 BasicBlock* bDest = bJump->bbJumpDest;
11553 BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc;
11557 bTemp = bTemp->bbNext;
11559 if (bTemp == nullptr)
11564 if (bTemp == bDest)
11575 /*****************************************************************************
11577 * Function called to expand the set of rarely run blocks
11580 bool Compiler::fgExpandRarelyRunBlocks()
11582 bool result = false;
11587 printf("\n*************** In fgExpandRarelyRunBlocks()\n");
11590 const char* reason = nullptr;
11593 // We expand the number of rarely run blocks by observing
11594 // that a block that falls into or jumps to a rarely run block,
11595 // must itself be rarely run and when we have a conditional
11596 // jump in which both branches go to rarely run blocks then
11597 // the block must itself be rarely run
11602 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
11604 if (bPrev->isRunRarely())
11609 /* bPrev is known to be a normal block here */
11610 switch (bPrev->bbJumpKind)
11614 /* Is the jump target rarely run? */
11615 if (bPrev->bbJumpDest->isRunRarely())
11617 INDEBUG(reason = "Unconditional jump to a rarely run block";)
11618 goto NEW_RARELY_RUN;
11622 case BBJ_CALLFINALLY:
11624 // Check for a BBJ_CALLFINALLY followed by a rarely run paired BBJ_ALWAYS
11626 if (bPrev->isBBCallAlwaysPair())
11628 /* Is the next block rarely run? */
11629 if (block->isRunRarely())
11631 INDEBUG(reason = "Call of finally followed by a rarely run block";)
11632 goto NEW_RARELY_RUN;
11639 /* is fall through target rarely run? */
11640 if (block->isRunRarely())
11642 INDEBUG(reason = "Falling into a rarely run block";)
11643 goto NEW_RARELY_RUN;
11649 if (!block->isRunRarely())
11654 /* If both targets of the BBJ_COND are run rarely then don't reorder */
11655 if (bPrev->bbJumpDest->isRunRarely())
11657 /* bPrev should also be marked as run rarely */
11658 if (!bPrev->isRunRarely())
11660 INDEBUG(reason = "Both sides of a conditional jump are rarely run";)
11663 /* If the weight of the block was obtained from a profile run,
11664 than it's more accurate than our static analysis */
11665 if (bPrev->hasProfileWeight())
11672 assert(reason != nullptr);
11675 printf("%s, marking BB%02u as rarely run\n", reason, bPrev->bbNum);
11679 /* Must not have previously been marked */
11680 noway_assert(!bPrev->isRunRarely());
11682 /* Mark bPrev as a new rarely run block */
11683 bPrev->bbSetRunRarely();
11685 BasicBlock* bPrevPrev = nullptr;
11688 if ((bPrev->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
11690 // If we've got a BBJ_CALLFINALLY/BBJ_ALWAYS pair, treat the BBJ_CALLFINALLY as an
11691 // additional predecessor for the BBJ_ALWAYS block
11692 tmpbb = bPrev->bbPrev;
11693 noway_assert(tmpbb != nullptr);
11694 #if FEATURE_EH_FUNCLETS
11695 noway_assert(tmpbb->isBBCallAlwaysPair());
11698 if (tmpbb->bbJumpKind == BBJ_CALLFINALLY)
11705 /* Now go back to it's earliest predecessor to see */
11706 /* if it too should now be marked as rarely run */
11707 flowList* pred = bPrev->bbPreds;
11709 if ((pred != nullptr) || (bPrevPrev != nullptr))
11711 // bPrevPrev will be set to the lexically
11712 // earliest predecessor of bPrev.
11714 while (pred != nullptr)
11716 if (bPrevPrev == nullptr)
11718 // Initially we select the first block in the bbPreds list
11719 bPrevPrev = pred->flBlock;
11723 // Walk the flow graph lexically forward from pred->flBlock
11724 // if we find (block == bPrevPrev) then
11725 // pred->flBlock is an earlier predecessor.
11726 for (tmpbb = pred->flBlock; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11728 if (tmpbb == bPrevPrev)
11730 /* We found an ealier predecessor */
11731 bPrevPrev = pred->flBlock;
11734 else if (tmpbb == bPrev)
11736 // We have reached bPrev so stop walking
11737 // as this cannot be an earlier predecessor
11742 // Onto the next predecessor
11743 pred = pred->flNext;
11746 // Walk the flow graph forward from bPrevPrev
11747 // if we don't find (tmpbb == bPrev) then our candidate
11748 // bPrevPrev is lexically after bPrev and we do not
11749 // want to select it as our new block
11751 for (tmpbb = bPrevPrev; tmpbb != nullptr; tmpbb = tmpbb->bbNext)
11753 if (tmpbb == bPrev)
11755 // Set up block back to the lexically
11756 // earliest predecessor of pPrev
11771 // Now iterate over every block to see if we can prove that a block is rarely run
11772 // (i.e. when all predecessors to the block are rarely run)
11774 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
11776 // If block is not run rarely, then check to make sure that it has
11777 // at least one non-rarely run block.
11779 if (!block->isRunRarely())
11783 /* Make sure that block has at least one normal predecessor */
11784 for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
11786 /* Find the fall through predecessor, if any */
11787 if (!pred->flBlock->isRunRarely())
11796 // If 'block' is the start of a handler or filter then we cannot make it
11797 // rarely run because we may have an exceptional edge that
11800 if (bbIsHandlerBeg(block))
11808 block->bbSetRunRarely();
11814 printf("All branches to BB%02u are from rarely run blocks, marking as rarely run\n", block->bbNum);
11818 // When marking a BBJ_CALLFINALLY as rarely run we also mark
11819 // the BBJ_ALWAYS that comes after it as rarely run
11821 if (block->isBBCallAlwaysPair())
11823 BasicBlock* bNext = block->bbNext;
11824 PREFIX_ASSUME(bNext != nullptr);
11825 bNext->bbSetRunRarely();
11829 printf("Also marking the BBJ_ALWAYS at BB%02u as rarely run\n", bNext->bbNum);
11836 /* COMPACT blocks if possible */
11837 if (bPrev->bbJumpKind == BBJ_NONE)
11839 if (fgCanCompactBlocks(bPrev, block))
11841 fgCompactBlocks(bPrev, block);
11848 // if bPrev->bbWeight is not based upon profile data we can adjust
11849 // the weights of bPrev and block
11851 else if (bPrev->isBBCallAlwaysPair() && // we must have a BBJ_CALLFINALLY and BBK_ALWAYS pair
11852 (bPrev->bbWeight != block->bbWeight) && // the weights are currently different
11853 !bPrev->hasProfileWeight()) // and the BBJ_CALLFINALLY block is not using profiled
11856 if (block->isRunRarely())
11859 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11860 bPrev->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11864 printf("Marking the BBJ_CALLFINALLY block at BB%02u as rarely run because BB%02u is rarely run\n",
11865 bPrev->bbNum, block->bbNum);
11869 else if (bPrev->isRunRarely())
11872 bPrev->bbWeight; // the BBJ_ALWAYS block now has the same weight as the BBJ_CALLFINALLY block
11873 block->bbFlags |= BBF_RUN_RARELY; // and is now rarely run
11877 printf("Marking the BBJ_ALWAYS block at BB%02u as rarely run because BB%02u is rarely run\n",
11878 block->bbNum, bPrev->bbNum);
11882 else // Both blocks are hot, bPrev is known not to be using profiled weight
11885 block->bbWeight; // the BBJ_CALLFINALLY block now has the same weight as the BBJ_ALWAYS block
11887 noway_assert(block->bbWeight == bPrev->bbWeight);
11894 /*****************************************************************************
11896 * Returns true if it is allowable (based upon the EH regions)
11897 * to place block bAfter immediately after bBefore. It is allowable
11898 * if the 'bBefore' and 'bAfter' blocks are in the exact same EH region.
11901 bool Compiler::fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter)
11903 return BasicBlock::sameEHRegion(bBefore, bAfter);
11906 /*****************************************************************************
11908 * Function called to move the range of blocks [bStart .. bEnd].
11909 * The blocks are placed immediately after the insertAfterBlk.
11910 * fgFirstFuncletBB is not updated; that is the responsibility of the caller, if necessary.
11913 void Compiler::fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk)
11915 /* We have decided to insert the block(s) after 'insertAfterBlk' */
11916 CLANG_FORMAT_COMMENT_ANCHOR;
11921 printf("Relocated block%s [BB%02u..BB%02u] inserted after BB%02u%s\n", (bStart == bEnd) ? "" : "s",
11922 bStart->bbNum, bEnd->bbNum, insertAfterBlk->bbNum,
11923 (insertAfterBlk->bbNext == nullptr) ? " at the end of method" : "");
11927 /* relink [bStart .. bEnd] into the flow graph */
11929 bEnd->bbNext = insertAfterBlk->bbNext;
11930 if (insertAfterBlk->bbNext)
11932 insertAfterBlk->bbNext->bbPrev = bEnd;
11934 insertAfterBlk->setNext(bStart);
11936 /* If insertAfterBlk was fgLastBB then update fgLastBB */
11937 if (insertAfterBlk == fgLastBB)
11940 noway_assert(fgLastBB->bbNext == nullptr);
11944 /*****************************************************************************
11946 * Function called to relocate a single range to the end of the method.
11947 * Only an entire consecutive region can be moved and it will be kept together.
11948 * Except for the first block, the range cannot have any blocks that jump into or out of the region.
11949 * When successful we return the bLast block which is the last block that we relocated.
11950 * When unsuccessful we return NULL.
11952 =============================================================
11953 NOTE: This function can invalidate all pointers into the EH table, as well as change the size of the EH table!
11954 =============================================================
11957 BasicBlock* Compiler::fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType)
11959 INDEBUG(const char* reason = "None";)
11961 // Figure out the range of blocks we're going to move
11965 BasicBlock* bStart = nullptr;
11966 BasicBlock* bMiddle = nullptr;
11967 BasicBlock* bLast = nullptr;
11968 BasicBlock* bPrev = nullptr;
11970 #if FEATURE_EH_FUNCLETS
11971 // We don't support moving try regions... yet?
11972 noway_assert(relocateType == FG_RELOCATE_HANDLER);
11973 #endif // FEATURE_EH_FUNCLETS
11975 HBtab = ehGetDsc(regionIndex);
11977 if (relocateType == FG_RELOCATE_TRY)
11979 bStart = HBtab->ebdTryBeg;
11980 bLast = HBtab->ebdTryLast;
11982 else if (relocateType == FG_RELOCATE_HANDLER)
11984 if (HBtab->HasFilter())
11986 // The filter and handler funclets must be moved together, and remain contiguous.
11987 bStart = HBtab->ebdFilter;
11988 bMiddle = HBtab->ebdHndBeg;
11989 bLast = HBtab->ebdHndLast;
11993 bStart = HBtab->ebdHndBeg;
11994 bLast = HBtab->ebdHndLast;
11998 // Our range must contain either all rarely run blocks or all non-rarely run blocks
11999 bool inTheRange = false;
12000 bool validRange = false;
12004 noway_assert(bStart != nullptr && bLast != nullptr);
12005 if (bStart == fgFirstBB)
12007 INDEBUG(reason = "can not relocate first block";)
12011 #if !FEATURE_EH_FUNCLETS
12012 // In the funclets case, we still need to set some information on the handler blocks
12013 if (bLast->bbNext == NULL)
12015 INDEBUG(reason = "region is already at the end of the method";)
12018 #endif // !FEATURE_EH_FUNCLETS
12020 // Walk the block list for this purpose:
12021 // 1. Verify that all the blocks in the range are either all rarely run or not rarely run.
12022 // When creating funclets, we ignore the run rarely flag, as we need to be able to move any blocks
12024 CLANG_FORMAT_COMMENT_ANCHOR;
12026 #if !FEATURE_EH_FUNCLETS
12028 isRare = bStart->isRunRarely();
12029 #endif // !FEATURE_EH_FUNCLETS
12033 if (block == bStart)
12035 noway_assert(inTheRange == false);
12038 else if (block == bLast->bbNext)
12040 noway_assert(inTheRange == true);
12041 inTheRange = false;
12042 break; // we found the end, so we're done
12047 #if !FEATURE_EH_FUNCLETS
12048 // Unless all blocks are (not) run rarely we must return false.
12049 if (isRare != block->isRunRarely())
12051 INDEBUG(reason = "this region contains both rarely run and non-rarely run blocks";)
12054 #endif // !FEATURE_EH_FUNCLETS
12059 if (block == nullptr)
12064 block = block->bbNext;
12066 // Ensure that bStart .. bLast defined a valid range
12067 noway_assert((validRange == true) && (inTheRange == false));
12069 bPrev = bStart->bbPrev;
12070 noway_assert(bPrev != nullptr); // Can't move a range that includes the first block of the function.
12072 JITDUMP("Relocating %s range BB%02u..BB%02u (EH#%u) to end of BBlist\n",
12073 (relocateType == FG_RELOCATE_TRY) ? "try" : "handler", bStart->bbNum, bLast->bbNum, regionIndex);
12078 fgDispBasicBlocks();
12079 fgDispHandlerTab();
12082 if (!FEATURE_EH_FUNCLETS)
12084 // This is really expensive, and quickly becomes O(n^n) with funclets
12085 // so only do it once after we've created them (see fgCreateFunclets)
12086 if (expensiveDebugCheckLevel >= 2)
12088 fgDebugCheckBBlist();
12093 #if FEATURE_EH_FUNCLETS
12095 bStart->bbFlags |= BBF_FUNCLET_BEG; // Mark the start block of the funclet
12097 if (bMiddle != nullptr)
12099 bMiddle->bbFlags |= BBF_FUNCLET_BEG; // Also mark the start block of a filter handler as a funclet
12102 #endif // FEATURE_EH_FUNCLETS
12105 bNext = bLast->bbNext;
12107 /* Temporarily unlink [bStart .. bLast] from the flow graph */
12108 fgUnlinkRange(bStart, bLast);
12110 BasicBlock* insertAfterBlk;
12111 insertAfterBlk = fgLastBB;
12113 #if FEATURE_EH_FUNCLETS
12115 // There are several cases we need to consider when moving an EH range.
12116 // If moving a range X, we must consider its relationship to every other EH
12117 // range A in the table. Note that each entry in the table represents both
12118 // a protected region and a handler region (possibly including a filter region
12119 // that must live before and adjacent to the handler region), so we must
12120 // consider try and handler regions independently. These are the cases:
12121 // 1. A is completely contained within X (where "completely contained" means
12122 // that the 'begin' and 'last' parts of A are strictly between the 'begin'
12123 // and 'end' parts of X, and aren't equal to either, for example, they don't
12124 // share 'last' blocks). In this case, when we move X, A moves with it, and
12125 // the EH table doesn't need to change.
12126 // 2. X is completely contained within A. In this case, X gets extracted from A,
12127 // and the range of A shrinks, but because A is strictly within X, the EH
12128 // table doesn't need to change.
12129 // 3. A and X have exactly the same range. In this case, A is moving with X and
12130 // the EH table doesn't need to change.
12131 // 4. A and X share the 'last' block. There are two sub-cases:
12132 // (a) A is a larger range than X (such that the beginning of A precedes the
12133 // beginning of X): in this case, we are moving the tail of A. We set the
12134 // 'last' block of A to the the block preceding the beginning block of X.
12135 // (b) A is a smaller range than X. Thus, we are moving the entirety of A along
12136 // with X. In this case, nothing in the EH record for A needs to change.
12137 // 5. A and X share the 'beginning' block (but aren't the same range, as in #3).
12138 // This can never happen here, because we are only moving handler ranges (we don't
12139 // move try ranges), and handler regions cannot start at the beginning of a try
12140 // range or handler range and be a subset.
12142 // Note that A and X must properly nest for the table to be well-formed. For example,
12143 // the beginning of A can't be strictly within the range of X (that is, the beginning
12144 // of A isn't shared with the beginning of X) and the end of A outside the range.
12146 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
12148 if (XTnum != regionIndex) // we don't need to update our 'last' pointer
12150 if (HBtab->ebdTryLast == bLast)
12152 // If we moved a set of blocks that were at the end of
12153 // a different try region then we may need to update ebdTryLast
12154 for (block = HBtab->ebdTryBeg; block != nullptr; block = block->bbNext)
12156 if (block == bPrev)
12158 // We were contained within it, so shrink its region by
12159 // setting its 'last'
12160 fgSetTryEnd(HBtab, bPrev);
12163 else if (block == HBtab->ebdTryLast->bbNext)
12165 // bPrev does not come after the TryBeg, thus we are larger, and
12166 // it is moving with us.
12171 if (HBtab->ebdHndLast == bLast)
12173 // If we moved a set of blocks that were at the end of
12174 // a different handler region then we must update ebdHndLast
12175 for (block = HBtab->ebdHndBeg; block != nullptr; block = block->bbNext)
12177 if (block == bPrev)
12179 fgSetHndEnd(HBtab, bPrev);
12182 else if (block == HBtab->ebdHndLast->bbNext)
12184 // bPrev does not come after the HndBeg
12190 } // end exception table iteration
12192 // Insert the block(s) we are moving after fgLastBlock
12193 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
12195 if (fgFirstFuncletBB == nullptr) // The funclet region isn't set yet
12197 fgFirstFuncletBB = bStart;
12201 assert(fgFirstFuncletBB !=
12202 insertAfterBlk->bbNext); // We insert at the end, not at the beginning, of the funclet region.
12205 // These asserts assume we aren't moving try regions (which we might need to do). Only
12206 // try regions can have fall through into or out of the region.
12208 noway_assert(!bPrev->bbFallsThrough()); // There can be no fall through into a filter or handler region
12209 noway_assert(!bLast->bbFallsThrough()); // There can be no fall through out of a handler region
12214 printf("Create funclets: moved region\n");
12215 fgDispHandlerTab();
12218 // We have to wait to do this until we've created all the additional regions
12219 // Because this relies on ebdEnclosingTryIndex and ebdEnclosingHndIndex
12220 if (!FEATURE_EH_FUNCLETS)
12222 // This is really expensive, and quickly becomes O(n^n) with funclets
12223 // so only do it once after we've created them (see fgCreateFunclets)
12224 if (expensiveDebugCheckLevel >= 2)
12226 fgDebugCheckBBlist();
12231 #else // FEATURE_EH_FUNCLETS
12233 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
12235 if (XTnum == regionIndex)
12237 // Don't update our handler's Last info
12241 if (HBtab->ebdTryLast == bLast)
12243 // If we moved a set of blocks that were at the end of
12244 // a different try region then we may need to update ebdTryLast
12245 for (block = HBtab->ebdTryBeg; block != NULL; block = block->bbNext)
12247 if (block == bPrev)
12249 fgSetTryEnd(HBtab, bPrev);
12252 else if (block == HBtab->ebdTryLast->bbNext)
12254 // bPrev does not come after the TryBeg
12259 if (HBtab->ebdHndLast == bLast)
12261 // If we moved a set of blocks that were at the end of
12262 // a different handler region then we must update ebdHndLast
12263 for (block = HBtab->ebdHndBeg; block != NULL; block = block->bbNext)
12265 if (block == bPrev)
12267 fgSetHndEnd(HBtab, bPrev);
12270 else if (block == HBtab->ebdHndLast->bbNext)
12272 // bPrev does not come after the HndBeg
12277 } // end exception table iteration
12279 // We have decided to insert the block(s) after fgLastBlock
12280 fgMoveBlocksAfter(bStart, bLast, insertAfterBlk);
12282 // If bPrev falls through, we will insert a jump to block
12283 fgConnectFallThrough(bPrev, bStart);
12285 // If bLast falls through, we will insert a jump to bNext
12286 fgConnectFallThrough(bLast, bNext);
12288 #endif // FEATURE_EH_FUNCLETS
12297 printf("*************** Failed fgRelocateEHRange(BB%02u..BB%02u) because %s\n", bStart->bbNum, bLast->bbNum,
12309 #if FEATURE_EH_FUNCLETS
12311 #if defined(_TARGET_ARM_)
12313 /*****************************************************************************
12314 * We just removed a BBJ_CALLFINALLY/BBJ_ALWAYS pair. If this was the only such pair
12315 * targeting the BBJ_ALWAYS target, then we need to clear the BBF_FINALLY_TARGET bit
12316 * so that target can also be removed. 'block' is the finally target. Since we just
12317 * removed the BBJ_ALWAYS, it better have the BBF_FINALLY_TARGET bit set.
12320 void Compiler::fgClearFinallyTargetBit(BasicBlock* block)
12322 assert(fgComputePredsDone);
12323 assert((block->bbFlags & BBF_FINALLY_TARGET) != 0);
12325 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
12327 if (pred->flBlock->bbJumpKind == BBJ_ALWAYS && pred->flBlock->bbJumpDest == block)
12329 BasicBlock* pPrev = pred->flBlock->bbPrev;
12332 if (pPrev->bbJumpKind == BBJ_CALLFINALLY)
12334 // We found a BBJ_CALLFINALLY / BBJ_ALWAYS that still points to this finally target
12341 // Didn't find any BBJ_CALLFINALLY / BBJ_ALWAYS that still points here, so clear the bit
12343 block->bbFlags &= ~BBF_FINALLY_TARGET;
12346 #endif // defined(_TARGET_ARM_)
12348 /*****************************************************************************
12349 * Is this an intra-handler control flow edge?
12351 * 'block' is the head block of a funclet/handler region, or .
12352 * 'predBlock' is a predecessor block of 'block' in the predecessor list.
12354 * 'predBlock' can legally only be one of three things:
12355 * 1. in the same handler region (e.g., the source of a back-edge of a loop from
12356 * 'predBlock' to 'block'), including in nested regions within the handler,
12357 * 2. if 'block' begins a handler that is a filter-handler, 'predBlock' must be in the 'filter' region,
12358 * 3. for other handlers, 'predBlock' must be in the 'try' region corresponding to handler (or any
12359 * region nested in the 'try' region).
12361 * Note that on AMD64/ARM64, the BBJ_CALLFINALLY block that calls a finally handler is not
12362 * within the corresponding 'try' region: it is placed in the corresponding 'try' region's
12363 * parent (which might be the main function body). This is how it is represented to the VM
12364 * (with a special "cloned finally" EH table entry).
12366 * Return 'true' for case #1, and 'false' otherwise.
12368 bool Compiler::fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block)
12370 // Some simple preconditions (as stated above)
12371 assert(!fgFuncletsCreated);
12372 assert(fgGetPredForBlock(block, predBlock) != nullptr);
12373 assert(block->hasHndIndex());
12375 EHblkDsc* xtab = ehGetDsc(block->getHndIndex());
12377 #if FEATURE_EH_CALLFINALLY_THUNKS
12378 if (xtab->HasFinallyHandler())
12380 assert((xtab->ebdHndBeg == block) || // The normal case
12381 ((xtab->ebdHndBeg->bbNext == block) &&
12382 (xtab->ebdHndBeg->bbFlags & BBF_INTERNAL))); // After we've already inserted a header block, and we're
12383 // trying to decide how to split up the predecessor edges.
12384 if (predBlock->bbJumpKind == BBJ_CALLFINALLY)
12386 assert(predBlock->bbJumpDest == block);
12388 // A BBJ_CALLFINALLY predecessor of the handler can only come from the corresponding try,
12389 // not from any EH clauses nested in this handler. However, we represent the BBJ_CALLFINALLY
12390 // as being in the 'try' region's parent EH region, which might be the main function body.
12392 unsigned tryIndex = xtab->ebdEnclosingTryIndex;
12393 if (tryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
12395 assert(!predBlock->hasTryIndex());
12399 assert(predBlock->hasTryIndex());
12400 assert(tryIndex == predBlock->getTryIndex());
12401 assert(ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
12406 #endif // FEATURE_EH_CALLFINALLY_THUNKS
12408 assert(predBlock->hasHndIndex() || predBlock->hasTryIndex());
12410 // We could search the try region looking for predBlock by using bbInTryRegions
12411 // but that does a lexical search for the block, and then assumes funclets
12412 // have been created and does a lexical search of all funclets that were pulled
12413 // out of the parent try region.
12414 // First, funclets haven't been created yet, and even if they had been, we shouldn't
12415 // have any funclet directly branching to another funclet (they have to return first).
12416 // So we can safely use CheckIsTryRegion instead of bbInTryRegions.
12417 // Second, I believe the depth of any EH graph will on average be smaller than the
12418 // breadth of the blocks within a try body. Thus it is faster to get our answer by
12419 // looping outward over the region graph. However, I have added asserts, as a
12420 // precaution, to ensure both algorithms agree. The asserts also check that the only
12421 // way to reach the head of a funclet is from the corresponding try body or from
12422 // within the funclet (and *not* any nested funclets).
12424 if (predBlock->hasTryIndex())
12426 // Because the EH clauses are listed inside-out, any nested trys will be at a
12427 // lower index than the current try and if there's no enclosing try, tryIndex
12428 // will terminate at NO_ENCLOSING_INDEX
12430 unsigned tryIndex = predBlock->getTryIndex();
12431 while (tryIndex < block->getHndIndex())
12433 tryIndex = ehGetEnclosingTryIndex(tryIndex);
12435 // tryIndex should enclose predBlock
12436 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(predBlock));
12438 // At this point tryIndex is either block's handler's corresponding try body
12439 // or some outer try region that contains both predBlock & block or
12440 // NO_ENCLOSING_REGION (because there was no try body that encloses both).
12441 if (tryIndex == block->getHndIndex())
12443 assert(xtab->InTryRegionBBRange(predBlock));
12444 assert(!xtab->InHndRegionBBRange(predBlock));
12447 // tryIndex should enclose block (and predBlock as previously asserted)
12448 assert((tryIndex == EHblkDsc::NO_ENCLOSING_INDEX) || ehGetDsc(tryIndex)->InTryRegionBBRange(block));
12450 if (xtab->HasFilter())
12452 // The block is a handler. Check if the pred block is from its filter. We only need to
12453 // check the end filter flag, as there is only a single filter for any handler, and we
12454 // already know predBlock is a predecessor of block.
12455 if (predBlock->bbJumpKind == BBJ_EHFILTERRET)
12457 assert(!xtab->InHndRegionBBRange(predBlock));
12461 // It is not in our try region (or filter), so it must be within this handler (or try bodies
12462 // within this handler)
12463 assert(!xtab->InTryRegionBBRange(predBlock));
12464 assert(xtab->InHndRegionBBRange(predBlock));
12468 /*****************************************************************************
12469 * Does this block, first block of a handler region, have any predecessor edges
12470 * that are not from its corresponding try region?
12473 bool Compiler::fgAnyIntraHandlerPreds(BasicBlock* block)
12475 assert(block->hasHndIndex());
12476 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
12480 for (pred = block->bbPreds; pred; pred = pred->flNext)
12482 BasicBlock* predBlock = pred->flBlock;
12484 if (fgIsIntraHandlerPred(predBlock, block))
12486 // We have a predecessor that is not from our try region
12494 /*****************************************************************************
12495 * Introduce a new head block of the handler for the prolog to be put in, ahead
12496 * of the current handler head 'block'.
12497 * Note that this code has some similarities to fgCreateLoopPreHeader().
12500 void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block)
12505 printf("\nCreating funclet prolog header for BB%02u\n", block->bbNum);
12509 assert(block->hasHndIndex());
12510 assert(fgFirstBlockOfHandler(block) == block); // this block is the first block of a handler
12512 /* Allocate a new basic block */
12514 BasicBlock* newHead = bbNewBasicBlock(BBJ_NONE);
12516 // In fgComputePreds() we set the BBF_JMP_TARGET and BBF_HAS_LABEL for all of the handler entry points
12518 newHead->bbFlags |= (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL);
12519 newHead->inheritWeight(block);
12520 newHead->bbRefs = 0;
12522 fgInsertBBbefore(block, newHead); // insert the new block in the block list
12523 fgExtendEHRegionBefore(block); // Update the EH table to make the prolog block the first block in the block's EH
12526 // Distribute the pred list between newHead and block. Incoming edges coming from outside
12527 // the handler go to the prolog. Edges coming from with the handler are back-edges, and
12528 // go to the existing 'block'.
12530 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
12532 BasicBlock* predBlock = pred->flBlock;
12533 if (!fgIsIntraHandlerPred(predBlock, block))
12535 // It's a jump from outside the handler; add it to the newHead preds list and remove
12536 // it from the block preds list.
12538 switch (predBlock->bbJumpKind)
12540 case BBJ_CALLFINALLY:
12541 noway_assert(predBlock->bbJumpDest == block);
12542 predBlock->bbJumpDest = newHead;
12543 fgRemoveRefPred(block, predBlock);
12544 fgAddRefPred(newHead, predBlock);
12548 // The only way into the handler is via a BBJ_CALLFINALLY (to a finally handler), or
12549 // via exception handling.
12550 noway_assert(false);
12556 assert(nullptr == fgGetPredForBlock(block, newHead));
12557 fgAddRefPred(block, newHead);
12559 assert((newHead->bbFlags & (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL)) ==
12560 (BBF_INTERNAL | BBF_JMP_TARGET | BBF_HAS_LABEL));
12563 /*****************************************************************************
12565 * Every funclet will have a prolog. That prolog will be inserted as the first instructions
12566 * in the first block of the funclet. If the prolog is also the head block of a loop, we
12567 * would end up with the prolog instructions being executed more than once.
12568 * Check for this by searching the predecessor list for loops, and create a new prolog header
12569 * block when needed. We detect a loop by looking for any predecessor that isn't in the
12570 * handler's try region, since the only way to get into a handler is via that try region.
12573 void Compiler::fgCreateFuncletPrologBlocks()
12575 noway_assert(fgComputePredsDone);
12576 noway_assert(!fgDomsComputed); // this function doesn't maintain the dom sets
12577 assert(!fgFuncletsCreated);
12579 bool prologBlocksCreated = false;
12580 EHblkDsc* HBtabEnd;
12583 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
12585 BasicBlock* head = HBtab->ebdHndBeg;
12587 if (fgAnyIntraHandlerPreds(head))
12589 // We need to create a new block in which to place the prolog, and split the existing
12590 // head block predecessor edges into those that should point to the prolog, and those
12593 // It's arguable that we should just always do this, and not only when we "need to",
12594 // so there aren't two different code paths. However, it's unlikely to be necessary
12595 // for catch handlers because they have an incoming argument (the exception object)
12596 // that needs to get stored or saved, so back-arcs won't normally go to the head. It's
12597 // possible when writing in IL to generate a legal loop (e.g., push an Exception object
12598 // on the stack before jumping back to the catch head), but C# probably won't. This will
12599 // most commonly only be needed for finallys with a do/while loop at the top of the
12602 // Note that we don't check filters. This might be a bug, but filters always have a filter
12603 // object live on entry, so it's at least unlikely (illegal?) that a loop edge targets the
12606 fgInsertFuncletPrologBlock(head);
12607 prologBlocksCreated = true;
12611 if (prologBlocksCreated)
12613 // If we've modified the graph, reset the 'modified' flag, since the dominators haven't
12615 fgModified = false;
12620 JITDUMP("\nAfter fgCreateFuncletPrologBlocks()");
12621 fgDispBasicBlocks();
12622 fgDispHandlerTab();
12625 fgVerifyHandlerTab();
12626 fgDebugCheckBBlist();
12631 /*****************************************************************************
12633 * Function to create funclets out of all EH catch/finally/fault blocks.
12634 * We only move filter and handler blocks, not try blocks.
12637 void Compiler::fgCreateFunclets()
12639 assert(!fgFuncletsCreated);
12644 printf("*************** In fgCreateFunclets()\n");
12648 fgCreateFuncletPrologBlocks();
12652 const unsigned int funcCnt = ehFuncletCount() + 1;
12654 if (!FitsIn<unsigned short>(funcCnt))
12656 IMPL_LIMITATION("Too many funclets");
12659 FuncInfoDsc* funcInfo = new (this, CMK_BasicBlock) FuncInfoDsc[funcCnt];
12661 unsigned short funcIdx;
12663 // Setup the root FuncInfoDsc and prepare to start associating
12664 // FuncInfoDsc's with their corresponding EH region
12665 memset((void*)funcInfo, 0, funcCnt * sizeof(FuncInfoDsc));
12666 assert(funcInfo[0].funKind == FUNC_ROOT);
12669 // Because we iterate from the top to the bottom of the compHndBBtab array, we are iterating
12670 // from most nested (innermost) to least nested (outermost) EH region. It would be reasonable
12671 // to iterate in the opposite order, but the order of funclets shouldn't matter.
12673 // We move every handler region to the end of the function: each handler will become a funclet.
12675 // Note that fgRelocateEHRange() can add new entries to the EH table. However, they will always
12676 // be added *after* the current index, so our iteration here is not invalidated.
12677 // It *can* invalidate the compHndBBtab pointer itself, though, if it gets reallocated!
12679 for (XTnum = 0; XTnum < compHndBBtabCount; XTnum++)
12681 HBtab = ehGetDsc(XTnum); // must re-compute this every loop, since fgRelocateEHRange changes the table
12682 if (HBtab->HasFilter())
12684 assert(funcIdx < funcCnt);
12685 funcInfo[funcIdx].funKind = FUNC_FILTER;
12686 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12689 assert(funcIdx < funcCnt);
12690 funcInfo[funcIdx].funKind = FUNC_HANDLER;
12691 funcInfo[funcIdx].funEHIndex = (unsigned short)XTnum;
12692 HBtab->ebdFuncIndex = funcIdx;
12694 fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12697 // We better have populated all of them by now
12698 assert(funcIdx == funcCnt);
12701 compCurrFuncIdx = 0;
12702 compFuncInfos = funcInfo;
12703 compFuncInfoCount = (unsigned short)funcCnt;
12705 fgFuncletsCreated = true;
12710 JITDUMP("\nAfter fgCreateFunclets()");
12711 fgDispBasicBlocks();
12712 fgDispHandlerTab();
12715 fgVerifyHandlerTab();
12716 fgDebugCheckBBlist();
12720 #else // !FEATURE_EH_FUNCLETS
12722 /*****************************************************************************
12724 * Function called to relocate any and all EH regions.
12725 * Only entire consecutive EH regions will be moved and they will be kept together.
12726 * Except for the first block, the range can not have any blocks that jump into or out of the region.
12729 bool Compiler::fgRelocateEHRegions()
12731 bool result = false; // Our return value
12735 printf("*************** In fgRelocateEHRegions()\n");
12738 if (fgCanRelocateEHRegions)
12743 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
12745 // Nested EH regions cannot be moved.
12746 // Also we don't want to relocate an EH region that has a filter
12747 if ((HBtab->ebdHandlerNestingLevel == 0) && !HBtab->HasFilter())
12749 bool movedTry = false;
12751 bool movedHnd = false;
12754 // Only try to move the outermost try region
12755 if (HBtab->ebdEnclosingTryIndex == EHblkDsc::NO_ENCLOSING_INDEX)
12757 // Move the entire try region if it can be moved
12758 if (HBtab->ebdTryBeg->isRunRarely())
12760 BasicBlock* bTryLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_TRY);
12761 if (bTryLastBB != NULL)
12768 if (verbose && movedTry)
12770 printf("\nAfter relocating an EH try region");
12771 fgDispBasicBlocks();
12772 fgDispHandlerTab();
12774 // Make sure that the predecessor lists are accurate
12775 if (expensiveDebugCheckLevel >= 2)
12777 fgDebugCheckBBlist();
12783 // Currently it is not good to move the rarely run handler regions to the end of the method
12784 // because fgDetermineFirstColdBlock() must put the start of any handler region in the hot
12786 CLANG_FORMAT_COMMENT_ANCHOR;
12789 // Now try to move the entire handler region if it can be moved.
12790 // Don't try to move a finally handler unless we already moved the try region.
12791 if (HBtab->ebdHndBeg->isRunRarely() &&
12792 !HBtab->ebdHndBeg->hasTryIndex() &&
12793 (movedTry || !HBtab->HasFinallyHandler()))
12795 BasicBlock* bHndLastBB = fgRelocateEHRange(XTnum, FG_RELOCATE_HANDLER);
12796 if (bHndLastBB != NULL)
12805 if (verbose && movedHnd)
12807 printf("\nAfter relocating an EH handler region");
12808 fgDispBasicBlocks();
12809 fgDispHandlerTab();
12811 // Make sure that the predecessor lists are accurate
12812 if (expensiveDebugCheckLevel >= 2)
12814 fgDebugCheckBBlist();
12823 fgVerifyHandlerTab();
12825 if (verbose && result)
12827 printf("\nAfter fgRelocateEHRegions()");
12828 fgDispBasicBlocks();
12829 fgDispHandlerTab();
12830 // Make sure that the predecessor lists are accurate
12831 fgDebugCheckBBlist();
12838 #endif // !FEATURE_EH_FUNCLETS
12840 bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12842 bool result = false;
12843 if ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin))
12845 flEdgeWeightMin = newWeight;
12850 // We allow for a small amount of inaccuracy in block weight counts.
12851 if (flEdgeWeightMax < newWeight)
12853 // We have already determined that this edge's weight
12854 // is less than newWeight, so we just allow for the slop
12855 if (newWeight <= (flEdgeWeightMax + slop))
12859 if (flEdgeWeightMax != 0)
12861 // We will raise flEdgeWeightMin and Max towards newWeight
12862 flEdgeWeightMin = flEdgeWeightMax;
12863 flEdgeWeightMax = newWeight;
12866 if (wbUsedSlop != nullptr)
12868 *wbUsedSlop = true;
12874 assert(flEdgeWeightMin > newWeight);
12876 // We have already determined that this edge's weight
12877 // is more than newWeight, so we just allow for the slop
12878 if ((newWeight + slop) >= flEdgeWeightMin)
12882 assert(flEdgeWeightMax != 0);
12884 // We will lower flEdgeWeightMin towards newWeight
12885 flEdgeWeightMin = newWeight;
12887 if (wbUsedSlop != nullptr)
12889 *wbUsedSlop = true;
12894 // If we are returning true then we should have adjusted the range so that
12895 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero.
12896 // Also we should have set wbUsedSlop to true.
12897 if (result == true)
12899 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12901 if (wbUsedSlop != nullptr)
12903 assert(*wbUsedSlop == true);
12909 if (result == false)
12911 result = false; // break here
12918 bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop)
12920 bool result = false;
12921 if ((newWeight >= flEdgeWeightMin) && (newWeight <= flEdgeWeightMax))
12923 flEdgeWeightMax = newWeight;
12928 // We allow for a small amount of inaccuracy in block weight counts.
12929 if (flEdgeWeightMax < newWeight)
12931 // We have already determined that this edge's weight
12932 // is less than newWeight, so we just allow for the slop
12933 if (newWeight <= (flEdgeWeightMax + slop))
12937 if (flEdgeWeightMax != 0)
12939 // We will allow this to raise flEdgeWeightMax towards newWeight
12940 flEdgeWeightMax = newWeight;
12943 if (wbUsedSlop != nullptr)
12945 *wbUsedSlop = true;
12951 assert(flEdgeWeightMin > newWeight);
12953 // We have already determined that this edge's weight
12954 // is more than newWeight, so we just allow for the slop
12955 if ((newWeight + slop) >= flEdgeWeightMin)
12959 assert(flEdgeWeightMax != 0);
12961 // We will allow this to lower flEdgeWeightMin and Max towards newWeight
12962 flEdgeWeightMax = flEdgeWeightMin;
12963 flEdgeWeightMin = newWeight;
12965 if (wbUsedSlop != nullptr)
12967 *wbUsedSlop = true;
12972 // If we are returning true then we should have adjusted the range so that
12973 // the newWeight is in new range [Min..Max] or fgEdjeWeightMax is zero
12974 // Also we should have set wbUsedSlop to true, unless it is NULL
12975 if (result == true)
12977 assert((flEdgeWeightMax == 0) || ((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
12979 assert((wbUsedSlop == nullptr) || (*wbUsedSlop == true));
12984 if (result == false)
12986 result = false; // break here
12994 void Compiler::fgPrintEdgeWeights()
13000 // Print out all of the edge weights
13001 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13003 if (bDst->bbPreds != nullptr)
13005 printf(" Edge weights into BB%02u :", bDst->bbNum);
13006 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13008 bSrc = edge->flBlock;
13009 // This is the control flow edge (bSrc -> bDst)
13011 printf("BB%02u ", bSrc->bbNum);
13013 if (edge->flEdgeWeightMin < BB_MAX_WEIGHT)
13015 printf("(%u", edge->flEdgeWeightMin);
13021 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
13023 if (edge->flEdgeWeightMax < BB_MAX_WEIGHT)
13025 printf("..%u", edge->flEdgeWeightMax);
13033 if (edge->flNext != nullptr)
13044 // return true if there is a possibility that the method has a loop (a backedge is present)
13045 bool Compiler::fgMightHaveLoop()
13047 // Don't use a BlockSet for this temporary bitset of blocks: we don't want to have to call EnsureBasicBlockEpoch()
13048 // and potentially change the block epoch.
13050 BitVecTraits blockVecTraits(fgBBNumMax + 1, this);
13051 BitVec blocksSeen(BitVecOps::MakeEmpty(&blockVecTraits));
13053 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
13055 BitVecOps::AddElemD(&blockVecTraits, blocksSeen, block->bbNum);
13057 for (BasicBlock* succ : block->GetAllSuccs(this))
13059 if (BitVecOps::IsMember(&blockVecTraits, blocksSeen, succ->bbNum))
13068 void Compiler::fgComputeEdgeWeights()
13073 printf("*************** In fgComputeEdgeWeights()\n");
13077 if (fgIsUsingProfileWeights() == false)
13082 printf("fgComputeEdgeWeights() we do not have any profile data so we are not using the edge weights\n");
13085 fgHaveValidEdgeWeights = false;
13086 fgCalledCount = BB_UNITY_WEIGHT;
13092 fgDispBasicBlocks();
13100 unsigned iterations = 0;
13101 unsigned goodEdgeCountCurrent = 0;
13102 unsigned goodEdgeCountPrevious = 0;
13103 bool inconsistentProfileData = false;
13104 bool hasIncompleteEdgeWeights = false;
13105 unsigned numEdges = 0;
13106 bool usedSlop = false;
13110 BasicBlock::weight_t returnWeight;
13111 BasicBlock::weight_t slop;
13113 // If we have any blocks that did not have profile derived weight
13114 // we will try to fix their weight up here
13117 do // while (changed)
13123 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13125 if (!bDst->hasProfileWeight() && (bDst->bbPreds != nullptr))
13127 BasicBlock* bOnlyNext;
13129 // This block does not have a profile derived weight
13131 BasicBlock::weight_t newWeight = BB_MAX_WEIGHT;
13133 if (bDst->countOfInEdges() == 1)
13135 // Only one block flows into bDst
13136 bSrc = bDst->bbPreds->flBlock;
13138 // Does this block flow into only one other block
13139 if (bSrc->bbJumpKind == BBJ_NONE)
13141 bOnlyNext = bSrc->bbNext;
13143 else if (bSrc->bbJumpKind == BBJ_ALWAYS)
13145 bOnlyNext = bSrc->bbJumpDest;
13149 bOnlyNext = nullptr;
13152 if ((bOnlyNext == bDst) && bSrc->hasProfileWeight())
13154 // We know the exact weight of bDst
13155 newWeight = bSrc->bbWeight;
13159 // Does this block flow into only one other block
13160 if (bDst->bbJumpKind == BBJ_NONE)
13162 bOnlyNext = bDst->bbNext;
13164 else if (bDst->bbJumpKind == BBJ_ALWAYS)
13166 bOnlyNext = bDst->bbJumpDest;
13170 bOnlyNext = nullptr;
13173 if ((bOnlyNext != nullptr) && (bOnlyNext->bbPreds != nullptr))
13175 // Does only one block flow into bOnlyNext
13176 if (bOnlyNext->countOfInEdges() == 1)
13178 noway_assert(bOnlyNext->bbPreds->flBlock == bDst);
13180 // We know the exact weight of bDst
13181 newWeight = bOnlyNext->bbWeight;
13185 if ((newWeight != BB_MAX_WEIGHT) && (bDst->bbWeight != newWeight))
13189 bDst->bbWeight = newWeight;
13190 if (newWeight == 0)
13192 bDst->bbFlags |= BBF_RUN_RARELY;
13196 bDst->bbFlags &= ~BBF_RUN_RARELY;
13201 // Sum up the weights of all of the return blocks and throw blocks
13202 // This is used when we have a back-edge into block 1
13204 if (bDst->hasProfileWeight() && ((bDst->bbJumpKind == BBJ_RETURN) || (bDst->bbJumpKind == BBJ_THROW)))
13206 returnWeight += bDst->bbWeight;
13210 // Generally when we synthesize profile estimates we do it in a way where this algorithm will converge
13211 // but downstream opts that remove conditional branches may create a situation where this is not the case.
13212 // For instance a loop that becomes unreachable creates a sort of 'ring oscillator' (See test b539509)
13213 while (changed && iterations < 10);
13216 if (verbose && modified)
13218 printf("fgComputeEdgeWeights() adjusted the weight of some blocks\n");
13219 fgDispBasicBlocks();
13224 // When we are not using profile data we have already setup fgCalledCount
13225 // only set it here if we are using profile data
13227 if (fgIsUsingProfileWeights())
13229 BasicBlock* firstILBlock = fgFirstBB; // The first block for IL code (i.e. for the IL code at offset 0)
13231 // Do we have an internal block as our first Block?
13232 if (firstILBlock->bbFlags & BBF_INTERNAL)
13234 // Skip past any/all BBF_INTERNAL blocks that may have been added before the first real IL block.
13236 while (firstILBlock->bbFlags & BBF_INTERNAL)
13238 firstILBlock = firstILBlock->bbNext;
13240 // The 'firstILBlock' is now expected to have a profile-derived weight
13241 assert(firstILBlock->hasProfileWeight());
13244 // If the first block only has one ref then we use it's weight for fgCalledCount.
13245 // Otherwise we have backedge's into the first block, so instead we use the sum
13246 // of the return block weights for fgCalledCount.
13248 // If the profile data has a 0 for the returnWeight
13249 // (i.e. the function never returns because it always throws)
13250 // then just use the first block weight rather than 0.
13252 if ((firstILBlock->countOfInEdges() == 1) || (returnWeight == 0))
13254 assert(firstILBlock->hasProfileWeight()); // This should always be a profile-derived weight
13255 fgCalledCount = firstILBlock->bbWeight;
13259 fgCalledCount = returnWeight;
13262 // If we allocated a scratch block as the first BB then we need
13263 // to set its profile-derived weight to be fgCalledCount
13264 if (fgFirstBBisScratch())
13266 fgFirstBB->setBBProfileWeight(fgCalledCount);
13267 if (fgFirstBB->bbWeight == 0)
13269 fgFirstBB->bbFlags |= BBF_RUN_RARELY;
13276 printf("We are using the Profile Weights and fgCalledCount is %d.\n", fgCalledCount);
13281 // Now we will compute the initial flEdgeWeightMin and flEdgeWeightMax values
13282 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13284 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
13286 // We subtract out the called count so that bDstWeight is
13287 // the sum of all edges that go into this block from this method.
13289 if (bDst == fgFirstBB)
13291 bDstWeight -= fgCalledCount;
13294 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13296 bool assignOK = true;
13298 bSrc = edge->flBlock;
13299 // We are processing the control flow edge (bSrc -> bDst)
13304 // If the bSrc or bDst blocks do not have exact profile weights
13305 // then we must reset any values that they currently have
13308 if (!bSrc->hasProfileWeight() || !bDst->hasProfileWeight())
13310 edge->flEdgeWeightMin = BB_ZERO_WEIGHT;
13311 edge->flEdgeWeightMax = BB_MAX_WEIGHT;
13314 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
13315 switch (bSrc->bbJumpKind)
13318 case BBJ_EHCATCHRET:
13320 case BBJ_CALLFINALLY:
13321 // We know the exact edge weight
13322 assignOK &= edge->setEdgeWeightMinChecked(bSrc->bbWeight, slop, &usedSlop);
13323 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
13328 case BBJ_EHFINALLYRET:
13329 case BBJ_EHFILTERRET:
13330 if (edge->flEdgeWeightMax > bSrc->bbWeight)
13332 // The maximum edge weight to block can't be greater than the weight of bSrc
13333 assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop);
13338 // We should never have an edge that starts from one of these jump kinds
13339 noway_assert(!"Unexpected bbJumpKind");
13343 // The maximum edge weight to block can't be greater than the weight of bDst
13344 if (edge->flEdgeWeightMax > bDstWeight)
13346 assignOK &= edge->setEdgeWeightMaxChecked(bDstWeight, slop, &usedSlop);
13351 // Here we have inconsistent profile data
13352 inconsistentProfileData = true;
13353 // No point in continuing
13359 fgEdgeCount = numEdges;
13366 goodEdgeCountPrevious = goodEdgeCountCurrent;
13367 goodEdgeCountCurrent = 0;
13368 hasIncompleteEdgeWeights = false;
13370 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13372 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13374 bool assignOK = true;
13376 // We are processing the control flow edge (bSrc -> bDst)
13377 bSrc = edge->flBlock;
13379 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
13380 if (bSrc->bbJumpKind == BBJ_COND)
13383 flowList* otherEdge;
13384 if (bSrc->bbNext == bDst)
13386 otherEdge = fgGetPredForBlock(bSrc->bbJumpDest, bSrc);
13390 otherEdge = fgGetPredForBlock(bSrc->bbNext, bSrc);
13392 noway_assert(edge->flEdgeWeightMin <= edge->flEdgeWeightMax);
13393 noway_assert(otherEdge->flEdgeWeightMin <= otherEdge->flEdgeWeightMax);
13395 // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down
13396 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
13399 assignOK &= edge->setEdgeWeightMinChecked(edge->flEdgeWeightMin + diff, slop, &usedSlop);
13404 otherEdge->setEdgeWeightMaxChecked(otherEdge->flEdgeWeightMax + diff, slop, &usedSlop);
13407 // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down
13408 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
13412 otherEdge->setEdgeWeightMinChecked(otherEdge->flEdgeWeightMin + diff, slop, &usedSlop);
13416 assignOK &= edge->setEdgeWeightMaxChecked(edge->flEdgeWeightMax + diff, slop, &usedSlop);
13421 // Here we have inconsistent profile data
13422 inconsistentProfileData = true;
13423 // No point in continuing
13427 // Now edge->flEdgeWeightMin and otherEdge->flEdgeWeightMax) should add up to bSrc->bbWeight
13428 diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax);
13429 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
13431 // Now otherEdge->flEdgeWeightMin and edge->flEdgeWeightMax) should add up to bSrc->bbWeight
13432 diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax);
13433 noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop)));
13439 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13441 BasicBlock::weight_t bDstWeight = bDst->bbWeight;
13443 if (bDstWeight == BB_MAX_WEIGHT)
13445 inconsistentProfileData = true;
13446 // No point in continuing
13451 // We subtract out the called count so that bDstWeight is
13452 // the sum of all edges that go into this block from this method.
13454 if (bDst == fgFirstBB)
13456 bDstWeight -= fgCalledCount;
13459 UINT64 minEdgeWeightSum = 0;
13460 UINT64 maxEdgeWeightSum = 0;
13462 // Calculate the sums of the minimum and maximum edge weights
13463 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13465 // We are processing the control flow edge (bSrc -> bDst)
13466 bSrc = edge->flBlock;
13468 maxEdgeWeightSum += edge->flEdgeWeightMax;
13469 minEdgeWeightSum += edge->flEdgeWeightMin;
13472 // maxEdgeWeightSum is the sum of all flEdgeWeightMax values into bDst
13473 // minEdgeWeightSum is the sum of all flEdgeWeightMin values into bDst
13475 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13477 bool assignOK = true;
13479 // We are processing the control flow edge (bSrc -> bDst)
13480 bSrc = edge->flBlock;
13481 slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
13483 // otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values
13484 // This can be used to compute a lower bound for our minimum edge weight
13485 noway_assert(maxEdgeWeightSum >= edge->flEdgeWeightMax);
13486 UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->flEdgeWeightMax;
13488 // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values
13489 // This can be used to compute an upper bound for our maximum edge weight
13490 noway_assert(minEdgeWeightSum >= edge->flEdgeWeightMin);
13491 UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->flEdgeWeightMin;
13493 if (bDstWeight >= otherMaxEdgesWeightSum)
13495 // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax value
13496 BasicBlock::weight_t minWeightCalc =
13497 (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum);
13498 if (minWeightCalc > edge->flEdgeWeightMin)
13500 assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, slop, &usedSlop);
13504 if (bDstWeight >= otherMinEdgesWeightSum)
13506 // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin value
13507 BasicBlock::weight_t maxWeightCalc =
13508 (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum);
13509 if (maxWeightCalc < edge->flEdgeWeightMax)
13511 assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, slop, &usedSlop);
13517 // Here we have inconsistent profile data
13518 inconsistentProfileData = true;
13519 // No point in continuing
13523 // When flEdgeWeightMin equals flEdgeWeightMax we have a "good" edge weight
13524 if (edge->flEdgeWeightMin == edge->flEdgeWeightMax)
13526 // Count how many "good" edge weights we have
13527 // Each time through we should have more "good" weights
13528 // We exit the while loop when no longer find any new "good" edges
13529 goodEdgeCountCurrent++;
13533 // Remember that we have seen at least one "Bad" edge weight
13534 // so that we will repeat the while loop again
13535 hasIncompleteEdgeWeights = true;
13541 if (inconsistentProfileData)
13543 hasIncompleteEdgeWeights = true;
13547 if (numEdges == goodEdgeCountCurrent)
13549 noway_assert(hasIncompleteEdgeWeights == false);
13553 } while (hasIncompleteEdgeWeights && (goodEdgeCountCurrent > goodEdgeCountPrevious) && (iterations < 8));
13560 if (inconsistentProfileData)
13562 printf("fgComputeEdgeWeights() found inconsistent profile data, not using the edge weights\n");
13566 if (hasIncompleteEdgeWeights)
13568 printf("fgComputeEdgeWeights() was able to compute exact edge weights for %3d of the %3d edges, using "
13570 goodEdgeCountCurrent, numEdges, iterations);
13574 printf("fgComputeEdgeWeights() was able to compute exact edge weights for all of the %3d edges, using "
13576 numEdges, iterations);
13579 fgPrintEdgeWeights();
13584 fgSlopUsedInEdgeWeights = usedSlop;
13585 fgRangeUsedInEdgeWeights = false;
13587 // See if any edge weight are expressed in [min..max] form
13589 for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)
13591 if (bDst->bbPreds != nullptr)
13593 for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
13595 bSrc = edge->flBlock;
13596 // This is the control flow edge (bSrc -> bDst)
13598 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
13600 fgRangeUsedInEdgeWeights = true;
13604 if (fgRangeUsedInEdgeWeights)
13611 fgHaveValidEdgeWeights = !inconsistentProfileData;
13612 fgEdgeWeightsComputed = true;
13615 // fgOptimizeBranchToEmptyUnconditional:
13616 // optimize a jump to an empty block which ends in an unconditional branch.
13618 // block: source block
13619 // bDest: destination
13620 // Returns: true if we changed the code
13622 bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest)
13624 bool optimizeJump = true;
13626 assert(bDest->isEmpty());
13627 assert(bDest->bbJumpKind == BBJ_ALWAYS);
13629 // We do not optimize jumps between two different try regions.
13630 // However jumping to a block that is not in any try region is OK
13632 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
13634 optimizeJump = false;
13637 // Don't optimize a jump to a removed block
13638 if (bDest->bbJumpDest->bbFlags & BBF_REMOVED)
13640 optimizeJump = false;
13643 // Don't optimize a jump to a cloned finally
13644 if (bDest->bbFlags & BBF_CLONED_FINALLY_BEGIN)
13646 optimizeJump = false;
13649 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13650 // Don't optimize a jump to a finally target. For BB1->BB2->BB3, where
13651 // BB2 is a finally target, if we changed BB1 to jump directly to BB3,
13652 // it would skip the finally target. BB1 might be a BBJ_ALWAYS block part
13653 // of a BBJ_CALLFINALLY/BBJ_ALWAYS pair, so changing the finally target
13654 // would change the unwind behavior.
13655 if (bDest->bbFlags & BBF_FINALLY_TARGET)
13657 optimizeJump = false;
13659 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13661 // Must optimize jump if bDest has been removed
13663 if (bDest->bbFlags & BBF_REMOVED)
13665 optimizeJump = true;
13668 // If we are optimizing using real profile weights
13669 // then don't optimize a conditional jump to an unconditional jump
13670 // until after we have computed the edge weights
13672 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
13674 fgNeedsUpdateFlowGraph = true;
13675 optimizeJump = false;
13683 printf("\nOptimizing a jump to an unconditional jump (BB%02u -> BB%02u -> BB%02u)\n", block->bbNum,
13684 bDest->bbNum, bDest->bbJumpDest->bbNum);
13689 // When we optimize a branch to branch we need to update the profile weight
13690 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
13692 if (fgHaveValidEdgeWeights && bDest->hasProfileWeight())
13694 flowList* edge1 = fgGetPredForBlock(bDest, block);
13695 noway_assert(edge1 != nullptr);
13697 BasicBlock::weight_t edgeWeight;
13699 if (edge1->flEdgeWeightMin != edge1->flEdgeWeightMax)
13702 // We only have an estimate for the edge weight
13704 edgeWeight = (edge1->flEdgeWeightMin + edge1->flEdgeWeightMax) / 2;
13706 // Clear the profile weight flag
13708 bDest->bbFlags &= ~BBF_PROF_WEIGHT;
13713 // We only have the exact edge weight
13715 edgeWeight = edge1->flEdgeWeightMin;
13719 // Update the bDest->bbWeight
13721 if (bDest->bbWeight > edgeWeight)
13723 bDest->bbWeight -= edgeWeight;
13727 bDest->bbWeight = BB_ZERO_WEIGHT;
13728 bDest->bbFlags |= BBF_RUN_RARELY; // Set the RarelyRun flag
13731 flowList* edge2 = fgGetPredForBlock(bDest->bbJumpDest, bDest);
13733 if (edge2 != nullptr)
13736 // Update the edge2 min/max weights
13738 if (edge2->flEdgeWeightMin > edge1->flEdgeWeightMin)
13740 edge2->flEdgeWeightMin -= edge1->flEdgeWeightMin;
13744 edge2->flEdgeWeightMin = BB_ZERO_WEIGHT;
13747 if (edge2->flEdgeWeightMax > edge1->flEdgeWeightMin)
13749 edge2->flEdgeWeightMax -= edge1->flEdgeWeightMin;
13753 edge2->flEdgeWeightMax = BB_ZERO_WEIGHT;
13758 // Optimize the JUMP to empty unconditional JUMP to go to the new target
13759 block->bbJumpDest = bDest->bbJumpDest;
13761 fgAddRefPred(bDest->bbJumpDest, block, fgRemoveRefPred(bDest, block));
13768 // fgOptimizeEmptyBlock:
13769 // Does flow optimization of an empty block (can remove it in some cases)
13772 // block: an empty block
13773 // Returns: true if we changed the code
13775 bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block)
13777 assert(block->isEmpty());
13779 BasicBlock* bPrev = block->bbPrev;
13781 switch (block->bbJumpKind)
13787 /* can never happen */
13788 noway_assert(!"Conditional, switch, or throw block with empty body!");
13791 case BBJ_CALLFINALLY:
13793 case BBJ_EHCATCHRET:
13794 case BBJ_EHFINALLYRET:
13795 case BBJ_EHFILTERRET:
13797 /* leave them as is */
13798 /* some compilers generate multiple returns and put all of them at the end -
13799 * to solve that we need the predecessor list */
13805 // A GOTO cannot be to the next block since that
13806 // should have been fixed by the optimization above
13807 // An exception is made for a jump from Hot to Cold
13808 noway_assert(block->bbJumpDest != block->bbNext || ((bPrev != nullptr) && bPrev->isBBCallAlwaysPair()) ||
13809 fgInDifferentRegions(block, block->bbNext));
13811 /* Cannot remove the first BB */
13817 /* Do not remove a block that jumps to itself - used for while (true){} */
13818 if (block->bbJumpDest == block)
13823 /* Empty GOTO can be removed iff bPrev is BBJ_NONE */
13824 if (bPrev->bbJumpKind != BBJ_NONE)
13829 // can't allow fall through into cold code
13830 if (block->bbNext == fgFirstColdBlock)
13835 /* Can fall through since this is similar with removing
13836 * a BBJ_NONE block, only the successor is different */
13842 /* special case if this is the first BB */
13845 assert(block == fgFirstBB);
13849 /* If this block follows a BBJ_CALLFINALLY do not remove it
13850 * (because we don't know who may jump to it) */
13851 if (bPrev->bbJumpKind == BBJ_CALLFINALLY)
13857 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13858 /* Don't remove finally targets */
13859 if (block->bbFlags & BBF_FINALLY_TARGET)
13861 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
13863 #if FEATURE_EH_FUNCLETS
13864 /* Don't remove an empty block that is in a different EH region
13865 * from its successor block, if the block is the target of a
13866 * catch return. It is required that the return address of a
13867 * catch be in the correct EH region, for re-raise of thread
13868 * abort exceptions to work. Insert a NOP in the empty block
13869 * to ensure we generate code for the block, if we keep it.
13872 BasicBlock* succBlock;
13874 if (block->bbJumpKind == BBJ_ALWAYS)
13876 succBlock = block->bbJumpDest;
13880 succBlock = block->bbNext;
13883 if ((succBlock != nullptr) && !BasicBlock::sameEHRegion(block, succBlock))
13885 // The empty block and the block that follows it are in different
13886 // EH regions. Is this a case where they can't be merged?
13888 bool okToMerge = true; // assume it's ok
13889 for (flowList* pred = block->bbPreds; pred; pred = pred->flNext)
13891 if (pred->flBlock->bbJumpKind == BBJ_EHCATCHRET)
13893 assert(pred->flBlock->bbJumpDest == block);
13894 okToMerge = false; // we can't get rid of the empty block
13901 // Insert a NOP in the empty block to ensure we generate code
13902 // for the catchret target in the right EH region.
13903 GenTree* nop = new (this, GT_NO_OP) GenTree(GT_NO_OP, TYP_VOID);
13905 if (block->IsLIR())
13907 LIR::AsRange(block).InsertAtEnd(nop);
13908 #ifndef LEGACY_BACKEND
13909 LIR::ReadOnlyRange range(nop, nop);
13910 m_pLowering->LowerRange(block, range);
13915 GenTree* nopStmt = fgInsertStmtAtEnd(block, nop);
13916 fgSetStmtSeq(nopStmt);
13917 gtSetStmtInfo(nopStmt);
13923 printf("\nKeeping empty block BB%02u - it is the target of a catch return\n", block->bbNum);
13927 break; // go to the next block
13931 #endif // FEATURE_EH_FUNCLETS
13933 if (!ehCanDeleteEmptyBlock(block))
13935 // We're not allowed to remove this block due to reasons related to the EH table.
13939 /* special case if this is the last BB */
13940 if (block == fgLastBB)
13949 // When using profile weights, fgComputeEdgeWeights expects the first non-internal block to have profile
13951 // Make sure we don't break that invariant.
13952 if (fgIsUsingProfileWeights() && block->hasProfileWeight() && (block->bbFlags & BBF_INTERNAL) == 0)
13954 BasicBlock* bNext = block->bbNext;
13956 // Check if the next block can't maintain the invariant.
13957 if ((bNext == nullptr) || ((bNext->bbFlags & BBF_INTERNAL) != 0) || !bNext->hasProfileWeight())
13959 // Check if the current block is the first non-internal block.
13960 BasicBlock* curBB = bPrev;
13961 while ((curBB != nullptr) && (curBB->bbFlags & BBF_INTERNAL) != 0)
13963 curBB = curBB->bbPrev;
13965 if (curBB == nullptr)
13967 // This block is the first non-internal block and it has profile weight.
13968 // Don't delete it.
13974 /* Remove the block */
13976 fgRemoveBlock(block, false);
13980 noway_assert(!"Unexpected bbJumpKind");
13986 // fgOptimizeSwitchBranches:
13987 // Does flow optimization for a switch - bypasses jumps to empty unconditional branches,
13988 // and transforms degenerate switch cases like those with 1 or 2 targets
13991 // block: BasicBlock that contains the switch
13992 // Returns: true if we changed the code
13994 bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
13996 assert(block->bbJumpKind == BBJ_SWITCH);
13998 unsigned jmpCnt = block->bbJumpSwt->bbsCount;
13999 BasicBlock** jmpTab = block->bbJumpSwt->bbsDstTab;
14000 BasicBlock* bNewDest; // the new jump target for the current switch case
14002 bool returnvalue = false;
14010 // Do we have a JUMP to an empty unconditional JUMP block?
14011 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
14012 (bDest != bDest->bbJumpDest)) // special case for self jumps
14014 bool optimizeJump = true;
14016 // We do not optimize jumps between two different try regions.
14017 // However jumping to a block that is not in any try region is OK
14019 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
14021 optimizeJump = false;
14024 // If we are optimize using real profile weights
14025 // then don't optimize a switch jump to an unconditional jump
14026 // until after we have computed the edge weights
14028 if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed)
14030 fgNeedsUpdateFlowGraph = true;
14031 optimizeJump = false;
14036 bNewDest = bDest->bbJumpDest;
14040 printf("\nOptimizing a switch jump to an empty block with an unconditional jump (BB%02u -> BB%02u "
14042 block->bbNum, bDest->bbNum, bNewDest->bbNum);
14048 if (bNewDest != bDest)
14051 // When we optimize a branch to branch we need to update the profile weight
14052 // of bDest by subtracting out the block/edge weight of the path that is being optimized.
14054 if (fgIsUsingProfileWeights() && bDest->hasProfileWeight())
14056 if (fgHaveValidEdgeWeights)
14058 flowList* edge = fgGetPredForBlock(bDest, block);
14059 BasicBlock::weight_t branchThroughWeight = edge->flEdgeWeightMin;
14061 if (bDest->bbWeight > branchThroughWeight)
14063 bDest->bbWeight -= branchThroughWeight;
14067 bDest->bbWeight = BB_ZERO_WEIGHT;
14068 bDest->bbFlags |= BBF_RUN_RARELY;
14073 // Update the switch jump table
14074 *jmpTab = bNewDest;
14076 // Maintain, if necessary, the set of unique targets of "block."
14077 UpdateSwitchTableTarget(block, bDest, bNewDest);
14079 fgAddRefPred(bNewDest, block, fgRemoveRefPred(bDest, block));
14081 // we optimized a Switch label - goto REPEAT_SWITCH to follow this new jump
14082 returnvalue = true;
14084 goto REPEAT_SWITCH;
14086 } while (++jmpTab, --jmpCnt);
14088 GenTreeStmt* switchStmt = nullptr;
14089 LIR::Range* blockRange = nullptr;
14091 GenTree* switchTree;
14092 if (block->IsLIR())
14094 blockRange = &LIR::AsRange(block);
14095 switchTree = blockRange->LastNode();
14097 assert(switchTree->OperGet() == GT_SWITCH_TABLE);
14101 switchStmt = block->lastStmt();
14102 switchTree = switchStmt->gtStmtExpr;
14104 assert(switchTree->OperGet() == GT_SWITCH);
14107 noway_assert(switchTree->gtType == TYP_VOID);
14109 // At this point all of the case jump targets have been updated such
14110 // that none of them go to block that is an empty unconditional block
14112 jmpTab = block->bbJumpSwt->bbsDstTab;
14113 jmpCnt = block->bbJumpSwt->bbsCount;
14114 // Now check for two trivial switch jumps.
14116 if (block->NumSucc(this) == 1)
14118 // Use BBJ_ALWAYS for a switch with only a default clause, or with only one unique successor.
14119 BasicBlock* uniqueSucc = jmpTab[0];
14124 printf("\nRemoving a switch jump with a single target (BB%02u)\n", block->bbNum);
14125 printf("BEFORE:\n");
14129 if (block->IsLIR())
14132 unsigned sideEffects;
14133 LIR::ReadOnlyRange switchTreeRange = blockRange->GetTreeRange(switchTree, &isClosed, &sideEffects);
14135 // The switch tree should form a contiguous, side-effect free range by construction. See
14136 // Lowering::LowerSwitch for details.
14138 assert((sideEffects & GTF_ALL_EFFECT) == 0);
14140 blockRange->Delete(this, block, std::move(switchTreeRange));
14144 /* check for SIDE_EFFECTS */
14145 if (switchTree->gtFlags & GTF_SIDE_EFFECT)
14147 /* Extract the side effects from the conditional */
14148 GenTree* sideEffList = nullptr;
14150 gtExtractSideEffList(switchTree, &sideEffList);
14152 if (sideEffList == nullptr)
14154 goto NO_SWITCH_SIDE_EFFECT;
14157 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
14162 printf("\nSwitch expression has side effects! Extracting side effects...\n");
14163 gtDispTree(switchTree);
14165 gtDispTree(sideEffList);
14170 /* Replace the conditional statement with the list of side effects */
14171 noway_assert(sideEffList->gtOper != GT_STMT);
14172 noway_assert(sideEffList->gtOper != GT_SWITCH);
14174 switchStmt->gtStmtExpr = sideEffList;
14176 if (fgStmtListThreaded)
14178 /* Update the lclvar ref counts */
14180 fgUpdateRefCntForExtract(switchTree, sideEffList);
14182 /* Update ordering, costs, FP levels, etc. */
14183 gtSetStmtInfo(switchStmt);
14185 /* Re-link the nodes for this statement */
14186 fgSetStmtSeq(switchStmt);
14192 NO_SWITCH_SIDE_EFFECT:
14194 /* conditional has NO side effect - remove it */
14195 fgRemoveStmt(block, switchStmt);
14199 // Change the switch jump into a BBJ_ALWAYS
14200 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
14201 block->bbJumpKind = BBJ_ALWAYS;
14204 for (unsigned i = 1; i < jmpCnt; ++i)
14206 (void)fgRemoveRefPred(jmpTab[i], block);
14212 else if (block->bbJumpSwt->bbsCount == 2 && block->bbJumpSwt->bbsDstTab[1] == block->bbNext)
14214 /* Use a BBJ_COND(switchVal==0) for a switch with only one
14215 significant clause besides the default clause, if the
14216 default clause is bbNext */
14217 GenTree* switchVal = switchTree->gtOp.gtOp1;
14218 noway_assert(genActualTypeIsIntOrI(switchVal->TypeGet()));
14220 #ifndef LEGACY_BACKEND
14221 // If we are in LIR, remove the jump table from the block.
14222 if (block->IsLIR())
14224 GenTree* jumpTable = switchTree->gtOp.gtOp2;
14225 assert(jumpTable->OperGet() == GT_JMPTABLE);
14226 blockRange->Remove(jumpTable);
14230 // Change the GT_SWITCH(switchVal) into GT_JTRUE(GT_EQ(switchVal==0)).
14231 // Also mark the node as GTF_DONT_CSE as further down JIT is not capable of handling it.
14232 // For example CSE could determine that the expression rooted at GT_EQ is a candidate cse and
14233 // replace it with a COMMA node. In such a case we will end up with GT_JTRUE node pointing to
14234 // a COMMA node which results in noway asserts in fgMorphSmpOp(), optAssertionGen() and rpPredictTreeRegUse().
14235 // For the same reason fgMorphSmpOp() marks GT_JTRUE nodes with RELOP children as GTF_DONT_CSE.
14236 CLANG_FORMAT_COMMENT_ANCHOR;
14241 printf("\nConverting a switch (BB%02u) with only one significant clause besides a default target to a "
14242 "conditional branch\n",
14247 switchTree->ChangeOper(GT_JTRUE);
14248 GenTree* zeroConstNode = gtNewZeroConNode(genActualType(switchVal->TypeGet()));
14249 GenTree* condNode = gtNewOperNode(GT_EQ, TYP_INT, switchVal, zeroConstNode);
14250 switchTree->gtOp.gtOp1 = condNode;
14251 switchTree->gtOp.gtOp1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
14253 if (block->IsLIR())
14255 blockRange->InsertAfter(switchVal, zeroConstNode, condNode);
14256 #ifndef LEGACY_BACKEND
14257 LIR::ReadOnlyRange range(zeroConstNode, switchTree);
14258 m_pLowering->LowerRange(block, range);
14259 #endif // !LEGACY_BACKEND
14263 // Re-link the nodes for this statement.
14264 fgSetStmtSeq(switchStmt);
14267 block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0];
14268 block->bbJumpKind = BBJ_COND;
14272 return returnvalue;
14275 // fgBlockEndFavorsTailDuplication:
14276 // Heuristic function that returns true if this block ends in a statement that looks favorable
14277 // for tail-duplicating its successor (such as assigning a constant to a local).
14279 // block: BasicBlock we are considering duplicating the successor of
14281 // true if it seems like a good idea
14283 bool Compiler::fgBlockEndFavorsTailDuplication(BasicBlock* block)
14285 if (block->isRunRarely())
14290 if (!block->lastStmt())
14296 // Tail duplication tends to pay off when the last statement
14297 // is an assignment of a constant, arraylength, or a relop.
14298 // This is because these statements produce information about values
14299 // that would otherwise be lost at the upcoming merge point.
14301 GenTreeStmt* lastStmt = block->lastStmt();
14302 GenTree* tree = lastStmt->gtStmtExpr;
14303 if (tree->gtOper != GT_ASG)
14308 if (tree->OperIsBlkOp())
14313 GenTree* op2 = tree->gtOp.gtOp2;
14314 if (op2->gtOper != GT_ARR_LENGTH && !op2->OperIsConst() && ((op2->OperKind() & GTK_RELOP) == 0))
14322 // fgBlockIsGoodTailDuplicationCandidate:
14323 // Heuristic function that examines a block (presumably one that is a merge point) to determine
14324 // if it should be duplicated.
14326 // target - the tail block (candidate for duplication)
14328 // true if this block seems like a good candidate for duplication
14330 bool Compiler::fgBlockIsGoodTailDuplicationCandidate(BasicBlock* target)
14332 GenTreeStmt* stmt = target->FirstNonPhiDef();
14334 // Here we are looking for blocks with a single statement feeding a conditional branch.
14335 // These blocks are small, and when duplicated onto the tail of blocks that end in
14336 // assignments, there is a high probability of the branch completely going away.
14338 // This is by no means the only kind of tail that it is beneficial to duplicate,
14339 // just the only one we recognize for now.
14341 if (stmt != target->lastStmt())
14346 if (target->bbJumpKind != BBJ_COND)
14351 GenTree* tree = stmt->gtStmtExpr;
14353 if (tree->gtOper != GT_JTRUE)
14358 // must be some kind of relational operator
14359 GenTree* cond = tree->gtOp.gtOp1;
14360 if (!(cond->OperKind() & GTK_RELOP))
14365 // op1 must be some combinations of casts of local or constant
14366 GenTree* op1 = cond->gtOp.gtOp1;
14367 while (op1->gtOper == GT_CAST)
14369 op1 = op1->gtOp.gtOp1;
14371 if (!op1->IsLocal() && !op1->OperIsConst())
14376 // op2 must be some combinations of casts of local or constant
14377 GenTree* op2 = cond->gtOp.gtOp2;
14378 while (op2->gtOper == GT_CAST)
14380 op2 = op2->gtOp.gtOp1;
14382 if (!op2->IsLocal() && !op2->OperIsConst())
14390 // fgOptimizeUncondBranchToSimpleCond:
14391 // For a block which has an unconditional branch, look to see if its target block
14392 // is a good candidate for tail duplication, and if so do that duplication.
14395 // block - block with uncond branch
14396 // target - block which is target of first block
14398 // returns: true if changes were made
14400 bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target)
14402 assert(block->bbJumpKind == BBJ_ALWAYS);
14403 assert(block->bbJumpDest == target);
14405 // TODO-Review: OK if they are in the same region?
14406 if (compHndBBtabCount > 0)
14411 if (!fgBlockIsGoodTailDuplicationCandidate(target))
14416 if (!fgBlockEndFavorsTailDuplication(block))
14421 // NOTE: we do not currently hit this assert because this function is only called when
14422 // `fgUpdateFlowGraph` has been called with `doTailDuplication` set to true, and the
14423 // backend always calls `fgUpdateFlowGraph` with `doTailDuplication` set to false.
14424 assert(!block->IsLIR());
14426 GenTreeStmt* stmt = target->FirstNonPhiDef();
14427 assert(stmt == target->lastStmt());
14429 // Duplicate the target block at the end of this block
14431 GenTree* cloned = gtCloneExpr(stmt->gtStmtExpr);
14432 noway_assert(cloned);
14433 GenTree* jmpStmt = gtNewStmt(cloned);
14435 block->bbJumpKind = BBJ_COND;
14436 block->bbJumpDest = target->bbJumpDest;
14437 fgAddRefPred(block->bbJumpDest, block);
14438 fgRemoveRefPred(target, block);
14440 // add an unconditional block after this block to jump to the target block's fallthrough block
14442 BasicBlock* next = fgNewBBafter(BBJ_ALWAYS, block, true);
14444 // The new block 'next' will inherit its weight from 'block'
14445 next->inheritWeight(block);
14446 next->bbJumpDest = target->bbNext;
14447 target->bbNext->bbFlags |= BBF_JMP_TARGET;
14448 fgAddRefPred(next, block);
14449 fgAddRefPred(next->bbJumpDest, next);
14454 printf("fgOptimizeUncondBranchToSimpleCond(from BB%02u to cond BB%02u), created new uncond BB%02u\n",
14455 block->bbNum, target->bbNum, next->bbNum);
14459 if (fgStmtListThreaded)
14461 gtSetStmtInfo(jmpStmt);
14464 fgInsertStmtAtEnd(block, jmpStmt);
14469 // fgOptimizeBranchToNext:
14470 // Optimize a block which has a branch to the following block
14472 // block - block with a branch
14473 // bNext - block which is both next and the target of the first block
14474 // bPrev - block which is prior to the first block
14476 // returns: true if changes were made
14478 bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev)
14480 assert(block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS);
14481 assert(block->bbJumpDest == bNext);
14482 assert(block->bbNext == bNext);
14483 assert(block->bbPrev == bPrev);
14485 if (block->bbJumpKind == BBJ_ALWAYS)
14487 // We can't remove it if it is a branch from hot => cold
14488 if (!fgInDifferentRegions(block, bNext))
14490 // We can't remove if it is marked as BBF_KEEP_BBJ_ALWAYS
14491 if (!(block->bbFlags & BBF_KEEP_BBJ_ALWAYS))
14493 // We can't remove if the BBJ_ALWAYS is part of a BBJ_CALLFINALLY pair
14494 if ((bPrev == nullptr) || !bPrev->isBBCallAlwaysPair())
14496 /* the unconditional jump is to the next BB */
14497 block->bbJumpKind = BBJ_NONE;
14498 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14502 printf("\nRemoving unconditional jump to next block (BB%02u -> BB%02u) (converted BB%02u to "
14504 block->bbNum, bNext->bbNum, block->bbNum);
14514 /* remove the conditional statement at the end of block */
14515 noway_assert(block->bbJumpKind == BBJ_COND);
14516 noway_assert(block->bbTreeList);
14521 printf("\nRemoving conditional jump to next block (BB%02u -> BB%02u)\n", block->bbNum, bNext->bbNum);
14525 if (block->IsLIR())
14527 LIR::Range& blockRange = LIR::AsRange(block);
14528 GenTree* jmp = blockRange.LastNode();
14529 assert(jmp->OperIsConditionalJump());
14530 if (jmp->OperGet() == GT_JTRUE)
14532 jmp->gtOp.gtOp1->gtFlags &= ~GTF_SET_FLAGS;
14536 unsigned sideEffects;
14537 LIR::ReadOnlyRange jmpRange = blockRange.GetTreeRange(jmp, &isClosed, &sideEffects);
14539 // TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
14540 // diffs compared to the existing backend.
14541 if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
14543 // If the jump and its operands form a contiguous, side-effect-free range,
14545 blockRange.Delete(this, block, std::move(jmpRange));
14549 // Otherwise, just remove the jump node itself.
14550 blockRange.Remove(jmp, true);
14555 GenTreeStmt* cond = block->lastStmt();
14556 noway_assert(cond->gtStmtExpr->gtOper == GT_JTRUE);
14558 /* check for SIDE_EFFECTS */
14559 if (cond->gtStmtExpr->gtFlags & GTF_SIDE_EFFECT)
14561 /* Extract the side effects from the conditional */
14562 GenTree* sideEffList = nullptr;
14564 gtExtractSideEffList(cond->gtStmtExpr, &sideEffList);
14566 if (sideEffList == nullptr)
14569 fgRemoveStmt(block, cond);
14573 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
14577 printf("\nConditional has side effects! Extracting side effects...\n");
14580 gtDispTree(sideEffList);
14585 /* Replace the conditional statement with the list of side effects */
14586 noway_assert(sideEffList->gtOper != GT_STMT);
14587 noway_assert(sideEffList->gtOper != GT_JTRUE);
14589 cond->gtStmtExpr = sideEffList;
14591 if (fgStmtListThreaded)
14593 /* Update the lclvar ref counts */
14595 fgUpdateRefCntForExtract(cond->gtStmtExpr, sideEffList);
14597 /* Update ordering, costs, FP levels, etc. */
14598 gtSetStmtInfo(cond);
14600 /* Re-link the nodes for this statement */
14601 fgSetStmtSeq(cond);
14608 /* conditional has NO side effect - remove it */
14609 fgRemoveStmt(block, cond);
14613 /* Conditional is gone - simply fall into the next block */
14615 block->bbJumpKind = BBJ_NONE;
14616 block->bbFlags &= ~BBF_NEEDS_GCPOLL;
14618 /* Update bbRefs and bbNum - Conditional predecessors to the same
14619 * block are counted twice so we have to remove one of them */
14621 noway_assert(bNext->countOfInEdges() > 1);
14622 fgRemoveRefPred(bNext, block);
14629 /*****************************************************************************
14631 * Function called to optimize an unconditional branch that branches
14632 * to a conditional branch.
14633 * Currently we require that the conditional branch jump back to the
14634 * block that follows the unconditional branch.
14636 * We can improve the code execution and layout by concatenating a copy
14637 * of the conditional branch block at the end of the conditional branch
14638 * and reversing the sense of the branch.
14640 * This is only done when the amount of code to be copied is smaller than
14641 * our calculated threshold in maxDupCostSz.
14645 bool Compiler::fgOptimizeBranch(BasicBlock* bJump)
14647 if (opts.MinOpts())
14652 if (bJump->bbJumpKind != BBJ_ALWAYS)
14657 if (bJump->bbFlags & BBF_KEEP_BBJ_ALWAYS)
14662 // Don't hoist a conditional branch into the scratch block; we'd prefer it stay
14663 // either BBJ_NONE or BBJ_ALWAYS.
14664 if (fgBBisScratch(bJump))
14669 BasicBlock* bDest = bJump->bbJumpDest;
14671 if (bDest->bbJumpKind != BBJ_COND)
14676 if (bDest->bbJumpDest != bJump->bbNext)
14681 // 'bJump' must be in the same try region as the condition, since we're going to insert
14682 // a duplicated condition in 'bJump', and the condition might include exception throwing code.
14683 if (!BasicBlock::sameTryRegion(bJump, bDest))
14688 // do not jump into another try region
14689 BasicBlock* bDestNext = bDest->bbNext;
14690 if (bDestNext->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNext))
14695 // This function is only called by fgReorderBlocks, which we do not run in the backend.
14696 // If we wanted to run block reordering in the backend, we would need to be able to
14697 // calculate cost information for LIR on a per-node basis in order for this function
14699 assert(!bJump->IsLIR());
14700 assert(!bDest->IsLIR());
14703 unsigned estDupCostSz = 0;
14704 for (stmt = bDest->firstStmt(); stmt; stmt = stmt->gtNextStmt)
14706 GenTree* expr = stmt->gtStmtExpr;
14708 /* We call gtPrepareCost to measure the cost of duplicating this tree */
14709 gtPrepareCost(expr);
14711 estDupCostSz += expr->gtCostSz;
14714 bool allProfileWeightsAreValid = false;
14715 BasicBlock::weight_t weightJump = bJump->bbWeight;
14716 BasicBlock::weight_t weightDest = bDest->bbWeight;
14717 BasicBlock::weight_t weightNext = bJump->bbNext->bbWeight;
14718 bool rareJump = bJump->isRunRarely();
14719 bool rareDest = bDest->isRunRarely();
14720 bool rareNext = bJump->bbNext->isRunRarely();
14722 // If we have profile data then we calculate the number of time
14723 // the loop will iterate into loopIterations
14724 if (fgIsUsingProfileWeights())
14726 // Only rely upon the profile weight when all three of these blocks
14727 // have either good profile weights or are rarelyRun
14729 if ((bJump->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
14730 (bDest->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)) &&
14731 (bJump->bbNext->bbFlags & (BBF_PROF_WEIGHT | BBF_RUN_RARELY)))
14733 allProfileWeightsAreValid = true;
14735 if ((weightJump * 100) < weightDest)
14740 if ((weightNext * 100) < weightDest)
14745 if (((weightDest * 100) < weightJump) && ((weightDest * 100) < weightNext))
14752 unsigned maxDupCostSz = 6;
14755 // Branches between the hot and rarely run regions
14756 // should be minimized. So we allow a larger size
14758 if (rareDest != rareJump)
14763 if (rareDest != rareNext)
14769 // We we are ngen-ing:
14770 // If the uncondional branch is a rarely run block then
14771 // we are willing to have more code expansion since we
14772 // won't be running code from this page
14774 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
14782 // If the compare has too high cost then we don't want to dup
14784 bool costIsTooHigh = (estDupCostSz > maxDupCostSz);
14789 printf("\nDuplication of the conditional block BB%02u (always branch from BB%02u) %s, because the cost of "
14790 "duplication (%i) is %s than %i,"
14791 " validProfileWeights = %s\n",
14792 bDest->bbNum, bJump->bbNum, costIsTooHigh ? "not done" : "performed", estDupCostSz,
14793 costIsTooHigh ? "greater" : "less or equal", maxDupCostSz, allProfileWeightsAreValid ? "true" : "false");
14802 /* Looks good - duplicate the conditional block */
14804 GenTree* newStmtList = nullptr; // new stmt list to be added to bJump
14805 GenTree* newStmtLast = nullptr;
14806 bool cloneExprFailed = false;
14808 /* Visit all the statements in bDest */
14810 for (GenTree* curStmt = bDest->bbTreeList; curStmt; curStmt = curStmt->gtNext)
14812 /* Clone/substitute the expression */
14814 stmt = gtCloneExpr(curStmt)->AsStmt();
14816 // cloneExpr doesn't handle everything
14818 if (stmt == nullptr)
14820 cloneExprFailed = true;
14824 /* Append the expression to our list */
14826 if (newStmtList != nullptr)
14828 newStmtLast->gtNext = stmt;
14832 newStmtList = stmt;
14835 stmt->gtPrev = newStmtLast;
14836 newStmtLast = stmt;
14839 if (cloneExprFailed)
14844 noway_assert(newStmtLast != nullptr);
14845 noway_assert(stmt != nullptr);
14846 noway_assert(stmt->gtOper == GT_STMT);
14848 if ((newStmtLast == nullptr) || (stmt == nullptr) || (stmt->gtOper != GT_STMT))
14853 /* Get to the condition node from the statement tree */
14855 GenTree* condTree = stmt->gtStmtExpr;
14856 noway_assert(condTree->gtOper == GT_JTRUE);
14858 if (condTree->gtOper != GT_JTRUE)
14864 // Set condTree to the operand to the GT_JTRUE
14866 condTree = condTree->gtOp.gtOp1;
14869 // This condTree has to be a RelOp comparison
14871 if (condTree->OperIsCompare() == false)
14876 // Bump up the ref-counts of any variables in 'stmt'
14877 fgUpdateRefCntForClone(bJump, stmt->gtStmtExpr);
14880 // Find the last statement in the bJump block
14882 GenTreeStmt* lastStmt = nullptr;
14883 for (stmt = bJump->firstStmt(); stmt; stmt = stmt->gtNextStmt)
14887 stmt = bJump->firstStmt();
14889 /* Join the two linked lists */
14890 newStmtLast->gtNext = nullptr;
14892 if (lastStmt != nullptr)
14894 stmt->gtPrev = newStmtLast;
14895 lastStmt->gtNext = newStmtList;
14896 newStmtList->gtPrev = lastStmt;
14900 bJump->bbTreeList = newStmtList;
14901 newStmtList->gtPrev = newStmtLast;
14905 // Reverse the sense of the compare
14907 gtReverseCond(condTree);
14909 // We need to update the following flags of the bJump block if they were set in the bDest block
14911 (bDest->bbFlags & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY | BBF_HAS_NULLCHECK | BBF_HAS_IDX_LEN | BBF_HAS_VTABREF));
14913 bJump->bbJumpKind = BBJ_COND;
14914 bJump->bbJumpDest = bDest->bbNext;
14916 /* Mark the jump dest block as being a jump target */
14917 bJump->bbJumpDest->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
14919 /* Update bbRefs and bbPreds */
14921 // bJump now falls through into the next block
14923 fgAddRefPred(bJump->bbNext, bJump);
14925 // bJump no longer jumps to bDest
14927 fgRemoveRefPred(bDest, bJump);
14929 // bJump now jumps to bDest->bbNext
14931 fgAddRefPred(bDest->bbNext, bJump);
14933 if (weightJump > 0)
14935 if (allProfileWeightsAreValid)
14937 if (weightDest > weightJump)
14939 bDest->bbWeight = (weightDest - weightJump);
14941 else if (!bDest->isRunRarely())
14943 bDest->bbWeight = BB_UNITY_WEIGHT;
14948 BasicBlock::weight_t newWeightDest = 0;
14949 BasicBlock::weight_t unloopWeightDest = 0;
14951 if (weightDest > weightJump)
14953 newWeightDest = (weightDest - weightJump);
14955 if (weightDest >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2)
14957 newWeightDest = (weightDest * 2) / (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT);
14959 if ((newWeightDest > 0) || (unloopWeightDest > 0))
14961 bDest->bbWeight = Max(newWeightDest, unloopWeightDest);
14969 // Dump out the newStmtList that we created
14970 printf("\nfgOptimizeBranch added these statements(s) at the end of BB%02u:\n", bJump->bbNum);
14971 for (stmt = newStmtList->AsStmt(); stmt; stmt = stmt->gtNextStmt)
14975 printf("\nfgOptimizeBranch changed block BB%02u from BBJ_ALWAYS to BBJ_COND.\n", bJump->bbNum);
14977 printf("\nAfter this change in fgOptimizeBranch the BB graph is:");
14978 fgDispBasicBlocks(verboseTrees);
14986 /*****************************************************************************
14988 * Function called to optimize switch statements
14991 bool Compiler::fgOptimizeSwitchJumps()
14993 bool result = false; // Our return value
14996 // TODO-CQ: Add switch jump optimizations?
15000 if (!fgHaveValidEdgeWeights)
15003 for (BasicBlock* bSrc = fgFirstBB; bSrc != NULL; bSrc = bSrc->bbNext)
15005 if (bSrc->bbJumpKind == BBJ_SWITCH)
15007 unsigned jumpCnt; jumpCnt = bSrc->bbJumpSwt->bbsCount;
15008 BasicBlock** jumpTab; jumpTab = bSrc->bbJumpSwt->bbsDstTab;
15012 BasicBlock* bDst = *jumpTab;
15013 flowList* edgeToDst = fgGetPredForBlock(bDst, bSrc);
15014 double outRatio = (double) edgeToDst->flEdgeWeightMin / (double) bSrc->bbWeight;
15016 if (outRatio >= 0.60)
15018 // straighten switch here...
15021 while (++jumpTab, --jumpCnt);
15030 #pragma warning(push)
15031 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
15033 /*****************************************************************************
15035 * Function called to reorder the flowgraph of BasicBlocks such that any
15036 * rarely run blocks are placed at the end of the block list.
15037 * If we have profile information we also use that information to reverse
15038 * all conditional jumps that would benefit.
15041 void Compiler::fgReorderBlocks()
15043 noway_assert(opts.compDbgCode == false);
15045 #if FEATURE_EH_FUNCLETS
15046 assert(fgFuncletsCreated);
15047 #endif // FEATURE_EH_FUNCLETS
15049 // We can't relocate anything if we only have one block
15050 if (fgFirstBB->bbNext == nullptr)
15055 bool newRarelyRun = false;
15056 bool movedBlocks = false;
15057 bool optimizedSwitches = false;
15059 // First let us expand the set of run rarely blocks
15060 newRarelyRun |= fgExpandRarelyRunBlocks();
15062 #if !FEATURE_EH_FUNCLETS
15063 movedBlocks |= fgRelocateEHRegions();
15064 #endif // !FEATURE_EH_FUNCLETS
15067 // If we are using profile weights we can change some
15068 // switch jumps into conditional test and jump
15070 if (fgIsUsingProfileWeights())
15073 // Note that this is currently not yet implemented
15075 optimizedSwitches = fgOptimizeSwitchJumps();
15076 if (optimizedSwitches)
15078 fgUpdateFlowGraph();
15085 printf("*************** In fgReorderBlocks()\n");
15087 printf("\nInitial BasicBlocks");
15088 fgDispBasicBlocks(verboseTrees);
15099 // Iterate over every block, remembering our previous block in bPrev
15100 for (bPrev = fgFirstBB, block = bPrev->bbNext; block != nullptr; bPrev = block, block = block->bbNext)
15103 // Consider relocating the rarely run blocks such that they are at the end of the method.
15104 // We also consider reversing conditional branches so that they become a not taken forwards branch.
15107 // If block is marked with a BBF_KEEP_BBJ_ALWAYS flag then we don't move the block
15108 if ((block->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)
15113 // Finally and handlers blocks are to be kept contiguous.
15114 // TODO-CQ: Allow reordering within the handler region
15115 if (block->hasHndIndex() == true)
15120 bool reorderBlock = true; // This is set to false if we decide not to reorder 'block'
15121 bool isRare = block->isRunRarely();
15122 BasicBlock* bDest = nullptr;
15123 bool forwardBranch = false;
15124 bool backwardBranch = false;
15127 if ((bPrev->bbJumpKind == BBJ_COND) || (bPrev->bbJumpKind == BBJ_ALWAYS))
15129 bDest = bPrev->bbJumpDest;
15130 forwardBranch = fgIsForwardBranch(bPrev);
15131 backwardBranch = !forwardBranch;
15134 // We will look for bPrev as a non rarely run block followed by block as a rarely run block
15136 if (bPrev->isRunRarely())
15138 reorderBlock = false;
15141 // If the weights of the bPrev, block and bDest were all obtained from a profile run
15142 // then we can use them to decide if it is useful to reverse this conditional branch
15144 BasicBlock::weight_t profHotWeight = -1;
15146 if (bPrev->hasProfileWeight() && block->hasProfileWeight() && ((bDest == nullptr) || bDest->hasProfileWeight()))
15149 // All blocks have profile information
15153 if (bPrev->bbJumpKind == BBJ_ALWAYS)
15155 // We can pull up the blocks that the unconditional jump branches to
15156 // if the weight of bDest is greater or equal to the weight of block
15157 // also the weight of bDest can't be zero.
15159 if ((bDest->bbWeight < block->bbWeight) || (bDest->bbWeight == 0))
15161 reorderBlock = false;
15166 // If this remains true then we will try to pull up bDest to succeed bPrev
15168 bool moveDestUp = true;
15170 if (fgHaveValidEdgeWeights)
15173 // The edge bPrev -> bDest must have a higher minimum weight
15174 // than every other edge into bDest
15176 flowList* edgeFromPrev = fgGetPredForBlock(bDest, bPrev);
15177 noway_assert(edgeFromPrev != nullptr);
15179 // Examine all of the other edges into bDest
15180 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
15182 if (edge != edgeFromPrev)
15184 if (edge->flEdgeWeightMax >= edgeFromPrev->flEdgeWeightMin)
15186 moveDestUp = false;
15195 // The block bPrev must have a higher weight
15196 // than every other block that goes into bDest
15199 // Examine all of the other edges into bDest
15200 for (flowList* edge = bDest->bbPreds; edge != nullptr; edge = edge->flNext)
15202 BasicBlock* bTemp = edge->flBlock;
15204 if ((bTemp != bPrev) && (bTemp->bbWeight >= bPrev->bbWeight))
15206 moveDestUp = false;
15212 // Are we still good to move bDest up to bPrev?
15216 // We will consider all blocks that have less weight than profHotWeight to be
15217 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
15219 profHotWeight = bDest->bbWeight - 1;
15223 if (block->isRunRarely())
15225 // We will move any rarely run blocks blocks
15230 // We will move all blocks that have a weight less or equal to our fall through block
15231 profHotWeight = block->bbWeight + 1;
15233 // But we won't try to connect with bDest
15238 else // (bPrev->bbJumpKind == BBJ_COND)
15240 noway_assert(bPrev->bbJumpKind == BBJ_COND);
15242 // We will reverse branch if the taken-jump to bDest ratio (i.e. 'takenRatio')
15243 // is more than 51%
15245 // We will setup profHotWeight to be maximum bbWeight that a block
15246 // could have for us not to want to reverse the conditional branch
15248 // We will consider all blocks that have less weight than profHotWeight to be
15249 // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
15251 if (fgHaveValidEdgeWeights)
15253 // We have valid edge weights, however even with valid edge weights
15254 // we may have a minimum and maximum range for each edges value
15256 // We will check that the min weight of the bPrev to bDest edge
15257 // is more than twice the max weight of the bPrev to block edge.
15259 // bPrev --> [BB04, weight 31]
15261 // edgeToBlock -------------> O \
15262 // [min=8,max=10] V \
15263 // block --> [BB05, weight 10] \
15265 // edgeToDest ----------------------------> O
15266 // [min=21,max=23] |
15268 // bDest ---------------> [BB08, weight 21]
15270 flowList* edgeToDest = fgGetPredForBlock(bDest, bPrev);
15271 flowList* edgeToBlock = fgGetPredForBlock(block, bPrev);
15272 noway_assert(edgeToDest != nullptr);
15273 noway_assert(edgeToBlock != nullptr);
15275 // Calculate the taken ratio
15276 // A takenRation of 0.10 means taken 10% of the time, not taken 90% of the time
15277 // A takenRation of 0.50 means taken 50% of the time, not taken 50% of the time
15278 // A takenRation of 0.90 means taken 90% of the time, not taken 10% of the time
15280 double takenCount =
15281 ((double)edgeToDest->flEdgeWeightMin + (double)edgeToDest->flEdgeWeightMax) / 2.0;
15282 double notTakenCount =
15283 ((double)edgeToBlock->flEdgeWeightMin + (double)edgeToBlock->flEdgeWeightMax) / 2.0;
15284 double totalCount = takenCount + notTakenCount;
15285 double takenRatio = takenCount / totalCount;
15287 // If the takenRatio is greater or equal to 51% then we will reverse the branch
15288 if (takenRatio < 0.51)
15290 reorderBlock = false;
15294 // set profHotWeight
15295 profHotWeight = (edgeToBlock->flEdgeWeightMin + edgeToBlock->flEdgeWeightMax) / 2 - 1;
15300 // We don't have valid edge weight so we will be more conservative
15301 // We could have bPrev, block or bDest as part of a loop and thus have extra weight
15303 // We will do two checks:
15304 // 1. Check that the weight of bDest is at least two times more than block
15305 // 2. Check that the weight of bPrev is at least three times more than block
15307 // bPrev --> [BB04, weight 31]
15310 // block --> [BB05, weight 10] \
15314 // bDest ---------------> [BB08, weight 21]
15316 // For this case weightDest is calculated as (21+1)/2 or 11
15317 // and weightPrev is calculated as (31+2)/3 also 11
15319 // Generally both weightDest and weightPrev should calculate
15320 // the same value unless bPrev or bDest are part of a loop
15322 BasicBlock::weight_t weightDest =
15323 bDest->isMaxBBWeight() ? bDest->bbWeight : (bDest->bbWeight + 1) / 2;
15324 BasicBlock::weight_t weightPrev =
15325 bPrev->isMaxBBWeight() ? bPrev->bbWeight : (bPrev->bbWeight + 2) / 3;
15327 // select the lower of weightDest and weightPrev
15328 profHotWeight = (weightDest < weightPrev) ? weightDest : weightPrev;
15330 // if the weight of block is greater (or equal) to profHotWeight then we don't reverse the cond
15331 if (block->bbWeight >= profHotWeight)
15333 reorderBlock = false;
15338 else // not a forwardBranch
15340 if (bPrev->bbFallsThrough())
15342 goto CHECK_FOR_RARE;
15345 // Here we should pull up the highest weight block remaining
15346 // and place it here since bPrev does not fall through.
15348 BasicBlock::weight_t highestWeight = 0;
15349 BasicBlock* candidateBlock = nullptr;
15350 BasicBlock* lastNonFallThroughBlock = bPrev;
15351 BasicBlock* bTmp = bPrev->bbNext;
15353 while (bTmp != nullptr)
15355 // Don't try to split a Call/Always pair
15357 if (bTmp->isBBCallAlwaysPair())
15359 // Move bTmp forward
15360 bTmp = bTmp->bbNext;
15364 // Check for loop exit condition
15366 if (bTmp == nullptr)
15372 // if its weight is the highest one we've seen and
15373 // the EH regions allow for us to place bTmp after bPrev
15375 if ((bTmp->bbWeight > highestWeight) && fgEhAllowsMoveBlock(bPrev, bTmp))
15377 // When we have a current candidateBlock that is a conditional (or unconditional) jump
15378 // to bTmp (which is a higher weighted block) then it is better to keep out current
15379 // candidateBlock and have it fall into bTmp
15381 if ((candidateBlock == nullptr) ||
15382 ((candidateBlock->bbJumpKind != BBJ_COND) && (candidateBlock->bbJumpKind != BBJ_ALWAYS)) ||
15383 (candidateBlock->bbJumpDest != bTmp))
15385 // otherwise we have a new candidateBlock
15387 highestWeight = bTmp->bbWeight;
15388 candidateBlock = lastNonFallThroughBlock->bbNext;
15392 if ((bTmp->bbFallsThrough() == false) || (bTmp->bbWeight == 0))
15394 lastNonFallThroughBlock = bTmp;
15397 bTmp = bTmp->bbNext;
15400 // If we didn't find a suitable block then skip this
15401 if (highestWeight == 0)
15403 reorderBlock = false;
15407 noway_assert(candidateBlock != nullptr);
15409 // If the candidateBlock is the same a block then skip this
15410 if (candidateBlock == block)
15412 reorderBlock = false;
15416 // Set bDest to the block that we want to come after bPrev
15417 bDest = candidateBlock;
15419 // set profHotWeight
15420 profHotWeight = highestWeight - 1;
15425 else // we don't have good profile info (or we are falling through)
15430 /* We only want to reorder when we have a rarely run */
15431 /* block right after a normal block, */
15432 /* (bPrev is known to be a normal block at this point) */
15435 if ((bDest == block->bbNext) && (block->bbJumpKind == BBJ_RETURN) && (bPrev->bbJumpKind == BBJ_ALWAYS))
15437 // This is a common case with expressions like "return Expr1 && Expr2" -- move the return
15438 // to establish fall-through.
15442 reorderBlock = false;
15447 /* If the jump target bDest is also a rarely run block then we don't want to do the reversal */
15448 if (bDest && bDest->isRunRarely())
15450 reorderBlock = false; /* Both block and bDest are rarely run */
15454 // We will move any rarely run blocks blocks
15460 if (reorderBlock == false)
15463 // Check for an unconditional branch to a conditional branch
15464 // which also branches back to our next block
15466 if (fgOptimizeBranch(bPrev))
15468 noway_assert(bPrev->bbJumpKind == BBJ_COND);
15473 // Now we need to determine which blocks should be moved
15475 // We consider one of two choices:
15477 // 1. Moving the fall-through blocks (or rarely run blocks) down to
15478 // later in the method and hopefully connecting the jump dest block
15479 // so that it becomes the fall through block
15481 // And when bDest in not NULL, we also consider:
15483 // 2. Moving the bDest block (or blocks) up to bPrev
15484 // so that it could be used as a fall through block
15486 // We will prefer option #1 if we are able to connect the jump dest
15487 // block as the fall though block otherwise will we try to use option #2
15491 // Consider option #1: relocating blocks starting at 'block'
15492 // to later in flowgraph
15494 // We set bStart to the first block that will be relocated
15495 // and bEnd to the last block that will be relocated
15497 BasicBlock* bStart = block;
15498 BasicBlock* bEnd = bStart;
15499 bNext = bEnd->bbNext;
15500 bool connected_bDest = false;
15502 if ((backwardBranch && !isRare) ||
15503 ((block->bbFlags & BBF_DONT_REMOVE) != 0)) // Don't choose option #1 when block is the start of a try region
15512 // Don't try to split a Call/Always pair
15514 if (bEnd->isBBCallAlwaysPair())
15516 // Move bEnd and bNext forward
15518 bNext = bNext->bbNext;
15522 // Check for loop exit condition
15524 if (bNext == nullptr)
15529 #if FEATURE_EH_FUNCLETS
15530 // Check if we've reached the funclets region, at the end of the function
15531 if (fgFirstFuncletBB == bEnd->bbNext)
15535 #endif // FEATURE_EH_FUNCLETS
15537 if (bNext == bDest)
15539 connected_bDest = true;
15543 // All the blocks must have the same try index
15544 // and must not have the BBF_DONT_REMOVE flag set
15546 if (!BasicBlock::sameTryRegion(bStart, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
15548 // exit the loop, bEnd is now set to the
15549 // last block that we want to relocate
15553 // If we are relocating rarely run blocks..
15556 // ... then all blocks must be rarely run
15557 if (!bNext->isRunRarely())
15559 // exit the loop, bEnd is now set to the
15560 // last block that we want to relocate
15566 // If we are moving blocks that are hot then all
15567 // of the blocks moved must be less than profHotWeight */
15568 if (bNext->bbWeight >= profHotWeight)
15570 // exit the loop, bEnd is now set to the
15571 // last block that we would relocate
15576 // Move bEnd and bNext forward
15578 bNext = bNext->bbNext;
15581 // Set connected_bDest to true if moving blocks [bStart .. bEnd]
15582 // connects with the the jump dest of bPrev (i.e bDest) and
15583 // thus allows bPrev fall through instead of jump.
15584 if (bNext == bDest)
15586 connected_bDest = true;
15590 // Now consider option #2: Moving the jump dest block (or blocks)
15593 // The variables bStart2, bEnd2 and bPrev2 are used for option #2
15595 // We will setup bStart2 to the first block that will be relocated
15596 // and bEnd2 to the last block that will be relocated
15597 // and bPrev2 to be the lexical pred of bDest
15599 // If after this calculation bStart2 is NULL we cannot use option #2,
15600 // otherwise bStart2, bEnd2 and bPrev2 are all non-NULL and we will use option #2
15602 BasicBlock* bStart2 = nullptr;
15603 BasicBlock* bEnd2 = nullptr;
15604 BasicBlock* bPrev2 = nullptr;
15606 // If option #1 didn't connect bDest and bDest isn't NULL
15607 if ((connected_bDest == false) && (bDest != nullptr) &&
15608 // The jump target cannot be moved if it has the BBF_DONT_REMOVE flag set
15609 ((bDest->bbFlags & BBF_DONT_REMOVE) == 0))
15611 // We will consider option #2: relocating blocks starting at 'bDest' to succeed bPrev
15613 // setup bPrev2 to be the lexical pred of bDest
15616 while (bPrev2 != nullptr)
15618 if (bPrev2->bbNext == bDest)
15623 bPrev2 = bPrev2->bbNext;
15626 if ((bPrev2 != nullptr) && fgEhAllowsMoveBlock(bPrev, bDest))
15628 // We have decided that relocating bDest to be after bPrev is best
15629 // Set bStart2 to the first block that will be relocated
15630 // and bEnd2 to the last block that will be relocated
15632 // Assigning to bStart2 selects option #2
15636 bNext = bEnd2->bbNext;
15640 // Don't try to split a Call/Always pair
15642 if (bEnd2->isBBCallAlwaysPair())
15644 noway_assert(bNext->bbJumpKind == BBJ_ALWAYS);
15645 // Move bEnd2 and bNext forward
15647 bNext = bNext->bbNext;
15650 // Check for the Loop exit conditions
15652 if (bNext == nullptr)
15657 if (bEnd2->bbFallsThrough() == false)
15662 // If we are relocating rarely run blocks..
15663 // All the blocks must have the same try index,
15664 // and must not have the BBF_DONT_REMOVE flag set
15666 if (!BasicBlock::sameTryRegion(bStart2, bNext) || ((bNext->bbFlags & BBF_DONT_REMOVE) != 0))
15668 // exit the loop, bEnd2 is now set to the
15669 // last block that we want to relocate
15675 /* ... then all blocks must not be rarely run */
15676 if (bNext->isRunRarely())
15678 // exit the loop, bEnd2 is now set to the
15679 // last block that we want to relocate
15685 // If we are relocating hot blocks
15686 // all blocks moved must be greater than profHotWeight
15687 if (bNext->bbWeight <= profHotWeight)
15689 // exit the loop, bEnd2 is now set to the
15690 // last block that we want to relocate
15695 // Move bEnd2 and bNext forward
15697 bNext = bNext->bbNext;
15702 // If we are using option #1 then ...
15703 if (bStart2 == nullptr)
15705 // Don't use option #1 for a backwards branch
15706 if (bStart == nullptr)
15711 // .... Don't move a set of blocks that are already at the end of the main method
15712 if (bEnd == fgLastBBInMainFunction())
15721 if (bDest != nullptr)
15723 if (bPrev->bbJumpKind == BBJ_COND)
15725 printf("Decided to reverse conditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
15728 else if (bPrev->bbJumpKind == BBJ_ALWAYS)
15730 printf("Decided to straighten unconditional branch at block BB%02u branch to BB%02u ", bPrev->bbNum,
15735 printf("Decided to place hot code after BB%02u, placed BB%02u after this block ", bPrev->bbNum,
15739 if (profHotWeight > 0)
15741 printf("because of IBC profile data\n");
15745 if (bPrev->bbFallsThrough())
15747 printf("since it falls into a rarely run block\n");
15751 printf("since it is succeeded by a rarely run block\n");
15757 printf("Decided to relocate block(s) after block BB%02u since they are %s block(s)\n", bPrev->bbNum,
15758 block->isRunRarely() ? "rarely run" : "uncommonly run");
15763 // We will set insertAfterBlk to the block the precedes our insertion range
15764 // We will set bStartPrev to be the block that precedes the set of blocks that we are moving
15765 BasicBlock* insertAfterBlk;
15766 BasicBlock* bStartPrev;
15768 if (bStart2 != nullptr)
15770 // Option #2: relocating blocks starting at 'bDest' to follow bPrev
15772 // Update bStart and bEnd so that we can use these two for all later operations
15776 // Set bStartPrev to be the block that comes before bStart
15777 bStartPrev = bPrev2;
15779 // We will move [bStart..bEnd] to immediately after bPrev
15780 insertAfterBlk = bPrev;
15784 // option #1: Moving the fall-through blocks (or rarely run blocks) down to later in the method
15786 // Set bStartPrev to be the block that come before bStart
15787 bStartPrev = bPrev;
15789 // We will move [bStart..bEnd] but we will pick the insert location later
15790 insertAfterBlk = nullptr;
15793 // We are going to move [bStart..bEnd] so they can't be NULL
15794 noway_assert(bStart != nullptr);
15795 noway_assert(bEnd != nullptr);
15797 // bEnd can't be a BBJ_CALLFINALLY unless it is a RETLESS call
15798 noway_assert((bEnd->bbJumpKind != BBJ_CALLFINALLY) || (bEnd->bbFlags & BBF_RETLESS_CALL));
15800 // bStartPrev must be set to the block that precedes bStart
15801 noway_assert(bStartPrev->bbNext == bStart);
15803 // Since we will be unlinking [bStart..bEnd],
15804 // we need to compute and remember if bStart is in each of
15805 // the try and handler regions
15807 bool* fStartIsInTry = nullptr;
15808 bool* fStartIsInHnd = nullptr;
15810 if (compHndBBtabCount > 0)
15812 fStartIsInTry = new (this, CMK_Unknown) bool[compHndBBtabCount];
15813 fStartIsInHnd = new (this, CMK_Unknown) bool[compHndBBtabCount];
15815 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
15817 fStartIsInTry[XTnum] = HBtab->InTryRegionBBRange(bStart);
15818 fStartIsInHnd[XTnum] = HBtab->InHndRegionBBRange(bStart);
15822 /* Temporarily unlink [bStart..bEnd] from the flow graph */
15823 fgUnlinkRange(bStart, bEnd);
15825 if (insertAfterBlk == nullptr)
15827 // Find new location for the unlinked block(s)
15828 // Set insertAfterBlk to the block which will precede the insertion point
15830 if (!bStart->hasTryIndex() && isRare)
15832 // We'll just insert the blocks at the end of the method. If the method
15833 // has funclets, we will insert at the end of the main method but before
15834 // any of the funclets. Note that we create funclets before we call
15835 // fgReorderBlocks().
15837 insertAfterBlk = fgLastBBInMainFunction();
15838 noway_assert(insertAfterBlk != bPrev);
15842 BasicBlock* startBlk;
15843 BasicBlock* lastBlk;
15844 EHblkDsc* ehDsc = ehInitTryBlockRange(bStart, &startBlk, &lastBlk);
15846 BasicBlock* endBlk;
15848 /* Setup startBlk and endBlk as the range to search */
15850 if (ehDsc != nullptr)
15852 endBlk = lastBlk->bbNext;
15855 Multiple (nested) try regions might start from the same BB.
15859 |--- |--- |--- BB01
15863 | |------------ BB05
15865 |------------------- BB07
15867 Now if we want to insert in try2 region, we will start with startBlk=BB01.
15868 The following loop will allow us to start from startBlk==BB04.
15870 while (!BasicBlock::sameTryRegion(startBlk, bStart) && (startBlk != endBlk))
15872 startBlk = startBlk->bbNext;
15875 // startBlk cannot equal endBlk as it must come before endBlk
15876 if (startBlk == endBlk)
15881 // we also can't start searching the try region at bStart
15882 if (startBlk == bStart)
15884 // if bEnd is the last block in the method or
15885 // or if bEnd->bbNext is in a different try region
15886 // then we cannot move the blocks
15888 if ((bEnd->bbNext == nullptr) || !BasicBlock::sameTryRegion(startBlk, bEnd->bbNext))
15893 startBlk = bEnd->bbNext;
15895 // Check that the new startBlk still comes before endBlk
15897 // startBlk cannot equal endBlk as it must come before endBlk
15898 if (startBlk == endBlk)
15903 BasicBlock* tmpBlk = startBlk;
15904 while ((tmpBlk != endBlk) && (tmpBlk != nullptr))
15906 tmpBlk = tmpBlk->bbNext;
15909 // when tmpBlk is NULL that means startBlk is after endBlk
15910 // so there is no way to move bStart..bEnd within the try region
15911 if (tmpBlk == nullptr)
15919 noway_assert(isRare == false);
15921 /* We'll search through the entire main method */
15922 startBlk = fgFirstBB;
15923 endBlk = fgEndBBAfterMainFunction();
15926 // Calculate nearBlk and jumpBlk and then call fgFindInsertPoint()
15927 // to find our insertion block
15930 // If the set of blocks that we are moving ends with a BBJ_ALWAYS to
15931 // another [rarely run] block that comes after bPrev (forward branch)
15932 // then we can set up nearBlk to eliminate this jump sometimes
15934 BasicBlock* nearBlk = nullptr;
15935 BasicBlock* jumpBlk = nullptr;
15937 if ((bEnd->bbJumpKind == BBJ_ALWAYS) && (!isRare || bEnd->bbJumpDest->isRunRarely()) &&
15938 fgIsForwardBranch(bEnd, bPrev))
15940 // Set nearBlk to be the block in [startBlk..endBlk]
15941 // such that nearBlk->bbNext == bEnd->JumpDest
15942 // if no such block exists then set nearBlk to NULL
15943 nearBlk = startBlk;
15947 // We do not want to set nearBlk to bPrev
15948 // since then we will not move [bStart..bEnd]
15950 if (nearBlk != bPrev)
15952 // Check if nearBlk satisfies our requirement
15953 if (nearBlk->bbNext == bEnd->bbJumpDest)
15959 // Did we reach the endBlk?
15960 if (nearBlk == endBlk)
15966 // advance nearBlk to the next block
15967 nearBlk = nearBlk->bbNext;
15969 } while (nearBlk != nullptr);
15972 // if nearBlk is NULL then we set nearBlk to be the
15973 // first block that we want to insert after.
15974 if (nearBlk == nullptr)
15976 if (bDest != nullptr)
15978 // we want to insert after bDest
15983 // we want to insert after bPrev
15988 /* Set insertAfterBlk to the block which we will insert after. */
15991 fgFindInsertPoint(bStart->bbTryIndex,
15992 true, // Insert in the try region.
15993 startBlk, endBlk, nearBlk, jumpBlk, bStart->bbWeight == BB_ZERO_WEIGHT);
15996 /* See if insertAfterBlk is the same as where we started, */
15997 /* or if we could not find any insertion point */
15999 if ((insertAfterBlk == bPrev) || (insertAfterBlk == nullptr))
16002 /* We couldn't move the blocks, so put everything back */
16003 /* relink [bStart .. bEnd] into the flow graph */
16005 bPrev->setNext(bStart);
16008 bEnd->bbNext->bbPrev = bEnd;
16013 if (bStart != bEnd)
16015 printf("Could not relocate blocks (BB%02u .. BB%02u)\n", bStart->bbNum, bEnd->bbNum);
16019 printf("Could not relocate block BB%02u\n", bStart->bbNum);
16028 noway_assert(insertAfterBlk != nullptr);
16029 noway_assert(bStartPrev != nullptr);
16030 noway_assert(bStartPrev != insertAfterBlk);
16033 movedBlocks = true;
16038 if (bStart2 != nullptr)
16046 msg = "rarely run";
16054 printf("Relocated %s ", msg);
16055 if (bStart != bEnd)
16057 printf("blocks (BB%02u .. BB%02u)", bStart->bbNum, bEnd->bbNum);
16061 printf("block BB%02u", bStart->bbNum);
16064 if (bPrev->bbJumpKind == BBJ_COND)
16066 printf(" by reversing conditional jump at BB%02u\n", bPrev->bbNum);
16070 printf("\n", bPrev->bbNum);
16075 if (bPrev->bbJumpKind == BBJ_COND)
16077 /* Reverse the bPrev jump condition */
16078 GenTree* condTest = bPrev->lastStmt();
16080 condTest = condTest->gtStmt.gtStmtExpr;
16081 noway_assert(condTest->gtOper == GT_JTRUE);
16083 condTest->gtOp.gtOp1 = gtReverseCond(condTest->gtOp.gtOp1);
16085 if (bStart2 == nullptr)
16087 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
16088 bPrev->bbJumpDest = bStart;
16089 bStart->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
16093 noway_assert(insertAfterBlk == bPrev);
16094 noway_assert(insertAfterBlk->bbNext == block);
16096 /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */
16097 bPrev->bbJumpDest = block;
16098 block->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL);
16102 // If we are moving blocks that are at the end of a try or handler
16103 // we will need to shorten ebdTryLast or ebdHndLast
16105 ehUpdateLastBlocks(bEnd, bStartPrev);
16107 // If we are moving blocks into the end of a try region or handler region
16108 // we will need to extend ebdTryLast or ebdHndLast so the blocks that we
16109 // are moving are part of this try or handler region.
16111 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
16113 // Are we moving blocks to the end of a try region?
16114 if (HBtab->ebdTryLast == insertAfterBlk)
16116 if (fStartIsInTry[XTnum])
16118 // bStart..bEnd is in the try, so extend the try region
16119 fgSetTryEnd(HBtab, bEnd);
16123 // Are we moving blocks to the end of a handler region?
16124 if (HBtab->ebdHndLast == insertAfterBlk)
16126 if (fStartIsInHnd[XTnum])
16128 // bStart..bEnd is in the handler, so extend the handler region
16129 fgSetHndEnd(HBtab, bEnd);
16134 /* We have decided to insert the block(s) after 'insertAfterBlk' */
16135 fgMoveBlocksAfter(bStart, bEnd, insertAfterBlk);
16139 /* We may need to insert an unconditional branch after bPrev to bDest */
16140 fgConnectFallThrough(bPrev, bDest);
16144 /* If bPrev falls through, we must insert a jump to block */
16145 fgConnectFallThrough(bPrev, block);
16148 BasicBlock* bSkip = bEnd->bbNext;
16150 /* If bEnd falls through, we must insert a jump to bNext */
16151 fgConnectFallThrough(bEnd, bNext);
16153 if (bStart2 == nullptr)
16155 /* If insertAfterBlk falls through, we are forced to */
16156 /* add a jump around the block(s) we just inserted */
16157 fgConnectFallThrough(insertAfterBlk, bSkip);
16161 /* We may need to insert an unconditional branch after bPrev2 to bStart */
16162 fgConnectFallThrough(bPrev2, bStart);
16168 printf("\nAfter this change in fgReorderBlocks the BB graph is:");
16169 fgDispBasicBlocks(verboseTrees);
16172 fgVerifyHandlerTab();
16174 // Make sure that the predecessor lists are accurate
16175 if (expensiveDebugCheckLevel >= 2)
16177 fgDebugCheckBBlist();
16181 // Set our iteration point 'block' to be the new bPrev->bbNext
16182 // It will be used as the next bPrev
16183 block = bPrev->bbNext;
16185 } // end of for loop(bPrev,block)
16187 bool changed = movedBlocks || newRarelyRun || optimizedSwitches;
16191 fgNeedsUpdateFlowGraph = true;
16193 // Make sure that the predecessor lists are accurate
16194 if (expensiveDebugCheckLevel >= 2)
16196 fgDebugCheckBBlist();
16202 #pragma warning(pop)
16205 /*-------------------------------------------------------------------------
16207 * Walk the basic blocks list to determine the first block to place in the
16208 * cold section. This would be the first of a series of rarely executed blocks
16209 * such that no succeeding blocks are in a try region or an exception handler
16210 * or are rarely executed.
16213 void Compiler::fgDetermineFirstColdBlock()
16218 printf("\n*************** In fgDetermineFirstColdBlock()\n");
16222 // Since we may need to create a new transistion block
16223 // we assert that it is OK to create new blocks.
16225 assert(fgSafeBasicBlockCreation);
16227 fgFirstColdBlock = nullptr;
16229 #if FEATURE_STACK_FP_X87
16230 if (compMayHaveTransitionBlocks)
16232 opts.compProcedureSplitting = false;
16234 // See comment above declaration of compMayHaveTransitionBlocks for comments on this
16235 JITDUMP("Turning off procedure splitting for this method, as it may end up having FP transition blocks\n");
16237 #endif // FEATURE_STACK_FP_X87
16239 if (!opts.compProcedureSplitting)
16241 JITDUMP("No procedure splitting will be done for this method\n");
16246 if ((compHndBBtabCount > 0) && !opts.compProcedureSplittingEH)
16248 JITDUMP("No procedure splitting will be done for this method with EH (by request)\n");
16253 #if FEATURE_EH_FUNCLETS
16254 // TODO-CQ: handle hot/cold splitting in functions with EH (including synchronized methods
16255 // that create EH in methods without explicit EH clauses).
16257 if (compHndBBtabCount > 0)
16259 JITDUMP("No procedure splitting will be done for this method with EH (implementation limitation)\n");
16262 #endif // FEATURE_EH_FUNCLETS
16264 BasicBlock* firstColdBlock = nullptr;
16265 BasicBlock* prevToFirstColdBlock = nullptr;
16269 for (lblk = nullptr, block = fgFirstBB; block != nullptr; lblk = block, block = block->bbNext)
16271 bool blockMustBeInHotSection = false;
16273 #if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
16274 if (bbIsHandlerBeg(block))
16276 blockMustBeInHotSection = true;
16278 #endif // HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION
16280 // Do we have a candidate for the first cold block?
16281 if (firstColdBlock != nullptr)
16283 // We have a candidate for first cold block
16285 // Is this a hot block?
16286 if (blockMustBeInHotSection || (block->isRunRarely() == false))
16288 // We have to restart the search for the first cold block
16289 firstColdBlock = nullptr;
16290 prevToFirstColdBlock = nullptr;
16293 else // (firstColdBlock == NULL)
16295 // We don't have a candidate for first cold block
16297 // Is this a cold block?
16298 if (!blockMustBeInHotSection && (block->isRunRarely() == true))
16301 // If the last block that was hot was a BBJ_COND
16302 // then we will have to add an unconditional jump
16303 // so the code size for block needs be large
16304 // enough to make it worth our while
16306 if ((lblk == nullptr) || (lblk->bbJumpKind != BBJ_COND) || (fgGetCodeEstimate(block) >= 8))
16308 // This block is now a candidate for first cold block
16309 // Also remember the predecessor to this block
16310 firstColdBlock = block;
16311 prevToFirstColdBlock = lblk;
16317 if (firstColdBlock == fgFirstBB)
16319 // If the first block is Cold then we can't move any blocks
16320 // into the cold section
16322 firstColdBlock = nullptr;
16325 if (firstColdBlock != nullptr)
16327 noway_assert(prevToFirstColdBlock != nullptr);
16329 if (prevToFirstColdBlock == nullptr)
16331 return; // To keep Prefast happy
16334 // If we only have one cold block
16335 // then it may not be worth it to move it
16336 // into the Cold section as a jump to the
16337 // Cold section is 5 bytes in size.
16339 if (firstColdBlock->bbNext == nullptr)
16341 // If the size of the cold block is 7 or less
16342 // then we will keep it in the Hot section.
16344 if (fgGetCodeEstimate(firstColdBlock) < 8)
16346 firstColdBlock = nullptr;
16351 // When the last Hot block fall through into the Cold section
16352 // we may need to add a jump
16354 if (prevToFirstColdBlock->bbFallsThrough())
16356 switch (prevToFirstColdBlock->bbJumpKind)
16359 noway_assert(!"Unhandled jumpkind in fgDetermineFirstColdBlock()");
16361 case BBJ_CALLFINALLY:
16362 // A BBJ_CALLFINALLY that falls through is always followed
16363 // by an empty BBJ_ALWAYS.
16365 assert(prevToFirstColdBlock->isBBCallAlwaysPair());
16367 firstColdBlock->bbNext; // Note that this assignment could make firstColdBlock == nullptr
16372 // This is a slightly more complicated case, because we will
16373 // probably need to insert a block to jump to the cold section.
16375 if (firstColdBlock->isEmpty() && (firstColdBlock->bbJumpKind == BBJ_ALWAYS))
16377 // We can just use this block as the transitionBlock
16378 firstColdBlock = firstColdBlock->bbNext;
16379 // Note that this assignment could make firstColdBlock == NULL
16383 BasicBlock* transitionBlock = fgNewBBafter(BBJ_ALWAYS, prevToFirstColdBlock, true);
16384 transitionBlock->bbJumpDest = firstColdBlock;
16385 transitionBlock->inheritWeight(firstColdBlock);
16387 noway_assert(fgComputePredsDone);
16389 // Update the predecessor list for firstColdBlock
16390 fgReplacePred(firstColdBlock, prevToFirstColdBlock, transitionBlock);
16392 // Add prevToFirstColdBlock as a predecessor for transitionBlock
16393 fgAddRefPred(transitionBlock, prevToFirstColdBlock);
16398 // If the block preceding the first cold block is BBJ_NONE,
16399 // convert it to BBJ_ALWAYS to force an explicit jump.
16401 prevToFirstColdBlock->bbJumpDest = firstColdBlock;
16402 prevToFirstColdBlock->bbJumpKind = BBJ_ALWAYS;
16408 if (firstColdBlock != nullptr)
16410 firstColdBlock->bbFlags |= BBF_JMP_TARGET;
16412 for (block = firstColdBlock; block; block = block->bbNext)
16414 block->bbFlags |= BBF_COLD;
16423 if (firstColdBlock)
16425 printf("fgFirstColdBlock is BB%02u.\n", firstColdBlock->bbNum);
16429 printf("fgFirstColdBlock is NULL.\n");
16432 fgDispBasicBlocks();
16435 fgVerifyHandlerTab();
16438 fgFirstColdBlock = firstColdBlock;
16442 #pragma warning(push)
16443 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
16445 /*****************************************************************************
16447 * Function called to "comb" the basic block list.
16448 * Removes any empty blocks, unreachable blocks and redundant jumps.
16449 * Most of those appear after dead store removal and folding of conditionals.
16451 * Returns: true if the flowgraph has been modified
16453 * It also compacts basic blocks
16454 * (consecutive basic blocks that should in fact be one).
16457 * Debuggable code and Min Optimization JIT also introduces basic blocks
16458 * but we do not optimize those!
16461 bool Compiler::fgUpdateFlowGraph(bool doTailDuplication)
16466 printf("\n*************** In fgUpdateFlowGraph()");
16470 /* This should never be called for debuggable code */
16472 noway_assert(!opts.MinOpts() && !opts.compDbgCode);
16477 printf("\nBefore updating the flow graph:\n");
16478 fgDispBasicBlocks(verboseTrees);
16483 /* Walk all the basic blocks - look for unconditional jumps, empty blocks, blocks to compact, etc...
16486 * Once a block is removed the predecessors are not accurate (assuming they were at the beginning)
16487 * For now we will only use the information in bbRefs because it is easier to be updated
16490 bool modified = false;
16496 BasicBlock* block; // the current block
16497 BasicBlock* bPrev = nullptr; // the previous non-worthless block
16498 BasicBlock* bNext; // the successor of the current block
16499 BasicBlock* bDest; // the jump target of the current block
16501 for (block = fgFirstBB; block != nullptr; block = block->bbNext)
16503 /* Some blocks may be already marked removed by other optimizations
16504 * (e.g worthless loop removal), without being explicitly removed
16508 if (block->bbFlags & BBF_REMOVED)
16512 bPrev->setNext(block->bbNext);
16516 /* WEIRD first basic block is removed - should have an assert here */
16517 noway_assert(!"First basic block marked as BBF_REMOVED???");
16519 fgFirstBB = block->bbNext;
16524 /* We jump to the REPEAT label if we performed a change involving the current block
16525 * This is in case there are other optimizations that can show up
16526 * (e.g. - compact 3 blocks in a row)
16527 * If nothing happens, we then finish the iteration and move to the next block
16532 bNext = block->bbNext;
16535 if (block->bbJumpKind == BBJ_ALWAYS)
16537 bDest = block->bbJumpDest;
16538 if (doTailDuplication && fgOptimizeUncondBranchToSimpleCond(block, bDest))
16542 bDest = block->bbJumpDest;
16543 bNext = block->bbNext;
16547 // Remove JUMPS to the following block
16548 // and optimize any JUMPS to JUMPS
16550 if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS)
16552 bDest = block->bbJumpDest;
16553 if (bDest == bNext)
16555 if (fgOptimizeBranchToNext(block, bNext, bPrev))
16564 if (bDest != nullptr)
16566 // Do we have a JUMP to an empty unconditional JUMP block?
16567 if (bDest->isEmpty() && (bDest->bbJumpKind == BBJ_ALWAYS) &&
16568 (bDest != bDest->bbJumpDest)) // special case for self jumps
16570 if (fgOptimizeBranchToEmptyUnconditional(block, bDest))
16578 // Check for a conditional branch that just skips over an empty BBJ_ALWAYS block
16580 if ((block->bbJumpKind == BBJ_COND) && // block is a BBJ_COND block
16581 (bNext != nullptr) && // block is not the last block
16582 (bNext->bbRefs == 1) && // No other block jumps to bNext
16583 (bNext->bbNext == bDest) && // The block after bNext is the BBJ_COND jump dest
16584 (bNext->bbJumpKind == BBJ_ALWAYS) && // The next block is a BBJ_ALWAYS block
16585 bNext->isEmpty() && // and it is an an empty block
16586 (bNext != bNext->bbJumpDest) && // special case for self jumps
16587 (bDest != fgFirstColdBlock))
16589 bool optimizeJump = true;
16591 // We do not optimize jumps between two different try regions.
16592 // However jumping to a block that is not in any try region is OK
16594 if (bDest->hasTryIndex() && !BasicBlock::sameTryRegion(block, bDest))
16596 optimizeJump = false;
16599 // Also consider bNext's try region
16601 if (bNext->hasTryIndex() && !BasicBlock::sameTryRegion(block, bNext))
16603 optimizeJump = false;
16606 // If we are optimizing using real profile weights
16607 // then don't optimize a conditional jump to an unconditional jump
16608 // until after we have computed the edge weights
16610 if (fgIsUsingProfileWeights())
16612 // if block and bdest are in different hot/cold regions we can't do this this optimization
16613 // because we can't allow fall-through into the cold region.
16614 if (!fgEdgeWeightsComputed || fgInDifferentRegions(block, bDest))
16616 fgNeedsUpdateFlowGraph = true;
16617 optimizeJump = false;
16626 printf("\nReversing a conditional jump around an unconditional jump (BB%02u -> BB%02u -> "
16628 block->bbNum, bDest->bbNum, bNext->bbJumpDest->bbNum);
16631 /* Reverse the jump condition */
16633 GenTree* test = block->lastNode();
16634 noway_assert(test->OperIsConditionalJump());
16636 if (test->OperGet() == GT_JTRUE)
16638 GenTree* cond = gtReverseCond(test->gtOp.gtOp1);
16639 assert(cond == test->gtOp.gtOp1); // Ensure `gtReverseCond` did not create a new node.
16640 test->gtOp.gtOp1 = cond;
16644 gtReverseCond(test);
16647 // Optimize the Conditional JUMP to go to the new target
16648 block->bbJumpDest = bNext->bbJumpDest;
16650 fgAddRefPred(bNext->bbJumpDest, block, fgRemoveRefPred(bNext->bbJumpDest, bNext));
16653 Unlink bNext from the BasicBlock list; note that we can
16654 do this even though other blocks could jump to it - the
16655 reason is that elsewhere in this function we always
16656 redirect jumps to jumps to jump to the final label,
16657 so even if another block jumps to bNext it won't matter
16658 once we're done since any such jump will be redirected
16659 to the final target by the time we're done here.
16662 fgRemoveRefPred(bNext, block);
16663 fgUnlinkBlock(bNext);
16665 /* Mark the block as removed */
16666 bNext->bbFlags |= BBF_REMOVED;
16668 // If this is the first Cold basic block update fgFirstColdBlock
16669 if (bNext == fgFirstColdBlock)
16671 fgFirstColdBlock = bNext->bbNext;
16675 // If we removed the end of a try region or handler region
16676 // we will need to update ebdTryLast or ebdHndLast.
16680 EHblkDsc* HBtabEnd;
16682 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd;
16685 if ((HBtab->ebdTryLast == bNext) || (HBtab->ebdHndLast == bNext))
16687 fgSkipRmvdBlocks(HBtab);
16691 // we optimized this JUMP - goto REPEAT to catch similar cases
16698 printf("\nAfter reversing the jump:\n");
16699 fgDispBasicBlocks(verboseTrees);
16704 For a rare special case we cannot jump to REPEAT
16705 as jumping to REPEAT will cause us to delete 'block'
16706 because it currently appears to be unreachable. As
16707 it is a self loop that only has a single bbRef (itself)
16708 However since the unlinked bNext has additional bbRefs
16709 (that we will later connect to 'block'), it is not really
16712 if ((bNext->bbRefs > 0) && (bNext->bbJumpDest == block) && (block->bbRefs == 1))
16723 // Update the switch jump table such that it follows jumps to jumps:
16725 if (block->bbJumpKind == BBJ_SWITCH)
16727 if (fgOptimizeSwitchBranches(block))
16735 noway_assert(!(block->bbFlags & BBF_REMOVED));
16737 /* COMPACT blocks if possible */
16739 if (fgCanCompactBlocks(block, bNext))
16741 fgCompactBlocks(block, bNext);
16743 /* we compacted two blocks - goto REPEAT to catch similar cases */
16749 /* Remove unreachable or empty blocks - do not consider blocks marked BBF_DONT_REMOVE or genReturnBB block
16750 * These include first and last block of a TRY, exception handlers and RANGE_CHECK_FAIL THROW blocks */
16752 if ((block->bbFlags & BBF_DONT_REMOVE) == BBF_DONT_REMOVE || block == genReturnBB)
16758 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16759 // Don't remove the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair.
16760 if (block->countOfInEdges() == 0 && bPrev->bbJumpKind == BBJ_CALLFINALLY)
16762 assert(bPrev->isBBCallAlwaysPair());
16763 noway_assert(!(bPrev->bbFlags & BBF_RETLESS_CALL));
16764 noway_assert(block->bbJumpKind == BBJ_ALWAYS);
16768 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16770 noway_assert(!block->bbCatchTyp);
16771 noway_assert(!(block->bbFlags & BBF_TRY_BEG));
16773 /* Remove unreachable blocks
16775 * We'll look for blocks that have countOfInEdges() = 0 (blocks may become
16776 * unreachable due to a BBJ_ALWAYS introduced by conditional folding for example)
16779 if (block->countOfInEdges() == 0)
16781 /* no references -> unreachable - remove it */
16782 /* For now do not update the bbNum, do it at the end */
16784 fgRemoveBlock(block, true);
16789 /* we removed the current block - the rest of the optimizations won't have a target
16790 * continue with the next one */
16794 else if (block->countOfInEdges() == 1)
16796 switch (block->bbJumpKind)
16800 if (block->bbJumpDest == block)
16802 fgRemoveBlock(block, true);
16807 /* we removed the current block - the rest of the optimizations
16808 * won't have a target so continue with the next block */
16819 noway_assert(!(block->bbFlags & BBF_REMOVED));
16821 /* Remove EMPTY blocks */
16823 if (block->isEmpty())
16825 assert(bPrev == block->bbPrev);
16826 if (fgOptimizeEmptyBlock(block))
16832 /* Have we removed the block? */
16834 if (block->bbFlags & BBF_REMOVED)
16836 /* block was removed - no change to bPrev */
16841 /* Set the predecessor of the last reachable block
16842 * If we removed the current block, the predecessor remains unchanged
16843 * otherwise, since the current block is ok, it becomes the predecessor */
16845 noway_assert(!(block->bbFlags & BBF_REMOVED));
16851 fgNeedsUpdateFlowGraph = false;
16854 if (verbose && modified)
16856 printf("\nAfter updating the flow graph:\n");
16857 fgDispBasicBlocks(verboseTrees);
16858 fgDispHandlerTab();
16861 if (compRationalIRForm)
16863 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
16865 LIR::AsRange(block).CheckLIR(this);
16869 fgVerifyHandlerTab();
16870 // Make sure that the predecessor lists are accurate
16871 fgDebugCheckBBlist();
16872 fgDebugCheckUpdate();
16878 #pragma warning(pop)
16881 /*****************************************************************************
16882 * Check that the flow graph is really updated
16887 void Compiler::fgDebugCheckUpdate()
16889 if (!compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
16894 /* We check for these conditions:
16895 * no unreachable blocks -> no blocks have countOfInEdges() = 0
16896 * no empty blocks -> no blocks have bbTreeList = 0
16897 * no un-imported blocks -> no blocks have BBF_IMPORTED not set (this is
16898 * kind of redundand with the above, but to make sure)
16899 * no un-compacted blocks -> BBJ_NONE followed by block with no jumps to it (countOfInEdges() = 1)
16904 for (prev = nullptr, block = fgFirstBB; block != nullptr; prev = block, block = block->bbNext)
16906 /* no unreachable blocks */
16908 if ((block->countOfInEdges() == 0) && !(block->bbFlags & BBF_DONT_REMOVE)
16909 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
16910 // With funclets, we never get rid of the BBJ_ALWAYS part of a BBJ_CALLFINALLY/BBJ_ALWAYS pair,
16911 // even if we can prove that the finally block never returns.
16912 && (prev == NULL || block->bbJumpKind != BBJ_ALWAYS || !prev->isBBCallAlwaysPair())
16913 #endif // FEATURE_EH_FUNCLETS
16916 noway_assert(!"Unreachable block not removed!");
16919 /* no empty blocks */
16921 if (block->isEmpty() && !(block->bbFlags & BBF_DONT_REMOVE))
16923 switch (block->bbJumpKind)
16925 case BBJ_CALLFINALLY:
16926 case BBJ_EHFINALLYRET:
16927 case BBJ_EHFILTERRET:
16929 /* for BBJ_ALWAYS is probably just a GOTO, but will have to be treated */
16931 case BBJ_EHCATCHRET:
16932 /* These jump kinds are allowed to have empty tree lists */
16936 /* it may be the case that the block had more than one reference to it
16937 * so we couldn't remove it */
16939 if (block->countOfInEdges() == 0)
16941 noway_assert(!"Empty block not removed!");
16947 /* no un-imported blocks */
16949 if (!(block->bbFlags & BBF_IMPORTED))
16951 /* internal blocks do not count */
16953 if (!(block->bbFlags & BBF_INTERNAL))
16955 noway_assert(!"Non IMPORTED block not removed!");
16959 bool prevIsCallAlwaysPair = ((prev != nullptr) && prev->isBBCallAlwaysPair());
16961 // Check for an unnecessary jumps to the next block
16962 bool doAssertOnJumpToNextBlock = false; // unless we have a BBJ_COND or BBJ_ALWAYS we can not assert
16964 if (block->bbJumpKind == BBJ_COND)
16966 // A conditional branch should never jump to the next block
16967 // as it can be folded into a BBJ_NONE;
16968 doAssertOnJumpToNextBlock = true;
16970 else if (block->bbJumpKind == BBJ_ALWAYS)
16972 // Generally we will want to assert if a BBJ_ALWAYS branches to the next block
16973 doAssertOnJumpToNextBlock = true;
16975 // If the BBF_KEEP_BBJ_ALWAYS flag is set we allow it to jump to the next block
16976 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
16978 doAssertOnJumpToNextBlock = false;
16981 // A call/always pair is also allowed to jump to the next block
16982 if (prevIsCallAlwaysPair)
16984 doAssertOnJumpToNextBlock = false;
16987 // We are allowed to have a branch from a hot 'block' to a cold 'bbNext'
16989 if ((block->bbNext != nullptr) && fgInDifferentRegions(block, block->bbNext))
16991 doAssertOnJumpToNextBlock = false;
16995 if (doAssertOnJumpToNextBlock)
16997 if (block->bbJumpDest == block->bbNext)
16999 noway_assert(!"Unnecessary jump to the next block!");
17003 /* Make sure BBF_KEEP_BBJ_ALWAYS is set correctly */
17005 if ((block->bbJumpKind == BBJ_ALWAYS) && prevIsCallAlwaysPair)
17007 noway_assert(block->bbFlags & BBF_KEEP_BBJ_ALWAYS);
17010 /* For a BBJ_CALLFINALLY block we make sure that we are followed by */
17011 /* an BBJ_ALWAYS block with BBF_INTERNAL set */
17012 /* or that it's a BBF_RETLESS_CALL */
17013 if (block->bbJumpKind == BBJ_CALLFINALLY)
17015 assert((block->bbFlags & BBF_RETLESS_CALL) || block->isBBCallAlwaysPair());
17018 /* no un-compacted blocks */
17020 if (fgCanCompactBlocks(block, block->bbNext))
17022 noway_assert(!"Found un-compacted blocks!");
17029 /*****************************************************************************
17030 * We've inserted a new block before 'block' that should be part of the same EH region as 'block'.
17031 * Update the EH table to make this so. Also, set the new block to have the right EH region data
17032 * (copy the bbTryIndex, bbHndIndex, and bbCatchTyp from 'block' to the new predecessor, and clear
17033 * 'bbCatchTyp' from 'block').
17035 void Compiler::fgExtendEHRegionBefore(BasicBlock* block)
17037 assert(block->bbPrev != nullptr);
17039 BasicBlock* bPrev = block->bbPrev;
17041 bPrev->copyEHRegion(block);
17043 // The first block (and only the first block) of a handler has bbCatchTyp set
17044 bPrev->bbCatchTyp = block->bbCatchTyp;
17045 block->bbCatchTyp = BBCT_NONE;
17048 EHblkDsc* HBtabEnd;
17050 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
17052 /* Multiple pointers in EHblkDsc can point to same block. We can not early out after the first match. */
17053 if (HBtab->ebdTryBeg == block)
17058 printf("EH#%u: New first block of try: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
17061 HBtab->ebdTryBeg = bPrev;
17062 bPrev->bbFlags |= BBF_TRY_BEG | BBF_DONT_REMOVE | BBF_HAS_LABEL;
17064 // clear the TryBeg flag unless it begins another try region
17065 if (!bbIsTryBeg(block))
17067 block->bbFlags &= ~BBF_TRY_BEG;
17071 if (HBtab->ebdHndBeg == block)
17076 printf("EH#%u: New first block of handler: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
17080 // The first block of a handler has an artificial extra refcount. Transfer that to the new block.
17081 assert(block->bbRefs > 0);
17084 HBtab->ebdHndBeg = bPrev;
17085 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
17087 #if FEATURE_EH_FUNCLETS
17088 if (fgFuncletsCreated)
17090 assert((block->bbFlags & BBF_FUNCLET_BEG) != 0);
17091 bPrev->bbFlags |= BBF_FUNCLET_BEG;
17092 block->bbFlags &= ~BBF_FUNCLET_BEG;
17094 #endif // FEATURE_EH_FUNCLETS
17098 // If this is a handler for a filter, the last block of the filter will end with
17099 // a BBJ_EJFILTERRET block that has a bbJumpDest that jumps to the first block of
17100 // it's handler. So we need to update it to keep things in sync.
17102 if (HBtab->HasFilter())
17104 BasicBlock* bFilterLast = HBtab->BBFilterLast();
17105 assert(bFilterLast != nullptr);
17106 assert(bFilterLast->bbJumpKind == BBJ_EHFILTERRET);
17107 assert(bFilterLast->bbJumpDest == block);
17111 printf("EH#%u: Updating bbJumpDest for filter ret block: BB%02u => BB%02u\n", ehGetIndex(HBtab),
17112 bFilterLast->bbNum, bPrev->bbNum);
17115 // Change the bbJumpDest for bFilterLast from the old first 'block' to the new first 'bPrev'
17116 bFilterLast->bbJumpDest = bPrev;
17120 if (HBtab->HasFilter() && (HBtab->ebdFilter == block))
17125 printf("EH#%u: New first block of filter: BB%02u\n", ehGetIndex(HBtab), bPrev->bbNum);
17129 // The first block of a filter has an artificial extra refcount. Transfer that to the new block.
17130 assert(block->bbRefs > 0);
17133 HBtab->ebdFilter = bPrev;
17134 bPrev->bbFlags |= BBF_DONT_REMOVE | BBF_HAS_LABEL;
17136 #if FEATURE_EH_FUNCLETS
17137 if (fgFuncletsCreated)
17139 assert((block->bbFlags & BBF_FUNCLET_BEG) != 0);
17140 bPrev->bbFlags |= BBF_FUNCLET_BEG;
17141 block->bbFlags &= ~BBF_FUNCLET_BEG;
17143 #endif // FEATURE_EH_FUNCLETS
17150 /*****************************************************************************
17151 * We've inserted a new block after 'block' that should be part of the same EH region as 'block'.
17152 * Update the EH table to make this so. Also, set the new block to have the right EH region data.
17155 void Compiler::fgExtendEHRegionAfter(BasicBlock* block)
17157 BasicBlock* newBlk = block->bbNext;
17158 assert(newBlk != nullptr);
17160 newBlk->copyEHRegion(block);
17161 newBlk->bbCatchTyp =
17162 BBCT_NONE; // Only the first block of a catch has this set, and 'newBlk' can't be the first block of a catch.
17164 // TODO-Throughput: if the block is not in an EH region, then we don't need to walk the EH table looking for 'last'
17165 // block pointers to update.
17166 ehUpdateLastBlocks(block, newBlk);
17169 /*****************************************************************************
17171 * Insert a BasicBlock before the given block.
17174 BasicBlock* Compiler::fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
17176 // Create a new BasicBlock and chain it in
17178 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
17179 newBlk->bbFlags |= BBF_INTERNAL;
17181 fgInsertBBbefore(block, newBlk);
17183 newBlk->bbRefs = 0;
17185 if (newBlk->bbFallsThrough() && block->isRunRarely())
17187 newBlk->bbSetRunRarely();
17192 fgExtendEHRegionBefore(block);
17196 // When extendRegion is false the caller is responsible for setting these two values
17197 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
17198 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
17201 // We assume that if the block we are inserting before is in the cold region, then this new
17202 // block will also be in the cold region.
17203 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
17208 /*****************************************************************************
17210 * Insert a BasicBlock after the given block.
17213 BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion)
17215 // Create a new BasicBlock and chain it in
17217 BasicBlock* newBlk = bbNewBasicBlock(jumpKind);
17218 newBlk->bbFlags |= BBF_INTERNAL;
17220 fgInsertBBafter(block, newBlk);
17222 newBlk->bbRefs = 0;
17224 if (block->bbFallsThrough() && block->isRunRarely())
17226 newBlk->bbSetRunRarely();
17231 fgExtendEHRegionAfter(block);
17235 // When extendRegion is false the caller is responsible for setting these two values
17236 newBlk->setTryIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
17237 newBlk->setHndIndex(MAX_XCPTN_INDEX); // Note: this is still a legal index, just unlikely
17240 // If the new block is in the cold region (because the block we are inserting after
17241 // is in the cold region), mark it as such.
17242 newBlk->bbFlags |= (block->bbFlags & BBF_COLD);
17247 /*****************************************************************************
17248 * Inserts basic block before existing basic block.
17250 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
17251 * (If insertBeforeBlk is the first block of the funclet region, then 'newBlk' will be the
17252 * new first block of the funclet region.)
17254 void Compiler::fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk)
17256 if (insertBeforeBlk->bbPrev)
17258 fgInsertBBafter(insertBeforeBlk->bbPrev, newBlk);
17262 newBlk->setNext(fgFirstBB);
17264 fgFirstBB = newBlk;
17265 newBlk->bbPrev = nullptr;
17268 #if FEATURE_EH_FUNCLETS
17270 /* Update fgFirstFuncletBB if insertBeforeBlk is the first block of the funclet region. */
17272 if (fgFirstFuncletBB == insertBeforeBlk)
17274 fgFirstFuncletBB = newBlk;
17277 #endif // FEATURE_EH_FUNCLETS
17280 /*****************************************************************************
17281 * Inserts basic block after existing basic block.
17283 * If insertBeforeBlk is in the funclet region, then newBlk will be in the funclet region.
17284 * (It can't be used to insert a block as the first block of the funclet region).
17286 void Compiler::fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk)
17288 newBlk->bbNext = insertAfterBlk->bbNext;
17290 if (insertAfterBlk->bbNext)
17292 insertAfterBlk->bbNext->bbPrev = newBlk;
17295 insertAfterBlk->bbNext = newBlk;
17296 newBlk->bbPrev = insertAfterBlk;
17298 if (fgLastBB == insertAfterBlk)
17301 assert(fgLastBB->bbNext == nullptr);
17305 // We have two edges (bAlt => bCur) and (bCur => bNext).
17307 // Returns true if the weight of (bAlt => bCur)
17308 // is greater than the weight of (bCur => bNext).
17309 // We compare the edge weights if we have valid edge weights
17310 // otherwise we compare blocks weights.
17312 bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt)
17314 // bCur can't be NULL and must be a fall through bbJumpKind
17315 noway_assert(bCur != nullptr);
17316 noway_assert(bCur->bbFallsThrough());
17317 noway_assert(bAlt != nullptr);
17319 // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND
17320 if ((bAlt->bbJumpKind != BBJ_ALWAYS) && (bAlt->bbJumpKind != BBJ_COND))
17325 // if bAlt doesn't jump to bCur it can't be a better fall through than bCur
17326 if (bAlt->bbJumpDest != bCur)
17331 // Currently bNext is the fall through for bCur
17332 BasicBlock* bNext = bCur->bbNext;
17333 noway_assert(bNext != nullptr);
17335 // We will set result to true if bAlt is a better fall through than bCur
17337 if (fgHaveValidEdgeWeights)
17339 // We will compare the edge weight for our two choices
17340 flowList* edgeFromAlt = fgGetPredForBlock(bCur, bAlt);
17341 flowList* edgeFromCur = fgGetPredForBlock(bNext, bCur);
17342 noway_assert(edgeFromCur != nullptr);
17343 noway_assert(edgeFromAlt != nullptr);
17345 result = (edgeFromAlt->flEdgeWeightMin > edgeFromCur->flEdgeWeightMax);
17349 if (bAlt->bbJumpKind == BBJ_ALWAYS)
17351 // Our result is true if bAlt's weight is more than bCur's weight
17352 result = (bAlt->bbWeight > bCur->bbWeight);
17356 noway_assert(bAlt->bbJumpKind == BBJ_COND);
17357 // Our result is true if bAlt's weight is more than twice bCur's weight
17358 result = (bAlt->bbWeight > (2 * bCur->bbWeight));
17364 //------------------------------------------------------------------------
17365 // fgCheckEHCanInsertAfterBlock: Determine if a block can be inserted after
17366 // 'blk' and legally be put in the EH region specified by 'regionIndex'. This
17367 // can be true if the most nested region the block is in is already 'regionIndex',
17368 // as we'll just extend the most nested region (and any region ending at the same block).
17369 // It can also be true if it is the end of (a set of) EH regions, such that
17370 // inserting the block and properly extending some EH regions (if necessary)
17371 // puts the block in the correct region. We only consider the case of extending
17372 // an EH region after 'blk' (that is, to include 'blk' and the newly insert block);
17373 // we don't consider inserting a block as the the first block of an EH region following 'blk'.
17375 // Consider this example:
17382 // | |--- |--- BB05
17384 // |----------------- BB07
17386 // Passing BB05 and try1/try2/try3 as the region to insert into (as well as putInTryRegion==true)
17387 // will all return 'true'. Here are the cases:
17388 // 1. Insert into try1: the most nested EH region BB05 is in is already try1, so we can insert after
17389 // it and extend try1 (and try2).
17390 // 2. Insert into try2: we can extend try2, but leave try1 alone.
17391 // 3. Insert into try3: we can leave try1 and try2 alone, and put the new block just in try3. Note that
17392 // in this case, after we "loop outwards" in the EH nesting, we get to a place where we're in the middle
17393 // of the try3 region, not at the end of it.
17394 // In all cases, it is possible to put a block after BB05 and put it in any of these three 'try' regions legally.
17396 // Filters are ignored; if 'blk' is in a filter, the answer will be false.
17399 // blk - the BasicBlock we are checking to see if we can insert after.
17400 // regionIndex - the EH region we want to insert a block into. regionIndex is
17401 // in the range [0..compHndBBtabCount]; 0 means "main method".
17402 // putInTryRegion - 'true' if the new block should be inserted in the 'try' region of 'regionIndex'.
17403 // For regionIndex 0 (the "main method"), this should be 'true'.
17406 // 'true' if a block can be inserted after 'blk' and put in EH region 'regionIndex', else 'false'.
17408 bool Compiler::fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion)
17410 assert(blk != nullptr);
17411 assert(regionIndex <= compHndBBtabCount);
17413 if (regionIndex == 0)
17415 assert(putInTryRegion);
17419 unsigned nestedRegionIndex = ehGetMostNestedRegionIndex(blk, &inTryRegion);
17421 bool insertOK = true;
17424 if (nestedRegionIndex == regionIndex)
17426 // This block is in the region we want to be in. We can insert here if it's the right type of region.
17427 // (If we want to be in the 'try' region, but the block is in the handler region, then inserting a
17428 // new block after 'blk' can't put it in the 'try' region, and vice-versa, since we only consider
17429 // extending regions after, not prepending to regions.)
17430 // This check will be 'true' if we are trying to put something in the main function (as putInTryRegion
17431 // must be 'true' if regionIndex is zero, and inTryRegion will also be 'true' if nestedRegionIndex is zero).
17432 insertOK = (putInTryRegion == inTryRegion);
17435 else if (nestedRegionIndex == 0)
17437 // The block is in the main function, but we want to put something in a nested region. We can't do that.
17442 assert(nestedRegionIndex > 0);
17443 EHblkDsc* ehDsc = ehGetDsc(nestedRegionIndex - 1); // ehGetDsc uses [0..compHndBBtabCount) form.
17447 if (blk != ehDsc->ebdTryLast)
17449 // Not the last block? Then it must be somewhere else within the try region, so we can't insert here.
17451 break; // exit the 'for' loop
17456 // We ignore filters.
17457 if (blk != ehDsc->ebdHndLast)
17459 // Not the last block? Then it must be somewhere else within the handler region, so we can't insert
17462 break; // exit the 'for' loop
17466 // Things look good for this region; check the enclosing regions, if any.
17468 nestedRegionIndex =
17469 ehGetEnclosingRegionIndex(nestedRegionIndex - 1,
17470 &inTryRegion); // ehGetEnclosingRegionIndex uses [0..compHndBBtabCount) form.
17472 // Convert to [0..compHndBBtabCount] form.
17473 nestedRegionIndex = (nestedRegionIndex == EHblkDsc::NO_ENCLOSING_INDEX) ? 0 : nestedRegionIndex + 1;
17474 } // end of for(;;)
17479 //------------------------------------------------------------------------
17480 // Finds the block closest to endBlk in the range [startBlk..endBlk) after which a block can be
17481 // inserted easily. Note that endBlk cannot be returned; its predecessor is the last block that can
17482 // be returned. The new block will be put in an EH region described by the arguments regionIndex,
17483 // putInTryRegion, startBlk, and endBlk (explained below), so it must be legal to place to put the
17484 // new block after the insertion location block, give it the specified EH region index, and not break
17485 // EH nesting rules. This function is careful to choose a block in the correct EH region. However,
17486 // it assumes that the new block can ALWAYS be placed at the end (just before endBlk). That means
17487 // that the caller must ensure that is true.
17489 // Below are the possible cases for the arguments to this method:
17490 // 1. putInTryRegion == true and regionIndex > 0:
17491 // Search in the try region indicated by regionIndex.
17492 // 2. putInTryRegion == false and regionIndex > 0:
17493 // a. If startBlk is the first block of a filter and endBlk is the block after the end of the
17494 // filter (that is, the startBlk and endBlk match a filter bounds exactly), then choose a
17495 // location within this filter region. (Note that, due to IL rules, filters do not have any
17496 // EH nested within them.) Otherwise, filters are skipped.
17497 // b. Else, search in the handler region indicated by regionIndex.
17498 // 3. regionIndex = 0:
17499 // Search in the entire main method, excluding all EH regions. In this case, putInTryRegion must be true.
17501 // This method makes sure to find an insertion point which would not cause the inserted block to
17502 // be put inside any inner try/filter/handler regions.
17504 // The actual insertion occurs after the returned block. Note that the returned insertion point might
17505 // be the last block of a more nested EH region, because the new block will be inserted after the insertion
17506 // point, and will not extend the more nested EH region. For example:
17513 // | |--- |--- BB05
17515 // |----------------- BB07
17517 // for regionIndex==try3, putInTryRegion==true, we might return BB05, even though BB05 will have a try index
17518 // for try1 (the most nested 'try' region the block is in). That's because when we insert after BB05, the new
17519 // block will be in the correct, desired EH region, since try1 and try2 regions will not be extended to include
17520 // the inserted block. Furthermore, for regionIndex==try2, putInTryRegion==true, we can also return BB05. In this
17521 // case, when the new block is inserted, the try1 region remains the same, but we need extend region 'try2' to
17522 // include the inserted block. (We also need to check all parent regions as well, just in case any parent regions
17523 // also end on the same block, in which case we would also need to extend the parent regions. This is standard
17524 // procedure when inserting a block at the end of an EH region.)
17526 // If nearBlk is non-nullptr then we return the closest block after nearBlk that will work best.
17528 // We try to find a block in the appropriate region that is not a fallthrough block, so we can insert after it
17529 // without the need to insert a jump around the inserted block.
17531 // Note that regionIndex is numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is, "0" is
17532 // "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
17535 // regionIndex - the region index where the new block will be inserted. Zero means entire method;
17536 // non-zero means either a "try" or a "handler" region, depending on what putInTryRegion says.
17537 // putInTryRegion - 'true' to put the block in the 'try' region corresponding to 'regionIndex', 'false'
17538 // to put the block in the handler region. Should be 'true' if regionIndex==0.
17539 // startBlk - start block of range to search.
17540 // endBlk - end block of range to search (don't include this block in the range). Can be nullptr to indicate
17541 // the end of the function.
17542 // nearBlk - If non-nullptr, try to find an insertion location closely after this block. If nullptr, we insert
17543 // at the best location found towards the end of the acceptable block range.
17544 // jumpBlk - When nearBlk is set, this can be set to the block which jumps to bNext->bbNext (TODO: need to review
17546 // runRarely - true if the block being inserted is expected to be rarely run. This helps determine
17547 // the best place to put the new block, by putting in a place that has the same 'rarely run' characteristic.
17550 // A block with the desired characteristics, so the new block will be inserted after this one.
17551 // If there is no suitable location, return nullptr. This should basically never happen.
17553 BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex,
17554 bool putInTryRegion,
17555 BasicBlock* startBlk,
17556 BasicBlock* endBlk,
17557 BasicBlock* nearBlk,
17558 BasicBlock* jumpBlk,
17561 noway_assert(startBlk != nullptr);
17562 noway_assert(startBlk != endBlk);
17563 noway_assert((regionIndex == 0 && putInTryRegion) || // Search in the main method
17564 (putInTryRegion && regionIndex > 0 &&
17565 startBlk->bbTryIndex == regionIndex) || // Search in the specified try region
17566 (!putInTryRegion && regionIndex > 0 &&
17567 startBlk->bbHndIndex == regionIndex)); // Search in the specified handler region
17570 // Assert that startBlk precedes endBlk in the block list.
17571 // We don't want to use bbNum to assert this condition, as we cannot depend on the block numbers being
17572 // sequential at all times.
17573 for (BasicBlock* b = startBlk; b != endBlk; b = b->bbNext)
17575 assert(b != nullptr); // We reached the end of the block list, but never found endBlk.
17579 JITDUMP("fgFindInsertPoint(regionIndex=%u, putInTryRegion=%s, startBlk=BB%02u, endBlk=BB%02u, nearBlk=BB%02u, "
17580 "jumpBlk=BB%02u, runRarely=%s)\n",
17581 regionIndex, dspBool(putInTryRegion), startBlk->bbNum, (endBlk == nullptr) ? 0 : endBlk->bbNum,
17582 (nearBlk == nullptr) ? 0 : nearBlk->bbNum, (jumpBlk == nullptr) ? 0 : jumpBlk->bbNum, dspBool(runRarely));
17584 bool insertingIntoFilter = false;
17585 if (!putInTryRegion)
17587 EHblkDsc* const dsc = ehGetDsc(regionIndex - 1);
17588 insertingIntoFilter = dsc->HasFilter() && (startBlk == dsc->ebdFilter) && (endBlk == dsc->ebdHndBeg);
17591 bool reachedNear = false; // Have we reached 'nearBlk' in our search? If not, we'll keep searching.
17592 bool inFilter = false; // Are we in a filter region that we need to skip?
17593 BasicBlock* bestBlk =
17594 nullptr; // Set to the best insertion point we've found so far that meets all the EH requirements.
17595 BasicBlock* goodBlk =
17596 nullptr; // Set to an acceptable insertion point that we'll use if we don't find a 'best' option.
17599 if (nearBlk != nullptr)
17601 // Does the nearBlk precede the startBlk?
17602 for (blk = nearBlk; blk != nullptr; blk = blk->bbNext)
17604 if (blk == startBlk)
17606 reachedNear = true;
17609 else if (blk == endBlk)
17616 for (blk = startBlk; blk != endBlk; blk = blk->bbNext)
17618 // The only way (blk == nullptr) could be true is if the caller passed an endBlk that preceded startBlk in the
17619 // block list, or if endBlk isn't in the block list at all. In DEBUG, we'll instead hit the similar
17620 // well-formedness assert earlier in this function.
17621 noway_assert(blk != nullptr);
17623 if (blk == nearBlk)
17625 reachedNear = true;
17628 if (blk->bbCatchTyp == BBCT_FILTER)
17630 // Record the fact that we entered a filter region, so we don't insert into filters...
17631 // Unless the caller actually wanted the block inserted in this exact filter region.
17632 if (!insertingIntoFilter || (blk != startBlk))
17637 else if (blk->bbCatchTyp == BBCT_FILTER_HANDLER)
17639 // Record the fact that we exited a filter region.
17643 // Don't insert a block inside this filter region.
17649 // Note that the new block will be inserted AFTER "blk". We check to make sure that doing so
17650 // would put the block in the correct EH region. We make an assumption here that you can
17651 // ALWAYS insert the new block before "endBlk" (that is, at the end of the search range)
17652 // and be in the correct EH region. This is must be guaranteed by the caller (as it is by
17653 // fgNewBBinRegion(), which passes the search range as an exact EH region block range).
17654 // Because of this assumption, we only check the EH information for blocks before the last block.
17655 if (blk->bbNext != endBlk)
17657 // We are in the middle of the search range. We can't insert the new block in
17658 // an inner try or handler region. We can, however, set the insertion
17659 // point to the last block of an EH try/handler region, if the enclosing
17660 // region is the region we wish to insert in. (Since multiple regions can
17661 // end at the same block, we need to search outwards, checking that the
17662 // block is the last block of every EH region out to the region we want
17663 // to insert in.) This is especially useful for putting a call-to-finally
17664 // block on AMD64 immediately after its corresponding 'try' block, so in the
17665 // common case, we'll just fall through to it. For example:
17668 // BB02 -- first block of try
17670 // BB04 -- last block of try
17671 // BB05 -- first block of finally
17673 // BB07 -- last block of handler
17676 // Assume there is only one try/finally, so BB01 and BB08 are in the "main function".
17677 // For AMD64 call-to-finally, we'll want to insert the BBJ_CALLFINALLY in
17678 // the main function, immediately after BB04. This allows us to do that.
17680 if (!fgCheckEHCanInsertAfterBlock(blk, regionIndex, putInTryRegion))
17682 // Can't insert here.
17687 // Look for an insert location:
17688 // 1. We want blocks that don't end with a fall through,
17689 // 2. Also, when blk equals nearBlk we may want to insert here.
17690 if (!blk->bbFallsThrough() || (blk == nearBlk))
17692 bool updateBestBlk = true; // We will probably update the bestBlk
17694 // If blk falls through then we must decide whether to use the nearBlk
17696 if (blk->bbFallsThrough())
17698 noway_assert(blk == nearBlk);
17699 if (jumpBlk != nullptr)
17701 updateBestBlk = fgIsBetterFallThrough(blk, jumpBlk);
17705 updateBestBlk = false;
17709 // If we already have a best block, see if the 'runRarely' flags influences
17710 // our choice. If we want a runRarely insertion point, and the existing best
17711 // block is run rarely but the current block isn't run rarely, then don't
17712 // update the best block.
17713 // TODO-CQ: We should also handle the reverse case, where runRarely is false (we
17714 // want a non-rarely-run block), but bestBlock->isRunRarely() is true. In that
17715 // case, we should update the block, also. Probably what we want is:
17716 // (bestBlk->isRunRarely() != runRarely) && (blk->isRunRarely() == runRarely)
17717 if (updateBestBlk && (bestBlk != nullptr) && runRarely && bestBlk->isRunRarely() && !blk->isRunRarely())
17719 updateBestBlk = false;
17724 // We found a 'best' insertion location, so save it away.
17727 // If we've reached nearBlk, we've satisfied all the criteria,
17734 // If we haven't reached nearBlk, keep looking for a 'best' location, just
17735 // in case we'll find one at or after nearBlk. If no nearBlk was specified,
17736 // we prefer inserting towards the end of the given range, so keep looking
17737 // for more acceptable insertion locations.
17741 // No need to update goodBlk after we have set bestBlk, but we could still find a better
17742 // bestBlk, so keep looking.
17743 if (bestBlk != nullptr)
17748 // Set the current block as a "good enough" insertion point, if it meets certain criteria.
17749 // We'll return this block if we don't find a "best" block in the search range. The block
17750 // can't be a BBJ_CALLFINALLY of a BBJ_CALLFINALLY/BBJ_ALWAYS pair (since we don't want
17751 // to insert anything between these two blocks). Otherwise, we can use it. However,
17752 // if we'd previously chosen a BBJ_COND block, then we'd prefer the "good" block to be
17753 // something else. We keep updating it until we've reached the 'nearBlk', to push it as
17754 // close to endBlk as possible.
17755 if (!blk->isBBCallAlwaysPair())
17757 if (goodBlk == nullptr)
17761 else if ((goodBlk->bbJumpKind == BBJ_COND) || (blk->bbJumpKind != BBJ_COND))
17763 if ((blk == nearBlk) || !reachedNear)
17771 // If we didn't find a non-fall_through block, then insert at the last good block.
17773 if (bestBlk == nullptr)
17780 #if defined(JIT32_GCENCODER)
17781 // If we are inserting into a filter and the best block is the end of the filter region, we need to
17782 // insert after its predecessor instead: the JIT32 GC encoding used by the x86 CLR ABI states that the
17783 // terminal block of a filter region is its exit block. If the filter region consists of a single block,
17784 // a new block cannot be inserted without either splitting the single block before inserting a new block
17785 // or inserting the new block before the single block and updating the filter description such that the
17786 // inserted block is marked as the entry block for the filter. Becuase this sort of split can be complex
17787 // (especially given that it must ensure that the liveness of the exception object is properly tracked),
17788 // we avoid this situation by never generating single-block filters on x86 (see impPushCatchArgOnStack).
17789 if (insertingIntoFilter && (bestBlk == endBlk->bbPrev))
17791 assert(bestBlk != startBlk);
17792 bestBlk = bestBlk->bbPrev;
17794 #endif // defined(JIT32_GCENCODER)
17799 //------------------------------------------------------------------------
17800 // Creates a new BasicBlock and inserts it in a specific EH region, given by 'tryIndex', 'hndIndex', and 'putInFilter'.
17802 // If 'putInFilter' it true, then the block is inserted in the filter region given by 'hndIndex'. In this case, tryIndex
17803 // must be a less nested EH region (that is, tryIndex > hndIndex).
17805 // Otherwise, the block is inserted in either the try region or the handler region, depending on which one is the inner
17806 // region. In other words, if the try region indicated by tryIndex is nested in the handler region indicated by
17808 // then the new BB will be created in the try region. Vice versa.
17810 // Note that tryIndex and hndIndex are numbered the same as BasicBlock::bbTryIndex and BasicBlock::bbHndIndex, that is,
17811 // "0" is "main method" and otherwise is +1 from normal, so we can call, e.g., ehGetDsc(tryIndex - 1).
17813 // To be more specific, this function will create a new BB in one of the following 5 regions (if putInFilter is false):
17814 // 1. When tryIndex = 0 and hndIndex = 0:
17815 // The new BB will be created in the method region.
17816 // 2. When tryIndex != 0 and hndIndex = 0:
17817 // The new BB will be created in the try region indicated by tryIndex.
17818 // 3. When tryIndex == 0 and hndIndex != 0:
17819 // The new BB will be created in the handler region indicated by hndIndex.
17820 // 4. When tryIndex != 0 and hndIndex != 0 and tryIndex < hndIndex:
17821 // In this case, the try region is nested inside the handler region. Therefore, the new BB will be created
17822 // in the try region indicated by tryIndex.
17823 // 5. When tryIndex != 0 and hndIndex != 0 and tryIndex > hndIndex:
17824 // In this case, the handler region is nested inside the try region. Therefore, the new BB will be created
17825 // in the handler region indicated by hndIndex.
17827 // Note that if tryIndex != 0 and hndIndex != 0 then tryIndex must not be equal to hndIndex (this makes sense because
17828 // if they are equal, you are asking to put the new block in both the try and handler, which is impossible).
17830 // The BasicBlock will not be inserted inside an EH region that is more nested than the requested tryIndex/hndIndex
17831 // region (so the function is careful to skip more nested EH regions when searching for a place to put the new block).
17833 // This function cannot be used to insert a block as the first block of any region. It always inserts a block after
17834 // an existing block in the given region.
17836 // If nearBlk is nullptr, or the block is run rarely, then the new block is assumed to be run rarely.
17839 // jumpKind - the jump kind of the new block to create.
17840 // tryIndex - the try region to insert the new block in, described above. This must be a number in the range
17841 // [0..compHndBBtabCount].
17842 // hndIndex - the handler region to insert the new block in, described above. This must be a number in the range
17843 // [0..compHndBBtabCount].
17844 // nearBlk - insert the new block closely after this block, if possible. If nullptr, put the new block anywhere
17845 // in the requested region.
17846 // putInFilter - put the new block in the filter region given by hndIndex, as described above.
17847 // runRarely - 'true' if the new block is run rarely.
17848 // insertAtEnd - 'true' if the block should be inserted at the end of the region. Note: this is currently only
17849 // implemented when inserting into the main function (not into any EH region).
17854 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17857 BasicBlock* nearBlk,
17858 bool putInFilter /* = false */,
17859 bool runRarely /* = false */,
17860 bool insertAtEnd /* = false */)
17862 assert(tryIndex <= compHndBBtabCount);
17863 assert(hndIndex <= compHndBBtabCount);
17865 /* afterBlk is the block which will precede the newBB */
17866 BasicBlock* afterBlk;
17868 // start and end limit for inserting the block
17869 BasicBlock* startBlk = nullptr;
17870 BasicBlock* endBlk = nullptr;
17872 bool putInTryRegion = true;
17873 unsigned regionIndex = 0;
17875 // First, figure out which region (the "try" region or the "handler" region) to put the newBB in.
17876 if ((tryIndex == 0) && (hndIndex == 0))
17878 assert(!putInFilter);
17880 endBlk = fgEndBBAfterMainFunction(); // don't put new BB in funclet region
17882 if (insertAtEnd || (nearBlk == nullptr))
17884 /* We'll just insert the block at the end of the method, before the funclets */
17886 afterBlk = fgLastBBInMainFunction();
17887 goto _FoundAfterBlk;
17891 // We'll search through the entire method
17892 startBlk = fgFirstBB;
17895 noway_assert(regionIndex == 0);
17899 noway_assert(tryIndex > 0 || hndIndex > 0);
17900 PREFIX_ASSUME(tryIndex <= compHndBBtabCount);
17901 PREFIX_ASSUME(hndIndex <= compHndBBtabCount);
17903 // Decide which region to put in, the "try" region or the "handler" region.
17906 noway_assert(hndIndex > 0);
17907 putInTryRegion = false;
17909 else if (hndIndex == 0)
17911 noway_assert(tryIndex > 0);
17912 noway_assert(putInTryRegion);
17913 assert(!putInFilter);
17917 noway_assert(tryIndex > 0 && hndIndex > 0 && tryIndex != hndIndex);
17918 putInTryRegion = (tryIndex < hndIndex);
17921 if (putInTryRegion)
17923 // Try region is the inner region.
17924 // In other words, try region must be nested inside the handler region.
17925 noway_assert(hndIndex == 0 || bbInHandlerRegions(hndIndex - 1, ehGetDsc(tryIndex - 1)->ebdTryBeg));
17926 assert(!putInFilter);
17930 // Handler region is the inner region.
17931 // In other words, handler region must be nested inside the try region.
17932 noway_assert(tryIndex == 0 || bbInTryRegions(tryIndex - 1, ehGetDsc(hndIndex - 1)->ebdHndBeg));
17935 // Figure out the start and end block range to search for an insertion location. Pick the beginning and
17936 // ending blocks of the target EH region (the 'endBlk' is one past the last block of the EH region, to make
17937 // loop iteration easier). Note that, after funclets have been created (for FEATURE_EH_FUNCLETS),
17938 // this linear block range will not include blocks of handlers for try/handler clauses nested within
17939 // this EH region, as those blocks have been extracted as funclets. That is ok, though, because we don't
17940 // want to insert a block in any nested EH region.
17942 if (putInTryRegion)
17944 // We will put the newBB in the try region.
17945 EHblkDsc* ehDsc = ehGetDsc(tryIndex - 1);
17946 startBlk = ehDsc->ebdTryBeg;
17947 endBlk = ehDsc->ebdTryLast->bbNext;
17948 regionIndex = tryIndex;
17950 else if (putInFilter)
17952 // We will put the newBB in the filter region.
17953 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17954 startBlk = ehDsc->ebdFilter;
17955 endBlk = ehDsc->ebdHndBeg;
17956 regionIndex = hndIndex;
17960 // We will put the newBB in the handler region.
17961 EHblkDsc* ehDsc = ehGetDsc(hndIndex - 1);
17962 startBlk = ehDsc->ebdHndBeg;
17963 endBlk = ehDsc->ebdHndLast->bbNext;
17964 regionIndex = hndIndex;
17967 noway_assert(regionIndex > 0);
17970 // Now find the insertion point.
17971 afterBlk = fgFindInsertPoint(regionIndex, putInTryRegion, startBlk, endBlk, nearBlk, nullptr, runRarely);
17975 /* We have decided to insert the block after 'afterBlk'. */
17976 noway_assert(afterBlk != nullptr);
17978 JITDUMP("fgNewBBinRegion(jumpKind=%u, tryIndex=%u, hndIndex=%u, putInFilter=%s, runRarely=%s, insertAtEnd=%s): "
17979 "inserting after BB%02u\n",
17980 jumpKind, tryIndex, hndIndex, dspBool(putInFilter), dspBool(runRarely), dspBool(insertAtEnd),
17983 return fgNewBBinRegionWorker(jumpKind, afterBlk, regionIndex, putInTryRegion);
17986 //------------------------------------------------------------------------
17987 // Creates a new BasicBlock and inserts it in the same EH region as 'srcBlk'.
17989 // See the implementation of fgNewBBinRegion() used by this one for more notes.
17992 // jumpKind - the jump kind of the new block to create.
17993 // srcBlk - insert the new block in the same EH region as this block, and closely after it if possible.
17998 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind,
17999 BasicBlock* srcBlk,
18000 bool runRarely /* = false */,
18001 bool insertAtEnd /* = false */)
18003 assert(srcBlk != nullptr);
18005 const unsigned tryIndex = srcBlk->bbTryIndex;
18006 const unsigned hndIndex = srcBlk->bbHndIndex;
18007 bool putInFilter = false;
18009 // Check to see if we need to put the new block in a filter. We do if srcBlk is in a filter.
18010 // This can only be true if there is a handler index, and the handler region is more nested than the
18011 // try region (if any). This is because no EH regions can be nested within a filter.
18012 if (BasicBlock::ehIndexMaybeMoreNested(hndIndex, tryIndex))
18014 assert(hndIndex != 0); // If hndIndex is more nested, we must be in some handler!
18015 putInFilter = ehGetDsc(hndIndex - 1)->InFilterRegionBBRange(srcBlk);
18018 return fgNewBBinRegion(jumpKind, tryIndex, hndIndex, srcBlk, putInFilter, runRarely, insertAtEnd);
18021 //------------------------------------------------------------------------
18022 // Creates a new BasicBlock and inserts it at the end of the function.
18024 // See the implementation of fgNewBBinRegion() used by this one for more notes.
18027 // jumpKind - the jump kind of the new block to create.
18032 BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind)
18034 return fgNewBBinRegion(jumpKind, 0, 0, nullptr, /* putInFilter */ false, /* runRarely */ false,
18035 /* insertAtEnd */ true);
18038 //------------------------------------------------------------------------
18039 // Creates a new BasicBlock, and inserts it after 'afterBlk'.
18041 // The block cannot be inserted into a more nested try/handler region than that specified by 'regionIndex'.
18042 // (It is given exactly 'regionIndex'.) Thus, the parameters must be passed to ensure proper EH nesting
18043 // rules are followed.
18046 // jumpKind - the jump kind of the new block to create.
18047 // afterBlk - insert the new block after this one.
18048 // regionIndex - the block will be put in this EH region.
18049 // putInTryRegion - If true, put the new block in the 'try' region corresponding to 'regionIndex', and
18050 // set its handler index to the most nested handler region enclosing that 'try' region.
18051 // Otherwise, put the block in the handler region specified by 'regionIndex', and set its 'try'
18052 // index to the most nested 'try' region enclosing that handler region.
18057 BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind,
18058 BasicBlock* afterBlk,
18059 unsigned regionIndex,
18060 bool putInTryRegion)
18062 /* Insert the new block */
18063 BasicBlock* afterBlkNext = afterBlk->bbNext;
18064 (void)afterBlkNext; // prevent "unused variable" error from GCC
18065 BasicBlock* newBlk = fgNewBBafter(jumpKind, afterBlk, false);
18067 if (putInTryRegion)
18069 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
18070 newBlk->bbTryIndex = (unsigned short)regionIndex;
18071 newBlk->bbHndIndex = bbFindInnermostHandlerRegionContainingTryRegion(regionIndex);
18075 newBlk->bbTryIndex = bbFindInnermostTryRegionContainingHandlerRegion(regionIndex);
18076 noway_assert(regionIndex <= MAX_XCPTN_INDEX);
18077 newBlk->bbHndIndex = (unsigned short)regionIndex;
18080 // We're going to compare for equal try regions (to handle the case of 'mutually protect'
18081 // regions). We need to save off the current try region, otherwise we might change it
18082 // before it gets compared later, thereby making future comparisons fail.
18084 BasicBlock* newTryBeg;
18085 BasicBlock* newTryLast;
18086 (void)ehInitTryBlockRange(newBlk, &newTryBeg, &newTryLast);
18091 for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
18093 // Is afterBlk at the end of a try region?
18094 if (HBtab->ebdTryLast == afterBlk)
18096 noway_assert(afterBlkNext == newBlk->bbNext);
18098 bool extendTryRegion = false;
18099 if (newBlk->hasTryIndex())
18101 // We're adding a block after the last block of some try region. Do
18102 // we extend the try region to include the block, or not?
18103 // If the try region is exactly the same as the try region
18104 // associated with the new block (based on the block's try index,
18105 // which represents the innermost try the block is a part of), then
18107 // If the try region is a "parent" try region -- an enclosing try region
18108 // that has the same last block as the new block's try region -- then
18109 // we also extend. For example:
18114 // } /* 2 */ } /* 1 */
18115 // This example is meant to indicate that both try regions 1 and 2 end at
18116 // the same block, and we're extending 2. Thus, we must also extend 1. If we
18117 // only extended 2, we would break proper nesting. (Dev11 bug 137967)
18119 extendTryRegion = HBtab->ebdIsSameTry(newTryBeg, newTryLast) || bbInTryRegions(XTnum, newBlk);
18122 // Does newBlk extend this try region?
18123 if (extendTryRegion)
18125 // Yes, newBlk extends this try region
18127 // newBlk is the now the new try last block
18128 fgSetTryEnd(HBtab, newBlk);
18132 // Is afterBlk at the end of a handler region?
18133 if (HBtab->ebdHndLast == afterBlk)
18135 noway_assert(afterBlkNext == newBlk->bbNext);
18137 // Does newBlk extend this handler region?
18138 bool extendHndRegion = false;
18139 if (newBlk->hasHndIndex())
18141 // We're adding a block after the last block of some handler region. Do
18142 // we extend the handler region to include the block, or not?
18143 // If the handler region is exactly the same as the handler region
18144 // associated with the new block (based on the block's handler index,
18145 // which represents the innermost handler the block is a part of), then
18147 // If the handler region is a "parent" handler region -- an enclosing
18148 // handler region that has the same last block as the new block's handler
18149 // region -- then we also extend. For example:
18154 // } /* 2 */ } /* 1 */
18155 // This example is meant to indicate that both handler regions 1 and 2 end at
18156 // the same block, and we're extending 2. Thus, we must also extend 1. If we
18157 // only extended 2, we would break proper nesting. (Dev11 bug 372051)
18159 extendHndRegion = bbInHandlerRegions(XTnum, newBlk);
18162 if (extendHndRegion)
18164 // Yes, newBlk extends this handler region
18166 // newBlk is now the last block of the handler.
18167 fgSetHndEnd(HBtab, newBlk);
18172 /* If afterBlk falls through, we insert a jump around newBlk */
18173 fgConnectFallThrough(afterBlk, newBlk->bbNext);
18176 fgVerifyHandlerTab();
18182 /*****************************************************************************
18186 unsigned Compiler::acdHelper(SpecialCodeKind codeKind)
18190 case SCK_RNGCHK_FAIL:
18191 return CORINFO_HELP_RNGCHKFAIL;
18192 case SCK_ARG_EXCPN:
18193 return CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
18194 case SCK_ARG_RNG_EXCPN:
18195 return CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
18196 case SCK_DIV_BY_ZERO:
18197 return CORINFO_HELP_THROWDIVZERO;
18198 case SCK_ARITH_EXCPN:
18199 return CORINFO_HELP_OVERFLOW;
18201 assert(!"Bad codeKind");
18206 /*****************************************************************************
18208 * Find/create an added code entry associated with the given block and with
18212 BasicBlock* Compiler::fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth)
18214 // Record that the code will call a THROW_HELPER
18215 // so on Windows Amd64 we can allocate the 4 outgoing
18216 // arg slots on the stack frame if there are no other calls.
18217 compUsesThrowHelper = true;
18219 if (!fgUseThrowHelperBlocks())
18224 const static BBjumpKinds jumpKinds[] = {
18225 BBJ_NONE, // SCK_NONE
18226 BBJ_THROW, // SCK_RNGCHK_FAIL
18227 BBJ_ALWAYS, // SCK_PAUSE_EXEC
18228 BBJ_THROW, // SCK_DIV_BY_ZERO
18229 BBJ_THROW, // SCK_ARITH_EXCP, SCK_OVERFLOW
18230 BBJ_THROW, // SCK_ARG_EXCPN
18231 BBJ_THROW, // SCK_ARG_RNG_EXCPN
18234 noway_assert(sizeof(jumpKinds) == SCK_COUNT); // sanity check
18236 /* First look for an existing entry that matches what we're looking for */
18238 AddCodeDsc* add = fgFindExcptnTarget(kind, refData);
18240 if (add) // found it
18242 #if !FEATURE_FIXED_OUT_ARGS
18243 // If different range checks happen at different stack levels,
18244 // they can't all jump to the same "call @rngChkFailed" AND have
18245 // frameless methods, as the rngChkFailed may need to unwind the
18246 // stack, and we have to be able to report the stack level.
18248 // The following check forces most methods that reference an
18249 // array element in a parameter list to have an EBP frame,
18250 // this restriction could be removed with more careful code
18251 // generation for BBJ_THROW (i.e. range check failed).
18253 // For Linux/x86, we possibly need to insert stack alignment adjustment
18254 // before the first stack argument pushed for every call. But we
18255 // don't know what the stack alignment adjustment will be when
18256 // we morph a tree that calls fgAddCodeRef(), so the stack depth
18257 // number will be incorrect. For now, simply force all functions with
18258 // these helpers to have EBP frames. It might be possible to make
18259 // this less conservative. E.g., for top-level (not nested) calls
18260 // without stack args, the stack pointer hasn't changed and stack
18261 // depth will be known to be zero. Or, figure out a way to update
18262 // or generate all required helpers after all stack alignment
18263 // has been added, and the stack level at each call to fgAddCodeRef()
18264 // is known, or can be recalculated.
18265 CLANG_FORMAT_COMMENT_ANCHOR;
18267 #if defined(UNIX_X86_ABI)
18268 codeGen->setFrameRequired(true);
18269 codeGen->setFramePointerRequiredGCInfo(true);
18270 #else // !defined(UNIX_X86_ABI)
18271 if (add->acdStkLvl != stkDepth)
18273 codeGen->setFrameRequired(true);
18274 codeGen->setFramePointerRequiredGCInfo(true);
18276 #endif // !defined(UNIX_X86_ABI)
18277 #endif // !FEATURE_FIXED_OUT_ARGS
18279 return add->acdDstBlk;
18282 /* We have to allocate a new entry and prepend it to the list */
18284 add = new (this, CMK_Unknown) AddCodeDsc;
18285 add->acdData = refData;
18286 add->acdKind = kind;
18287 add->acdNext = fgAddCodeList;
18288 #if !FEATURE_FIXED_OUT_ARGS
18289 add->acdStkLvl = stkDepth;
18290 add->acdStkLvlInit = false;
18291 #endif // !FEATURE_FIXED_OUT_ARGS
18293 fgAddCodeList = add;
18295 /* Create the target basic block */
18297 BasicBlock* newBlk;
18299 newBlk = add->acdDstBlk = fgNewBBinRegion(jumpKinds[kind], srcBlk, /* runRarely */ true, /* insertAtEnd */ true);
18301 add->acdDstBlk->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
18306 const char* msgWhere = "";
18307 if (!srcBlk->hasTryIndex() && !srcBlk->hasHndIndex())
18309 msgWhere = "non-EH region";
18311 else if (!srcBlk->hasTryIndex())
18313 msgWhere = "handler";
18315 else if (!srcBlk->hasHndIndex())
18319 else if (srcBlk->getTryIndex() < srcBlk->getHndIndex())
18325 msgWhere = "handler";
18331 case SCK_RNGCHK_FAIL:
18332 msg = " for RNGCHK_FAIL";
18334 case SCK_PAUSE_EXEC:
18335 msg = " for PAUSE_EXEC";
18337 case SCK_DIV_BY_ZERO:
18338 msg = " for DIV_BY_ZERO";
18341 msg = " for OVERFLOW";
18343 case SCK_ARG_EXCPN:
18344 msg = " for ARG_EXCPN";
18346 case SCK_ARG_RNG_EXCPN:
18347 msg = " for ARG_RNG_EXCPN";
18354 printf("\nfgAddCodeRef - Add BB in %s%s, new block %s, stkDepth is %d\n", msgWhere, msg,
18355 add->acdDstBlk->dspToString(), stkDepth);
18360 newBlk->bbTgtStkDepth = stkDepth;
18363 /* Mark the block as added by the compiler and not removable by future flow
18364 graph optimizations. Note that no bbJumpDest points to these blocks. */
18366 newBlk->bbFlags |= BBF_IMPORTED;
18367 newBlk->bbFlags |= BBF_DONT_REMOVE;
18369 /* Remember that we're adding a new basic block */
18371 fgAddCodeModf = true;
18372 fgRngChkThrowAdded = true;
18374 /* Now figure out what code to insert */
18377 int helper = CORINFO_HELP_UNDEF;
18381 case SCK_RNGCHK_FAIL:
18382 helper = CORINFO_HELP_RNGCHKFAIL;
18385 case SCK_DIV_BY_ZERO:
18386 helper = CORINFO_HELP_THROWDIVZERO;
18389 case SCK_ARITH_EXCPN:
18390 helper = CORINFO_HELP_OVERFLOW;
18391 noway_assert(SCK_OVERFLOW == SCK_ARITH_EXCPN);
18394 case SCK_ARG_EXCPN:
18395 helper = CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
18398 case SCK_ARG_RNG_EXCPN:
18399 helper = CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
18402 // case SCK_PAUSE_EXEC:
18403 // noway_assert(!"add code to pause exec");
18406 noway_assert(!"unexpected code addition kind");
18410 noway_assert(helper != CORINFO_HELP_UNDEF);
18412 // Add the appropriate helper call.
18413 tree = gtNewHelperCallNode(helper, TYP_VOID);
18415 // There are no args here but fgMorphArgs has side effects
18416 // such as setting the outgoing arg area (which is necessary
18417 // on AMD if there are any calls).
18418 tree = fgMorphArgs(tree);
18420 // Store the tree in the new basic block.
18421 assert(!srcBlk->isEmpty());
18422 if (!srcBlk->IsLIR())
18424 fgInsertStmtAtEnd(newBlk, fgNewStmtFromTree(tree));
18428 LIR::AsRange(newBlk).InsertAtEnd(LIR::SeqTree(this, tree));
18431 return add->acdDstBlk;
18434 /*****************************************************************************
18435 * Finds the block to jump to, to throw a given kind of exception
18436 * We maintain a cache of one AddCodeDsc for each kind, to make searching fast.
18437 * Note : Each block uses the same (maybe shared) block as the jump target for
18438 * a given type of exception
18441 Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData)
18443 assert(fgUseThrowHelperBlocks());
18444 if (!(fgExcptnTargetCache[kind] && // Try the cached value first
18445 fgExcptnTargetCache[kind]->acdData == refData))
18447 // Too bad, have to search for the jump target for the exception
18449 AddCodeDsc* add = nullptr;
18451 for (add = fgAddCodeList; add != nullptr; add = add->acdNext)
18453 if (add->acdData == refData && add->acdKind == kind)
18459 fgExcptnTargetCache[kind] = add; // Cache it
18462 return fgExcptnTargetCache[kind];
18465 /*****************************************************************************
18467 * The given basic block contains an array range check; return the label this
18468 * range check is to jump to upon failure.
18471 BasicBlock* Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind)
18476 printf("*** Computing fgRngChkTarget for block BB%02u to stkDepth %d\n", block->bbNum, stkDepth);
18477 if (!block->IsLIR())
18479 gtDispTree(compCurStmt);
18484 /* We attach the target label to the containing try block (if any) */
18485 noway_assert(!compIsForInlining());
18486 return fgAddCodeRef(block, bbThrowIndex(block), kind, stkDepth);
18489 // Sequences the tree.
18490 // prevTree is what gtPrev of the first node in execution order gets set to.
18491 // Returns the first node (execution order) in the sequenced tree.
18492 GenTree* Compiler::fgSetTreeSeq(GenTree* tree, GenTree* prevTree, bool isLIR)
18496 if (prevTree == nullptr)
18500 fgTreeSeqLst = prevTree;
18502 fgTreeSeqBeg = nullptr;
18503 fgSetTreeSeqHelper(tree, isLIR);
18505 GenTree* result = prevTree->gtNext;
18506 if (prevTree == &list)
18508 list.gtNext->gtPrev = nullptr;
18514 /*****************************************************************************
18516 * Assigns sequence numbers to the given tree and its sub-operands, and
18517 * threads all the nodes together via the 'gtNext' and 'gtPrev' fields.
18518 * Uses 'global' - fgTreeSeqLst
18521 void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR)
18526 noway_assert(tree);
18527 assert(!IsUninitialized(tree));
18528 noway_assert(tree->gtOper != GT_STMT);
18530 /* Figure out what kind of a node we have */
18532 oper = tree->OperGet();
18533 kind = tree->OperKind();
18535 /* Is this a leaf/constant node? */
18537 if (kind & (GTK_CONST | GTK_LEAF))
18539 fgSetTreeSeqFinish(tree, isLIR);
18543 // Special handling for dynamic block ops.
18544 if (tree->OperIsDynBlkOp())
18546 GenTreeDynBlk* dynBlk;
18548 GenTree* asg = tree;
18549 if (tree->OperGet() == GT_ASG)
18551 dynBlk = tree->gtGetOp1()->AsDynBlk();
18552 src = tree->gtGetOp2();
18556 dynBlk = tree->AsDynBlk();
18557 src = dynBlk->Data();
18560 GenTree* sizeNode = dynBlk->gtDynamicSize;
18561 GenTree* dstAddr = dynBlk->Addr();
18562 if (dynBlk->gtEvalSizeFirst)
18564 fgSetTreeSeqHelper(sizeNode, isLIR);
18566 if (tree->gtFlags & GTF_REVERSE_OPS)
18568 fgSetTreeSeqHelper(src, isLIR);
18569 fgSetTreeSeqHelper(dstAddr, isLIR);
18573 fgSetTreeSeqHelper(dstAddr, isLIR);
18574 fgSetTreeSeqHelper(src, isLIR);
18576 if (!dynBlk->gtEvalSizeFirst)
18578 fgSetTreeSeqHelper(sizeNode, isLIR);
18580 fgSetTreeSeqFinish(dynBlk, isLIR);
18581 if (asg != nullptr)
18583 fgSetTreeSeqFinish(asg, isLIR);
18588 /* Is it a 'simple' unary/binary operator? */
18590 if (kind & GTK_SMPOP)
18592 GenTree* op1 = tree->gtOp.gtOp1;
18593 GenTree* op2 = tree->gtGetOp2IfPresent();
18595 // Special handling for GT_LIST
18596 if (tree->OperGet() == GT_LIST)
18598 // First, handle the list items, which will be linked in forward order.
18599 // As we go, we will link the GT_LIST nodes in reverse order - we will number
18600 // them and update fgTreeSeqList in a subsequent traversal.
18601 GenTree* nextList = tree;
18602 GenTree* list = nullptr;
18603 while (nextList != nullptr && nextList->OperGet() == GT_LIST)
18606 GenTree* listItem = list->gtOp.gtOp1;
18607 fgSetTreeSeqHelper(listItem, isLIR);
18608 nextList = list->gtOp.gtOp2;
18609 if (nextList != nullptr)
18611 nextList->gtNext = list;
18613 list->gtPrev = nextList;
18615 // Next, handle the GT_LIST nodes.
18616 // Note that fgSetTreeSeqFinish() sets the gtNext to null, so we need to capture the nextList
18617 // before we call that method.
18621 assert(list != nullptr);
18623 nextList = list->gtNext;
18624 fgSetTreeSeqFinish(list, isLIR);
18625 } while (list != tree);
18629 /* Special handling for AddrMode */
18630 if (tree->OperIsAddrMode())
18632 bool reverse = ((tree->gtFlags & GTF_REVERSE_OPS) != 0);
18635 assert(op1 != nullptr && op2 != nullptr);
18636 fgSetTreeSeqHelper(op2, isLIR);
18638 if (op1 != nullptr)
18640 fgSetTreeSeqHelper(op1, isLIR);
18642 if (!reverse && op2 != nullptr)
18644 fgSetTreeSeqHelper(op2, isLIR);
18647 fgSetTreeSeqFinish(tree, isLIR);
18651 /* Check for a nilary operator */
18653 if (op1 == nullptr)
18655 noway_assert(op2 == nullptr);
18656 fgSetTreeSeqFinish(tree, isLIR);
18660 /* Is this a unary operator?
18661 * Although UNARY GT_IND has a special structure */
18663 if (oper == GT_IND)
18665 /* Visit the indirection first - op2 may point to the
18666 * jump Label for array-index-out-of-range */
18668 fgSetTreeSeqHelper(op1, isLIR);
18669 fgSetTreeSeqFinish(tree, isLIR);
18673 /* Now this is REALLY a unary operator */
18677 /* Visit the (only) operand and we're done */
18679 fgSetTreeSeqHelper(op1, isLIR);
18680 fgSetTreeSeqFinish(tree, isLIR);
18685 For "real" ?: operators, we make sure the order is
18695 if (oper == GT_QMARK)
18697 noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
18699 fgSetTreeSeqHelper(op1, isLIR);
18700 // Here, for the colon, the sequence does not actually represent "order of evaluation":
18701 // one or the other of the branches is executed, not both. Still, to make debugging checks
18702 // work, we want the sequence to match the order in which we'll generate code, which means
18703 // "else" clause then "then" clause.
18704 fgSetTreeSeqHelper(op2->AsColon()->ElseNode(), isLIR);
18705 fgSetTreeSeqHelper(op2, isLIR);
18706 fgSetTreeSeqHelper(op2->AsColon()->ThenNode(), isLIR);
18708 fgSetTreeSeqFinish(tree, isLIR);
18712 if (oper == GT_COLON)
18714 fgSetTreeSeqFinish(tree, isLIR);
18718 /* This is a binary operator */
18720 if (tree->gtFlags & GTF_REVERSE_OPS)
18722 fgSetTreeSeqHelper(op2, isLIR);
18723 fgSetTreeSeqHelper(op1, isLIR);
18727 fgSetTreeSeqHelper(op1, isLIR);
18728 fgSetTreeSeqHelper(op2, isLIR);
18731 fgSetTreeSeqFinish(tree, isLIR);
18735 /* See what kind of a special operator we have here */
18740 noway_assert(tree->gtField.gtFldObj == nullptr);
18745 /* We'll evaluate the 'this' argument value first */
18746 if (tree->gtCall.gtCallObjp)
18748 fgSetTreeSeqHelper(tree->gtCall.gtCallObjp, isLIR);
18751 /* We'll evaluate the arguments next, left to right
18752 * NOTE: setListOrder needs cleanup - eliminate the #ifdef afterwards */
18754 if (tree->gtCall.gtCallArgs)
18756 fgSetTreeSeqHelper(tree->gtCall.gtCallArgs, isLIR);
18759 /* Evaluate the temp register arguments list
18760 * This is a "hidden" list and its only purpose is to
18761 * extend the life of temps until we make the call */
18763 if (tree->gtCall.gtCallLateArgs)
18765 fgSetTreeSeqHelper(tree->gtCall.gtCallLateArgs, isLIR);
18768 if ((tree->gtCall.gtCallType == CT_INDIRECT) && (tree->gtCall.gtCallCookie != nullptr))
18770 fgSetTreeSeqHelper(tree->gtCall.gtCallCookie, isLIR);
18773 if (tree->gtCall.gtCallType == CT_INDIRECT)
18775 fgSetTreeSeqHelper(tree->gtCall.gtCallAddr, isLIR);
18778 if (tree->gtCall.gtControlExpr)
18780 fgSetTreeSeqHelper(tree->gtCall.gtControlExpr, isLIR);
18787 fgSetTreeSeqHelper(tree->gtArrElem.gtArrObj, isLIR);
18790 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
18792 fgSetTreeSeqHelper(tree->gtArrElem.gtArrInds[dim], isLIR);
18797 case GT_ARR_OFFSET:
18798 fgSetTreeSeqHelper(tree->gtArrOffs.gtOffset, isLIR);
18799 fgSetTreeSeqHelper(tree->gtArrOffs.gtIndex, isLIR);
18800 fgSetTreeSeqHelper(tree->gtArrOffs.gtArrObj, isLIR);
18804 // Evaluate the trees left to right
18805 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpLocation, isLIR);
18806 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpValue, isLIR);
18807 fgSetTreeSeqHelper(tree->gtCmpXchg.gtOpComparand, isLIR);
18810 case GT_ARR_BOUNDS_CHECK:
18811 #ifdef FEATURE_SIMD
18813 #endif // FEATURE_SIMD
18814 #ifdef FEATURE_HW_INTRINSICS
18815 case GT_HW_INTRINSIC_CHK:
18816 #endif // FEATURE_HW_INTRINSICS
18817 // Evaluate the trees left to right
18818 fgSetTreeSeqHelper(tree->gtBoundsChk.gtIndex, isLIR);
18819 fgSetTreeSeqHelper(tree->gtBoundsChk.gtArrLen, isLIR);
18822 case GT_STORE_DYN_BLK:
18824 noway_assert(!"DYN_BLK nodes should be sequenced as a special case");
18827 case GT_INDEX_ADDR:
18828 // Evaluate the index first, then the array address
18829 assert((tree->gtFlags & GTF_REVERSE_OPS) != 0);
18830 fgSetTreeSeqHelper(tree->AsIndexAddr()->Index(), isLIR);
18831 fgSetTreeSeqHelper(tree->AsIndexAddr()->Arr(), isLIR);
18837 noway_assert(!"unexpected operator");
18842 fgSetTreeSeqFinish(tree, isLIR);
18845 void Compiler::fgSetTreeSeqFinish(GenTree* tree, bool isLIR)
18847 // If we are sequencing for LIR:
18848 // - Clear the reverse ops flag
18849 // - If we are processing a node that does not appear in LIR, do not add it to the list.
18852 tree->gtFlags &= ~GTF_REVERSE_OPS;
18854 if ((tree->OperGet() == GT_LIST) || (tree->OperGet() == GT_ARGPLACE) ||
18855 (tree->OperGet() == GT_FIELD_LIST && !tree->AsFieldList()->IsFieldListHead()))
18861 /* Append to the node list */
18865 tree->gtSeqNum = fgTreeSeqNum;
18869 printf("SetTreeOrder: ");
18870 printTreeID(fgTreeSeqLst);
18871 printf(" followed by ");
18877 fgTreeSeqLst->gtNext = tree;
18878 tree->gtNext = nullptr;
18879 tree->gtPrev = fgTreeSeqLst;
18880 fgTreeSeqLst = tree;
18882 /* Remember the very first node */
18886 fgTreeSeqBeg = tree;
18887 assert(tree->gtSeqNum == 1);
18891 /*****************************************************************************
18893 * Figure out the order in which operators should be evaluated, along with
18894 * other information (such as the register sets trashed by each subtree).
18895 * Also finds blocks that need GC polls and inserts them as needed.
18898 void Compiler::fgSetBlockOrder()
18903 printf("*************** In fgSetBlockOrder()\n");
18908 BasicBlock::s_nMaxTrees = 0;
18911 /* Walk the basic blocks to assign sequence numbers */
18913 /* If we don't compute the doms, then we never mark blocks as loops. */
18914 if (fgDomsComputed)
18916 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18918 /* If this block is a loop header, mark it appropriately */
18920 if (block->isLoopHead())
18922 fgMarkLoopHead(block);
18926 // only enable fully interruptible code for if we're hijacking.
18927 else if (GCPOLL_NONE == opts.compGCPollType)
18929 /* If we don't have the dominators, use an abbreviated test for fully interruptible. If there are
18930 * any back edges, check the source and destination blocks to see if they're GC Safe. If not, then
18931 * go fully interruptible. */
18933 /* XXX Mon 1/21/2008
18934 * Wouldn't it be nice to have a block iterator that can do this loop?
18936 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18938 // true if the edge is forward, or if it is a back edge and either the source and dest are GC safe.
18939 #define EDGE_IS_GC_SAFE(src, dst) \
18940 (((src)->bbNum < (dst)->bbNum) || (((src)->bbFlags | (dst)->bbFlags) & BBF_GC_SAFE_POINT))
18942 bool partiallyInterruptible = true;
18943 switch (block->bbJumpKind)
18947 partiallyInterruptible = EDGE_IS_GC_SAFE(block, block->bbJumpDest);
18953 jumpCnt = block->bbJumpSwt->bbsCount;
18954 BasicBlock** jumpPtr;
18955 jumpPtr = block->bbJumpSwt->bbsDstTab;
18959 partiallyInterruptible &= EDGE_IS_GC_SAFE(block, *jumpPtr);
18960 } while (++jumpPtr, --jumpCnt);
18968 if (!partiallyInterruptible)
18971 // The GC encoding for fully interruptible methods does not
18972 // support more than 1023 pushed arguments, so we can't set
18973 // genInterruptible here when we have 1024 or more pushed args
18975 if (compCanEncodePtrArgCntMax())
18977 genInterruptible = true;
18981 #undef EDGE_IS_GC_SAFE
18985 if (!fgGCPollsCreated)
18990 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
18993 #if FEATURE_FASTTAILCALL
18994 #ifndef JIT32_GCENCODER
18995 if (block->endsWithTailCallOrJmp(this, true) && optReachWithoutCall(fgFirstBB, block))
18997 // We have a tail call that is reachable without making any other
18998 // 'normal' call that would have counted as a GC Poll. If we were
18999 // using polls, all return blocks meeting this criteria would have
19000 // already added polls and then marked as being GC safe
19001 // (BBF_GC_SAFE_POINT). Thus we can only reach here when *NOT*
19002 // using GC polls, but instead relying on the JIT to generate
19003 // fully-interruptible code.
19004 noway_assert(GCPOLL_NONE == opts.compGCPollType);
19006 // This tail call might combine with other tail calls to form a
19007 // loop. Thus we need to either add a poll, or make the method
19008 // fully interruptible. I chose the later because that's what
19010 genInterruptible = true;
19012 #endif // !JIT32_GCENCODER
19013 #endif // FEATURE_FASTTAILCALL
19015 fgSetBlockOrder(block);
19018 /* Remember that now the tree list is threaded */
19020 fgStmtListThreaded = true;
19025 printf("The biggest BB has %4u tree nodes\n", BasicBlock::s_nMaxTrees);
19027 fgDebugCheckLinks();
19031 /*****************************************************************************/
19033 void Compiler::fgSetStmtSeq(GenTree* tree)
19035 GenTree list; // helper node that we use to start the StmtList
19036 // It's located in front of the first node in the list
19038 noway_assert(tree->gtOper == GT_STMT);
19040 /* Assign numbers and next/prev links for this tree */
19043 fgTreeSeqLst = &list;
19044 fgTreeSeqBeg = nullptr;
19046 fgSetTreeSeqHelper(tree->gtStmt.gtStmtExpr, false);
19048 /* Record the address of the first node */
19050 tree->gtStmt.gtStmtList = fgTreeSeqBeg;
19054 if (list.gtNext->gtPrev != &list)
19057 printTreeID(&list);
19058 printf(" != list.next->prev ");
19059 printTreeID(list.gtNext->gtPrev);
19066 for (temp = list.gtNext, last = &list; temp; last = temp, temp = temp->gtNext)
19068 if (temp->gtPrev != last)
19071 printf("->gtPrev = ");
19072 printTreeID(temp->gtPrev);
19073 printf(", but last = ");
19080 gtDispTree(tree->gtStmt.gtStmtExpr);
19083 for (GenTree* bad = &list; bad; bad = bad->gtNext)
19085 printf(" entry at ");
19088 printTreeID(bad->gtPrev);
19090 printTreeID(bad->gtNext);
19095 noway_assert(!"Badly linked tree");
19101 /* Fix the first node's 'prev' link */
19103 noway_assert(list.gtNext->gtPrev == &list);
19104 list.gtNext->gtPrev = nullptr;
19107 /* Keep track of the highest # of tree nodes */
19109 if (BasicBlock::s_nMaxTrees < fgTreeSeqNum)
19111 BasicBlock::s_nMaxTrees = fgTreeSeqNum;
19116 /*****************************************************************************/
19118 void Compiler::fgSetBlockOrder(BasicBlock* block)
19122 tree = block->bbTreeList;
19130 fgSetStmtSeq(tree);
19132 /* Are there any more trees in this basic block? */
19134 if (tree->gtNext == nullptr)
19136 /* last statement in the tree list */
19137 noway_assert(block->lastStmt() == tree);
19142 if (block->bbTreeList == tree)
19144 /* first statement in the list */
19145 noway_assert(tree->gtPrev->gtNext == nullptr);
19149 noway_assert(tree->gtPrev->gtNext == tree);
19152 noway_assert(tree->gtNext->gtPrev == tree);
19155 tree = tree->gtNext;
19159 #ifdef LEGACY_BACKEND
19160 //------------------------------------------------------------------------
19161 // fgOrderBlockOps: Get the execution order for a block assignment
19164 // tree - The block assignment
19165 // reg0 - The register for the destination
19166 // reg1 - The register for the source
19167 // reg2 - The register for the size
19168 // opsPtr - An array of 3 GenTree*'s, an out argument for the operands, in order
19169 // regsPtr - An array of three regMaskTP - an out argument for the registers, in order
19172 // The return values go into the arrays that are passed in, and provide the
19173 // operands and associated registers, in execution order.
19176 // This method is somewhat convoluted in order to preserve old behavior from when
19177 // block assignments had their dst and src in a GT_LIST as op1, and their size as op2.
19178 // The old tree was like this:
19181 // GT_LIST [size/clsHnd]
19183 // [dest] [val/src]
19185 // The new tree looks like this:
19188 // blk/obj [val/src]
19190 // [destAddr] [*size/clsHnd] *only for GT_DYN_BLK
19192 // For the (usual) case of GT_BLK or GT_OBJ, the size is always "evaluated" (i.e.
19193 // instantiated into a register) last. In those cases, the GTF_REVERSE_OPS flag
19194 // on the assignment works as usual.
19195 // In order to preserve previous possible orderings, the order for evaluating
19196 // the size of a GT_DYN_BLK node is controlled by its gtEvalSizeFirst flag. If
19197 // that is set, the size is evaluated first, and then the src and dst are evaluated
19198 // according to the GTF_REVERSE_OPS flag on the assignment.
19200 void Compiler::fgOrderBlockOps(GenTree* tree,
19204 GenTree** opsPtr, // OUT
19205 regMaskTP* regsPtr) // OUT
19207 assert(tree->OperIsBlkOp());
19209 GenTreeBlk* destBlk = tree->gtOp.gtOp1->AsBlk();
19210 GenTree* destAddr = destBlk->Addr();
19211 GenTree* srcPtrOrVal = tree->gtOp.gtOp2;
19212 if (tree->OperIsCopyBlkOp())
19214 assert(srcPtrOrVal->OperIsIndir());
19215 srcPtrOrVal = srcPtrOrVal->AsIndir()->Addr();
19218 assert(destAddr != nullptr);
19219 assert(srcPtrOrVal != nullptr);
19221 GenTree* ops[3] = {
19222 destAddr, // Dest address
19223 srcPtrOrVal, // Val / Src address
19224 nullptr // Size of block
19227 regMaskTP regs[3] = {reg0, reg1, reg2};
19229 static int blockOpsOrder[4][3] =
19230 // destBlk->gtEvalSizeFirst | tree->gtFlags
19232 // -------------------------+----------------------------
19233 {0, 1, 2}, // false | -
19234 {2, 0, 1}, // true | -
19235 {1, 0, 2}, // false | GTF_REVERSE_OPS
19236 {2, 1, 0} // true | GTF_REVERSE_OPS
19239 int orderNum = ((tree->gtFlags & GTF_REVERSE_OPS) == 0) ? 0 : 2;
19240 if (destBlk->OperIs(GT_DYN_BLK))
19242 GenTreeDynBlk* const dynBlk = destBlk->AsDynBlk();
19243 if (dynBlk->gtEvalSizeFirst)
19247 ops[2] = dynBlk->gtDynamicSize;
19250 assert(orderNum < 4);
19252 int* order = blockOpsOrder[orderNum];
19254 PREFIX_ASSUME(order != NULL);
19256 // Fill in the OUT arrays according to the order we have selected
19258 opsPtr[0] = ops[order[0]];
19259 opsPtr[1] = ops[order[1]];
19260 opsPtr[2] = ops[order[2]];
19262 regsPtr[0] = regs[order[0]];
19263 regsPtr[1] = regs[order[1]];
19264 regsPtr[2] = regs[order[2]];
19266 #endif // LEGACY_BACKEND
19268 //------------------------------------------------------------------------
19269 // fgGetFirstNode: Get the first node in the tree, in execution order
19272 // tree - The top node of the tree of interest
19275 // The first node in execution order, that belongs to tree.
19278 // 'tree' must either be a leaf, or all of its constituent nodes must be contiguous
19279 // in execution order.
19280 // TODO-Cleanup: Add a debug-only method that verifies this.
19283 GenTree* Compiler::fgGetFirstNode(GenTree* tree)
19285 GenTree* child = tree;
19286 while (child->NumChildren() > 0)
19288 if (child->OperIsBinary() && child->IsReverseOp())
19290 child = child->GetChild(1);
19294 child = child->GetChild(0);
19300 // Examine the bbTreeList and return the estimated code size for this block
19301 unsigned Compiler::fgGetCodeEstimate(BasicBlock* block)
19303 unsigned costSz = 0; // estimate of blocks code size cost
19305 switch (block->bbJumpKind)
19311 case BBJ_EHCATCHRET:
19316 case BBJ_CALLFINALLY:
19323 costSz = 1; // We place a int3 after the code for a throw block
19325 case BBJ_EHFINALLYRET:
19326 case BBJ_EHFILTERRET:
19329 case BBJ_RETURN: // return from method
19333 noway_assert(!"Bad bbJumpKind");
19337 GenTree* tree = block->FirstNonPhiDef();
19342 noway_assert(tree->gtOper == GT_STMT);
19344 if (tree->gtCostSz < MAX_COST)
19346 costSz += tree->gtCostSz;
19350 // We could walk the tree to find out the real gtCostSz,
19351 // but just using MAX_COST for this trees code size works OK
19352 costSz += tree->gtCostSz;
19355 tree = tree->gtNext;
19362 #if DUMP_FLOWGRAPHS
19364 struct escapeMapping_t
19370 // clang-format off
19371 static escapeMapping_t s_EscapeFileMapping[] =
19384 static escapeMapping_t s_EscapeMapping[] =
19394 const char* Compiler::fgProcessEscapes(const char* nameIn, escapeMapping_t* map)
19396 const char* nameOut = nameIn;
19397 unsigned lengthOut;
19400 bool subsitutionRequired;
19404 subsitutionRequired = false;
19406 while (*pChar != '\0')
19410 while (map[index].ch != 0)
19412 if (*pChar == map[index].ch)
19421 subsitutionRequired = true;
19422 lengthOut += (unsigned)strlen(map[index].sub);
19431 if (subsitutionRequired)
19433 char* newName = (char*)compGetMem(lengthOut, CMK_DebugOnly);
19437 while (*pChar != '\0')
19441 while (map[index].ch != 0)
19443 if (*pChar == map[index].ch)
19452 strcpy(pDest, map[index].sub);
19453 pDest += strlen(map[index].sub);
19462 nameOut = (const char*)newName;
19468 static void fprintfDouble(FILE* fgxFile, double value)
19470 assert(value >= 0.0);
19472 if ((value >= 0.010) || (value == 0.0))
19474 fprintf(fgxFile, "\"%7.3f\"", value);
19476 else if (value >= 0.00010)
19478 fprintf(fgxFile, "\"%7.5f\"", value);
19482 fprintf(fgxFile, "\"%7E\"", value);
19486 //------------------------------------------------------------------------
19487 // fgOpenFlowGraphFile: Open a file to dump either the xml or dot format flow graph
19490 // wbDontClose - A boolean out argument that indicates whether the caller should close the file
19491 // phase - A phase identifier to indicate which phase is associated with the dump
19492 // type - A (wide) string indicating the type of dump, "dot" or "xml"
19495 // Opens a file to which a flowgraph can be dumped, whose name is based on the current
19498 FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type)
19501 LPCWSTR pattern = nullptr;
19502 LPCWSTR filename = nullptr;
19503 LPCWSTR pathname = nullptr;
19504 const char* escapedString;
19505 bool createDuplicateFgxFiles = true;
19508 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
19510 pattern = JitConfig.NgenDumpFg();
19511 filename = JitConfig.NgenDumpFgFile();
19512 pathname = JitConfig.NgenDumpFgDir();
19516 pattern = JitConfig.JitDumpFg();
19517 filename = JitConfig.JitDumpFgFile();
19518 pathname = JitConfig.JitDumpFgDir();
19522 if (fgBBcount <= 1)
19527 if (pattern == nullptr)
19532 if (wcslen(pattern) == 0)
19537 LPCWSTR phasePattern = JitConfig.JitDumpFgPhase();
19538 LPCWSTR phaseName = PhaseShortNames[phase];
19539 if (phasePattern == nullptr)
19541 if (phase != PHASE_DETERMINE_FIRST_COLD_BLOCK)
19546 else if (*phasePattern != W('*'))
19548 if (wcsstr(phasePattern, phaseName) == nullptr)
19554 if (*pattern != W('*'))
19556 bool hasColon = (wcschr(pattern, W(':')) != nullptr);
19560 const char* className = info.compClassName;
19561 if (*pattern == W('*'))
19567 while ((*pattern != W(':')) && (*pattern != W('*')))
19569 if (*pattern != *className)
19577 if (*pattern == W('*'))
19583 if (*className != 0)
19589 if (*pattern != W(':'))
19597 const char* methodName = info.compMethodName;
19598 if (*pattern == W('*'))
19604 while ((*pattern != 0) && (*pattern != W('*')))
19606 if (*pattern != *methodName)
19614 if (*pattern == W('*'))
19620 if (*methodName != 0)
19632 if (filename == nullptr)
19634 filename = W("default");
19637 if (wcscmp(filename, W("profiled")) == 0)
19639 if (fgFirstBB->hasProfileWeight())
19641 createDuplicateFgxFiles = true;
19642 goto ONE_FILE_PER_METHOD;
19649 if (wcscmp(filename, W("hot")) == 0)
19651 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
19654 createDuplicateFgxFiles = true;
19655 goto ONE_FILE_PER_METHOD;
19662 else if (wcscmp(filename, W("cold")) == 0)
19664 if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
19666 createDuplicateFgxFiles = true;
19667 goto ONE_FILE_PER_METHOD;
19674 else if (wcscmp(filename, W("jit")) == 0)
19676 if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
19678 createDuplicateFgxFiles = true;
19679 goto ONE_FILE_PER_METHOD;
19686 else if (wcscmp(filename, W("all")) == 0)
19688 createDuplicateFgxFiles = true;
19690 ONE_FILE_PER_METHOD:;
19692 escapedString = fgProcessEscapes(info.compFullName, s_EscapeFileMapping);
19693 size_t wCharCount = strlen(escapedString) + wcslen(phaseName) + 1 + strlen("~999") + wcslen(type) + 1;
19694 if (pathname != nullptr)
19696 wCharCount += wcslen(pathname) + 1;
19698 filename = (LPCWSTR)alloca(wCharCount * sizeof(WCHAR));
19699 if (pathname != nullptr)
19701 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S-%s.%s"), pathname, escapedString, phaseName, type);
19705 swprintf_s((LPWSTR)filename, wCharCount, W("%S.%s"), escapedString, type);
19707 fgxFile = _wfopen(filename, W("r")); // Check if this file already exists
19708 if (fgxFile != nullptr)
19710 // For Generic methods we will have both hot and cold versions
19711 if (createDuplicateFgxFiles == false)
19716 // Yes, this filename already exists, so create a different one by appending ~2, ~3, etc...
19717 for (int i = 2; i < 1000; i++)
19720 if (pathname != nullptr)
19722 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S~%d.%s"), pathname, escapedString, i, type);
19726 swprintf_s((LPWSTR)filename, wCharCount, W("%S~%d.%s"), escapedString, i, type);
19728 fgxFile = _wfopen(filename, W("r")); // Check if this file exists
19729 if (fgxFile == nullptr)
19734 // If we have already created 1000 files with this name then just fail
19735 if (fgxFile != nullptr)
19741 fgxFile = _wfopen(filename, W("a+"));
19742 *wbDontClose = false;
19744 else if (wcscmp(filename, W("stdout")) == 0)
19746 fgxFile = jitstdout;
19747 *wbDontClose = true;
19749 else if (wcscmp(filename, W("stderr")) == 0)
19752 *wbDontClose = true;
19756 LPCWSTR origFilename = filename;
19757 size_t wCharCount = wcslen(origFilename) + wcslen(type) + 2;
19758 if (pathname != nullptr)
19760 wCharCount += wcslen(pathname) + 1;
19762 filename = (LPCWSTR)alloca(wCharCount * sizeof(WCHAR));
19763 if (pathname != nullptr)
19765 swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%s.%s"), pathname, origFilename, type);
19769 swprintf_s((LPWSTR)filename, wCharCount, W("%s.%s"), origFilename, type);
19771 fgxFile = _wfopen(filename, W("a+"));
19772 *wbDontClose = false;
19778 //------------------------------------------------------------------------
19779 // fgDumpFlowGraph: Dump the xml or dot format flow graph, if enabled for this phase.
19782 // phase - A phase identifier to indicate which phase is associated with the dump,
19783 // i.e. which phase has just completed.
19786 // True iff a flowgraph has been dumped.
19789 // The xml dumps are the historical mechanism for dumping the flowgraph.
19790 // The dot format can be viewed by:
19791 // - Graphviz (http://www.graphviz.org/)
19792 // - The command "C:\Program Files (x86)\Graphviz2.38\bin\dot.exe" -Tsvg -oFoo.svg -Kdot Foo.dot
19793 // will produce a Foo.svg file that can be opened with any svg-capable browser (e.g. IE).
19794 // - http://rise4fun.com/Agl/
19795 // - Cut and paste the graph from your .dot file, replacing the digraph on the page, and then click the play
19797 // - It will show a rotating '/' and then render the graph in the browser.
19798 // MSAGL has also been open-sourced to https://github.com/Microsoft/automatic-graph-layout.git.
19800 // Here are the config values that control it:
19801 // COMPlus_JitDumpFg A string (ala the COMPlus_JitDump string) indicating what methods to dump flowgraphs
19803 // COMPlus_JitDumpFgDir A path to a directory into which the flowgraphs will be dumped.
19804 // COMPlus_JitDumpFgFile The filename to use. The default is "default.[xml|dot]".
19805 // Note that the new graphs will be appended to this file if it already exists.
19806 // COMPlus_JitDumpFgPhase Phase(s) after which to dump the flowgraph.
19807 // Set to the short name of a phase to see the flowgraph after that phase.
19808 // Leave unset to dump after COLD-BLK (determine first cold block) or set to * for all
19810 // COMPlus_JitDumpFgDot Set to non-zero to emit Dot instead of Xml Flowgraph dump. (Default is xml format.)
19812 bool Compiler::fgDumpFlowGraph(Phases phase)
19814 bool result = false;
19815 bool dontClose = false;
19816 bool createDotFile = false;
19817 if (JitConfig.JitDumpFgDot())
19819 createDotFile = true;
19822 FILE* fgxFile = fgOpenFlowGraphFile(&dontClose, phase, createDotFile ? W("dot") : W("fgx"));
19824 if (fgxFile == nullptr)
19828 bool validWeights = fgHaveValidEdgeWeights;
19829 unsigned calledCount = max(fgCalledCount, BB_UNITY_WEIGHT) / BB_UNITY_WEIGHT;
19830 double weightDivisor = (double)(calledCount * BB_UNITY_WEIGHT);
19831 const char* escapedString;
19832 const char* regionString = "NONE";
19834 if (info.compMethodInfo->regionKind == CORINFO_REGION_HOT)
19836 regionString = "HOT";
19838 else if (info.compMethodInfo->regionKind == CORINFO_REGION_COLD)
19840 regionString = "COLD";
19842 else if (info.compMethodInfo->regionKind == CORINFO_REGION_JIT)
19844 regionString = "JIT";
19849 fprintf(fgxFile, "digraph %s\n{\n", info.compMethodName);
19850 fprintf(fgxFile, "/* Method %d, after phase %s */", Compiler::jitTotalMethodCompiled, PhaseNames[phase]);
19854 fprintf(fgxFile, "<method");
19856 escapedString = fgProcessEscapes(info.compFullName, s_EscapeMapping);
19857 fprintf(fgxFile, "\n name=\"%s\"", escapedString);
19859 escapedString = fgProcessEscapes(info.compClassName, s_EscapeMapping);
19860 fprintf(fgxFile, "\n className=\"%s\"", escapedString);
19862 escapedString = fgProcessEscapes(info.compMethodName, s_EscapeMapping);
19863 fprintf(fgxFile, "\n methodName=\"%s\"", escapedString);
19864 fprintf(fgxFile, "\n ngenRegion=\"%s\"", regionString);
19866 fprintf(fgxFile, "\n bytesOfIL=\"%d\"", info.compILCodeSize);
19867 fprintf(fgxFile, "\n localVarCount=\"%d\"", lvaCount);
19869 if (fgHaveProfileData())
19871 fprintf(fgxFile, "\n calledCount=\"%d\"", calledCount);
19872 fprintf(fgxFile, "\n profileData=\"true\"");
19874 if (compHndBBtabCount > 0)
19876 fprintf(fgxFile, "\n hasEHRegions=\"true\"");
19880 fprintf(fgxFile, "\n hasLoops=\"true\"");
19884 fprintf(fgxFile, "\n validEdgeWeights=\"true\"");
19885 if (!fgSlopUsedInEdgeWeights && !fgRangeUsedInEdgeWeights)
19887 fprintf(fgxFile, "\n exactEdgeWeights=\"true\"");
19890 if (fgFirstColdBlock != nullptr)
19892 fprintf(fgxFile, "\n firstColdBlock=\"%d\"", fgFirstColdBlock->bbNum);
19895 fprintf(fgxFile, ">");
19897 fprintf(fgxFile, "\n <blocks");
19898 fprintf(fgxFile, "\n blockCount=\"%d\"", fgBBcount);
19899 fprintf(fgxFile, ">");
19902 static const char* kindImage[] = {"EHFINALLYRET", "EHFILTERRET", "EHCATCHRET", "THROW", "RETURN", "NONE",
19903 "ALWAYS", "LEAVE", "CALLFINALLY", "COND", "SWITCH"};
19906 unsigned blockOrdinal;
19907 for (block = fgFirstBB, blockOrdinal = 1; block != nullptr; block = block->bbNext, blockOrdinal++)
19911 // Add constraint edges to try to keep nodes ordered.
19912 // It seems to work best if these edges are all created first.
19913 switch (block->bbJumpKind)
19917 assert(block->bbNext != nullptr);
19918 fprintf(fgxFile, " BB%02u -> BB%02u\n", block->bbNum, block->bbNext->bbNum);
19921 // These may or may not have an edge to the next block.
19922 // Add a transparent edge to keep nodes ordered.
19923 if (block->bbNext != nullptr)
19925 fprintf(fgxFile, " BB%02u -> BB%02u [arrowtail=none,color=transparent]\n", block->bbNum,
19926 block->bbNext->bbNum);
19932 fprintf(fgxFile, "\n <block");
19933 fprintf(fgxFile, "\n id=\"%d\"", block->bbNum);
19934 fprintf(fgxFile, "\n ordinal=\"%d\"", blockOrdinal);
19935 fprintf(fgxFile, "\n jumpKind=\"%s\"", kindImage[block->bbJumpKind]);
19936 if (block->hasTryIndex())
19938 fprintf(fgxFile, "\n inTry=\"%s\"", "true");
19940 if (block->hasHndIndex())
19942 fprintf(fgxFile, "\n inHandler=\"%s\"", "true");
19944 if ((fgFirstBB->hasProfileWeight()) && ((block->bbFlags & BBF_COLD) == 0))
19946 fprintf(fgxFile, "\n hot=\"true\"");
19948 if (block->bbFlags & (BBF_HAS_NEWOBJ | BBF_HAS_NEWARRAY))
19950 fprintf(fgxFile, "\n callsNew=\"true\"");
19952 if (block->bbFlags & BBF_LOOP_HEAD)
19954 fprintf(fgxFile, "\n loopHead=\"true\"");
19956 fprintf(fgxFile, "\n weight=");
19957 fprintfDouble(fgxFile, ((double)block->bbWeight) / weightDivisor);
19958 fprintf(fgxFile, "\n codeEstimate=\"%d\"", fgGetCodeEstimate(block));
19959 fprintf(fgxFile, "\n startOffset=\"%d\"", block->bbCodeOffs);
19960 fprintf(fgxFile, "\n endOffset=\"%d\"", block->bbCodeOffsEnd);
19961 fprintf(fgxFile, ">");
19962 fprintf(fgxFile, "\n </block>");
19966 if (!createDotFile)
19968 fprintf(fgxFile, "\n </blocks>");
19970 fprintf(fgxFile, "\n <edges");
19971 fprintf(fgxFile, "\n edgeCount=\"%d\"", fgEdgeCount);
19972 fprintf(fgxFile, ">");
19975 unsigned edgeNum = 1;
19976 BasicBlock* bTarget;
19977 for (bTarget = fgFirstBB; bTarget != nullptr; bTarget = bTarget->bbNext)
19979 double targetWeightDivisor;
19980 if (bTarget->bbWeight == BB_ZERO_WEIGHT)
19982 targetWeightDivisor = 1.0;
19986 targetWeightDivisor = (double)bTarget->bbWeight;
19990 for (edge = bTarget->bbPreds; edge != nullptr; edge = edge->flNext, edgeNum++)
19992 BasicBlock* bSource = edge->flBlock;
19993 double sourceWeightDivisor;
19994 if (bSource->bbWeight == BB_ZERO_WEIGHT)
19996 sourceWeightDivisor = 1.0;
20000 sourceWeightDivisor = (double)bSource->bbWeight;
20004 // Don't duplicate the edges we added above.
20005 if ((bSource->bbNum == (bTarget->bbNum - 1)) &&
20006 ((bSource->bbJumpKind == BBJ_NONE) || (bSource->bbJumpKind == BBJ_COND)))
20010 fprintf(fgxFile, " BB%02u -> BB%02u", bSource->bbNum, bTarget->bbNum);
20011 if ((bSource->bbNum > bTarget->bbNum))
20013 fprintf(fgxFile, "[arrowhead=normal,arrowtail=none,color=green]\n");
20017 fprintf(fgxFile, "\n");
20022 fprintf(fgxFile, "\n <edge");
20023 fprintf(fgxFile, "\n id=\"%d\"", edgeNum);
20024 fprintf(fgxFile, "\n source=\"%d\"", bSource->bbNum);
20025 fprintf(fgxFile, "\n target=\"%d\"", bTarget->bbNum);
20026 if (bSource->bbJumpKind == BBJ_SWITCH)
20028 if (edge->flDupCount >= 2)
20030 fprintf(fgxFile, "\n switchCases=\"%d\"", edge->flDupCount);
20032 if (bSource->bbJumpSwt->getDefault() == bTarget)
20034 fprintf(fgxFile, "\n switchDefault=\"true\"");
20039 unsigned edgeWeight = (edge->flEdgeWeightMin + edge->flEdgeWeightMax) / 2;
20040 fprintf(fgxFile, "\n weight=");
20041 fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor);
20043 if (edge->flEdgeWeightMin != edge->flEdgeWeightMax)
20045 fprintf(fgxFile, "\n minWeight=");
20046 fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMin) / weightDivisor);
20047 fprintf(fgxFile, "\n maxWeight=");
20048 fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMax) / weightDivisor);
20051 if (edgeWeight > 0)
20053 if (edgeWeight < bSource->bbWeight)
20055 fprintf(fgxFile, "\n out=");
20056 fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor);
20058 if (edgeWeight < bTarget->bbWeight)
20060 fprintf(fgxFile, "\n in=");
20061 fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor);
20066 if (!createDotFile)
20068 fprintf(fgxFile, ">");
20069 fprintf(fgxFile, "\n </edge>");
20075 fprintf(fgxFile, "}\n");
20079 fprintf(fgxFile, "\n </edges>");
20080 fprintf(fgxFile, "\n</method>\n");
20085 // fgxFile is jitstdout or stderr
20086 fprintf(fgxFile, "\n");
20096 #endif // DUMP_FLOWGRAPHS
20098 /*****************************************************************************/
20101 void Compiler::fgDispReach()
20103 printf("------------------------------------------------\n");
20104 printf("BBnum Reachable by \n");
20105 printf("------------------------------------------------\n");
20107 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
20109 printf("BB%02u : ", block->bbNum);
20110 BlockSetOps::Iter iter(this, block->bbReach);
20111 unsigned bbNum = 0;
20112 while (iter.NextElem(&bbNum))
20114 printf("BB%02u ", bbNum);
20120 void Compiler::fgDispDoms()
20122 // Don't bother printing this when we have a large number of BasicBlocks in the method
20123 if (fgBBcount > 256)
20128 printf("------------------------------------------------\n");
20129 printf("BBnum Dominated by\n");
20130 printf("------------------------------------------------\n");
20132 for (unsigned i = 1; i <= fgBBNumMax; ++i)
20134 BasicBlock* current = fgBBInvPostOrder[i];
20135 printf("BB%02u: ", current->bbNum);
20136 while (current != current->bbIDom)
20138 printf("BB%02u ", current->bbNum);
20139 current = current->bbIDom;
20145 /*****************************************************************************/
20147 void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 */)
20149 const unsigned __int64 flags = block->bbFlags;
20150 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
20151 int maxBlockNumWidth = CountDigits(bbNumMax);
20152 maxBlockNumWidth = max(maxBlockNumWidth, 2);
20153 int blockNumWidth = CountDigits(block->bbNum);
20154 blockNumWidth = max(blockNumWidth, 2);
20155 int blockNumPadding = maxBlockNumWidth - blockNumWidth;
20157 printf("%s %2u", block->dspToString(blockNumPadding), block->bbRefs);
20160 // Display EH 'try' region index
20163 if (block->hasTryIndex())
20165 printf(" %2u", block->getTryIndex());
20173 // Display EH handler region index
20176 if (block->hasHndIndex())
20178 printf(" %2u", block->getHndIndex());
20188 // Display block predecessor list
20192 if (fgCheapPredsValid)
20194 charCnt = block->dspCheapPreds();
20198 charCnt = block->dspPreds();
20203 printf("%*s", 19 - charCnt, "");
20209 // Display block weight
20212 if (block->isMaxBBWeight())
20218 BasicBlock::weight_t weight = block->getBBWeight(this);
20220 if (weight > 99999) // Is it going to be more than 6 characters?
20222 if (weight <= 99999 * BB_UNITY_WEIGHT)
20224 // print weight in this format ddddd.
20225 printf("%5u.", (weight + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT);
20227 else // print weight in terms of k (i.e. 156k )
20229 // print weight in this format dddddk
20230 BasicBlock::weight_t weightK = weight / 1000;
20231 printf("%5uk", (weightK + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT);
20234 else // print weight in this format ddd.dd
20236 printf("%6s", refCntWtd2str(weight));
20242 // Display optional IBC weight column.
20243 // Note that iColWidth includes one character for a leading space, if there is an IBC column.
20246 if (ibcColWidth > 0)
20248 if (block->hasProfileWeight())
20250 printf("%*u", ibcColWidth, block->bbWeight);
20254 // No IBC data. Just print spaces to align the column.
20255 printf("%*s", ibcColWidth, "");
20262 // Display block IL range
20265 block->dspBlockILRange();
20268 // Display block branch target
20271 if (flags & BBF_REMOVED)
20273 printf("[removed] ");
20277 switch (block->bbJumpKind)
20280 printf("-> BB%02u%*s ( cond )", block->bbJumpDest->bbNum,
20281 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20284 case BBJ_CALLFINALLY:
20285 printf("-> BB%02u%*s (callf )", block->bbJumpDest->bbNum,
20286 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20290 if (flags & BBF_KEEP_BBJ_ALWAYS)
20292 printf("-> BB%02u%*s (ALWAYS)", block->bbJumpDest->bbNum,
20293 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20297 printf("-> BB%02u%*s (always)", block->bbJumpDest->bbNum,
20298 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20303 printf("-> BB%02u%*s (leave )", block->bbJumpDest->bbNum,
20304 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20307 case BBJ_EHFINALLYRET:
20308 printf("%*s (finret)", maxBlockNumWidth - 2, "");
20311 case BBJ_EHFILTERRET:
20312 printf("%*s (fltret)", maxBlockNumWidth - 2, "");
20315 case BBJ_EHCATCHRET:
20316 printf("-> BB%02u%*s ( cret )", block->bbJumpDest->bbNum,
20317 maxBlockNumWidth - max(CountDigits(block->bbJumpDest->bbNum), 2), "");
20321 printf("%*s (throw )", maxBlockNumWidth - 2, "");
20325 printf("%*s (return)", maxBlockNumWidth - 2, "");
20329 printf("%*s ", maxBlockNumWidth - 2, "");
20336 jumpCnt = block->bbJumpSwt->bbsCount;
20337 BasicBlock** jumpTab;
20338 jumpTab = block->bbJumpSwt->bbsDstTab;
20343 printf("%cBB%02u", (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',', (*jumpTab)->bbNum);
20344 switchWidth += 1 /* space/comma */ + 2 /* BB */ + max(CountDigits((*jumpTab)->bbNum), 2);
20345 } while (++jumpTab, --jumpCnt);
20347 if (switchWidth < 7)
20349 printf("%*s", 8 - switchWidth, "");
20352 printf(" (switch)");
20360 // Display block EH region and type, including nesting indicator
20363 if (block->hasTryIndex())
20365 printf("T%d ", block->getTryIndex());
20372 if (block->hasHndIndex())
20374 printf("H%d ", block->getHndIndex());
20381 if (flags & BBF_FUNCLET_BEG)
20392 switch (block->bbCatchTyp)
20401 printf("finally ");
20408 case BBCT_FILTER_HANDLER:
20409 printf("filtHnd ");
20418 if (block->bbCatchTyp != BBCT_NONE)
20422 /* brace matching editor workaround to compensate for the preceding line: } */
20425 if (flags & BBF_TRY_BEG)
20427 // Output a brace for every try region that this block opens
20430 EHblkDsc* HBtabEnd;
20432 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
20434 if (HBtab->ebdTryBeg == block)
20438 /* brace matching editor workaround to compensate for the preceding line: } */
20444 EHblkDsc* HBtabEnd;
20446 for (HBtab = compHndBBtab, HBtabEnd = compHndBBtab + compHndBBtabCount; HBtab < HBtabEnd; HBtab++)
20448 if (HBtab->ebdTryLast == block)
20451 /* brace matching editor workaround to compensate for the following line: { */
20454 if (HBtab->ebdHndLast == block)
20457 /* brace matching editor workaround to compensate for the following line: { */
20460 if (HBtab->HasFilter() && block->bbNext == HBtab->ebdHndBeg)
20463 /* brace matching editor workaround to compensate for the following line: { */
20475 // Display block flags
20483 /****************************************************************************
20484 Dump blocks from firstBlock to lastBlock.
20487 void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees)
20491 // If any block has IBC data, we add an "IBC weight" column just before the 'IL range' column. This column is as
20492 // wide as necessary to accommodate all the various IBC weights. It's at least 4 characters wide, to accommodate
20493 // the "IBC" title and leading space.
20494 int ibcColWidth = 0;
20495 for (block = firstBlock; block != nullptr; block = block->bbNext)
20497 if (block->hasProfileWeight())
20499 int thisIbcWidth = CountDigits(block->bbWeight);
20500 ibcColWidth = max(ibcColWidth, thisIbcWidth);
20503 if (block == lastBlock)
20508 if (ibcColWidth > 0)
20510 ibcColWidth = max(ibcColWidth, 3) + 1; // + 1 for the leading space
20513 unsigned bbNumMax = compIsForInlining() ? impInlineInfo->InlinerCompiler->fgBBNumMax : fgBBNumMax;
20514 int maxBlockNumWidth = CountDigits(bbNumMax);
20515 maxBlockNumWidth = max(maxBlockNumWidth, 2);
20516 int padWidth = maxBlockNumWidth - 2; // Account for functions with a large number of blocks.
20518 // clang-format off
20521 printf("------%*s-------------------------------------%*s-----------------------%*s----------------------------------------\n",
20522 padWidth, "------------",
20523 ibcColWidth, "------------",
20524 maxBlockNumWidth, "----");
20525 printf("BBnum %*sBBid ref try hnd %s weight %*s%s [IL range] [jump]%*s [EH region] [flags]\n",
20527 fgCheapPredsValid ? "cheap preds" :
20528 (fgComputePredsDone ? "preds "
20530 ((ibcColWidth > 0) ? ibcColWidth - 3 : 0), "", // Subtract 3 for the width of "IBC", printed next.
20531 ((ibcColWidth > 0) ? "IBC"
20533 maxBlockNumWidth, ""
20535 printf("------%*s-------------------------------------%*s-----------------------%*s----------------------------------------\n",
20536 padWidth, "------------",
20537 ibcColWidth, "------------",
20538 maxBlockNumWidth, "----");
20542 for (block = firstBlock; block; block = block->bbNext)
20544 // First, do some checking on the bbPrev links
20547 if (block->bbPrev->bbNext != block)
20549 printf("bad prev link\n");
20552 else if (block != fgFirstBB)
20554 printf("bad prev link!\n");
20557 if (block == fgFirstColdBlock)
20559 printf("~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~"
20560 "~~~~~~~~~~~~~~~~\n",
20561 padWidth, "~~~~~~~~~~~~", ibcColWidth, "~~~~~~~~~~~~", maxBlockNumWidth, "~~~~");
20564 #if FEATURE_EH_FUNCLETS
20565 if (block == fgFirstFuncletBB)
20567 printf("++++++%*s+++++++++++++++++++++++++++++++++++++%*s+++++++++++++++++++++++%*s++++++++++++++++++++++++"
20568 "++++++++++++++++ funclets follow\n",
20569 padWidth, "++++++++++++", ibcColWidth, "++++++++++++", maxBlockNumWidth, "++++");
20571 #endif // FEATURE_EH_FUNCLETS
20573 fgTableDispBasicBlock(block, ibcColWidth);
20575 if (block == lastBlock)
20581 printf("------%*s-------------------------------------%*s-----------------------%*s--------------------------------"
20583 padWidth, "------------", ibcColWidth, "------------", maxBlockNumWidth, "----");
20587 fgDumpTrees(firstBlock, lastBlock);
20591 /*****************************************************************************/
20593 void Compiler::fgDispBasicBlocks(bool dumpTrees)
20595 fgDispBasicBlocks(fgFirstBB, nullptr, dumpTrees);
20598 /*****************************************************************************/
20599 // Increment the stmtNum and dump the tree using gtDispTree
20601 void Compiler::fgDumpStmtTree(GenTree* stmt, unsigned bbNum)
20603 compCurStmtNum++; // Increment the current stmtNum
20605 printf("\n***** BB%02u, stmt %d\n", bbNum, compCurStmtNum);
20607 if (fgOrder == FGOrderLinear || opts.compDbgInfo)
20613 gtDispTree(stmt->gtStmt.gtStmtExpr);
20617 //------------------------------------------------------------------------
20618 // Compiler::fgDumpBlock: dumps the contents of the given block to stdout.
20621 // block - The block to dump.
20623 void Compiler::fgDumpBlock(BasicBlock* block)
20625 printf("\n------------ ");
20626 block->dspBlockHeader(this);
20628 if (!block->IsLIR())
20630 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
20632 fgDumpStmtTree(stmt, block->bbNum);
20633 if (stmt == block->bbTreeList)
20635 block->bbStmtNum = compCurStmtNum; // Set the block->bbStmtNum
20641 gtDispRange(LIR::AsRange(block));
20645 /*****************************************************************************/
20646 // Walk the BasicBlock list calling fgDumpTree once per Stmt
20648 void Compiler::fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock)
20650 compCurStmtNum = 0; // Reset the current stmtNum
20652 /* Walk the basic blocks */
20654 // Note that typically we have already called fgDispBasicBlocks()
20655 // so we don't need to print the preds and succs again here
20657 for (BasicBlock* block = firstBlock; block; block = block->bbNext)
20659 fgDumpBlock(block);
20661 if (block == lastBlock)
20666 printf("\n---------------------------------------------------------------------------------------------------------"
20670 /*****************************************************************************
20671 * Try to create as many candidates for GTF_MUL_64RSLT as possible.
20672 * We convert 'intOp1*intOp2' into 'int(long(nop(intOp1))*long(intOp2))'.
20676 Compiler::fgWalkResult Compiler::fgStress64RsltMulCB(GenTree** pTree, fgWalkData* data)
20678 GenTree* tree = *pTree;
20679 Compiler* pComp = data->compiler;
20681 if (tree->gtOper != GT_MUL || tree->gtType != TYP_INT || (tree->gtOverflow()))
20683 return WALK_CONTINUE;
20687 if (pComp->verbose)
20689 printf("STRESS_64RSLT_MUL before:\n");
20690 pComp->gtDispTree(tree);
20694 // To ensure optNarrowTree() doesn't fold back to the original tree.
20695 tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, false, TYP_LONG);
20696 tree->gtOp.gtOp1 = pComp->gtNewOperNode(GT_NOP, TYP_LONG, tree->gtOp.gtOp1);
20697 tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, false, TYP_LONG);
20698 tree->gtOp.gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp2, false, TYP_LONG);
20699 tree->gtType = TYP_LONG;
20700 *pTree = pComp->gtNewCastNode(TYP_INT, tree, false, TYP_INT);
20703 if (pComp->verbose)
20705 printf("STRESS_64RSLT_MUL after:\n");
20706 pComp->gtDispTree(*pTree);
20710 return WALK_SKIP_SUBTREES;
20713 void Compiler::fgStress64RsltMul()
20715 if (!compStressCompile(STRESS_64RSLT_MUL, 20))
20720 fgWalkAllTreesPre(fgStress64RsltMulCB, (void*)this);
20723 // This variable is used to generate "traversal labels": one-time constants with which
20724 // we label basic blocks that are members of the basic block list, in order to have a
20725 // fast, high-probability test for membership in that list. Type is "volatile" because
20726 // it's incremented with an atomic operation, which wants a volatile type; "long" so that
20727 // wrap-around to 0 (which I think has the highest probability of accidental collision) is
20728 // postponed a *long* time.
20729 static volatile int bbTraverseLabel = 1;
20731 /*****************************************************************************
20733 * A DEBUG routine to check the consistency of the flowgraph,
20734 * i.e. bbNum, bbRefs, bbPreds have to be up to date.
20736 *****************************************************************************/
20738 void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRefs /* = true */)
20743 printf("*************** In fgDebugCheckBBlist\n");
20747 fgDebugCheckBlockLinks();
20749 if (fgBBcount > 10000 && expensiveDebugCheckLevel < 1)
20751 // The basic block checks are too expensive if there are too many blocks,
20752 // so give up unless we've been told to try hard.
20756 DWORD startTickCount = GetTickCount();
20759 BasicBlock* prevBlock;
20760 BasicBlock* blockPred;
20762 unsigned blockRefs;
20764 #if FEATURE_EH_FUNCLETS
20765 bool reachedFirstFunclet = false;
20766 if (fgFuncletsCreated)
20769 // Make sure that fgFirstFuncletBB is accurate.
20770 // It should be the first basic block in a handler region.
20772 if (fgFirstFuncletBB != nullptr)
20774 assert(fgFirstFuncletBB->hasHndIndex() == true);
20775 assert(fgFirstFuncletBB->bbFlags & BBF_FUNCLET_BEG);
20778 #endif // FEATURE_EH_FUNCLETS
20780 /* Check bbNum, bbRefs and bbPreds */
20781 // First, pick a traversal stamp, and label all the blocks with it.
20782 unsigned curTraversalStamp = unsigned(InterlockedIncrement((LONG*)&bbTraverseLabel));
20783 for (block = fgFirstBB; block; block = block->bbNext)
20785 block->bbTraversalStamp = curTraversalStamp;
20788 for (prevBlock = nullptr, block = fgFirstBB; block; prevBlock = block, block = block->bbNext)
20792 /* First basic block has countOfInEdges() >= 1 */
20794 if (block == fgFirstBB)
20796 noway_assert(block->countOfInEdges() >= 1);
20802 // Check that bbNum is sequential
20803 noway_assert(block->bbNext == nullptr || (block->bbNum + 1 == block->bbNext->bbNum));
20806 // If the block is a BBJ_COND, a BBJ_SWITCH or a
20807 // lowered GT_SWITCH_TABLE node then make sure it
20808 // ends with a conditional jump or a GT_SWITCH
20810 if (block->bbJumpKind == BBJ_COND)
20812 noway_assert(block->lastNode()->gtNext == nullptr && block->lastNode()->OperIsConditionalJump());
20814 else if (block->bbJumpKind == BBJ_SWITCH)
20816 #ifndef LEGACY_BACKEND
20817 noway_assert(block->lastNode()->gtNext == nullptr &&
20818 (block->lastNode()->gtOper == GT_SWITCH || block->lastNode()->gtOper == GT_SWITCH_TABLE));
20819 #else // LEGACY_BACKEND
20820 noway_assert(block->lastStmt()->gtNext == NULL && block->lastStmt()->gtStmtExpr->gtOper == GT_SWITCH);
20821 #endif // LEGACY_BACKEND
20823 else if (!(block->bbJumpKind == BBJ_ALWAYS || block->bbJumpKind == BBJ_RETURN))
20825 // this block cannot have a poll
20826 noway_assert(!(block->bbFlags & BBF_NEEDS_GCPOLL));
20829 if (block->bbCatchTyp == BBCT_FILTER)
20831 if (!fgCheapPredsValid) // Don't check cheap preds
20833 // A filter has no predecessors
20834 noway_assert(block->bbPreds == nullptr);
20838 #if FEATURE_EH_FUNCLETS
20839 if (fgFuncletsCreated)
20842 // There should be no handler blocks until
20843 // we get to the fgFirstFuncletBB block,
20844 // then every block should be a handler block
20846 if (!reachedFirstFunclet)
20848 if (block == fgFirstFuncletBB)
20850 assert(block->hasHndIndex() == true);
20851 reachedFirstFunclet = true;
20855 assert(block->hasHndIndex() == false);
20858 else // reachedFirstFunclet
20860 assert(block->hasHndIndex() == true);
20863 #endif // FEATURE_EH_FUNCLETS
20865 // Don't check cheap preds.
20866 for (pred = (fgCheapPredsValid ? nullptr : block->bbPreds); pred != nullptr;
20867 blockRefs += pred->flDupCount, pred = pred->flNext)
20869 assert(fgComputePredsDone); // If this isn't set, why do we have a preds list?
20871 /* make sure this pred is part of the BB list */
20873 blockPred = pred->flBlock;
20874 noway_assert(blockPred->bbTraversalStamp == curTraversalStamp);
20876 EHblkDsc* ehTryDsc = ehGetBlockTryDsc(block);
20877 if (ehTryDsc != nullptr)
20879 // You can jump to the start of a try
20880 if (ehTryDsc->ebdTryBeg == block)
20885 // You can jump within the same try region
20886 if (bbInTryRegions(block->getTryIndex(), blockPred))
20891 // The catch block can jump back into the middle of the try
20892 if (bbInCatchHandlerRegions(block, blockPred))
20897 // The end of a finally region is a BBJ_EHFINALLYRET block (during importing, BBJ_LEAVE) which
20898 // is marked as "returning" to the BBJ_ALWAYS block following the BBJ_CALLFINALLY
20899 // block that does a local call to the finally. This BBJ_ALWAYS is within
20900 // the try region protected by the finally (for x86, ARM), but that's ok.
20901 if (prevBlock->bbJumpKind == BBJ_CALLFINALLY && block->bbJumpKind == BBJ_ALWAYS &&
20902 blockPred->bbJumpKind == BBJ_EHFINALLYRET)
20907 printf("Jump into the middle of try region: BB%02u branches to BB%02u\n", blockPred->bbNum,
20909 noway_assert(!"Jump into middle of try region");
20914 EHblkDsc* ehHndDsc = ehGetBlockHndDsc(block);
20915 if (ehHndDsc != nullptr)
20917 // You can do a BBJ_EHFINALLYRET or BBJ_EHFILTERRET into a handler region
20918 if ((blockPred->bbJumpKind == BBJ_EHFINALLYRET) || (blockPred->bbJumpKind == BBJ_EHFILTERRET))
20923 // Our try block can call our finally block
20924 if ((block->bbCatchTyp == BBCT_FINALLY) && (blockPred->bbJumpKind == BBJ_CALLFINALLY) &&
20925 ehCallFinallyInCorrectRegion(blockPred, block->getHndIndex()))
20930 // You can jump within the same handler region
20931 if (bbInHandlerRegions(block->getHndIndex(), blockPred))
20936 // A filter can jump to the start of the filter handler
20937 if (ehHndDsc->HasFilter())
20942 printf("Jump into the middle of handler region: BB%02u branches to BB%02u\n", blockPred->bbNum,
20944 noway_assert(!"Jump into the middle of handler region");
20949 switch (blockPred->bbJumpKind)
20952 noway_assert(blockPred->bbNext == block || blockPred->bbJumpDest == block);
20956 noway_assert(blockPred->bbNext == block);
20959 case BBJ_CALLFINALLY:
20961 case BBJ_EHCATCHRET:
20962 case BBJ_EHFILTERRET:
20963 noway_assert(blockPred->bbJumpDest == block);
20966 case BBJ_EHFINALLYRET:
20968 // If the current block is a successor to a BBJ_EHFINALLYRET (return from finally),
20969 // then the lexically previous block should be a call to the same finally.
20970 // Verify all of that.
20972 unsigned hndIndex = blockPred->getHndIndex();
20973 EHblkDsc* ehDsc = ehGetDsc(hndIndex);
20974 BasicBlock* finBeg = ehDsc->ebdHndBeg;
20976 // Because there is no bbPrev, we have to search for the lexically previous
20977 // block. We can shorten the search by only looking in places where it is legal
20978 // to have a call to the finally.
20980 BasicBlock* begBlk;
20981 BasicBlock* endBlk;
20982 ehGetCallFinallyBlockRange(hndIndex, &begBlk, &endBlk);
20984 for (BasicBlock* bcall = begBlk; bcall != endBlk; bcall = bcall->bbNext)
20986 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
20991 if (block == bcall->bbNext)
20997 #if FEATURE_EH_FUNCLETS
20999 if (fgFuncletsCreated)
21001 // There is no easy way to search just the funclets that were pulled out of
21002 // the corresponding try body, so instead we search all the funclets, and if
21003 // we find a potential 'hit' we check if the funclet we're looking at is
21004 // from the correct try region.
21006 for (BasicBlock* bcall = fgFirstFuncletBB; bcall; bcall = bcall->bbNext)
21008 if (bcall->bbJumpKind != BBJ_CALLFINALLY || bcall->bbJumpDest != finBeg)
21013 if (block != bcall->bbNext)
21018 if (ehCallFinallyInCorrectRegion(bcall, hndIndex))
21025 #endif // FEATURE_EH_FUNCLETS
21027 noway_assert(!"BBJ_EHFINALLYRET predecessor of block that doesn't follow a BBJ_CALLFINALLY!");
21033 noway_assert(!"THROW and RETURN block cannot be in the predecessor list!");
21038 jumpCnt = blockPred->bbJumpSwt->bbsCount;
21039 BasicBlock** jumpTab;
21040 jumpTab = blockPred->bbJumpSwt->bbsDstTab;
21044 if (block == *jumpTab)
21048 } while (++jumpTab, --jumpCnt);
21050 noway_assert(!"SWITCH in the predecessor list with no jump label to BLOCK!");
21054 noway_assert(!"Unexpected bbJumpKind");
21061 /* Check the bbRefs */
21064 if (block->bbRefs != blockRefs)
21066 // Check to see if this block is the beginning of a filter or a handler and adjust the ref count
21068 for (EHblkDsc *HBtab = compHndBBtab, *HBtabEnd = &compHndBBtab[compHndBBtabCount]; HBtab != HBtabEnd;
21071 if (HBtab->ebdHndBeg == block)
21075 if (HBtab->HasFilter() && (HBtab->ebdFilter == block))
21082 assert(block->bbRefs == blockRefs);
21085 /* Check that BBF_HAS_HANDLER is valid bbTryIndex */
21086 if (block->hasTryIndex())
21088 noway_assert(block->getTryIndex() < compHndBBtabCount);
21091 /* Check if BBF_RUN_RARELY is set that we have bbWeight of zero */
21092 if (block->isRunRarely())
21094 noway_assert(block->bbWeight == BB_ZERO_WEIGHT);
21098 noway_assert(block->bbWeight > BB_ZERO_WEIGHT);
21102 // Make sure the one return BB is not changed.
21105 noway_assert(genReturnBB->bbTreeList);
21106 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtOper == GT_STMT);
21107 noway_assert(genReturnBB->IsLIR() || genReturnBB->bbTreeList->gtType == TYP_VOID);
21110 // The general encoder/decoder (currently) only reports "this" as a generics context as a stack location,
21111 // so we mark info.compThisArg as lvAddrTaken to ensure that it is not enregistered. Otherwise, it should
21112 // not be address-taken. This variable determines if the address-taken-ness of "thisArg" is "OK".
21113 bool copiedForGenericsCtxt;
21114 #ifndef JIT32_GCENCODER
21115 copiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
21116 #else // JIT32_GCENCODER
21117 copiedForGenericsCtxt = FALSE;
21118 #endif // JIT32_GCENCODER
21120 // This if only in support of the noway_asserts it contains.
21121 if (info.compIsStatic)
21123 // For static method, should have never grabbed the temp.
21124 noway_assert(lvaArg0Var == BAD_VAR_NUM);
21128 // For instance method:
21129 assert(info.compThisArg != BAD_VAR_NUM);
21130 bool compThisArgAddrExposedOK = !lvaTable[info.compThisArg].lvAddrExposed;
21132 #ifndef JIT32_GCENCODER
21133 compThisArgAddrExposedOK = compThisArgAddrExposedOK || copiedForGenericsCtxt;
21134 #endif // !JIT32_GCENCODER
21136 // Should never expose the address of arg 0 or write to arg 0.
21137 // In addition, lvArg0Var should remain 0 if arg0 is not
21138 // written to or address-exposed.
21140 compThisArgAddrExposedOK && !lvaTable[info.compThisArg].lvHasILStoreOp &&
21141 (lvaArg0Var == info.compThisArg ||
21142 lvaArg0Var != info.compThisArg &&
21143 (lvaTable[lvaArg0Var].lvAddrExposed || lvaTable[lvaArg0Var].lvHasILStoreOp || copiedForGenericsCtxt)));
21147 /*****************************************************************************
21149 * A DEBUG routine to check the that the exception flags are correctly set.
21151 ****************************************************************************/
21153 void Compiler::fgDebugCheckFlags(GenTree* tree)
21155 noway_assert(tree->gtOper != GT_STMT);
21157 const genTreeOps oper = tree->OperGet();
21158 const unsigned kind = tree->OperKind();
21159 unsigned treeFlags = tree->gtFlags & GTF_ALL_EFFECT;
21160 unsigned chkFlags = 0;
21162 if (tree->OperMayThrow(this))
21164 chkFlags |= GTF_EXCEPT;
21167 /* Is this a leaf node? */
21169 if (kind & GTK_LEAF)
21174 chkFlags |= GTF_GLOB_REF;
21178 chkFlags |= GTF_ORDER_SIDEEFF;
21181 case GT_MEMORYBARRIER:
21182 chkFlags |= GTF_GLOB_REF | GTF_ASG;
21190 /* Is it a 'simple' unary/binary operator? */
21192 else if (kind & GTK_SMPOP)
21194 GenTree* op1 = tree->gtOp.gtOp1;
21195 GenTree* op2 = tree->gtGetOp2IfPresent();
21197 // During GS work, we make shadow copies for params.
21198 // In gsParamsToShadows(), we create a shadow var of TYP_INT for every small type param.
21199 // Then in gsReplaceShadowParams(), we change the gtLclNum to the shadow var.
21200 // We also change the types of the local var tree and the assignment tree to TYP_INT if necessary.
21201 // However, since we don't morph the tree at this late stage. Manually propagating
21202 // TYP_INT up to the GT_ASG tree is only correct if we don't need to propagate the TYP_INT back up.
21203 // The following checks will ensure this.
21205 // Is the left child of "tree" a GT_ASG?
21207 // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
21208 // (or) If GT_ASG is the left child of a GT_COMMA, the type of the GT_COMMA node will
21209 // be determined by its right child. So we don't need to propagate TYP_INT up either. We are fine.
21210 if (op1 && op1->gtOper == GT_ASG)
21212 assert(tree->gtType == TYP_VOID || tree->gtOper == GT_COMMA);
21215 // Is the right child of "tree" a GT_ASG?
21217 // If parent is a TYP_VOID, we don't no need to propagate TYP_INT up. We are fine.
21218 if (op2 && op2->gtOper == GT_ASG)
21220 assert(tree->gtType == TYP_VOID);
21226 if (op1->OperIsCompare())
21228 noway_assert(op1->gtFlags & GTF_DONT_CSE);
21232 noway_assert((op1->gtOper == GT_CNS_INT) &&
21233 ((op1->gtIntCon.gtIconVal == 0) || (op1->gtIntCon.gtIconVal == 1)));
21238 case GT_FIELD_LIST:
21239 if ((op2 != nullptr) && op2->OperIsAnyList())
21241 ArrayStack<GenTree*> stack(this);
21242 while ((tree->gtGetOp2() != nullptr) && tree->gtGetOp2()->OperIsAnyList())
21245 tree = tree->gtGetOp2();
21248 fgDebugCheckFlags(tree);
21250 while (stack.Height() > 0)
21252 tree = stack.Pop();
21253 assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
21254 fgDebugCheckFlags(tree->gtOp.gtOp1);
21255 chkFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
21256 chkFlags |= (tree->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
21257 fgDebugCheckFlagsHelper(tree, (tree->gtFlags & GTF_ALL_EFFECT), chkFlags);
21268 /* Recursively check the subtrees */
21272 fgDebugCheckFlags(op1);
21276 fgDebugCheckFlags(op2);
21281 chkFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
21285 chkFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
21288 // We reuse the value of GTF_REVERSE_OPS for a GT_IND-specific flag,
21289 // so exempt that (unary) operator.
21290 if (tree->OperGet() != GT_IND && tree->gtFlags & GTF_REVERSE_OPS)
21292 /* Must have two operands if GTF_REVERSE is set */
21293 noway_assert(op1 && op2);
21295 /* Make sure that the order of side effects has not been swapped. */
21297 /* However CSE may introduce an assignment after the reverse flag
21298 was set and thus GTF_ASG cannot be considered here. */
21300 /* For a GT_ASG(GT_IND(x), y) we are interested in the side effects of x */
21302 if (GenTree::OperIsAssignment(oper) && (op1->gtOper == GT_IND))
21304 op1p = op1->gtOp.gtOp1;
21311 /* This isn't true any more with the sticky GTF_REVERSE */
21313 // if op1p has side effects, then op2 cannot have side effects
21314 if (op1p->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
21316 if (op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG))
21318 noway_assert(!(op2->gtFlags & (GTF_SIDE_EFFECT & ~GTF_ASG)));
21323 if (tree->OperRequiresAsgFlag())
21325 chkFlags |= GTF_ASG;
21328 if (oper == GT_ADDR && (op1->OperIsLocal() || op1->gtOper == GT_CLS_VAR ||
21329 (op1->gtOper == GT_IND && op1->gtOp.gtOp1->gtOper == GT_CLS_VAR_ADDR)))
21331 /* &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does.
21332 Similarly for clsVar */
21333 treeFlags |= GTF_GLOB_REF;
21337 /* See what kind of a special operator we have here */
21341 switch (tree->OperGet())
21349 call = tree->AsCall();
21351 chkFlags |= GTF_CALL;
21353 if (call->gtCallObjp)
21355 fgDebugCheckFlags(call->gtCallObjp);
21356 chkFlags |= (call->gtCallObjp->gtFlags & GTF_SIDE_EFFECT);
21358 if (call->gtCallObjp->gtFlags & GTF_ASG)
21360 treeFlags |= GTF_ASG;
21364 for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2)
21366 argx = args->gtOp.gtOp1;
21367 fgDebugCheckFlags(argx);
21369 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
21371 if (argx->gtFlags & GTF_ASG)
21373 treeFlags |= GTF_ASG;
21377 for (args = call->gtCallLateArgs; args; args = args->gtOp.gtOp2)
21379 argx = args->gtOp.gtOp1;
21380 fgDebugCheckFlags(argx);
21382 chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
21384 if (argx->gtFlags & GTF_ASG)
21386 treeFlags |= GTF_ASG;
21390 if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != nullptr))
21392 fgDebugCheckFlags(call->gtCallCookie);
21393 chkFlags |= (call->gtCallCookie->gtFlags & GTF_SIDE_EFFECT);
21396 if (call->gtCallType == CT_INDIRECT)
21398 fgDebugCheckFlags(call->gtCallAddr);
21399 chkFlags |= (call->gtCallAddr->gtFlags & GTF_SIDE_EFFECT);
21402 if (call->IsUnmanaged() && (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL))
21404 if (call->gtCallArgs->gtOp.gtOp1->OperGet() == GT_NOP)
21406 noway_assert(call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
21407 call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
21411 noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
21412 call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
21422 arrObj = tree->gtArrElem.gtArrObj;
21423 fgDebugCheckFlags(arrObj);
21424 chkFlags |= (arrObj->gtFlags & GTF_ALL_EFFECT);
21426 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
21428 fgDebugCheckFlags(tree->gtArrElem.gtArrInds[dim]);
21429 chkFlags |= tree->gtArrElem.gtArrInds[dim]->gtFlags & GTF_ALL_EFFECT;
21433 case GT_ARR_OFFSET:
21435 fgDebugCheckFlags(tree->gtArrOffs.gtOffset);
21436 chkFlags |= (tree->gtArrOffs.gtOffset->gtFlags & GTF_ALL_EFFECT);
21437 fgDebugCheckFlags(tree->gtArrOffs.gtIndex);
21438 chkFlags |= (tree->gtArrOffs.gtIndex->gtFlags & GTF_ALL_EFFECT);
21439 fgDebugCheckFlags(tree->gtArrOffs.gtArrObj);
21440 chkFlags |= (tree->gtArrOffs.gtArrObj->gtFlags & GTF_ALL_EFFECT);
21443 case GT_ARR_BOUNDS_CHECK:
21444 #ifdef FEATURE_SIMD
21446 #endif // FEATURE_SIMD
21447 #ifdef FEATURE_HW_INTRINSICS
21448 case GT_HW_INTRINSIC_CHK:
21449 #endif // FEATURE_HW_INTRINSICS
21451 GenTreeBoundsChk* bndsChk;
21452 bndsChk = tree->AsBoundsChk();
21453 fgDebugCheckFlags(bndsChk->gtIndex);
21454 chkFlags |= (bndsChk->gtIndex->gtFlags & GTF_ALL_EFFECT);
21455 fgDebugCheckFlags(bndsChk->gtArrLen);
21456 chkFlags |= (bndsChk->gtArrLen->gtFlags & GTF_ALL_EFFECT);
21461 chkFlags |= (GTF_GLOB_REF | GTF_ASG);
21462 GenTreeCmpXchg* cmpXchg;
21463 cmpXchg = tree->AsCmpXchg();
21464 fgDebugCheckFlags(cmpXchg->gtOpLocation);
21465 chkFlags |= (cmpXchg->gtOpLocation->gtFlags & GTF_ALL_EFFECT);
21466 fgDebugCheckFlags(cmpXchg->gtOpValue);
21467 chkFlags |= (cmpXchg->gtOpValue->gtFlags & GTF_ALL_EFFECT);
21468 fgDebugCheckFlags(cmpXchg->gtOpComparand);
21469 chkFlags |= (cmpXchg->gtOpComparand->gtFlags & GTF_ALL_EFFECT);
21472 case GT_STORE_DYN_BLK:
21475 GenTreeDynBlk* dynBlk;
21476 dynBlk = tree->AsDynBlk();
21477 fgDebugCheckFlags(dynBlk->gtDynamicSize);
21478 chkFlags |= (dynBlk->gtDynamicSize->gtFlags & GTF_ALL_EFFECT);
21479 fgDebugCheckFlags(dynBlk->Addr());
21480 chkFlags |= (dynBlk->Addr()->gtFlags & GTF_ALL_EFFECT);
21481 if (tree->OperGet() == GT_STORE_DYN_BLK)
21483 fgDebugCheckFlags(dynBlk->Data());
21484 chkFlags |= (dynBlk->Data()->gtFlags & GTF_ALL_EFFECT);
21494 assert(!"Unknown operator for fgDebugCheckFlags");
21499 fgDebugCheckFlagsHelper(tree, treeFlags, chkFlags);
21502 //------------------------------------------------------------------------------
21503 // fgDebugCheckFlagsHelper : Check if all bits that are set in chkFlags are also set in treeFlags.
21507 // tree - Tree whose flags are being checked
21508 // treeFlags - Actual flags on the tree
21509 // chkFlags - Expected flags
21512 // Checking that all bits that are set in treeFlags are also set in chkFlags is currently disabled.
21514 void Compiler::fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags)
21516 if (chkFlags & ~treeFlags)
21518 // Print the tree so we can see it in the log.
21519 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
21520 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
21524 noway_assert(!"Missing flags on tree");
21526 // Print the tree again so we can see it right after we hook up the debugger.
21527 printf("Missing flags on tree [%06d]: ", dspTreeID(tree));
21528 GenTree::gtDispFlags(chkFlags & ~treeFlags, GTF_DEBUG_NONE);
21532 else if (treeFlags & ~chkFlags)
21534 // TODO: We are currently only checking extra GTF_EXCEPT and GTF_ASG flags.
21535 if ((treeFlags & ~chkFlags & ~GTF_GLOB_REF & ~GTF_ORDER_SIDEEFF & ~GTF_CALL) != 0)
21537 // Print the tree so we can see it in the log.
21538 printf("Extra flags on parent tree [%X]: ", tree);
21539 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
21543 noway_assert(!"Extra flags on tree");
21545 // Print the tree again so we can see it right after we hook up the debugger.
21546 printf("Extra flags on parent tree [%X]: ", tree);
21547 GenTree::gtDispFlags(treeFlags & ~chkFlags, GTF_DEBUG_NONE);
21554 // DEBUG routine to check correctness of the internal gtNext, gtPrev threading of a statement.
21555 // This threading is only valid when fgStmtListThreaded is true.
21556 // This calls an alternate method for FGOrderLinear.
21557 void Compiler::fgDebugCheckNodeLinks(BasicBlock* block, GenTree* node)
21559 // LIR blocks are checked using BasicBlock::CheckLIR().
21560 if (block->IsLIR())
21562 LIR::AsRange(block).CheckLIR(this);
21566 GenTreeStmt* stmt = node->AsStmt();
21568 assert(fgStmtListThreaded);
21570 noway_assert(stmt->gtStmtList);
21572 // The first node's gtPrev must be nullptr (the gtPrev list is not circular).
21573 // The last node's gtNext must be nullptr (the gtNext list is not circular). This is tested if the loop below
21575 assert(stmt->gtStmtList->gtPrev == nullptr);
21577 for (GenTree* tree = stmt->gtStmtList; tree != nullptr; tree = tree->gtNext)
21581 noway_assert(tree->gtPrev->gtNext == tree);
21585 noway_assert(tree == stmt->gtStmtList);
21590 noway_assert(tree->gtNext->gtPrev == tree);
21594 noway_assert(tree == stmt->gtStmtExpr);
21597 /* Cross-check gtPrev,gtNext with gtOp for simple trees */
21599 GenTree* expectedPrevTree = nullptr;
21601 if (tree->OperIsLeaf())
21603 if (tree->gtOper == GT_CATCH_ARG)
21605 // The GT_CATCH_ARG should always have GTF_ORDER_SIDEEFF set
21606 noway_assert(tree->gtFlags & GTF_ORDER_SIDEEFF);
21607 // The GT_CATCH_ARG has to be the first thing evaluated
21608 noway_assert(stmt == block->FirstNonPhiDef());
21609 noway_assert(stmt->gtStmtList->gtOper == GT_CATCH_ARG);
21610 // The root of the tree should have GTF_ORDER_SIDEEFF set
21611 noway_assert(stmt->gtStmtExpr->gtFlags & GTF_ORDER_SIDEEFF);
21615 if (tree->OperIsUnary() && tree->gtOp.gtOp1)
21617 expectedPrevTree = tree->gtOp.gtOp1;
21619 else if (tree->OperIsBinary() && tree->gtOp.gtOp1)
21621 switch (tree->gtOper)
21625 tree->gtOp.gtOp2->AsColon()->ThenNode(); // "then" operand of the GT_COLON (generated second).
21629 expectedPrevTree = tree->AsColon()->ElseNode(); // "else" branch result (generated first).
21633 if (tree->gtOp.gtOp2)
21635 if (tree->gtFlags & GTF_REVERSE_OPS)
21637 expectedPrevTree = tree->gtOp.gtOp1;
21641 expectedPrevTree = tree->gtOp.gtOp2;
21646 expectedPrevTree = tree->gtOp.gtOp1;
21652 noway_assert(expectedPrevTree == nullptr || // No expectations about the prev node
21653 tree->gtPrev == expectedPrevTree); // The "normal" case
21657 /*****************************************************************************
21659 * A DEBUG routine to check the correctness of the links between GT_STMT nodes
21660 * and ordinary nodes within a statement.
21662 ****************************************************************************/
21664 void Compiler::fgDebugCheckLinks(bool morphTrees)
21666 // This used to be only on for stress, and there was a comment stating that
21667 // it was "quite an expensive operation" but I did not find that to be true.
21668 // Set DO_SANITY_DEBUG_CHECKS to false to revert to that behavior.
21669 const bool DO_SANITY_DEBUG_CHECKS = true;
21671 if (!DO_SANITY_DEBUG_CHECKS && !compStressCompile(STRESS_CHK_FLOW_UPDATE, 30))
21676 fgDebugCheckBlockLinks();
21678 /* For each basic block check the bbTreeList links */
21679 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
21681 if (block->IsLIR())
21683 LIR::AsRange(block).CheckLIR(this);
21687 fgDebugCheckStmtsList(block, morphTrees);
21691 fgDebugCheckNodesUniqueness();
21694 //------------------------------------------------------------------------------
21695 // fgDebugCheckStmtsList : Perfoms the set of checks:
21696 // - all statements in the block are linked correctly
21697 // - check statements flags
21698 // - check nodes gtNext and gtPrev values, if the node list is threaded
21701 // block - the block to check statements in
21702 // morphTrees - try to morph trees in the checker
21705 // Checking that all bits that are set in treeFlags are also set in chkFlags is currently disabled.
21707 void Compiler::fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees)
21709 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
21711 /* Verify that bbTreeList is threaded correctly */
21712 /* Note that for the GT_STMT list, the gtPrev list is circular. The gtNext list is not: gtNext of the
21713 * last GT_STMT in a block is nullptr. */
21715 noway_assert(stmt->gtPrev);
21717 if (stmt == block->bbTreeList)
21719 noway_assert(stmt->gtPrev->gtNext == nullptr);
21723 noway_assert(stmt->gtPrev->gtNext == stmt);
21728 noway_assert(stmt->gtNext->gtPrev == stmt);
21732 noway_assert(block->lastStmt() == stmt);
21735 /* For each statement check that the exception flags are properly set */
21737 noway_assert(stmt->gtStmtExpr);
21741 gtDispTree(stmt->gtStmtExpr);
21744 fgDebugCheckFlags(stmt->gtStmtExpr);
21746 // Not only will this stress fgMorphBlockStmt(), but we also get all the checks
21747 // done by fgMorphTree()
21751 // If 'stmt' is removed from the block, start a new check for the current block,
21752 // break the current check.
21753 if (fgMorphBlockStmt(block, stmt DEBUGARG("test morphing")))
21755 fgDebugCheckStmtsList(block, morphTrees);
21760 /* For each GT_STMT node check that the nodes are threaded correcly - gtStmtList */
21762 if (fgStmtListThreaded)
21764 fgDebugCheckNodeLinks(block, stmt);
21769 // ensure that bbNext and bbPrev are consistent
21770 void Compiler::fgDebugCheckBlockLinks()
21772 assert(fgFirstBB->bbPrev == nullptr);
21774 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
21778 assert(block->bbNext->bbPrev == block);
21782 assert(block == fgLastBB);
21787 assert(block->bbPrev->bbNext == block);
21791 assert(block == fgFirstBB);
21794 // If this is a switch, check that the tables are consistent.
21795 // Note that we don't call GetSwitchDescMap(), because it has the side-effect
21796 // of allocating it if it is not present.
21797 if (block->bbJumpKind == BBJ_SWITCH && m_switchDescMap != nullptr)
21799 SwitchUniqueSuccSet uniqueSuccSet;
21800 if (m_switchDescMap->Lookup(block, &uniqueSuccSet))
21802 // Create a set with all the successors. Don't use BlockSet, so we don't need to worry
21803 // about the BlockSet epoch.
21804 BitVecTraits bitVecTraits(fgBBNumMax + 1, this);
21805 BitVec succBlocks(BitVecOps::MakeEmpty(&bitVecTraits));
21806 BasicBlock** jumpTable = block->bbJumpSwt->bbsDstTab;
21807 unsigned jumpCount = block->bbJumpSwt->bbsCount;
21808 for (unsigned i = 0; i < jumpCount; i++)
21810 BitVecOps::AddElemD(&bitVecTraits, succBlocks, jumpTable[i]->bbNum);
21812 // Now we should have a set of unique successors that matches what's in the switchMap.
21813 // First, check the number of entries, then make sure all the blocks in uniqueSuccSet
21814 // are in the BlockSet.
21815 unsigned count = BitVecOps::Count(&bitVecTraits, succBlocks);
21816 assert(uniqueSuccSet.numDistinctSuccs == count);
21817 for (unsigned i = 0; i < uniqueSuccSet.numDistinctSuccs; i++)
21819 assert(BitVecOps::IsMember(&bitVecTraits, succBlocks, uniqueSuccSet.nonDuplicates[i]->bbNum));
21826 // UniquenessCheckWalker keeps data that is neccesary to check
21827 // that each tree has it is own unique id and they do not repeat.
21828 class UniquenessCheckWalker
21831 UniquenessCheckWalker(Compiler* comp)
21832 : comp(comp), nodesVecTraits(comp->compGenTreeID, comp), uniqueNodes(BitVecOps::MakeEmpty(&nodesVecTraits))
21836 //------------------------------------------------------------------------
21837 // fgMarkTreeId: Visit all subtrees in the tree and check gtTreeIDs.
21840 // pTree - Pointer to the tree to walk
21841 // fgWalkPre - the UniquenessCheckWalker instance
21843 static Compiler::fgWalkResult MarkTreeId(GenTree** pTree, Compiler::fgWalkData* fgWalkPre)
21845 UniquenessCheckWalker* walker = static_cast<UniquenessCheckWalker*>(fgWalkPre->pCallbackData);
21846 unsigned gtTreeID = (*pTree)->gtTreeID;
21847 walker->CheckTreeId(gtTreeID);
21848 return Compiler::WALK_CONTINUE;
21851 //------------------------------------------------------------------------
21852 // CheckTreeId: Check that this tree was not visit before and memorize it as visited.
21855 // gtTreeID - identificator of GenTree.
21857 void CheckTreeId(unsigned gtTreeID)
21859 assert(!BitVecOps::IsMember(&nodesVecTraits, uniqueNodes, gtTreeID));
21860 BitVecOps::AddElemD(&nodesVecTraits, uniqueNodes, gtTreeID);
21865 BitVecTraits nodesVecTraits;
21866 BitVec uniqueNodes;
21869 //------------------------------------------------------------------------------
21870 // fgDebugCheckNodesUniqueness: Check that each tree in the method has its own unique gtTreeId.
21872 void Compiler::fgDebugCheckNodesUniqueness()
21874 UniquenessCheckWalker walker(this);
21876 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
21878 if (block->IsLIR())
21880 for (GenTree* i : LIR::AsRange(block))
21882 walker.CheckTreeId(i->gtTreeID);
21887 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
21889 GenTree* root = stmt->gtStmtExpr;
21890 fgWalkTreePre(&root, UniquenessCheckWalker::MarkTreeId, &walker);
21896 /*****************************************************************************/
21898 /*****************************************************************************/
21900 //------------------------------------------------------------------------
21901 // fgCheckForInlineDepthAndRecursion: compute depth of the candidate, and
21902 // check for recursion.
21905 // The depth of the inline candidate. The root method is a depth 0, top-level
21906 // candidates at depth 1, etc.
21909 // We generally disallow recursive inlines by policy. However, they are
21910 // supported by the underlying machinery.
21912 // Likewise the depth limit is a policy consideration, and serves mostly
21913 // as a safeguard to prevent runaway inlining of small methods.
21915 unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo)
21917 BYTE* candidateCode = inlineInfo->inlineCandidateInfo->methInfo.ILCode;
21918 InlineContext* inlineContext = inlineInfo->iciStmt->gtInlineContext;
21919 InlineResult* inlineResult = inlineInfo->inlineResult;
21921 // There should be a context for all candidates.
21922 assert(inlineContext != nullptr);
21925 for (; inlineContext != nullptr; inlineContext = inlineContext->GetParent())
21930 if (inlineContext->GetCode() == candidateCode)
21932 // This inline candidate has the same IL code buffer as an already
21933 // inlined method does.
21934 inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_RECURSIVE);
21938 if (depth > InlineStrategy::IMPLEMENTATION_MAX_INLINE_DEPTH)
21944 inlineResult->NoteInt(InlineObservation::CALLSITE_DEPTH, depth);
21948 /*****************************************************************************
21953 void Compiler::fgInline()
21955 if (!opts.OptEnabled(CLFLG_INLINING))
21963 printf("*************** In fgInline()\n");
21967 BasicBlock* block = fgFirstBB;
21968 noway_assert(block != nullptr);
21970 // Set the root inline context on all statements
21971 InlineContext* rootContext = m_inlineStrategy->GetRootContext();
21973 for (; block != nullptr; block = block->bbNext)
21975 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
21977 stmt->gtInlineContext = rootContext;
21981 // Reset block back to start for inlining
21986 /* Make the current basic block address available globally */
21993 for (stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
21995 expr = stmt->gtStmtExpr;
21997 // See if we can expand the inline candidate
21998 if ((expr->gtOper == GT_CALL) && ((expr->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0))
22000 GenTreeCall* call = expr->AsCall();
22001 InlineResult inlineResult(this, call, stmt, "fgInline");
22003 fgMorphStmt = stmt;
22005 fgMorphCallInline(call, &inlineResult);
22007 if (stmt->gtStmtExpr->IsNothingNode())
22009 fgRemoveStmt(block, stmt);
22016 // Look for non-candidates.
22017 fgWalkTreePre(&stmt->gtStmtExpr, fgFindNonInlineCandidate, stmt);
22021 // See if we need to replace the return value place holder.
22022 // Also, see if this update enables further devirtualization.
22023 fgWalkTreePre(&stmt->gtStmtExpr, fgUpdateInlineReturnExpressionPlaceHolder, (void*)this);
22025 // See if stmt is of the form GT_COMMA(call, nop)
22026 // If yes, we can get rid of GT_COMMA.
22027 if (expr->OperGet() == GT_COMMA && expr->gtOp.gtOp1->OperGet() == GT_CALL &&
22028 expr->gtOp.gtOp2->OperGet() == GT_NOP)
22030 stmt->gtStmtExpr = expr->gtOp.gtOp1;
22034 block = block->bbNext;
22040 // Check that we should not have any inline candidate or return value place holder left.
22043 noway_assert(block);
22049 for (stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
22051 // Call Compiler::fgDebugCheckInlineCandidates on each node
22052 fgWalkTreePre(&stmt->gtStmtExpr, fgDebugCheckInlineCandidates);
22055 block = block->bbNext;
22059 fgVerifyHandlerTab();
22063 printf("*************** After fgInline()\n");
22064 fgDispBasicBlocks(true);
22065 fgDispHandlerTab();
22068 if (verbose || fgPrintInlinedMethods)
22070 printf("**************** Inline Tree\n");
22071 m_inlineStrategy->Dump();
22079 //------------------------------------------------------------------------
22080 // fgFindNonInlineCandidate: tree walk helper to ensure that a tree node
22081 // that is not an inline candidate is noted as a failed inline.
22084 // pTree - pointer to pointer tree node being walked
22085 // data - contextual data for the walk
22091 // Invokes fgNoteNonInlineCandidate on the nodes it finds.
22093 Compiler::fgWalkResult Compiler::fgFindNonInlineCandidate(GenTree** pTree, fgWalkData* data)
22095 GenTree* tree = *pTree;
22096 if (tree->gtOper == GT_CALL)
22098 Compiler* compiler = data->compiler;
22099 GenTreeStmt* stmt = (GenTreeStmt*)data->pCallbackData;
22100 GenTreeCall* call = tree->AsCall();
22102 compiler->fgNoteNonInlineCandidate(stmt, call);
22104 return WALK_CONTINUE;
22107 //------------------------------------------------------------------------
22108 // fgNoteNonInlineCandidate: account for inlining failures in calls
22109 // not marked as inline candidates.
22112 // stmt - statement containing the call
22113 // call - the call itself
22116 // Used in debug only to try and place descriptions of inline failures
22117 // into the proper context in the inline tree.
22119 void Compiler::fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call)
22121 InlineResult inlineResult(this, call, nullptr, "fgNotInlineCandidate");
22122 InlineObservation currentObservation = InlineObservation::CALLSITE_NOT_CANDIDATE;
22124 // Try and recover the reason left behind when the jit decided
22125 // this call was not a candidate.
22126 InlineObservation priorObservation = call->gtInlineObservation;
22128 if (InlIsValidObservation(priorObservation))
22130 currentObservation = priorObservation;
22133 // Propagate the prior failure observation to this result.
22134 inlineResult.NotePriorFailure(currentObservation);
22135 inlineResult.SetReported();
22137 if (call->gtCallType == CT_USER_FUNC)
22139 // Create InlineContext for the failure
22140 m_inlineStrategy->NewFailure(stmt, &inlineResult);
22146 #if FEATURE_MULTIREG_RET
22148 /*********************************************************************************
22150 * tree - The node which needs to be converted to a struct pointer.
22152 * Return the pointer by either __replacing__ the tree node with a suitable pointer
22153 * type or __without replacing__ and just returning a subtree or by __modifying__
22156 GenTree* Compiler::fgGetStructAsStructPtr(GenTree* tree)
22158 noway_assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_FIELD) || (tree->gtOper == GT_IND) ||
22159 (tree->gtOper == GT_BLK) || (tree->gtOper == GT_OBJ) || tree->OperIsSIMD() ||
22160 // tree->gtOper == GT_CALL || cannot get address of call.
22161 // tree->gtOper == GT_MKREFANY || inlining should've been aborted due to mkrefany opcode.
22162 // tree->gtOper == GT_RET_EXPR || cannot happen after fgUpdateInlineReturnExpressionPlaceHolder
22163 (tree->gtOper == GT_COMMA));
22165 switch (tree->OperGet())
22170 return tree->gtOp.gtOp1;
22173 tree->gtOp.gtOp2 = fgGetStructAsStructPtr(tree->gtOp.gtOp2);
22174 tree->gtType = TYP_BYREF;
22178 return gtNewOperNode(GT_ADDR, TYP_BYREF, tree);
22182 /***************************************************************************************************
22183 * child - The inlinee of the retExpr node.
22184 * retClsHnd - The struct class handle of the type of the inlinee.
22186 * Assign the inlinee to a tmp, if it is a call, just assign it to a lclVar, else we can
22187 * use a copyblock to do the assignment.
22189 GenTree* Compiler::fgAssignStructInlineeToVar(GenTree* child, CORINFO_CLASS_HANDLE retClsHnd)
22191 assert(child->gtOper != GT_RET_EXPR && child->gtOper != GT_MKREFANY);
22193 unsigned tmpNum = lvaGrabTemp(false DEBUGARG("RetBuf for struct inline return candidates."));
22194 lvaSetStruct(tmpNum, retClsHnd, false);
22195 var_types structType = lvaTable[tmpNum].lvType;
22197 GenTree* dst = gtNewLclvNode(tmpNum, structType);
22199 // If we have a call, we'd like it to be: V00 = call(), but first check if
22200 // we have a ", , , call()" -- this is very defensive as we may never get
22201 // an inlinee that is made of commas. If the inlinee is not a call, then
22202 // we use a copy block to do the assignment.
22203 GenTree* src = child;
22204 GenTree* lastComma = nullptr;
22205 while (src->gtOper == GT_COMMA)
22208 src = src->gtOp.gtOp2;
22211 GenTree* newInlinee = nullptr;
22212 if (src->gtOper == GT_CALL)
22214 // If inlinee was just a call, new inlinee is v05 = call()
22215 newInlinee = gtNewAssignNode(dst, src);
22217 // When returning a multi-register value in a local var, make sure the variable is
22218 // marked as lvIsMultiRegRet, so it does not get promoted.
22219 if (src->AsCall()->HasMultiRegRetVal())
22221 lvaTable[tmpNum].lvIsMultiRegRet = true;
22224 // If inlinee was comma, but a deeper call, new inlinee is (, , , v05 = call())
22225 if (child->gtOper == GT_COMMA)
22227 lastComma->gtOp.gtOp2 = newInlinee;
22228 newInlinee = child;
22233 // Inlinee is not a call, so just create a copy block to the tmp.
22235 GenTree* dstAddr = fgGetStructAsStructPtr(dst);
22236 GenTree* srcAddr = fgGetStructAsStructPtr(src);
22237 newInlinee = gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false);
22240 GenTree* production = gtNewLclvNode(tmpNum, structType);
22241 return gtNewOperNode(GT_COMMA, structType, newInlinee, production);
22244 /***************************************************************************************************
22245 * tree - The tree pointer that has one of its child nodes as retExpr.
22246 * child - The inlinee child.
22247 * retClsHnd - The struct class handle of the type of the inlinee.
22249 * V04 = call() assignments are okay as we codegen it. Everything else needs to be a copy block or
22250 * would need a temp. For example, a cast(ldobj) will then be, cast(v05 = ldobj, v05); But it is
22251 * a very rare (or impossible) scenario that we'd have a retExpr transform into a ldobj other than
22252 * a lclVar/call. So it is not worthwhile to do pattern matching optimizations like addr(ldobj(op1))
22255 void Compiler::fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO_CLASS_HANDLE retClsHnd)
22257 // We are okay to have:
22258 // 1. V02 = call();
22259 // 2. copyBlk(dstAddr, srcAddr);
22260 assert(tree->gtOper == GT_ASG);
22262 // We have an assignment, we codegen only V05 = call().
22263 if (child->gtOper == GT_CALL && tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)
22265 // If it is a multireg return on x64/ux, the local variable should be marked as lvIsMultiRegRet
22266 if (child->AsCall()->HasMultiRegRetVal())
22268 unsigned lclNum = tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
22269 lvaTable[lclNum].lvIsMultiRegRet = true;
22274 GenTree* dstAddr = fgGetStructAsStructPtr(tree->gtOp.gtOp1);
22275 GenTree* srcAddr = fgGetStructAsStructPtr(
22276 (child->gtOper == GT_CALL)
22277 ? fgAssignStructInlineeToVar(child, retClsHnd) // Assign to a variable if it is a call.
22278 : child); // Just get the address, if not a call.
22280 tree->ReplaceWith(gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false), this);
22283 #endif // FEATURE_MULTIREG_RET
22285 //------------------------------------------------------------------------
22286 // fgUpdateInlineReturnExpressionPlaceHolder: callback to replace the
22287 // inline return expression placeholder.
22290 // pTree -- pointer to tree to examine for updates
22291 // data -- context data for the tree walk
22294 // fgWalkResult indicating the walk should continue; that
22295 // is we wish to fully explore the tree.
22298 // Looks for GT_RET_EXPR nodes that arose from tree splitting done
22299 // during importation for inline candidates, and replaces them.
22301 // For successful inlines, substitutes the return value expression
22302 // from the inline body for the GT_RET_EXPR.
22304 // For failed inlines, rejoins the original call into the tree from
22305 // whence it was split during importation.
22307 // The code doesn't actually know if the corresponding inline
22308 // succeeded or not; it relies on the fact that gtInlineCandidate
22309 // initially points back at the call and is modified in place to
22310 // the inlinee return expression if the inline is successful (see
22311 // tail end of fgInsertInlineeBlocks for the update of iciCall).
22313 // If the parent of the GT_RET_EXPR is a virtual call,
22314 // devirtualization is attempted. This should only succeed in the
22315 // successful inline case, when the inlinee's return value
22316 // expression provides a better type than the return type of the
22317 // method. Note for failed inlines, the devirtualizer can only go
22318 // by the return type, and any devirtualization that type enabled
22319 // would have already happened during importation.
22321 // If the return type is a struct type and we're on a platform
22322 // where structs can be returned in multiple registers, ensure the
22323 // call has a suitable parent.
22325 Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTree** pTree, fgWalkData* data)
22327 GenTree* tree = *pTree;
22328 Compiler* comp = data->compiler;
22329 CORINFO_CLASS_HANDLE retClsHnd = NO_CLASS_HANDLE;
22331 if (tree->gtOper == GT_RET_EXPR)
22333 // We are going to copy the tree from the inlinee,
22334 // so record the handle now.
22336 if (varTypeIsStruct(tree))
22338 retClsHnd = tree->gtRetExpr.gtRetClsHnd;
22343 // Obtained the expanded inline candidate
22344 GenTree* inlineCandidate = tree->gtRetExpr.gtInlineCandidate;
22349 printf("\nReplacing the return expression placeholder ");
22352 printTreeID(inlineCandidate);
22354 // Dump out the old return expression placeholder it will be overwritten by the ReplaceWith below
22355 comp->gtDispTree(tree);
22359 tree->ReplaceWith(inlineCandidate, comp);
22364 printf("\nInserting the inline return expression\n");
22365 comp->gtDispTree(tree);
22369 } while (tree->gtOper == GT_RET_EXPR);
22371 // Now see if this return value expression feeds the 'this'
22372 // object at a virtual call site.
22374 // Note for void returns where the inline failed, the
22375 // GT_RET_EXPR may be top-level.
22377 // May miss cases where there are intermediaries between call
22378 // and this, eg commas.
22379 GenTree* parentTree = data->parent;
22381 if ((parentTree != nullptr) && (parentTree->gtOper == GT_CALL))
22383 GenTreeCall* call = parentTree->AsCall();
22384 bool tryLateDevirt = call->IsVirtual() && (call->gtCallObjp == tree) && (call->gtCallType == CT_USER_FUNC);
22387 tryLateDevirt = tryLateDevirt && (JitConfig.JitEnableLateDevirtualization() == 1);
22395 printf("**** Late devirt opportunity\n");
22396 comp->gtDispTree(call);
22400 CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
22401 unsigned methodFlags = 0;
22402 CORINFO_CONTEXT_HANDLE context = nullptr;
22403 comp->impDevirtualizeCall(call, &method, &methodFlags, &context, nullptr);
22408 #if FEATURE_MULTIREG_RET
22410 // Did we record a struct return class handle above?
22412 if (retClsHnd != NO_CLASS_HANDLE)
22414 // Is this a type that is returned in multiple registers?
22415 // if so we need to force into into a form we accept.
22416 // i.e. LclVar = call()
22418 if (comp->IsMultiRegReturnedType(retClsHnd))
22420 GenTree* parent = data->parent;
22421 // See assert below, we only look one level above for an asg parent.
22422 if (parent->gtOper == GT_ASG)
22424 // Either lhs is a call V05 = call(); or lhs is addr, and asg becomes a copyBlk.
22425 comp->fgAttachStructInlineeToAsg(parent, tree, retClsHnd);
22429 // Just assign the inlinee to a variable to keep it simple.
22430 tree->ReplaceWith(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
22437 // Make sure we don't have a tree like so: V05 = (, , , retExpr);
22438 // Since we only look one level above for the parent for '=' and
22439 // do not check if there is a series of COMMAs. See above.
22440 // Importer and FlowGraph will not generate such a tree, so just
22441 // leaving an assert in here. This can be fixed by looking ahead
22442 // when we visit GT_ASG similar to fgAttachStructInlineeToAsg.
22444 if ((tree->gtOper == GT_ASG) && (tree->gtOp.gtOp2->gtOper == GT_COMMA))
22447 for (comma = tree->gtOp.gtOp2; comma->gtOper == GT_COMMA; comma = comma->gtOp.gtOp2)
22452 noway_assert(!varTypeIsStruct(comma) || comma->gtOper != GT_RET_EXPR ||
22453 !comp->IsMultiRegReturnedType(comma->gtRetExpr.gtRetClsHnd));
22456 #endif // defined(DEBUG)
22457 #endif // FEATURE_MULTIREG_RET
22459 return WALK_CONTINUE;
22464 /*****************************************************************************
22465 * Callback to make sure there is no more GT_RET_EXPR and GTF_CALL_INLINE_CANDIDATE nodes.
22469 Compiler::fgWalkResult Compiler::fgDebugCheckInlineCandidates(GenTree** pTree, fgWalkData* data)
22471 GenTree* tree = *pTree;
22472 if (tree->gtOper == GT_CALL)
22474 assert((tree->gtFlags & GTF_CALL_INLINE_CANDIDATE) == 0);
22478 assert(tree->gtOper != GT_RET_EXPR);
22481 return WALK_CONTINUE;
22486 void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineResult)
22488 noway_assert(call->gtOper == GT_CALL);
22489 noway_assert((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0);
22490 noway_assert(opts.OptEnabled(CLFLG_INLINING));
22492 // This is the InlineInfo struct representing a method to be inlined.
22493 InlineInfo inlineInfo;
22494 memset(&inlineInfo, 0, sizeof(inlineInfo));
22495 CORINFO_METHOD_HANDLE fncHandle = call->gtCallMethHnd;
22497 inlineInfo.fncHandle = fncHandle;
22498 inlineInfo.iciCall = call;
22499 inlineInfo.iciStmt = fgMorphStmt;
22500 inlineInfo.iciBlock = compCurBB;
22501 inlineInfo.thisDereferencedFirst = false;
22502 inlineInfo.retExpr = nullptr;
22503 inlineInfo.retExprClassHnd = nullptr;
22504 inlineInfo.retExprClassHndIsExact = false;
22505 inlineInfo.inlineResult = inlineResult;
22506 #ifdef FEATURE_SIMD
22507 inlineInfo.hasSIMDTypeArgLocalOrReturn = false;
22508 #endif // FEATURE_SIMD
22510 InlineCandidateInfo* inlineCandidateInfo = call->gtInlineCandidateInfo;
22511 noway_assert(inlineCandidateInfo);
22512 // Store the link to inlineCandidateInfo into inlineInfo
22513 inlineInfo.inlineCandidateInfo = inlineCandidateInfo;
22515 unsigned inlineDepth = fgCheckInlineDepthAndRecursion(&inlineInfo);
22517 if (inlineResult->IsFailure())
22522 printf("Recursive or deep inline recursion detected. Will not expand this INLINECANDIDATE \n");
22528 // Set the trap to catch all errors (including recoverable ones from the EE)
22533 CORINFO_METHOD_HANDLE fncHandle;
22534 InlineCandidateInfo* inlineCandidateInfo;
22535 InlineInfo* inlineInfo;
22537 memset(¶m, 0, sizeof(param));
22539 param.pThis = this;
22541 param.fncHandle = fncHandle;
22542 param.inlineCandidateInfo = inlineCandidateInfo;
22543 param.inlineInfo = &inlineInfo;
22544 bool success = eeRunWithErrorTrap<Param>(
22545 [](Param* pParam) {
22546 // Init the local var info of the inlinee
22547 pParam->pThis->impInlineInitVars(pParam->inlineInfo);
22549 if (pParam->inlineInfo->inlineResult->IsCandidate())
22551 /* Clear the temp table */
22552 memset(pParam->inlineInfo->lclTmpNum, -1, sizeof(pParam->inlineInfo->lclTmpNum));
22555 // Prepare the call to jitNativeCode
22558 pParam->inlineInfo->InlinerCompiler = pParam->pThis;
22559 if (pParam->pThis->impInlineInfo == nullptr)
22561 pParam->inlineInfo->InlineRoot = pParam->pThis;
22565 pParam->inlineInfo->InlineRoot = pParam->pThis->impInlineInfo->InlineRoot;
22567 pParam->inlineInfo->argCnt = pParam->inlineCandidateInfo->methInfo.args.totalILArgs();
22568 pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHnd;
22570 JITLOG_THIS(pParam->pThis,
22571 (LL_INFO100000, "INLINER: inlineInfo.tokenLookupContextHandle for %s set to 0x%p:\n",
22572 pParam->pThis->eeGetMethodFullName(pParam->fncHandle),
22573 pParam->pThis->dspPtr(pParam->inlineInfo->tokenLookupContextHandle)));
22575 JitFlags compileFlagsForInlinee = *pParam->pThis->opts.jitFlags;
22577 // The following flags are lost when inlining.
22578 // (This is checked in Compiler::compInitOptions().)
22579 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_BBOPT);
22580 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_BBINSTR);
22581 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_PROF_ENTERLEAVE);
22582 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_EnC);
22583 compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_INFO);
22585 compileFlagsForInlinee.Set(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
22588 if (pParam->pThis->verbose)
22590 printf("\nInvoking compiler for the inlinee method %s :\n",
22591 pParam->pThis->eeGetMethodFullName(pParam->fncHandle));
22596 jitNativeCode(pParam->fncHandle, pParam->inlineCandidateInfo->methInfo.scope,
22597 pParam->pThis->info.compCompHnd, &pParam->inlineCandidateInfo->methInfo,
22598 (void**)pParam->inlineInfo, nullptr, &compileFlagsForInlinee, pParam->inlineInfo);
22600 if (result != CORJIT_OK)
22602 // If we haven't yet determined why this inline fails, use
22603 // a catch-all something bad happened observation.
22604 InlineResult* innerInlineResult = pParam->inlineInfo->inlineResult;
22606 if (!innerInlineResult->IsFailure())
22608 innerInlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_FAILURE);
22619 printf("\nInlining failed due to an exception during invoking the compiler for the inlinee method %s.\n",
22620 eeGetMethodFullName(fncHandle));
22624 // If we haven't yet determined why this inline fails, use
22625 // a catch-all something bad happened observation.
22626 if (!inlineResult->IsFailure())
22628 inlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
22632 if (inlineResult->IsFailure())
22640 printf("\nDone invoking compiler for the inlinee method %s\n", eeGetMethodFullName(fncHandle));
22644 // If there is non-NULL return, but we haven't set the pInlineInfo->retExpr,
22645 // That means we haven't imported any BB that contains CEE_RET opcode.
22646 // (This could happen for example for a BBJ_THROW block fall through a BBJ_RETURN block which
22647 // causes the BBJ_RETURN block not to be imported at all.)
22648 // Fail the inlining attempt
22649 if (inlineCandidateInfo->fncRetType != TYP_VOID && inlineInfo.retExpr == nullptr)
22654 printf("\nInlining failed because pInlineInfo->retExpr is not set in the inlinee method %s.\n",
22655 eeGetMethodFullName(fncHandle));
22658 inlineResult->NoteFatal(InlineObservation::CALLEE_LACKS_RETURN);
22662 if (inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_SPECULATIVE)
22664 // we defer the call to initClass() until inlining is completed in case it fails. If inlining succeeds,
22665 // we will call initClass().
22666 if (!(info.compCompHnd->initClass(nullptr /* field */, fncHandle /* method */,
22667 inlineCandidateInfo->exactContextHnd /* context */) &
22668 CORINFO_INITCLASS_INITIALIZED))
22670 inlineResult->NoteFatal(InlineObservation::CALLEE_CLASS_INIT_FAILURE);
22675 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
22676 // The inlining attempt cannot be failed starting from this point.
22677 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
22679 // We've successfully obtain the list of inlinee's basic blocks.
22680 // Let's insert it to inliner's basic block list.
22681 fgInsertInlineeBlocks(&inlineInfo);
22685 if (verbose || fgPrintInlinedMethods)
22687 printf("Successfully inlined %s (%d IL bytes) (depth %d) [%s]\n", eeGetMethodFullName(fncHandle),
22688 inlineCandidateInfo->methInfo.ILCodeSize, inlineDepth, inlineResult->ReasonString());
22693 printf("--------------------------------------------------------------------------------------------\n");
22698 impInlinedCodeSize += inlineCandidateInfo->methInfo.ILCodeSize;
22702 inlineResult->NoteSuccess();
22705 //------------------------------------------------------------------------
22706 // fgInsertInlineeBlocks: incorporate statements for an inline into the
22710 // inlineInfo -- info for the inline
22713 // The inlining attempt cannot be failed once this method is called.
22715 // Adds all inlinee statements, plus any glue statements needed
22716 // either before or after the inlined call.
22718 // Updates flow graph and assigns weights to inlinee
22719 // blocks. Currently does not attempt to read IBC data for the
22722 // Updates relevant root method status flags (eg optMethodFlags) to
22723 // include information from the inlinee.
22725 // Marks newly added statements with an appropriate inline context.
22727 void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo)
22729 GenTreeCall* iciCall = pInlineInfo->iciCall;
22730 GenTreeStmt* iciStmt = pInlineInfo->iciStmt;
22731 BasicBlock* iciBlock = pInlineInfo->iciBlock;
22734 // We can write better assert here. For example, we can check that
22735 // iciBlock contains iciStmt, which in turn contains iciCall.
22736 noway_assert(iciBlock->bbTreeList != nullptr);
22737 noway_assert(iciStmt->gtStmtExpr != nullptr);
22738 noway_assert(iciCall->gtOper == GT_CALL);
22742 GenTree* currentDumpStmt = nullptr;
22746 printf("\n\n----------- Statements (and blocks) added due to the inlining of call ");
22747 printTreeID(iciCall);
22748 printf(" -----------\n");
22753 // Create a new inline context and mark the inlined statements with it
22754 InlineContext* calleeContext = m_inlineStrategy->NewSuccess(pInlineInfo);
22756 for (block = InlineeCompiler->fgFirstBB; block != nullptr; block = block->bbNext)
22758 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
22760 stmt->gtInlineContext = calleeContext;
22764 // Prepend statements
22765 GenTree* stmtAfter = fgInlinePrependStatements(pInlineInfo);
22770 currentDumpStmt = stmtAfter;
22771 printf("\nInlinee method body:");
22775 BasicBlock* topBlock = iciBlock;
22776 BasicBlock* bottomBlock = nullptr;
22778 if (InlineeCompiler->fgBBcount == 1)
22780 // When fgBBCount is 1 we will always have a non-NULL fgFirstBB
22782 PREFAST_ASSUME(InlineeCompiler->fgFirstBB != nullptr);
22784 // DDB 91389: Don't throw away the (only) inlinee block
22785 // when its return type is not BBJ_RETURN.
22786 // In other words, we need its BBJ_ to perform the right thing.
22787 if (InlineeCompiler->fgFirstBB->bbJumpKind == BBJ_RETURN)
22789 // Inlinee contains just one BB. So just insert its statement list to topBlock.
22790 if (InlineeCompiler->fgFirstBB->bbTreeList)
22792 stmtAfter = fgInsertStmtListAfter(iciBlock, stmtAfter, InlineeCompiler->fgFirstBB->bbTreeList);
22794 // Copy inlinee bbFlags to caller bbFlags.
22795 const unsigned __int64 inlineeBlockFlags = InlineeCompiler->fgFirstBB->bbFlags;
22796 noway_assert((inlineeBlockFlags & BBF_HAS_JMP) == 0);
22797 noway_assert((inlineeBlockFlags & BBF_KEEP_BBJ_ALWAYS) == 0);
22798 iciBlock->bbFlags |= inlineeBlockFlags;
22804 noway_assert(currentDumpStmt);
22806 if (currentDumpStmt != stmtAfter)
22810 currentDumpStmt = currentDumpStmt->gtNext;
22814 noway_assert(currentDumpStmt->gtOper == GT_STMT);
22816 gtDispTree(currentDumpStmt);
22819 } while (currentDumpStmt != stmtAfter);
22824 // Append statements to null out gc ref locals, if necessary.
22825 fgInlineAppendStatements(pInlineInfo, iciBlock, stmtAfter);
22832 // ======= Inserting inlinee's basic blocks ===============
22835 bottomBlock = fgNewBBafter(topBlock->bbJumpKind, topBlock, true);
22836 bottomBlock->bbRefs = 1;
22837 bottomBlock->bbJumpDest = topBlock->bbJumpDest;
22838 bottomBlock->inheritWeight(topBlock);
22840 topBlock->bbJumpKind = BBJ_NONE;
22842 // Update block flags
22844 const unsigned __int64 originalFlags = topBlock->bbFlags;
22845 noway_assert((originalFlags & BBF_SPLIT_NONEXIST) == 0);
22846 topBlock->bbFlags &= ~(BBF_SPLIT_LOST);
22847 bottomBlock->bbFlags |= originalFlags & BBF_SPLIT_GAINED;
22851 // Split statements between topBlock and bottomBlock
22853 GenTree* topBlock_Begin;
22854 GenTree* topBlock_End;
22855 GenTree* bottomBlock_Begin;
22856 GenTree* bottomBlock_End;
22858 topBlock_Begin = nullptr;
22859 topBlock_End = nullptr;
22860 bottomBlock_Begin = nullptr;
22861 bottomBlock_End = nullptr;
22864 // First figure out bottomBlock_Begin
22867 bottomBlock_Begin = stmtAfter->gtNext;
22869 if (topBlock->bbTreeList == nullptr)
22871 // topBlock is empty before the split.
22872 // In this case, both topBlock and bottomBlock should be empty
22873 noway_assert(bottomBlock_Begin == nullptr);
22874 topBlock->bbTreeList = nullptr;
22875 bottomBlock->bbTreeList = nullptr;
22877 else if (topBlock->bbTreeList == bottomBlock_Begin)
22879 noway_assert(bottomBlock_Begin);
22881 // topBlock contains at least one statement before the split.
22882 // And the split is before the first statement.
22883 // In this case, topBlock should be empty, and everything else should be moved to the bottonBlock.
22884 bottomBlock->bbTreeList = topBlock->bbTreeList;
22885 topBlock->bbTreeList = nullptr;
22887 else if (bottomBlock_Begin == nullptr)
22889 noway_assert(topBlock->bbTreeList);
22891 // topBlock contains at least one statement before the split.
22892 // And the split is at the end of the topBlock.
22893 // In this case, everything should be kept in the topBlock, and the bottomBlock should be empty
22895 bottomBlock->bbTreeList = nullptr;
22899 noway_assert(topBlock->bbTreeList);
22900 noway_assert(bottomBlock_Begin);
22902 // This is the normal case where both blocks should contain at least one statement.
22903 topBlock_Begin = topBlock->bbTreeList;
22904 noway_assert(topBlock_Begin);
22905 topBlock_End = bottomBlock_Begin->gtPrev;
22906 noway_assert(topBlock_End);
22907 bottomBlock_End = topBlock->lastStmt();
22908 noway_assert(bottomBlock_End);
22910 // Break the linkage between 2 blocks.
22911 topBlock_End->gtNext = nullptr;
22913 // Fix up all the pointers.
22914 topBlock->bbTreeList = topBlock_Begin;
22915 topBlock->bbTreeList->gtPrev = topBlock_End;
22917 bottomBlock->bbTreeList = bottomBlock_Begin;
22918 bottomBlock->bbTreeList->gtPrev = bottomBlock_End;
22922 // Set the try and handler index and fix the jump types of inlinee's blocks.
22925 bool inheritWeight;
22926 inheritWeight = true; // The firstBB does inherit the weight from the iciBlock
22928 for (block = InlineeCompiler->fgFirstBB; block != nullptr; block = block->bbNext)
22930 noway_assert(!block->hasTryIndex());
22931 noway_assert(!block->hasHndIndex());
22932 block->copyEHRegion(iciBlock);
22933 block->bbFlags |= iciBlock->bbFlags & BBF_BACKWARD_JUMP;
22935 if (iciStmt->gtStmtILoffsx != BAD_IL_OFFSET)
22937 block->bbCodeOffs = jitGetILoffs(iciStmt->gtStmtILoffsx);
22938 block->bbCodeOffsEnd = block->bbCodeOffs + 1; // TODO: is code size of 1 some magic number for inlining?
22942 block->bbCodeOffs = 0; // TODO: why not BAD_IL_OFFSET?
22943 block->bbCodeOffsEnd = 0;
22944 block->bbFlags |= BBF_INTERNAL;
22947 if (block->bbJumpKind == BBJ_RETURN)
22949 inheritWeight = true; // A return block does inherit the weight from the iciBlock
22950 noway_assert((block->bbFlags & BBF_HAS_JMP) == 0);
22953 block->bbJumpKind = BBJ_ALWAYS;
22954 block->bbJumpDest = bottomBlock;
22958 printf("\nConvert bbJumpKind of BB%02u to BBJ_ALWAYS to bottomBlock BB%02u\n", block->bbNum,
22959 bottomBlock->bbNum);
22968 printf("\nConvert bbJumpKind of BB%02u to BBJ_NONE\n", block->bbNum);
22971 block->bbJumpKind = BBJ_NONE;
22976 block->inheritWeight(iciBlock);
22977 inheritWeight = false;
22981 block->modifyBBWeight(iciBlock->bbWeight / 2);
22985 // Insert inlinee's blocks into inliner's block list.
22986 topBlock->setNext(InlineeCompiler->fgFirstBB);
22987 InlineeCompiler->fgLastBB->setNext(bottomBlock);
22990 // Add inlinee's block count to inliner's.
22992 fgBBcount += InlineeCompiler->fgBBcount;
22994 // Append statements to null out gc ref locals, if necessary.
22995 fgInlineAppendStatements(pInlineInfo, bottomBlock, nullptr);
23000 fgDispBasicBlocks(InlineeCompiler->fgFirstBB, InlineeCompiler->fgLastBB, true);
23007 // At this point, we have successully inserted inlinee's code.
23011 // Copy out some flags
23013 compLongUsed |= InlineeCompiler->compLongUsed;
23014 compFloatingPointUsed |= InlineeCompiler->compFloatingPointUsed;
23015 compLocallocUsed |= InlineeCompiler->compLocallocUsed;
23016 compLocallocOptimized |= InlineeCompiler->compLocallocOptimized;
23017 compQmarkUsed |= InlineeCompiler->compQmarkUsed;
23018 compUnsafeCastUsed |= InlineeCompiler->compUnsafeCastUsed;
23019 compNeedsGSSecurityCookie |= InlineeCompiler->compNeedsGSSecurityCookie;
23020 compGSReorderStackLayout |= InlineeCompiler->compGSReorderStackLayout;
23022 #ifdef FEATURE_SIMD
23023 if (InlineeCompiler->usesSIMDTypes())
23025 setUsesSIMDTypes(true);
23027 #endif // FEATURE_SIMD
23029 // Update unmanaged call count
23030 info.compCallUnmanaged += InlineeCompiler->info.compCallUnmanaged;
23032 // Update optMethodFlags
23035 unsigned optMethodFlagsBefore = optMethodFlags;
23038 optMethodFlags |= InlineeCompiler->optMethodFlags;
23041 if (optMethodFlags != optMethodFlagsBefore)
23043 JITDUMP("INLINER: Updating optMethodFlags -- root:%0x callee:%0x new:%0x\n", optMethodFlagsBefore,
23044 InlineeCompiler->optMethodFlags, optMethodFlags);
23048 // If there is non-NULL return, replace the GT_CALL with its return value expression,
23049 // so later it will be picked up by the GT_RET_EXPR node.
23050 if ((pInlineInfo->inlineCandidateInfo->fncRetType != TYP_VOID) || (iciCall->gtReturnType == TYP_STRUCT))
23052 noway_assert(pInlineInfo->retExpr);
23056 printf("\nReturn expression for call at ");
23057 printTreeID(iciCall);
23059 gtDispTree(pInlineInfo->retExpr);
23062 // Replace the call with the return expression
23063 iciCall->ReplaceWith(pInlineInfo->retExpr, this);
23067 // Detach the GT_CALL node from the original statement by hanging a "nothing" node under it,
23068 // so that fgMorphStmts can remove the statement once we return from here.
23070 iciStmt->gtStmtExpr = gtNewNothingNode();
23073 //------------------------------------------------------------------------
23074 // fgInlinePrependStatements: prepend statements needed to match up
23075 // caller and inlined callee
23078 // inlineInfo -- info for the inline
23081 // The last statement that was added, or the original call if no
23082 // statements were added.
23085 // Statements prepended may include the following:
23086 // * This pointer null check
23087 // * Class initialization
23088 // * Zeroing of must-init locals in the callee
23089 // * Passing of call arguments via temps
23091 // Newly added statements are placed just after the original call
23092 // and are are given the same inline context as the call any calls
23093 // added here will appear to have been part of the immediate caller.
23095 GenTree* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
23097 BasicBlock* block = inlineInfo->iciBlock;
23098 GenTreeStmt* callStmt = inlineInfo->iciStmt;
23099 IL_OFFSETX callILOffset = callStmt->gtStmtILoffsx;
23100 GenTreeStmt* postStmt = callStmt->gtNextStmt;
23101 GenTree* afterStmt = callStmt; // afterStmt is the place where the new statements should be inserted after.
23102 GenTree* newStmt = nullptr;
23103 GenTreeCall* call = inlineInfo->iciCall->AsCall();
23105 noway_assert(call->gtOper == GT_CALL);
23110 printf("\nfgInlinePrependStatements for iciCall= ");
23116 // Prepend statements for any initialization / side effects
23118 InlArgInfo* inlArgInfo = inlineInfo->inlArgInfo;
23119 InlLclVarInfo* lclVarInfo = inlineInfo->lclVarInfo;
23123 // Create the null check statement (but not appending it to the statement list yet) for the 'this' pointer if
23125 // The NULL check should be done after "argument setup statements".
23126 // The only reason we move it here is for calling "impInlineFetchArg(0,..." to reserve a temp
23127 // for the "this" pointer.
23128 // Note: Here we no longer do the optimization that was done by thisDereferencedFirst in the old inliner.
23129 // However the assetionProp logic will remove any unecessary null checks that we may have added
23131 GenTree* nullcheck = nullptr;
23133 if (call->gtFlags & GTF_CALL_NULLCHECK && !inlineInfo->thisDereferencedFirst)
23135 // Call impInlineFetchArg to "reserve" a temp for the "this" pointer.
23136 nullcheck = gtNewOperNode(GT_IND, TYP_INT, impInlineFetchArg(0, inlArgInfo, lclVarInfo));
23137 nullcheck->gtFlags |= GTF_EXCEPT;
23139 // The NULL-check statement will be inserted to the statement list after those statements
23140 // that assign arguments to temps and before the actual body of the inlinee method.
23143 /* Treat arguments that had to be assigned to temps */
23144 if (inlineInfo->argCnt)
23150 printf("\nArguments setup:\n");
23154 for (unsigned argNum = 0; argNum < inlineInfo->argCnt; argNum++)
23156 const InlArgInfo& argInfo = inlArgInfo[argNum];
23157 const bool argIsSingleDef = !argInfo.argHasLdargaOp && !argInfo.argHasStargOp;
23158 GenTree* const argNode = inlArgInfo[argNum].argNode;
23160 if (argInfo.argHasTmp)
23162 noway_assert(argInfo.argIsUsed);
23164 /* argBashTmpNode is non-NULL iff the argument's value was
23165 referenced exactly once by the original IL. This offers an
23166 oppportunity to avoid an intermediate temp and just insert
23167 the original argument tree.
23169 However, if the temp node has been cloned somewhere while
23170 importing (e.g. when handling isinst or dup), or if the IL
23171 took the address of the argument, then argBashTmpNode will
23172 be set (because the value was only explicitly retrieved
23173 once) but the optimization cannot be applied.
23176 GenTree* argSingleUseNode = argInfo.argBashTmpNode;
23178 if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) && argIsSingleDef)
23180 // Change the temp in-place to the actual argument.
23181 // We currently do not support this for struct arguments, so it must not be a GT_OBJ.
23182 assert(argNode->gtOper != GT_OBJ);
23183 argSingleUseNode->ReplaceWith(argNode, this);
23188 // We're going to assign the argument value to the
23189 // temp we use for it in the inline body.
23190 const unsigned tmpNum = argInfo.argTmpNum;
23191 const var_types argType = lclVarInfo[argNum].lclTypeInfo;
23193 // Create the temp assignment for this argument
23194 CORINFO_CLASS_HANDLE structHnd = DUMMY_INIT(0);
23196 if (varTypeIsStruct(argType))
23198 structHnd = gtGetStructHandleIfPresent(argNode);
23199 noway_assert(structHnd != NO_CLASS_HANDLE);
23202 // Unsafe value cls check is not needed for
23203 // argTmpNum here since in-linee compiler instance
23204 // would have iterated over these and marked them
23206 impAssignTempGen(tmpNum, argNode, structHnd, (unsigned)CHECK_SPILL_NONE, &afterStmt, callILOffset,
23209 // We used to refine the temp type here based on
23210 // the actual arg, but we now do this up front, when
23211 // creating the temp, over in impInlineFetchArg.
23212 CLANG_FORMAT_COMMENT_ANCHOR;
23217 gtDispTree(afterStmt);
23222 else if (argInfo.argIsByRefToStructLocal)
23224 // Do nothing. Arg was directly substituted as we read
23229 /* The argument is either not used or a const or lcl var */
23231 noway_assert(!argInfo.argIsUsed || argInfo.argIsInvariant || argInfo.argIsLclVar);
23233 /* Make sure we didnt change argNode's along the way, or else
23234 subsequent uses of the arg would have worked with the bashed value */
23235 if (argInfo.argIsInvariant)
23237 assert(argNode->OperIsConst() || argNode->gtOper == GT_ADDR);
23239 noway_assert((argInfo.argIsLclVar == 0) ==
23240 (argNode->gtOper != GT_LCL_VAR || (argNode->gtFlags & GTF_GLOB_REF)));
23242 /* If the argument has side effects, append it */
23244 if (argInfo.argHasSideEff)
23246 noway_assert(argInfo.argIsUsed == false);
23248 bool append = true;
23250 if (argNode->gtOper == GT_OBJ || argNode->gtOper == GT_MKREFANY)
23252 // Don't put GT_OBJ node under a GT_COMMA.
23253 // Codegen can't deal with it.
23254 // Just hang the address here in case there are side-effect.
23255 newStmt = gtNewStmt(gtUnusedValNode(argNode->gtOp.gtOp1), callILOffset);
23259 // In some special cases, unused args with side effects can
23260 // trigger further changes.
23262 // (1) If the arg is a static field access and the field access
23263 // was produced by a call to EqualityComparer<T>.get_Default, the
23264 // helper call to ensure the field has a value can be suppressed.
23265 // This helper call is marked as a "Special DCE" helper during
23266 // importation, over in fgGetStaticsCCtorHelper.
23268 // (2) NYI. If, after tunneling through GT_RET_VALs, we find that
23269 // the actual arg expression has no side effects, we can skip
23270 // appending all together. This will help jit TP a bit.
23272 // Chase through any GT_RET_EXPRs to find the actual argument
23274 GenTree* actualArgNode = argNode->gtRetExprVal();
23278 // Look for the following tree shapes
23279 // prejit: (IND (ADD (CONST, CALL(special dce helper...))))
23280 // jit : (COMMA (CALL(special dce helper...), (FIELD ...)))
23281 if (actualArgNode->gtOper == GT_COMMA)
23283 // Look for (COMMA (CALL(special dce helper...), (FIELD ...)))
23284 GenTree* op1 = actualArgNode->gtOp.gtOp1;
23285 GenTree* op2 = actualArgNode->gtOp.gtOp2;
23286 if (op1->IsCall() && ((op1->gtCall.gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) &&
23287 (op2->gtOper == GT_FIELD) && ((op2->gtFlags & GTF_EXCEPT) == 0))
23289 JITDUMP("\nPerforming special dce on unused arg [%06u]:"
23290 " actual arg [%06u] helper call [%06u]\n",
23291 argNode->gtTreeID, actualArgNode->gtTreeID, op1->gtTreeID);
23292 // Drop the whole tree
23296 else if (actualArgNode->gtOper == GT_IND)
23298 // Look for (IND (ADD (CONST, CALL(special dce helper...))))
23299 GenTree* addr = actualArgNode->gtOp.gtOp1;
23301 if (addr->gtOper == GT_ADD)
23303 GenTree* op1 = addr->gtOp.gtOp1;
23304 GenTree* op2 = addr->gtOp.gtOp2;
23305 if (op1->IsCall() &&
23306 ((op1->gtCall.gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) &&
23307 op2->IsCnsIntOrI())
23309 // Drop the whole tree
23310 JITDUMP("\nPerforming special dce on unused arg [%06u]:"
23311 " actual arg [%06u] helper call [%06u]\n",
23312 argNode->gtTreeID, actualArgNode->gtTreeID, op1->gtTreeID);
23321 assert(newStmt == nullptr);
23322 JITDUMP("Arg tree side effects were discardable, not appending anything for arg\n");
23326 // If we don't have something custom to append,
23327 // just append the arg node as an unused value.
23328 if (newStmt == nullptr)
23330 newStmt = gtNewStmt(gtUnusedValNode(argNode), callILOffset);
23333 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
23337 gtDispTree(afterStmt);
23342 else if (argNode->IsBoxedValue())
23344 // Try to clean up any unnecessary boxing side effects
23345 // since the box itself will be ignored.
23346 gtTryRemoveBoxUpstreamEffects(argNode);
23352 // Add the CCTOR check if asked for.
23353 // Note: We no longer do the optimization that is done before by staticAccessedFirstUsingHelper in the old inliner.
23354 // Therefore we might prepend redundant call to HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
23355 // before the inlined method body, even if a static field of this type was accessed in the inlinee
23356 // using a helper before any other observable side-effect.
23358 if (inlineInfo->inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_USE_HELPER)
23360 CORINFO_CONTEXT_HANDLE exactContext = inlineInfo->inlineCandidateInfo->exactContextHnd;
23361 CORINFO_CLASS_HANDLE exactClass;
23363 if (((SIZE_T)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
23365 exactClass = CORINFO_CLASS_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
23369 exactClass = info.compCompHnd->getMethodClass(
23370 CORINFO_METHOD_HANDLE((SIZE_T)exactContext & ~CORINFO_CONTEXTFLAGS_MASK));
23373 tree = fgGetSharedCCtor(exactClass);
23374 newStmt = gtNewStmt(tree, callILOffset);
23375 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
23378 // Insert the nullcheck statement now.
23381 newStmt = gtNewStmt(nullcheck, callILOffset);
23382 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
23386 // Now zero-init inlinee locals
23389 CORINFO_METHOD_INFO* InlineeMethodInfo = InlineeCompiler->info.compMethodInfo;
23391 unsigned lclCnt = InlineeMethodInfo->locals.numArgs;
23393 // Does callee contain any zero-init local?
23394 if ((lclCnt != 0) && (InlineeMethodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0)
23400 printf("\nZero init inlinee locals:\n");
23404 for (unsigned lclNum = 0; lclNum < lclCnt; lclNum++)
23406 unsigned tmpNum = inlineInfo->lclTmpNum[lclNum];
23408 // Is the local used at all?
23409 if (tmpNum != BAD_VAR_NUM)
23411 var_types lclTyp = (var_types)lvaTable[tmpNum].lvType;
23412 noway_assert(lclTyp == lclVarInfo[lclNum + inlineInfo->argCnt].lclTypeInfo);
23414 if (!varTypeIsStruct(lclTyp))
23416 // Unsafe value cls check is not needed here since in-linee compiler instance would have
23417 // iterated over locals and marked accordingly.
23418 impAssignTempGen(tmpNum, gtNewZeroConNode(genActualType(lclTyp)), NO_CLASS_HANDLE,
23419 (unsigned)CHECK_SPILL_NONE, &afterStmt, callILOffset, block);
23423 CORINFO_CLASS_HANDLE structType =
23424 lclVarInfo[lclNum + inlineInfo->argCnt].lclVerTypeInfo.GetClassHandle();
23426 if (fgStructTempNeedsExplicitZeroInit(lvaTable + tmpNum, block))
23428 tree = gtNewBlkOpNode(gtNewLclvNode(tmpNum, lclTyp), // Dest
23429 gtNewIconNode(0), // Value
23430 info.compCompHnd->getClassSize(structType), // Size
23431 false, // isVolatile
23432 false); // not copyBlock
23434 newStmt = gtNewStmt(tree, callILOffset);
23435 afterStmt = fgInsertStmtAfter(block, afterStmt, newStmt);
23442 gtDispTree(afterStmt);
23449 // Update any newly added statements with the appropriate context.
23450 InlineContext* context = callStmt->gtInlineContext;
23451 assert(context != nullptr);
23452 for (GenTreeStmt* addedStmt = callStmt->gtNextStmt; addedStmt != postStmt; addedStmt = addedStmt->gtNextStmt)
23454 assert(addedStmt->gtInlineContext == nullptr);
23455 addedStmt->gtInlineContext = context;
23461 //------------------------------------------------------------------------
23462 // fgInlineAppendStatements: Append statements that are needed
23463 // after the inlined call.
23466 // inlineInfo - information about the inline
23467 // block - basic block for the new statements
23468 // stmtAfter - (optional) insertion point for mid-block cases
23471 // If the call we're inlining is in tail position then
23472 // we skip nulling the locals, since it can interfere
23473 // with tail calls introduced by the local.
23475 void Compiler::fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTree* stmtAfter)
23477 // If this inlinee was passed a runtime lookup generic context and
23478 // ignores it, we can decrement the "generic context was used" ref
23479 // count, because we created a new lookup tree and incremented the
23480 // count when we imported the type parameter argument to pass to
23481 // the inlinee. See corresponding logic in impImportCall that
23482 // checks the sig for CORINFO_CALLCONV_PARAMTYPE.
23484 // Does this method require a context (type) parameter?
23485 if ((inlineInfo->inlineCandidateInfo->methInfo.args.callConv & CORINFO_CALLCONV_PARAMTYPE) != 0)
23487 // Did the computation of that parameter require the
23488 // caller to perform a runtime lookup?
23489 if (inlineInfo->inlineCandidateInfo->exactContextNeedsRuntimeLookup)
23491 // Fetch the temp for the generic context as it would
23492 // appear in the inlinee's body.
23493 const unsigned typeCtxtArg = inlineInfo->typeContextArg;
23494 const unsigned tmpNum = inlineInfo->lclTmpNum[typeCtxtArg];
23496 // Was it used in the inline body?
23497 if (tmpNum == BAD_VAR_NUM)
23499 // No -- so the associated runtime lookup is not needed
23500 // and also no longer provides evidence that the generic
23501 // context should be kept alive.
23502 JITDUMP("Inlinee ignores runtime lookup generics context\n");
23503 assert(lvaGenericsContextUseCount > 0);
23504 lvaGenericsContextUseCount--;
23509 // Null out any gc ref locals
23510 if (!inlineInfo->HasGcRefLocals())
23512 // No ref locals, nothing to do.
23513 JITDUMP("fgInlineAppendStatements: no gc ref inline locals.\n");
23517 if (inlineInfo->iciCall->IsImplicitTailCall())
23519 JITDUMP("fgInlineAppendStatements: implicit tail call; skipping nulling.\n");
23523 JITDUMP("fgInlineAppendStatements: nulling out gc ref inlinee locals.\n");
23525 GenTree* callStmt = inlineInfo->iciStmt;
23526 IL_OFFSETX callILOffset = callStmt->gtStmt.gtStmtILoffsx;
23527 CORINFO_METHOD_INFO* InlineeMethodInfo = InlineeCompiler->info.compMethodInfo;
23528 const unsigned lclCnt = InlineeMethodInfo->locals.numArgs;
23529 InlLclVarInfo* lclVarInfo = inlineInfo->lclVarInfo;
23530 unsigned gcRefLclCnt = inlineInfo->numberOfGcRefLocals;
23531 const unsigned argCnt = inlineInfo->argCnt;
23533 noway_assert(callStmt->gtOper == GT_STMT);
23535 for (unsigned lclNum = 0; lclNum < lclCnt; lclNum++)
23537 // Is the local a gc ref type? Need to look at the
23538 // inline info for this since we will not have local
23539 // temps for unused inlinee locals.
23540 const var_types lclTyp = lclVarInfo[argCnt + lclNum].lclTypeInfo;
23542 if (!varTypeIsGC(lclTyp))
23544 // Nope, nothing to null out.
23548 // Ensure we're examining just the right number of locals.
23549 assert(gcRefLclCnt > 0);
23552 // Fetch the temp for this inline local
23553 const unsigned tmpNum = inlineInfo->lclTmpNum[lclNum];
23555 // Is the local used at all?
23556 if (tmpNum == BAD_VAR_NUM)
23558 // Nope, nothing to null out.
23562 // Local was used, make sure the type is consistent.
23563 assert(lvaTable[tmpNum].lvType == lclTyp);
23565 // Does the local we're about to null out appear in the return
23566 // expression? If so we somehow messed up and didn't properly
23567 // spill the return value. See impInlineFetchLocal.
23568 GenTree* retExpr = inlineInfo->retExpr;
23569 if (retExpr != nullptr)
23571 const bool interferesWithReturn = gtHasRef(inlineInfo->retExpr, tmpNum, false);
23572 noway_assert(!interferesWithReturn);
23575 // Assign null to the local.
23576 GenTree* nullExpr = gtNewTempAssign(tmpNum, gtNewZeroConNode(lclTyp));
23577 GenTree* nullStmt = gtNewStmt(nullExpr, callILOffset);
23579 if (stmtAfter == nullptr)
23581 stmtAfter = fgInsertStmtAtBeg(block, nullStmt);
23585 stmtAfter = fgInsertStmtAfter(block, stmtAfter, nullStmt);
23591 gtDispTree(nullStmt);
23596 // There should not be any GC ref locals left to null out.
23597 assert(gcRefLclCnt == 0);
23600 /*****************************************************************************/
23602 Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTree** pTree, fgWalkData* data)
23604 GenTree* tree = *pTree;
23606 // If this tree doesn't have the EXCEPT flag set, then there is no
23607 // way any of the child nodes could throw, so we can stop recursing.
23608 if (!(tree->gtFlags & GTF_EXCEPT))
23610 return Compiler::WALK_SKIP_SUBTREES;
23613 switch (tree->gtOper)
23618 #ifdef LEGACY_BACKEND
23623 if (tree->gtOverflow())
23625 return Compiler::WALK_ABORT;
23630 case GT_INDEX_ADDR:
23631 // These two call CORINFO_HELP_RNGCHKFAIL for Debug code
23632 if (tree->gtFlags & GTF_INX_RNGCHK)
23634 return Compiler::WALK_ABORT;
23638 case GT_ARR_BOUNDS_CHECK:
23639 return Compiler::WALK_ABORT;
23645 return Compiler::WALK_CONTINUE;
23648 /*****************************************************************************/
23650 Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTree** pTree, fgWalkData* data)
23652 GenTree* tree = *pTree;
23654 if (tree->gtOper == GT_LCLHEAP)
23656 return Compiler::WALK_ABORT;
23659 return Compiler::WALK_CONTINUE;
23662 /*****************************************************************************/
23664 Compiler::fgWalkResult Compiler::fgChkQmarkCB(GenTree** pTree, fgWalkData* data)
23666 GenTree* tree = *pTree;
23668 if (tree->gtOper == GT_QMARK)
23670 return Compiler::WALK_ABORT;
23673 return Compiler::WALK_CONTINUE;
23676 void Compiler::fgLclFldAssign(unsigned lclNum)
23678 assert(varTypeIsStruct(lvaTable[lclNum].lvType));
23679 if (lvaTable[lclNum].lvPromoted && lvaTable[lclNum].lvFieldCnt > 1)
23681 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
23685 //------------------------------------------------------------------------
23686 // fgRemoveEmptyFinally: Remove try/finallys where the finally is empty
23689 // Removes all try/finallys in the method with empty finallys.
23690 // These typically arise from inlining empty Dispose methods.
23692 // Converts callfinally to a jump to the finally continuation.
23693 // Removes the finally, and reparents all blocks in the try to the
23694 // enclosing try or method region.
23696 // Currently limited to trivially empty finallys: those with one basic
23697 // block containing only single RETFILT statement. It is possible but
23698 // not likely that more complex-looking finallys will eventually become
23699 // empty (from say subsequent optimization). An SPMI run with
23700 // just the "detection" part of this phase run after optimization
23701 // found only one example where a new empty finally was detected.
23703 void Compiler::fgRemoveEmptyFinally()
23705 JITDUMP("\n*************** In fgRemoveEmptyFinally()\n");
23707 #if FEATURE_EH_FUNCLETS
23708 // We need to do this transformation before funclets are created.
23709 assert(!fgFuncletsCreated);
23710 #endif // FEATURE_EH_FUNCLETS
23712 // Assume we don't need to update the bbPreds lists.
23713 assert(!fgComputePredsDone);
23715 if (compHndBBtabCount == 0)
23717 JITDUMP("No EH in this method, nothing to remove.\n");
23721 if (opts.MinOpts())
23723 JITDUMP("Method compiled with minOpts, no removal.\n");
23727 if (opts.compDbgCode)
23729 JITDUMP("Method compiled with debug codegen, no removal.\n");
23736 printf("\n*************** Before fgRemoveEmptyFinally()\n");
23737 fgDispBasicBlocks();
23738 fgDispHandlerTab();
23743 // Look for finallys or faults that are empty.
23744 unsigned finallyCount = 0;
23745 unsigned emptyCount = 0;
23746 unsigned XTnum = 0;
23747 while (XTnum < compHndBBtabCount)
23749 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
23751 // Check if this is a try/finally. We could also look for empty
23752 // try/fault but presumably those are rare.
23753 if (!HBtab->HasFinallyHandler())
23755 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
23762 // Look at blocks involved.
23763 BasicBlock* const firstBlock = HBtab->ebdHndBeg;
23764 BasicBlock* const lastBlock = HBtab->ebdHndLast;
23766 // Limit for now to finallys that are single blocks.
23767 if (firstBlock != lastBlock)
23769 JITDUMP("EH#%u finally has multiple basic blocks; skipping.\n", XTnum);
23774 // Limit for now to finallys that contain only a GT_RETFILT.
23775 bool isEmpty = true;
23777 for (GenTreeStmt* stmt = firstBlock->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
23779 GenTree* stmtExpr = stmt->gtStmtExpr;
23781 if (stmtExpr->gtOper != GT_RETFILT)
23790 JITDUMP("EH#%u finally is not empty; skipping.\n", XTnum);
23795 JITDUMP("EH#%u has empty finally, removing the region.\n", XTnum);
23797 // Find all the call finallys that invoke this finally,
23798 // and modify them to jump to the return point.
23799 BasicBlock* firstCallFinallyRangeBlock = nullptr;
23800 BasicBlock* endCallFinallyRangeBlock = nullptr;
23801 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
23803 BasicBlock* currentBlock = firstCallFinallyRangeBlock;
23805 while (currentBlock != endCallFinallyRangeBlock)
23807 BasicBlock* nextBlock = currentBlock->bbNext;
23809 if ((currentBlock->bbJumpKind == BBJ_CALLFINALLY) && (currentBlock->bbJumpDest == firstBlock))
23811 // Retarget the call finally to jump to the return
23814 // We don't expect to see retless finallys here, since
23815 // the finally is empty.
23816 noway_assert(currentBlock->isBBCallAlwaysPair());
23818 BasicBlock* const leaveBlock = currentBlock->bbNext;
23819 BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
23821 noway_assert(leaveBlock->bbJumpKind == BBJ_ALWAYS);
23823 currentBlock->bbJumpDest = postTryFinallyBlock;
23824 currentBlock->bbJumpKind = BBJ_ALWAYS;
23826 // Ref count updates.
23827 fgAddRefPred(postTryFinallyBlock, currentBlock);
23828 // fgRemoveRefPred(firstBlock, currentBlock);
23830 // Delete the leave block, which should be marked as
23832 assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
23833 nextBlock = leaveBlock->bbNext;
23835 leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
23836 fgRemoveBlock(leaveBlock, true);
23838 // Cleanup the postTryFinallyBlock
23839 fgCleanupContinuation(postTryFinallyBlock);
23841 // Make sure iteration isn't going off the deep end.
23842 assert(leaveBlock != endCallFinallyRangeBlock);
23845 currentBlock = nextBlock;
23848 // Handler block should now be unreferenced, since the only
23849 // explicit references to it were in call finallys.
23850 firstBlock->bbRefs = 0;
23852 // Remove the handler block.
23853 const bool unreachable = true;
23854 firstBlock->bbFlags &= ~BBF_DONT_REMOVE;
23855 fgRemoveBlock(firstBlock, unreachable);
23857 // Find enclosing try region for the try, if any, and update
23858 // the try region. Note the handler region (if any) won't
23860 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
23861 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
23862 assert(firstTryBlock->getTryIndex() == XTnum);
23864 for (BasicBlock* block = firstTryBlock; block != nullptr; block = block->bbNext)
23866 // Look for blocks directly contained in this try, and
23867 // update the try region appropriately.
23869 // Try region for blocks transitively contained (say in a
23870 // child try) will get updated by the subsequent call to
23871 // fgRemoveEHTableEntry.
23872 if (block->getTryIndex() == XTnum)
23874 if (firstBlock->hasTryIndex())
23876 block->setTryIndex(firstBlock->getTryIndex());
23880 block->clearTryIndex();
23884 if (block == firstTryBlock)
23886 assert((block->bbFlags & BBF_TRY_BEG) != 0);
23887 block->bbFlags &= ~BBF_TRY_BEG;
23890 if (block == lastTryBlock)
23896 // Remove the try-finally EH region. This will compact the EH table
23897 // so XTnum now points at the next entry.
23898 fgRemoveEHTableEntry(XTnum);
23903 if (emptyCount > 0)
23905 JITDUMP("fgRemoveEmptyFinally() removed %u try-finally clauses from %u finallys\n", emptyCount, finallyCount);
23906 fgOptimizedFinally = true;
23911 printf("\n*************** After fgRemoveEmptyFinally()\n");
23912 fgDispBasicBlocks();
23913 fgDispHandlerTab();
23917 fgVerifyHandlerTab();
23918 fgDebugCheckBBlist(false, false);
23924 //------------------------------------------------------------------------
23925 // fgRemoveEmptyTry: Optimize try/finallys where the try is empty
23928 // In runtimes where thread abort is not possible, `try {} finally {S}`
23929 // can be optimized to simply `S`. This method looks for such
23930 // cases and removes the try-finally from the EH table, making
23931 // suitable flow, block flag, statement, and region updates.
23933 // This optimization is not legal in runtimes that support thread
23934 // abort because those runtimes ensure that a finally is completely
23935 // executed before continuing to process the thread abort. With
23936 // this optimization, the code block `S` can lose special
23937 // within-finally status and so complete execution is no longer
23940 void Compiler::fgRemoveEmptyTry()
23942 JITDUMP("\n*************** In fgRemoveEmptyTry()\n");
23944 #if FEATURE_EH_FUNCLETS
23945 // We need to do this transformation before funclets are created.
23946 assert(!fgFuncletsCreated);
23947 #endif // FEATURE_EH_FUNCLETS
23949 // Assume we don't need to update the bbPreds lists.
23950 assert(!fgComputePredsDone);
23952 #ifdef FEATURE_CORECLR
23953 bool enableRemoveEmptyTry = true;
23955 // Code in a finally gets special treatment in the presence of
23957 bool enableRemoveEmptyTry = false;
23958 #endif // FEATURE_CORECLR
23961 // Allow override to enable/disable.
23962 enableRemoveEmptyTry = (JitConfig.JitEnableRemoveEmptyTry() == 1);
23965 if (!enableRemoveEmptyTry)
23967 JITDUMP("Empty try removal disabled.\n");
23971 if (compHndBBtabCount == 0)
23973 JITDUMP("No EH in this method, nothing to remove.\n");
23977 if (opts.MinOpts())
23979 JITDUMP("Method compiled with minOpts, no removal.\n");
23983 if (opts.compDbgCode)
23985 JITDUMP("Method compiled with debug codegen, no removal.\n");
23992 printf("\n*************** Before fgRemoveEmptyTry()\n");
23993 fgDispBasicBlocks();
23994 fgDispHandlerTab();
23999 // Look for try-finallys where the try is empty.
24000 unsigned emptyCount = 0;
24001 unsigned XTnum = 0;
24002 while (XTnum < compHndBBtabCount)
24004 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
24006 // Check if this is a try/finally. We could also look for empty
24007 // try/fault but presumably those are rare.
24008 if (!HBtab->HasFinallyHandler())
24010 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
24015 // Examine the try region
24016 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
24017 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
24018 BasicBlock* const firstHandlerBlock = HBtab->ebdHndBeg;
24019 BasicBlock* const lastHandlerBlock = HBtab->ebdHndLast;
24020 BasicBlock* const endHandlerBlock = lastHandlerBlock->bbNext;
24022 assert(firstTryBlock->getTryIndex() == XTnum);
24024 // Limit for now to trys that contain only a callfinally pair
24025 // or branch to same.
24026 if (!firstTryBlock->isEmpty())
24028 JITDUMP("EH#%u first try block BB%02u not empty; skipping.\n", XTnum, firstTryBlock->bbNum);
24033 #if FEATURE_EH_CALLFINALLY_THUNKS
24035 // Look for blocks that are always jumps to a call finally
24036 // pair that targets the finally
24037 if (firstTryBlock->bbJumpKind != BBJ_ALWAYS)
24039 JITDUMP("EH#%u first try block BB%02u not jump to a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum);
24044 BasicBlock* const callFinally = firstTryBlock->bbJumpDest;
24046 // Look for call always pair. Note this will also disqualify
24047 // empty try removal in cases where the finally doesn't
24049 if (!callFinally->isBBCallAlwaysPair() || (callFinally->bbJumpDest != firstHandlerBlock))
24051 JITDUMP("EH#%u first try block BB%02u always jumps but not to a callfinally; skipping.\n", XTnum,
24052 firstTryBlock->bbNum);
24057 // Try itself must be a single block.
24058 if (firstTryBlock != lastTryBlock)
24060 JITDUMP("EH#%u first try block BB%02u not only block in try; skipping.\n", XTnum,
24061 firstTryBlock->bbNext->bbNum);
24067 // Look for call always pair within the try itself. Note this
24068 // will also disqualify empty try removal in cases where the
24069 // finally doesn't return.
24070 if (!firstTryBlock->isBBCallAlwaysPair() || (firstTryBlock->bbJumpDest != firstHandlerBlock))
24072 JITDUMP("EH#%u first try block BB%02u not a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum);
24077 BasicBlock* const callFinally = firstTryBlock;
24079 // Try must be a callalways pair of blocks.
24080 if (firstTryBlock->bbNext != lastTryBlock)
24082 JITDUMP("EH#%u block BB%02u not last block in try; skipping.\n", XTnum, firstTryBlock->bbNext->bbNum);
24087 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24089 JITDUMP("EH#%u has empty try, removing the try region and promoting the finally.\n", XTnum);
24091 // There should be just one callfinally that invokes this
24092 // finally, the one we found above. Verify this.
24093 BasicBlock* firstCallFinallyRangeBlock = nullptr;
24094 BasicBlock* endCallFinallyRangeBlock = nullptr;
24095 bool verifiedSingleCallfinally = true;
24096 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
24098 for (BasicBlock* block = firstCallFinallyRangeBlock; block != endCallFinallyRangeBlock; block = block->bbNext)
24100 if ((block->bbJumpKind == BBJ_CALLFINALLY) && (block->bbJumpDest == firstHandlerBlock))
24102 assert(block->isBBCallAlwaysPair());
24104 if (block != callFinally)
24106 JITDUMP("EH#%u found unexpected callfinally BB%02u; skipping.\n");
24107 verifiedSingleCallfinally = false;
24111 block = block->bbNext;
24115 if (!verifiedSingleCallfinally)
24117 JITDUMP("EH#%u -- unexpectedly -- has multiple callfinallys; skipping.\n");
24119 assert(verifiedSingleCallfinally);
24123 // Time to optimize.
24125 // (1) Convert the callfinally to a normal jump to the handler
24126 callFinally->bbJumpKind = BBJ_ALWAYS;
24128 // Identify the leave block and the continuation
24129 BasicBlock* const leave = callFinally->bbNext;
24130 BasicBlock* const continuation = leave->bbJumpDest;
24132 // (2) Cleanup the leave so it can be deleted by subsequent opts
24133 assert((leave->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
24134 leave->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
24136 // (3) Cleanup the continuation
24137 fgCleanupContinuation(continuation);
24139 // (4) Find enclosing try region for the try, if any, and
24140 // update the try region for the blocks in the try. Note the
24141 // handler region (if any) won't change.
24143 // Kind of overkill to loop here, but hey.
24144 for (BasicBlock* block = firstTryBlock; block != nullptr; block = block->bbNext)
24146 // Look for blocks directly contained in this try, and
24147 // update the try region appropriately.
24149 // The try region for blocks transitively contained (say in a
24150 // child try) will get updated by the subsequent call to
24151 // fgRemoveEHTableEntry.
24152 if (block->getTryIndex() == XTnum)
24154 if (firstHandlerBlock->hasTryIndex())
24156 block->setTryIndex(firstHandlerBlock->getTryIndex());
24160 block->clearTryIndex();
24164 if (block == firstTryBlock)
24166 assert((block->bbFlags & BBF_TRY_BEG) != 0);
24167 block->bbFlags &= ~BBF_TRY_BEG;
24170 if (block == lastTryBlock)
24176 // (5) Update the directly contained handler blocks' handler index.
24177 // Handler index of any nested blocks will update when we
24178 // remove the EH table entry. Change handler exits to jump to
24179 // the continuation. Clear catch type on handler entry.
24180 // Decrement nesting level of enclosed GT_END_LFINs.
24181 for (BasicBlock* block = firstHandlerBlock; block != endHandlerBlock; block = block->bbNext)
24183 if (block == firstHandlerBlock)
24185 block->bbCatchTyp = BBCT_NONE;
24188 if (block->getHndIndex() == XTnum)
24190 if (firstTryBlock->hasHndIndex())
24192 block->setHndIndex(firstTryBlock->getHndIndex());
24196 block->clearHndIndex();
24199 if (block->bbJumpKind == BBJ_EHFINALLYRET)
24201 GenTreeStmt* finallyRet = block->lastStmt();
24202 GenTree* finallyRetExpr = finallyRet->gtStmtExpr;
24203 assert(finallyRetExpr->gtOper == GT_RETFILT);
24204 fgRemoveStmt(block, finallyRet);
24205 block->bbJumpKind = BBJ_ALWAYS;
24206 block->bbJumpDest = continuation;
24207 fgAddRefPred(continuation, block);
24211 #if !FEATURE_EH_FUNCLETS
24212 // If we're in a non-funclet model, decrement the nesting
24213 // level of any GT_END_LFIN we find in the handler region,
24214 // since we're removing the enclosing handler.
24215 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
24217 GenTree* expr = stmt->gtStmtExpr;
24218 if (expr->gtOper == GT_END_LFIN)
24220 const unsigned nestLevel = expr->gtVal.gtVal1;
24221 assert(nestLevel > 0);
24222 expr->gtVal.gtVal1 = nestLevel - 1;
24225 #endif // !FEATURE_EH_FUNCLETS
24228 // (6) Remove the try-finally EH region. This will compact the
24229 // EH table so XTnum now points at the next entry and will update
24230 // the EH region indices of any nested EH in the (former) handler.
24231 fgRemoveEHTableEntry(XTnum);
24233 // Another one bites the dust...
24237 if (emptyCount > 0)
24239 JITDUMP("fgRemoveEmptyTry() optimized %u empty-try try-finally clauses\n", emptyCount);
24240 fgOptimizedFinally = true;
24245 printf("\n*************** After fgRemoveEmptyTry()\n");
24246 fgDispBasicBlocks();
24247 fgDispHandlerTab();
24251 fgVerifyHandlerTab();
24252 fgDebugCheckBBlist(false, false);
24258 //------------------------------------------------------------------------
24259 // fgCloneFinally: Optimize normal exit path from a try/finally
24262 // Handles finallys that are not enclosed by or enclosing other
24263 // handler regions.
24265 // Converts the "normal exit" callfinally to a jump to a cloned copy
24266 // of the finally, which in turn jumps to the finally continuation.
24268 // If all callfinallys for a given finally are converted to jump to
24269 // the clone, the try-finally is modified into a try-fault,
24270 // distingushable from organic try-faults by handler type
24271 // EH_HANDLER_FAULT_WAS_FINALLY vs the organic EH_HANDLER_FAULT.
24273 // Does not yet handle thread abort. The open issues here are how
24274 // to maintain the proper description of the cloned finally blocks
24275 // as a handler (for thread abort purposes), how to prevent code
24276 // motion in or out of these blocks, and how to report this cloned
24277 // handler to the runtime. Some building blocks for thread abort
24278 // exist (see below) but more work needed.
24280 // The first and last blocks of the cloned finally are marked with
24281 // BBF_CLONED_FINALLY_BEGIN and BBF_CLONED_FINALLY_END. However
24282 // these markers currently can get lost during subsequent
24285 void Compiler::fgCloneFinally()
24287 JITDUMP("\n*************** In fgCloneFinally()\n");
24289 #if FEATURE_EH_FUNCLETS
24290 // We need to do this transformation before funclets are created.
24291 assert(!fgFuncletsCreated);
24292 #endif // FEATURE_EH_FUNCLETS
24294 // Assume we don't need to update the bbPreds lists.
24295 assert(!fgComputePredsDone);
24297 #ifdef FEATURE_CORECLR
24298 bool enableCloning = true;
24300 // Finally cloning currently doesn't provide sufficient protection
24301 // for the cloned code in the presence of thread abort.
24302 bool enableCloning = false;
24303 #endif // FEATURE_CORECLR
24306 // Allow override to enable/disable.
24307 enableCloning = (JitConfig.JitEnableFinallyCloning() == 1);
24310 if (!enableCloning)
24312 JITDUMP("Finally cloning disabled.\n");
24316 if (compHndBBtabCount == 0)
24318 JITDUMP("No EH in this method, no cloning.\n");
24322 if (opts.MinOpts())
24324 JITDUMP("Method compiled with minOpts, no cloning.\n");
24328 if (opts.compDbgCode)
24330 JITDUMP("Method compiled with debug codegen, no cloning.\n");
24337 printf("\n*************** Before fgCloneFinally()\n");
24338 fgDispBasicBlocks();
24339 fgDispHandlerTab();
24343 // Verify try-finally exits look good before we start.
24344 fgDebugCheckTryFinallyExits();
24348 // Look for finallys that are not contained within other handlers,
24349 // and which do not themselves contain EH.
24351 // Note these cases potentially could be handled, but are less
24352 // obviously profitable and require modification of the handler
24354 unsigned XTnum = 0;
24355 EHblkDsc* HBtab = compHndBBtab;
24356 unsigned cloneCount = 0;
24357 for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
24359 // Check if this is a try/finally
24360 if (!HBtab->HasFinallyHandler())
24362 JITDUMP("EH#%u is not a try-finally; skipping.\n", XTnum);
24366 // Check if enclosed by another handler.
24367 const unsigned enclosingHandlerRegion = ehGetEnclosingHndIndex(XTnum);
24369 if (enclosingHandlerRegion != EHblkDsc::NO_ENCLOSING_INDEX)
24371 JITDUMP("EH#%u is enclosed by handler EH#%u; skipping.\n", XTnum, enclosingHandlerRegion);
24375 bool containsEH = false;
24376 unsigned exampleEnclosedHandlerRegion = 0;
24378 // Only need to look at lower numbered regions because the
24379 // handler table is ordered by nesting.
24380 for (unsigned i = 0; i < XTnum; i++)
24382 if (ehGetEnclosingHndIndex(i) == XTnum)
24384 exampleEnclosedHandlerRegion = i;
24392 JITDUMP("Finally for EH#%u encloses handler EH#%u; skipping.\n", XTnum, exampleEnclosedHandlerRegion);
24396 // Look at blocks involved.
24397 BasicBlock* const firstBlock = HBtab->ebdHndBeg;
24398 BasicBlock* const lastBlock = HBtab->ebdHndLast;
24399 assert(firstBlock != nullptr);
24400 assert(lastBlock != nullptr);
24401 BasicBlock* nextBlock = lastBlock->bbNext;
24402 unsigned regionBBCount = 0;
24403 unsigned regionStmtCount = 0;
24404 bool hasFinallyRet = false;
24405 bool isAllRare = true;
24406 bool hasSwitch = false;
24408 for (const BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
24410 if (block->bbJumpKind == BBJ_SWITCH)
24418 // Should we compute statement cost here, or is it
24419 // premature...? For now just count statements I guess.
24420 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
24425 hasFinallyRet = hasFinallyRet || (block->bbJumpKind == BBJ_EHFINALLYRET);
24426 isAllRare = isAllRare && block->isRunRarely();
24429 // Skip cloning if the finally has a switch.
24432 JITDUMP("Finally in EH#%u has a switch; skipping.\n", XTnum);
24436 // Skip cloning if the finally must throw.
24437 if (!hasFinallyRet)
24439 JITDUMP("Finally in EH#%u does not return; skipping.\n", XTnum);
24443 // Skip cloning if the finally is rarely run code.
24446 JITDUMP("Finally in EH#%u is run rarely; skipping.\n", XTnum);
24450 // Empirical studies from CoreCLR and CoreFX show that less
24451 // that 1% of finally regions have more than 15
24452 // statements. So, to avoid potentially excessive code growth,
24453 // only clone finallys that have 15 or fewer statements.
24454 const unsigned stmtCountLimit = 15;
24455 if (regionStmtCount > stmtCountLimit)
24457 JITDUMP("Finally in EH#%u has %u statements, limit is %u; skipping.\n", XTnum, regionStmtCount,
24462 JITDUMP("EH#%u is a candidate for finally cloning:"
24463 " %u blocks, %u statements\n",
24464 XTnum, regionBBCount, regionStmtCount);
24466 // Walk the try region backwards looking for the last block
24467 // that transfers control to a callfinally.
24468 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
24469 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
24470 assert(firstTryBlock->getTryIndex() == XTnum);
24471 assert(bbInTryRegions(XTnum, lastTryBlock));
24472 BasicBlock* const beforeTryBlock = firstTryBlock->bbPrev;
24474 BasicBlock* normalCallFinallyBlock = nullptr;
24475 BasicBlock* normalCallFinallyReturn = nullptr;
24476 BasicBlock* cloneInsertAfter = HBtab->ebdTryLast;
24477 bool tryToRelocateCallFinally = false;
24479 for (BasicBlock* block = lastTryBlock; block != beforeTryBlock; block = block->bbPrev)
24481 #if FEATURE_EH_CALLFINALLY_THUNKS
24482 // Look for blocks that are always jumps to a call finally
24483 // pair that targets our finally.
24484 if (block->bbJumpKind != BBJ_ALWAYS)
24489 BasicBlock* const jumpDest = block->bbJumpDest;
24491 if (!jumpDest->isBBCallAlwaysPair() || (jumpDest->bbJumpDest != firstBlock))
24496 // Look for call finally pair directly within the try
24497 if (!block->isBBCallAlwaysPair() || (block->bbJumpDest != firstBlock))
24502 BasicBlock* const jumpDest = block;
24503 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24505 // Found our block.
24506 BasicBlock* const finallyReturnBlock = jumpDest->bbNext;
24507 BasicBlock* const postTryFinallyBlock = finallyReturnBlock->bbJumpDest;
24509 normalCallFinallyBlock = jumpDest;
24510 normalCallFinallyReturn = postTryFinallyBlock;
24512 #if FEATURE_EH_CALLFINALLY_THUNKS
24513 // When there are callfinally thunks, we don't expect to see the
24514 // callfinally within a handler region either.
24515 assert(!jumpDest->hasHndIndex());
24517 // Update the clone insertion point to just after the
24518 // call always pair.
24519 cloneInsertAfter = finallyReturnBlock;
24521 // We will consider moving the callfinally so we can fall
24522 // through from the try into the clone.
24523 tryToRelocateCallFinally = true;
24525 JITDUMP("Chose path to clone: try block BB%02u jumps to callfinally at BB%02u;"
24526 " the call returns to BB%02u which jumps to BB%02u\n",
24527 block->bbNum, jumpDest->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
24529 JITDUMP("Chose path to clone: try block BB%02u is a callfinally;"
24530 " the call returns to BB%02u which jumps to BB%02u\n",
24531 block->bbNum, finallyReturnBlock->bbNum, postTryFinallyBlock->bbNum);
24532 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24537 // If there is no call to the finally, don't clone.
24538 if (normalCallFinallyBlock == nullptr)
24540 JITDUMP("EH#%u: no calls from the try to the finally, skipping.\n", XTnum);
24544 JITDUMP("Will update callfinally block BB%02u to jump to the clone;"
24545 " clone will jump to BB%02u\n",
24546 normalCallFinallyBlock->bbNum, normalCallFinallyReturn->bbNum);
24548 // If there are multiple callfinallys and we're in the
24549 // callfinally thunk model, all the callfinallys are placed
24550 // just outside the try region. We'd like our chosen
24551 // callfinally to come first after the try, so we can fall out of the try
24553 BasicBlock* firstCallFinallyRangeBlock = nullptr;
24554 BasicBlock* endCallFinallyRangeBlock = nullptr;
24555 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
24557 if (tryToRelocateCallFinally)
24559 BasicBlock* firstCallFinallyBlock = nullptr;
24561 for (BasicBlock* block = firstCallFinallyRangeBlock; block != endCallFinallyRangeBlock;
24562 block = block->bbNext)
24564 if (block->isBBCallAlwaysPair())
24566 if (block->bbJumpDest == firstBlock)
24568 firstCallFinallyBlock = block;
24574 // We better have found at least one call finally.
24575 assert(firstCallFinallyBlock != nullptr);
24577 // If there is more than one callfinally, move the one we are
24578 // going to retarget to be first in the callfinally range.
24579 if (firstCallFinallyBlock != normalCallFinallyBlock)
24581 JITDUMP("Moving callfinally BB%02u to be first in line, before BB%02u\n", normalCallFinallyBlock->bbNum,
24582 firstCallFinallyBlock->bbNum);
24584 BasicBlock* const firstToMove = normalCallFinallyBlock;
24585 BasicBlock* const lastToMove = normalCallFinallyBlock->bbNext;
24586 BasicBlock* const placeToMoveAfter = firstCallFinallyBlock->bbPrev;
24588 fgUnlinkRange(firstToMove, lastToMove);
24589 fgMoveBlocksAfter(firstToMove, lastToMove, placeToMoveAfter);
24593 fgDebugCheckBBlist(false, false);
24594 fgVerifyHandlerTab();
24597 assert(nextBlock == lastBlock->bbNext);
24599 // Update where the callfinally range begins, since we might
24600 // have altered this with callfinally rearrangement, and/or
24601 // the range begin might have been pretty loose to begin with.
24602 firstCallFinallyRangeBlock = normalCallFinallyBlock;
24606 // Clone the finally and retarget the normal return path and
24607 // any other path that happens to share that same return
24608 // point. For instance a construct like:
24610 // try { } catch { } finally { }
24612 // will have two call finally blocks, one for the normal exit
24613 // from the try, and the the other for the exit from the
24614 // catch. They'll both pass the same return point which is the
24615 // statement after the finally, so they can share the clone.
24617 // Clone the finally body, and splice it into the flow graph
24618 // within in the parent region of the try.
24619 const unsigned finallyTryIndex = firstBlock->bbTryIndex;
24620 BasicBlock* insertAfter = nullptr;
24621 BlockToBlockMap blockMap(getAllocator());
24622 bool clonedOk = true;
24623 unsigned cloneBBCount = 0;
24625 for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
24627 BasicBlock* newBlock;
24629 if (block == firstBlock)
24631 // Put first cloned finally block into the approprate
24632 // region, somewhere within or after the range of
24633 // callfinallys, depending on the EH implementation.
24634 const unsigned hndIndex = 0;
24635 BasicBlock* const nearBlk = cloneInsertAfter;
24636 newBlock = fgNewBBinRegion(block->bbJumpKind, finallyTryIndex, hndIndex, nearBlk);
24638 // If the clone ends up just after the finally, adjust
24639 // the stopping point for finally traversal.
24640 if (newBlock->bbNext == nextBlock)
24642 assert(newBlock->bbPrev == lastBlock);
24643 nextBlock = newBlock;
24648 // Put subsequent blocks in the same region...
24649 const bool extendRegion = true;
24650 newBlock = fgNewBBafter(block->bbJumpKind, insertAfter, extendRegion);
24654 assert(cloneBBCount <= regionBBCount);
24656 insertAfter = newBlock;
24657 blockMap.Set(block, newBlock);
24659 clonedOk = BasicBlock::CloneBlockState(this, newBlock, block);
24666 // Update block flags. Note a block can be both first and last.
24667 if (block == firstBlock)
24669 // Mark the block as the start of the cloned finally.
24670 newBlock->bbFlags |= BBF_CLONED_FINALLY_BEGIN;
24673 if (block == lastBlock)
24675 // Mark the block as the end of the cloned finally.
24676 newBlock->bbFlags |= BBF_CLONED_FINALLY_END;
24679 // Make sure clone block state hasn't munged the try region.
24680 assert(newBlock->bbTryIndex == finallyTryIndex);
24682 // Cloned handler block is no longer within the handler.
24683 newBlock->clearHndIndex();
24685 // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them.
24686 assert(newBlock->bbJumpDest == nullptr);
24691 // TODO: cleanup the partial clone?
24692 JITDUMP("Unable to clone the finally; skipping.\n");
24696 // We should have cloned all the finally region blocks.
24697 assert(cloneBBCount == regionBBCount);
24699 JITDUMP("Cloned finally blocks are: BB%2u ... BB%2u\n", blockMap[firstBlock]->bbNum,
24700 blockMap[lastBlock]->bbNum);
24702 // Redirect redirect any branches within the newly-cloned
24703 // finally, and any finally returns to jump to the return
24705 for (BasicBlock* block = firstBlock; block != nextBlock; block = block->bbNext)
24707 BasicBlock* newBlock = blockMap[block];
24709 if (block->bbJumpKind == BBJ_EHFINALLYRET)
24711 GenTreeStmt* finallyRet = newBlock->lastStmt();
24712 GenTree* finallyRetExpr = finallyRet->gtStmtExpr;
24713 assert(finallyRetExpr->gtOper == GT_RETFILT);
24714 fgRemoveStmt(newBlock, finallyRet);
24715 newBlock->bbJumpKind = BBJ_ALWAYS;
24716 newBlock->bbJumpDest = normalCallFinallyReturn;
24718 fgAddRefPred(normalCallFinallyReturn, newBlock);
24722 optCopyBlkDest(block, newBlock);
24723 optRedirectBlock(newBlock, &blockMap);
24727 // Modify the targeting call finallys to branch to the cloned
24728 // finally. Make a note if we see some calls that can't be
24729 // retargeted (since they want to return to other places).
24730 BasicBlock* const firstCloneBlock = blockMap[firstBlock];
24731 bool retargetedAllCalls = true;
24732 BasicBlock* currentBlock = firstCallFinallyRangeBlock;
24734 while (currentBlock != endCallFinallyRangeBlock)
24736 BasicBlock* nextBlockToScan = currentBlock->bbNext;
24738 if (currentBlock->isBBCallAlwaysPair())
24740 if (currentBlock->bbJumpDest == firstBlock)
24742 BasicBlock* const leaveBlock = currentBlock->bbNext;
24743 BasicBlock* const postTryFinallyBlock = leaveBlock->bbJumpDest;
24745 // Note we must retarget all callfinallies that have this
24746 // continuation, or we can't clean up the continuation
24747 // block properly below, since it will be reachable both
24748 // by the cloned finally and by the called finally.
24749 if (postTryFinallyBlock == normalCallFinallyReturn)
24751 // This call returns to the expected spot, so
24752 // retarget it to branch to the clone.
24753 currentBlock->bbJumpDest = firstCloneBlock;
24754 currentBlock->bbJumpKind = BBJ_ALWAYS;
24756 // Ref count updates.
24757 fgAddRefPred(firstCloneBlock, currentBlock);
24758 // fgRemoveRefPred(firstBlock, currentBlock);
24760 // Delete the leave block, which should be marked as
24762 assert((leaveBlock->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0);
24763 nextBlock = leaveBlock->bbNext;
24765 leaveBlock->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
24766 fgRemoveBlock(leaveBlock, true);
24768 // Make sure iteration isn't going off the deep end.
24769 assert(leaveBlock != endCallFinallyRangeBlock);
24773 // We can't retarget this call since it
24774 // returns somewhere else.
24775 retargetedAllCalls = false;
24780 currentBlock = nextBlockToScan;
24783 // If we retargeted all calls, modify EH descriptor to be
24784 // try-fault instead of try-finally, and then non-cloned
24785 // finally catch type to be fault.
24786 if (retargetedAllCalls)
24788 JITDUMP("All callfinallys retargeted; changing finally to fault.\n");
24789 HBtab->ebdHandlerType = EH_HANDLER_FAULT_WAS_FINALLY;
24790 firstBlock->bbCatchTyp = BBCT_FAULT;
24794 JITDUMP("Some callfinallys *not* retargeted, so region must remain as a finally.\n");
24797 // Modify first block of cloned finally to be a "normal" block.
24798 BasicBlock* firstClonedBlock = blockMap[firstBlock];
24799 firstClonedBlock->bbCatchTyp = BBCT_NONE;
24801 // Cleanup the continuation
24802 fgCleanupContinuation(normalCallFinallyReturn);
24804 // Todo -- mark cloned blocks as a cloned finally....
24807 JITDUMP("\nDone with EH#%u\n\n", XTnum);
24811 if (cloneCount > 0)
24813 JITDUMP("fgCloneFinally() cloned %u finally handlers\n", cloneCount);
24814 fgOptimizedFinally = true;
24819 printf("\n*************** After fgCloneFinally()\n");
24820 fgDispBasicBlocks();
24821 fgDispHandlerTab();
24825 fgVerifyHandlerTab();
24826 fgDebugCheckBBlist(false, false);
24827 fgDebugCheckTryFinallyExits();
24835 //------------------------------------------------------------------------
24836 // fgDebugCheckTryFinallyExits: validate normal flow from try-finally
24837 // or try-fault-was-finally.
24841 // Normal control flow exiting the try block of a try-finally must
24842 // pass through the finally. This checker attempts to verify that by
24843 // looking at the control flow graph.
24845 // Each path that exits the try of a try-finally (including try-faults
24846 // that were optimized into try-finallys by fgCloneFinally) should
24847 // thus either execute a callfinally to the associated finally or else
24848 // jump to a block with the BBF_CLONED_FINALLY_BEGIN flag set.
24850 // Depending on when this check is done, there may also be an empty
24851 // block along the path.
24853 // Depending on the model for invoking finallys, the callfinallies may
24854 // lie within the try region (callfinally thunks) or in the enclosing
24857 void Compiler::fgDebugCheckTryFinallyExits()
24859 unsigned XTnum = 0;
24860 EHblkDsc* HBtab = compHndBBtab;
24861 unsigned cloneCount = 0;
24862 bool allTryExitsValid = true;
24863 for (; XTnum < compHndBBtabCount; XTnum++, HBtab++)
24865 const EHHandlerType handlerType = HBtab->ebdHandlerType;
24866 const bool isFinally = (handlerType == EH_HANDLER_FINALLY);
24867 const bool wasFinally = (handlerType == EH_HANDLER_FAULT_WAS_FINALLY);
24869 // Screen out regions that are or were not finallys.
24870 if (!isFinally && !wasFinally)
24875 // Walk blocks of the try, looking for normal control flow to
24876 // an ancestor region.
24878 BasicBlock* const firstTryBlock = HBtab->ebdTryBeg;
24879 BasicBlock* const lastTryBlock = HBtab->ebdTryLast;
24880 assert(firstTryBlock->getTryIndex() <= XTnum);
24881 assert(lastTryBlock->getTryIndex() <= XTnum);
24882 BasicBlock* const afterTryBlock = lastTryBlock->bbNext;
24883 BasicBlock* const finallyBlock = isFinally ? HBtab->ebdHndBeg : nullptr;
24885 for (BasicBlock* block = firstTryBlock; block != afterTryBlock; block = block->bbNext)
24887 // Only check the directly contained blocks.
24888 assert(block->hasTryIndex());
24890 if (block->getTryIndex() != XTnum)
24895 // Look at each of the normal control flow possibilities.
24896 const unsigned numSuccs = block->NumSucc();
24898 for (unsigned i = 0; i < numSuccs; i++)
24900 BasicBlock* const succBlock = block->GetSucc(i);
24902 if (succBlock->hasTryIndex() && succBlock->getTryIndex() <= XTnum)
24904 // Successor does not exit this try region.
24908 #if FEATURE_EH_CALLFINALLY_THUNKS
24910 // When there are callfinally thunks, callfinallies
24911 // logically "belong" to a child region and the exit
24912 // path validity will be checked when looking at the
24913 // try blocks in that region.
24914 if (block->bbJumpKind == BBJ_CALLFINALLY)
24919 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24921 // Now we know block lies directly within the try of a
24922 // try-finally, and succBlock is in an enclosing
24923 // region (possibly the method region). So this path
24924 // represents flow out of the try and should be
24927 // There are various ways control can properly leave a
24928 // try-finally (or try-fault-was-finally):
24930 // (a1) via a jump to a callfinally (only for finallys, only for call finally thunks)
24931 // (a2) via a callfinally (only for finallys, only for !call finally thunks)
24932 // (b) via a jump to a begin finally clone block
24933 // (c) via a jump to an empty block to (b)
24934 // (d) via a fallthrough to an empty block to (b)
24935 // (e) via the always half of a callfinally pair
24936 // (f) via an always jump clonefinally exit
24937 bool isCallToFinally = false;
24939 #if FEATURE_EH_CALLFINALLY_THUNKS
24940 if (succBlock->bbJumpKind == BBJ_CALLFINALLY)
24943 isCallToFinally = isFinally && (succBlock->bbJumpDest == finallyBlock);
24946 if (block->bbJumpKind == BBJ_CALLFINALLY)
24949 isCallToFinally = isFinally && (block->bbJumpDest == finallyBlock);
24951 #endif // FEATURE_EH_CALLFINALLY_THUNKS
24953 bool isJumpToClonedFinally = false;
24955 if (succBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24958 isJumpToClonedFinally = true;
24960 else if (succBlock->bbJumpKind == BBJ_ALWAYS)
24962 if (succBlock->isEmpty())
24965 BasicBlock* const succSuccBlock = succBlock->bbJumpDest;
24967 if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24969 isJumpToClonedFinally = true;
24973 else if (succBlock->bbJumpKind == BBJ_NONE)
24975 if (succBlock->isEmpty())
24977 BasicBlock* const succSuccBlock = succBlock->bbNext;
24980 if (succSuccBlock->bbFlags & BBF_CLONED_FINALLY_BEGIN)
24982 isJumpToClonedFinally = true;
24987 bool isReturnFromFinally = false;
24989 // Case (e). Ideally we'd have something stronger to
24990 // check here -- eg that we are returning from a call
24991 // to the right finally -- but there are odd cases
24992 // like orphaned second halves of callfinally pairs
24993 // that we need to tolerate.
24994 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
24996 isReturnFromFinally = true;
25000 if (block->bbFlags & BBF_CLONED_FINALLY_END)
25002 isReturnFromFinally = true;
25005 const bool thisExitValid = isCallToFinally || isJumpToClonedFinally || isReturnFromFinally;
25007 if (!thisExitValid)
25009 JITDUMP("fgCheckTryFinallyExitS: EH#%u exit via BB%02u -> BB%02u is invalid\n", XTnum, block->bbNum,
25013 allTryExitsValid = allTryExitsValid & thisExitValid;
25018 if (!allTryExitsValid)
25020 JITDUMP("fgCheckTryFinallyExits: method contains invalid try exit paths\n");
25021 assert(allTryExitsValid);
25027 //------------------------------------------------------------------------
25028 // fgCleanupContinuation: cleanup a finally continuation after a
25029 // finally is removed or converted to normal control flow.
25032 // The continuation is the block targeted by the second half of
25033 // a callfinally/always pair.
25035 // Used by finally cloning, empty try removal, and empty
25036 // finally removal.
25038 // BBF_FINALLY_TARGET bbFlag is left unchanged by this method
25039 // since it cannot be incrementally updated. Proper updates happen
25040 // when fgUpdateFinallyTargetFlags runs after all finally optimizations.
25042 void Compiler::fgCleanupContinuation(BasicBlock* continuation)
25044 // The continuation may be a finalStep block.
25045 // It is now a normal block, so clear the special keep
25047 continuation->bbFlags &= ~BBF_KEEP_BBJ_ALWAYS;
25049 #if !FEATURE_EH_FUNCLETS
25050 // Remove the GT_END_LFIN from the continuation,
25051 // Note we only expect to see one such statement.
25052 bool foundEndLFin = false;
25053 for (GenTreeStmt* stmt = continuation->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
25055 GenTree* expr = stmt->gtStmtExpr;
25056 if (expr->gtOper == GT_END_LFIN)
25058 assert(!foundEndLFin);
25059 fgRemoveStmt(continuation, stmt);
25060 foundEndLFin = true;
25063 assert(foundEndLFin);
25064 #endif // !FEATURE_EH_FUNCLETS
25067 //------------------------------------------------------------------------
25068 // fgUpdateFinallyTargetFlags: recompute BBF_FINALLY_TARGET bits for all blocks
25069 // after finally optimizations have run.
25071 void Compiler::fgUpdateFinallyTargetFlags()
25073 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25075 // Any fixup required?
25076 if (!fgOptimizedFinally)
25078 JITDUMP("In fgUpdateFinallyTargetFlags - no finally opts, no fixup required\n");
25082 JITDUMP("In fgUpdateFinallyTargetFlags, updating finally target flag bits\n");
25084 fgClearAllFinallyTargetBits();
25085 fgAddFinallyTargetFlags();
25087 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25090 //------------------------------------------------------------------------
25091 // fgClearAllFinallyTargetBits: Clear all BBF_FINALLY_TARGET bits; these will need to be
25092 // recomputed later.
25094 void Compiler::fgClearAllFinallyTargetBits()
25096 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25098 JITDUMP("*************** In fgClearAllFinallyTargetBits()\n");
25100 // Note that we clear the flags even if there are no EH clauses (compHndBBtabCount == 0)
25101 // in case bits are left over from EH clauses being deleted.
25103 // Walk all blocks, and reset the target bits.
25104 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25106 block->bbFlags &= ~BBF_FINALLY_TARGET;
25109 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25112 //------------------------------------------------------------------------
25113 // fgAddFinallyTargetFlags: Add BBF_FINALLY_TARGET bits to all finally targets.
25115 void Compiler::fgAddFinallyTargetFlags()
25117 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25119 JITDUMP("*************** In fgAddFinallyTargetFlags()\n");
25121 if (compHndBBtabCount == 0)
25123 JITDUMP("No EH in this method, no flags to set.\n");
25127 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25129 if (block->isBBCallAlwaysPair())
25131 BasicBlock* const leave = block->bbNext;
25132 BasicBlock* const continuation = leave->bbJumpDest;
25134 if ((continuation->bbFlags & BBF_FINALLY_TARGET) == 0)
25136 JITDUMP("Found callfinally BB%02u; setting finally target bit on BB%02u\n", block->bbNum,
25137 continuation->bbNum);
25139 continuation->bbFlags |= BBF_FINALLY_TARGET;
25143 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
25146 //------------------------------------------------------------------------
25147 // fgMergeFinallyChains: tail merge finally invocations
25151 // Looks for common suffixes in chains of finally invocations
25152 // (callfinallys) and merges them. These typically arise from
25153 // try-finallys where there are multiple exit points in the try
25154 // that have the same target.
25156 void Compiler::fgMergeFinallyChains()
25158 JITDUMP("\n*************** In fgMergeFinallyChains()\n");
25160 #if FEATURE_EH_FUNCLETS
25161 // We need to do this transformation before funclets are created.
25162 assert(!fgFuncletsCreated);
25163 #endif // FEATURE_EH_FUNCLETS
25165 // Assume we don't need to update the bbPreds lists.
25166 assert(!fgComputePredsDone);
25168 if (compHndBBtabCount == 0)
25170 JITDUMP("No EH in this method, nothing to merge.\n");
25174 if (opts.MinOpts())
25176 JITDUMP("Method compiled with minOpts, no merging.\n");
25180 if (opts.compDbgCode)
25182 JITDUMP("Method compiled with debug codegen, no merging.\n");
25186 bool enableMergeFinallyChains = true;
25188 #if !FEATURE_EH_FUNCLETS
25189 // For non-funclet models (x86) the callfinallys may contain
25190 // statements and the continuations contain GT_END_LFINs. So no
25191 // merging is possible until the GT_END_LFIN blocks can be merged
25192 // and merging is not safe unless the callfinally blocks are split.
25193 JITDUMP("EH using non-funclet model; merging not yet implemented.\n");
25194 enableMergeFinallyChains = false;
25195 #endif // !FEATURE_EH_FUNCLETS
25197 #if !FEATURE_EH_CALLFINALLY_THUNKS
25198 // For non-thunk EH models (arm32) the callfinallys may contain
25199 // statements, and merging is not safe unless the callfinally
25200 // blocks are split.
25201 JITDUMP("EH using non-callfinally thunk model; merging not yet implemented.\n");
25202 enableMergeFinallyChains = false;
25205 if (!enableMergeFinallyChains)
25207 JITDUMP("fgMergeFinallyChains disabled\n");
25214 printf("\n*************** Before fgMergeFinallyChains()\n");
25215 fgDispBasicBlocks();
25216 fgDispHandlerTab();
25221 // Look for finallys.
25222 bool hasFinally = false;
25223 for (unsigned XTnum = 0; XTnum < compHndBBtabCount; XTnum++)
25225 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
25227 // Check if this is a try/finally.
25228 if (HBtab->HasFinallyHandler())
25237 JITDUMP("Method does not have any try-finallys; no merging.\n");
25241 // Process finallys from outside in, merging as we go. This gives
25242 // us the desired bottom-up tail merge order for callfinally
25243 // chains: outer merges may enable inner merges.
25244 bool canMerge = false;
25245 bool didMerge = false;
25246 BlockToBlockMap continuationMap(getAllocator());
25248 // Note XTnum is signed here so we can count down.
25249 for (int XTnum = compHndBBtabCount - 1; XTnum >= 0; XTnum--)
25251 EHblkDsc* const HBtab = &compHndBBtab[XTnum];
25253 // Screen out non-finallys
25254 if (!HBtab->HasFinallyHandler())
25259 JITDUMP("Examining callfinallys for EH#%d.\n", XTnum);
25261 // Find all the callfinallys that invoke this finally.
25262 BasicBlock* firstCallFinallyRangeBlock = nullptr;
25263 BasicBlock* endCallFinallyRangeBlock = nullptr;
25264 ehGetCallFinallyBlockRange(XTnum, &firstCallFinallyRangeBlock, &endCallFinallyRangeBlock);
25266 // Clear out any stale entries in the continuation map
25267 continuationMap.RemoveAll();
25269 // Build a map from each continuation to the "canonical"
25270 // callfinally for that continuation.
25271 unsigned callFinallyCount = 0;
25272 BasicBlock* const beginHandlerBlock = HBtab->ebdHndBeg;
25274 for (BasicBlock* currentBlock = firstCallFinallyRangeBlock; currentBlock != endCallFinallyRangeBlock;
25275 currentBlock = currentBlock->bbNext)
25277 // Ignore "retless" callfinallys (where the finally doesn't return).
25278 if (currentBlock->isBBCallAlwaysPair() && (currentBlock->bbJumpDest == beginHandlerBlock))
25280 // The callfinally must be empty, so that we can
25281 // safely retarget anything that branches here to
25282 // another callfinally with the same contiuation.
25283 assert(currentBlock->isEmpty());
25285 // This callfinally invokes the finally for this try.
25286 callFinallyCount++;
25288 // Locate the continuation
25289 BasicBlock* const leaveBlock = currentBlock->bbNext;
25290 BasicBlock* const continuationBlock = leaveBlock->bbJumpDest;
25292 // If this is the first time we've seen this
25293 // continuation, register this callfinally as the
25295 if (!continuationMap.Lookup(continuationBlock))
25297 continuationMap.Set(continuationBlock, currentBlock);
25302 // Now we've seen all the callfinallys and their continuations.
25303 JITDUMP("EH#%i has %u callfinallys, %u continuations\n", XTnum, callFinallyCount, continuationMap.GetCount());
25305 // If there are more callfinallys than continuations, some of the
25306 // callfinallys must share a continuation, and we can merge them.
25307 const bool tryMerge = callFinallyCount > continuationMap.GetCount();
25311 JITDUMP("EH#%i does not have any mergeable callfinallys\n", XTnum);
25317 // Walk the callfinally region, looking for blocks that jump
25318 // to a callfinally that invokes this try's finally, and make
25319 // sure they all jump to the appropriate canonical
25321 for (BasicBlock* currentBlock = firstCallFinallyRangeBlock; currentBlock != endCallFinallyRangeBlock;
25322 currentBlock = currentBlock->bbNext)
25324 bool merged = fgRetargetBranchesToCanonicalCallFinally(currentBlock, beginHandlerBlock, continuationMap);
25325 didMerge = didMerge || merged;
25331 JITDUMP("Method had try-finallys, but did not have any mergeable finally chains.\n");
25337 JITDUMP("Method had mergeable try-finallys and some callfinally merges were performed.\n");
25342 printf("\n*************** After fgMergeFinallyChains()\n");
25343 fgDispBasicBlocks();
25344 fgDispHandlerTab();
25352 // We may not end up doing any merges, because we are only
25353 // merging continuations for callfinallys that can
25354 // actually be invoked, and the importer may leave
25355 // unreachable callfinallys around (for instance, if it
25356 // is forced to re-import a leave).
25357 JITDUMP("Method had mergeable try-finallys but no callfinally merges were performed,\n"
25358 "likely the non-canonical callfinallys were unreachable\n");
25363 //------------------------------------------------------------------------
25364 // fgRetargetBranchesToCanonicalCallFinally: find non-canonical callfinally
25365 // invocations and make them canonical.
25368 // block -- block to examine for call finally invocation
25369 // handler -- start of the finally region for the try
25370 // continuationMap -- map giving the canonical callfinally for
25371 // each continuation
25374 // true iff the block's branch was retargeted.
25376 bool Compiler::fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
25377 BasicBlock* handler,
25378 BlockToBlockMap& continuationMap)
25380 // We expect callfinallys to be invoked by a BBJ_ALWAYS at this
25381 // stage in compilation.
25382 if (block->bbJumpKind != BBJ_ALWAYS)
25384 // Possible paranoia assert here -- no flow successor of
25385 // this block should be a callfinally for this try.
25389 // Screen out cases that are not callfinallys to the right
25391 BasicBlock* const callFinally = block->bbJumpDest;
25393 if (!callFinally->isBBCallAlwaysPair())
25398 if (callFinally->bbJumpDest != handler)
25403 // Ok, this is a callfinally that invokes the right handler.
25404 // Get its continuation.
25405 BasicBlock* const leaveBlock = callFinally->bbNext;
25406 BasicBlock* const continuationBlock = leaveBlock->bbJumpDest;
25408 // Find the canonical callfinally for that continuation.
25409 BasicBlock* const canonicalCallFinally = continuationMap[continuationBlock];
25410 assert(canonicalCallFinally != nullptr);
25412 // If the block already jumps to the canoncial call finally, no work needed.
25413 if (block->bbJumpDest == canonicalCallFinally)
25415 JITDUMP("BB%02u already canonical\n", block->bbNum);
25419 // Else, retarget it so that it does...
25420 JITDUMP("Redirecting branch in BB%02u from BB%02u to BB%02u.\n", block->bbNum, callFinally->bbNum,
25421 canonicalCallFinally->bbNum);
25423 block->bbJumpDest = canonicalCallFinally;
25424 fgAddRefPred(canonicalCallFinally, block);
25425 assert(callFinally->bbRefs > 0);
25426 fgRemoveRefPred(callFinally, block);
25431 // FatCalliTransformer transforms calli that can use fat function pointer.
25432 // Fat function pointer is pointer with the second least significant bit set,
25433 // if the bit is set, the pointer (after clearing the bit) actually points to
25434 // a tuple <method pointer, instantiation argument pointer> where
25435 // instantiationArgument is a hidden first argument required by method pointer.
25437 // Fat pointers are used in CoreRT as a replacement for instantiating stubs,
25438 // because CoreRT can't generate stubs in runtime.
25440 // Jit is responsible for the checking the bit, do the regular call if it is not set
25441 // or load hidden argument, fix the pointer and make a call with the fixed pointer and
25442 // the instantiation argument.
25447 // previous statements
25448 // transforming statement
25450 // call with GTF_CALL_M_FAT_POINTER_CHECK flag set in function ptr
25452 // subsequent statements
25458 // previous statements
25459 // } BBJ_NONE check block
25462 // jump to else if function ptr has GTF_CALL_M_FAT_POINTER_CHECK set.
25463 // } BBJ_COND then block, else block
25466 // original statement
25467 // } BBJ_ALWAYS remainder block
25470 // unset GTF_CALL_M_FAT_POINTER_CHECK
25471 // load actual function pointer
25472 // load instantiation argument
25473 // create newArgList = (instantiation argument, original argList)
25474 // call (actual function pointer, newArgList)
25475 // } BBJ_NONE remainder block
25478 // subsequent statements
25481 class FatCalliTransformer
25484 FatCalliTransformer(Compiler* compiler) : compiler(compiler)
25488 //------------------------------------------------------------------------
25489 // Run: run transformation for each block.
25493 for (BasicBlock* block = compiler->fgFirstBB; block != nullptr; block = block->bbNext)
25495 TransformBlock(block);
25500 //------------------------------------------------------------------------
25501 // TransformBlock: look through statements and transform statements with fat pointer calls.
25503 void TransformBlock(BasicBlock* block)
25505 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
25507 if (ContainsFatCalli(stmt))
25509 StatementTransformer stmtTransformer(compiler, block, stmt);
25510 stmtTransformer.Run();
25515 //------------------------------------------------------------------------
25516 // ContainsFatCalli: check does this statement contain fat pointer call.
25518 // Checks fatPointerCandidate in form of call() or lclVar = call().
25521 // true if contains, false otherwise.
25523 bool ContainsFatCalli(GenTreeStmt* stmt)
25525 GenTree* fatPointerCandidate = stmt->gtStmtExpr;
25526 if (fatPointerCandidate->OperIsAssignment())
25528 fatPointerCandidate = fatPointerCandidate->gtGetOp2();
25530 return fatPointerCandidate->IsCall() && fatPointerCandidate->AsCall()->IsFatPointerCandidate();
25533 class StatementTransformer
25536 StatementTransformer(Compiler* compiler, BasicBlock* block, GenTreeStmt* stmt)
25537 : compiler(compiler), currBlock(block), stmt(stmt)
25539 remainderBlock = nullptr;
25540 checkBlock = nullptr;
25541 thenBlock = nullptr;
25542 elseBlock = nullptr;
25543 doesReturnValue = stmt->gtStmtExpr->OperIsAssignment();
25544 origCall = GetCall(stmt);
25545 fptrAddress = origCall->gtCallAddr;
25546 pointerType = fptrAddress->TypeGet();
25549 //------------------------------------------------------------------------
25550 // Run: transform the statement as described above.
25560 RemoveOldStatement();
25566 //------------------------------------------------------------------------
25567 // GetCall: find a call in a statement.
25570 // callStmt - the statement with the call inside.
25573 // call tree node pointer.
25574 GenTreeCall* GetCall(GenTreeStmt* callStmt)
25576 GenTree* tree = callStmt->gtStmtExpr;
25577 GenTreeCall* call = nullptr;
25578 if (doesReturnValue)
25580 assert(tree->OperIsAssignment());
25581 call = tree->gtGetOp2()->AsCall();
25585 call = tree->AsCall(); // call with void return type.
25590 //------------------------------------------------------------------------
25591 // ClearFatFlag: clear fat pointer candidate flag from the original call.
25593 void ClearFatFlag()
25595 origCall->ClearFatPointerCandidate();
25598 //------------------------------------------------------------------------
25599 // CreateRemainder: split current block at the fat call stmt and
25600 // insert statements after the call into remainderBlock.
25602 void CreateRemainder()
25604 remainderBlock = compiler->fgSplitBlockAfterStatement(currBlock, stmt);
25605 unsigned propagateFlags = currBlock->bbFlags & BBF_GC_SAFE_POINT;
25606 remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | propagateFlags;
25609 //------------------------------------------------------------------------
25610 // CreateCheck: create check block, that checks fat pointer bit set.
25614 checkBlock = CreateAndInsertBasicBlock(BBJ_COND, currBlock);
25615 GenTree* fatPointerMask = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, FAT_POINTER_MASK);
25616 GenTree* fptrAddressCopy = compiler->gtCloneExpr(fptrAddress);
25617 GenTree* fatPointerAnd = compiler->gtNewOperNode(GT_AND, TYP_I_IMPL, fptrAddressCopy, fatPointerMask);
25618 GenTree* zero = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, 0);
25619 GenTree* fatPointerCmp = compiler->gtNewOperNode(GT_NE, TYP_INT, fatPointerAnd, zero);
25620 GenTree* jmpTree = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, fatPointerCmp);
25621 GenTree* jmpStmt = compiler->fgNewStmtFromTree(jmpTree, stmt->gtStmt.gtStmtILoffsx);
25622 compiler->fgInsertStmtAtEnd(checkBlock, jmpStmt);
25625 //------------------------------------------------------------------------
25626 // CreateCheck: create then block, that is executed if call address is not fat pointer.
25630 thenBlock = CreateAndInsertBasicBlock(BBJ_ALWAYS, checkBlock);
25631 GenTree* nonFatCallStmt = compiler->gtCloneExpr(stmt)->AsStmt();
25632 compiler->fgInsertStmtAtEnd(thenBlock, nonFatCallStmt);
25635 //------------------------------------------------------------------------
25636 // CreateCheck: create else block, that is executed if call address is fat pointer.
25640 elseBlock = CreateAndInsertBasicBlock(BBJ_NONE, thenBlock);
25642 GenTree* fixedFptrAddress = GetFixedFptrAddress();
25643 GenTree* actualCallAddress = compiler->gtNewOperNode(GT_IND, pointerType, fixedFptrAddress);
25644 GenTree* hiddenArgument = GetHiddenArgument(fixedFptrAddress);
25646 GenTreeStmt* fatStmt = CreateFatCallStmt(actualCallAddress, hiddenArgument);
25647 compiler->fgInsertStmtAtEnd(elseBlock, fatStmt);
25650 //------------------------------------------------------------------------
25651 // CreateAndInsertBasicBlock: ask compiler to create new basic block.
25652 // and insert in into the basic block list.
25655 // jumpKind - jump kind for the new basic block
25656 // insertAfter - basic block, after which compiler has to insert the new one.
25659 // new basic block.
25660 BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter)
25662 BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true);
25663 if ((insertAfter->bbFlags & BBF_INTERNAL) == 0)
25665 block->bbFlags &= ~BBF_INTERNAL;
25666 block->bbFlags |= BBF_IMPORTED;
25671 //------------------------------------------------------------------------
25672 // GetFixedFptrAddress: clear fat pointer bit from fat pointer address.
25675 // address without fat pointer bit set.
25676 GenTree* GetFixedFptrAddress()
25678 GenTree* fptrAddressCopy = compiler->gtCloneExpr(fptrAddress);
25679 GenTree* fatPointerMask = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, FAT_POINTER_MASK);
25680 return compiler->gtNewOperNode(GT_SUB, pointerType, fptrAddressCopy, fatPointerMask);
25683 //------------------------------------------------------------------------
25684 // GetHiddenArgument: load hidden argument.
25687 // fixedFptrAddress - pointer to the tuple <methodPointer, instantiationArgumentPointer>
25690 // generic context hidden argument.
25691 GenTree* GetHiddenArgument(GenTree* fixedFptrAddress)
25693 GenTree* fixedFptrAddressCopy = compiler->gtCloneExpr(fixedFptrAddress);
25694 GenTree* wordSize = new (compiler, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, genTypeSize(TYP_I_IMPL));
25695 GenTree* hiddenArgumentPtrPtr =
25696 compiler->gtNewOperNode(GT_ADD, pointerType, fixedFptrAddressCopy, wordSize);
25697 GenTree* hiddenArgumentPtr = compiler->gtNewOperNode(GT_IND, pointerType, hiddenArgumentPtrPtr);
25698 return compiler->gtNewOperNode(GT_IND, fixedFptrAddressCopy->TypeGet(), hiddenArgumentPtr);
25701 //------------------------------------------------------------------------
25702 // CreateFatCallStmt: create call with fixed call address and hidden argument in the args list.
25705 // actualCallAddress - fixed call address
25706 // hiddenArgument - generic context hidden argument
25709 // created call node.
25710 GenTreeStmt* CreateFatCallStmt(GenTree* actualCallAddress, GenTree* hiddenArgument)
25712 GenTreeStmt* fatStmt = compiler->gtCloneExpr(stmt)->AsStmt();
25713 GenTree* fatTree = fatStmt->gtStmtExpr;
25714 GenTreeCall* fatCall = GetCall(fatStmt);
25715 fatCall->gtCallAddr = actualCallAddress;
25716 AddHiddenArgument(fatCall, hiddenArgument);
25720 //------------------------------------------------------------------------
25721 // AddHiddenArgument: add hidden argument to the call argument list.
25724 // fatCall - fat call node
25725 // hiddenArgument - generic context hidden argument
25727 void AddHiddenArgument(GenTreeCall* fatCall, GenTree* hiddenArgument)
25729 GenTreeArgList* oldArgs = fatCall->gtCallArgs;
25730 GenTreeArgList* newArgs;
25731 #if USER_ARGS_COME_LAST
25732 if (fatCall->HasRetBufArg())
25734 GenTree* retBuffer = oldArgs->Current();
25735 GenTreeArgList* rest = oldArgs->Rest();
25736 newArgs = compiler->gtNewListNode(hiddenArgument, rest);
25737 newArgs = compiler->gtNewListNode(retBuffer, newArgs);
25741 newArgs = compiler->gtNewListNode(hiddenArgument, oldArgs);
25745 AddArgumentToTail(newArgs, hiddenArgument);
25747 fatCall->gtCallArgs = newArgs;
25750 //------------------------------------------------------------------------
25751 // AddArgumentToTail: add hidden argument to the tail of the call argument list.
25754 // argList - fat call node
25755 // hiddenArgument - generic context hidden argument
25757 void AddArgumentToTail(GenTreeArgList* argList, GenTree* hiddenArgument)
25759 GenTreeArgList* iterator = argList;
25760 while (iterator->Rest() != nullptr)
25762 iterator = iterator->Rest();
25764 iterator->Rest() = compiler->gtNewArgList(hiddenArgument);
25767 //------------------------------------------------------------------------
25768 // RemoveOldStatement: remove original stmt from current block.
25770 void RemoveOldStatement()
25772 compiler->fgRemoveStmt(currBlock, stmt);
25775 //------------------------------------------------------------------------
25776 // SetWeights: set weights for new blocks.
25780 remainderBlock->inheritWeight(currBlock);
25781 checkBlock->inheritWeight(currBlock);
25782 thenBlock->inheritWeightPercentage(currBlock, HIGH_PROBABILITY);
25783 elseBlock->inheritWeightPercentage(currBlock, 100 - HIGH_PROBABILITY);
25786 //------------------------------------------------------------------------
25787 // ChainFlow: link new blocks into correct cfg.
25791 assert(!compiler->fgComputePredsDone);
25792 checkBlock->bbJumpDest = elseBlock;
25793 thenBlock->bbJumpDest = remainderBlock;
25796 Compiler* compiler;
25797 BasicBlock* currBlock;
25798 BasicBlock* remainderBlock;
25799 BasicBlock* checkBlock;
25800 BasicBlock* thenBlock;
25801 BasicBlock* elseBlock;
25803 GenTreeCall* origCall;
25804 GenTree* fptrAddress;
25805 var_types pointerType;
25806 bool doesReturnValue;
25808 const int FAT_POINTER_MASK = 0x2;
25809 const int HIGH_PROBABILITY = 80;
25812 Compiler* compiler;
25817 //------------------------------------------------------------------------
25818 // fgDebugCheckFatPointerCandidates: callback to make sure there are no more GTF_CALL_M_FAT_POINTER_CHECK calls.
25820 Compiler::fgWalkResult Compiler::fgDebugCheckFatPointerCandidates(GenTree** pTree, fgWalkData* data)
25822 GenTree* tree = *pTree;
25823 if (tree->IsCall())
25825 assert(!tree->AsCall()->IsFatPointerCandidate());
25827 return WALK_CONTINUE;
25830 //------------------------------------------------------------------------
25831 // CheckNoFatPointerCandidatesLeft: walk through blocks and check that there are no fat pointer candidates left.
25833 void Compiler::CheckNoFatPointerCandidatesLeft()
25835 assert(!doesMethodHaveFatPointer());
25836 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25838 for (GenTreeStmt* stmt = fgFirstBB->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
25840 fgWalkTreePre(&stmt->gtStmtExpr, fgDebugCheckFatPointerCandidates);
25846 //------------------------------------------------------------------------
25847 // fgTransformFatCalli: find and transform fat calls.
25849 void Compiler::fgTransformFatCalli()
25851 assert(IsTargetAbi(CORINFO_CORERT_ABI));
25852 FatCalliTransformer fatCalliTransformer(this);
25853 fatCalliTransformer.Run();
25854 clearMethodHasFatPointer();
25856 CheckNoFatPointerCandidatesLeft();
25860 //------------------------------------------------------------------------
25861 // fgMeasureIR: count and return the number of IR nodes in the function.
25863 unsigned Compiler::fgMeasureIR()
25865 unsigned nodeCount = 0;
25867 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
25869 if (!block->IsLIR())
25871 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
25873 fgWalkTreePre(&stmt->gtStmtExpr,
25874 [](GenTree** slot, fgWalkData* data) -> Compiler::fgWalkResult {
25875 (*reinterpret_cast<unsigned*>(data->pCallbackData))++;
25876 return Compiler::WALK_CONTINUE;
25883 for (GenTree* node : LIR::AsRange(block))
25893 //------------------------------------------------------------------------
25894 // fgCompDominatedByExceptionalEntryBlocks: compute blocks that are
25895 // dominated by not normal entry.
25897 void Compiler::fgCompDominatedByExceptionalEntryBlocks()
25899 assert(fgEnterBlksSetValid);
25900 if (BlockSetOps::Count(this, fgEnterBlks) != 1) // There are exception entries.
25902 for (unsigned i = 1; i <= fgBBNumMax; ++i)
25904 BasicBlock* block = fgBBInvPostOrder[i];
25905 if (BlockSetOps::IsMember(this, fgEnterBlks, block->bbNum))
25907 if (fgFirstBB != block) // skip the normal entry.
25909 block->SetDominatedByExceptionalEntryFlag();
25912 else if (block->bbIDom->IsDominatedByExceptionalEntryFlag())
25914 block->SetDominatedByExceptionalEntryFlag();
25920 //------------------------------------------------------------------------
25921 // fgNeedReturnSpillTemp: Answers does the inlinee need to spill all returns
25925 // true if the inlinee has to spill return exprs.
25926 bool Compiler::fgNeedReturnSpillTemp()
25928 assert(compIsForInlining());
25929 return (lvaInlineeReturnSpillTemp != BAD_VAR_NUM);
25932 //------------------------------------------------------------------------
25933 // fgUseThrowHelperBlocks: Determinate does compiler use throw helper blocks.
25936 // For debuggable code, codegen will generate the 'throw' code inline.
25938 // true if 'throw' helper block should be created.
25939 bool Compiler::fgUseThrowHelperBlocks()
25941 return !opts.compDbgCode;