diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index af81c1638585a..8f6786888dd36 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -5550,7 +5550,7 @@ class AssertionPropFlowCallback { ASSERT_TP pAssertionOut; - if (predBlock->KindIs(BBJ_COND) && predBlock->HasJumpTo(block)) + if (predBlock->KindIs(BBJ_COND) && predBlock->TrueTargetIs(block)) { pAssertionOut = mJumpDestOut[predBlock->bbNum]; @@ -5558,7 +5558,7 @@ class AssertionPropFlowCallback { // Scenario where next block and conditional block, both point to the same block. // In such case, intersect the assertions present on both the out edges of predBlock. - assert(predBlock->NextIs(block)); + assert(predBlock->FalseTargetIs(block)); BitVecOps::IntersectionD(apTraits, pAssertionOut, predBlock->bbAssertionOut); if (VerboseDataflow()) @@ -5728,7 +5728,7 @@ ASSERT_TP* Compiler::optComputeAssertionGen() if (jumpDestAssertionIndex != NO_ASSERTION_INDEX) { - // Update jumpDestValueGen if we have an assertion for the bbJumpDest edge + // Update jumpDestValueGen if we have an assertion for the bbTarget edge optImpliedAssertions(jumpDestAssertionIndex, jumpDestValueGen); BitVecOps::AddElemD(apTraits, jumpDestValueGen, jumpDestAssertionIndex - 1); } @@ -5755,7 +5755,7 @@ ASSERT_TP* Compiler::optComputeAssertionGen() optPrintAssertionIndices(block->bbAssertionGen); if (block->KindIs(BBJ_COND)) { - printf(" => " FMT_BB " valueGen = ", block->GetJumpDest()->bbNum); + printf(" => " FMT_BB " valueGen = ", block->GetTrueTarget()->bbNum); optPrintAssertionIndices(jumpDestGen[block->bbNum]); } printf("\n"); @@ -6315,7 +6315,7 @@ PhaseStatus Compiler::optAssertionPropMain() optDumpAssertionIndices(" out = ", block->bbAssertionOut, "\n"); if (block->KindIs(BBJ_COND)) { - printf(" " FMT_BB " = ", block->GetJumpDest()->bbNum); + printf(" " FMT_BB " = ", block->GetTrueTarget()->bbNum); optDumpAssertionIndices(bbJtrueAssertionOut[block->bbNum], "\n"); } } diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index e6e2abeb059c2..a8ab92f5c668e 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -297,7 +297,7 @@ bool BasicBlock::IsFirstColdBlock(Compiler* compiler) const bool BasicBlock::CanRemoveJumpToNext(Compiler* compiler) { assert(KindIs(BBJ_ALWAYS)); - return JumpsToNext() && !hasAlign() && !compiler->fgInDifferentRegions(this, bbJumpDest); + return JumpsToNext() && !hasAlign() && !compiler->fgInDifferentRegions(this, bbTarget); } //------------------------------------------------------------------------ @@ -644,7 +644,7 @@ void BasicBlock::dspSuccs(Compiler* compiler) // and/or compute this switch block's unique succ set if it is not present. Debug output functions should // never have an effect on codegen. We also don't want to assume the unique succ set is accurate, so we // compute it ourselves here. - if (bbJumpKind == BBJ_SWITCH) + if (bbKind == BBJ_SWITCH) { // Create a set with all the successors. Don't use BlockSet, so we don't need to worry // about the BlockSet epoch. @@ -660,7 +660,7 @@ void BasicBlock::dspSuccs(Compiler* compiler) while (iter.NextElem(&bbNum)) { // Note that we will output switch successors in increasing numerical bbNum order, which is - // not related to their order in the bbJumpSwt->bbsDstTab table. + // not related to their order in the bbSwtTargets->bbsDstTab table. printf("%s" FMT_BB, first ? "" : ",", bbNum); first = false; } @@ -675,26 +675,26 @@ void BasicBlock::dspSuccs(Compiler* compiler) } } -// Display a compact representation of the bbJumpKind, that is, where this block branches. +// Display a compact representation of the bbKind, that is, where this block branches. // This is similar to code in Compiler::fgTableDispBasicBlock(), but doesn't have that code's requirements to align // things strictly. -void BasicBlock::dspJumpKind() +void BasicBlock::dspKind() { - switch (bbJumpKind) + switch (bbKind) { case BBJ_EHFINALLYRET: { printf(" ->"); // Early in compilation, we display the jump kind before the BBJ_EHFINALLYRET successors have been set. - if (bbJumpEhf == nullptr) + if (bbEhfTargets == nullptr) { printf(" ????"); } else { - const unsigned jumpCnt = bbJumpEhf->bbeCount; - BasicBlock** const jumpTab = bbJumpEhf->bbeSuccs; + const unsigned jumpCnt = bbEhfTargets->bbeCount; + BasicBlock** const jumpTab = bbEhfTargets->bbeSuccs; for (unsigned i = 0; i < jumpCnt; i++) { @@ -711,11 +711,11 @@ void BasicBlock::dspJumpKind() break; case BBJ_EHFILTERRET: - printf(" -> " FMT_BB " (fltret)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (fltret)", bbTarget->bbNum); break; case BBJ_EHCATCHRET: - printf(" -> " FMT_BB " (cret)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (cret)", bbTarget->bbNum); break; case BBJ_THROW: @@ -729,47 +729,47 @@ void BasicBlock::dspJumpKind() case BBJ_ALWAYS: if (HasFlag(BBF_KEEP_BBJ_ALWAYS)) { - printf(" -> " FMT_BB " (ALWAYS)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (ALWAYS)", bbTarget->bbNum); } else { - printf(" -> " FMT_BB " (always)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (always)", bbTarget->bbNum); } break; case BBJ_LEAVE: - printf(" -> " FMT_BB " (leave)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (leave)", bbTarget->bbNum); break; case BBJ_CALLFINALLY: - printf(" -> " FMT_BB " (callf)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (callf)", bbTarget->bbNum); break; case BBJ_COND: - printf(" -> " FMT_BB " (cond)", bbJumpDest->bbNum); + printf(" -> " FMT_BB " (cond)", bbTarget->bbNum); break; case BBJ_SWITCH: { printf(" ->"); - const unsigned jumpCnt = bbJumpSwt->bbsCount; - BasicBlock** const jumpTab = bbJumpSwt->bbsDstTab; + const unsigned jumpCnt = bbSwtTargets->bbsCount; + BasicBlock** const jumpTab = bbSwtTargets->bbsDstTab; for (unsigned i = 0; i < jumpCnt; i++) { printf("%c" FMT_BB, (i == 0) ? ' ' : ',', jumpTab[i]->bbNum); - const bool isDefault = bbJumpSwt->bbsHasDefault && (i == jumpCnt - 1); + const bool isDefault = bbSwtTargets->bbsHasDefault && (i == jumpCnt - 1); if (isDefault) { printf("[def]"); } - const bool isDominant = bbJumpSwt->bbsHasDominantCase && (i == bbJumpSwt->bbsDominantCase); + const bool isDominant = bbSwtTargets->bbsHasDominantCase && (i == bbSwtTargets->bbsDominantCase); if (isDominant) { - printf("[dom(" FMT_WT ")]", bbJumpSwt->bbsDominantFraction); + printf("[dom(" FMT_WT ")]", bbSwtTargets->bbsDominantFraction); } } @@ -792,7 +792,7 @@ void BasicBlock::dspBlockHeader(Compiler* compiler, dspBlockILRange(); if (showKind) { - dspJumpKind(); + dspKind(); } if (showPreds) { @@ -993,7 +993,7 @@ BasicBlock* BasicBlock::GetUniquePred(Compiler* compiler) const // BasicBlock* BasicBlock::GetUniqueSucc() const { - return KindIs(BBJ_ALWAYS) ? bbJumpDest : nullptr; + return KindIs(BBJ_ALWAYS) ? bbTarget : nullptr; } // Static vars. @@ -1098,7 +1098,7 @@ Statement* BasicBlock::FirstNonPhiDefOrCatchArgStore() const bool BasicBlock::bbFallsThrough() const { - switch (bbJumpKind) + switch (bbKind) { case BBJ_THROW: case BBJ_EHFINALLYRET: @@ -1112,13 +1112,13 @@ bool BasicBlock::bbFallsThrough() const return false; case BBJ_COND: - return true; + return NextIs(GetFalseTarget()); case BBJ_CALLFINALLY: return !HasFlag(BBF_RETLESS_CALL); default: - assert(!"Unknown bbJumpKind in bbFallsThrough()"); + assert(!"Unknown bbKind in bbFallsThrough()"); return true; } } @@ -1134,7 +1134,7 @@ bool BasicBlock::bbFallsThrough() const // unsigned BasicBlock::NumSucc() const { - switch (bbJumpKind) + switch (bbKind) { case BBJ_THROW: case BBJ_RETURN: @@ -1149,7 +1149,7 @@ unsigned BasicBlock::NumSucc() const return 1; case BBJ_COND: - if (bbJumpDest == bbNext) + if (bbTarget == bbNext) { return 1; } @@ -1168,15 +1168,15 @@ unsigned BasicBlock::NumSucc() const // We may call this before we've computed the BBJ_EHFINALLYRET successors in the importer. Tolerate. // - if (bbJumpEhf == nullptr) + if (bbEhfTargets == nullptr) { return 0; } - return bbJumpEhf->bbeCount; + return bbEhfTargets->bbeCount; case BBJ_SWITCH: - return bbJumpSwt->bbsCount; + return bbSwtTargets->bbsCount; default: unreached(); @@ -1195,32 +1195,32 @@ unsigned BasicBlock::NumSucc() const BasicBlock* BasicBlock::GetSucc(unsigned i) const { assert(i < NumSucc()); // Index bounds check. - switch (bbJumpKind) + switch (bbKind) { case BBJ_CALLFINALLY: case BBJ_ALWAYS: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: case BBJ_LEAVE: - return bbJumpDest; + return bbTarget; case BBJ_COND: if (i == 0) { - return bbNext; + return bbFalseTarget; } else { assert(i == 1); - assert(bbNext != bbJumpDest); - return bbJumpDest; + assert(bbFalseTarget != bbTrueTarget); + return bbTrueTarget; } case BBJ_EHFINALLYRET: - return bbJumpEhf->bbeSuccs[i]; + return bbEhfTargets->bbeSuccs[i]; case BBJ_SWITCH: - return bbJumpSwt->bbsDstTab[i]; + return bbSwtTargets->bbsDstTab[i]; default: unreached(); @@ -1240,7 +1240,7 @@ unsigned BasicBlock::NumSucc(Compiler* comp) { assert(comp != nullptr); - switch (bbJumpKind) + switch (bbKind) { case BBJ_THROW: case BBJ_RETURN: @@ -1257,12 +1257,12 @@ unsigned BasicBlock::NumSucc(Compiler* comp) // We may call this before we've computed the BBJ_EHFINALLYRET successors in the importer. Tolerate. // - if (bbJumpEhf == nullptr) + if (bbEhfTargets == nullptr) { return 0; } - return bbJumpEhf->bbeCount; + return bbEhfTargets->bbeCount; case BBJ_CALLFINALLY: case BBJ_ALWAYS: @@ -1272,7 +1272,7 @@ unsigned BasicBlock::NumSucc(Compiler* comp) return 1; case BBJ_COND: - if (bbJumpDest == bbNext) + if (bbTarget == bbNext) { return 1; } @@ -1307,34 +1307,34 @@ BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp) assert(comp != nullptr); assert(i < NumSucc(comp)); // Index bounds check. - switch (bbJumpKind) + switch (bbKind) { case BBJ_EHFILTERRET: // Handler is the (sole) normal successor of the filter. - assert(comp->fgFirstBlockOfHandler(this) == bbJumpDest); - return bbJumpDest; + assert(comp->fgFirstBlockOfHandler(this) == bbTarget); + return bbTarget; case BBJ_EHFINALLYRET: - assert(bbJumpEhf != nullptr); - assert(i < bbJumpEhf->bbeCount); - return bbJumpEhf->bbeSuccs[i]; + assert(bbEhfTargets != nullptr); + assert(i < bbEhfTargets->bbeCount); + return bbEhfTargets->bbeSuccs[i]; case BBJ_CALLFINALLY: case BBJ_ALWAYS: case BBJ_EHCATCHRET: case BBJ_LEAVE: - return bbJumpDest; + return bbTarget; case BBJ_COND: if (i == 0) { - return bbNext; + return bbFalseTarget; } else { assert(i == 1); - assert(bbNext != bbJumpDest); - return bbJumpDest; + assert(bbFalseTarget != bbTrueTarget); + return bbTrueTarget; } case BBJ_SWITCH: @@ -1366,7 +1366,7 @@ void BasicBlock::InitVarSets(Compiler* comp) // Returns true if the basic block ends with GT_JMP bool BasicBlock::endsWithJmpMethod(Compiler* comp) const { - if (comp->compJmpOpUsed && (bbJumpKind == BBJ_RETURN) && HasFlag(BBF_HAS_JMP)) + if (comp->compJmpOpUsed && (bbKind == BBJ_RETURN) && HasFlag(BBF_HAS_JMP)) { GenTree* lastNode = this->lastNode(); assert(lastNode != nullptr); @@ -1425,12 +1425,12 @@ bool BasicBlock::endsWithTailCall(Compiler* comp, if (fastTailCallsOnly || tailCallsConvertibleToLoopOnly) { // Only fast tail calls or only tail calls convertible to loops - result = HasFlag(BBF_HAS_JMP) && (bbJumpKind == BBJ_RETURN); + result = HasFlag(BBF_HAS_JMP) && (bbKind == BBJ_RETURN); } else { // Fast tail calls, tail calls convertible to loops, and tails calls dispatched via helper - result = (bbJumpKind == BBJ_THROW) || (HasFlag(BBF_HAS_JMP) && (bbJumpKind == BBJ_RETURN)); + result = (bbKind == BBJ_THROW) || (HasFlag(BBF_HAS_JMP) && (bbKind == BBJ_RETURN)); } if (result) @@ -1592,15 +1592,15 @@ BasicBlock* BasicBlock::New(Compiler* compiler) return block; } -BasicBlock* BasicBlock::New(Compiler* compiler, BBjumpKinds jumpKind, BasicBlock* jumpDest /* = nullptr */) +BasicBlock* BasicBlock::New(Compiler* compiler, BBKinds kind, BasicBlock* target /* = nullptr */) { BasicBlock* block = BasicBlock::New(compiler); // In some cases, we don't know a block's jump target during initialization, so don't check the jump kind/target // yet. // The checks will be done any time the jump kind/target is read or written to after initialization. - block->bbJumpKind = jumpKind; - block->bbJumpDest = jumpDest; + block->bbKind = kind; + block->bbTarget = target; if (block->KindIs(BBJ_THROW)) { @@ -1610,19 +1610,27 @@ BasicBlock* BasicBlock::New(Compiler* compiler, BBjumpKinds jumpKind, BasicBlock return block; } -BasicBlock* BasicBlock::New(Compiler* compiler, BBswtDesc* jumpSwt) +BasicBlock* BasicBlock::New(Compiler* compiler, BBehfDesc* ehfTargets) { - BasicBlock* block = BasicBlock::New(compiler); - block->bbJumpKind = BBJ_SWITCH; - block->bbJumpSwt = jumpSwt; + BasicBlock* block = BasicBlock::New(compiler); + block->bbKind = BBJ_EHFINALLYRET; + block->bbEhfTargets = ehfTargets; return block; } -BasicBlock* BasicBlock::New(Compiler* compiler, BBjumpKinds jumpKind, unsigned jumpOffs) +BasicBlock* BasicBlock::New(Compiler* compiler, BBswtDesc* swtTargets) { - BasicBlock* block = BasicBlock::New(compiler); - block->bbJumpKind = jumpKind; - block->bbJumpOffs = jumpOffs; + BasicBlock* block = BasicBlock::New(compiler); + block->bbKind = BBJ_SWITCH; + block->bbSwtTargets = swtTargets; + return block; +} + +BasicBlock* BasicBlock::New(Compiler* compiler, BBKinds kind, unsigned targetOffs) +{ + BasicBlock* block = BasicBlock::New(compiler); + block->bbKind = kind; + block->bbTargetOffs = targetOffs; return block; } @@ -1724,7 +1732,7 @@ bool BasicBlock::hasEHBoundaryOut() const bool returnVal = KindIs(BBJ_EHFILTERRET, BBJ_EHFINALLYRET, BBJ_EHFAULTRET); #if FEATURE_EH_FUNCLETS - if (bbJumpKind == BBJ_EHCATCHRET) + if (bbKind == BBJ_EHCATCHRET) { returnVal = true; } diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 93fdc0358ce83..159bcd61f5470 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -57,7 +57,7 @@ typedef BitVec_ValRet_T ASSERT_VALRET_TP; // clang-format off -enum BBjumpKinds : BYTE +enum BBKinds : BYTE { BBJ_EHFINALLYRET,// block ends with 'endfinally' (for finally) BBJ_EHFAULTRET, // block ends with 'endfinally' (IL alias for 'endfault') (for fault) @@ -75,7 +75,7 @@ enum BBjumpKinds : BYTE }; #ifdef DEBUG -const char* const BBjumpKindNames[] = { +const char* const bbKindNames[] = { "BBJ_EHFINALLYRET", "BBJ_EHFAULTRET", "BBJ_EHFILTERRET", @@ -522,34 +522,39 @@ struct BasicBlock : private LIR::Range BasicBlock* bbNext; // next BB in ascending PC offset order BasicBlock* bbPrev; - BBjumpKinds bbJumpKind; // jump (if any) at the end of this block + BBKinds bbKind; // jump (if any) at the end of this block /* The following union describes the jump target(s) of this block */ union { - unsigned bbJumpOffs; // PC offset (temporary only) - BasicBlock* bbJumpDest; // basic block - BBswtDesc* bbJumpSwt; // switch descriptor - BBehfDesc* bbJumpEhf; // BBJ_EHFINALLYRET descriptor + unsigned bbTargetOffs; // PC offset (temporary only) + BasicBlock* bbTarget; // basic block + BasicBlock* bbTrueTarget; // BBJ_COND jump target when its condition is true (alias for bbTarget) + BBswtDesc* bbSwtTargets; // switch descriptor + BBehfDesc* bbEhfTargets; // BBJ_EHFINALLYRET descriptor }; + // Points to the successor of a BBJ_COND block if bbTrueTarget is not taken + BasicBlock* bbFalseTarget; + public: static BasicBlock* New(Compiler* compiler); - static BasicBlock* New(Compiler* compiler, BBjumpKinds jumpKind, BasicBlock* jumpDest = nullptr); - static BasicBlock* New(Compiler* compiler, BBswtDesc* jumpSwt); - static BasicBlock* New(Compiler* compiler, BBjumpKinds jumpKind, unsigned jumpOffs); + static BasicBlock* New(Compiler* compiler, BBKinds kind, BasicBlock* target = nullptr); + static BasicBlock* New(Compiler* compiler, BBehfDesc* ehfTargets); + static BasicBlock* New(Compiler* compiler, BBswtDesc* swtTargets); + static BasicBlock* New(Compiler* compiler, BBKinds kind, unsigned targetOffs); - BBjumpKinds GetJumpKind() const + BBKinds GetKind() const { - return bbJumpKind; + return bbKind; } - void SetJumpKind(BBjumpKinds jumpKind) + void SetKind(BBKinds kind) { // If this block's jump kind requires a target, ensure it is already set - assert(!HasJumpDest() || HasInitializedJumpDest()); - bbJumpKind = jumpKind; + assert(!HasTarget() || HasInitializedTarget()); + bbKind = kind; // If new jump kind requires a target, ensure a target is already set - assert(!HasJumpDest() || HasInitializedJumpDest()); + assert(!HasTarget() || HasInitializedTarget()); } BasicBlock* Prev() const @@ -578,6 +583,12 @@ struct BasicBlock : private LIR::Range { next->bbPrev = this; } + + // BBJ_COND convenience: This ensures bbFalseTarget is always consistent with bbNext. + // For now, if a BBJ_COND's bbTrueTarget is not taken, we expect to fall through, + // so bbFalseTarget must be the next block. + // TODO-NoFallThrough: Remove this once we allow bbFalseTarget to diverge from bbNext + bbFalseTarget = next; } bool IsFirst() const @@ -606,98 +617,166 @@ struct BasicBlock : private LIR::Range bool CanRemoveJumpToNext(Compiler* compiler); - unsigned GetJumpOffs() const + unsigned GetTargetOffs() const { - return bbJumpOffs; + return bbTargetOffs; } - void SetJumpKindAndTarget(BBjumpKinds jumpKind, unsigned jumpOffs) + void SetKindAndTarget(BBKinds kind, unsigned targetOffs) { - bbJumpKind = jumpKind; - bbJumpOffs = jumpOffs; + bbKind = kind; + bbTargetOffs = targetOffs; assert(KindIs(BBJ_ALWAYS, BBJ_COND, BBJ_LEAVE)); } - bool HasJumpDest() const + bool HasTarget() const { - // These block types should always have bbJumpDest set + // These block types should always have bbTarget set return KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_COND, BBJ_EHCATCHRET, BBJ_EHFILTERRET, BBJ_LEAVE); } - BasicBlock* GetJumpDest() const + BasicBlock* GetTarget() const + { + // BBJ_COND should use GetTrueTarget, and BBJ_EHFINALLYRET/BBJ_SWITCH don't use bbTarget + assert(!KindIs(BBJ_COND, BBJ_EHFINALLYRET, BBJ_SWITCH)); + + // If bbKind indicates this block has a jump, bbTarget cannot be null + assert(!HasTarget() || HasInitializedTarget()); + return bbTarget; + } + + void SetTarget(BasicBlock* target) + { + // BBJ_COND should use SetTrueTarget, and BBJ_EHFINALLYRET/BBJ_SWITCH don't use bbTarget + assert(!KindIs(BBJ_COND, BBJ_EHFINALLYRET, BBJ_SWITCH)); + + // SetKindAndTarget() nulls target for non-jump kinds, + // so don't use SetTarget() to null bbTarget without updating bbKind. + bbTarget = target; + assert(!HasTarget() || HasInitializedTarget()); + } + + BasicBlock* GetTrueTarget() const { - // If bbJumpKind indicates this block has a jump, bbJumpDest cannot be null - assert(!HasJumpDest() || HasInitializedJumpDest()); - return bbJumpDest; + assert(KindIs(BBJ_COND)); + assert(HasInitializedTarget()); + return bbTrueTarget; } - void SetJumpDest(BasicBlock* jumpDest) + void SetTrueTarget(BasicBlock* target) { - // SetJumpKindAndTarget() nulls jumpDest for non-jump kinds, - // so don't use SetJumpDest() to null bbJumpDest without updating bbJumpKind. - bbJumpDest = jumpDest; - assert(!HasJumpDest() || HasInitializedJumpDest()); + assert(KindIs(BBJ_COND)); + assert(target != nullptr); + bbTrueTarget = target; } - void SetJumpKindAndTarget(BBjumpKinds jumpKind, BasicBlock* jumpDest = nullptr) + bool TrueTargetIs(const BasicBlock* target) const { - bbJumpKind = jumpKind; - bbJumpDest = jumpDest; + assert(KindIs(BBJ_COND)); + assert(HasInitializedTarget()); + assert(target != nullptr); + return (bbTrueTarget == target); + } + + BasicBlock* GetFalseTarget() const + { + assert(KindIs(BBJ_COND)); + + // So long as bbFalseTarget tracks bbNext in SetNext(), it is possible for bbFalseTarget to be null + // if this block is unlinked from the block list. + // So check bbNext before triggering the assert if bbFalseTarget is null. + // TODO-NoFallThrough: Remove IsLast() check once bbFalseTarget isn't hard-coded to bbNext + assert((bbFalseTarget != nullptr) || IsLast()); + return bbFalseTarget; + } + + void SetFalseTarget(BasicBlock* target) + { + assert(KindIs(BBJ_COND)); + assert(target != nullptr); + bbFalseTarget = target; + } + + bool FalseTargetIs(const BasicBlock* target) const + { + assert(KindIs(BBJ_COND)); + assert(bbFalseTarget != nullptr); + assert(target != nullptr); + return (bbFalseTarget == target); + } + + void SetCond(BasicBlock* target) + { + assert(target != nullptr); + bbKind = BBJ_COND; + bbTrueTarget = target; + } + + void SetKindAndTarget(BBKinds kind, BasicBlock* target = nullptr) + { + // For BBJ_COND/BBJ_EHFINALLYRET/BBJ_SWITCH, use SetCond/SetEhf/SetSwitch + assert(kind != BBJ_COND); + assert(kind != BBJ_EHFINALLYRET); + assert(kind != BBJ_SWITCH); + + bbKind = kind; + bbTarget = target; - // If bbJumpKind indicates this block has a jump, bbJumpDest cannot be null - assert(!HasJumpDest() || HasInitializedJumpDest()); + // If bbKind indicates this block has a jump, bbTarget cannot be null + assert(!HasTarget() || HasInitializedTarget()); } - bool HasInitializedJumpDest() const + bool HasInitializedTarget() const { - assert(HasJumpDest()); - return (bbJumpDest != nullptr); + assert(HasTarget()); + return (bbTarget != nullptr); } - bool HasJumpTo(const BasicBlock* jumpDest) const + bool TargetIs(const BasicBlock* target) const { - assert(HasInitializedJumpDest()); - return (bbJumpDest == jumpDest); + // BBJ_COND should use TrueTargetIs, and BBJ_EHFINALLYRET/BBJ_SWITCH don't use bbTarget + assert(!KindIs(BBJ_COND, BBJ_EHFINALLYRET, BBJ_SWITCH)); + assert(HasInitializedTarget()); + return (bbTarget == target); } bool JumpsToNext() const { - assert(HasInitializedJumpDest()); - return (bbJumpDest == bbNext); + assert(HasInitializedTarget()); + return (bbTarget == bbNext); } - BBswtDesc* GetJumpSwt() const + BBswtDesc* GetSwitchTargets() const { assert(KindIs(BBJ_SWITCH)); - assert(bbJumpSwt != nullptr); - return bbJumpSwt; + assert(bbSwtTargets != nullptr); + return bbSwtTargets; } - void SetSwitchKindAndTarget(BBswtDesc* jumpSwt) + void SetSwitch(BBswtDesc* swtTarget) { - assert(jumpSwt != nullptr); - bbJumpKind = BBJ_SWITCH; - bbJumpSwt = jumpSwt; + assert(swtTarget != nullptr); + bbKind = BBJ_SWITCH; + bbSwtTargets = swtTarget; } - BBehfDesc* GetJumpEhf() const + BBehfDesc* GetEhfTargets() const { assert(KindIs(BBJ_EHFINALLYRET)); - return bbJumpEhf; + return bbEhfTargets; } - void SetJumpEhf(BBehfDesc* jumpEhf) + void SetEhfTargets(BBehfDesc* ehfTarget) { assert(KindIs(BBJ_EHFINALLYRET)); - bbJumpEhf = jumpEhf; + bbEhfTargets = ehfTarget; } - void SetJumpKindAndTarget(BBjumpKinds jumpKind, BBehfDesc* jumpEhf) + void SetEhf(BBehfDesc* ehfTarget) { - assert(jumpKind == BBJ_EHFINALLYRET); - assert(jumpEhf != nullptr); - bbJumpKind = jumpKind; - bbJumpEhf = jumpEhf; + assert(ehfTarget != nullptr); + bbKind = BBJ_EHFINALLYRET; + bbEhfTargets = ehfTarget; } private: @@ -806,7 +885,7 @@ struct BasicBlock : private LIR::Range unsigned dspPreds(); // Print the predecessors (bbPreds) void dspSuccs(Compiler* compiler); // Print the successors. The 'compiler' argument determines whether EH // regions are printed: see NumSucc() for details. - void dspJumpKind(); // Print the block jump kind (e.g., BBJ_ALWAYS, BBJ_COND, etc.). + void dspKind(); // Print the block jump kind (e.g., BBJ_ALWAYS, BBJ_COND, etc.). // Print a simple basic block header for various output, including a list of predecessors and successors. void dspBlockHeader(Compiler* compiler, bool showKind = true, bool showFlags = false, bool showPreds = true); @@ -951,13 +1030,13 @@ struct BasicBlock : private LIR::Range // a block corresponding to an exit from the try of a try/finally. bool isBBCallAlwaysPairTail() const; - bool KindIs(BBjumpKinds kind) const + bool KindIs(BBKinds kind) const { - return bbJumpKind == kind; + return bbKind == kind; } template - bool KindIs(BBjumpKinds kind, T... rest) const + bool KindIs(BBKinds kind, T... rest) const { return KindIs(kind) || KindIs(rest...); } @@ -996,8 +1075,8 @@ struct BasicBlock : private LIR::Range // BBSwitchTargetList SwitchTargets() const { - assert(bbJumpKind == BBJ_SWITCH); - return BBSwitchTargetList(bbJumpSwt); + assert(bbKind == BBJ_SWITCH); + return BBSwitchTargetList(bbSwtTargets); } // EHFinallyRetSuccs: convenience method for enabling range-based `for` iteration over BBJ_EHFINALLYRET block @@ -1006,8 +1085,8 @@ struct BasicBlock : private LIR::Range // BBEhfSuccList EHFinallyRetSuccs() const { - assert(bbJumpKind == BBJ_EHFINALLYRET); - return BBEhfSuccList(bbJumpEhf); + assert(bbKind == BBJ_EHFINALLYRET); + return BBEhfSuccList(bbEhfTargets); } BasicBlock* GetUniquePred(Compiler* comp) const; @@ -1828,7 +1907,7 @@ inline BBArrayIterator BBEhfSuccList::end() const inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block) { assert(block != nullptr); - switch (block->bbJumpKind) + switch (block->bbKind) { case BBJ_THROW: case BBJ_RETURN: @@ -1843,13 +1922,13 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block) case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: case BBJ_LEAVE: - m_succs[0] = block->bbJumpDest; + m_succs[0] = block->bbTarget; m_begin = &m_succs[0]; m_end = &m_succs[1]; break; case BBJ_COND: - m_succs[0] = block->bbNext; + m_succs[0] = block->bbFalseTarget; m_begin = &m_succs[0]; // If both fall-through and branch successors are identical, then only include @@ -1860,7 +1939,7 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block) } else { - m_succs[1] = block->bbJumpDest; + m_succs[1] = block->bbTrueTarget; m_end = &m_succs[2]; } break; @@ -1869,24 +1948,24 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block) // We don't use the m_succs in-line data; use the existing successor table in the block. // We must tolerate iterating successors early in the system, before EH_FINALLYRET successors have // been computed. - if (block->GetJumpEhf() == nullptr) + if (block->GetEhfTargets() == nullptr) { m_begin = nullptr; m_end = nullptr; } else { - m_begin = block->GetJumpEhf()->bbeSuccs; - m_end = block->GetJumpEhf()->bbeSuccs + block->GetJumpEhf()->bbeCount; + m_begin = block->GetEhfTargets()->bbeSuccs; + m_end = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount; } break; case BBJ_SWITCH: // We don't use the m_succs in-line data for switches; use the existing jump table in the block. - assert(block->bbJumpSwt != nullptr); - assert(block->bbJumpSwt->bbsDstTab != nullptr); - m_begin = block->bbJumpSwt->bbsDstTab; - m_end = block->bbJumpSwt->bbsDstTab + block->bbJumpSwt->bbsCount; + assert(block->bbSwtTargets != nullptr); + assert(block->bbSwtTargets->bbsDstTab != nullptr); + m_begin = block->bbSwtTargets->bbsDstTab; + m_end = block->bbSwtTargets->bbsDstTab + block->bbSwtTargets->bbsCount; break; default: diff --git a/src/coreclr/jit/clrjit.natvis b/src/coreclr/jit/clrjit.natvis index f56ac98cf6a16..deafd370c58d8 100644 --- a/src/coreclr/jit/clrjit.natvis +++ b/src/coreclr/jit/clrjit.natvis @@ -21,10 +21,10 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u - BB{bbNum,d}->BB{bbJumpDest->bbNum,d}; {bbJumpKind,en} - BB{bbNum,d}; {bbJumpKind,en}; {bbJumpSwt->bbsCount} cases - BB{bbNum,d}; {bbJumpKind,en}; {bbJumpEhf->bbeCount} succs - BB{bbNum,d}; {bbJumpKind,en} + BB{bbNum,d}->BB{bbTarget->bbNum,d}; {bbKind,en} + BB{bbNum,d}; {bbKind,en}; {bbSwtTargets->bbsCount} cases + BB{bbNum,d}; {bbKind,en}; {bbEhfTargets->bbeCount} succs + BB{bbNum,d}; {bbKind,en} diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp index 4f34c29058052..e3539b9c87ff4 100644 --- a/src/coreclr/jit/codegenarm.cpp +++ b/src/coreclr/jit/codegenarm.cpp @@ -117,7 +117,7 @@ bool CodeGen::genStackPointerAdjustment(ssize_t spDelta, regNumber tmpReg) // BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { - GetEmitter()->emitIns_J(INS_bl, block->GetJumpDest()); + GetEmitter()->emitIns_J(INS_bl, block->GetTarget()); BasicBlock* nextBlock = block->Next(); @@ -137,7 +137,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) // handler. So turn off GC reporting for this single instruction. GetEmitter()->emitDisableGC(); - BasicBlock* const jumpDest = nextBlock->GetJumpDest(); + BasicBlock* const jumpDest = nextBlock->GetTarget(); // Now go to where the finally funclet needs to return to. if (nextBlock->NextIs(jumpDest) && !compiler->fgInDifferentRegions(nextBlock, jumpDest)) @@ -157,7 +157,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) } // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the - // jump target using bbJumpDest - that is already used to point + // jump target using bbTarget - that is already used to point // to the finally block. So just skip past the BBJ_ALWAYS unless the // block is RETLESS. if (!block->HasFlag(BBF_RETLESS_CALL)) @@ -172,7 +172,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) // genEHCatchRet: void CodeGen::genEHCatchRet(BasicBlock* block) { - genMov32RelocatableDisplacement(block->GetJumpDest(), REG_INTRET); + genMov32RelocatableDisplacement(block->GetTarget(), REG_INTRET); } //------------------------------------------------------------------------ @@ -655,8 +655,8 @@ void CodeGen::genJumpTable(GenTree* treeNode) noway_assert(compiler->compCurBB->KindIs(BBJ_SWITCH)); assert(treeNode->OperGet() == GT_JMPTABLE); - unsigned jumpCount = compiler->compCurBB->GetJumpSwt()->bbsCount; - BasicBlock** jumpTable = compiler->compCurBB->GetJumpSwt()->bbsDstTab; + unsigned jumpCount = compiler->compCurBB->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTable = compiler->compCurBB->GetSwitchTargets()->bbsDstTab; unsigned jmpTabBase; jmpTabBase = GetEmitter()->emitBBTableDataGenBeg(jumpCount, false); @@ -1321,7 +1321,7 @@ void CodeGen::genCodeForJTrue(GenTreeOp* jtrue) GenTree* op = jtrue->gtGetOp1(); regNumber reg = genConsumeReg(op); inst_RV_RV(INS_tst, reg, reg, genActualType(op)); - inst_JMP(EJ_ne, compiler->compCurBB->GetJumpDest()); + inst_JMP(EJ_ne, compiler->compCurBB->GetTrueTarget()); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 9432bc714e252..983b13969412d 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2158,7 +2158,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, REG_R0, REG_SPBASE, /* canSkip */ false); } - GetEmitter()->emitIns_J(INS_bl_local, block->GetJumpDest()); + GetEmitter()->emitIns_J(INS_bl_local, block->GetTarget()); BasicBlock* const nextBlock = block->Next(); @@ -2181,7 +2181,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) // handler. So turn off GC reporting for this single instruction. GetEmitter()->emitDisableGC(); - BasicBlock* const jumpDest = nextBlock->GetJumpDest(); + BasicBlock* const jumpDest = nextBlock->GetTarget(); // Now go to where the finally funclet needs to return to. if (nextBlock->NextIs(jumpDest) && !compiler->fgInDifferentRegions(nextBlock, jumpDest)) @@ -2201,7 +2201,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) } // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the - // jump target using bbJumpDest - that is already used to point + // jump target using bbTarget - that is already used to point // to the finally block. So just skip past the BBJ_ALWAYS unless the // block is RETLESS. if (!block->HasFlag(BBF_RETLESS_CALL)) @@ -2216,7 +2216,7 @@ void CodeGen::genEHCatchRet(BasicBlock* block) { // For long address (default): `adrp + add` will be emitted. // For short address (proven later): `adr` will be emitted. - GetEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, block->GetJumpDest(), REG_INTRET); + GetEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, block->GetTarget(), REG_INTRET); } // move an immediate value into an integer register @@ -3752,8 +3752,8 @@ void CodeGen::genJumpTable(GenTree* treeNode) noway_assert(compiler->compCurBB->KindIs(BBJ_SWITCH)); assert(treeNode->OperGet() == GT_JMPTABLE); - unsigned jumpCount = compiler->compCurBB->GetJumpSwt()->bbsCount; - BasicBlock** jumpTable = compiler->compCurBB->GetJumpSwt()->bbsDstTab; + unsigned jumpCount = compiler->compCurBB->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTable = compiler->compCurBB->GetSwitchTargets()->bbsDstTab; unsigned jmpTabOffs; unsigned jmpTabBase; @@ -4654,7 +4654,7 @@ void CodeGen::genCodeForJTrue(GenTreeOp* jtrue) GenTree* op = jtrue->gtGetOp1(); regNumber reg = genConsumeReg(op); - GetEmitter()->emitIns_J_R(INS_cbnz, emitActualTypeSize(op), compiler->compCurBB->GetJumpDest(), reg); + GetEmitter()->emitIns_J_R(INS_cbnz, emitActualTypeSize(op), compiler->compCurBB->GetTrueTarget(), reg); } //------------------------------------------------------------------------ @@ -4872,7 +4872,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) instruction ins = (cc.GetCode() == GenCondition::EQ) ? INS_tbz : INS_tbnz; int imm = genLog2((size_t)compareImm); - GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->GetJumpDest(), reg, imm); + GetEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->GetTrueTarget(), reg, imm); } else { @@ -4880,7 +4880,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) instruction ins = (cc.GetCode() == GenCondition::EQ) ? INS_cbz : INS_cbnz; - GetEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->GetJumpDest(), reg); + GetEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->GetTrueTarget(), reg); } } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 7a96748a50a2c..bf2bb4be24058 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -376,7 +376,7 @@ void CodeGen::genMarkLabelsForCodegen() for (BasicBlock* const block : compiler->Blocks()) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_ALWAYS: // This will also handle the BBJ_ALWAYS of a BBJ_CALLFINALLY/BBJ_ALWAYS pair. { @@ -388,10 +388,14 @@ void CodeGen::genMarkLabelsForCodegen() FALLTHROUGH; } - case BBJ_COND: case BBJ_EHCATCHRET: - JITDUMP(" " FMT_BB " : branch target\n", block->GetJumpDest()->bbNum); - block->GetJumpDest()->SetFlags(BBF_HAS_LABEL); + JITDUMP(" " FMT_BB " : branch target\n", block->GetTarget()->bbNum); + block->GetTarget()->SetFlags(BBF_HAS_LABEL); + break; + + case BBJ_COND: + JITDUMP(" " FMT_BB " : branch target\n", block->GetTrueTarget()->bbNum); + block->GetTrueTarget()->SetFlags(BBF_HAS_LABEL); break; case BBJ_SWITCH: @@ -434,7 +438,7 @@ void CodeGen::genMarkLabelsForCodegen() break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } } diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 33d9a937b6e78..1fe4879affb16 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -619,7 +619,7 @@ void CodeGen::genCodeForBBlist() { // We only need the NOP if we're not going to generate any more code as part of the block end. - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_ALWAYS: // We might skip generating the jump via a peephole optimization. @@ -644,7 +644,7 @@ void CodeGen::genCodeForBBlist() // These can't have a call as the last instruction! default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } } @@ -653,7 +653,7 @@ void CodeGen::genCodeForBBlist() /* Do we need to generate a jump or return? */ - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_RETURN: genExitCode(block); @@ -748,18 +748,14 @@ void CodeGen::genCodeForBBlist() // with a jump, do not remove jumps from such blocks. // Do not remove a jump between hot and cold regions. bool isRemovableJmpCandidate = - !block->hasAlign() && !compiler->fgInDifferentRegions(block, block->GetJumpDest()); + !block->hasAlign() && !compiler->fgInDifferentRegions(block, block->GetTarget()); - inst_JMP(EJ_jmp, block->GetJumpDest(), isRemovableJmpCandidate); + inst_JMP(EJ_jmp, block->GetTarget(), isRemovableJmpCandidate); #else - inst_JMP(EJ_jmp, block->GetJumpDest()); + inst_JMP(EJ_jmp, block->GetTarget()); #endif // TARGET_XARCH } - FALLTHROUGH; - - case BBJ_COND: - #if FEATURE_LOOP_ALIGN // This is the last place where we operate on blocks and after this, we operate // on IG. Hence, if we know that the destination of "block" is the first block @@ -769,14 +765,30 @@ void CodeGen::genCodeForBBlist() // During emitter, this information will be used to calculate the loop size. // Depending on the loop size, decision of whether to align a loop or not will be taken. // - // In the emitter, we need to calculate the loop size from `block->bbJumpDest` through + // In the emitter, we need to calculate the loop size from `block->bbTarget` through // `block` (inclusive). Thus, we need to ensure there is a label on the lexical fall-through // block, even if one is not otherwise needed, to be able to calculate the size of this // loop (loop size is calculated by walking the instruction groups; see emitter::getLoopSize()). - if (block->GetJumpDest()->isLoopAlign()) + if (block->GetTarget()->isLoopAlign()) + { + GetEmitter()->emitSetLoopBackEdge(block->GetTarget()); + + if (!block->IsLast()) + { + JITDUMP("Mark " FMT_BB " as label: alignment end-of-loop\n", block->Next()->bbNum); + block->Next()->SetFlags(BBF_HAS_LABEL); + } + } +#endif // FEATURE_LOOP_ALIGN + break; + + case BBJ_COND: + +#if FEATURE_LOOP_ALIGN + if (block->GetTrueTarget()->isLoopAlign()) { - GetEmitter()->emitSetLoopBackEdge(block->GetJumpDest()); + GetEmitter()->emitSetLoopBackEdge(block->GetTrueTarget()); if (!block->IsLast()) { @@ -789,7 +801,7 @@ void CodeGen::genCodeForBBlist() break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } @@ -2617,7 +2629,7 @@ void CodeGen::genCodeForJcc(GenTreeCC* jcc) assert(compiler->compCurBB->KindIs(BBJ_COND)); assert(jcc->OperIs(GT_JCC)); - inst_JCC(jcc->gtCondition, compiler->compCurBB->GetJumpDest()); + inst_JCC(jcc->gtCondition, compiler->compCurBB->GetTrueTarget()); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 18bb1875dfb8e..68eb98ea9492f 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -1518,7 +1518,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { GetEmitter()->emitIns_R_R_I(INS_ori, EA_PTRSIZE, REG_A0, REG_SPBASE, 0); } - GetEmitter()->emitIns_J(INS_bl, block->GetJumpDest()); + GetEmitter()->emitIns_J(INS_bl, block->GetTarget()); BasicBlock* const nextBlock = block->Next(); @@ -1541,7 +1541,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) // handler. So turn off GC reporting for this single instruction. GetEmitter()->emitDisableGC(); - BasicBlock* const jumpDest = nextBlock->GetJumpDest(); + BasicBlock* const jumpDest = nextBlock->GetTarget(); // Now go to where the finally funclet needs to return to. if (nextBlock->NextIs(jumpDest) && !compiler->fgInDifferentRegions(nextBlock, jumpDest)) @@ -1561,7 +1561,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) } // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the - // jump target using bbJumpDest - that is already used to point + // jump target using bbTarget - that is already used to point // to the finally block. So just skip past the BBJ_ALWAYS unless the // block is RETLESS. if (!block->HasFlag(BBF_RETLESS_CALL)) @@ -1574,7 +1574,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) void CodeGen::genEHCatchRet(BasicBlock* block) { - GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, block->GetJumpDest(), REG_INTRET); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, block->GetTarget(), REG_INTRET); } // move an immediate value into an integer register @@ -2935,8 +2935,8 @@ void CodeGen::genJumpTable(GenTree* treeNode) noway_assert(compiler->compCurBB->KindIs(BBJ_SWITCH)); assert(treeNode->OperGet() == GT_JMPTABLE); - unsigned jumpCount = compiler->compCurBB->GetJumpSwt()->bbsCount; - BasicBlock** jumpTable = compiler->compCurBB->GetJumpSwt()->bbsDstTab; + unsigned jumpCount = compiler->compCurBB->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTable = compiler->compCurBB->GetSwitchTargets()->bbsDstTab; unsigned jmpTabOffs; unsigned jmpTabBase; @@ -4334,7 +4334,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) assert(ins != INS_invalid); assert(regs != 0); - emit->emitIns_J(ins, compiler->compCurBB->GetJumpDest(), regs); // 5-bits; + emit->emitIns_J(ins, compiler->compCurBB->GetTrueTarget(), regs); // 5-bits; } //--------------------------------------------------------------------- @@ -4910,7 +4910,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) case GT_JCC: { - BasicBlock* tgtBlock = compiler->compCurBB->GetJumpDest(); + BasicBlock* tgtBlock = compiler->compCurBB->KindIs(BBJ_COND) ? compiler->compCurBB->GetTrueTarget() + : compiler->compCurBB->GetTarget(); #if !FEATURE_FIXED_OUT_ARGS assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed()); #endif // !FEATURE_FIXED_OUT_ARGS diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index f8b1951263461..03dc95ef40583 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -1156,7 +1156,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { GetEmitter()->emitIns_R_R_I(INS_ori, EA_PTRSIZE, REG_A0, REG_SPBASE, 0); } - GetEmitter()->emitIns_J(INS_jal, block->GetJumpDest()); + GetEmitter()->emitIns_J(INS_jal, block->GetTarget()); BasicBlock* const nextBlock = block->Next(); @@ -1179,7 +1179,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) // handler. So turn off GC reporting for this single instruction. GetEmitter()->emitDisableGC(); - BasicBlock* const jumpDest = nextBlock->GetJumpDest(); + BasicBlock* const jumpDest = nextBlock->GetTarget(); // Now go to where the finally funclet needs to return to. if (nextBlock->NextIs(jumpDest) && !compiler->fgInDifferentRegions(nextBlock, jumpDest)) @@ -1199,7 +1199,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) } // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the - // jump target using bbJumpDest - that is already used to point + // jump target using bbTarget - that is already used to point // to the finally block. So just skip past the BBJ_ALWAYS unless the // block is RETLESS. if (!block->HasFlag(BBF_RETLESS_CALL)) @@ -1212,7 +1212,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) void CodeGen::genEHCatchRet(BasicBlock* block) { - GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, block->GetJumpDest(), REG_INTRET); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, block->GetTarget(), REG_INTRET); } // move an immediate value into an integer register @@ -2577,8 +2577,8 @@ void CodeGen::genJumpTable(GenTree* treeNode) noway_assert(compiler->compCurBB->KindIs(BBJ_SWITCH)); assert(treeNode->OperGet() == GT_JMPTABLE); - unsigned jumpCount = compiler->compCurBB->GetJumpSwt()->bbsCount; - BasicBlock** jumpTable = compiler->compCurBB->GetJumpSwt()->bbsDstTab; + unsigned jumpCount = compiler->compCurBB->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTable = compiler->compCurBB->GetSwitchTargets()->bbsDstTab; unsigned jmpTabOffs; unsigned jmpTabBase; @@ -3985,7 +3985,7 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) assert(ins != INS_invalid); assert(regs != 0); - emit->emitIns_J(ins, compiler->compCurBB->GetJumpDest(), regs); // 5-bits; + emit->emitIns_J(ins, compiler->compCurBB->GetTrueTarget(), regs); // 5-bits; } //--------------------------------------------------------------------- diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 1126414745254..392fc61eb3f8f 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -228,7 +228,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { GetEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_ARG_0, compiler->lvaPSPSym, 0); } - GetEmitter()->emitIns_J(INS_call, block->GetJumpDest()); + GetEmitter()->emitIns_J(INS_call, block->GetTarget()); if (block->HasFlag(BBF_RETLESS_CALL)) { @@ -253,7 +253,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) GetEmitter()->emitDisableGC(); #endif // JIT32_GCENCODER - BasicBlock* const jumpDest = nextBlock->GetJumpDest(); + BasicBlock* const jumpDest = nextBlock->GetTarget(); // Now go to where the finally funclet needs to return to. if (nextBlock->NextIs(jumpDest) && !compiler->fgInDifferentRegions(nextBlock, jumpDest)) @@ -316,7 +316,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) if (!block->HasFlag(BBF_RETLESS_CALL)) { assert(block->isBBCallAlwaysPair()); - GetEmitter()->emitIns_J(INS_push_hide, nextBlock->GetJumpDest()); + GetEmitter()->emitIns_J(INS_push_hide, nextBlock->GetTarget()); } else { @@ -325,12 +325,12 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) } // Jump to the finally BB - inst_JMP(EJ_jmp, block->GetJumpDest()); + inst_JMP(EJ_jmp, block->GetTarget()); #endif // !FEATURE_EH_FUNCLETS // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the - // jump target using bbJumpDest - that is already used to point + // jump target using bbTarget - that is already used to point // to the finally block. So just skip past the BBJ_ALWAYS unless the // block is RETLESS. if (!block->HasFlag(BBF_RETLESS_CALL)) @@ -348,7 +348,7 @@ void CodeGen::genEHCatchRet(BasicBlock* block) // Generate a RIP-relative // lea reg, [rip + disp32] ; the RIP is implicit // which will be position-independent. - GetEmitter()->emitIns_R_L(INS_lea, EA_PTR_DSP_RELOC, block->GetJumpDest(), REG_INTRET); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTR_DSP_RELOC, block->GetTarget(), REG_INTRET); } #else // !FEATURE_EH_FUNCLETS @@ -1450,7 +1450,7 @@ void CodeGen::genCodeForJTrue(GenTreeOp* jtrue) GenTree* op = jtrue->gtGetOp1(); regNumber reg = genConsumeReg(op); inst_RV_RV(INS_test, reg, reg, genActualType(op)); - inst_JMP(EJ_jne, compiler->compCurBB->GetJumpDest()); + inst_JMP(EJ_jne, compiler->compCurBB->GetTrueTarget()); } //------------------------------------------------------------------------ @@ -4265,8 +4265,8 @@ void CodeGen::genJumpTable(GenTree* treeNode) noway_assert(compiler->compCurBB->KindIs(BBJ_SWITCH)); assert(treeNode->OperGet() == GT_JMPTABLE); - unsigned jumpCount = compiler->compCurBB->GetJumpSwt()->bbsCount; - BasicBlock** jumpTable = compiler->compCurBB->GetJumpSwt()->bbsDstTab; + unsigned jumpCount = compiler->compCurBB->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTable = compiler->compCurBB->GetSwitchTargets()->bbsDstTab; unsigned jmpTabOffs; unsigned jmpTabBase; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 315fd2d0988e2..7453540b12a81 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5050,13 +5050,13 @@ class Compiler void fgExtendEHRegionBefore(BasicBlock* block); void fgExtendEHRegionAfter(BasicBlock* block); - BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr); + BasicBlock* fgNewBBbefore(BBKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr); - BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr); + BasicBlock* fgNewBBafter(BBKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest = nullptr); - BasicBlock* fgNewBBFromTreeAfter(BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, BasicBlock* jumpDest = nullptr, bool updateSideEffects = false); + BasicBlock* fgNewBBFromTreeAfter(BBKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, BasicBlock* jumpDest = nullptr, bool updateSideEffects = false); - BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind, + BasicBlock* fgNewBBinRegion(BBKinds jumpKind, unsigned tryIndex, unsigned hndIndex, BasicBlock* nearBlk, @@ -5065,15 +5065,15 @@ class Compiler bool runRarely = false, bool insertAtEnd = false); - BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind, + BasicBlock* fgNewBBinRegion(BBKinds jumpKind, BasicBlock* srcBlk, BasicBlock* jumpDest = nullptr, bool runRarely = false, bool insertAtEnd = false); - BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind, BasicBlock* jumpDest = nullptr); + BasicBlock* fgNewBBinRegion(BBKinds jumpKind, BasicBlock* jumpDest = nullptr); - BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind, + BasicBlock* fgNewBBinRegionWorker(BBKinds jumpKind, BasicBlock* afterBlk, unsigned xcptnIndex, bool putInTryRegion, @@ -6034,7 +6034,7 @@ class Compiler PhaseStatus fgDetermineFirstColdBlock(); - bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr); + bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bDest, BasicBlock* bSrc = nullptr); bool fgUpdateFlowGraph(bool doTailDup = false, bool isPhase = false); PhaseStatus fgUpdateFlowGraphPhase(); @@ -7182,7 +7182,7 @@ class Compiler // Adds "elemType" to the set of modified array element types of "loop" and any parent loops. void AddModifiedElemTypeAllContainingLoops(FlowGraphNaturalLoop* loop, CORINFO_CLASS_HANDLE elemType); - // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone + // Requires that "from" and "to" have the same "bbKind" (perhaps because "to" is a clone // of "from".) Copies the jump destination from "from" to "to". void optCopyBlkDest(BasicBlock* from, BasicBlock* to); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index a725ca79b899b..9bbc4e3fe02b5 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -537,7 +537,7 @@ static BasicBlockVisit VisitEHSuccs(Compiler* comp, BasicBlock* block, TFunc fun { // For BBJ_CALLFINALLY the user may already have processed one of // the EH successors as a regular successor; skip it if requested. - if (!skipJumpDest || !block->HasJumpTo(eh->ebdHndBeg)) + if (!skipJumpDest || !block->TargetIs(eh->ebdHndBeg)) { RETURN_ON_ABORT(func(eh->ebdHndBeg)); } @@ -588,33 +588,33 @@ BasicBlockVisit BasicBlock::VisitEHSuccs(Compiler* comp, TFunc func) template BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func) { - switch (bbJumpKind) + switch (bbKind) { case BBJ_EHFINALLYRET: // This can run before import, in which case we haven't converted // LEAVE into callfinally yet, and haven't added return successors. - if (bbJumpEhf != nullptr) + if (bbEhfTargets != nullptr) { - for (unsigned i = 0; i < bbJumpEhf->bbeCount; i++) + for (unsigned i = 0; i < bbEhfTargets->bbeCount; i++) { - RETURN_ON_ABORT(func(bbJumpEhf->bbeSuccs[i])); + RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i])); } } return VisitEHSuccs(comp, func); case BBJ_CALLFINALLY: - RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(func(bbTarget)); return ::VisitEHSuccs(comp, this, func); case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: case BBJ_LEAVE: - RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(func(bbTarget)); return VisitEHSuccs(comp, func); case BBJ_ALWAYS: - RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(func(bbTarget)); // If this is a "leave helper" block (the empty BBJ_ALWAYS block // that pairs with a preceding BBJ_CALLFINALLY block to implement a @@ -628,11 +628,11 @@ BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func) return BasicBlockVisit::Continue; case BBJ_COND: - RETURN_ON_ABORT(func(bbNext)); + RETURN_ON_ABORT(func(bbFalseTarget)); - if (bbJumpDest != bbNext) + if (bbTrueTarget != bbFalseTarget) { - RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(func(bbTrueTarget)); } return VisitEHSuccs(comp, func); @@ -671,16 +671,16 @@ BasicBlockVisit BasicBlock::VisitAllSuccs(Compiler* comp, TFunc func) template BasicBlockVisit BasicBlock::VisitRegularSuccs(Compiler* comp, TFunc func) { - switch (bbJumpKind) + switch (bbKind) { case BBJ_EHFINALLYRET: // This can run before import, in which case we haven't converted // LEAVE into callfinally yet, and haven't added return successors. - if (bbJumpEhf != nullptr) + if (bbEhfTargets != nullptr) { - for (unsigned i = 0; i < bbJumpEhf->bbeCount; i++) + for (unsigned i = 0; i < bbEhfTargets->bbeCount; i++) { - RETURN_ON_ABORT(func(bbJumpEhf->bbeSuccs[i])); + RETURN_ON_ABORT(func(bbEhfTargets->bbeSuccs[i])); } } @@ -691,14 +691,14 @@ BasicBlockVisit BasicBlock::VisitRegularSuccs(Compiler* comp, TFunc func) case BBJ_EHFILTERRET: case BBJ_LEAVE: case BBJ_ALWAYS: - return func(bbJumpDest); + return func(bbTarget); case BBJ_COND: - RETURN_ON_ABORT(func(bbNext)); + RETURN_ON_ABORT(func(bbFalseTarget)); - if (bbJumpDest != bbNext) + if (bbTrueTarget != bbFalseTarget) { - RETURN_ON_ABORT(func(bbJumpDest)); + RETURN_ON_ABORT(func(bbTrueTarget)); } return BasicBlockVisit::Continue; diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 0091dcf39f8b4..a3ad1cd3c0609 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -5987,7 +5987,7 @@ void emitter::emitSetLoopBackEdge(BasicBlock* loopTopBlock) // With (dstIG != nullptr), ensure that only back edges are tracked. // If there is forward jump, dstIG is not yet generated. // - // We don't rely on (block->GetJumpDest()->bbNum <= block->bbNum) because the basic + // We don't rely on (block->GetTarget()->bbNum <= block->bbNum) because the basic // block numbering is not guaranteed to be sequential. if ((dstIG != nullptr) && (dstIG->igNum <= emitCurIG->igNum)) { diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index d701a9b4b4bec..db2d257ae6de7 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -362,7 +362,7 @@ void Compiler::fgConvertBBToThrowBB(BasicBlock* block) fgRemoveBlockAsPred(block); // Update jump kind after the scrub. - block->SetJumpKindAndTarget(BBJ_THROW); + block->SetKindAndTarget(BBJ_THROW); // Any block with a throw is rare block->bbSetRunRarely(); @@ -370,7 +370,7 @@ void Compiler::fgConvertBBToThrowBB(BasicBlock* block) // If we've converted a BBJ_CALLFINALLY block to a BBJ_THROW block, // then mark the subsequent BBJ_ALWAYS block as unreferenced. // - // Must do this after we update bbJumpKind of block. + // Must do this after we update bbKind of block. if (isCallAlwaysPair) { BasicBlock* leaveBlk = block->Next(); @@ -467,8 +467,8 @@ void Compiler::fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* ne // For the jump targets values that match oldTarget of our BBJ_SWITCH // replace predecessor 'blockSwitch' with 'newTarget' - unsigned jumpCnt = blockSwitch->GetJumpSwt()->bbsCount; - BasicBlock** jumpTab = blockSwitch->GetJumpSwt()->bbsDstTab; + unsigned jumpCnt = blockSwitch->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTab = blockSwitch->GetSwitchTargets()->bbsDstTab; unsigned i = 0; @@ -568,7 +568,7 @@ void Compiler::fgReplaceEhfSuccessor(BasicBlock* block, BasicBlock* oldSucc, Bas assert(block->KindIs(BBJ_EHFINALLYRET)); assert(fgPredsComputed); - BBehfDesc* const ehfDesc = block->GetJumpEhf(); + BBehfDesc* const ehfDesc = block->GetEhfTargets(); const unsigned succCount = ehfDesc->bbeCount; BasicBlock** const succTab = ehfDesc->bbeSuccs; @@ -627,7 +627,7 @@ void Compiler::fgRemoveEhfSuccessor(BasicBlock* block, BasicBlock* succ) fgRemoveRefPred(succ, block); - BBehfDesc* const ehfDesc = block->GetJumpEhf(); + BBehfDesc* const ehfDesc = block->GetEhfTargets(); unsigned succCount = ehfDesc->bbeCount; BasicBlock** succTab = ehfDesc->bbeSuccs; bool found = false; @@ -685,18 +685,28 @@ void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, Bas assert(block != nullptr); assert(fgPredsComputed); - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_CALLFINALLY: - case BBJ_COND: case BBJ_ALWAYS: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: case BBJ_LEAVE: // This function can be called before import, so we still have BBJ_LEAVE - if (block->HasJumpTo(oldTarget)) + if (block->TargetIs(oldTarget)) { - block->SetJumpDest(newTarget); + block->SetTarget(newTarget); + fgRemoveRefPred(oldTarget, block); + fgAddRefPred(newTarget, block); + } + break; + + case BBJ_COND: + + // Functionally equivalent to above + if (block->TrueTargetIs(oldTarget)) + { + block->SetTrueTarget(newTarget); fgRemoveRefPred(oldTarget, block); fgAddRefPred(newTarget, block); } @@ -704,8 +714,8 @@ void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, Bas case BBJ_SWITCH: { - unsigned const jumpCnt = block->GetJumpSwt()->bbsCount; - BasicBlock** const jumpTab = block->GetJumpSwt()->bbsDstTab; + unsigned const jumpCnt = block->GetSwitchTargets()->bbsCount; + BasicBlock** const jumpTab = block->GetSwitchTargets()->bbsDstTab; bool changed = false; for (unsigned i = 0; i < jumpCnt; i++) @@ -2926,43 +2936,46 @@ void Compiler::fgLinkBasicBlocks() for (BasicBlock* const curBBdesc : Blocks()) { - switch (curBBdesc->GetJumpKind()) + switch (curBBdesc->GetKind()) { case BBJ_COND: + { + BasicBlock* const trueTarget = fgLookupBB(curBBdesc->GetTargetOffs()); + curBBdesc->SetTrueTarget(trueTarget); + curBBdesc->SetFalseTarget(curBBdesc->Next()); + fgAddRefPred(trueTarget, curBBdesc, oldEdge); + fgAddRefPred(curBBdesc->GetFalseTarget(), curBBdesc, oldEdge); + + if (curBBdesc->GetTrueTarget()->bbNum <= curBBdesc->bbNum) + { + fgMarkBackwardJump(curBBdesc->GetTrueTarget(), curBBdesc); + } + + if (curBBdesc->IsLast()) + { + BADCODE("Fall thru the end of a method"); + } + + break; + } case BBJ_ALWAYS: case BBJ_LEAVE: { // Avoid fgLookupBB overhead for blocks that jump to next block // (curBBdesc cannot be the last block if it jumps to the next block) - const bool jumpsToNext = (curBBdesc->GetJumpOffs() == curBBdesc->bbCodeOffsEnd); + const bool jumpsToNext = (curBBdesc->GetTargetOffs() == curBBdesc->bbCodeOffsEnd); assert(!(curBBdesc->IsLast() && jumpsToNext)); - BasicBlock* const jumpDest = jumpsToNext ? curBBdesc->Next() : fgLookupBB(curBBdesc->GetJumpOffs()); + BasicBlock* const jumpDest = jumpsToNext ? curBBdesc->Next() : fgLookupBB(curBBdesc->GetTargetOffs()); - // Redundantly use SetJumpKindAndTarget() instead of SetJumpDest() just this once, - // so we don't break the HasInitializedJumpDest() invariant of SetJumpDest(). - curBBdesc->SetJumpKindAndTarget(curBBdesc->GetJumpKind(), jumpDest); + // Redundantly use SetKindAndTarget() instead of SetTarget() just this once, + // so we don't break the HasInitializedTarget() invariant of SetTarget(). + curBBdesc->SetKindAndTarget(curBBdesc->GetKind(), jumpDest); fgAddRefPred(jumpDest, curBBdesc, oldEdge); - if (curBBdesc->GetJumpDest()->bbNum <= curBBdesc->bbNum) + if (curBBdesc->GetTarget()->bbNum <= curBBdesc->bbNum) { - fgMarkBackwardJump(curBBdesc->GetJumpDest(), curBBdesc); + fgMarkBackwardJump(curBBdesc->GetTarget(), curBBdesc); } - - // Can this block fall through into the next block? - // - if (curBBdesc->KindIs(BBJ_ALWAYS, BBJ_LEAVE)) - { - break; - } - - if (curBBdesc->IsLast()) - { - BADCODE("Fall thru the end of a method"); - } - - // The fall-through block is also reachable - assert(curBBdesc->KindIs(BBJ_COND)); - fgAddRefPred(curBBdesc->Next(), curBBdesc, oldEdge); break; } @@ -2983,8 +2996,8 @@ void Compiler::fgLinkBasicBlocks() case BBJ_SWITCH: { - unsigned jumpCnt = curBBdesc->GetJumpSwt()->bbsCount; - BasicBlock** jumpPtr = curBBdesc->GetJumpSwt()->bbsDstTab; + unsigned jumpCnt = curBBdesc->GetSwitchTargets()->bbsCount; + BasicBlock** jumpPtr = curBBdesc->GetSwitchTargets()->bbsDstTab; do { @@ -3006,7 +3019,7 @@ void Compiler::fgLinkBasicBlocks() case BBJ_CALLFINALLY: // BBJ_CALLFINALLY and BBJ_EHCATCHRET don't appear until later case BBJ_EHCATCHRET: default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } } @@ -3075,7 +3088,7 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F unsigned nxtBBoffs; OPCODE opcode = (OPCODE)getU1LittleEndian(codeAddr); codeAddr += sizeof(__int8); - BBjumpKinds jmpKind = BBJ_COUNT; + BBKinds jmpKind = BBJ_COUNT; DECODE_OPCODE: @@ -3532,7 +3545,7 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F noway_assert(codeAddr == codeEndp); - /* Finally link up the bbJumpDest of the blocks together */ + /* Finally link up the bbTarget of the blocks together */ fgLinkBasicBlocks(); @@ -3858,9 +3871,9 @@ void Compiler::fgFindBasicBlocks() if (block->KindIs(BBJ_EHFILTERRET)) { // Mark catch handler as successor. - block->SetJumpDest(hndBegBB); + block->SetTarget(hndBegBB); fgAddRefPred(hndBegBB, block); - assert(block->GetJumpDest()->bbCatchTyp == BBCT_FILTER_HANDLER); + assert(block->GetTarget()->bbCatchTyp == BBCT_FILTER_HANDLER); break; } } @@ -3984,7 +3997,7 @@ void Compiler::fgFindBasicBlocks() // BBJ_EHFINALLYRET that were imported to BBJ_EHFAULTRET. if ((hndBegBB->bbCatchTyp == BBCT_FAULT) && block->KindIs(BBJ_EHFINALLYRET)) { - block->SetJumpKind(BBJ_EHFAULTRET); + block->SetKind(BBJ_EHFAULTRET); } } @@ -4192,8 +4205,8 @@ void Compiler::fgFixEntryFlowForOSR() // fgEnsureFirstBBisScratch(); assert(fgFirstBB->KindIs(BBJ_ALWAYS) && fgFirstBB->JumpsToNext()); - fgRemoveRefPred(fgFirstBB->GetJumpDest(), fgFirstBB); - fgFirstBB->SetJumpKindAndTarget(BBJ_ALWAYS, fgOSREntryBB); + fgRemoveRefPred(fgFirstBB->GetTarget(), fgFirstBB); + fgFirstBB->SetKindAndTarget(BBJ_ALWAYS, fgOSREntryBB); FlowEdge* const edge = fgAddRefPred(fgOSREntryBB, fgFirstBB); edge->setLikelihood(1.0); @@ -4232,19 +4245,19 @@ void Compiler::fgCheckBasicBlockControlFlow() continue; } - switch (blk->GetJumpKind()) + switch (blk->GetKind()) { case BBJ_ALWAYS: // block does unconditional jump to target - fgControlFlowPermitted(blk, blk->GetJumpDest()); + fgControlFlowPermitted(blk, blk->GetTarget()); break; case BBJ_COND: // block conditionally jumps to the target - fgControlFlowPermitted(blk, blk->Next()); + fgControlFlowPermitted(blk, blk->GetFalseTarget()); - fgControlFlowPermitted(blk, blk->GetJumpDest()); + fgControlFlowPermitted(blk, blk->GetTrueTarget()); break; @@ -4308,7 +4321,7 @@ void Compiler::fgCheckBasicBlockControlFlow() case BBJ_LEAVE: // block always jumps to the target, maybe out of guarded // region. Used temporarily until importing - fgControlFlowPermitted(blk, blk->GetJumpDest(), true); + fgControlFlowPermitted(blk, blk->GetTarget(), true); break; @@ -4322,7 +4335,7 @@ void Compiler::fgCheckBasicBlockControlFlow() case BBJ_EHCATCHRET: // block ends with a leave out of a catch (only #if defined(FEATURE_EH_FUNCLETS)) case BBJ_CALLFINALLY: // block always calls the target finally default: - noway_assert(!"Unexpected bbJumpKind"); // these blocks don't get created until importing + noway_assert(!"Unexpected bbKind"); // these blocks don't get created until importing break; } } @@ -4734,12 +4747,35 @@ BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr) // For each successor of the original block, set the new block as their predecessor. // Note we are using the "rational" version of the successor iterator that does not hide the finallyret arcs. // Without these arcs, a block 'b' may not be a member of succs(preds(b)) - if (!curr->KindIs(BBJ_SWITCH)) + switch (curr->GetKind()) { - // Start the new block with no refs. When we set the preds below, this will get updated correctly. - newBlock = BasicBlock::New(this, curr->GetJumpKind(), curr->GetJumpDest()); - newBlock->bbRefs = 0; + case BBJ_COND: + newBlock = BasicBlock::New(this, BBJ_COND, curr->GetTrueTarget()); + break; + + case BBJ_EHFINALLYRET: + newBlock = BasicBlock::New(this, curr->GetEhfTargets()); + break; + + case BBJ_SWITCH: + newBlock = BasicBlock::New(this, curr->GetSwitchTargets()); + break; + + default: + newBlock = BasicBlock::New(this, curr->GetKind(), curr->GetTarget()); + } + + // Start the new block with no refs. When we set the preds below, this will get updated correctly. + newBlock->bbRefs = 0; + if (curr->KindIs(BBJ_SWITCH)) + { + // In the case of a switch statement there's more complicated logic in order to wire up the predecessor lists + // but fortunately there's an existing method that implements this functionality. + fgChangeSwitchBlock(curr, newBlock); + } + else + { for (BasicBlock* const succ : curr->Succs(this)) { if (succ != newBlock) @@ -4750,16 +4786,6 @@ BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr) } } } - else - { - // Start the new block with no refs. When we set the preds below, this will get updated correctly. - newBlock = BasicBlock::New(this, curr->GetJumpSwt()); - newBlock->bbRefs = 0; - - // In the case of a switch statement there's more complicated logic in order to wire up the predecessor lists - // but fortunately there's an existing method that implements this functionality. - fgChangeSwitchBlock(curr, newBlock); - } newBlock->inheritWeight(curr); @@ -4791,7 +4817,7 @@ BasicBlock* Compiler::fgSplitBlockAtEnd(BasicBlock* curr) // Default to fallthru, and add the arc for that. curr->SetFlags(BBF_NONE_QUIRK); - curr->SetJumpKindAndTarget(BBJ_ALWAYS, newBlock); + curr->SetKindAndTarget(BBJ_ALWAYS, newBlock); fgAddRefPred(newBlock, curr); assert(curr->JumpsToNext()); @@ -5011,7 +5037,7 @@ BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr) // Returns a new block, that is a successor of 'curr' and which branches unconditionally to 'succ' // // Assumptions: -// 'curr' must have a bbJumpKind of BBJ_COND, BBJ_ALWAYS, or BBJ_SWITCH +// 'curr' must have a bbKind of BBJ_COND, BBJ_ALWAYS, or BBJ_SWITCH // // Notes: // The returned block is empty. @@ -5030,6 +5056,7 @@ BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ) // an immediately following block of a BBJ_SWITCH (which has // no fall-through path). For this case, simply insert a new // fall-through block after 'curr'. + // TODO-NoFallThrough: Once bbFalseTarget can diverge from bbNext, this will be unnecessary for BBJ_COND newBlock = fgNewBBafter(BBJ_ALWAYS, curr, true /* extendRegion */, /* jumpDest */ succ); newBlock->SetFlags(BBF_NONE_QUIRK); assert(newBlock->JumpsToNext()); @@ -5047,10 +5074,10 @@ BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ) if (curr->KindIs(BBJ_COND)) { fgReplacePred(succ, curr, newBlock); - if (curr->HasJumpTo(succ)) + if (curr->TrueTargetIs(succ)) { // Now 'curr' jumps to newBlock - curr->SetJumpDest(newBlock); + curr->SetTrueTarget(newBlock); } fgAddRefPred(newBlock, curr); } @@ -5066,7 +5093,7 @@ BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ) { assert(curr->KindIs(BBJ_ALWAYS)); fgReplacePred(succ, curr, newBlock); - curr->SetJumpDest(newBlock); + curr->SetTarget(newBlock); fgAddRefPred(newBlock, curr); } @@ -5289,10 +5316,10 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) noway_assert(block->KindIs(BBJ_ALWAYS)); /* Do not remove a block that jumps to itself - used for while (true){} */ - noway_assert(!block->HasJumpTo(block)); + noway_assert(!block->TargetIs(block)); #endif // DEBUG - BasicBlock* succBlock = block->GetJumpDest(); + BasicBlock* succBlock = block->GetTarget(); bool skipUnmarkLoop = false; @@ -5373,37 +5400,38 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) } /* change all jumps to the removed block */ - switch (predBlock->GetJumpKind()) + switch (predBlock->GetKind()) { default: - noway_assert(!"Unexpected bbJumpKind in fgRemoveBlock()"); + noway_assert(!"Unexpected bbKind in fgRemoveBlock()"); break; case BBJ_COND: /* The links for the direct predecessor case have already been updated above */ - if (!predBlock->HasJumpTo(block)) + if (!predBlock->TrueTargetIs(block)) { break; } - /* Check if both side of the BBJ_COND now jump to the same block */ - if (predBlock->NextIs(succBlock)) + /* Check if both sides of the BBJ_COND now jump to the same block */ + if (predBlock->FalseTargetIs(succBlock)) { - // Make sure we are replacing "block" with "succBlock" in predBlock->bbJumpDest. - noway_assert(predBlock->HasJumpTo(block)); - predBlock->SetJumpDest(succBlock); + // Make sure we are replacing "block" with "succBlock" in predBlock->bbTarget. + noway_assert(predBlock->TrueTargetIs(block)); + predBlock->SetTrueTarget(succBlock); fgRemoveConditionalJump(predBlock); break; } - /* Fall through for the jump case */ - FALLTHROUGH; + noway_assert(predBlock->TrueTargetIs(block)); + predBlock->SetTrueTarget(succBlock); + break; case BBJ_CALLFINALLY: case BBJ_ALWAYS: case BBJ_EHCATCHRET: - noway_assert(predBlock->HasJumpTo(block)); - predBlock->SetJumpDest(succBlock); + noway_assert(predBlock->TargetIs(block)); + predBlock->SetTarget(succBlock); break; case BBJ_EHFINALLYRET: @@ -5425,7 +5453,7 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) if (bPrev != nullptr) { - switch (bPrev->GetJumpKind()) + switch (bPrev->GetKind()) { case BBJ_CALLFINALLY: // If prev is a BBJ_CALLFINALLY it better be marked as RETLESS @@ -5433,8 +5461,8 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) break; case BBJ_COND: - /* Check for branch to next block */ - if (bPrev->JumpsToNext()) + /* Check if both sides of the BBJ_COND now jump to the same block */ + if (bPrev->TrueTargetIs(bPrev->GetFalseTarget())) { fgRemoveConditionalJump(bPrev); } @@ -5472,7 +5500,7 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) if (bSrc->bbFallsThrough() && !bSrc->NextIs(bDst)) { - switch (bSrc->GetJumpKind()) + switch (bSrc->GetKind()) { case BBJ_CALLFINALLY: case BBJ_COND: @@ -5530,15 +5558,15 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) fgReplacePred(bDst, bSrc, jmpBlk); JITDUMP("Added an unconditional jump to " FMT_BB " after block " FMT_BB "\n", - jmpBlk->GetJumpDest()->bbNum, bSrc->bbNum); + jmpBlk->GetTarget()->bbNum, bSrc->bbNum); break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } } - else if (bSrc->KindIs(BBJ_ALWAYS) && !bSrc->HasFlag(BBF_KEEP_BBJ_ALWAYS) && bSrc->HasInitializedJumpDest() && + else if (bSrc->KindIs(BBJ_ALWAYS) && !bSrc->HasFlag(BBF_KEEP_BBJ_ALWAYS) && bSrc->HasInitializedTarget() && bSrc->JumpsToNext()) { bSrc->SetFlags(BBF_NONE_QUIRK); @@ -5657,29 +5685,27 @@ bool Compiler::fgRenumberBlocks() * Optionally bSrc can be supplied to indicate that * bJump must be forward with respect to bSrc */ -bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc /* = NULL */) +bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bDest, BasicBlock* bSrc /* = NULL */) { - bool result = false; + assert((bJump->KindIs(BBJ_ALWAYS) && bJump->TargetIs(bDest)) || + (bJump->KindIs(BBJ_COND) && bJump->TrueTargetIs(bDest))); + + bool result = false; + BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc; - if (bJump->KindIs(BBJ_COND, BBJ_ALWAYS)) + while (true) { - BasicBlock* bDest = bJump->GetJumpDest(); - BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc; + bTemp = bTemp->Next(); - while (true) + if (bTemp == nullptr) { - bTemp = bTemp->Next(); - - if (bTemp == nullptr) - { - break; - } + break; + } - if (bTemp == bDest) - { - result = true; - break; - } + if (bTemp == bDest) + { + result = true; + break; } } @@ -6134,7 +6160,7 @@ bool Compiler::fgMightHaveLoop() * Insert a BasicBlock before the given block. */ -BasicBlock* Compiler::fgNewBBbefore(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBbefore(BBKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest /* = nullptr */) @@ -6176,7 +6202,7 @@ BasicBlock* Compiler::fgNewBBbefore(BBjumpKinds jumpKind, * Insert a BasicBlock after the given block. */ -BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBafter(BBKinds jumpKind, BasicBlock* block, bool extendRegion, BasicBlock* jumpDest /* = nullptr */) @@ -6232,7 +6258,7 @@ BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, // Notes: // The new block will have BBF_INTERNAL flag and EH region will be extended // -BasicBlock* Compiler::fgNewBBFromTreeAfter(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBFromTreeAfter(BBKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, @@ -6312,20 +6338,30 @@ void Compiler::fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk) // bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt) { - // bCur can't be NULL and must be a fall through bbJumpKind + // bCur can't be NULL and must be a fall through bbKind noway_assert(bCur != nullptr); noway_assert(bCur->bbFallsThrough() || (bCur->KindIs(BBJ_ALWAYS) && bCur->JumpsToNext())); noway_assert(bAlt != nullptr); - // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND - if (!bAlt->KindIs(BBJ_ALWAYS, BBJ_COND)) + if (bAlt->KindIs(BBJ_ALWAYS)) { - return false; + // If bAlt doesn't jump to bCur, it can't be a better fall through than bCur + if (!bAlt->TargetIs(bCur)) + { + return false; + } } - - // if bAlt doesn't jump to bCur it can't be a better fall through than bCur - if (!bAlt->HasJumpTo(bCur)) + else if (bAlt->KindIs(BBJ_COND)) + { + // If bAlt doesn't potentially jump to bCur, it can't be a better fall through than bCur + if (!bAlt->TrueTargetIs(bCur)) + { + return false; + } + } + else { + // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND return false; } @@ -6336,6 +6372,8 @@ bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt) } // Currently bNext is the fall through for bCur + // TODO-NoFallThrough: Allow bbFalseTarget to diverge from bbNext for BBJ_COND + assert(!bCur->KindIs(BBJ_COND) || bCur->NextIs(bCur->GetFalseTarget())); BasicBlock* bNext = bCur->Next(); noway_assert(bNext != nullptr); @@ -6745,7 +6783,7 @@ BasicBlock* Compiler::fgFindInsertPoint(unsigned regionIndex, // Return Value: // The new block. -BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBinRegion(BBKinds jumpKind, unsigned tryIndex, unsigned hndIndex, BasicBlock* nearBlk, @@ -6872,8 +6910,8 @@ _FoundAfterBlk:; JITDUMP("fgNewBBinRegion(jumpKind=%s, tryIndex=%u, hndIndex=%u, putInFilter=%s, runRarely=%s, insertAtEnd=%s): " "inserting after " FMT_BB "\n", - BBjumpKindNames[jumpKind], tryIndex, hndIndex, dspBool(putInFilter), dspBool(runRarely), - dspBool(insertAtEnd), afterBlk->bbNum); + bbKindNames[jumpKind], tryIndex, hndIndex, dspBool(putInFilter), dspBool(runRarely), dspBool(insertAtEnd), + afterBlk->bbNum); return fgNewBBinRegionWorker(jumpKind, afterBlk, regionIndex, putInTryRegion, jumpDest); } @@ -6894,7 +6932,7 @@ _FoundAfterBlk:; // Return Value: // The new block. -BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBinRegion(BBKinds jumpKind, BasicBlock* srcBlk, BasicBlock* jumpDest /* = nullptr */, bool runRarely /* = false */, @@ -6930,7 +6968,7 @@ BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind, // Return Value: // The new block. -BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind, BasicBlock* jumpDest /* = nullptr */) +BasicBlock* Compiler::fgNewBBinRegion(BBKinds jumpKind, BasicBlock* jumpDest /* = nullptr */) { return fgNewBBinRegion(jumpKind, 0, 0, nullptr, jumpDest, /* putInFilter */ false, /* runRarely */ false, /* insertAtEnd */ true); @@ -6956,7 +6994,7 @@ BasicBlock* Compiler::fgNewBBinRegion(BBjumpKinds jumpKind, BasicBlock* jumpDest // Return Value: // The new block. -BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, +BasicBlock* Compiler::fgNewBBinRegionWorker(BBKinds jumpKind, BasicBlock* afterBlk, unsigned regionIndex, bool putInTryRegion, diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 89ef663463bb0..edf1c84b5621c 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -95,7 +95,7 @@ void Compiler::fgDebugCheckUpdate() if (block->isEmpty() && !block->HasFlag(BBF_DONT_REMOVE)) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_CALLFINALLY: case BBJ_EHFINALLYRET: @@ -1007,7 +1007,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos) fprintf(fgxFile, "\n bbNum); fprintf(fgxFile, "\n ordinal=\"%d\"", blockOrdinal); - fprintf(fgxFile, "\n jumpKind=\"%s\"", kindImage[block->GetJumpKind()]); + fprintf(fgxFile, "\n jumpKind=\"%s\"", kindImage[block->GetKind()]); if (block->hasTryIndex()) { fprintf(fgxFile, "\n inTry=\"%s\"", "true"); @@ -1130,7 +1130,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos) { fprintf(fgxFile, "\n switchCases=\"%d\"", edge->getDupCount()); } - if (bSource->GetJumpSwt()->getDefault() == bTarget) + if (bSource->GetSwitchTargets()->getDefault() == bTarget) { fprintf(fgxFile, "\n switchDefault=\"true\""); } @@ -1976,34 +1976,34 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * } else { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: - printf("-> " FMT_BB "%*s ( cond )", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s ( cond )", block->GetTrueTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTrueTarget()->bbNum), 2), ""); break; case BBJ_CALLFINALLY: - printf("-> " FMT_BB "%*s (callf )", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s (callf )", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); break; case BBJ_ALWAYS: if (flags & BBF_KEEP_BBJ_ALWAYS) { - printf("-> " FMT_BB "%*s (ALWAYS)", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s (ALWAYS)", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); } else { - printf("-> " FMT_BB "%*s (always)", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s (always)", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); } break; case BBJ_LEAVE: - printf("-> " FMT_BB "%*s (leave )", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s (leave )", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); break; case BBJ_EHFINALLYRET: @@ -2011,7 +2011,7 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * printf("->"); int ehfWidth = 0; - const BBehfDesc* const ehfDesc = block->GetJumpEhf(); + const BBehfDesc* const ehfDesc = block->GetEhfTargets(); if (ehfDesc == nullptr) { printf(" ????"); @@ -2047,13 +2047,13 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * break; case BBJ_EHFILTERRET: - printf("-> " FMT_BB "%*s (fltret)", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s (fltret)", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); break; case BBJ_EHCATCHRET: - printf("-> " FMT_BB "%*s ( cret )", block->GetJumpDest()->bbNum, - maxBlockNumWidth - max(CountDigits(block->GetJumpDest()->bbNum), 2), ""); + printf("-> " FMT_BB "%*s ( cret )", block->GetTarget()->bbNum, + maxBlockNumWidth - max(CountDigits(block->GetTarget()->bbNum), 2), ""); break; case BBJ_THROW: @@ -2072,7 +2072,7 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * { printf("->"); - const BBswtDesc* const jumpSwt = block->GetJumpSwt(); + const BBswtDesc* const jumpSwt = block->GetSwitchTargets(); const unsigned jumpCnt = jumpSwt->bbsCount; BasicBlock** const jumpTab = jumpSwt->bbsDstTab; int switchWidth = 0; @@ -2748,17 +2748,17 @@ bool BBPredsChecker::CheckEhHndDsc(BasicBlock* block, BasicBlock* blockPred, EHb bool BBPredsChecker::CheckJump(BasicBlock* blockPred, BasicBlock* block) { - switch (blockPred->GetJumpKind()) + switch (blockPred->GetKind()) { case BBJ_COND: - assert(blockPred->NextIs(block) || blockPred->HasJumpTo(block)); + assert(blockPred->FalseTargetIs(block) || blockPred->TrueTargetIs(block)); return true; case BBJ_ALWAYS: case BBJ_CALLFINALLY: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: - assert(blockPred->HasJumpTo(block)); + assert(blockPred->TargetIs(block)); return true; case BBJ_EHFINALLYRET: @@ -2792,7 +2792,7 @@ bool BBPredsChecker::CheckJump(BasicBlock* blockPred, BasicBlock* block) break; default: - assert(!"Unexpected bbJumpKind"); + assert(!"Unexpected bbKind"); break; } return false; @@ -2827,7 +2827,7 @@ bool BBPredsChecker::CheckEHFinallyRet(BasicBlock* blockPred, BasicBlock* block) found = false; for (BasicBlock* const bcall : comp->Blocks(firstBlock, lastBlock)) { - if (bcall->KindIs(BBJ_CALLFINALLY) && bcall->HasJumpTo(finBeg) && bcall->NextIs(block)) + if (bcall->KindIs(BBJ_CALLFINALLY) && bcall->TargetIs(finBeg) && bcall->NextIs(block)) { found = true; break; @@ -2845,7 +2845,7 @@ bool BBPredsChecker::CheckEHFinallyRet(BasicBlock* blockPred, BasicBlock* block) for (BasicBlock* const bcall : comp->Blocks(comp->fgFirstFuncletBB)) { - if (bcall->KindIs(BBJ_CALLFINALLY) && bcall->HasJumpTo(finBeg) && bcall->NextIs(block) && + if (bcall->KindIs(BBJ_CALLFINALLY) && bcall->TargetIs(finBeg) && bcall->NextIs(block) && comp->ehCallFinallyInCorrectRegion(bcall, hndIndex)) { found = true; @@ -2957,6 +2957,13 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef maxBBNum = max(maxBBNum, block->bbNum); + // BBJ_COND's normal (false) jump target is expected to be the next block + // TODO-NoFallThrough: Allow bbFalseTarget to diverge from bbNext + if (block->KindIs(BBJ_COND)) + { + assert(block->NextIs(block->GetFalseTarget())); + } + // Check that all the successors have the current traversal stamp. Use the 'Compiler*' version of the // iterator, but not for BBJ_SWITCH: we don't want to end up calling GetDescriptorForSwitch(), which will // dynamically create the unique switch list. @@ -3097,9 +3104,9 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef } // Blocks with these jump kinds must have non-null jump targets - if (block->HasJumpDest()) + if (block->HasTarget()) { - assert(block->HasInitializedJumpDest()); + assert(block->HasInitializedTarget()); } // A branch or fall-through to a BBJ_CALLFINALLY block must come from the `try` region associated @@ -3117,7 +3124,7 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef { if (succBlock->KindIs(BBJ_CALLFINALLY)) { - BasicBlock* finallyBlock = succBlock->GetJumpDest(); + BasicBlock* finallyBlock = succBlock->GetTarget(); assert(finallyBlock->hasHndIndex()); unsigned finallyIndex = finallyBlock->getHndIndex(); @@ -5003,7 +5010,7 @@ void Compiler::fgDebugCheckLoopTable() // The pre-header can only be BBJ_ALWAYS and must enter the loop. BasicBlock* e = loop.lpEntry; assert(h->KindIs(BBJ_ALWAYS)); - assert(h->HasJumpTo(e)); + assert(h->TargetIs(e)); // The entry block has a single non-loop predecessor, and it is the pre-header. for (BasicBlock* const predBlock : e->PredBlocks()) diff --git a/src/coreclr/jit/fgehopt.cpp b/src/coreclr/jit/fgehopt.cpp index 596a36d20f52f..b605c367e541f 100644 --- a/src/coreclr/jit/fgehopt.cpp +++ b/src/coreclr/jit/fgehopt.cpp @@ -100,7 +100,7 @@ PhaseStatus Compiler::fgRemoveEmptyFinally() } // If the finally's block jumps back to itself, then it is not empty. - if (firstBlock->KindIs(BBJ_ALWAYS) && firstBlock->HasJumpTo(firstBlock)) + if (firstBlock->KindIs(BBJ_ALWAYS) && firstBlock->TargetIs(firstBlock)) { JITDUMP("EH#%u finally has basic block that jumps to itself; skipping.\n", XTnum); XTnum++; @@ -145,7 +145,7 @@ PhaseStatus Compiler::fgRemoveEmptyFinally() { BasicBlock* nextBlock = currentBlock->Next(); - if (currentBlock->KindIs(BBJ_CALLFINALLY) && currentBlock->HasJumpTo(firstBlock)) + if (currentBlock->KindIs(BBJ_CALLFINALLY) && currentBlock->TargetIs(firstBlock)) { // Retarget the call finally to jump to the return // point. @@ -155,7 +155,7 @@ PhaseStatus Compiler::fgRemoveEmptyFinally() noway_assert(currentBlock->isBBCallAlwaysPair()); BasicBlock* const leaveBlock = currentBlock->Next(); - BasicBlock* const postTryFinallyBlock = leaveBlock->GetJumpDest(); + BasicBlock* const postTryFinallyBlock = leaveBlock->GetTarget(); JITDUMP("Modifying callfinally " FMT_BB " leave " FMT_BB " finally " FMT_BB " continuation " FMT_BB "\n", @@ -165,7 +165,7 @@ PhaseStatus Compiler::fgRemoveEmptyFinally() noway_assert(leaveBlock->KindIs(BBJ_ALWAYS)); - currentBlock->SetJumpKindAndTarget(BBJ_ALWAYS, postTryFinallyBlock); + currentBlock->SetKindAndTarget(BBJ_ALWAYS, postTryFinallyBlock); // Ref count updates. fgAddRefPred(postTryFinallyBlock, currentBlock); @@ -374,12 +374,12 @@ PhaseStatus Compiler::fgRemoveEmptyTry() continue; } - BasicBlock* const callFinally = firstTryBlock->GetJumpDest(); + BasicBlock* const callFinally = firstTryBlock->GetTarget(); // Look for call always pair. Note this will also disqualify // empty try removal in cases where the finally doesn't // return. - if (!callFinally->isBBCallAlwaysPair() || !callFinally->HasJumpTo(firstHandlerBlock)) + if (!callFinally->isBBCallAlwaysPair() || !callFinally->TargetIs(firstHandlerBlock)) { JITDUMP("EH#%u first try block " FMT_BB " always jumps but not to a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum); @@ -400,7 +400,7 @@ PhaseStatus Compiler::fgRemoveEmptyTry() // Look for call always pair within the try itself. Note this // will also disqualify empty try removal in cases where the // finally doesn't return. - if (!firstTryBlock->isBBCallAlwaysPair() || !firstTryBlock->HasJumpTo(firstHandlerBlock)) + if (!firstTryBlock->isBBCallAlwaysPair() || !firstTryBlock->TargetIs(firstHandlerBlock)) { JITDUMP("EH#%u first try block " FMT_BB " not a callfinally; skipping.\n", XTnum, firstTryBlock->bbNum); XTnum++; @@ -430,7 +430,7 @@ PhaseStatus Compiler::fgRemoveEmptyTry() for (BasicBlock* const block : Blocks(firstCallFinallyRangeBlock, lastCallFinallyRangeBlock)) { - if (block->KindIs(BBJ_CALLFINALLY) && block->HasJumpTo(firstHandlerBlock)) + if (block->KindIs(BBJ_CALLFINALLY) && block->TargetIs(firstHandlerBlock)) { assert(block->isBBCallAlwaysPair()); @@ -454,12 +454,12 @@ PhaseStatus Compiler::fgRemoveEmptyTry() // Time to optimize. // // (1) Convert the callfinally to a normal jump to the handler - assert(callFinally->HasInitializedJumpDest()); - callFinally->SetJumpKind(BBJ_ALWAYS); + assert(callFinally->HasInitializedTarget()); + callFinally->SetKind(BBJ_ALWAYS); // Identify the leave block and the continuation BasicBlock* const leave = callFinally->Next(); - BasicBlock* const continuation = leave->GetJumpDest(); + BasicBlock* const continuation = leave->GetTarget(); // (2) Cleanup the leave so it can be deleted by subsequent opts assert(leave->HasFlag(BBF_KEEP_BBJ_ALWAYS)); @@ -528,7 +528,7 @@ PhaseStatus Compiler::fgRemoveEmptyTry() GenTree* finallyRetExpr = finallyRet->GetRootNode(); assert(finallyRetExpr->gtOper == GT_RETFILT); fgRemoveStmt(block, finallyRet); - block->SetJumpKindAndTarget(BBJ_ALWAYS, continuation); + block->SetKindAndTarget(BBJ_ALWAYS, continuation); fgAddRefPred(continuation, block); fgRemoveRefPred(leave, block); } @@ -810,7 +810,7 @@ PhaseStatus Compiler::fgCloneFinally() if (block->KindIs(BBJ_ALWAYS)) { - jumpDest = block->GetJumpDest(); + jumpDest = block->GetTarget(); } if (jumpDest == nullptr) @@ -823,7 +823,7 @@ PhaseStatus Compiler::fgCloneFinally() // The jumpDest must be a callfinally that in turn invokes the // finally of interest. - if (!jumpDest->isBBCallAlwaysPair() || !jumpDest->HasJumpTo(firstBlock)) + if (!jumpDest->isBBCallAlwaysPair() || !jumpDest->TargetIs(firstBlock)) { continue; } @@ -831,7 +831,7 @@ PhaseStatus Compiler::fgCloneFinally() // Found a block that invokes the finally. // BasicBlock* const finallyReturnBlock = jumpDest->Next(); - BasicBlock* const postTryFinallyBlock = finallyReturnBlock->GetJumpDest(); + BasicBlock* const postTryFinallyBlock = finallyReturnBlock->GetTarget(); bool isUpdate = false; // See if this is the one we want to use to inspire cloning. @@ -945,7 +945,7 @@ PhaseStatus Compiler::fgCloneFinally() for (BasicBlock* const block : Blocks(firstCallFinallyRangeBlock, lastCallFinallyRangeBlock)) { - if (block->isBBCallAlwaysPair() && block->HasJumpTo(firstBlock)) + if (block->isBBCallAlwaysPair() && block->TargetIs(firstBlock)) { firstCallFinallyBlock = block; break; @@ -962,7 +962,7 @@ PhaseStatus Compiler::fgCloneFinally() { BasicBlock* const placeToMoveAfter = firstCallFinallyBlock->Prev(); - if (placeToMoveAfter->KindIs(BBJ_ALWAYS) && placeToMoveAfter->HasJumpTo(normalCallFinallyBlock)) + if (placeToMoveAfter->KindIs(BBJ_ALWAYS) && placeToMoveAfter->TargetIs(normalCallFinallyBlock)) { JITDUMP("Moving callfinally " FMT_BB " to be first in line, before " FMT_BB "\n", normalCallFinallyBlock->bbNum, firstCallFinallyBlock->bbNum); @@ -1078,7 +1078,7 @@ PhaseStatus Compiler::fgCloneFinally() // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them. assert(newBlock->KindIs(BBJ_ALWAYS)); - assert(!newBlock->HasInitializedJumpDest()); + assert(!newBlock->HasInitializedTarget()); } if (!clonedOk) @@ -1102,7 +1102,7 @@ PhaseStatus Compiler::fgCloneFinally() BasicBlock* newBlock = blockMap[block]; // Jump kind/target should not be set yet assert(newBlock->KindIs(BBJ_ALWAYS)); - assert(!newBlock->HasInitializedJumpDest()); + assert(!newBlock->HasInitializedTarget()); if (block->KindIs(BBJ_EHFINALLYRET)) { @@ -1110,7 +1110,7 @@ PhaseStatus Compiler::fgCloneFinally() GenTree* finallyRetExpr = finallyRet->GetRootNode(); assert(finallyRetExpr->gtOper == GT_RETFILT); fgRemoveStmt(newBlock, finallyRet); - newBlock->SetJumpKindAndTarget(BBJ_ALWAYS, normalCallFinallyReturn); + newBlock->SetKindAndTarget(BBJ_ALWAYS, normalCallFinallyReturn); fgAddRefPred(normalCallFinallyReturn, newBlock); } @@ -1134,10 +1134,10 @@ PhaseStatus Compiler::fgCloneFinally() { BasicBlock* nextBlockToScan = currentBlock->Next(); - if (currentBlock->isBBCallAlwaysPair() && currentBlock->HasJumpTo(firstBlock)) + if (currentBlock->isBBCallAlwaysPair() && currentBlock->TargetIs(firstBlock)) { BasicBlock* const leaveBlock = currentBlock->Next(); - BasicBlock* const postTryFinallyBlock = leaveBlock->GetJumpDest(); + BasicBlock* const postTryFinallyBlock = leaveBlock->GetTarget(); // Note we must retarget all callfinallies that have this // continuation, or we can't clean up the continuation @@ -1150,7 +1150,7 @@ PhaseStatus Compiler::fgCloneFinally() // This call returns to the expected spot, so // retarget it to branch to the clone. - currentBlock->SetJumpKindAndTarget(BBJ_ALWAYS, firstCloneBlock); + currentBlock->SetKindAndTarget(BBJ_ALWAYS, firstCloneBlock); // Ref count updates. fgAddRefPred(firstCloneBlock, currentBlock); @@ -1209,8 +1209,8 @@ PhaseStatus Compiler::fgCloneFinally() { if (block->KindIs(BBJ_EHFINALLYRET)) { - assert(block->GetJumpEhf()->bbeCount == 0); - block->SetJumpKind(BBJ_EHFAULTRET); + assert(block->GetEhfTargets()->bbeCount == 0); + block->SetKind(BBJ_EHFAULTRET); } } } @@ -1403,13 +1403,13 @@ void Compiler::fgDebugCheckTryFinallyExits() if (succBlock->KindIs(BBJ_CALLFINALLY)) { // case (a1) - isCallToFinally = isFinally && succBlock->HasJumpTo(finallyBlock); + isCallToFinally = isFinally && succBlock->TargetIs(finallyBlock); } #else if (block->KindIs(BBJ_CALLFINALLY)) { // case (a2) - isCallToFinally = isFinally && block->HasJumpTo(finallyBlock); + isCallToFinally = isFinally && block->TargetIs(finallyBlock); } #endif // FEATURE_EH_CALLFINALLY_THUNKS @@ -1425,7 +1425,7 @@ void Compiler::fgDebugCheckTryFinallyExits() if (succBlock->isEmpty()) { // case (c) - BasicBlock* const succSuccBlock = succBlock->GetJumpDest(); + BasicBlock* const succSuccBlock = succBlock->GetTarget(); if (succSuccBlock->HasFlag(BBF_CLONED_FINALLY_BEGIN)) { @@ -1645,7 +1645,7 @@ PhaseStatus Compiler::fgMergeFinallyChains() for (BasicBlock* const currentBlock : Blocks(firstCallFinallyRangeBlock, lastCallFinallyRangeBlock)) { // Ignore "retless" callfinallys (where the finally doesn't return). - if (currentBlock->isBBCallAlwaysPair() && currentBlock->HasJumpTo(beginHandlerBlock)) + if (currentBlock->isBBCallAlwaysPair() && currentBlock->TargetIs(beginHandlerBlock)) { // The callfinally must be empty, so that we can // safely retarget anything that branches here to @@ -1657,7 +1657,7 @@ PhaseStatus Compiler::fgMergeFinallyChains() // Locate the continuation BasicBlock* const leaveBlock = currentBlock->Next(); - BasicBlock* const continuationBlock = leaveBlock->GetJumpDest(); + BasicBlock* const continuationBlock = leaveBlock->GetTarget(); // If this is the first time we've seen this // continuation, register this callfinally as the @@ -1759,14 +1759,14 @@ bool Compiler::fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block, // Screen out cases that are not callfinallys to the right // handler. - BasicBlock* const callFinally = block->GetJumpDest(); + BasicBlock* const callFinally = block->GetTarget(); if (!callFinally->isBBCallAlwaysPair()) { return false; } - if (!callFinally->HasJumpTo(handler)) + if (!callFinally->TargetIs(handler)) { return false; } @@ -1774,14 +1774,14 @@ bool Compiler::fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block, // Ok, this is a callfinally that invokes the right handler. // Get its continuation. BasicBlock* const leaveBlock = callFinally->Next(); - BasicBlock* const continuationBlock = leaveBlock->GetJumpDest(); + BasicBlock* const continuationBlock = leaveBlock->GetTarget(); // Find the canonical callfinally for that continuation. BasicBlock* const canonicalCallFinally = continuationMap[continuationBlock]; assert(canonicalCallFinally != nullptr); // If the block already jumps to the canonical call finally, no work needed. - if (block->HasJumpTo(canonicalCallFinally)) + if (block->TargetIs(canonicalCallFinally)) { JITDUMP(FMT_BB " already canonical\n", block->bbNum); return false; @@ -1791,7 +1791,7 @@ bool Compiler::fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block, JITDUMP("Redirecting branch in " FMT_BB " from " FMT_BB " to " FMT_BB ".\n", block->bbNum, callFinally->bbNum, canonicalCallFinally->bbNum); - block->SetJumpDest(canonicalCallFinally); + block->SetTarget(canonicalCallFinally); fgAddRefPred(canonicalCallFinally, block); assert(callFinally->bbRefs > 0); fgRemoveRefPred(callFinally, block); @@ -2046,7 +2046,7 @@ PhaseStatus Compiler::fgTailMergeThrows() BasicBlock* const predBlock = predEdge->getSourceBlock(); nextPredEdge = predEdge->getNextPredEdge(); - switch (predBlock->GetJumpKind()) + switch (predBlock->GetKind()) { case BBJ_ALWAYS: { @@ -2058,12 +2058,12 @@ PhaseStatus Compiler::fgTailMergeThrows() case BBJ_COND: { // Flow to non canonical block could be via fall through or jump or both. - if (predBlock->NextIs(nonCanonicalBlock)) + if (predBlock->FalseTargetIs(nonCanonicalBlock)) { fgTailMergeThrowsFallThroughHelper(predBlock, nonCanonicalBlock, canonicalBlock, predEdge); } - if (predBlock->HasJumpTo(nonCanonicalBlock)) + if (predBlock->TrueTargetIs(nonCanonicalBlock)) { fgTailMergeThrowsJumpToHelper(predBlock, nonCanonicalBlock, canonicalBlock, predEdge); } @@ -2134,7 +2134,8 @@ void Compiler::fgTailMergeThrowsFallThroughHelper(BasicBlock* predBlock, BasicBlock* canonicalBlock, FlowEdge* predEdge) { - assert(predBlock->NextIs(nonCanonicalBlock)); + assert(predBlock->KindIs(BBJ_COND)); + assert(predBlock->FalseTargetIs(nonCanonicalBlock)); BasicBlock* const newBlock = fgNewBBafter(BBJ_ALWAYS, predBlock, true, canonicalBlock); @@ -2175,14 +2176,23 @@ void Compiler::fgTailMergeThrowsJumpToHelper(BasicBlock* predBlock, BasicBlock* canonicalBlock, FlowEdge* predEdge) { - assert(predBlock->HasJumpTo(nonCanonicalBlock)); - JITDUMP("*** " FMT_BB " now branching to " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum); // Remove the old flow fgRemoveRefPred(nonCanonicalBlock, predBlock); // Wire up the new flow - predBlock->SetJumpDest(canonicalBlock); + if (predBlock->KindIs(BBJ_ALWAYS)) + { + assert(predBlock->TargetIs(nonCanonicalBlock)); + predBlock->SetTarget(canonicalBlock); + } + else + { + assert(predBlock->KindIs(BBJ_COND)); + assert(predBlock->TrueTargetIs(nonCanonicalBlock)); + predBlock->SetTrueTarget(canonicalBlock); + } + fgAddRefPred(canonicalBlock, predBlock, predEdge); } diff --git a/src/coreclr/jit/fgflow.cpp b/src/coreclr/jit/fgflow.cpp index 5368bb881d961..6f602c415d8d9 100644 --- a/src/coreclr/jit/fgflow.cpp +++ b/src/coreclr/jit/fgflow.cpp @@ -346,18 +346,18 @@ void Compiler::fgRemoveBlockAsPred(BasicBlock* block) { PREFIX_ASSUME(block != nullptr); - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_CALLFINALLY: case BBJ_ALWAYS: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: - fgRemoveRefPred(block->GetJumpDest(), block); + fgRemoveRefPred(block->GetTarget(), block); break; case BBJ_COND: - fgRemoveRefPred(block->GetJumpDest(), block); - fgRemoveRefPred(block->Next(), block); + fgRemoveRefPred(block->GetTrueTarget(), block); + fgRemoveRefPred(block->GetFalseTarget(), block); break; case BBJ_EHFINALLYRET: @@ -380,7 +380,7 @@ void Compiler::fgRemoveBlockAsPred(BasicBlock* block) break; default: - noway_assert(!"Block doesn't have a valid bbJumpKind!!!!"); + noway_assert(!"Block doesn't have a valid bbKind!!!!"); break; } } diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index b318b1469f636..4a4093492179d 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -675,14 +675,14 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorIsIntegralConst(0)) { - m_compiler->fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKindAndTarget(BBJ_ALWAYS, block->Next()); + m_compiler->fgRemoveRefPred(block->GetTrueTarget(), block); + block->SetKindAndTarget(BBJ_ALWAYS, block->Next()); block->SetFlags(BBF_NONE_QUIRK); } else { - block->SetJumpKind(BBJ_ALWAYS); - m_compiler->fgRemoveRefPred(block->Next(), block); + m_compiler->fgRemoveRefPred(block->GetFalseTarget(), block); + block->SetKind(BBJ_ALWAYS); } } } @@ -1530,10 +1530,10 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo) if (block->KindIs(BBJ_RETURN)) { noway_assert(!block->HasFlag(BBF_HAS_JMP)); - JITDUMP("\nConvert bbJumpKind of " FMT_BB " to BBJ_ALWAYS to bottomBlock " FMT_BB "\n", block->bbNum, + JITDUMP("\nConvert bbKind of " FMT_BB " to BBJ_ALWAYS to bottomBlock " FMT_BB "\n", block->bbNum, bottomBlock->bbNum); - block->SetJumpKindAndTarget(BBJ_ALWAYS, bottomBlock); + block->SetKindAndTarget(BBJ_ALWAYS, bottomBlock); fgAddRefPred(bottomBlock, block); if (block == InlineeCompiler->fgLastBB) @@ -1549,9 +1549,9 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo) // Insert inlinee's blocks into inliner's block list. assert(topBlock->KindIs(BBJ_ALWAYS)); - assert(topBlock->HasJumpTo(bottomBlock)); + assert(topBlock->TargetIs(bottomBlock)); topBlock->SetNext(InlineeCompiler->fgFirstBB); - topBlock->SetJumpDest(topBlock->Next()); + topBlock->SetTarget(topBlock->Next()); topBlock->SetFlags(BBF_NONE_QUIRK); fgRemoveRefPred(bottomBlock, topBlock); fgAddRefPred(InlineeCompiler->fgFirstBB, topBlock); diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 6198601061525..fa77fabb87559 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -136,11 +136,11 @@ bool Compiler::fgReachable(BasicBlock* b1, BasicBlock* b2) if (b1->KindIs(BBJ_COND)) { - return fgReachable(b1->Next(), b2) || fgReachable(b1->GetJumpDest(), b2); + return fgReachable(b1->GetFalseTarget(), b2) || fgReachable(b1->GetTrueTarget(), b2); } else { - return fgReachable(b1->GetJumpDest(), b2); + return fgReachable(b1->GetTarget(), b2); } } @@ -449,7 +449,7 @@ bool Compiler::fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock) block->RemoveFlags(BBF_REMOVED | BBF_INTERNAL); block->SetFlags(BBF_IMPORTED); - block->SetJumpKindAndTarget(BBJ_THROW); + block->SetKindAndTarget(BBJ_THROW); block->bbSetRunRarely(); } else @@ -470,7 +470,7 @@ bool Compiler::fgRemoveUnreachableBlocks(CanRemoveBlockBody canRemoveBlock) // change the kind to something else. Otherwise, we can hit asserts below in fgRemoveBlock that // the leaveBlk BBJ_ALWAYS is not allowed to be a CallAlwaysPairTail. assert(block->KindIs(BBJ_CALLFINALLY)); - block->SetJumpKindAndTarget(BBJ_ALWAYS, block->Next()); + block->SetKindAndTarget(BBJ_ALWAYS, block->Next()); } leaveBlk->RemoveFlags(BBF_DONT_REMOVE); @@ -1622,7 +1622,7 @@ PhaseStatus Compiler::fgPostImportationCleanup() // plausible flow target. Simplest is to just mark it as a throw. if (bbIsHandlerBeg(newTryEntry->Next())) { - newTryEntry->SetJumpKindAndTarget(BBJ_THROW); + newTryEntry->SetKindAndTarget(BBJ_THROW); } else { @@ -1759,7 +1759,7 @@ PhaseStatus Compiler::fgPostImportationCleanup() GenTree* const jumpIfEntryStateZero = gtNewOperNode(GT_JTRUE, TYP_VOID, compareEntryStateToZero); fgNewStmtAtBeg(fromBlock, jumpIfEntryStateZero); - fromBlock->SetJumpKindAndTarget(BBJ_COND, toBlock); + fromBlock->SetCond(toBlock); fgAddRefPred(toBlock, fromBlock); newBlock->inheritWeight(fromBlock); @@ -1797,12 +1797,12 @@ PhaseStatus Compiler::fgPostImportationCleanup() // Note even if the OSR is in a nested try, if it's a mutual protect try // it can be reached directly from "outside". // - assert(fgFirstBB->HasJumpTo(osrEntry)); + assert(fgFirstBB->TargetIs(osrEntry)); assert(fgFirstBB->KindIs(BBJ_ALWAYS)); if (entryJumpTarget != osrEntry) { - fgFirstBB->SetJumpDest(entryJumpTarget); + fgFirstBB->SetTarget(entryJumpTarget); fgRemoveRefPred(osrEntry, fgFirstBB); fgAddRefPred(entryJumpTarget, fgFirstBB); @@ -1889,7 +1889,7 @@ bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext) assert(block->NextIs(bNext)); - if (!block->KindIs(BBJ_ALWAYS) || !block->HasJumpTo(bNext) || block->HasFlag(BBF_KEEP_BBJ_ALWAYS)) + if (!block->KindIs(BBJ_ALWAYS) || !block->TargetIs(bNext) || block->HasFlag(BBF_KEEP_BBJ_ALWAYS)) { return false; } @@ -1998,7 +1998,7 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext) noway_assert(bNext->bbPreds != nullptr); assert(block->KindIs(BBJ_ALWAYS)); - assert(block->HasJumpTo(bNext)); + assert(block->TargetIs(bNext)); assert(!block->isBBCallAlwaysPairTail()); assert(!fgInDifferentRegions(block, bNext)); @@ -2292,7 +2292,7 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext) /* Set the jump targets */ - switch (bNext->GetJumpKind()) + switch (bNext->GetKind()) { case BBJ_CALLFINALLY: // Propagate RETLESS property @@ -2306,23 +2306,29 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext) FALLTHROUGH; - case BBJ_COND: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: - block->SetJumpKindAndTarget(bNext->GetJumpKind(), bNext->GetJumpDest()); + block->SetKindAndTarget(bNext->GetKind(), bNext->GetTarget()); + + /* Update the predecessor list for 'bNext->bbTarget' */ + fgReplacePred(bNext->GetTarget(), bNext, block); + break; - /* Update the predecessor list for 'bNext->bbJumpDest' */ - fgReplacePred(bNext->GetJumpDest(), bNext, block); + case BBJ_COND: + block->SetCond(bNext->GetTrueTarget()); + + /* Update the predecessor list for 'bNext->bbTarget' */ + fgReplacePred(bNext->GetTrueTarget(), bNext, block); - /* Update the predecessor list for 'bNext->bbNext' if it is different than 'bNext->bbJumpDest' */ - if (bNext->KindIs(BBJ_COND) && !bNext->JumpsToNext()) + /* Update the predecessor list for 'bNext->bbFalseTarget' if it is different than 'bNext->bbTarget' */ + if (!bNext->TrueTargetIs(bNext->GetFalseTarget())) { - fgReplacePred(bNext->Next(), bNext, block); + fgReplacePred(bNext->GetFalseTarget(), bNext, block); } break; case BBJ_EHFINALLYRET: - block->SetJumpKindAndTarget(bNext->GetJumpKind(), bNext->GetJumpEhf()); + block->SetEhf(bNext->GetEhfTargets()); fgChangeEhfBlock(bNext, block); break; @@ -2330,24 +2336,32 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext) case BBJ_THROW: case BBJ_RETURN: /* no jumps or fall through blocks to set here */ - block->SetJumpKind(bNext->GetJumpKind()); + block->SetKind(bNext->GetKind()); break; case BBJ_SWITCH: - block->SetSwitchKindAndTarget(bNext->GetJumpSwt()); + block->SetSwitch(bNext->GetSwitchTargets()); // We are moving the switch jump from bNext to block. Examine the jump targets // of the BBJ_SWITCH at bNext and replace the predecessor to 'bNext' with ones to 'block' fgChangeSwitchBlock(bNext, block); break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } - assert(block->KindIs(bNext->GetJumpKind())); + assert(block->KindIs(bNext->GetKind())); - if (bNext->KindIs(BBJ_COND, BBJ_ALWAYS) && bNext->GetJumpDest()->isLoopAlign()) + if (bNext->KindIs(BBJ_ALWAYS) && bNext->GetTarget()->isLoopAlign()) + { + // `bNext` has a backward target to some block which mean bNext is part of a loop. + // `block` into which `bNext` is compacted should be updated with its loop number + JITDUMP("Updating loop number for " FMT_BB " from " FMT_LP " to " FMT_LP ".\n", block->bbNum, + block->bbNatLoopNum, bNext->bbNatLoopNum); + block->bbNatLoopNum = bNext->bbNatLoopNum; + } + else if (bNext->KindIs(BBJ_COND) && bNext->GetTrueTarget()->isLoopAlign()) { // `bNext` has a backward target to some block which mean bNext is part of a loop. // `block` into which `bNext` is compacted should be updated with its loop number @@ -2565,16 +2579,16 @@ void Compiler::fgUnreachableBlock(BasicBlock* block) // void Compiler::fgRemoveConditionalJump(BasicBlock* block) { - noway_assert(block->KindIs(BBJ_COND) && block->JumpsToNext()); + noway_assert(block->KindIs(BBJ_COND) && block->TrueTargetIs(block->GetFalseTarget())); assert(compRationalIRForm == block->IsLIR()); - FlowEdge* flow = fgGetPredForBlock(block->Next(), block); + FlowEdge* flow = fgGetPredForBlock(block->GetFalseTarget(), block); noway_assert(flow->getDupCount() == 2); // Change the BBJ_COND to BBJ_ALWAYS, and adjust the refCount and dupCount. - block->SetJumpKind(BBJ_ALWAYS); + --block->GetFalseTarget()->bbRefs; + block->SetKind(BBJ_ALWAYS); block->SetFlags(BBF_NONE_QUIRK); - --block->Next()->bbRefs; flow->decrementDupCount(); #ifdef DEBUG @@ -2582,7 +2596,7 @@ void Compiler::fgRemoveConditionalJump(BasicBlock* block) { printf("Block " FMT_BB " becoming a BBJ_ALWAYS to " FMT_BB " (jump target is the same whether the condition" " is true or false)\n", - block->bbNum, block->Next()->bbNum); + block->bbNum, block->GetFalseTarget()->bbNum); } #endif @@ -2684,7 +2698,7 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc } // Don't optimize a jump to a removed block - if (bDest->GetJumpDest()->HasFlag(BBF_REMOVED)) + if (bDest->GetTarget()->HasFlag(BBF_REMOVED)) { optimizeJump = false; } @@ -2708,7 +2722,7 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc if (verbose) { printf("\nOptimizing a jump to an unconditional jump (" FMT_BB " -> " FMT_BB " -> " FMT_BB ")\n", - block->bbNum, bDest->bbNum, bDest->GetJumpDest()->bbNum); + block->bbNum, bDest->bbNum, bDest->GetTarget()->bbNum); } #endif // DEBUG @@ -2755,7 +2769,7 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc bDest->SetFlags(BBF_RUN_RARELY); // Set the RarelyRun flag } - FlowEdge* edge2 = fgGetPredForBlock(bDest->GetJumpDest(), bDest); + FlowEdge* edge2 = fgGetPredForBlock(bDest->GetTarget(), bDest); if (edge2 != nullptr) { @@ -2787,9 +2801,21 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc } // Optimize the JUMP to empty unconditional JUMP to go to the new target - block->SetJumpDest(bDest->GetJumpDest()); + switch (block->GetKind()) + { + case BBJ_ALWAYS: + block->SetTarget(bDest->GetTarget()); + break; - fgAddRefPred(bDest->GetJumpDest(), block, fgRemoveRefPred(bDest, block)); + case BBJ_COND: + block->SetTrueTarget(bDest->GetTarget()); + break; + + default: + unreached(); + } + + fgAddRefPred(bDest->GetTarget(), block, fgRemoveRefPred(bDest, block)); return true; } @@ -2812,7 +2838,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) bool madeChanges = false; BasicBlock* bPrev = block->Prev(); - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: case BBJ_SWITCH: @@ -2855,8 +2881,8 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) break; } - // TODO: Once BBJ_COND blocks have pointers to their false branches, - // allow removing empty BBJ_ALWAYS and pointing bPrev's false branch to block->bbJumpDest. + // TODO-NoFallThrough: Once BBJ_COND blocks have pointers to their false branches, + // allow removing empty BBJ_ALWAYS and pointing bPrev's false branch to block->bbTarget. if (bPrev->bbFallsThrough() && !block->JumpsToNext()) { break; @@ -2864,7 +2890,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) } /* Do not remove a block that jumps to itself - used for while (true){} */ - if (block->HasJumpTo(block)) + if (block->TargetIs(block)) { break; } @@ -2897,7 +2923,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) * to ensure we generate code for the block, if we keep it. */ { - BasicBlock* succBlock = block->GetJumpDest(); + BasicBlock* succBlock = block->GetTarget(); if ((succBlock != nullptr) && !BasicBlock::sameEHRegion(block, succBlock)) { @@ -2909,7 +2935,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) { if (predBlock->KindIs(BBJ_EHCATCHRET)) { - assert(predBlock->HasJumpTo(block)); + assert(predBlock->TargetIs(block)); okToMerge = false; // we can't get rid of the empty block break; } @@ -3010,7 +3036,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } @@ -3031,8 +3057,8 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) { assert(block->KindIs(BBJ_SWITCH)); - unsigned jmpCnt = block->GetJumpSwt()->bbsCount; - BasicBlock** jmpTab = block->GetJumpSwt()->bbsDstTab; + unsigned jmpCnt = block->GetSwitchTargets()->bbsCount; + BasicBlock** jmpTab = block->GetSwitchTargets()->bbsDstTab; BasicBlock* bNewDest; // the new jump target for the current switch case BasicBlock* bDest; bool returnvalue = false; @@ -3044,7 +3070,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) bNewDest = bDest; // Do we have a JUMP to an empty unconditional JUMP block? - if (bDest->isEmpty() && bDest->KindIs(BBJ_ALWAYS) && !bDest->HasJumpTo(bDest)) // special case for self jumps + if (bDest->isEmpty() && bDest->KindIs(BBJ_ALWAYS) && !bDest->TargetIs(bDest)) // special case for self jumps { bool optimizeJump = true; @@ -3058,7 +3084,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) if (optimizeJump) { - bNewDest = bDest->GetJumpDest(); + bNewDest = bDest->GetTarget(); #ifdef DEBUG if (verbose) { @@ -3134,8 +3160,8 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) // At this point all of the case jump targets have been updated such // that none of them go to block that is an empty unconditional block // - jmpTab = block->GetJumpSwt()->bbsDstTab; - jmpCnt = block->GetJumpSwt()->bbsCount; + jmpTab = block->GetSwitchTargets()->bbsDstTab; + jmpCnt = block->GetSwitchTargets()->bbsCount; // Now check for two trivial switch jumps. // @@ -3220,7 +3246,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) } // Change the switch jump into a BBJ_ALWAYS - block->SetJumpKindAndTarget(BBJ_ALWAYS, block->GetJumpSwt()->bbsDstTab[0]); + block->SetKindAndTarget(BBJ_ALWAYS, block->GetSwitchTargets()->bbsDstTab[0]); if (jmpCnt > 1) { for (unsigned i = 1; i < jmpCnt; ++i) @@ -3231,7 +3257,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) return true; } - else if ((block->GetJumpSwt()->bbsCount == 2) && block->NextIs(block->GetJumpSwt()->bbsDstTab[1])) + else if ((block->GetSwitchTargets()->bbsCount == 2) && block->NextIs(block->GetSwitchTargets()->bbsDstTab[1])) { /* Use a BBJ_COND(switchVal==0) for a switch with only one significant clause besides the default clause, if the @@ -3284,7 +3310,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) fgSetStmtSeq(switchStmt); } - block->SetJumpKindAndTarget(BBJ_COND, block->GetJumpSwt()->bbsDstTab[0]); + block->SetCond(block->GetSwitchTargets()->bbsDstTab[0]); JITDUMP("After:\n"); DISPNODE(switchTree); @@ -3641,26 +3667,25 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* } // At this point we know target is BBJ_COND. - // + assert(target->KindIs(BBJ_COND)); + // Bail out if OSR, as we can have unusual flow into loops. If one // of target's successors is also a backedge target, this optimization // may mess up loop recognition by creating too many non-loop preds. // if (opts.IsOSR()) { - assert(target->KindIs(BBJ_COND)); - - if (target->Next()->HasFlag(BBF_BACKWARD_JUMP_TARGET)) + if (target->GetFalseTarget()->HasFlag(BBF_BACKWARD_JUMP_TARGET)) { JITDUMP("Deferring: " FMT_BB " --> " FMT_BB "; latter looks like loop top\n", target->bbNum, - target->Next()->bbNum); + target->GetFalseTarget()->bbNum); return false; } - if (target->GetJumpDest()->HasFlag(BBF_BACKWARD_JUMP_TARGET)) + if (target->GetTrueTarget()->HasFlag(BBF_BACKWARD_JUMP_TARGET)) { JITDUMP("Deferring: " FMT_BB " --> " FMT_BB "; latter looks like loop top\n", target->bbNum, - target->GetJumpDest()->bbNum); + target->GetTrueTarget()->bbNum); return false; } } @@ -3695,20 +3720,20 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* // Fix up block's flow // - block->SetJumpKindAndTarget(BBJ_COND, target->GetJumpDest()); - fgAddRefPred(block->GetJumpDest(), block); + block->SetCond(target->GetTrueTarget()); + fgAddRefPred(block->GetTrueTarget(), block); fgRemoveRefPred(target, block); // add an unconditional block after this block to jump to the target block's fallthrough block // assert(!target->IsLast()); - BasicBlock* next = fgNewBBafter(BBJ_ALWAYS, block, true, target->Next()); + BasicBlock* next = fgNewBBafter(BBJ_ALWAYS, block, true, target->GetFalseTarget()); // The new block 'next' will inherit its weight from 'block' // next->inheritWeight(block); fgAddRefPred(next, block); - fgAddRefPred(next->GetJumpDest(), next); + fgAddRefPred(next->GetTarget(), next); JITDUMP("fgOptimizeUncondBranchToSimpleCond(from " FMT_BB " to cond " FMT_BB "), created new uncond " FMT_BB "\n", block->bbNum, target->bbNum, next->bbNum); @@ -3722,8 +3747,8 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* // Optimize a block which has a branch to the following block // // Arguments: -// block - block with a branch -// bNext - block which is both next and the target of the first block +// block - block with a BBJ_COND jump kind +// bNext - target that block jumps to regardless of its condition // bPrev - block which is prior to the first block // // Returns: true if changes were made @@ -3731,8 +3756,8 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev) { assert(block->KindIs(BBJ_COND)); - assert(block->HasJumpTo(bNext)); - assert(block->NextIs(bNext)); + assert(block->TrueTargetIs(bNext)); + assert(block->FalseTargetIs(bNext)); assert(block->PrevIs(bPrev)); #ifdef DEBUG @@ -3839,7 +3864,7 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi /* Conditional is gone - always jump to the next block */ - block->SetJumpKind(BBJ_ALWAYS); + block->SetKind(BBJ_ALWAYS); /* Update bbRefs and bbNum - Conditional predecessors to the same * block are counted twice so we have to remove one of them */ @@ -3894,14 +3919,14 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) return false; } - BasicBlock* bDest = bJump->GetJumpDest(); + BasicBlock* bDest = bJump->GetTarget(); if (!bDest->KindIs(BBJ_COND)) { return false; } - if (!bJump->NextIs(bDest->GetJumpDest())) + if (!bJump->NextIs(bDest->GetTrueTarget())) { return false; } @@ -3914,8 +3939,8 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) } // do not jump into another try region - BasicBlock* bDestNext = bDest->Next(); - if (bDestNext->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNext)) + BasicBlock* bDestNormalTarget = bDest->GetFalseTarget(); + if (bDestNormalTarget->hasTryIndex() && !BasicBlock::sameTryRegion(bJump, bDestNormalTarget)) { return false; } @@ -4107,21 +4132,22 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) // We need to update the following flags of the bJump block if they were set in the bDest block bJump->CopyFlags(bDest, BBF_COPY_PROPAGATE); - bJump->SetJumpKindAndTarget(BBJ_COND, bDest->Next()); + bJump->SetCond(bDestNormalTarget); + bJump->SetFalseTarget(bJump->Next()); /* Update bbRefs and bbPreds */ // bJump now falls through into the next block // - fgAddRefPred(bJump->Next(), bJump); + fgAddRefPred(bJump->GetFalseTarget(), bJump); // bJump no longer jumps to bDest // fgRemoveRefPred(bDest, bJump); - // bJump now jumps to bDest->bbNext + // bJump now jumps to bDest's normal jump target // - fgAddRefPred(bDest->Next(), bJump); + fgAddRefPred(bDestNormalTarget, bJump); if (weightJump > 0) { @@ -4208,7 +4234,7 @@ bool Compiler::fgOptimizeSwitchJumps() continue; } - if (!block->GetJumpSwt()->bbsHasDominantCase) + if (!block->GetSwitchTargets()->bbsHasDominantCase) { continue; } @@ -4217,14 +4243,14 @@ bool Compiler::fgOptimizeSwitchJumps() // assert(block->hasProfileWeight()); - const unsigned dominantCase = block->GetJumpSwt()->bbsDominantCase; + const unsigned dominantCase = block->GetSwitchTargets()->bbsDominantCase; JITDUMP(FMT_BB " has switch with dominant case %u, considering peeling\n", block->bbNum, dominantCase); // The dominant case should not be the default case, as we already peel that one. // - assert(dominantCase < (block->GetJumpSwt()->bbsCount - 1)); - BasicBlock* const dominantTarget = block->GetJumpSwt()->bbsDstTab[dominantCase]; + assert(dominantCase < (block->GetSwitchTargets()->bbsCount - 1)); + BasicBlock* const dominantTarget = block->GetSwitchTargets()->bbsDstTab[dominantCase]; Statement* const switchStmt = block->lastStmt(); GenTree* const switchTree = switchStmt->GetRootNode(); assert(switchTree->OperIs(GT_SWITCH)); @@ -4267,7 +4293,7 @@ bool Compiler::fgOptimizeSwitchJumps() // Wire up the new control flow. // - block->SetJumpKindAndTarget(BBJ_COND, dominantTarget); + block->SetCond(dominantTarget); FlowEdge* const blockToTargetEdge = fgAddRefPred(dominantTarget, block); FlowEdge* const blockToNewBlockEdge = newBlock->bbPreds; assert(blockToNewBlockEdge->getSourceBlock() == block); @@ -4275,7 +4301,7 @@ bool Compiler::fgOptimizeSwitchJumps() // Update profile data // - const weight_t fraction = newBlock->GetJumpSwt()->bbsDominantFraction; + const weight_t fraction = newBlock->GetSwitchTargets()->bbsDominantFraction; const weight_t blockToTargetWeight = block->bbWeight * fraction; const weight_t blockToNewBlockWeight = block->bbWeight - blockToTargetWeight; @@ -4325,7 +4351,7 @@ bool Compiler::fgOptimizeSwitchJumps() // // But it no longer has a dominant case. // - newBlock->GetJumpSwt()->bbsHasDominantCase = false; + newBlock->GetSwitchTargets()->bbsHasDominantCase = false; if (fgNodeThreading == NodeThreading::AllTrees) { @@ -4483,11 +4509,11 @@ bool Compiler::fgExpandRarelyRunBlocks() const char* reason = nullptr; - switch (bPrev->GetJumpKind()) + switch (bPrev->GetKind()) { case BBJ_ALWAYS: - if (bPrev->GetJumpDest()->isRunRarely()) + if (bPrev->GetTarget()->isRunRarely()) { reason = "Unconditional jump to a rarely run block"; } @@ -4503,7 +4529,7 @@ bool Compiler::fgExpandRarelyRunBlocks() case BBJ_COND: - if (block->isRunRarely() && bPrev->GetJumpDest()->isRunRarely()) + if (block->isRunRarely() && bPrev->GetTrueTarget()->isRunRarely()) { reason = "Both sides of a conditional jump are rarely run"; } @@ -4769,10 +4795,16 @@ bool Compiler::fgReorderBlocks(bool useProfile) bool backwardBranch = false; // Setup bDest - if (bPrev->KindIs(BBJ_COND, BBJ_ALWAYS)) + if (bPrev->KindIs(BBJ_ALWAYS)) + { + bDest = bPrev->GetTarget(); + forwardBranch = fgIsForwardBranch(bPrev, bDest); + backwardBranch = !forwardBranch; + } + else if (bPrev->KindIs(BBJ_COND)) { - bDest = bPrev->GetJumpDest(); - forwardBranch = fgIsForwardBranch(bPrev); + bDest = bPrev->GetTrueTarget(); + forwardBranch = fgIsForwardBranch(bPrev, bDest); backwardBranch = !forwardBranch; } @@ -5027,8 +5059,9 @@ bool Compiler::fgReorderBlocks(bool useProfile) // candidateBlock and have it fall into bTmp // if ((candidateBlock == nullptr) || !candidateBlock->KindIs(BBJ_COND, BBJ_ALWAYS) || - !candidateBlock->HasJumpTo(bTmp) || - (candidateBlock->KindIs(BBJ_ALWAYS) && candidateBlock->JumpsToNext())) + (candidateBlock->KindIs(BBJ_ALWAYS) && + (!candidateBlock->TargetIs(bTmp) || candidateBlock->JumpsToNext())) || + (candidateBlock->KindIs(BBJ_COND) && !candidateBlock->TrueTargetIs(bTmp))) { // otherwise we have a new candidateBlock // @@ -5601,7 +5634,8 @@ bool Compiler::fgReorderBlocks(bool useProfile) BasicBlock* jumpBlk = nullptr; if (bEnd->KindIs(BBJ_ALWAYS) && !bEnd->JumpsToNext() && - (!isRare || bEnd->GetJumpDest()->isRunRarely()) && fgIsForwardBranch(bEnd, bPrev)) + (!isRare || bEnd->GetTarget()->isRunRarely()) && + fgIsForwardBranch(bEnd, bEnd->GetTarget(), bPrev)) { // Set nearBlk to be the block in [startBlk..endBlk] // such that nearBlk->NextIs(bEnd->JumpDest) @@ -5616,7 +5650,7 @@ bool Compiler::fgReorderBlocks(bool useProfile) if (nearBlk != bPrev) { // Check if nearBlk satisfies our requirement - if (nearBlk->NextIs(bEnd->GetJumpDest())) + if (nearBlk->NextIs(bEnd->GetTarget())) { break; } @@ -5760,7 +5794,7 @@ bool Compiler::fgReorderBlocks(bool useProfile) if (bStart2 == nullptr) { /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */ - bPrev->SetJumpDest(bStart); + bPrev->SetTrueTarget(bStart); } else { @@ -5768,7 +5802,7 @@ bool Compiler::fgReorderBlocks(bool useProfile) noway_assert(insertAfterBlk->NextIs(block)); /* Set the new jump dest for bPrev to the rarely run or uncommon block(s) */ - bPrev->SetJumpDest(block); + bPrev->SetTrueTarget(block); } } @@ -5989,14 +6023,17 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) if (block->KindIs(BBJ_ALWAYS)) { - bDest = block->GetJumpDest(); + bDest = block->GetTarget(); if (doTailDuplication && fgOptimizeUncondBranchToSimpleCond(block, bDest)) { assert(block->KindIs(BBJ_COND)); change = true; modified = true; - bDest = block->GetJumpDest(); - bNext = block->Next(); + bDest = block->GetTrueTarget(); + bNext = block->GetFalseTarget(); + + // TODO-NoFallThrough: Adjust the above logic once bbFalseTarget can diverge from bbNext + assert(block->NextIs(bNext)); } } @@ -6005,7 +6042,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) if (block->KindIs(BBJ_ALWAYS)) { - bDest = block->GetJumpDest(); + bDest = block->GetTarget(); if (bDest == bNext) { // Skip jump optimizations, and try to compact block and bNext later @@ -6015,9 +6052,11 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) } else if (block->KindIs(BBJ_COND)) { - bDest = block->GetJumpDest(); + bDest = block->GetTrueTarget(); if (bDest == bNext) { + // TODO-NoFallThrough: Fix above condition once bbFalseTarget can diverge from bbNext + assert(block->FalseTargetIs(bNext)); if (fgOptimizeBranchToNext(block, bNext, bPrev)) { change = true; @@ -6031,7 +6070,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) { // Do we have a JUMP to an empty unconditional JUMP block? if (bDest->isEmpty() && bDest->KindIs(BBJ_ALWAYS) && - !bDest->HasJumpTo(bDest)) // special case for self jumps + !bDest->TargetIs(bDest)) // special case for self jumps { // TODO: Allow optimizing branches to blocks that jump to the next block const bool optimizeBranch = !bDest->JumpsToNext() || !bDest->HasFlag(BBF_NONE_QUIRK); @@ -6052,15 +6091,18 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) // bNext's jump target has a join. // if (block->KindIs(BBJ_COND) && // block is a BBJ_COND block - (bNext != nullptr) && // block is not the last block (bNext->bbRefs == 1) && // No other block jumps to bNext bNext->KindIs(BBJ_ALWAYS) && // The next block is a BBJ_ALWAYS block !bNext->JumpsToNext() && // and it doesn't jump to the next block (we might compact them) bNext->isEmpty() && // and it is an empty block - !bNext->HasJumpTo(bNext) && // special case for self jumps + !bNext->TargetIs(bNext) && // special case for self jumps !bDest->IsFirstColdBlock(this) && !fgInDifferentRegions(block, bDest)) // do not cross hot/cold sections { + // bbFalseTarget cannot be null + assert(block->FalseTargetIs(bNext)); + assert(bNext != nullptr); + // case (a) // const bool isJumpAroundEmpty = bNext->NextIs(bDest); @@ -6079,7 +6121,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) // * don't consider lexical predecessors, or we may confuse loop recognition // * don't consider blocks of different rarities // - BasicBlock* const bNextJumpDest = bNext->GetJumpDest(); + BasicBlock* const bNextJumpDest = bNext->GetTarget(); const bool isJumpToJoinFree = !isJumpAroundEmpty && (bDest->bbRefs == 1) && (bNextJumpDest->bbRefs > 1) && (bDest->bbNum > block->bbNum) && (block->isRunRarely() == bDest->isRunRarely()); @@ -6138,6 +6180,10 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) // BasicBlock* const bDestNext = bDest->Next(); + // Once bbFalseTarget and bbNext can diverge, this assert will hit + // TODO-NoFallThrough: Remove fall-through for BBJ_COND below + assert(!bDest->KindIs(BBJ_COND) || bDest->FalseTargetIs(bDestNext)); + // Move bDest // if (ehIsBlockEHLast(bDest)) @@ -6163,6 +6209,8 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) fgRemoveRefPred(bDestNext, bDest); fgAddRefPred(bFixup, bDest); fgAddRefPred(bDestNext, bFixup); + + bDest->SetFalseTarget(bDest->Next()); } } } @@ -6190,9 +6238,9 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) } // Optimize the Conditional JUMP to go to the new target - block->SetJumpDest(bNext->GetJumpDest()); + block->SetTrueTarget(bNext->GetTarget()); - fgAddRefPred(bNext->GetJumpDest(), block, fgRemoveRefPred(bNext->GetJumpDest(), bNext)); + fgAddRefPred(bNext->GetTarget(), block, fgRemoveRefPred(bNext->GetTarget(), bNext)); /* Unlink bNext from the BasicBlock list; note that we can @@ -6256,7 +6304,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) (that we will later connect to 'block'), it is not really unreachable. */ - if ((bNext->bbRefs > 0) && bNext->HasJumpTo(block) && (block->bbRefs == 1)) + if ((bNext->bbRefs > 0) && bNext->TargetIs(block) && (block->bbRefs == 1)) { continue; } @@ -6327,11 +6375,24 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) } else if (block->countOfInEdges() == 1) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: + if (block->TrueTargetIs(block)) + { + fgRemoveBlock(block, /* unreachable */ true); + + change = true; + modified = true; + + /* we removed the current block - the rest of the optimizations + * won't have a target so continue with the next block */ + + continue; + } + break; case BBJ_ALWAYS: - if (block->HasJumpTo(block)) + if (block->TargetIs(block)) { fgRemoveBlock(block, /* unreachable */ true); @@ -6424,7 +6485,7 @@ unsigned Compiler::fgGetCodeEstimate(BasicBlock* block) { unsigned costSz = 0; // estimate of block's code size cost - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_ALWAYS: case BBJ_EHCATCHRET: @@ -6450,7 +6511,7 @@ unsigned Compiler::fgGetCodeEstimate(BasicBlock* block) costSz = 3; break; default: - noway_assert(!"Bad bbJumpKind"); + noway_assert(!"Bad bbKind"); break; } @@ -6793,7 +6854,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // Fix up the flow. // - predBlock->SetJumpKindAndTarget(BBJ_ALWAYS, crossJumpTarget); + predBlock->SetKindAndTarget(BBJ_ALWAYS, crossJumpTarget); if (commSucc != nullptr) { @@ -6968,7 +7029,7 @@ bool Compiler::fgTryOneHeadMerge(BasicBlock* block, bool early) // ternaries in C#). // The logic below could be generalized to BBJ_SWITCH, but this currently // has almost no CQ benefit but does have a TP impact. - if (!block->KindIs(BBJ_COND) || block->JumpsToNext()) + if (!block->KindIs(BBJ_COND) || block->TrueTargetIs(block->GetFalseTarget())) { return false; } @@ -7017,7 +7078,8 @@ bool Compiler::fgTryOneHeadMerge(BasicBlock* block, bool early) Statement* nextFirstStmt; Statement* destFirstStmt; - if (!getSuccCandidate(block->Next(), &nextFirstStmt) || !getSuccCandidate(block->GetJumpDest(), &destFirstStmt)) + if (!getSuccCandidate(block->GetFalseTarget(), &nextFirstStmt) || + !getSuccCandidate(block->GetTrueTarget(), &destFirstStmt)) { return false; } @@ -7045,10 +7107,10 @@ bool Compiler::fgTryOneHeadMerge(BasicBlock* block, bool early) JITDUMP("We can; moving statement\n"); - fgUnlinkStmt(block->Next(), nextFirstStmt); + fgUnlinkStmt(block->GetFalseTarget(), nextFirstStmt); fgInsertStmtNearEnd(block, nextFirstStmt); - fgUnlinkStmt(block->GetJumpDest(), destFirstStmt); - block->CopyFlags(block->Next(), BBF_COPY_PROPAGATE); + fgUnlinkStmt(block->GetTrueTarget(), destFirstStmt); + block->CopyFlags(block->GetFalseTarget(), BBF_COPY_PROPAGATE); return true; } diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 5fd6b30eeddd9..b7ab37551695a 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -935,7 +935,7 @@ void Compiler::WalkSpanningTree(SpanningTreeVisitor* visitor) visitor->VisitBlock(block); nBlocks++; - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_CALLFINALLY: { @@ -1008,7 +1008,7 @@ void Compiler::WalkSpanningTree(SpanningTreeVisitor* visitor) // We're leaving a try or catch, not a handler. // Treat this as a normal edge. // - BasicBlock* const target = block->GetJumpDest(); + BasicBlock* const target = block->GetTarget(); // In some bad IL cases we may not have a target. // In others we may see something other than LEAVE be most-nested in a try. @@ -1677,7 +1677,7 @@ void EfficientEdgeCountInstrumentor::RelocateProbes() // Ensure this pred always jumps to block // assert(pred->KindIs(BBJ_ALWAYS)); - assert(pred->HasJumpTo(block)); + assert(pred->TargetIs(block)); } } @@ -3781,8 +3781,8 @@ void EfficientEdgeCountReconstructor::PropagateEdges(BasicBlock* block, BlockInf { assert(nSucc == 1); assert(block == pseudoEdge->m_sourceBlock); - assert(block->HasInitializedJumpDest()); - FlowEdge* const flowEdge = m_comp->fgGetPredForBlock(block->GetJumpDest(), block); + assert(block->HasInitializedTarget()); + FlowEdge* const flowEdge = m_comp->fgGetPredForBlock(block->GetTarget(), block); assert(flowEdge != nullptr); flowEdge->setLikelihood(1.0); return; @@ -3792,7 +3792,7 @@ void EfficientEdgeCountReconstructor::PropagateEdges(BasicBlock* block, BlockInf // // This can happen because bome BBJ_LEAVE blocks may have been missed during // our spanning tree walk since we don't know where all the finallies can return - // to just yet (specially, in WalkSpanningTree, we may not add the bbJumpDest of + // to just yet (specially, in WalkSpanningTree, we may not add the bbTarget of // a BBJ_LEAVE to the worklist). // // Worst case those missed blocks dominate other blocks so we can't limit @@ -3900,7 +3900,7 @@ void EfficientEdgeCountReconstructor::PropagateEdges(BasicBlock* block, BlockInf // void EfficientEdgeCountReconstructor::MarkInterestingBlocks(BasicBlock* block, BlockInfo* info) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_SWITCH: MarkInterestingSwitches(block, info); @@ -3994,8 +3994,8 @@ void EfficientEdgeCountReconstructor::MarkInterestingSwitches(BasicBlock* block, // If it turns out often we fail at this stage, we might consider building a histogram of switch case // values at runtime, similar to what we do for classes at virtual call sites. // - const unsigned caseCount = block->GetJumpSwt()->bbsCount; - BasicBlock** const jumpTab = block->GetJumpSwt()->bbsDstTab; + const unsigned caseCount = block->GetSwitchTargets()->bbsCount; + BasicBlock** const jumpTab = block->GetSwitchTargets()->bbsDstTab; unsigned dominantCase = caseCount; for (unsigned i = 0; i < caseCount; i++) @@ -4021,7 +4021,7 @@ void EfficientEdgeCountReconstructor::MarkInterestingSwitches(BasicBlock* block, return; } - if (block->GetJumpSwt()->bbsHasDefault && (dominantCase == caseCount - 1)) + if (block->GetSwitchTargets()->bbsHasDefault && (dominantCase == caseCount - 1)) { // Dominant case is the default case. // This effectively gets peeled already, so defer. @@ -4035,9 +4035,9 @@ void EfficientEdgeCountReconstructor::MarkInterestingSwitches(BasicBlock* block, "; marking for peeling\n", dominantCase, dominantEdge->m_targetBlock->bbNum, fraction); - block->GetJumpSwt()->bbsHasDominantCase = true; - block->GetJumpSwt()->bbsDominantCase = dominantCase; - block->GetJumpSwt()->bbsDominantFraction = fraction; + block->GetSwitchTargets()->bbsHasDominantCase = true; + block->GetSwitchTargets()->bbsDominantCase = dominantCase; + block->GetSwitchTargets()->bbsDominantFraction = fraction; } //------------------------------------------------------------------------ @@ -4409,7 +4409,7 @@ bool Compiler::fgComputeMissingBlockWeights(weight_t* returnWeight) // Does this block flow into only one other block if (bSrc->KindIs(BBJ_ALWAYS)) { - bOnlyNext = bSrc->GetJumpDest(); + bOnlyNext = bSrc->GetTarget(); } else { @@ -4426,7 +4426,7 @@ bool Compiler::fgComputeMissingBlockWeights(weight_t* returnWeight) // Does this block flow into only one other block if (bDst->KindIs(BBJ_ALWAYS)) { - bOnlyNext = bDst->GetJumpDest(); + bOnlyNext = bDst->GetTarget(); } else { @@ -4657,7 +4657,7 @@ PhaseStatus Compiler::fgComputeEdgeWeights() } slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1; - switch (bSrc->GetJumpKind()) + switch (bSrc->GetKind()) { case BBJ_ALWAYS: case BBJ_EHCATCHRET: @@ -4681,7 +4681,7 @@ PhaseStatus Compiler::fgComputeEdgeWeights() default: // We should never have an edge that starts from one of these jump kinds - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } @@ -4730,13 +4730,13 @@ PhaseStatus Compiler::fgComputeEdgeWeights() weight_t diff; FlowEdge* otherEdge; BasicBlock* otherDst; - if (bSrc->NextIs(bDst)) + if (bSrc->FalseTargetIs(bDst)) { - otherDst = bSrc->GetJumpDest(); + otherDst = bSrc->GetTrueTarget(); } else { - otherDst = bSrc->Next(); + otherDst = bSrc->GetFalseTarget(); } otherEdge = fgGetPredForBlock(otherDst, bSrc); diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index cd9d872d7ea17..b49e511e0c22c 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -132,7 +132,7 @@ void ProfileSynthesis::AssignLikelihoods() for (BasicBlock* const block : m_comp->Blocks()) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_THROW: case BBJ_RETURN: @@ -190,14 +190,14 @@ void ProfileSynthesis::AssignLikelihoodNext(BasicBlock* block) //------------------------------------------------------------------------ // AssignLikelihoodJump: update edge likelihood for a block that always -// transfers control to bbJumpDest +// transfers control to bbTarget // // Arguments; // block -- block in question // void ProfileSynthesis::AssignLikelihoodJump(BasicBlock* block) { - FlowEdge* const edge = m_comp->fgGetPredForBlock(block->GetJumpDest(), block); + FlowEdge* const edge = m_comp->fgGetPredForBlock(block->GetTarget(), block); edge->setLikelihood(1.0); } @@ -210,8 +210,8 @@ void ProfileSynthesis::AssignLikelihoodJump(BasicBlock* block) // void ProfileSynthesis::AssignLikelihoodCond(BasicBlock* block) { - BasicBlock* const jump = block->GetJumpDest(); - BasicBlock* const next = block->Next(); + BasicBlock* const jump = block->GetTrueTarget(); + BasicBlock* const next = block->GetFalseTarget(); // Watch for degenerate case // @@ -393,7 +393,7 @@ void ProfileSynthesis::RepairLikelihoods() for (BasicBlock* const block : m_comp->Blocks()) { - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_THROW: case BBJ_RETURN: @@ -484,7 +484,7 @@ void ProfileSynthesis::BlendLikelihoods() { weight_t sum = SumOutgoingLikelihoods(block, &likelihoods); - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_THROW: case BBJ_RETURN: @@ -861,8 +861,8 @@ void ProfileSynthesis::ComputeCyclicProbabilities(FlowGraphNaturalLoop* loop) " to reflect capping; current likelihood is " FMT_WT "\n", exitBlock->bbNum, exitEdge->getLikelihood()); - BasicBlock* const jump = exitBlock->GetJumpDest(); - BasicBlock* const next = exitBlock->Next(); + BasicBlock* const jump = exitBlock->GetTrueTarget(); + BasicBlock* const next = exitBlock->GetFalseTarget(); FlowEdge* const jumpEdge = m_comp->fgGetPredForBlock(jump, exitBlock); FlowEdge* const nextEdge = m_comp->fgGetPredForBlock(next, exitBlock); weight_t const exitLikelihood = (missingExitWeight + currentExitWeight) / exitBlockWeight; diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index f1263d2c9d118..c432a192df65d 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -130,7 +130,7 @@ PhaseStatus Compiler::fgInsertGCPolls() JITDUMP("Selecting CALL poll in block " FMT_BB " because it is the single return block\n", block->bbNum); pollType = GCPOLL_CALL; } - else if (BBJ_SWITCH == block->GetJumpKind()) + else if (BBJ_SWITCH == block->GetKind()) { // We don't want to deal with all the outgoing edges of a switch block. // @@ -267,21 +267,27 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) // I want to create: // top -> poll -> bottom (lexically) // so that we jump over poll to get to bottom. - BasicBlock* top = block; - BasicBlock* topFallThrough = nullptr; + BasicBlock* top = block; + BasicBlock* topFallThrough = nullptr; + BasicBlock* topJumpTarget; unsigned char lpIndexFallThrough = BasicBlock::NOT_IN_LOOP; if (top->KindIs(BBJ_COND)) { - topFallThrough = top->Next(); + topFallThrough = top->GetFalseTarget(); + topJumpTarget = top->GetTrueTarget(); lpIndexFallThrough = topFallThrough->bbNatLoopNum; } + else + { + topJumpTarget = top->GetTarget(); + } BasicBlock* poll = fgNewBBafter(BBJ_ALWAYS, top, true); - bottom = fgNewBBafter(top->GetJumpKind(), poll, true, top->GetJumpDest()); - BBjumpKinds oldJumpKind = top->GetJumpKind(); + bottom = fgNewBBafter(top->GetKind(), poll, true, topJumpTarget); + BBKinds oldJumpKind = top->GetKind(); unsigned char lpIndex = top->bbNatLoopNum; - poll->SetJumpDest(bottom); + poll->SetTarget(bottom); assert(poll->JumpsToNext()); // Update block flags @@ -388,7 +394,7 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) } #endif - top->SetJumpKindAndTarget(BBJ_COND, bottom); + top->SetCond(bottom); // Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor. fgAddRefPred(bottom, poll); fgAddRefPred(bottom, top); @@ -403,16 +409,15 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) // no successors break; case BBJ_COND: - // replace predecessor in the fall through block. + // replace predecessor in true/false successors. noway_assert(!bottom->IsLast()); - fgReplacePred(bottom->Next(), top, bottom); - - // fall through for the jump target - FALLTHROUGH; + fgReplacePred(bottom->GetFalseTarget(), top, bottom); + fgReplacePred(bottom->GetTrueTarget(), top, bottom); + break; case BBJ_ALWAYS: case BBJ_CALLFINALLY: - fgReplacePred(bottom->GetJumpDest(), top, bottom); + fgReplacePred(bottom->GetTarget(), top, bottom); break; case BBJ_SWITCH: NO_WAY("SWITCH should be a call rather than an inlined poll."); @@ -1674,14 +1679,14 @@ void Compiler::fgConvertSyncReturnToLeave(BasicBlock* block) assert(ehDsc->ebdEnclosingHndIndex == EHblkDsc::NO_ENCLOSING_INDEX); // Convert the BBJ_RETURN to BBJ_ALWAYS, jumping to genReturnBB. - block->SetJumpKindAndTarget(BBJ_ALWAYS, genReturnBB); + block->SetKindAndTarget(BBJ_ALWAYS, genReturnBB); fgAddRefPred(genReturnBB, block); #ifdef DEBUG if (verbose) { printf("Synchronized method - convert block " FMT_BB " to BBJ_ALWAYS [targets " FMT_BB "]\n", block->bbNum, - block->GetJumpDest()->bbNum); + block->GetTarget()->bbNum); } #endif } @@ -2145,7 +2150,7 @@ class MergedReturns // Change BBJ_RETURN to BBJ_ALWAYS targeting const return block. assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); - returnBlock->SetJumpKindAndTarget(BBJ_ALWAYS, constReturnBlock); + returnBlock->SetKindAndTarget(BBJ_ALWAYS, constReturnBlock); comp->fgAddRefPred(constReturnBlock, returnBlock); // Remove GT_RETURN since constReturnBlock returns the constant. @@ -2831,11 +2836,11 @@ void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block) // It's a jump from outside the handler; add it to the newHead preds list and remove // it from the block preds list. - switch (predBlock->GetJumpKind()) + switch (predBlock->GetKind()) { case BBJ_CALLFINALLY: - noway_assert(predBlock->HasJumpTo(block)); - predBlock->SetJumpDest(newHead); + noway_assert(predBlock->TargetIs(block)); + predBlock->SetTarget(newHead); fgRemoveRefPred(block, predBlock); fgAddRefPred(newHead, predBlock); break; @@ -3209,7 +3214,7 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() // if (prevToFirstColdBlock->bbFallsThrough()) { - switch (prevToFirstColdBlock->GetJumpKind()) + switch (prevToFirstColdBlock->GetKind()) { default: noway_assert(!"Unhandled jumpkind in fgDetermineFirstColdBlock()"); @@ -3229,6 +3234,10 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() // This is a slightly more complicated case, because we will // probably need to insert a block to jump to the cold section. // + + // TODO-NoFallThrough: Below logic will need additional check once bbFalseTarget can diverge from + // bbNext + assert(prevToFirstColdBlock->FalseTargetIs(firstColdBlock)); if (firstColdBlock->isEmpty() && firstColdBlock->KindIs(BBJ_ALWAYS)) { // We can just use this block as the transitionBlock @@ -3444,7 +3453,7 @@ PhaseStatus Compiler::fgCreateThrowHelperBlocks() // assert(!fgRngChkThrowAdded); - const static BBjumpKinds jumpKinds[] = { + const static BBKinds jumpKinds[] = { BBJ_ALWAYS, // SCK_NONE BBJ_THROW, // SCK_RNGCHK_FAIL BBJ_THROW, // SCK_DIV_BY_ZERO @@ -3532,7 +3541,7 @@ PhaseStatus Compiler::fgCreateThrowHelperBlocks() #endif // DEBUG // Mark the block as added by the compiler and not removable by future flow - // graph optimizations. Note that no bbJumpDest points to these blocks. + // graph optimizations. Note that no bbTarget points to these blocks. // newBlk->SetFlags(BBF_IMPORTED | BBF_DONT_REMOVE); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index ceb7399766384..9f1afb21f4c18 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -194,7 +194,7 @@ inline AssertionIndex GetAssertionIndex(unsigned index) class AssertionInfo { - // true if the assertion holds on the bbNext edge instead of the bbJumpDest edge (for GT_JTRUE nodes) + // true if the assertion holds on the bbNext edge instead of the bbTarget edge (for GT_JTRUE nodes) unsigned short m_isNextEdgeAssertion : 1; // 1-based index of the assertion unsigned short m_assertionIndex : 15; diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 52db3d163a70e..d5ca9f2fbb032 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -286,13 +286,13 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock** pBlock, Statement* stm // Fallback basic block GenTree* fallbackValueDef = gtNewStoreLclVarNode(rtLookupLcl->GetLclNum(), call); BasicBlock* fallbackBb = - fgNewBBFromTreeAfter(BBJ_ALWAYS, nullcheckBb, fallbackValueDef, debugInfo, nullcheckBb->Next(), true); + fgNewBBFromTreeAfter(BBJ_ALWAYS, nullcheckBb, fallbackValueDef, debugInfo, nullcheckBb->GetFalseTarget(), true); assert(fallbackBb->JumpsToNext()); fallbackBb->SetFlags(BBF_NONE_QUIRK); - // Set nullcheckBb's real jump target - nullcheckBb->SetJumpDest(fallbackBb); + // Set nullcheckBb's true jump target + nullcheckBb->SetTrueTarget(fallbackBb); // Fast-path basic block GenTree* fastpathValueDef = gtNewStoreLclVarNode(rtLookupLcl->GetLclNum(), fastPathValueClone); @@ -352,7 +352,7 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock** pBlock, Statement* stm if (needsSizeCheck) { // sizeCheckBb is the first block after prevBb - prevBb->SetJumpDest(sizeCheckBb); + prevBb->SetTarget(sizeCheckBb); fgAddRefPred(sizeCheckBb, prevBb); // sizeCheckBb flows into nullcheckBb in case if the size check passes fgAddRefPred(nullcheckBb, sizeCheckBb); @@ -365,7 +365,7 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock** pBlock, Statement* stm else { // nullcheckBb is the first block after prevBb - prevBb->SetJumpDest(nullcheckBb); + prevBb->SetTarget(nullcheckBb); fgAddRefPred(nullcheckBb, prevBb); // No size check, nullcheckBb jumps to fast path fgAddRefPred(fastPathBb, nullcheckBb); @@ -780,17 +780,17 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* gtNewStoreLclVarNode(threadStaticBlockLclNum, gtCloneExpr(threadStaticBlockBaseLclValueUse)); BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, fastPathValueDef, debugInfo, block, true); - // Set maxThreadStaticBlocksCondBB's real jump target - maxThreadStaticBlocksCondBB->SetJumpDest(fallbackBb); + // Set maxThreadStaticBlocksCondBB's true jump target + maxThreadStaticBlocksCondBB->SetTrueTarget(fallbackBb); - // Set threadStaticBlockNullCondBB's real jump target - threadStaticBlockNullCondBB->SetJumpDest(fastPathBb); + // Set threadStaticBlockNullCondBB's true jump target + threadStaticBlockNullCondBB->SetTrueTarget(fastPathBb); // // Update preds in all new blocks // assert(prevBb->KindIs(BBJ_ALWAYS)); - prevBb->SetJumpDest(maxThreadStaticBlocksCondBB); + prevBb->SetTarget(maxThreadStaticBlocksCondBB); fgRemoveRefPred(block, prevBb); fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); @@ -1095,7 +1095,8 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock** pBlock, Statement* stmt, G // Fallback basic block // TODO-CQ: for JIT we can replace the original call with CORINFO_HELP_INITCLASS // that only accepts a single argument - BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, isInitedBb, call, debugInfo, isInitedBb->Next(), true); + BasicBlock* helperCallBb = + fgNewBBFromTreeAfter(BBJ_ALWAYS, isInitedBb, call, debugInfo, isInitedBb->GetFalseTarget(), true); assert(helperCallBb->JumpsToNext()); helperCallBb->SetFlags(BBF_NONE_QUIRK); @@ -1165,7 +1166,7 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock** pBlock, Statement* stmt, G // prevBb always flows into isInitedBb assert(prevBb->KindIs(BBJ_ALWAYS)); - prevBb->SetJumpDest(isInitedBb); + prevBb->SetTarget(isInitedBb); prevBb->SetFlags(BBF_NONE_QUIRK); assert(prevBb->JumpsToNext()); fgAddRefPred(isInitedBb, prevBb); @@ -1450,7 +1451,7 @@ bool Compiler::fgVNBasedIntrinsicExpansionForCall_ReadUtf8(BasicBlock** pBlock, // In theory, we could just emit the const U8 data to the data section and use GT_BLK here // but that would be a bit less efficient since we would have to load the data from memory. // - BasicBlock* fastpathBb = fgNewBBafter(BBJ_ALWAYS, lengthCheckBb, true, lengthCheckBb->Next()); + BasicBlock* fastpathBb = fgNewBBafter(BBJ_ALWAYS, lengthCheckBb, true, lengthCheckBb->GetFalseTarget()); assert(fastpathBb->JumpsToNext()); fastpathBb->SetFlags(BBF_INTERNAL | BBF_NONE_QUIRK); @@ -1508,7 +1509,7 @@ bool Compiler::fgVNBasedIntrinsicExpansionForCall_ReadUtf8(BasicBlock** pBlock, fgRemoveRefPred(block, prevBb); // prevBb flows into lengthCheckBb assert(prevBb->KindIs(BBJ_ALWAYS)); - prevBb->SetJumpDest(lengthCheckBb); + prevBb->SetTarget(lengthCheckBb); prevBb->SetFlags(BBF_NONE_QUIRK); assert(prevBb->JumpsToNext()); fgAddRefPred(lengthCheckBb, prevBb); diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 434656d520c59..5c52e5c31a2d1 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -122,7 +122,7 @@ bool OptIfConversionDsc::IfConvertCheckInnerBlockFlow(BasicBlock* block) bool OptIfConversionDsc::IfConvertCheckThenFlow() { m_flowFound = false; - BasicBlock* thenBlock = m_startBlock->Next(); + BasicBlock* thenBlock = m_startBlock->GetFalseTarget(); for (int thenLimit = 0; thenLimit < m_checkLimit; thenLimit++) { @@ -175,7 +175,7 @@ void OptIfConversionDsc::IfConvertFindFlow() { // First check for flow with no else case. The final block is the destination of the jump. m_doElseConversion = false; - m_finalBlock = m_startBlock->GetJumpDest(); + m_finalBlock = m_startBlock->GetTrueTarget(); assert(m_finalBlock != nullptr); if (!IfConvertCheckThenFlow() || m_flowFound) { @@ -388,7 +388,7 @@ void OptIfConversionDsc::IfConvertDump() } if (m_doElseConversion) { - for (BasicBlock* dumpBlock = m_startBlock->GetJumpDest(); dumpBlock != m_finalBlock; + for (BasicBlock* dumpBlock = m_startBlock->GetTrueTarget(); dumpBlock != m_finalBlock; dumpBlock = dumpBlock->GetUniqueSucc()) { m_comp->fgDumpBlock(dumpBlock); @@ -571,14 +571,14 @@ bool OptIfConversionDsc::optIfConvert() } // Check the Then and Else blocks have a single operation each. - if (!IfConvertCheckStmts(m_startBlock->Next(), &m_thenOperation)) + if (!IfConvertCheckStmts(m_startBlock->GetFalseTarget(), &m_thenOperation)) { return false; } assert(m_thenOperation.node->OperIs(GT_STORE_LCL_VAR, GT_RETURN)); if (m_doElseConversion) { - if (!IfConvertCheckStmts(m_startBlock->GetJumpDest(), &m_elseOperation)) + if (!IfConvertCheckStmts(m_startBlock->GetTrueTarget(), &m_elseOperation)) { return false; } @@ -738,9 +738,9 @@ bool OptIfConversionDsc::optIfConvert() } // Update the flow from the original block. - m_comp->fgRemoveAllRefPreds(m_startBlock->Next(), m_startBlock); - assert(m_startBlock->HasInitializedJumpDest()); - m_startBlock->SetJumpKind(BBJ_ALWAYS); + m_comp->fgRemoveAllRefPreds(m_startBlock->GetFalseTarget(), m_startBlock); + assert(m_startBlock->HasInitializedTarget()); + m_startBlock->SetKind(BBJ_ALWAYS); #ifdef DEBUG if (m_comp->verbose) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 6e4449581e5ac..8177792b0919a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -2493,7 +2493,7 @@ GenTree* Compiler::impTypeIsAssignable(GenTree* typeTo, GenTree* typeFrom) void Compiler::verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg)) { - block->SetJumpKindAndTarget(BBJ_THROW); + block->SetKindAndTarget(BBJ_THROW); block->SetFlags(BBF_FAILED_VERIFICATION); block->RemoveFlags(BBF_IMPORTED); @@ -4303,7 +4303,7 @@ void Compiler::impImportLeave(BasicBlock* block) #endif // DEBUG unsigned const blkAddr = block->bbCodeOffs; - BasicBlock* const leaveTarget = block->GetJumpDest(); + BasicBlock* const leaveTarget = block->GetTarget(); unsigned const jmpAddr = leaveTarget->bbCodeOffs; // LEAVE clears the stack, spill side effects, and set stack to 0 @@ -4384,11 +4384,11 @@ void Compiler::impImportLeave(BasicBlock* block) assert(step == DUMMY_INIT(NULL)); callBlock = block; - assert(callBlock->HasInitializedJumpDest()); - fgRemoveRefPred(callBlock->GetJumpDest(), callBlock); + assert(callBlock->HasInitializedTarget()); + fgRemoveRefPred(callBlock->GetTarget(), callBlock); // callBlock will call the finally handler. Convert the BBJ_LEAVE to BBJ_CALLFINALLY - callBlock->SetJumpKindAndTarget(BBJ_CALLFINALLY, HBtab->ebdHndBeg); + callBlock->SetKindAndTarget(BBJ_CALLFINALLY, HBtab->ebdHndBeg); if (endCatches) { @@ -4414,10 +4414,10 @@ void Compiler::impImportLeave(BasicBlock* block) callBlock = fgNewBBinRegion(BBJ_CALLFINALLY, XTnum + 1, 0, step, HBtab->ebdHndBeg); // step's jump target shouldn't be set yet - assert(!step->HasInitializedJumpDest()); + assert(!step->HasInitializedTarget()); // the previous call to a finally returns to this call (to the next finally in the chain) - step->SetJumpDest(callBlock); + step->SetTarget(callBlock); fgAddRefPred(callBlock, step); /* The new block will inherit this block's weight */ @@ -4466,8 +4466,8 @@ void Compiler::impImportLeave(BasicBlock* block) assert(finallyNesting <= compHndBBtabCount); assert(callBlock->KindIs(BBJ_CALLFINALLY)); - assert(callBlock->HasJumpTo(HBtab->ebdHndBeg)); - fgAddRefPred(callBlock->GetJumpDest(), callBlock); + assert(callBlock->TargetIs(HBtab->ebdHndBeg)); + fgAddRefPred(callBlock->GetTarget(), callBlock); GenTree* endLFin = new (this, GT_END_LFIN) GenTreeVal(GT_END_LFIN, TYP_VOID, finallyNesting); endLFinStmt = gtNewStmt(endLFin); @@ -4484,7 +4484,7 @@ void Compiler::impImportLeave(BasicBlock* block) if (encFinallies == 0) { assert(step == DUMMY_INIT(NULL)); - block->SetJumpKind(BBJ_ALWAYS); // convert the BBJ_LEAVE to a BBJ_ALWAYS + block->SetKind(BBJ_ALWAYS); // convert the BBJ_LEAVE to a BBJ_ALWAYS if (endCatches) { @@ -4514,9 +4514,9 @@ void Compiler::impImportLeave(BasicBlock* block) finalStep->SetFlags(BBF_KEEP_BBJ_ALWAYS); // step's jump target shouldn't be set yet - assert(!step->HasInitializedJumpDest()); + assert(!step->HasInitializedTarget()); - step->SetJumpDest(finalStep); + step->SetTarget(finalStep); fgAddRefPred(finalStep, step); /* The new block will inherit this block's weight */ @@ -4573,14 +4573,14 @@ void Compiler::impImportLeave(BasicBlock* block) if (verbose) { printf("\nBefore import CEE_LEAVE in " FMT_BB " (targeting " FMT_BB "):\n", block->bbNum, - block->GetJumpDest()->bbNum); + block->GetTarget()->bbNum); fgDispBasicBlocks(); fgDispHandlerTab(); } #endif // DEBUG unsigned blkAddr = block->bbCodeOffs; - BasicBlock* leaveTarget = block->GetJumpDest(); + BasicBlock* leaveTarget = block->GetTarget(); unsigned jmpAddr = leaveTarget->bbCodeOffs; // LEAVE clears the stack, spill side effects, and set stack to 0 @@ -4599,7 +4599,7 @@ void Compiler::impImportLeave(BasicBlock* block) ST_None, // Is the step block the BBJ_ALWAYS block of a BBJ_CALLFINALLY/BBJ_ALWAYS pair? - // That is, is step->bbJumpDest where a finally will return to? + // That is, is step->bbTarget where a finally will return to? ST_FinallyReturn, // The step block is a catch return. @@ -4638,7 +4638,7 @@ void Compiler::impImportLeave(BasicBlock* block) if (step == nullptr) { step = block; - step->SetJumpKind(BBJ_EHCATCHRET); // convert the BBJ_LEAVE to BBJ_EHCATCHRET + step->SetKind(BBJ_EHCATCHRET); // convert the BBJ_LEAVE to BBJ_EHCATCHRET stepType = ST_Catch; #ifdef DEBUG @@ -4659,13 +4659,13 @@ void Compiler::impImportLeave(BasicBlock* block) BasicBlock* exitBlock = fgNewBBinRegion(BBJ_EHCATCHRET, 0, XTnum + 1, step); assert(step->KindIs(BBJ_ALWAYS, BBJ_EHCATCHRET)); - assert((step == block) || !step->HasInitializedJumpDest()); + assert((step == block) || !step->HasInitializedTarget()); if (step == block) { - fgRemoveRefPred(step->GetJumpDest(), step); + fgRemoveRefPred(step->GetTarget(), step); } - step->SetJumpDest(exitBlock); // the previous step (maybe a call to a nested finally, or a nested catch - // exit) returns to this block + step->SetTarget(exitBlock); // the previous step (maybe a call to a nested finally, or a nested catch + // exit) returns to this block fgAddRefPred(exitBlock, step); /* The new block will inherit this block's weight */ @@ -4708,8 +4708,8 @@ void Compiler::impImportLeave(BasicBlock* block) // the new BBJ_CALLFINALLY is in a different EH region, thus it can't just replace the BBJ_LEAVE, // which might be in the middle of the "try". In most cases, the BBJ_ALWAYS will jump to the // next block, and flow optimizations will remove it. - fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKindAndTarget(BBJ_ALWAYS, callBlock); + fgRemoveRefPred(block->GetTarget(), block); + block->SetKindAndTarget(BBJ_ALWAYS, callBlock); fgAddRefPred(callBlock, block); /* The new block will inherit this block's weight */ @@ -4730,11 +4730,11 @@ void Compiler::impImportLeave(BasicBlock* block) callBlock = block; - assert(callBlock->HasInitializedJumpDest()); - fgRemoveRefPred(callBlock->GetJumpDest(), callBlock); + assert(callBlock->HasInitializedTarget()); + fgRemoveRefPred(callBlock->GetTarget(), callBlock); // callBlock will call the finally handler. Convert the BBJ_LEAVE to BBJ_CALLFINALLY - callBlock->SetJumpKindAndTarget(BBJ_CALLFINALLY, HBtab->ebdHndBeg); + callBlock->SetKindAndTarget(BBJ_CALLFINALLY, HBtab->ebdHndBeg); #ifdef DEBUG if (verbose) @@ -4767,7 +4767,7 @@ void Compiler::impImportLeave(BasicBlock* block) // stack walks.) assert(step->KindIs(BBJ_ALWAYS, BBJ_EHCATCHRET)); - assert((step == block) || !step->HasInitializedJumpDest()); + assert((step == block) || !step->HasInitializedTarget()); #if FEATURE_EH_CALLFINALLY_THUNKS if (step->KindIs(BBJ_EHCATCHRET)) @@ -4778,9 +4778,9 @@ void Compiler::impImportLeave(BasicBlock* block) BasicBlock* step2 = fgNewBBinRegion(BBJ_ALWAYS, XTnum + 1, 0, step); if (step == block) { - fgRemoveRefPred(step->GetJumpDest(), step); + fgRemoveRefPred(step->GetTarget(), step); } - step->SetJumpDest(step2); + step->SetTarget(step2); fgAddRefPred(step2, step); step2->inheritWeight(block); step2->CopyFlags(block, BBF_RUN_RARELY); @@ -4811,17 +4811,17 @@ void Compiler::impImportLeave(BasicBlock* block) #endif // !FEATURE_EH_CALLFINALLY_THUNKS assert(step->KindIs(BBJ_ALWAYS, BBJ_EHCATCHRET)); - assert((step == block) || !step->HasInitializedJumpDest()); + assert((step == block) || !step->HasInitializedTarget()); // callBlock will call the finally handler callBlock = fgNewBBinRegion(BBJ_CALLFINALLY, callFinallyTryIndex, callFinallyHndIndex, step, HBtab->ebdHndBeg); if (step == block) { - fgRemoveRefPred(step->GetJumpDest(), step); + fgRemoveRefPred(step->GetTarget(), step); } - step->SetJumpDest(callBlock); // the previous call to a finally returns to this call (to the next - // finally in the chain) + step->SetTarget(callBlock); // the previous call to a finally returns to this call (to the next + // finally in the chain) fgAddRefPred(callBlock, step); /* The new block will inherit this block's weight */ @@ -4856,8 +4856,8 @@ void Compiler::impImportLeave(BasicBlock* block) #endif assert(callBlock->KindIs(BBJ_CALLFINALLY)); - assert(callBlock->HasJumpTo(HBtab->ebdHndBeg)); - fgAddRefPred(callBlock->GetJumpDest(), callBlock); + assert(callBlock->TargetIs(HBtab->ebdHndBeg)); + fgAddRefPred(callBlock->GetTarget(), callBlock); } else if (HBtab->HasCatchHandler() && jitIsBetween(blkAddr, tryBeg, tryEnd) && !jitIsBetween(jmpAddr, tryBeg, tryEnd)) @@ -4903,7 +4903,7 @@ void Compiler::impImportLeave(BasicBlock* block) if ((stepType == ST_FinallyReturn) || (stepType == ST_Catch)) { assert(step); - assert((step == block) || !step->HasInitializedJumpDest()); + assert((step == block) || !step->HasInitializedTarget()); if (stepType == ST_FinallyReturn) { @@ -4921,9 +4921,9 @@ void Compiler::impImportLeave(BasicBlock* block) if (step == block) { - fgRemoveRefPred(step->GetJumpDest(), step); + fgRemoveRefPred(step->GetTarget(), step); } - step->SetJumpDest(catchStep); + step->SetTarget(catchStep); fgAddRefPred(catchStep, step); /* The new block will inherit this block's weight */ @@ -4958,7 +4958,7 @@ void Compiler::impImportLeave(BasicBlock* block) if (step == nullptr) { - block->SetJumpKind(BBJ_ALWAYS); // convert the BBJ_LEAVE to a BBJ_ALWAYS + block->SetKind(BBJ_ALWAYS); // convert the BBJ_LEAVE to a BBJ_ALWAYS #ifdef DEBUG if (verbose) @@ -4971,13 +4971,13 @@ void Compiler::impImportLeave(BasicBlock* block) } else { - assert((step == block) || !step->HasInitializedJumpDest()); + assert((step == block) || !step->HasInitializedTarget()); if (step == block) { - fgRemoveRefPred(step->GetJumpDest(), step); + fgRemoveRefPred(step->GetTarget(), step); } - step->SetJumpDest(leaveTarget); // this is the ultimate destination of the LEAVE + step->SetTarget(leaveTarget); // this is the ultimate destination of the LEAVE fgAddRefPred(leaveTarget, step); #ifdef DEBUG @@ -5037,9 +5037,9 @@ void Compiler::impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr) // will be treated as pair and handled correctly. if (block->KindIs(BBJ_CALLFINALLY)) { - BasicBlock* dupBlock = BasicBlock::New(this, BBJ_CALLFINALLY, block->GetJumpDest()); + BasicBlock* dupBlock = BasicBlock::New(this, BBJ_CALLFINALLY, block->GetTarget()); dupBlock->CopyFlags(block); - fgAddRefPred(dupBlock->GetJumpDest(), dupBlock); + fgAddRefPred(dupBlock->GetTarget(), dupBlock); dupBlock->copyEHRegion(block); dupBlock->bbCatchTyp = block->bbCatchTyp; @@ -5068,9 +5068,9 @@ void Compiler::impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr) fgInitBBLookup(); - fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKindAndTarget(BBJ_LEAVE, fgLookupBB(jmpAddr)); - fgAddRefPred(block->GetJumpDest(), block); + fgRemoveRefPred(block->GetTarget(), block); + block->SetKindAndTarget(BBJ_LEAVE, fgLookupBB(jmpAddr)); + fgAddRefPred(block->GetTarget(), block); // We will leave the BBJ_ALWAYS block we introduced. When it's reimported // the BBJ_ALWAYS block will be unreachable, and will be removed after. The @@ -6044,7 +6044,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) // Change block to BBJ_THROW so we won't trigger importation of successors. // - block->SetJumpKindAndTarget(BBJ_THROW); + block->SetKindAndTarget(BBJ_THROW); // If this method has a explicit generic context, the only uses of it may be in // the IL for this block. So assume it's used. @@ -7306,7 +7306,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) impResetLeaveBlock(block, jmpAddr); } - assert(jmpAddr == block->GetJumpDest()->bbCodeOffs); + assert(jmpAddr == block->GetTarget()->bbCodeOffs); impImportLeave(block); impNoteBranchOffs(); @@ -7349,10 +7349,13 @@ void Compiler::impImportBlockCode(BasicBlock* block) // if (block->KindIs(BBJ_COND)) { - JITDUMP(FMT_BB " both branches and falls through to " FMT_BB ", changing to BBJ_ALWAYS\n", - block->bbNum, block->Next()->bbNum); - fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKind(BBJ_ALWAYS); + JITDUMP(FMT_BB " always branches to " FMT_BB ", changing to BBJ_ALWAYS\n", block->bbNum, + block->GetFalseTarget()->bbNum); + fgRemoveRefPred(block->GetFalseTarget(), block); + block->SetKind(BBJ_ALWAYS); + + // TODO-NoFallThrough: Once bbFalseTarget can diverge from bbNext, it may not make sense to + // set BBF_NONE_QUIRK block->SetFlags(BBF_NONE_QUIRK); } else @@ -7417,15 +7420,20 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (op1->AsIntCon()->gtIconVal) { JITDUMP("\nThe conditional jump becomes an unconditional jump to " FMT_BB "\n", - block->GetJumpDest()->bbNum); - fgRemoveRefPred(block->Next(), block); - block->SetJumpKind(BBJ_ALWAYS); + block->GetTrueTarget()->bbNum); + fgRemoveRefPred(block->GetFalseTarget(), block); + block->SetKind(BBJ_ALWAYS); } else { + // TODO-NoFallThrough: Update once bbFalseTarget can diverge from bbNext + assert(block->NextIs(block->GetFalseTarget())); JITDUMP("\nThe block jumps to the next " FMT_BB "\n", block->Next()->bbNum); - fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKindAndTarget(BBJ_ALWAYS, block->Next()); + fgRemoveRefPred(block->GetTrueTarget(), block); + block->SetKindAndTarget(BBJ_ALWAYS, block->Next()); + + // TODO-NoFallThrough: Once bbFalseTarget can diverge from bbNext, it may not make sense + // to set BBF_NONE_QUIRK block->SetFlags(BBF_NONE_QUIRK); } } @@ -7597,10 +7605,13 @@ void Compiler::impImportBlockCode(BasicBlock* block) // if (block->KindIs(BBJ_COND)) { - JITDUMP(FMT_BB " both branches and falls through to " FMT_BB ", changing to BBJ_ALWAYS\n", - block->bbNum, block->Next()->bbNum); - fgRemoveRefPred(block->GetJumpDest(), block); - block->SetJumpKind(BBJ_ALWAYS); + JITDUMP(FMT_BB " always branches to " FMT_BB ", changing to BBJ_ALWAYS\n", block->bbNum, + block->GetFalseTarget()->bbNum); + fgRemoveRefPred(block->GetFalseTarget(), block); + block->SetKind(BBJ_ALWAYS); + + // TODO-NoFallThrough: Once bbFalseTarget can diverge from bbNext, it may not make sense to + // set BBF_NONE_QUIRK block->SetFlags(BBF_NONE_QUIRK); } else @@ -7664,8 +7675,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) { // Find the jump target size_t switchVal = (size_t)op1->AsIntCon()->gtIconVal; - unsigned jumpCnt = block->GetJumpSwt()->bbsCount; - BasicBlock** jumpTab = block->GetJumpSwt()->bbsDstTab; + unsigned jumpCnt = block->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTab = block->GetSwitchTargets()->bbsDstTab; bool foundVal = false; for (unsigned val = 0; val < jumpCnt; val++, jumpTab++) @@ -7680,7 +7691,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) if ((val == switchVal) || (!foundVal && (val == jumpCnt - 1))) { // transform the basic block into a BBJ_ALWAYS - block->SetJumpKindAndTarget(BBJ_ALWAYS, curJump); + block->SetKindAndTarget(BBJ_ALWAYS, curJump); foundVal = true; } else @@ -7701,7 +7712,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) { printf("\nSwitch folded at " FMT_BB "\n", block->bbNum); printf(FMT_BB " becomes a %s", block->bbNum, "BBJ_ALWAYS"); - printf(" to " FMT_BB, block->GetJumpDest()->bbNum); + printf(" to " FMT_BB, block->GetTarget()->bbNum); printf("\n"); } #endif @@ -11261,7 +11272,7 @@ void Compiler::impImportBlock(BasicBlock* block) unsigned multRef = impCanReimport ? unsigned(~0) : 0; - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: @@ -11271,12 +11282,12 @@ void Compiler::impImportBlock(BasicBlock* block) /* Note if the next block has more than one ancestor */ - multRef |= block->Next()->bbRefs; + multRef |= block->GetFalseTarget()->bbRefs; /* Does the next block have temps assigned? */ - baseTmp = block->Next()->bbStkTempsIn; - tgtBlock = block->Next(); + baseTmp = block->GetFalseTarget()->bbStkTempsIn; + tgtBlock = block->GetFalseTarget(); if (baseTmp != NO_BASE_TMP) { @@ -11285,15 +11296,15 @@ void Compiler::impImportBlock(BasicBlock* block) /* Try the target of the jump then */ - multRef |= block->GetJumpDest()->bbRefs; - baseTmp = block->GetJumpDest()->bbStkTempsIn; - tgtBlock = block->GetJumpDest(); + multRef |= block->GetTrueTarget()->bbRefs; + baseTmp = block->GetTrueTarget()->bbStkTempsIn; + tgtBlock = block->GetTrueTarget(); break; case BBJ_ALWAYS: - multRef |= block->GetJumpDest()->bbRefs; - baseTmp = block->GetJumpDest()->bbStkTempsIn; - tgtBlock = block->GetJumpDest(); + multRef |= block->GetTarget()->bbRefs; + baseTmp = block->GetTarget()->bbStkTempsIn; + tgtBlock = block->GetTarget(); break; case BBJ_SWITCH: @@ -11325,7 +11336,7 @@ void Compiler::impImportBlock(BasicBlock* block) break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } @@ -12101,7 +12112,7 @@ void Compiler::impImport() entryBlock->SetFlags(BBF_IMPORTED); assert(entryBlock->KindIs(BBJ_ALWAYS)); - entryBlock = entryBlock->GetJumpDest(); + entryBlock = entryBlock->GetTarget(); } // Note for OSR we'd like to be able to verify this block must be @@ -12218,7 +12229,7 @@ void Compiler::impFixPredLists() continue; } - // Count the number of predecessors. Then we can allocate the bbJumpEhf table and fill it in. + // Count the number of predecessors. Then we can allocate the bbEhfTargets table and fill it in. // We only need to count once, since it's invariant with the finally block. if (predCount == (unsigned)-1) { @@ -12271,7 +12282,7 @@ void Compiler::impFixPredLists() assert(predNum == predCount); } - finallyBlock->SetJumpEhf(jumpEhf); + finallyBlock->SetEhfTargets(jumpEhf); } } } diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index 98088b0983fa9..427cc76796bd1 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -222,9 +222,7 @@ class IndirectCallTransformer // // Return Value: // new basic block. - BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, - BasicBlock* insertAfter, - BasicBlock* jumpDest = nullptr) + BasicBlock* CreateAndInsertBasicBlock(BBKinds jumpKind, BasicBlock* insertAfter, BasicBlock* jumpDest = nullptr) { BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true, jumpDest); block->SetFlags(BBF_IMPORTED); @@ -274,18 +272,18 @@ class IndirectCallTransformer if (checkBlock != currBlock) { assert(currBlock->KindIs(BBJ_ALWAYS)); - currBlock->SetJumpDest(checkBlock); + currBlock->SetTarget(checkBlock); compiler->fgAddRefPred(checkBlock, currBlock); } // checkBlock assert(checkBlock->KindIs(BBJ_ALWAYS)); - checkBlock->SetJumpKindAndTarget(BBJ_COND, elseBlock); + checkBlock->SetCond(elseBlock); compiler->fgAddRefPred(elseBlock, checkBlock); compiler->fgAddRefPred(thenBlock, checkBlock); // thenBlock - assert(thenBlock->HasJumpTo(remainderBlock)); + assert(thenBlock->TargetIs(remainderBlock)); compiler->fgAddRefPred(remainderBlock, thenBlock); // elseBlock @@ -593,7 +591,7 @@ class IndirectCallTransformer checkFallsThrough = false; // prevCheckBlock is expected to jump to this new check (if its type check doesn't succeed) - prevCheckBlock->SetJumpKindAndTarget(BBJ_COND, checkBlock); + prevCheckBlock->SetCond(checkBlock); compiler->fgAddRefPred(checkBlock, prevCheckBlock); // Calculate the total likelihood for this check as a sum of likelihoods @@ -1011,7 +1009,7 @@ class IndirectCallTransformer // Also, thenBlock has a single pred - last checkBlock assert(checkBlock->KindIs(BBJ_ALWAYS)); - checkBlock->SetJumpDest(thenBlock); + checkBlock->SetTarget(thenBlock); checkBlock->SetFlags(BBF_NONE_QUIRK); assert(checkBlock->JumpsToNext()); compiler->fgAddRefPred(thenBlock, checkBlock); @@ -1033,7 +1031,7 @@ class IndirectCallTransformer // where we know the last check is always true (in case of "exact" GDV) if (!checkFallsThrough) { - checkBlock->SetJumpKindAndTarget(BBJ_COND, elseBlock); + checkBlock->SetCond(elseBlock); compiler->fgAddRefPred(elseBlock, checkBlock); } else @@ -1111,7 +1109,7 @@ class IndirectCallTransformer BasicBlock* const hotBlock = coldBlock->Prev(); - if (!hotBlock->KindIs(BBJ_ALWAYS) || !hotBlock->HasJumpTo(checkBlock)) + if (!hotBlock->KindIs(BBJ_ALWAYS) || !hotBlock->TargetIs(checkBlock)) { JITDUMP("Unexpected flow from hot path " FMT_BB "\n", hotBlock->bbNum); return; @@ -1156,7 +1154,7 @@ class IndirectCallTransformer // not fall through to the check block. // compiler->fgRemoveRefPred(checkBlock, coldBlock); - coldBlock->SetJumpKindAndTarget(BBJ_ALWAYS, elseBlock); + coldBlock->SetKindAndTarget(BBJ_ALWAYS, elseBlock); compiler->fgAddRefPred(elseBlock, coldBlock); } diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp index 2aad48278ded3..04985af018f41 100644 --- a/src/coreclr/jit/jiteh.cpp +++ b/src/coreclr/jit/jiteh.cpp @@ -3459,7 +3459,7 @@ void Compiler::fgVerifyHandlerTab() } // Check for legal block types - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_EHFINALLYRET: { @@ -4031,7 +4031,7 @@ bool Compiler::fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block) // trying to decide how to split up the predecessor edges. if (predBlock->KindIs(BBJ_CALLFINALLY)) { - assert(predBlock->HasJumpTo(block)); + assert(predBlock->TargetIs(block)); // A BBJ_CALLFINALLY predecessor of the handler can only come from the corresponding try, // not from any EH clauses nested in this handler. However, we represent the BBJ_CALLFINALLY @@ -4321,7 +4321,7 @@ void Compiler::fgExtendEHRegionBefore(BasicBlock* block) #endif // FEATURE_EH_FUNCLETS // If this is a handler for a filter, the last block of the filter will end with - // a BBJ_EHFILTERRET block that has a bbJumpDest that jumps to the first block of + // a BBJ_EHFILTERRET block that has a bbTarget that jumps to the first block of // its handler. So we need to update it to keep things in sync. // if (HBtab->HasFilter()) @@ -4329,17 +4329,17 @@ void Compiler::fgExtendEHRegionBefore(BasicBlock* block) BasicBlock* bFilterLast = HBtab->BBFilterLast(); assert(bFilterLast != nullptr); assert(bFilterLast->KindIs(BBJ_EHFILTERRET)); - assert(bFilterLast->HasJumpTo(block)); + assert(bFilterLast->TargetIs(block)); #ifdef DEBUG if (verbose) { - printf("EH#%u: Updating bbJumpDest for filter ret block: " FMT_BB " => " FMT_BB "\n", + printf("EH#%u: Updating bbTarget for filter ret block: " FMT_BB " => " FMT_BB "\n", ehGetIndex(HBtab), bFilterLast->bbNum, bPrev->bbNum); } #endif // DEBUG - // Change the bbJumpDest for bFilterLast from the old first 'block' to the new first 'bPrev' - fgRemoveRefPred(bFilterLast->GetJumpDest(), bFilterLast); - bFilterLast->SetJumpDest(bPrev); + // Change the bbTarget for bFilterLast from the old first 'block' to the new first 'bPrev' + fgRemoveRefPred(bFilterLast->GetTarget(), bFilterLast); + bFilterLast->SetTarget(bPrev); fgAddRefPred(bPrev, bFilterLast); } } diff --git a/src/coreclr/jit/lir.cpp b/src/coreclr/jit/lir.cpp index cedbc5c0e5918..b10bd98ff6221 100644 --- a/src/coreclr/jit/lir.cpp +++ b/src/coreclr/jit/lir.cpp @@ -1770,7 +1770,7 @@ void LIR::InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range) assert(insertionPoint != nullptr); #if DEBUG - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: assert(insertionPoint->OperIsConditionalJump()); diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index a1cc4c35d8b6d..55c0b74b449f7 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -378,7 +378,7 @@ void Compiler::fgPerBlockLocalVarLiveness() block->bbMemoryLiveIn = fullMemoryKindSet; block->bbMemoryLiveOut = fullMemoryKindSet; - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_EHFINALLYRET: case BBJ_EHFAULTRET: @@ -886,12 +886,12 @@ void Compiler::fgExtendDbgLifetimes() { VarSetOps::ClearD(this, initVars); - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_ALWAYS: case BBJ_EHCATCHRET: case BBJ_EHFILTERRET: - VarSetOps::UnionD(this, initVars, block->GetJumpDest()->bbScope); + VarSetOps::UnionD(this, initVars, block->GetTarget()->bbScope); break; case BBJ_CALLFINALLY: @@ -901,13 +901,13 @@ void Compiler::fgExtendDbgLifetimes() PREFIX_ASSUME(!block->IsLast()); VarSetOps::UnionD(this, initVars, block->Next()->bbScope); } - VarSetOps::UnionD(this, initVars, block->GetJumpDest()->bbScope); + VarSetOps::UnionD(this, initVars, block->GetTarget()->bbScope); break; case BBJ_COND: PREFIX_ASSUME(!block->IsLast()); - VarSetOps::UnionD(this, initVars, block->Next()->bbScope); - VarSetOps::UnionD(this, initVars, block->GetJumpDest()->bbScope); + VarSetOps::UnionD(this, initVars, block->GetFalseTarget()->bbScope); + VarSetOps::UnionD(this, initVars, block->GetTrueTarget()->bbScope); break; case BBJ_SWITCH: @@ -930,7 +930,7 @@ void Compiler::fgExtendDbgLifetimes() break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index b6e52bd9a09e8..f1a027de6f0ed 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -864,8 +864,8 @@ BasicBlock* LoopCloneContext::CondToStmtInBlock(Compiler* newBlk->inheritWeight(insertAfter); newBlk->bbNatLoopNum = insertAfter->bbNatLoopNum; - JITDUMP("Adding " FMT_BB " -> " FMT_BB "\n", newBlk->bbNum, newBlk->GetJumpDest()->bbNum); - comp->fgAddRefPred(newBlk->GetJumpDest(), newBlk); + JITDUMP("Adding " FMT_BB " -> " FMT_BB "\n", newBlk->bbNum, newBlk->GetTrueTarget()->bbNum); + comp->fgAddRefPred(newBlk->GetTrueTarget(), newBlk); if (insertAfter->bbFallsThrough()) { @@ -898,8 +898,8 @@ BasicBlock* LoopCloneContext::CondToStmtInBlock(Compiler* newBlk->inheritWeight(insertAfter); newBlk->bbNatLoopNum = insertAfter->bbNatLoopNum; - JITDUMP("Adding " FMT_BB " -> " FMT_BB "\n", newBlk->bbNum, newBlk->GetJumpDest()->bbNum); - comp->fgAddRefPred(newBlk->GetJumpDest(), newBlk); + JITDUMP("Adding " FMT_BB " -> " FMT_BB "\n", newBlk->bbNum, newBlk->GetTrueTarget()->bbNum); + comp->fgAddRefPred(newBlk->GetTrueTarget(), newBlk); if (insertAfter->bbFallsThrough()) { @@ -1884,7 +1884,7 @@ bool Compiler::optIsLoopClonable(FlowGraphNaturalLoop* loop, LoopCloneContext* c return false; } - if (!oldLoopBottom->HasJumpTo(oldLoopTop)) + if (!oldLoopBottom->TrueTargetIs(oldLoopTop)) { JITDUMP("Loop cloning: rejecting loop " FMT_LP ". Branch at loop 'bottom' not looping to 'top'.\n", loop->GetIndex()); @@ -2058,7 +2058,7 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex } assert(preheader->KindIs(BBJ_ALWAYS)); - assert(preheader->HasJumpTo(loop->GetHeader())); + assert(preheader->TargetIs(loop->GetHeader())); fgReplacePred(loop->GetHeader(), preheader, fastPreheader); JITDUMP("Replace " FMT_BB " -> " FMT_BB " with " FMT_BB " -> " FMT_BB "\n", preheader->bbNum, @@ -2083,6 +2083,9 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex BasicBlock* newPred = bottom; if (bottom->bbFallsThrough()) { + // Once bbFalseTarget can diverge from bbNext, BBJ_COND blocks will "fall through" + // only if bbFalseTarget is still the next block + assert(!bottom->KindIs(BBJ_COND) || bottom->NextIs(bottom->GetFalseTarget())); BasicBlock* bottomNext = bottom->Next(); JITDUMP("Create branch around cloned loop\n"); BasicBlock* bottomRedirBlk = fgNewBBafter(BBJ_ALWAYS, bottom, /*extendRegion*/ true, bottomNext); @@ -2175,9 +2178,10 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex if (blk->KindIs(BBJ_COND)) { // TODO-Quirk: We see a lot of these cases and some of them cause diffs. - BasicBlock* targetBlk = blk->Next(); + BasicBlock* targetBlk = blk->GetFalseTarget(); + assert(blk->NextIs(targetBlk)); if (targetBlk->KindIs(BBJ_ALWAYS) && targetBlk->isEmpty()) - targetBlk = targetBlk->GetJumpDest(); + targetBlk = targetBlk->GetTarget(); // Need to insert a block. BasicBlock* newRedirBlk = fgNewBBafter(BBJ_ALWAYS, newPred, /* extendRegion */ true, targetBlk); @@ -2219,7 +2223,7 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex assert(b && newblk != nullptr); // Jump target should not be set yet - assert(!newblk->HasInitializedJumpDest()); + assert(!newblk->HasInitializedTarget()); // First copy the jump destination(s) from "blk". optCopyBlkDest(blk, newblk); @@ -2228,16 +2232,16 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex optRedirectBlock(newblk, blockMap); // Add predecessor edges for the new successors, as well as the fall-through paths. - switch (newblk->GetJumpKind()) + switch (newblk->GetKind()) { case BBJ_ALWAYS: case BBJ_CALLFINALLY: - fgAddRefPred(newblk->GetJumpDest(), newblk); + fgAddRefPred(newblk->GetTarget(), newblk); break; case BBJ_COND: - fgAddRefPred(newblk->Next(), newblk); - fgAddRefPred(newblk->GetJumpDest(), newblk); + fgAddRefPred(newblk->GetFalseTarget(), newblk); + fgAddRefPred(newblk->GetTrueTarget(), newblk); break; case BBJ_SWITCH: @@ -2294,8 +2298,8 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex // We haven't set the jump target yet assert(slowPreheader->KindIs(BBJ_ALWAYS)); - assert(!slowPreheader->HasInitializedJumpDest()); - slowPreheader->SetJumpDest(slowHeader); + assert(!slowPreheader->HasInitializedTarget()); + slowPreheader->SetTarget(slowHeader); fgAddRefPred(slowHeader, slowPreheader); JITDUMP("Adding " FMT_BB " -> " FMT_BB "\n", slowPreheader->bbNum, slowHeader->bbNum); @@ -2304,7 +2308,8 @@ void Compiler::optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* contex // Now redirect the old preheader to jump to the first new condition that // was inserted by the above function. - preheader->SetJumpDest(preheader->Next()); + assert(preheader->KindIs(BBJ_ALWAYS)); + preheader->SetTarget(preheader->Next()); fgAddRefPred(preheader->Next(), preheader); preheader->SetFlags(BBF_NONE_QUIRK); @@ -2965,8 +2970,10 @@ bool Compiler::optCheckLoopCloningGDVTestProfitable(GenTreeOp* guard, LoopCloneV // Check for (4) // - BasicBlock* const hotSuccessor = guard->OperIs(GT_EQ) ? typeTestBlock->GetJumpDest() : typeTestBlock->Next(); - BasicBlock* const coldSuccessor = guard->OperIs(GT_EQ) ? typeTestBlock->Next() : typeTestBlock->GetJumpDest(); + BasicBlock* const hotSuccessor = + guard->OperIs(GT_EQ) ? typeTestBlock->GetTrueTarget() : typeTestBlock->GetFalseTarget(); + BasicBlock* const coldSuccessor = + guard->OperIs(GT_EQ) ? typeTestBlock->GetFalseTarget() : typeTestBlock->GetTrueTarget(); if (!hotSuccessor->hasProfileWeight() || !coldSuccessor->hasProfileWeight()) { diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index c996b78f48f20..fa98f068dc53e 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -846,8 +846,8 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // jumpCnt is the number of elements in the jump table array. // jumpTab is the actual pointer to the jump table array. // targetCnt is the number of unique targets in the jump table array. - jumpCnt = originalSwitchBB->GetJumpSwt()->bbsCount; - jumpTab = originalSwitchBB->GetJumpSwt()->bbsDstTab; + jumpCnt = originalSwitchBB->GetSwitchTargets()->bbsCount; + jumpTab = originalSwitchBB->GetSwitchTargets()->bbsDstTab; targetCnt = originalSwitchBB->NumSucc(comp); // GT_SWITCH must be a top-level node with no use. @@ -867,7 +867,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) { JITDUMP("Lowering switch " FMT_BB ": single target; converting to BBJ_ALWAYS\n", originalSwitchBB->bbNum); noway_assert(comp->opts.OptimizationDisabled()); - originalSwitchBB->SetJumpKindAndTarget(BBJ_ALWAYS, jumpTab[0]); + originalSwitchBB->SetKindAndTarget(BBJ_ALWAYS, jumpTab[0]); if (originalSwitchBB->JumpsToNext()) { @@ -959,13 +959,13 @@ GenTree* Lowering::LowerSwitch(GenTree* node) assert(originalSwitchBB->KindIs(BBJ_ALWAYS)); assert(originalSwitchBB->NextIs(afterDefaultCondBlock)); assert(afterDefaultCondBlock->KindIs(BBJ_SWITCH)); - assert(afterDefaultCondBlock->GetJumpSwt()->bbsHasDefault); + assert(afterDefaultCondBlock->GetSwitchTargets()->bbsHasDefault); assert(afterDefaultCondBlock->isEmpty()); // Nothing here yet. // The GT_SWITCH code is still in originalSwitchBB (it will be removed later). // Turn originalSwitchBB into a BBJ_COND. - originalSwitchBB->SetJumpKindAndTarget(BBJ_COND, jumpTab[jumpCnt - 1]); + originalSwitchBB->SetCond(jumpTab[jumpCnt - 1]); // Fix the pred for the default case: the default block target still has originalSwitchBB // as a predecessor, but the fgSplitBlockAfterStatement() moved all predecessors to point @@ -1020,7 +1020,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) (void)comp->fgRemoveRefPred(uniqueSucc, afterDefaultCondBlock); } - afterDefaultCondBlock->SetJumpKindAndTarget(BBJ_ALWAYS, uniqueSucc); + afterDefaultCondBlock->SetKindAndTarget(BBJ_ALWAYS, uniqueSucc); if (afterDefaultCondBlock->JumpsToNext()) { @@ -1094,13 +1094,13 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // case: there is no need to compare against the case index, since it's // guaranteed to be taken (since the default case was handled first, above). - currentBlock->SetJumpKindAndTarget(BBJ_ALWAYS, jumpTab[i]); + currentBlock->SetKindAndTarget(BBJ_ALWAYS, jumpTab[i]); } else { // Otherwise, it's a conditional branch. Set the branch kind, then add the // condition statement. - currentBlock->SetJumpKindAndTarget(BBJ_COND, jumpTab[i]); + currentBlock->SetCond(jumpTab[i]); // Now, build the conditional statement for the current case that is // being evaluated: @@ -1133,7 +1133,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) JITDUMP("Lowering switch " FMT_BB ": all switch cases were fall-through\n", originalSwitchBB->bbNum); assert(currentBlock == afterDefaultCondBlock); assert(currentBlock->KindIs(BBJ_SWITCH)); - currentBlock->SetJumpKindAndTarget(BBJ_ALWAYS, currentBlock->Next()); + currentBlock->SetKindAndTarget(BBJ_ALWAYS, currentBlock->Next()); currentBlock->RemoveFlags(BBF_DONT_REMOVE); comp->fgRemoveBlock(currentBlock, /* unreachable */ false); // It's an empty block. } @@ -1168,7 +1168,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) switchBlockRange.InsertAfter(switchValue, switchTable, switchJump); // this block no longer branches to the default block - afterDefaultCondBlock->GetJumpSwt()->removeDefault(); + afterDefaultCondBlock->GetSwitchTargets()->removeDefault(); } comp->fgInvalidateSwitchDescMapEntry(afterDefaultCondBlock); @@ -1312,7 +1312,7 @@ bool Lowering::TryLowerSwitchToBitTest( { // GenCondition::C generates JC so we jump to bbCase1 when the bit is set bbSwitchCondition = GenCondition::C; - bbSwitch->SetJumpKindAndTarget(BBJ_COND, bbCase1); + bbSwitch->SetCond(bbCase1); comp->fgAddRefPred(bbCase0, bbSwitch); comp->fgAddRefPred(bbCase1, bbSwitch); @@ -1323,7 +1323,7 @@ bool Lowering::TryLowerSwitchToBitTest( // GenCondition::NC generates JNC so we jump to bbCase0 when the bit is not set bbSwitchCondition = GenCondition::NC; - bbSwitch->SetJumpKindAndTarget(BBJ_COND, bbCase0); + bbSwitch->SetCond(bbCase0); comp->fgAddRefPred(bbCase0, bbSwitch); comp->fgAddRefPred(bbCase1, bbSwitch); diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 7b1b55b211387..1747c5a5955ec 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -2545,7 +2545,8 @@ BasicBlock* LinearScan::findPredBlockForLiveIn(BasicBlock* block, if (predBlock->KindIs(BBJ_COND)) { // Special handling to improve matching on backedges. - BasicBlock* otherBlock = predBlock->NextIs(block) ? predBlock->GetJumpDest() : predBlock->Next(); + BasicBlock* otherBlock = + predBlock->FalseTargetIs(block) ? predBlock->GetTrueTarget() : predBlock->GetFalseTarget(); noway_assert(otherBlock != nullptr); if (isBlockVisited(otherBlock) && !blockInfo[otherBlock->bbNum].hasEHBoundaryIn) { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 002f0b196e572..0a0afe09800fc 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -6156,8 +6156,8 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) // Many tailcalls will have call and ret in the same block, and thus be // BBJ_RETURN, but if the call falls through to a ret, and we are doing a // tailcall, change it here. - // (compCurBB may have a jump target, so use SetJumpKind() to avoid nulling it) - compCurBB->SetJumpKind(BBJ_RETURN); + // (compCurBB may have a jump target, so use SetKind() to avoid nulling it) + compCurBB->SetKind(BBJ_RETURN); } GenTree* stmtExpr = fgMorphStmt->GetRootNode(); @@ -6308,7 +6308,7 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) { // We call CORINFO_HELP_TAILCALL which does not return, so we will // not need epilogue. - compCurBB->SetJumpKindAndTarget(BBJ_THROW); + compCurBB->SetKindAndTarget(BBJ_THROW); } if (isRootReplaced) @@ -7446,7 +7446,7 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa { // Todo: this may not look like a viable loop header. // Might need the moral equivalent of a scratch BB. - block->SetJumpKindAndTarget(BBJ_ALWAYS, fgEntryBB); + block->SetKindAndTarget(BBJ_ALWAYS, fgEntryBB); } else { @@ -7461,11 +7461,11 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa // block removal on it. // fgFirstBB->SetFlags(BBF_DONT_REMOVE); - block->SetJumpKindAndTarget(BBJ_ALWAYS, fgFirstBB->Next()); + block->SetKindAndTarget(BBJ_ALWAYS, fgFirstBB->Next()); } // Finish hooking things up. - fgAddRefPred(block->GetJumpDest(), block); + fgAddRefPred(block->GetTarget(), block); block->RemoveFlags(BBF_HAS_JMP); } @@ -13158,7 +13158,8 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) * Remove the conditional statement */ noway_assert(cond->gtOper == GT_CNS_INT); - noway_assert((block->Next()->countOfInEdges() > 0) && (block->GetJumpDest()->countOfInEdges() > 0)); + noway_assert((block->GetFalseTarget()->countOfInEdges() > 0) && + (block->GetTrueTarget()->countOfInEdges() > 0)); if (condTree != cond) { @@ -13183,25 +13184,25 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) if (cond->AsIntCon()->gtIconVal != 0) { /* JTRUE 1 - transform the basic block into a BBJ_ALWAYS */ - block->SetJumpKind(BBJ_ALWAYS); - bTaken = block->GetJumpDest(); - bNotTaken = block->Next(); + bTaken = block->GetTrueTarget(); + bNotTaken = block->GetFalseTarget(); + block->SetKind(BBJ_ALWAYS); } else { /* Unmark the loop if we are removing a backwards branch */ /* dest block must also be marked as a loop head and */ /* We must be able to reach the backedge block */ - if (block->GetJumpDest()->isLoopHead() && (block->GetJumpDest()->bbNum <= block->bbNum) && - fgReachable(block->GetJumpDest(), block)) + if (block->GetTrueTarget()->isLoopHead() && (block->GetTrueTarget()->bbNum <= block->bbNum) && + fgReachable(block->GetTrueTarget(), block)) { - optUnmarkLoopBlocks(block->GetJumpDest(), block); + optUnmarkLoopBlocks(block->GetTrueTarget(), block); } /* JTRUE 0 - transform the basic block into a BBJ_ALWAYS */ - bTaken = block->Next(); - bNotTaken = block->GetJumpDest(); - block->SetJumpKindAndTarget(BBJ_ALWAYS, bTaken); + bTaken = block->GetFalseTarget(); + bNotTaken = block->GetTrueTarget(); + block->SetKindAndTarget(BBJ_ALWAYS, bTaken); block->SetFlags(BBF_NONE_QUIRK); } @@ -13255,17 +13256,22 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) FlowEdge* edge; // Now fix the weights of the edges out of 'bUpdated' - switch (bUpdated->GetJumpKind()) + switch (bUpdated->GetKind()) { case BBJ_COND: - edge = fgGetPredForBlock(bUpdated->Next(), bUpdated); + edge = fgGetPredForBlock(bUpdated->GetFalseTarget(), bUpdated); newMaxWeight = bUpdated->bbWeight; newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); - edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->Next()); - FALLTHROUGH; + edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->GetFalseTarget()); + + edge = fgGetPredForBlock(bUpdated->GetTrueTarget(), bUpdated); + newMaxWeight = bUpdated->bbWeight; + newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); + edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->GetFalseTarget()); + break; case BBJ_ALWAYS: - edge = fgGetPredForBlock(bUpdated->GetJumpDest(), bUpdated); + edge = fgGetPredForBlock(bUpdated->GetTarget(), bUpdated); newMaxWeight = bUpdated->bbWeight; newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->Next()); @@ -13288,7 +13294,7 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) { printf("\nConditional folded at " FMT_BB "\n", block->bbNum); printf(FMT_BB " becomes a %s", block->bbNum, "BBJ_ALWAYS"); - printf(" to " FMT_BB, block->GetJumpDest()->bbNum); + printf(" to " FMT_BB, block->GetTarget()->bbNum); printf("\n"); } #endif @@ -13401,8 +13407,8 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) // Find the actual jump target size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal; - unsigned jumpCnt = block->GetJumpSwt()->bbsCount; - BasicBlock** jumpTab = block->GetJumpSwt()->bbsDstTab; + unsigned jumpCnt = block->GetSwitchTargets()->bbsCount; + BasicBlock** jumpTab = block->GetSwitchTargets()->bbsDstTab; bool foundVal = false; for (unsigned val = 0; val < jumpCnt; val++, jumpTab++) @@ -13416,7 +13422,7 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) if ((val == switchVal) || (!foundVal && (val == jumpCnt - 1))) { - block->SetJumpKindAndTarget(BBJ_ALWAYS, curJump); + block->SetKindAndTarget(BBJ_ALWAYS, curJump); foundVal = true; } else @@ -13437,7 +13443,7 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) { printf("\nConditional folded at " FMT_BB "\n", block->bbNum); printf(FMT_BB " becomes a %s", block->bbNum, "BBJ_ALWAYS"); - printf(" to " FMT_BB, block->GetJumpDest()->bbNum); + printf(" to " FMT_BB, block->GetTarget()->bbNum); printf("\n"); } #endif @@ -13897,14 +13903,14 @@ void Compiler::fgMorphBlock(BasicBlock* block, unsigned highestReachablePostorde if (useCondAssertions) { - if (block == pred->GetJumpDest()) + if (block == pred->GetTrueTarget()) { JITDUMP("Using `if true` assertions from pred " FMT_BB "\n", pred->bbNum); assertionsOut = pred->bbAssertionOutIfTrue; } else { - assert(block == pred->Next()); + assert(block == pred->GetFalseTarget()); JITDUMP("Using `if false` assertions from pred " FMT_BB "\n", pred->bbNum); assertionsOut = pred->bbAssertionOutIfFalse; } @@ -14177,7 +14183,7 @@ void Compiler::fgMergeBlockReturn(BasicBlock* block) else #endif // !TARGET_X86 { - block->SetJumpKindAndTarget(BBJ_ALWAYS, genReturnBB); + block->SetKindAndTarget(BBJ_ALWAYS, genReturnBB); fgAddRefPred(genReturnBB, block); fgReturnCount--; } @@ -14674,7 +14680,7 @@ bool Compiler::fgExpandQmarkForCastInstOf(BasicBlock* block, Statement* stmt) // Chain the flow correctly. assert(block->KindIs(BBJ_ALWAYS)); - block->SetJumpDest(asgBlock); + block->SetTarget(asgBlock); fgAddRefPred(asgBlock, block); fgAddRefPred(cond1Block, asgBlock); fgAddRefPred(cond2Block, cond1Block); @@ -14873,9 +14879,9 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) condBlock->inheritWeight(block); assert(block->KindIs(BBJ_ALWAYS)); - block->SetJumpDest(condBlock); - condBlock->SetJumpDest(elseBlock); - elseBlock->SetJumpDest(remainderBlock); + block->SetTarget(condBlock); + condBlock->SetTarget(elseBlock); + elseBlock->SetTarget(remainderBlock); assert(condBlock->JumpsToNext()); assert(elseBlock->JumpsToNext()); @@ -14898,7 +14904,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) // bbj_cond(true) // gtReverseCond(condExpr); - condBlock->SetJumpKindAndTarget(BBJ_COND, elseBlock); + condBlock->SetCond(elseBlock); thenBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true, remainderBlock); thenBlock->SetFlags(propagateFlagsToAll); @@ -14923,7 +14929,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) // bbj_cond(true) // gtReverseCond(condExpr); - condBlock->SetJumpKindAndTarget(BBJ_COND, remainderBlock); + condBlock->SetCond(remainderBlock); fgAddRefPred(remainderBlock, condBlock); // Since we have no false expr, use the one we'd already created. thenBlock = elseBlock; @@ -14939,7 +14945,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) // +-->------------+ // bbj_cond(true) // - condBlock->SetJumpKindAndTarget(BBJ_COND, remainderBlock); + condBlock->SetCond(remainderBlock); fgAddRefPred(remainderBlock, condBlock); elseBlock->inheritWeightPercentage(condBlock, 50); diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index ca159980a138f..76058748e3baf 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -46,7 +46,7 @@ class OptBoolsDsc private: BasicBlock* m_b1; // The first basic block with the BBJ_COND conditional jump type BasicBlock* m_b2; // The next basic block of m_b1. Either BBJ_COND or BBJ_RETURN type - BasicBlock* m_b3; // m_b1->bbJumpDest. Null if m_b2 is not a return block. + BasicBlock* m_b3; // m_b1->bbTarget. Null if m_b2 is not a return block. Compiler* m_comp; // The pointer to the Compiler instance @@ -81,7 +81,7 @@ class OptBoolsDsc }; //----------------------------------------------------------------------------- -// optOptimizeBoolsCondBlock: Optimize boolean when bbJumpKind of both m_b1 and m_b2 are BBJ_COND +// optOptimizeBoolsCondBlock: Optimize boolean when bbKind of both m_b1 and m_b2 are BBJ_COND // // Returns: // true if boolean optimization is done and m_b1 and m_b2 are folded into m_b1, else false. @@ -89,7 +89,7 @@ class OptBoolsDsc // Notes: // m_b1 and m_b2 are set on entry. // -// Case 1: if b1.bbJumpDest == b2.bbJumpDest, it transforms +// Case 1: if b1.bbTarget == b2.bbTarget, it transforms // B1 : brtrue(t1, Bx) // B2 : brtrue(t2, Bx) // B3 : @@ -107,7 +107,7 @@ class OptBoolsDsc // B3: GT_RETURN (BBJ_RETURN) // B4: GT_RETURN (BBJ_RETURN) // -// Case 2: if B2->NextIs(B1.bbJumpDest), it transforms +// Case 2: if B2->FalseTargetIs(B1.bbTarget), it transforms // B1 : brtrue(t1, B3) // B2 : brtrue(t2, Bx) // B3 : @@ -123,9 +123,9 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() m_t3 = nullptr; - // Check if m_b1 and m_b2 have the same bbJumpDest + // Check if m_b1 and m_b2 have the same bbTarget - if (m_b1->HasJumpTo(m_b2->GetJumpDest())) + if (m_b1->TrueTargetIs(m_b2->GetTrueTarget())) { // Given the following sequence of blocks : // B1: brtrue(t1, BX) @@ -137,7 +137,7 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock() m_sameTarget = true; } - else if (m_b2->NextIs(m_b1->GetJumpDest())) + else if (m_b2->FalseTargetIs(m_b1->GetTrueTarget())) { // Given the following sequence of blocks : // B1: brtrue(t1, B3) @@ -726,7 +726,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() { // At this point we have two consecutive conditional blocks (BBJ_COND): m_b1 and m_b2 assert((m_b1 != nullptr) && (m_b2 != nullptr) && (m_b3 == nullptr)); - assert(m_b1->KindIs(BBJ_COND) && m_b2->KindIs(BBJ_COND) && m_b1->NextIs(m_b2)); + assert(m_b1->KindIs(BBJ_COND) && m_b2->KindIs(BBJ_COND) && m_b1->FalseTargetIs(m_b2)); if (m_b2->isRunRarely()) { @@ -741,7 +741,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() return false; } - if (m_b1->HasJumpTo(m_b1) || m_b1->HasJumpTo(m_b2) || m_b2->HasJumpTo(m_b2) || m_b2->HasJumpTo(m_b1)) + if (m_b1->TrueTargetIs(m_b1) || m_b1->TrueTargetIs(m_b2) || m_b2->TrueTargetIs(m_b2) || m_b2->TrueTargetIs(m_b1)) { // Ignoring weird cases like a condition jumping to itself or when JumpDest == Next return false; @@ -749,9 +749,9 @@ bool OptBoolsDsc::optOptimizeRangeTests() // We're interested in just two shapes for e.g. "X > 10 && X < 100" range test: // - BasicBlock* notInRangeBb = m_b1->GetJumpDest(); + BasicBlock* notInRangeBb = m_b1->GetTrueTarget(); BasicBlock* inRangeBb; - if (notInRangeBb == m_b2->GetJumpDest()) + if (notInRangeBb == m_b2->GetTrueTarget()) { // Shape 1: both conditions jump to NotInRange // @@ -763,9 +763,9 @@ bool OptBoolsDsc::optOptimizeRangeTests() // // InRange: // ... - inRangeBb = m_b2->Next(); + inRangeBb = m_b2->GetFalseTarget(); } - else if (notInRangeBb == m_b2->Next()) + else if (notInRangeBb == m_b2->GetFalseTarget()) { // Shape 2: 2nd block jumps to InRange // @@ -777,7 +777,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() // // NotInRange: // ... - inRangeBb = m_b2->GetJumpDest(); + inRangeBb = m_b2->GetTrueTarget(); } else { @@ -800,7 +800,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() const bool cmp1IsReversed = true; // cmp2 can be either reversed or not - const bool cmp2IsReversed = m_b2->HasJumpTo(notInRangeBb); + const bool cmp2IsReversed = m_b2->TrueTargetIs(notInRangeBb); if (!FoldRangeTests(m_comp, cmp1, cmp1IsReversed, cmp2, cmp2IsReversed)) { @@ -811,7 +811,7 @@ bool OptBoolsDsc::optOptimizeRangeTests() if (!cmp2IsReversed) { // Re-direct firstBlock to jump to inRangeBb - m_b1->SetJumpDest(inRangeBb); + m_b1->SetTrueTarget(inRangeBb); } // Remove the 2nd condition block as we no longer need it @@ -901,13 +901,13 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() m_t3 = nullptr; bool foundEndOfOrConditions = false; - if (m_b1->NextIs(m_b2) && m_b2->NextIs(m_b1->GetJumpDest())) + if (m_b1->FalseTargetIs(m_b2) && m_b2->FalseTargetIs(m_b1->GetTrueTarget())) { // Found the end of two (or more) conditions being ORed together. // The final condition has been inverted. foundEndOfOrConditions = true; } - else if (m_b1->NextIs(m_b2) && m_b1->HasJumpTo(m_b2->GetJumpDest())) + else if (m_b1->FalseTargetIs(m_b2) && m_b1->TrueTargetIs(m_b2->GetTrueTarget())) { // Found two conditions connected together. } @@ -1007,8 +1007,8 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() m_comp->fgSetStmtSeq(s2); // Update the flow. - m_comp->fgRemoveRefPred(m_b1->GetJumpDest(), m_b1); - m_b1->SetJumpKindAndTarget(BBJ_ALWAYS, m_b1->Next()); + m_comp->fgRemoveRefPred(m_b1->GetTrueTarget(), m_b1); + m_b1->SetKindAndTarget(BBJ_ALWAYS, m_b1->GetFalseTarget()); m_b1->SetFlags(BBF_NONE_QUIRK); // Fixup flags. @@ -1261,22 +1261,22 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() { // Update edges if m_b1: BBJ_COND and m_b2: BBJ_COND - FlowEdge* edge1 = m_comp->fgGetPredForBlock(m_b1->GetJumpDest(), m_b1); + FlowEdge* edge1 = m_comp->fgGetPredForBlock(m_b1->GetTrueTarget(), m_b1); FlowEdge* edge2; if (m_sameTarget) { - edge2 = m_comp->fgGetPredForBlock(m_b2->GetJumpDest(), m_b2); + edge2 = m_comp->fgGetPredForBlock(m_b2->GetTrueTarget(), m_b2); } else { - edge2 = m_comp->fgGetPredForBlock(m_b2->Next(), m_b2); + edge2 = m_comp->fgGetPredForBlock(m_b2->GetFalseTarget(), m_b2); - m_comp->fgRemoveRefPred(m_b1->GetJumpDest(), m_b1); + m_comp->fgRemoveRefPred(m_b1->GetTrueTarget(), m_b1); - m_b1->SetJumpDest(m_b2->GetJumpDest()); + m_b1->SetTrueTarget(m_b2->GetTrueTarget()); - m_comp->fgAddRefPred(m_b2->GetJumpDest(), m_b1); + m_comp->fgAddRefPred(m_b2->GetTrueTarget(), m_b1); } assert(edge1 != nullptr); @@ -1286,11 +1286,11 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() weight_t edgeSumMax = edge1->edgeWeightMax() + edge2->edgeWeightMax(); if ((edgeSumMax >= edge1->edgeWeightMax()) && (edgeSumMax >= edge2->edgeWeightMax())) { - edge1->setEdgeWeights(edgeSumMin, edgeSumMax, m_b1->GetJumpDest()); + edge1->setEdgeWeights(edgeSumMin, edgeSumMax, m_b1->GetTrueTarget()); } else { - edge1->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT, m_b1->GetJumpDest()); + edge1->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT, m_b1->GetTrueTarget()); } } @@ -1298,17 +1298,17 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() if (optReturnBlock) { - m_b1->SetJumpKindAndTarget(BBJ_RETURN); assert(m_b2->KindIs(BBJ_RETURN)); - assert(m_b1->NextIs(m_b2)); + assert(m_b1->FalseTargetIs(m_b2)); assert(m_b3 != nullptr); + m_b1->SetKindAndTarget(BBJ_RETURN); } else { assert(m_b1->KindIs(BBJ_COND)); assert(m_b2->KindIs(BBJ_COND)); - assert(m_b1->HasJumpTo(m_b2->GetJumpDest())); - assert(m_b1->NextIs(m_b2)); + assert(m_b1->TrueTargetIs(m_b2->GetTrueTarget())); + assert(m_b1->FalseTargetIs(m_b2)); assert(!m_b2->IsLast()); } @@ -1317,9 +1317,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // Update bbRefs and bbPreds // // Replace pred 'm_b2' for 'm_b2->bbNext' with 'm_b1' - // Remove pred 'm_b2' for 'm_b2->bbJumpDest' - m_comp->fgReplacePred(m_b2->Next(), m_b2, m_b1); - m_comp->fgRemoveRefPred(m_b2->GetJumpDest(), m_b2); + // Remove pred 'm_b2' for 'm_b2->bbTarget' + m_comp->fgReplacePred(m_b2->GetFalseTarget(), m_b2, m_b1); + m_comp->fgRemoveRefPred(m_b2->GetTrueTarget(), m_b2); } // Get rid of the second block @@ -1361,7 +1361,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() // Notes: // m_b1, m_b2 and m_b3 of OptBoolsDsc are set on entry. // -// if B1.bbJumpDest == b3, it transforms +// if B1.bbTarget == b3, it transforms // B1 : brtrue(t1, B3) // B2 : ret(t2) // B3 : ret(0) @@ -1894,7 +1894,7 @@ PhaseStatus Compiler::optOptimizeBools() // If there is no next block, we're done - BasicBlock* b2 = b1->Next(); + BasicBlock* b2 = b1->GetFalseTarget(); if (b2 == nullptr) { break; @@ -1912,7 +1912,7 @@ PhaseStatus Compiler::optOptimizeBools() if (b2->KindIs(BBJ_COND)) { - if (!b1->HasJumpTo(b2->GetJumpDest()) && !b2->NextIs(b1->GetJumpDest())) + if (!b1->TrueTargetIs(b2->GetTrueTarget()) && !b2->FalseTargetIs(b1->GetTrueTarget())) { continue; } @@ -1944,7 +1944,7 @@ PhaseStatus Compiler::optOptimizeBools() else if (b2->KindIs(BBJ_RETURN)) { // Set b3 to b1 jump destination - BasicBlock* b3 = b1->GetJumpDest(); + BasicBlock* b3 = b1->GetTrueTarget(); // b3 must not be marked as BBF_DONT_REMOVE diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 2a546d4d40cb5..0471f68509e92 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -497,16 +497,27 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar reportAfter(); } - if ((skipUnmarkLoop == false) && // If we want to unmark this loop... - block->KindIs(BBJ_ALWAYS, BBJ_COND) && // This block reaches conditionally or always - block->GetJumpDest()->isLoopHead() && // to a loop head... - (fgCurBBEpochSize == fgBBNumMax + 1) && // We didn't add new blocks since last renumber... - (block->GetJumpDest()->bbNum <= block->bbNum) && // This is a backedge... - fgDomsComputed && // Given the doms are computed and valid... - (fgCurBBEpochSize == fgDomBBcount + 1) && // - fgReachable(block->GetJumpDest(), block)) // Block's destination (target of back edge) can reach block... + if (!skipUnmarkLoop && // If we want to unmark this loop... + (fgCurBBEpochSize == fgBBNumMax + 1) && // We didn't add new blocks since last renumber... + fgDomsComputed && // Given the doms are computed and valid... + (fgCurBBEpochSize == fgDomBBcount + 1)) { - optUnmarkLoopBlocks(block->GetJumpDest(), block); // Unscale the blocks in such loop. + // This block must reach conditionally or always + + if (block->KindIs(BBJ_ALWAYS) && // This block always reaches + block->GetTarget()->isLoopHead() && // to a loop head... + (block->GetTarget()->bbNum <= block->bbNum) && // This is a backedge... + fgReachable(block->GetTarget(), block)) // Block's back edge target can reach block... + { + optUnmarkLoopBlocks(block->GetTarget(), block); // Unscale the blocks in such loop. + } + else if (block->KindIs(BBJ_COND) && // This block conditionally reaches + block->GetTrueTarget()->isLoopHead() && // to a loop head... + (block->GetTrueTarget()->bbNum <= block->bbNum) && // This is a backedge... + fgReachable(block->GetTrueTarget(), block)) // Block's back edge target can reach block... + { + optUnmarkLoopBlocks(block->GetTrueTarget(), block); // Unscale the blocks in such loop. + } } } @@ -742,7 +753,7 @@ bool Compiler::optPopulateInitInfo(unsigned loopInd, BasicBlock* initBlock, GenT bool initBlockOk = (predBlock == initBlock); if (!initBlockOk) { - if (predBlock->KindIs(BBJ_ALWAYS) && predBlock->HasJumpTo(optLoopTable[loopInd].lpEntry) && + if (predBlock->KindIs(BBJ_ALWAYS) && predBlock->TargetIs(optLoopTable[loopInd].lpEntry) && (predBlock->countOfInEdges() == 1) && (predBlock->firstStmt() == nullptr) && !predBlock->IsFirst() && predBlock->Prev()->bbFallsThrough()) { @@ -1137,7 +1148,7 @@ bool Compiler::optExtractInitTestIncr( // If we are rebuilding the loop table, we would already have the pre-header block introduced // the first time, which might be empty if no hoisting has yet occurred. In this case, look a // little harder for the possible loop initialization statement. - if (initBlock->KindIs(BBJ_ALWAYS) && initBlock->HasJumpTo(top) && (initBlock->countOfInEdges() == 1) && + if (initBlock->KindIs(BBJ_ALWAYS) && initBlock->TargetIs(top) && (initBlock->countOfInEdges() == 1) && !initBlock->IsFirst() && initBlock->Prev()->bbFallsThrough()) { initBlock = initBlock->Prev(); @@ -1372,19 +1383,19 @@ void Compiler::optCheckPreds() } } noway_assert(bb); - switch (bb->GetJumpKind()) + switch (bb->GetKind()) { case BBJ_COND: - if (bb->HasJumpTo(block)) + if (bb->TrueTargetIs(block)) { break; } - noway_assert(bb->NextIs(block)); + noway_assert(bb->FalseTargetIs(block)); break; case BBJ_EHFILTERRET: case BBJ_ALWAYS: case BBJ_EHCATCHRET: - noway_assert(bb->HasJumpTo(block)); + noway_assert(bb->TargetIs(block)); break; default: break; @@ -1773,10 +1784,10 @@ class LoopSearch { if (head->KindIs(BBJ_ALWAYS)) { - if (head->GetJumpDest()->bbNum <= bottom->bbNum && head->GetJumpDest()->bbNum >= top->bbNum) + if (head->GetTarget()->bbNum <= bottom->bbNum && head->GetTarget()->bbNum >= top->bbNum) { // OK - we enter somewhere within the loop. - return head->GetJumpDest(); + return head->GetTarget(); } else { @@ -2114,7 +2125,8 @@ class LoopSearch if (newMoveAfter->KindIs(BBJ_ALWAYS, BBJ_COND)) { - unsigned int destNum = newMoveAfter->GetJumpDest()->bbNum; + unsigned int destNum = newMoveAfter->KindIs(BBJ_ALWAYS) ? newMoveAfter->GetTarget()->bbNum + : newMoveAfter->GetTrueTarget()->bbNum; if ((destNum >= top->bbNum) && (destNum <= bottom->bbNum) && !loopBlocks.IsMember(destNum)) { // Reversing this branch out of block `newMoveAfter` could confuse this algorithm @@ -2263,7 +2275,7 @@ class LoopSearch { // Need to reconnect the flow from `block` to `oldNext`. - if (block->KindIs(BBJ_COND) && block->HasJumpTo(newNext)) + if (block->KindIs(BBJ_COND) && block->TrueTargetIs(newNext)) { // Reverse the jump condition GenTree* test = block->lastNode(); @@ -2281,7 +2293,7 @@ class LoopSearch } // Redirect the Conditional JUMP to go to `oldNext` - block->SetJumpDest(oldNext); + block->SetTrueTarget(oldNext); } else { @@ -2290,7 +2302,7 @@ class LoopSearch noway_assert((newBlock == nullptr) || loopBlocks.CanRepresent(newBlock->bbNum)); } } - else if (block->KindIs(BBJ_ALWAYS) && block->HasJumpTo(newNext)) + else if (block->KindIs(BBJ_ALWAYS) && block->TargetIs(newNext)) { // If block is newNext's only predecessor, move the IR from block to newNext, // but keep the now-empty block around. @@ -2356,14 +2368,14 @@ class LoopSearch { BasicBlock* exitPoint; - switch (block->GetJumpKind()) + switch (block->GetKind()) { case BBJ_COND: case BBJ_CALLFINALLY: case BBJ_ALWAYS: case BBJ_EHCATCHRET: - assert(block->HasInitializedJumpDest()); - exitPoint = block->GetJumpDest(); + assert(block->HasInitializedTarget()); + exitPoint = block->KindIs(BBJ_COND) ? block->GetTrueTarget() : block->GetTarget(); if (!loopBlocks.IsMember(exitPoint->bbNum)) { @@ -2414,7 +2426,7 @@ class LoopSearch break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } @@ -2693,7 +2705,7 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R BasicBlock* newJumpDest = nullptr; - switch (blk->GetJumpKind()) + switch (blk->GetKind()) { case BBJ_THROW: case BBJ_RETURN: @@ -2713,15 +2725,34 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R FALLTHROUGH; case BBJ_LEAVE: case BBJ_CALLFINALLY: - case BBJ_COND: // All of these have a single jump destination to update. - if (redirectMap->Lookup(blk->GetJumpDest(), &newJumpDest)) + if (redirectMap->Lookup(blk->GetTarget(), &newJumpDest)) + { + if (updatePreds) + { + fgRemoveRefPred(blk->GetTarget(), blk); + } + blk->SetTarget(newJumpDest); + if (updatePreds || addPreds) + { + fgAddRefPred(newJumpDest, blk); + } + } + else if (addPreds) + { + fgAddRefPred(blk->GetTarget(), blk); + } + break; + + case BBJ_COND: + // Update jump taken when condition is true + if (redirectMap->Lookup(blk->GetTrueTarget(), &newJumpDest)) { if (updatePreds) { - fgRemoveRefPred(blk->GetJumpDest(), blk); + fgRemoveRefPred(blk->GetTrueTarget(), blk); } - blk->SetJumpDest(newJumpDest); + blk->SetTrueTarget(newJumpDest); if (updatePreds || addPreds) { fgAddRefPred(newJumpDest, blk); @@ -2729,13 +2760,13 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R } else if (addPreds) { - fgAddRefPred(blk->GetJumpDest(), blk); + fgAddRefPred(blk->GetTrueTarget(), blk); } break; case BBJ_EHFINALLYRET: { - BBehfDesc* ehfDesc = blk->GetJumpEhf(); + BBehfDesc* ehfDesc = blk->GetEhfTargets(); BasicBlock* newSucc = nullptr; for (unsigned i = 0; i < ehfDesc->bbeCount; i++) { @@ -2763,9 +2794,9 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R case BBJ_SWITCH: { bool redirected = false; - for (unsigned i = 0; i < blk->GetJumpSwt()->bbsCount; i++) + for (unsigned i = 0; i < blk->GetSwitchTargets()->bbsCount; i++) { - BasicBlock* const switchDest = blk->GetJumpSwt()->bbsDstTab[i]; + BasicBlock* const switchDest = blk->GetSwitchTargets()->bbsDstTab[i]; if (redirectMap->Lookup(switchDest, &newJumpDest)) { if (updatePreds) @@ -2776,8 +2807,8 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R { fgAddRefPred(newJumpDest, blk); } - blk->GetJumpSwt()->bbsDstTab[i] = newJumpDest; - redirected = true; + blk->GetSwitchTargets()->bbsDstTab[i] = newJumpDest; + redirected = true; } else if (addPreds) { @@ -2806,21 +2837,24 @@ void Compiler::optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap, R void Compiler::optCopyBlkDest(BasicBlock* from, BasicBlock* to) { // copy the jump destination(s) from "from" to "to". - switch (from->GetJumpKind()) + switch (from->GetKind()) { case BBJ_SWITCH: - to->SetSwitchKindAndTarget(new (this, CMK_BasicBlock) BBswtDesc(this, from->GetJumpSwt())); + to->SetSwitch(new (this, CMK_BasicBlock) BBswtDesc(this, from->GetSwitchTargets())); break; case BBJ_EHFINALLYRET: - to->SetJumpKindAndTarget(BBJ_EHFINALLYRET, new (this, CMK_BasicBlock) BBehfDesc(this, from->GetJumpEhf())); + to->SetEhf(new (this, CMK_BasicBlock) BBehfDesc(this, from->GetEhfTargets())); + break; + case BBJ_COND: + to->SetCond(from->GetTrueTarget()); break; default: - to->SetJumpKindAndTarget(from->GetJumpKind(), from->GetJumpDest()); + to->SetKindAndTarget(from->GetKind(), from->GetTarget()); to->CopyFlags(from, BBF_NONE_QUIRK); break; } - assert(to->KindIs(from->GetJumpKind())); + assert(to->KindIs(from->GetKind())); } // Returns true if 'block' is an entry block for any loop in 'optLoopTable' @@ -2919,7 +2953,7 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd) // entry block. If the `head` branches to `top` because it is the BBJ_ALWAYS of a // BBJ_CALLFINALLY/BBJ_ALWAYS pair, we canonicalize by introducing a new fall-through // head block. See FindEntry() for the logic that allows this. - if (h->KindIs(BBJ_ALWAYS) && h->HasJumpTo(t) && h->HasFlag(BBF_KEEP_BBJ_ALWAYS)) + if (h->KindIs(BBJ_ALWAYS) && h->TargetIs(t) && h->HasFlag(BBF_KEEP_BBJ_ALWAYS)) { // Insert new head @@ -2927,7 +2961,7 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd) newH->SetFlags(BBF_NONE_QUIRK); newH->inheritWeight(h); newH->bbNatLoopNum = h->bbNatLoopNum; - h->SetJumpDest(newH); + h->SetTarget(newH); fgRemoveRefPred(t, h); fgAddRefPred(newH, h); @@ -3015,7 +3049,7 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd) // BasicBlock* const t = optLoopTable[loopInd].lpTop; assert(siblingB->KindIs(BBJ_COND)); - assert(siblingB->NextIs(t)); + assert(siblingB->FalseTargetIs(t)); JITDUMP(FMT_LP " head " FMT_BB " is also " FMT_LP " bottom\n", loopInd, h->bbNum, sibling); @@ -3190,8 +3224,8 @@ bool Compiler::optCanonicalizeLoopCore(unsigned char loopInd, LoopCanonicalizati // Because of this, introducing a block before t automatically gives us // the right flow out of h. // - assert(h->NextIs(t) || !h->KindIs(BBJ_COND)); - assert(h->HasJumpTo(t) || !h->KindIs(BBJ_ALWAYS)); + assert(!h->KindIs(BBJ_COND) || h->FalseTargetIs(t)); + assert(!h->KindIs(BBJ_ALWAYS) || h->TargetIs(t)); assert(h->KindIs(BBJ_ALWAYS, BBJ_COND)); // If the bottom block is in the same "try" region, then we extend the EH @@ -3203,12 +3237,12 @@ bool Compiler::optCanonicalizeLoopCore(unsigned char loopInd, LoopCanonicalizati if (h->KindIs(BBJ_COND)) { - BasicBlock* const hj = h->GetJumpDest(); + BasicBlock* const hj = h->GetTrueTarget(); assert((hj->bbNum < t->bbNum) || (hj->bbNum > b->bbNum)); } else { - h->SetJumpDest(newT); + h->SetTarget(newT); } fgRemoveRefPred(t, h); @@ -3352,7 +3386,7 @@ bool Compiler::optCanonicalizeLoopCore(unsigned char loopInd, LoopCanonicalizati { assert(newT->KindIs(BBJ_ALWAYS)); if ((optLoopTable[childLoop].lpEntry == origE) && (optLoopTable[childLoop].lpHead == h) && - newT->HasJumpTo(origE)) + newT->TargetIs(origE)) { optUpdateLoopHead(childLoop, h, newT); @@ -3424,7 +3458,7 @@ BasicBlock* Compiler::optLoopEntry(BasicBlock* preHeader) { assert(preHeader->HasFlag(BBF_LOOP_PREHEADER)); assert(preHeader->KindIs(BBJ_ALWAYS)); - return preHeader->GetJumpDest(); + return preHeader->GetTarget(); } //----------------------------------------------------------------------------- @@ -4381,7 +4415,7 @@ PhaseStatus Compiler::optUnrollLoops() // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them. assert(newBlock->KindIs(BBJ_ALWAYS)); - assert(!newBlock->HasInitializedJumpDest()); + assert(!newBlock->HasInitializedTarget()); if (block == bottom) { @@ -4405,12 +4439,12 @@ PhaseStatus Compiler::optUnrollLoops() // Now redirect any branches within the newly-cloned iteration. // Don't include `bottom` in the iteration, since we've already changed the - // newBlock->bbJumpKind, above. + // newBlock->bbKind, above. for (BasicBlock* block = loop.lpTop; block != loop.lpBottom; block = block->Next()) { // Jump kind/target should not be set yet BasicBlock* newBlock = blockMap[block]; - assert(!newBlock->HasInitializedJumpDest()); + assert(!newBlock->HasInitializedTarget()); // Now copy the jump kind/target optCopyBlkDest(block, newBlock); @@ -4427,8 +4461,8 @@ PhaseStatus Compiler::optUnrollLoops() if (clonedTopPrev->KindIs(BBJ_ALWAYS)) { - assert(!clonedTopPrev->HasInitializedJumpDest()); - clonedTopPrev->SetJumpDest(clonedTop); + assert(!clonedTopPrev->HasInitializedTarget()); + clonedTopPrev->SetTarget(clonedTop); } fgAddRefPred(clonedTop, clonedTop->Prev()); @@ -4483,7 +4517,7 @@ PhaseStatus Compiler::optUnrollLoops() fgRemoveAllRefPreds(succ, block); } - block->SetJumpKindAndTarget(BBJ_ALWAYS, block->Next()); + block->SetKindAndTarget(BBJ_ALWAYS, block->Next()); block->bbStmtList = nullptr; block->bbNatLoopNum = newLoopNum; block->SetFlags(BBF_NONE_QUIRK); @@ -4527,8 +4561,11 @@ PhaseStatus Compiler::optUnrollLoops() Statement* initBlockBranchStmt = initBlock->lastStmt(); noway_assert(initBlockBranchStmt->GetRootNode()->OperIs(GT_JTRUE)); fgRemoveStmt(initBlock, initBlockBranchStmt); - fgRemoveRefPred(initBlock->GetJumpDest(), initBlock); - initBlock->SetJumpKindAndTarget(BBJ_ALWAYS, initBlock->Next()); + fgRemoveRefPred(initBlock->GetTrueTarget(), initBlock); + initBlock->SetKindAndTarget(BBJ_ALWAYS, initBlock->GetFalseTarget()); + + // TODO-NoFallThrough: If bbFalseTarget can diverge from bbNext, it may not make sense to set + // BBF_NONE_QUIRK initBlock->SetFlags(BBF_NONE_QUIRK); } else @@ -4558,9 +4595,9 @@ PhaseStatus Compiler::optUnrollLoops() { BasicBlock* clonedBottom = blockMap[bottom]; assert(clonedBottom->KindIs(BBJ_ALWAYS)); - assert(!clonedBottom->HasInitializedJumpDest()); + assert(!clonedBottom->HasInitializedTarget()); - clonedBottom->SetJumpDest(tail); + clonedBottom->SetTarget(tail); fgAddRefPred(tail, clonedBottom); fgRemoveRefPred(tail, bottom); } @@ -4768,7 +4805,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) } // Get hold of the jump target - BasicBlock* const bTest = block->GetJumpDest(); + BasicBlock* const bTest = block->GetTarget(); // Does the bTest consist of 'jtrue(cond) block' ? if (!bTest->KindIs(BBJ_COND)) @@ -4779,16 +4816,16 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) // bTest must be a backwards jump to block->bbNext // This will be the top of the loop. // - BasicBlock* const bTop = bTest->GetJumpDest(); + BasicBlock* const bTop = bTest->GetTrueTarget(); if (!block->NextIs(bTop)) { return false; } - // Since bTest is a BBJ_COND it will have a bbNext + // Since bTest is a BBJ_COND it will have a bbFalseTarget // - BasicBlock* const bJoin = bTest->Next(); + BasicBlock* const bJoin = bTest->GetFalseTarget(); noway_assert(bJoin != nullptr); // 'block' must be in the same try region as the condition, since we're going to insert a duplicated condition @@ -4800,7 +4837,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) return false; } - // The duplicated condition block will branch to bTest->Next(), so that also better be in the + // The duplicated condition block will branch to bTest->GetFalseTarget(), so that also better be in the // same try region (or no try region) to avoid generating illegal flow. if (bJoin->hasTryIndex() && !BasicBlock::sameTryRegion(block, bJoin)) { @@ -4808,10 +4845,10 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) } // It has to be a forward jump. Defer this check until after all the cheap checks - // are done, since it iterates forward in the block list looking for bbJumpDest. + // are done, since it iterates forward in the block list looking for bbTarget. // TODO-CQ: Check if we can also optimize the backwards jump as well. // - if (!fgIsForwardBranch(block)) + if (!fgIsForwardBranch(block, block->GetTarget())) { return false; } @@ -4999,7 +5036,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) // Create a new block after `block` to put the copied condition code. BasicBlock* bNewCond = fgNewBBafter(BBJ_COND, block, /*extendRegion*/ true, bJoin); - block->SetJumpKindAndTarget(BBJ_ALWAYS, bNewCond); + block->SetKindAndTarget(BBJ_ALWAYS, bNewCond); block->SetFlags(BBF_NONE_QUIRK); assert(block->JumpsToNext()); @@ -5137,7 +5174,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) weight_t const testToAfterWeight = weightTop * testToAfterLikelihood; FlowEdge* const edgeTestToNext = fgGetPredForBlock(bTop, bTest); - FlowEdge* const edgeTestToAfter = fgGetPredForBlock(bTest->Next(), bTest); + FlowEdge* const edgeTestToAfter = fgGetPredForBlock(bTest->GetFalseTarget(), bTest); JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (iterate loop)\n", bTest->bbNum, bTop->bbNum, testToNextWeight); @@ -5145,7 +5182,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) bTest->Next()->bbNum, testToAfterWeight); edgeTestToNext->setEdgeWeights(testToNextWeight, testToNextWeight, bTop); - edgeTestToAfter->setEdgeWeights(testToAfterWeight, testToAfterWeight, bTest->Next()); + edgeTestToAfter->setEdgeWeights(testToAfterWeight, testToAfterWeight, bTest->GetFalseTarget()); // Adjust edges out of block, using the same distribution. // @@ -5157,16 +5194,16 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) weight_t const blockToNextWeight = weightBlock * blockToNextLikelihood; weight_t const blockToAfterWeight = weightBlock * blockToAfterLikelihood; - FlowEdge* const edgeBlockToNext = fgGetPredForBlock(bNewCond->Next(), bNewCond); - FlowEdge* const edgeBlockToAfter = fgGetPredForBlock(bNewCond->GetJumpDest(), bNewCond); + FlowEdge* const edgeBlockToNext = fgGetPredForBlock(bNewCond->GetFalseTarget(), bNewCond); + FlowEdge* const edgeBlockToAfter = fgGetPredForBlock(bNewCond->GetTrueTarget(), bNewCond); JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (enter loop)\n", bNewCond->bbNum, - bNewCond->Next()->bbNum, blockToNextWeight); + bNewCond->GetFalseTarget()->bbNum, blockToNextWeight); JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (avoid loop)\n", bNewCond->bbNum, - bNewCond->GetJumpDest()->bbNum, blockToAfterWeight); + bNewCond->GetTrueTarget()->bbNum, blockToAfterWeight); - edgeBlockToNext->setEdgeWeights(blockToNextWeight, blockToNextWeight, bNewCond->Next()); - edgeBlockToAfter->setEdgeWeights(blockToAfterWeight, blockToAfterWeight, bNewCond->GetJumpDest()); + edgeBlockToNext->setEdgeWeights(blockToNextWeight, blockToNextWeight, bNewCond->GetFalseTarget()); + edgeBlockToAfter->setEdgeWeights(blockToAfterWeight, blockToAfterWeight, bNewCond->GetTrueTarget()); #ifdef DEBUG // If we're checkig profile data, see if profile for the two target blocks is consistent. @@ -5174,8 +5211,8 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) if ((activePhaseChecks & PhaseChecks::CHECK_PROFILE) == PhaseChecks::CHECK_PROFILE) { const ProfileChecks checks = (ProfileChecks)JitConfig.JitProfileChecks(); - const bool nextProfileOk = fgDebugCheckIncomingProfileData(bNewCond->Next(), checks); - const bool jumpProfileOk = fgDebugCheckIncomingProfileData(bNewCond->GetJumpDest(), checks); + const bool nextProfileOk = fgDebugCheckIncomingProfileData(bNewCond->GetFalseTarget(), checks); + const bool jumpProfileOk = fgDebugCheckIncomingProfileData(bNewCond->GetTrueTarget(), checks); if (hasFlag(checks, ProfileChecks::RAISE_ASSERT)) { @@ -5190,7 +5227,7 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block) if (verbose) { printf("\nDuplicated loop exit block at " FMT_BB " for loop (" FMT_BB " - " FMT_BB ")\n", bNewCond->bbNum, - bNewCond->Next()->bbNum, bTest->bbNum); + bNewCond->GetFalseTarget()->bbNum, bTest->bbNum); printf("Estimated code size expansion is %d\n", estDupCostSz); fgDumpBlock(bNewCond); @@ -8176,13 +8213,13 @@ bool Compiler::fgCreateLoopPreHeader(unsigned lnum) { // Allow for either the fall-through or branch to target 'entry'. BasicBlock* skipLoopBlock; - if (head->NextIs(entry)) + if (head->FalseTargetIs(entry)) { - skipLoopBlock = head->GetJumpDest(); + skipLoopBlock = head->GetTrueTarget(); } else { - skipLoopBlock = head->Next(); + skipLoopBlock = head->GetFalseTarget(); } assert(skipLoopBlock != entry); @@ -8273,17 +8310,17 @@ bool Compiler::fgCreateLoopPreHeader(unsigned lnum) continue; } - switch (predBlock->GetJumpKind()) + switch (predBlock->GetKind()) { case BBJ_COND: - if (predBlock->HasJumpTo(entry)) + if (predBlock->TrueTargetIs(entry)) { - predBlock->SetJumpDest(preHead); - noway_assert(!predBlock->NextIs(preHead)); + predBlock->SetTrueTarget(preHead); + noway_assert(!predBlock->FalseTargetIs(preHead)); } else { - noway_assert((entry == top) && (predBlock == head) && predBlock->NextIs(preHead)); + noway_assert((entry == top) && (predBlock == head) && predBlock->FalseTargetIs(preHead)); } fgRemoveRefPred(entry, predBlock); fgAddRefPred(preHead, predBlock); @@ -8291,17 +8328,17 @@ bool Compiler::fgCreateLoopPreHeader(unsigned lnum) case BBJ_ALWAYS: case BBJ_EHCATCHRET: - noway_assert(predBlock->HasJumpTo(entry)); - predBlock->SetJumpDest(preHead); + noway_assert(predBlock->TargetIs(entry)); + predBlock->SetTarget(preHead); fgRemoveRefPred(entry, predBlock); fgAddRefPred(preHead, predBlock); break; case BBJ_SWITCH: unsigned jumpCnt; - jumpCnt = predBlock->GetJumpSwt()->bbsCount; + jumpCnt = predBlock->GetSwitchTargets()->bbsCount; BasicBlock** jumpTab; - jumpTab = predBlock->GetJumpSwt()->bbsDstTab; + jumpTab = predBlock->GetSwitchTargets()->bbsDstTab; do { @@ -8319,7 +8356,7 @@ bool Compiler::fgCreateLoopPreHeader(unsigned lnum) break; default: - noway_assert(!"Unexpected bbJumpKind"); + noway_assert(!"Unexpected bbKind"); break; } } diff --git a/src/coreclr/jit/patchpoint.cpp b/src/coreclr/jit/patchpoint.cpp index b2e5e74934090..2306d0a54a4b5 100644 --- a/src/coreclr/jit/patchpoint.cpp +++ b/src/coreclr/jit/patchpoint.cpp @@ -105,7 +105,7 @@ class PatchpointTransformer // // Return Value: // new basic block. - BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter, BasicBlock* jumpDest = nullptr) + BasicBlock* CreateAndInsertBasicBlock(BBKinds jumpKind, BasicBlock* insertAfter, BasicBlock* jumpDest = nullptr) { BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true, jumpDest); block->SetFlags(BBF_IMPORTED); @@ -146,7 +146,7 @@ class PatchpointTransformer BasicBlock* helperBlock = CreateAndInsertBasicBlock(BBJ_ALWAYS, block, block->Next()); // Update flow and flags - block->SetJumpKindAndTarget(BBJ_COND, remainderBlock); + block->SetCond(remainderBlock); block->SetFlags(BBF_INTERNAL); helperBlock->SetFlags(BBF_BACKWARD_JUMP | BBF_NONE_QUIRK); @@ -233,7 +233,7 @@ class PatchpointTransformer } // Update flow - block->SetJumpKindAndTarget(BBJ_THROW); + block->SetKindAndTarget(BBJ_THROW); // Add helper call // diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 6a6397d57aaaf..d1bfc0aaf4ff9 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -941,7 +941,8 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE JITDUMP("Merge assertions from pred " FMT_BB " edge: ", pred->bbNum); Compiler::optDumpAssertionIndices(assertions, "\n"); } - else if (pred->KindIs(BBJ_COND, BBJ_ALWAYS) && pred->HasJumpTo(block)) + else if ((pred->KindIs(BBJ_ALWAYS) && pred->TargetIs(block)) || + (pred->KindIs(BBJ_COND) && pred->TrueTargetIs(block))) { if (m_pCompiler->bbJtrueAssertionOut != nullptr) { diff --git a/src/coreclr/jit/redundantbranchopts.cpp b/src/coreclr/jit/redundantbranchopts.cpp index 6647e8ebda470..823514a1d8b48 100644 --- a/src/coreclr/jit/redundantbranchopts.cpp +++ b/src/coreclr/jit/redundantbranchopts.cpp @@ -47,8 +47,8 @@ PhaseStatus Compiler::optRedundantBranches() { bool madeChangesThisBlock = m_compiler->optRedundantRelop(block); - BasicBlock* const bbNext = block->Next(); - BasicBlock* const bbJump = block->GetJumpDest(); + BasicBlock* const bbNext = block->GetFalseTarget(); + BasicBlock* const bbJump = block->GetTrueTarget(); madeChangesThisBlock |= m_compiler->optRedundantBranch(block); @@ -566,8 +566,8 @@ bool Compiler::optRedundantBranch(BasicBlock* const block) const bool domIsSameRelop = (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Same) || (rii.vnRelation == ValueNumStore::VN_RELATION_KIND::VRK_Swap); - BasicBlock* const trueSuccessor = domBlock->GetJumpDest(); - BasicBlock* const falseSuccessor = domBlock->Next(); + BasicBlock* const trueSuccessor = domBlock->GetTrueTarget(); + BasicBlock* const falseSuccessor = domBlock->GetFalseTarget(); // If we can trace the flow from the dominating relop, we can infer its value. // @@ -601,7 +601,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block) // const bool relopIsTrue = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop); JITDUMP("Jump successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n", - domBlock->GetJumpDest()->bbNum, domBlock->bbNum, dspTreeID(tree), + domBlock->GetTrueTarget()->bbNum, domBlock->bbNum, dspTreeID(tree), relopIsTrue ? "true" : "false"); relopValue = relopIsTrue ? 1 : 0; break; @@ -612,7 +612,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block) // const bool relopIsFalse = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop); JITDUMP("Fall through successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n", - domBlock->Next()->bbNum, domBlock->bbNum, dspTreeID(tree), + domBlock->GetFalseTarget()->bbNum, domBlock->bbNum, dspTreeID(tree), relopIsFalse ? "false" : "true"); relopValue = relopIsFalse ? 0 : 1; break; @@ -709,8 +709,8 @@ struct JumpThreadInfo { JumpThreadInfo(Compiler* comp, BasicBlock* block) : m_block(block) - , m_trueTarget(block->GetJumpDest()) - , m_falseTarget(block->Next()) + , m_trueTarget(block->GetTrueTarget()) + , m_falseTarget(block->GetFalseTarget()) , m_fallThroughPred(nullptr) , m_ambiguousVNBlock(nullptr) , m_truePreds(BlockSetOps::MakeEmpty(comp)) @@ -1071,8 +1071,8 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl // latter should prove useful in subsequent work, where we aim to enable jump // threading in cases where block has side effects. // - BasicBlock* const domTrueSuccessor = domIsSameRelop ? domBlock->GetJumpDest() : domBlock->Next(); - BasicBlock* const domFalseSuccessor = domIsSameRelop ? domBlock->Next() : domBlock->GetJumpDest(); + BasicBlock* const domTrueSuccessor = domIsSameRelop ? domBlock->GetTrueTarget() : domBlock->GetFalseTarget(); + BasicBlock* const domFalseSuccessor = domIsSameRelop ? domBlock->GetFalseTarget() : domBlock->GetTrueTarget(); JumpThreadInfo jti(this, block); for (BasicBlock* const predBlock : block->PredBlocks()) @@ -1454,7 +1454,7 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti) jti.m_block->bbNum, fallThroughIsTruePred ? "true" : "false", fallThroughIsTruePred ? "false" : "true", jti.m_fallThroughPred->bbNum); - assert(jti.m_fallThroughPred->HasJumpTo(jti.m_block)); + assert(jti.m_fallThroughPred->TargetIs(jti.m_block)); } else { @@ -1523,7 +1523,7 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti) fgRemoveStmt(jti.m_block, lastStmt); JITDUMP(" repurposing " FMT_BB " to always jump to " FMT_BB "\n", jti.m_block->bbNum, jti.m_trueTarget->bbNum); fgRemoveRefPred(jti.m_falseTarget, jti.m_block); - jti.m_block->SetJumpKind(BBJ_ALWAYS); + jti.m_block->SetKind(BBJ_ALWAYS); } else if (falsePredsWillReuseBlock) { @@ -1532,7 +1532,7 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti) JITDUMP(" repurposing " FMT_BB " to always fall through to " FMT_BB "\n", jti.m_block->bbNum, jti.m_falseTarget->bbNum); fgRemoveRefPred(jti.m_trueTarget, jti.m_block); - jti.m_block->SetJumpKindAndTarget(BBJ_ALWAYS, jti.m_falseTarget); + jti.m_block->SetKindAndTarget(BBJ_ALWAYS, jti.m_falseTarget); jti.m_block->SetFlags(BBF_NONE_QUIRK); assert(jti.m_block->JumpsToNext()); } diff --git a/src/coreclr/jit/switchrecognition.cpp b/src/coreclr/jit/switchrecognition.cpp index 4a2135506477e..7d8defae3b4c6 100644 --- a/src/coreclr/jit/switchrecognition.cpp +++ b/src/coreclr/jit/switchrecognition.cpp @@ -95,10 +95,10 @@ bool IsConstantTestCondBlock(const BasicBlock* block, } *isReversed = rootNode->gtGetOp1()->OperIs(GT_NE); - *blockIfTrue = *isReversed ? block->Next() : block->GetJumpDest(); - *blockIfFalse = *isReversed ? block->GetJumpDest() : block->Next(); + *blockIfTrue = *isReversed ? block->GetFalseTarget() : block->GetTrueTarget(); + *blockIfFalse = *isReversed ? block->GetTrueTarget() : block->GetFalseTarget(); - if (block->JumpsToNext() || block->HasJumpTo(block)) + if (block->FalseTargetIs(block) || block->TrueTargetIs(block)) { // Ignoring weird cases like a condition jumping to itself return false; @@ -320,7 +320,7 @@ bool Compiler::optSwitchConvert(BasicBlock* firstBlock, int testsCount, ssize_t* assert(isTest); // Convert firstBlock to a switch block - firstBlock->SetSwitchKindAndTarget(new (this, CMK_BasicBlock) BBswtDesc); + firstBlock->SetSwitch(new (this, CMK_BasicBlock) BBswtDesc); firstBlock->bbCodeOffsEnd = lastBlock->bbCodeOffsEnd; firstBlock->lastStmt()->GetRootNode()->ChangeOper(GT_SWITCH); @@ -351,10 +351,10 @@ bool Compiler::optSwitchConvert(BasicBlock* firstBlock, int testsCount, ssize_t* assert((jumpCount > 0) && (jumpCount <= SWITCH_MAX_DISTANCE + 1)); const auto jmpTab = new (this, CMK_BasicBlock) BasicBlock*[jumpCount + 1 /*default case*/]; - fgHasSwitch = true; - firstBlock->GetJumpSwt()->bbsCount = jumpCount + 1; - firstBlock->GetJumpSwt()->bbsHasDefault = true; - firstBlock->GetJumpSwt()->bbsDstTab = jmpTab; + fgHasSwitch = true; + firstBlock->GetSwitchTargets()->bbsCount = jumpCount + 1; + firstBlock->GetSwitchTargets()->bbsHasDefault = true; + firstBlock->GetSwitchTargets()->bbsDstTab = jmpTab; firstBlock->SetNext(isReversed ? blockIfTrue : blockIfFalse); // Splitting doesn't work well with jump-tables currently diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 773f51f988808..ec330c09a210d 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9738,7 +9738,7 @@ class ValueNumberState } bool isTaken = normalVN != m_comp->vnStore->VNZeroForType(TYP_INT); - BasicBlock* unreachableSucc = isTaken ? predBlock->Next() : predBlock->GetJumpDest(); + BasicBlock* unreachableSucc = isTaken ? predBlock->GetFalseTarget() : predBlock->GetTrueTarget(); return block != unreachableSucc; } };