diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c486176a7c682d..8ce8f3d976a5f7 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5228,14 +5228,6 @@ class Compiler void fgCleanupContinuation(BasicBlock* continuation); PhaseStatus fgTailMergeThrows(); - void fgTailMergeThrowsFallThroughHelper(BasicBlock* predBlock, - BasicBlock* nonCanonicalBlock, - BasicBlock* canonicalBlock, - FlowEdge* predEdge); - void fgTailMergeThrowsJumpToHelper(BasicBlock* predBlock, - BasicBlock* nonCanonicalBlock, - BasicBlock* canonicalBlock, - FlowEdge* predEdge); bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block, BasicBlock* handler, @@ -5915,6 +5907,10 @@ class Compiler public: void fgRedirectTargetEdge(BasicBlock* block, BasicBlock* newTarget); + void fgRedirectTrueEdge(BasicBlock* block, BasicBlock* newTarget); + + void fgRedirectFalseEdge(BasicBlock* block, BasicBlock* newTarget); + void fgFindBasicBlocks(); bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion); diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 9d9c44776b436a..200c72a4d4e1c8 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -650,57 +650,30 @@ void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* oldTarget, Bas case BBJ_COND: if (block->TrueTargetIs(oldTarget)) { - FlowEdge* const oldEdge = block->GetTrueEdge(); - - if (block->FalseEdgeIs(oldEdge)) + if (block->FalseEdgeIs(block->GetTrueEdge())) { // Branch was degenerate, simplify it first // fgRemoveConditionalJump(block); assert(block->KindIs(BBJ_ALWAYS)); assert(block->TargetIs(oldTarget)); - } - - // fgRemoveRefPred should have removed the flow edge - fgRemoveRefPred(oldEdge); - assert(oldEdge->getDupCount() == 0); - FlowEdge* const newEdge = fgAddRefPred(newTarget, block, oldEdge); - - if (block->KindIs(BBJ_ALWAYS)) - { - block->SetTargetEdge(newEdge); + fgRedirectTargetEdge(block, newTarget); } else { - assert(block->KindIs(BBJ_COND)); - block->SetTrueEdge(newEdge); + fgRedirectTrueEdge(block, newTarget); } } else { + // Already degenerate cases should have taken the true path above + // assert(block->FalseTargetIs(oldTarget)); - FlowEdge* const oldEdge = block->GetFalseEdge(); - - // Already degenerate cases should have taken the true path above. - assert(!block->TrueEdgeIs(oldEdge)); - - // fgRemoveRefPred should have removed the flow edge - fgRemoveRefPred(oldEdge); - assert(oldEdge->getDupCount() == 0); - FlowEdge* const newEdge = fgAddRefPred(newTarget, block, oldEdge); - - if (block->KindIs(BBJ_ALWAYS)) - { - block->SetTargetEdge(newEdge); - } - else - { - assert(block->KindIs(BBJ_COND)); - block->SetFalseEdge(newEdge); - } + assert(!block->TrueEdgeIs(block->GetFalseEdge())); + fgRedirectFalseEdge(block, newTarget); } - if (block->KindIs(BBJ_COND) && (block->GetFalseEdge() == block->GetTrueEdge())) + if (block->KindIs(BBJ_COND) && block->TrueEdgeIs(block->GetFalseEdge())) { // Block became degenerate, simplify // diff --git a/src/coreclr/jit/fgehopt.cpp b/src/coreclr/jit/fgehopt.cpp index a284b318d2e57d..a437a3da128d4c 100644 --- a/src/coreclr/jit/fgehopt.cpp +++ b/src/coreclr/jit/fgehopt.cpp @@ -2006,26 +2006,8 @@ PhaseStatus Compiler::fgTailMergeThrows() { switch (predBlock->GetKind()) { - // TODO: Use fgReplaceJumpTarget once it preserves edge weights for BBJ_COND blocks - case BBJ_COND: - { - // Flow to non canonical block could be via true or false target. - if (predBlock->FalseTargetIs(nonCanonicalBlock)) - { - fgTailMergeThrowsFallThroughHelper(predBlock, nonCanonicalBlock, canonicalBlock, - predBlock->GetFalseEdge()); - } - - if (predBlock->TrueTargetIs(nonCanonicalBlock)) - { - fgTailMergeThrowsJumpToHelper(predBlock, nonCanonicalBlock, canonicalBlock, - predBlock->GetTrueEdge()); - } - updated = true; - } - break; - case BBJ_ALWAYS: + case BBJ_COND: case BBJ_SWITCH: { JITDUMP("*** " FMT_BB " now branching to " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum); @@ -2068,65 +2050,3 @@ PhaseStatus Compiler::fgTailMergeThrows() fgModified = false; return PhaseStatus::MODIFIED_EVERYTHING; } - -//------------------------------------------------------------------------ -// fgTailMergeThrowsFallThroughHelper: fixup flow for fall throughs to mergeable throws -// -// Arguments: -// predBlock - block falling through to the throw helper -// nonCanonicalBlock - original fall through target -// canonicalBlock - new (jump) target -// predEdge - original flow edge -// -// Notes: -// Alters fall through flow of predBlock so it jumps to the -// canonicalBlock via a new basic block. Does not try and fix -// jump-around flow; we leave that to optOptimizeFlow which runs -// just afterwards. -// -void Compiler::fgTailMergeThrowsFallThroughHelper(BasicBlock* predBlock, - BasicBlock* nonCanonicalBlock, - BasicBlock* canonicalBlock, - FlowEdge* predEdge) -{ - assert(predBlock->KindIs(BBJ_COND)); - assert(predBlock->FalseTargetIs(nonCanonicalBlock)); - - JITDUMP("*** " FMT_BB " false target is now " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum); - - // Remove the old flow - fgRemoveRefPred(predEdge); - - // Wire up the new flow - FlowEdge* const falseEdge = fgAddRefPred(canonicalBlock, predBlock, predEdge); - predBlock->SetFalseEdge(falseEdge); -} - -//------------------------------------------------------------------------ -// fgTailMergeThrowsJumpToHelper: fixup flow for jumps to mergeable throws -// -// Arguments: -// predBlock - block jumping to the throw helper -// nonCanonicalBlock - original jump target -// canonicalBlock - new jump target -// predEdge - original flow edge -// -// Notes: -// Alters jumpDest of predBlock so it jumps to the canonicalBlock. -// -void Compiler::fgTailMergeThrowsJumpToHelper(BasicBlock* predBlock, - BasicBlock* nonCanonicalBlock, - BasicBlock* canonicalBlock, - FlowEdge* predEdge) -{ - JITDUMP("*** " FMT_BB " now branching to " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum); - - // Remove the old flow - assert(predBlock->KindIs(BBJ_COND)); - assert(predBlock->TrueTargetIs(nonCanonicalBlock)); - fgRemoveRefPred(predBlock->GetTrueEdge()); - - // Wire up the new flow - FlowEdge* const trueEdge = fgAddRefPred(canonicalBlock, predBlock, predEdge); - predBlock->SetTrueEdge(trueEdge); -} diff --git a/src/coreclr/jit/fgflow.cpp b/src/coreclr/jit/fgflow.cpp index d77775a1cde938..f9a1721218683b 100644 --- a/src/coreclr/jit/fgflow.cpp +++ b/src/coreclr/jit/fgflow.cpp @@ -449,6 +449,118 @@ void Compiler::fgRedirectTargetEdge(BasicBlock* block, BasicBlock* newTarget) newTarget->bbRefs++; } +//------------------------------------------------------------------------ +// fgRedirectTrueEdge: Sets block->bbTrueEdge's target block to newTarget, +// updating pred lists as necessary. +// +// Arguments: +// block -- The block we want to make a predecessor of newTarget. +// It could be one already, in which case nothing changes. +// newTarget -- The new successor of block. +// +// Notes: +// This assumes block's true and false targets are different. +// If setting block's true target to its false target, +// fgRedirectTrueEdge increments the false edge's dup count, +// and ensures block->bbTrueEdge == block->bbFalseEdge. +// We don't update newTarget->bbPreds in this case, +// as we don't want to have more than one edge from the same predecessor. +// +void Compiler::fgRedirectTrueEdge(BasicBlock* block, BasicBlock* newTarget) +{ + assert(block != nullptr); + assert(newTarget != nullptr); + assert(block->KindIs(BBJ_COND)); + assert(!block->TrueEdgeIs(block->GetFalseEdge())); + + // Update oldTarget's pred list. + // We could call fgRemoveRefPred, but since we're removing the one and only ref from block to oldTarget, + // fgRemoveAllRefPreds is slightly more efficient (one fewer branch, doesn't update edge's dup count, etc). + // + FlowEdge* trueEdge = block->GetTrueEdge(); + BasicBlock* oldTarget = trueEdge->getDestinationBlock(); + fgRemoveAllRefPreds(oldTarget, block); + + // Splice edge into new target block's pred list + // + FlowEdge** predListPtr = fgGetPredInsertPoint(block, newTarget); + FlowEdge* predEdge = *predListPtr; + + if (block->FalseEdgeIs(predEdge)) + { + block->SetTrueEdge(predEdge); + predEdge->incrementDupCount(); + } + else + { + trueEdge->setNextPredEdge(predEdge); + trueEdge->setDestinationBlock(newTarget); + *predListPtr = trueEdge; + } + + newTarget->bbRefs++; + + // Pred list of target should (still) be ordered + // + assert(newTarget->checkPredListOrder()); +} + +//------------------------------------------------------------------------ +// fgRedirectFalseEdge: Sets block->bbFalseEdge's target block to newTarget, +// updating pred lists as necessary. +// +// Arguments: +// block -- The block we want to make a predecessor of newTarget. +// It could be one already, in which case nothing changes. +// newTarget -- The new successor of block. +// +// Notes: +// This assumes block's true and false targets are different. +// If setting block's false target to its true target, +// fgRedirectFalseEdge increments the true edge's dup count, +// and ensures block->bbTrueEdge == block->bbFalseEdge. +// We don't update newTarget->bbPreds in this case, +// as we don't want to have more than one edge from the same predecessor. +// +void Compiler::fgRedirectFalseEdge(BasicBlock* block, BasicBlock* newTarget) +{ + assert(block != nullptr); + assert(newTarget != nullptr); + assert(block->KindIs(BBJ_COND)); + assert(!block->TrueEdgeIs(block->GetFalseEdge())); + + // Update oldTarget's pred list. + // We could call fgRemoveRefPred, but since we're removing the one and only ref from block to oldTarget, + // fgRemoveAllRefPreds is slightly more efficient (one fewer branch, doesn't update edge's dup count, etc). + // + FlowEdge* falseEdge = block->GetFalseEdge(); + BasicBlock* oldTarget = falseEdge->getDestinationBlock(); + fgRemoveAllRefPreds(oldTarget, block); + + // Splice edge into new target block's pred list + // + FlowEdge** predListPtr = fgGetPredInsertPoint(block, newTarget); + FlowEdge* predEdge = *predListPtr; + + if (block->TrueEdgeIs(predEdge)) + { + block->SetFalseEdge(predEdge); + predEdge->incrementDupCount(); + } + else + { + falseEdge->setNextPredEdge(predEdge); + falseEdge->setDestinationBlock(newTarget); + *predListPtr = falseEdge; + } + + newTarget->bbRefs++; + + // Pred list of target should (still) be ordered + // + assert(newTarget->checkPredListOrder()); +} + Compiler::SwitchUniqueSuccSet Compiler::GetDescriptorForSwitch(BasicBlock* switchBlk) { assert(switchBlk->KindIs(BBJ_SWITCH)); diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 13f8970fd247bd..3052d2fca63eaf 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -1548,16 +1548,12 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc if (block->TrueTargetIs(bDest)) { assert(!block->FalseTargetIs(bDest)); - fgRemoveRefPred(block->GetTrueEdge()); - FlowEdge* const trueEdge = fgAddRefPred(bDest->GetTarget(), block, block->GetTrueEdge()); - block->SetTrueEdge(trueEdge); + fgRedirectTrueEdge(block, bDest->GetTarget()); } else { assert(block->FalseTargetIs(bDest)); - fgRemoveRefPred(block->GetFalseEdge()); - FlowEdge* const falseEdge = fgAddRefPred(bDest->GetTarget(), block, block->GetFalseEdge()); - block->SetFalseEdge(falseEdge); + fgRedirectFalseEdge(block, bDest->GetTarget()); } break; @@ -2478,11 +2474,11 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* // Fix up block's flow. // Assume edge likelihoods transfer over. // - fgRemoveRefPred(block->GetTargetEdge()); + fgRedirectTargetEdge(block, target->GetTrueTarget()); + block->GetTargetEdge()->setLikelihood(target->GetTrueEdge()->getLikelihood()); - FlowEdge* const trueEdge = fgAddRefPred(target->GetTrueTarget(), block, target->GetTrueEdge()); FlowEdge* const falseEdge = fgAddRefPred(target->GetFalseTarget(), block, target->GetFalseEdge()); - block->SetCond(trueEdge, falseEdge); + block->SetCond(block->GetTargetEdge(), falseEdge); JITDUMP("fgOptimizeUncondBranchToSimpleCond(from " FMT_BB " to cond " FMT_BB "), modified " FMT_BB "\n", block->bbNum, target->bbNum, block->bbNum); @@ -2911,15 +2907,12 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) // FlowEdge* const falseEdge = fgAddRefPred(bJump->Next(), bJump, destFalseEdge); - // bJump no longer jumps to bDest - // - fgRemoveRefPred(bJump->GetTargetEdge()); - // bJump now jumps to bDest's normal jump target // - FlowEdge* const trueEdge = fgAddRefPred(bDestNormalTarget, bJump, destTrueEdge); + fgRedirectTargetEdge(bJump, bDestNormalTarget); + bJump->GetTargetEdge()->setLikelihood(destTrueEdge->getLikelihood()); - bJump->SetCond(trueEdge, falseEdge); + bJump->SetCond(bJump->GetTargetEdge(), falseEdge); if (weightJump > 0) { @@ -5036,8 +5029,8 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication /* = false */, bool isPh // Rewire flow from block // block->SetFalseEdge(oldTrueEdge); - FlowEdge* const newTrueEdge = fgAddRefPred(bNext->GetTarget(), block, oldFalseEdge); - block->SetTrueEdge(newTrueEdge); + block->SetTrueEdge(oldFalseEdge); + fgRedirectTrueEdge(block, bNext->GetTarget()); /* Unlink bNext from the BasicBlock list; note that we can @@ -5683,11 +5676,14 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // if (commSucc != nullptr) { - fgRemoveRefPred(predBlock->GetTargetEdge()); + assert(predBlock->KindIs(BBJ_ALWAYS)); + fgRedirectTargetEdge(predBlock, crossJumpTarget); + } + else + { + FlowEdge* const newEdge = fgAddRefPred(crossJumpTarget, predBlock); + predBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); } - - FlowEdge* const newEdge = fgAddRefPred(crossJumpTarget, predBlock); - predBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); } // We changed things diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index a824b5d264cb30..6c6edd7485694a 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -2774,7 +2774,7 @@ void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block) // the handler go to the prolog. Edges coming from with the handler are back-edges, and // go to the existing 'block'. - for (BasicBlock* const predBlock : block->PredBlocks()) + for (BasicBlock* const predBlock : block->PredBlocksEditing()) { if (!fgIsIntraHandlerPred(predBlock, block)) { @@ -2786,9 +2786,7 @@ void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block) case BBJ_CALLFINALLY: { noway_assert(predBlock->TargetIs(block)); - fgRemoveRefPred(predBlock->GetTargetEdge()); - FlowEdge* const newEdge = fgAddRefPred(newHead, predBlock); - predBlock->SetTargetEdge(newEdge); + fgRedirectTargetEdge(predBlock, newHead); break; } diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 4ab8af48bb1fd7..eb203cbd3f68c0 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -2473,39 +2473,11 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt, // No-op because tmp was already assigned to obj typeCheckSucceedTree = gtNewNothingNode(); } - BasicBlock* typeCheckSucceedBb = - typeCheckNotNeeded ? nullptr : fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, typeCheckSucceedTree, debugInfo); // // Wire up the blocks // - // Tricky case - wire up multiple type check blocks (in most cases there is only one) - for (int candidateId = 0; candidateId < numOfCandidates; candidateId++) - { - BasicBlock* curTypeCheckBb = typeChecksBbs[candidateId]; - - // All type checks jump straight to the typeCheckSucceedBb on success - FlowEdge* const trueEdge = fgAddRefPred(typeCheckSucceedBb, curTypeCheckBb); - curTypeCheckBb->SetTrueEdge(trueEdge); - - // or ... - if (candidateId == numOfCandidates - 1) - { - // ... jump to the fallbackBb on last type check's failure - FlowEdge* const falseEdge = fgAddRefPred(fallbackBb, curTypeCheckBb); - curTypeCheckBb->SetFalseEdge(falseEdge); - } - else - { - // ... jump to the next type check on failure - FlowEdge* const falseEdge = fgAddRefPred(typeChecksBbs[candidateId + 1], curTypeCheckBb); - curTypeCheckBb->SetFalseEdge(falseEdge); - } - } - - fgRedirectTargetEdge(firstBb, nullcheckBb); - // We assume obj is 50%/50% null/not-null (TODO-InlineCast: rely on PGO) // and rely on profile for the slow path. // @@ -2516,6 +2488,7 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt, // const weight_t nullcheckTrueLikelihood = 0.5; const weight_t nullcheckFalseLikelihood = 0.5; + BasicBlock* typeCheckSucceedBb; { FlowEdge* const trueEdge = fgAddRefPred(lastBb, nullcheckBb); @@ -2528,6 +2501,8 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt, FlowEdge* const falseEdge = fgAddRefPred(fallbackBb, nullcheckBb); nullcheckBb->SetFalseEdge(falseEdge); falseEdge->setLikelihood(nullcheckFalseLikelihood); + + typeCheckSucceedBb = nullptr; } else { @@ -2535,10 +2510,37 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt, nullcheckBb->SetFalseEdge(falseEdge); falseEdge->setLikelihood(nullcheckFalseLikelihood); + typeCheckSucceedBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, typeCheckSucceedTree, debugInfo); FlowEdge* const newEdge = fgAddRefPred(lastBb, typeCheckSucceedBb); typeCheckSucceedBb->SetTargetEdge(newEdge); } + // Tricky case - wire up multiple type check blocks (in most cases there is only one) + for (int candidateId = 0; candidateId < numOfCandidates; candidateId++) + { + BasicBlock* curTypeCheckBb = typeChecksBbs[candidateId]; + + // All type checks jump straight to the typeCheckSucceedBb on success + FlowEdge* const trueEdge = fgAddRefPred(typeCheckSucceedBb, curTypeCheckBb); + curTypeCheckBb->SetTrueEdge(trueEdge); + + // or ... + if (candidateId == numOfCandidates - 1) + { + // ... jump to the fallbackBb on last type check's failure + FlowEdge* const falseEdge = fgAddRefPred(fallbackBb, curTypeCheckBb); + curTypeCheckBb->SetFalseEdge(falseEdge); + } + else + { + // ... jump to the next type check on failure + FlowEdge* const falseEdge = fgAddRefPred(typeChecksBbs[candidateId + 1], curTypeCheckBb); + curTypeCheckBb->SetFalseEdge(falseEdge); + } + } + + fgRedirectTargetEdge(firstBb, nullcheckBb); + // // Re-distribute weights and set edge likelihoods. // diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e50773eefd4a53..49bdd4e5e77576 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4403,10 +4403,10 @@ void Compiler::impImportLeave(BasicBlock* block) assert(step == DUMMY_INIT(NULL)); callBlock = block; + // callBlock calls the finally handler assert(callBlock->HasInitializedTarget()); - fgRemoveRefPred(callBlock->GetTargetEdge()); - - // callBlock will call the finally handler. This will be set up later. + fgRedirectTargetEdge(callBlock, HBtab->ebdHndBeg); + callBlock->SetKind(BBJ_CALLFINALLY); if (endCatches) { @@ -4428,15 +4428,22 @@ void Compiler::impImportLeave(BasicBlock* block) // Calling the finally block. - // callBlock will call the finally handler. This will be set up later. + // callBlock calls the finally handler callBlock = fgNewBBinRegion(BBJ_CALLFINALLY, XTnum + 1, 0, step); + { + FlowEdge* const newEdge = fgAddRefPred(HBtab->ebdHndBeg, callBlock); + callBlock->SetTargetEdge(newEdge); + } + // step's jump target shouldn't be set yet assert(!step->HasInitializedTarget()); - // the previous call to a finally returns to this call (to the next finally in the chain) - FlowEdge* const newEdge = fgAddRefPred(callBlock, step); - step->SetTargetEdge(newEdge); + { + // the previous call to a finally returns to this call (to the next finally in the chain) + FlowEdge* const newEdge = fgAddRefPred(callBlock, step); + step->SetTargetEdge(newEdge); + } // The new block will inherit this block's weight. callBlock->inheritWeight(block); @@ -4466,6 +4473,9 @@ void Compiler::impImportLeave(BasicBlock* block) impEndTreeList(callBlock, endLFinStmt, lastStmt); } + // callBlock should be set up at this point + assert(callBlock->TargetIs(HBtab->ebdHndBeg)); + // Note: we don't know the jump target yet step = fgNewBBafter(BBJ_CALLFINALLYRET, callBlock, true); // The new block will inherit this block's weight. @@ -4484,9 +4494,6 @@ void Compiler::impImportLeave(BasicBlock* block) unsigned finallyNesting = compHndBBtab[XTnum].ebdHandlerNestingLevel; assert(finallyNesting <= compHndBBtabCount); - FlowEdge* const newEdge = fgAddRefPred(HBtab->ebdHndBeg, callBlock); - callBlock->SetKindAndTargetEdge(BBJ_CALLFINALLY, newEdge); - GenTree* endLFin = new (this, GT_END_LFIN) GenTreeVal(GT_END_LFIN, TYP_VOID, finallyNesting); endLFinStmt = gtNewStmt(endLFin); endCatches = NULL; @@ -4739,6 +4746,10 @@ void Compiler::impImportLeave(BasicBlock* block) callBlock->inheritWeight(block); callBlock->SetFlags(BBF_IMPORTED); + // callBlock calls the finally handler + FlowEdge* const newEdge = fgAddRefPred(HBtab->ebdHndBeg, callBlock); + callBlock->SetKindAndTargetEdge(BBJ_CALLFINALLY, newEdge); + #ifdef DEBUG if (verbose) { @@ -4752,10 +4763,10 @@ void Compiler::impImportLeave(BasicBlock* block) callBlock = block; + // callBlock calls the finally handler assert(callBlock->HasInitializedTarget()); - fgRemoveRefPred(callBlock->GetTargetEdge()); - -// callBlock will call the finally handler. This will be set up later. + fgRedirectTargetEdge(callBlock, HBtab->ebdHndBeg); + callBlock->SetKind(BBJ_CALLFINALLY); #ifdef DEBUG if (verbose) @@ -4854,6 +4865,10 @@ void Compiler::impImportLeave(BasicBlock* block) callBlock->inheritWeight(block); callBlock->SetFlags(BBF_IMPORTED); + // callBlock calls the finally handler + FlowEdge* const newEdge = fgAddRefPred(HBtab->ebdHndBeg, callBlock); + callBlock->SetKindAndTargetEdge(BBJ_CALLFINALLY, newEdge); + #ifdef DEBUG if (verbose) { @@ -4864,6 +4879,9 @@ void Compiler::impImportLeave(BasicBlock* block) #endif } + // callBlock should be set up at this point + assert(callBlock->TargetIs(HBtab->ebdHndBeg)); + // Note: we don't know the jump target yet step = fgNewBBafter(BBJ_CALLFINALLYRET, callBlock, true); stepType = ST_FinallyReturn; @@ -4881,9 +4899,6 @@ void Compiler::impImportLeave(BasicBlock* block) XTnum, step->bbNum); } #endif - - FlowEdge* const newEdge = fgAddRefPred(HBtab->ebdHndBeg, callBlock); - callBlock->SetKindAndTargetEdge(BBJ_CALLFINALLY, newEdge); } else if (HBtab->HasCatchHandler() && jitIsBetween(blkAddr, tryBeg, tryEnd) && !jitIsBetween(jmpAddr, tryBeg, tryEnd)) diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index c0fff352e231fb..4363e946af51d4 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -1298,8 +1298,6 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() FlowEdge* const origB2TrueEdge = m_b2->GetTrueEdge(); FlowEdge* const origB2FalseEdge = m_b2->GetFalseEdge(); - FlowEdge* newB1TrueEdge = origB1TrueEdge; - weight_t const origB1TrueLikelihood = origB1TrueEdge->getLikelihood(); weight_t newB1TrueLikelihood = 0; @@ -1318,9 +1316,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // We will now reach via B1 true. // Modify flow for true side of B1 // - m_comp->fgRemoveRefPred(origB1TrueEdge); - newB1TrueEdge = m_comp->fgAddRefPred(m_b2->GetTrueTarget(), m_b1); - m_b1->SetTrueEdge(newB1TrueEdge); + m_comp->fgRedirectTrueEdge(m_b1, m_b2->GetTrueTarget()); newB1TrueLikelihood = (1.0 - origB1TrueLikelihood) + origB1TrueLikelihood * origB2FalseEdge->getLikelihood(); @@ -1328,9 +1324,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // Fix B1 true edge likelihood and min/max weights // - newB1TrueEdge->setLikelihood(newB1TrueLikelihood); + origB1TrueEdge->setLikelihood(newB1TrueLikelihood); weight_t const newB1TrueWeight = m_b1->bbWeight * newB1TrueLikelihood; - newB1TrueEdge->setEdgeWeights(newB1TrueWeight, newB1TrueWeight, m_b1->GetTrueTarget()); + origB1TrueEdge->setEdgeWeights(newB1TrueWeight, newB1TrueWeight, m_b1->GetTrueTarget()); assert(m_b1->KindIs(BBJ_COND)); assert(m_b2->KindIs(BBJ_COND)); diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index f66b9e85fef3c2..e837dbfe72d21f 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -1742,12 +1742,10 @@ void Compiler::optRedirectPrevUnrollIteration(FlowGraphNaturalLoop* loop, BasicB testCopyStmt->SetRootNode(sideEffList); } - fgRemoveRefPred(prevTestBlock->GetTrueEdge()); - fgRemoveRefPred(prevTestBlock->GetFalseEdge()); - // Redirect exit edge from previous iteration to new entry. - FlowEdge* const newEdge = fgAddRefPred(target, prevTestBlock); - prevTestBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); + fgRedirectTrueEdge(prevTestBlock, target); + fgRemoveRefPred(prevTestBlock->GetFalseEdge()); + prevTestBlock->SetKindAndTargetEdge(BBJ_ALWAYS, prevTestBlock->GetTrueEdge()); JITDUMP("Redirecting previously created exiting " FMT_BB " -> " FMT_BB "\n", prevTestBlock->bbNum, target->bbNum);