diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b2acfa5e21f7db..d117aef56220b9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6947,7 +6947,7 @@ class Compiler void fgDebugCheckFlagsHelper(GenTree* tree, GenTreeFlags actualFlags, GenTreeFlags expectedFlags); void fgDebugCheckTryFinallyExits(); void fgDebugCheckProfile(PhaseChecks checks = PhaseChecks::CHECK_NONE); - bool fgDebugCheckProfileWeights(ProfileChecks checks); + bool fgDebugCheckProfileWeights(ProfileChecks checks, bool dump = false); bool fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks checks); bool fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks checks); diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 00a3661c5f6dac..eed8abc111b65e 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -4595,6 +4595,8 @@ void Compiler::fgDebugCheckProfile(PhaseChecks checks) // // Arguments: // checks - checker options +// dump - if true, report inconsistencies via JITDUMP without asserting (used by the +// re-run below to log details before the initial pass asserts) // // Returns: // True if all enabled checks pass @@ -4610,7 +4612,7 @@ void Compiler::fgDebugCheckProfile(PhaseChecks checks) // There's no point checking until we've built pred lists, as // we can't easily reason about consistency without them. // -bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks) +bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks, bool dump) { // We can check classic (min/max, late computed) weights // and/or @@ -4845,13 +4847,20 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks) // Note we only assert when we think the profile data should be consistent. // - if (assertOnFailure) + if (assertOnFailure && !dump) { + // Re-run with dumping forced on so the offending blocks are logged before we assert. + // + const bool wasVerbose = verbose; + verbose = true; + fgDebugCheckProfileWeights(checks, /* dump */ true); + verbose = wasVerbose; + assert(!"Inconsistent profile data"); } } - if (unflaggedBlocks > 0) + if ((unflaggedBlocks > 0) && !dump) { JITDUMP("%d blocks are missing BBF_PROF_WEIGHT flag.\n", unflaggedBlocks); assert(!"Missing BBF_PROF_WEIGHT flag"); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index f1dd62dfcc2ae8..640756f6275d31 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1306,15 +1306,17 @@ GenTree* Lowering::LowerSwitch(GenTree* node) bool profileInconsistent = false; for (unsigned i = 0; i < targetCnt; i++) { - FlowEdge* const edge = uniqueSuccs[i]; - weight_t const oldEdgeWeight = edge->getLikelyWeight(); + FlowEdge* const edge = uniqueSuccs[i]; edge->setLikelihood(newLikelihood * edge->getDupCount()); - weight_t const newEdgeWeight = edge->getLikelyWeight(); if (afterDefaultCondBlock->hasProfileWeight()) { + // Recompute the target's weight from its incoming edges rather than adjusting + // it incrementally: the earlier default-peel scaled afterDefaultCondBlock's + // weight but left the switch targets' weights stale, so an incremental update + // would accumulate on top of a stale value (see #130785). BasicBlock* const targetBlock = edge->getDestinationBlock(); - targetBlock->increaseBBProfileWeight(newEdgeWeight - oldEdgeWeight); + targetBlock->setBBProfileWeight(targetBlock->computeIncomingWeight()); profileInconsistent |= (targetBlock->NumSucc() > 0); } }