};
// Basic block predecessor lists. Predecessor lists are created by fgLinkBasicBlocks(), stored
- // in 'bbPreds', and then maintained throughout compilation. 'fgComputePredsDone' will be 'true' after the
+ // in 'bbPreds', and then maintained throughout compilation. 'fgPredsComputed' will be 'true' after the
// predecessor lists are created.
//
flowList* bbPreds; // ptr to list of predecessors
lvaRefCountState = RCS_INVALID;
fgLocalVarLivenessDone = false;
-#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
- if (fgNeedToAddFinallyTargetBits)
- {
- // We previously wiped out the BBF_FINALLY_TARGET bits due to some morphing; add them back.
- fgAddFinallyTargetFlags();
- fgNeedToAddFinallyTargetBits = false;
- }
-#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
-
// Decide the kind of code we want to generate
fgSetOptions();
#endif // FEATURE_EH_FUNCLETS
-#if !FEATURE_EH
- void fgRemoveEH();
-#endif // !FEATURE_EH
-
void fgSortEHTable();
// Causes the EH table to obey some well-formedness conditions, by inserting
#endif // FEATURE_JIT_METHOD_PERF
bool fgModified; // True if the flow graph has been modified recently
- bool fgComputePredsDone; // Have we computed the bbPreds list
+ bool fgPredsComputed; // Have we computed the bbPreds list
bool fgDomsComputed; // Have we computed the dominator sets?
bool fgReturnBlocksComputed; // Have we computed the return blocks list?
bool fgOptimizedFinally; // Did we optimize any try-finallys?
void fgAddFinallyTargetFlags();
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
-
PhaseStatus fgTailMergeThrows();
void fgTailMergeThrowsFallThroughHelper(BasicBlock* predBlock,
BasicBlock* nonCanonicalBlock,
BasicBlock* canonicalBlock,
flowList* predEdge);
-#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
- // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
- // when this is necessary.
- bool fgNeedToAddFinallyTargetBits;
-#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
-
bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
BasicBlock* handler,
BlockToBlockMap& continuationMap);
inline void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
{
JITDUMP("Converting " FMT_BB " to BBJ_THROW\n", block->bbNum);
+ assert(fgPredsComputed);
// Ordering of the following operations matters.
// First, note if we are looking at the first block of a call always pair.
leaveBlk->bbPreds = nullptr;
#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
- // This function (fgConvertBBToThrowBB) can be called before the predecessor lists are created (e.g., in
- // fgMorph). The fgClearFinallyTargetBit() function to update the BBF_FINALLY_TARGET bit depends on these
- // predecessor lists. If there are no predecessor lists, we immediately clear all BBF_FINALLY_TARGET bits
- // (to allow subsequent dead code elimination to delete such blocks without asserts), and set a flag to
- // recompute them later, before they are required.
- if (fgComputePredsDone)
- {
- fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
- }
- else
- {
- fgClearAllFinallyTargetBits();
- fgNeedToAddFinallyTargetBits = true;
- }
+ fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
}
}
#endif // DEBUG
/* We haven't yet computed the bbPreds lists */
- fgComputePredsDone = false;
+ fgPredsComputed = false;
/* We haven't yet computed the edge weight */
fgEdgeWeightsComputed = false;
// But if we call this early, before fgLinkBasicBlocks,
// defer and let it handle adding the implicit ref.
//
- block->bbRefs = fgComputePredsDone ? 1 : 0;
+ block->bbRefs = fgPredsComputed ? 1 : 0;
fgFirstBBScratch = fgFirstBB;
{
assert(fgFirstBBScratch == fgFirstBB);
assert(fgFirstBBScratch->bbFlags & BBF_INTERNAL);
- if (fgComputePredsDone)
+ if (fgPredsComputed)
{
assert(fgFirstBBScratch->countOfInEdges() == 1);
}
noway_assert(oldSwitchBlock != nullptr);
noway_assert(newSwitchBlock != nullptr);
noway_assert(oldSwitchBlock->bbJumpKind == BBJ_SWITCH);
+ assert(fgPredsComputed);
// Walk the switch's jump table, updating the predecessor for each branch.
for (BasicBlock* const bJump : oldSwitchBlock->SwitchTargets())
// fgRemoveRefPred()/fgAddRefPred() will do the right thing: the second and
// subsequent duplicates will simply subtract from and add to the duplicate
// count (respectively).
- if (bJump->countOfInEdges() > 0)
- {
- //
- // Remove the old edge [oldSwitchBlock => bJump]
- //
- fgRemoveRefPred(bJump, oldSwitchBlock);
- }
- else
- {
- // bJump->countOfInEdges() must not be zero after preds are calculated.
- assert(!fgComputePredsDone);
- }
+
+ //
+ // Remove the old edge [oldSwitchBlock => bJump]
+ //
+ assert(bJump->countOfInEdges() > 0);
+ fgRemoveRefPred(bJump, oldSwitchBlock);
//
// Create the new edge [newSwitchBlock => bJump]
noway_assert(newTarget != nullptr);
noway_assert(oldTarget != nullptr);
noway_assert(blockSwitch->bbJumpKind == BBJ_SWITCH);
+ assert(fgPredsComputed);
// For the jump targets values that match oldTarget of our BBJ_SWITCH
// replace predecessor 'blockSwitch' with 'newTarget'
{
// Remove the old edge [oldTarget from blockSwitch]
//
- if (fgComputePredsDone)
- {
- fgRemoveAllRefPreds(oldTarget, blockSwitch);
- }
+ fgRemoveAllRefPreds(oldTarget, blockSwitch);
//
// Change the jumpTab entry to branch to the new location
//
// Create the new edge [newTarget from blockSwitch]
//
- flowList* newEdge = nullptr;
-
- if (fgComputePredsDone)
- {
- newEdge = fgAddRefPred(newTarget, blockSwitch);
- }
+ flowList* const newEdge = fgAddRefPred(newTarget, blockSwitch);
// Now set the correct value of newEdge->flDupCount
// and replace any other jumps in jumpTab[] that go to oldTarget.
//
// Increment the flDupCount
//
- if (fgComputePredsDone)
- {
- newEdge->flDupCount++;
- }
+ newEdge->flDupCount++;
}
i++; // Check the next entry in jumpTab[]
}
void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget)
{
assert(block != nullptr);
+ assert(fgPredsComputed);
switch (block->bbJumpKind)
{
if (block->bbJumpDest == oldTarget)
{
block->bbJumpDest = newTarget;
-
- if (fgComputePredsDone)
- {
- fgRemoveRefPred(oldTarget, block);
- fgAddRefPred(newTarget, block);
- }
+ fgRemoveRefPred(oldTarget, block);
+ fgAddRefPred(newTarget, block);
}
break;
{
jumpTab[i] = newTarget;
changed = true;
-
- if (fgComputePredsDone)
- {
- fgRemoveRefPred(oldTarget, block);
- fgAddRefPred(newTarget, block);
- }
+ fgRemoveRefPred(oldTarget, block);
+ fgAddRefPred(newTarget, block);
}
}
// Pred lists now established.
//
- fgComputePredsDone = true;
+ fgPredsComputed = true;
}
//------------------------------------------------------------------------
BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ)
{
assert(curr->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_ALWAYS));
-
- if (fgComputePredsDone)
- {
- assert(fgGetPredForBlock(succ, curr) != nullptr);
- }
+ assert(fgPredsComputed);
+ assert(fgGetPredForBlock(succ, curr) != nullptr);
BasicBlock* newBlock;
if (succ == curr->bbNext)
}
}
-/*****************************************************************************
- *
- * Function called to connect to block that previously had a fall through
- */
-
+//------------------------------------------------------------------------
+// fgConnectFallThrough: fix flow from a block that previously had a fall through
+//
+// Arguments:
+// bSrc - source of fall through (may be null?)
+// bDst - target of fall through
+//
+// Returns:
+// Newly inserted block after bSrc that jumps to bDst,
+// or nullptr if bSrc already falls through to bDst
+//
BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
{
+ assert(fgPredsComputed);
BasicBlock* jmpBlk = nullptr;
/* If bSrc is non-NULL */
case BBJ_NONE:
bSrc->bbJumpKind = BBJ_ALWAYS;
bSrc->bbJumpDest = bDst;
-#ifdef DEBUG
- if (verbose)
- {
- printf("Block " FMT_BB " ended with a BBJ_NONE, Changed to an unconditional jump to " FMT_BB
- "\n",
- bSrc->bbNum, bSrc->bbJumpDest->bbNum);
- }
-#endif
+ JITDUMP("Block " FMT_BB " ended with a BBJ_NONE, Changed to an unconditional jump to " FMT_BB "\n",
+ bSrc->bbNum, bSrc->bbJumpDest->bbNum);
break;
case BBJ_CALLFINALLY:
// Add a new block after bSrc which jumps to 'bDst'
jmpBlk = fgNewBBafter(BBJ_ALWAYS, bSrc, true);
+ fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc));
- if (fgComputePredsDone)
- {
- fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc));
- }
// Record the loop number in the new block
jmpBlk->bbNatLoopNum = bSrc->bbNatLoopNum;
//
if (fgHaveValidEdgeWeights && fgHaveProfileWeights())
{
- noway_assert(fgComputePredsDone);
-
- flowList* newEdge = fgGetPredForBlock(jmpBlk, bSrc);
+ flowList* const newEdge = fgGetPredForBlock(jmpBlk, bSrc);
jmpBlk->bbWeight = (newEdge->edgeWeightMin() + newEdge->edgeWeightMax()) / 2;
if (bSrc->bbWeight == BB_ZERO_WEIGHT)
jmpBlk->bbJumpDest = bDst;
- if (fgComputePredsDone)
- {
- fgReplacePred(bDst, bSrc, jmpBlk);
- }
- else
- {
- jmpBlk->bbFlags |= BBF_IMPORTED;
- }
+ fgReplacePred(bDst, bSrc, jmpBlk);
-#ifdef DEBUG
- if (verbose)
- {
- printf("Added an unconditional jump to " FMT_BB " after block " FMT_BB "\n",
- jmpBlk->bbJumpDest->bbNum, bSrc->bbNum);
- }
-#endif // DEBUG
+ JITDUMP("Added an unconditional jump to " FMT_BB " after block " FMT_BB "\n",
+ jmpBlk->bbJumpDest->bbNum, bSrc->bbNum);
break;
default:
(bSrc->bbJumpDest == bSrc->bbNext))
{
bSrc->bbJumpKind = BBJ_NONE;
-#ifdef DEBUG
- if (verbose)
- {
- printf("Changed an unconditional jump from " FMT_BB " to the next block " FMT_BB
- " into a BBJ_NONE block\n",
- bSrc->bbNum, bSrc->bbNext->bbNum);
- }
-#endif // DEBUG
+ JITDUMP("Changed an unconditional jump from " FMT_BB " to the next block " FMT_BB
+ " into a BBJ_NONE block\n",
+ bSrc->bbNum, bSrc->bbNext->bbNum);
}
}
}
//
bool Compiler::fgRenumberBlocks()
{
+ assert(fgPredsComputed);
+
// If we renumber the blocks the dominator information will be out-of-date
if (fgDomsComputed)
{
noway_assert(!"Can't call Compiler::fgRenumberBlocks() when fgDomsComputed==true");
}
-#ifdef DEBUG
- if (verbose)
- {
- printf("\n*************** Before renumbering the basic blocks\n");
- fgDispBasicBlocks();
- fgDispHandlerTab();
- }
-#endif // DEBUG
+ JITDUMP("\n*************** Before renumbering the basic blocks\n");
+ JITDUMPEXEC(fgDispBasicBlocks());
+ JITDUMPEXEC(fgDispHandlerTab());
bool renumbered = false;
bool newMaxBBNum = false;
// If we renumbered, then we may need to reorder some pred lists.
//
- if (renumbered && fgComputePredsDone)
+ if (renumbered)
{
for (BasicBlock* const block : Blocks())
{
block->ensurePredListOrder(this);
}
+ JITDUMP("\n*************** After renumbering the basic blocks\n");
+ JITDUMPEXEC(fgDispBasicBlocks());
+ JITDUMPEXEC(fgDispHandlerTab());
}
-
-#ifdef DEBUG
- if (verbose)
+ else
{
- printf("\n*************** After renumbering the basic blocks\n");
- if (renumbered)
- {
- fgDispBasicBlocks();
- fgDispHandlerTab();
- }
- else
- {
- printf("=============== No blocks renumbered!\n");
- }
+ JITDUMP("=============== No blocks renumbered!\n");
}
-#endif // DEBUG
// Now update the BlockSet epoch, which depends on the block numbers.
// If any blocks have been renumbered then create a new BlockSet epoch.
fprintf(fgxFile, ">");
}
- if (fgComputePredsDone)
+ if (fgPredsComputed)
{
unsigned edgeNum = 1;
BasicBlock* bTarget;
}
}
- if (fgComputePredsDone)
+ if (fgPredsComputed)
{
// Already emitted pred edges above.
//
maxBlockNumWidth, "----");
printf("BBnum %*sBBid ref try hnd %s weight %*s%s lp [IL range] [jump]%*s [EH region] [flags]\n",
padWidth, "",
- (fgComputePredsDone ? "preds "
+ (fgPredsComputed ? "preds "
: " "),
((ibcColWidth > 0) ? ibcColWidth - 3 : 0), "", // Subtract 3 for the width of "IBC", printed next.
((ibcColWidth > 0) ? "IBC"
// the number of incoming edges for the block.
unsigned BBPredsChecker::CheckBBPreds(BasicBlock* block, unsigned curTraversalStamp)
{
- if (!comp->fgComputePredsDone)
+ if (!comp->fgPredsComputed)
{
assert(block->bbPreds == nullptr);
return 0;
if (checkBBRefs)
{
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
}
BBPredsChecker checker(this);
#endif // FEATURE_EH_FUNCLETS
// We need to update the bbPreds lists.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
if (compHndBBtabCount == 0)
{
#endif // FEATURE_EH_FUNCLETS
// We need to update the bbPreds lists.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
bool enableRemoveEmptyTry = true;
#endif // FEATURE_EH_FUNCLETS
// We need to update the bbPreds lists.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
bool enableCloning = true;
#endif // FEATURE_EH_FUNCLETS
// We need to update the bbPreds lists.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
if (compHndBBtabCount == 0)
{
// This transformation requires block pred lists to be built
// so that flow can be safely updated.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
struct ThrowHelper
{
{
assert(block != nullptr);
assert(blockPred != nullptr);
+ assert(fgPredsComputed ^ initializingPreds);
block->bbRefs++;
- if (!fgComputePredsDone && !initializingPreds)
- {
- // Why is someone trying to update the preds list when the preds haven't been created?
- // Ignore them! This can happen when fgMorph is called before the preds list is created.
- return nullptr;
- }
-
// Keep the predecessor list in lowest to highest bbNum order. This allows us to discover the loops in
// optFindNaturalLoops from innermost to outermost.
//
{
noway_assert(block != nullptr);
noway_assert(blockPred != nullptr);
-
noway_assert(block->countOfInEdges() > 0);
+ assert(fgPredsComputed);
block->bbRefs--;
- // Do nothing if we haven't calculated the predecessor list yet.
- // Yes, this does happen.
- // For example the predecessor lists haven't been created yet when we do fgMorph.
- // But fgMorph calls fgFoldConditional, which in turn calls fgRemoveRefPred.
- if (!fgComputePredsDone)
- {
- return nullptr;
- }
-
flowList** ptrToPred;
flowList* pred = fgGetPredForBlock(block, blockPred, &ptrToPred);
noway_assert(pred != nullptr);
{
assert(block != nullptr);
assert(blockPred != nullptr);
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
assert(block->countOfInEdges() > 0);
flowList** ptrToPred;
//
void Compiler::fgComputeReachabilitySets()
{
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
#ifdef DEBUG
fgReachabilitySetsValid = false;
//
PhaseStatus Compiler::fgComputeReachability()
{
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
fgComputeReturnBlocks();
{
// Optionally check profile data, if we have any.
//
- const bool enabled = (JitConfig.JitProfileChecks() > 0) && fgHaveProfileWeights() && fgComputePredsDone;
+ const bool enabled = (JitConfig.JitProfileChecks() > 0) && fgHaveProfileWeights() && fgPredsComputed;
if (!enabled)
{
return;
assert(!fgFuncletsCreated);
// We need to update the bbPreds lists.
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
#if !FEATURE_EH
// If we don't support EH, we can't add the EH needed by synchronized methods.
//
void Compiler::fgCreateFuncletPrologBlocks()
{
- noway_assert(fgComputePredsDone);
+ noway_assert(fgPredsComputed);
noway_assert(!fgDomsComputed); // this function doesn't maintain the dom sets
assert(!fgFuncletsCreated);
// Since we may need to create a new transition block
// we assert that it is OK to create new blocks.
//
+ assert(fgPredsComputed);
assert(fgSafeBasicBlockCreation);
assert(fgFirstColdBlock == nullptr);
transitionBlock->bbJumpDest = firstColdBlock;
transitionBlock->inheritWeight(firstColdBlock);
- noway_assert(fgComputePredsDone);
-
// Update the predecessor list for firstColdBlock
fgReplacePred(firstColdBlock, prevToFirstColdBlock, transitionBlock);
//
virtual void ChainFlow()
{
- assert(compiler->fgComputePredsDone);
+ assert(compiler->fgPredsComputed);
// currBlock
compiler->fgRemoveRefPred(remainderBlock, currBlock);
//
virtual void ChainFlow() override
{
- assert(compiler->fgComputePredsDone);
+ assert(compiler->fgPredsComputed);
// currBlock
compiler->fgRemoveRefPred(remainderBlock, currBlock);
#endif // FEATURE_EH_FUNCLETS
-#if !FEATURE_EH
-
-/*****************************************************************************
- * fgRemoveEH: To facilitate the bring-up of new platforms without having to
- * worry about fully implementing EH, we want to simply remove EH constructs
- * from the IR. This works because a large percentage of our tests contain
- * EH constructs but don't actually throw exceptions. This function removes
- * 'catch', 'filter', 'filter-handler', and 'fault' clauses completely.
- * It requires that the importer has created the EH table, and that normal
- * EH well-formedness tests have been done, and 'leave' opcodes have been
- * imported.
- *
- * It currently does not handle 'finally' clauses, so tests that include
- * 'finally' will NYI(). To handle 'finally', we would need to inline the
- * 'finally' clause IL at each exit from a finally-protected 'try', or
- * else call the 'finally' clause, like normal.
- *
- * Walk the EH table from beginning to end. If a table entry is nested within
- * a handler, we skip it, as we'll delete its code when we get to the enclosing
- * handler. If a clause is enclosed within a 'try', or has no nesting, then we delete
- * it (and its range of code blocks). We don't need to worry about cleaning up
- * the EH table entries as we remove the individual handlers (such as calling
- * fgRemoveEHTableEntry()), as we'll null out the entire table at the end.
- *
- * This function assumes FEATURE_EH_FUNCLETS is defined.
- */
-void Compiler::fgRemoveEH()
-{
-#ifdef DEBUG
- if (verbose)
- printf("\n*************** In fgRemoveEH()\n");
-#endif // DEBUG
-
- if (compHndBBtabCount == 0)
- {
- JITDUMP("No EH to remove\n\n");
- return;
- }
-
-#ifdef DEBUG
- if (verbose)
- {
- printf("\n*************** Before fgRemoveEH()\n");
- fgDispBasicBlocks();
- fgDispHandlerTab();
- printf("\n");
- }
-#endif // DEBUG
-
- // Make sure we're early in compilation, so we don't need to update lots of data structures.
- assert(!fgComputePredsDone);
- assert(!fgDomsComputed);
- assert(!fgFuncletsCreated);
- assert(fgFirstFuncletBB == nullptr); // this should follow from "!fgFuncletsCreated"
- assert(!optLoopTableValid);
-
- unsigned XTnum;
- EHblkDsc* HBtab;
-
- for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++)
- {
- if (HBtab->ebdEnclosingHndIndex != EHblkDsc::NO_ENCLOSING_INDEX)
- {
- // This entry is nested within some other handler. So, don't delete the
- // EH entry here; let the enclosing handler delete it. Note that for this
- // EH entry, both the 'try' and handler portions are fully nested within
- // the enclosing handler region, due to proper nesting rules.
- continue;
- }
-
- if (HBtab->HasCatchHandler() || HBtab->HasFilter() || HBtab->HasFaultHandler())
- {
- // Remove all the blocks associated with the handler. Note that there is no
- // fall-through into the handler, or fall-through out of the handler, so
- // just deleting the blocks is sufficient. Note, however, that for every
- // BBJ_EHCATCHRET we delete, we need to fix up the reference count of the
- // block it points to (by subtracting one from its reference count).
- // Note that the blocks for a filter immediately precede the blocks for its associated filter-handler.
-
- BasicBlock* blkBeg = HBtab->HasFilter() ? HBtab->ebdFilter : HBtab->ebdHndBeg;
- BasicBlock* blkLast = HBtab->ebdHndLast;
-
- // Splice out the range of blocks from blkBeg to blkLast (inclusive).
- fgUnlinkRange(blkBeg, blkLast);
-
- BasicBlock* blk;
-
- // Walk the unlinked blocks and marked them as having been removed.
- for (blk = blkBeg; blk != blkLast->bbNext; blk = blk->bbNext)
- {
- blk->bbFlags |= BBF_REMOVED;
-
- if (blk->bbJumpKind == BBJ_EHCATCHRET)
- {
- assert(blk->bbJumpDest->bbRefs > 0);
- blk->bbJumpDest->bbRefs -= 1;
- }
- }
-
- // Walk the blocks of the 'try' and clear data that makes them appear to be within a 'try'.
- for (blk = HBtab->ebdTryBeg; blk != HBtab->ebdTryLast->bbNext; blk = blk->bbNext)
- {
- blk->clearTryIndex();
- blk->bbFlags &= ~BBF_TRY_BEG;
- }
-
- // If we are deleting a range of blocks whose last block is
- // the 'last' block of an enclosing try/hnd region, we need to
- // fix up the EH table. We only care about less nested
- // EH table entries, since we've already deleted everything up to XTnum.
-
- unsigned XTnum2;
- EHblkDsc* HBtab2;
- for (XTnum2 = XTnum + 1, HBtab2 = compHndBBtab + XTnum2; XTnum2 < compHndBBtabCount; XTnum2++, HBtab2++)
- {
- // Handle case where deleted range is at the end of a 'try'.
- if (HBtab2->ebdTryLast == blkLast)
- {
- fgSetTryEnd(HBtab2, blkBeg->bbPrev);
- }
- // Handle case where deleted range is at the end of a handler.
- // (This shouldn't happen, though, because we don't delete handlers
- // nested within other handlers; we wait until we get to the
- // enclosing handler.)
- if (HBtab2->ebdHndLast == blkLast)
- {
- unreached();
- }
- }
- }
- else
- {
- // It must be a 'finally'. We still need to call the finally. Note that the
- // 'finally' can be "called" from multiple locations (e.g., the 'try' block
- // can have multiple 'leave' instructions, each leaving to different targets,
- // and each going through the 'finally'). We could inline the 'finally' at each
- // LEAVE site within a 'try'. If the 'try' exits at all (that is, no infinite loop),
- // there will be at least one since there is no "fall through" at the end of
- // the 'try'.
-
- assert(HBtab->HasFinallyHandler());
-
- NYI("remove finally blocks");
- }
- } /* end of the for loop over XTnum */
-
-#ifdef DEBUG
- // Make sure none of the remaining blocks have any EH.
-
- for (BasicBlock* const blk : Blocks())
- {
- assert(!blk->hasTryIndex());
- assert(!blk->hasHndIndex());
- assert((blk->bbFlags & BBF_TRY_BEG) == 0);
- assert((blk->bbFlags & BBF_FUNCLET_BEG) == 0);
- assert((blk->bbFlags & BBF_REMOVED) == 0);
- assert(blk->bbCatchTyp == BBCT_NONE);
- }
-#endif // DEBUG
-
- // Delete the EH table
-
- compHndBBtab = nullptr;
- compHndBBtabCount = 0;
- // Leave compHndBBtabAllocCount alone.
-
- // Renumber the basic blocks
- JITDUMP("\nRenumbering the basic blocks for fgRemoveEH\n");
- fgRenumberBlocks();
-
-#ifdef DEBUG
- if (verbose)
- {
- printf("\n*************** After fgRemoveEH()\n");
- fgDispBasicBlocks();
- fgDispHandlerTab();
- printf("\n");
- }
-#endif
-}
-
-#endif // !FEATURE_EH
-
/*****************************************************************************
*
* Sort the EH table if necessary.
void Compiler::fgClearFinallyTargetBit(BasicBlock* block)
{
- assert(fgComputePredsDone);
+ assert(fgPredsComputed);
assert((block->bbFlags & BBF_FINALLY_TARGET) != 0);
for (BasicBlock* const predBlock : block->PredBlocks())
{
bool madeChanges = false;
-#if !FEATURE_EH
- // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so
- // we can pass tests that contain try/catch EH, but don't actually throw any exceptions.
- fgRemoveEH();
- madeChanges = true;
-#endif // !FEATURE_EH
-
// We could allow ESP frames. Just need to reserve space for
// pushing EBP if the method becomes an EBP-frame after an edit.
// Note that requiring a EBP Frame disallows double alignment. Thus if we change this
void SsaBuilder::SetupBBRoot()
{
+ assert(m_pCompiler->fgPredsComputed);
+
// Allocate a bbroot, if necessary.
// We need a unique block to be the root of the dominator tree.
// This can be violated if the first block is in a try, or if it is the first block of
m_pCompiler->fgInsertBBbefore(m_pCompiler->fgFirstBB, bbRoot);
assert(m_pCompiler->fgFirstBB == bbRoot);
- if (m_pCompiler->fgComputePredsDone)
- {
- m_pCompiler->fgAddRefPred(oldFirst, bbRoot);
- }
+ m_pCompiler->fgAddRefPred(oldFirst, bbRoot);
}
#ifdef DEBUG