From 1d9af3c29f40ce9deb5f9856e54d0ddd20f728dd Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Wed, 13 Mar 2024 19:29:32 -0700 Subject: [PATCH] Add edge likelihood dumping; fix one edge likelihood update case 1. Add dumping of edge likelihood numbers to the block table and other block dumping. Examples: `BB17(0.143)`, `BB18(1)`. Edge likelihood dumping is parameterized in the code, but is currently always enabled. 2. Update `setLikelihood` and `updateLikelihood` to print the previous value of the likelihood that is being updated (if there is a previous value). 3. Fix a case of likelihood updating in `fgReplaceJumpTarget()`: in a switch block, when the new target block is already a target of the switch, then there already exists an edge from the switch to the new target. In that case, we were updating the edge dup count, but `fgAddRefPred` wasn't updating the edge likelihood to add the removed edge likelihood to the existing edge likelihood. This was found as part of work to fix JitOptRepeat: https://github.com/dotnet/runtime/pull/94250. 4. Add natvis debugger support for FlowEdge. 5. In 'fgDebugCheckOutgoingProfileData()`, if outgoing likelihoods are invalid, print out all the likelihoods of the outgoing edges. --- src/coreclr/jit/block.cpp | 65 +++++++++++++++-------- src/coreclr/jit/block.h | 29 ++++++++++- src/coreclr/jit/clrjit.natvis | 10 ++-- src/coreclr/jit/compiler.h | 8 ++- src/coreclr/jit/fgbasic.cpp | 46 +++++++++++++++-- src/coreclr/jit/fgdiagnostic.cpp | 85 +++++++++++++++++++------------ src/coreclr/jit/fgopt.cpp | 1 + src/coreclr/jit/fgprofile.cpp | 19 +++++++ src/coreclr/jit/jitconfigvalues.h | 6 ++- src/coreclr/jit/optimizer.cpp | 11 ++-- 10 files changed, 209 insertions(+), 71 deletions(-) diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index ec81d028c43a5..1e7750997a103 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -79,11 +79,20 @@ void FlowEdge::setLikelihood(weight_t likelihood) { assert(likelihood >= 0.0); assert(likelihood <= 1.0); + + if (m_likelihoodSet) + { + JITDUMP("setting likelihood of " FMT_BB " -> " FMT_BB " from " FMT_WT " to " FMT_WT "\n", m_sourceBlock->bbNum, + m_destBlock->bbNum, m_likelihood, likelihood); + } + else + { + JITDUMP("setting likelihood of " FMT_BB " -> " FMT_BB " to " FMT_WT "\n", m_sourceBlock->bbNum, + m_destBlock->bbNum, likelihood); + } + m_likelihoodSet = true; m_likelihood = likelihood; - - JITDUMP("setting likelihood of " FMT_BB " -> " FMT_BB " to " FMT_WT "\n", m_sourceBlock->bbNum, m_destBlock->bbNum, - m_likelihood); } //------------------------------------------------------------------------ @@ -114,10 +123,11 @@ void FlowEdge::addLikelihood(weight_t addedLikelihood) assert(newLikelihood >= 0.0); assert(newLikelihood <= 1.0); - m_likelihood = newLikelihood; - JITDUMP("updating likelihood of " FMT_BB " -> " FMT_BB " to " FMT_WT "\n", m_sourceBlock->bbNum, m_destBlock->bbNum, - m_likelihood); + JITDUMP("updating likelihood of " FMT_BB " -> " FMT_BB " from " FMT_WT " to " FMT_WT "\n", m_sourceBlock->bbNum, + m_destBlock->bbNum, m_likelihood, newLikelihood); + + m_likelihood = newLikelihood; } //------------------------------------------------------------------------ @@ -678,20 +688,33 @@ void BasicBlock::dspSuccs(Compiler* compiler) // things strictly. void BasicBlock::dspKind() const { - auto dspBlockNum = [](const BasicBlock* b) -> const char* { + auto dspBlockNum = [](const FlowEdge* e) -> const char* { static char buffers[3][64]; // static array of 3 to allow 3 concurrent calls in one printf() static int nextBufferIndex = 0; - auto& buffer = buffers[nextBufferIndex]; - nextBufferIndex = (nextBufferIndex + 1) % ArrLen(buffers); + auto& buffer = buffers[nextBufferIndex]; + nextBufferIndex = (nextBufferIndex + 1) % ArrLen(buffers); + const size_t sizeOfBuffer = ArrLen(buffer); + int written; + const BasicBlock* b = e->getDestinationBlock(); if (b == nullptr) { - _snprintf_s(buffer, ArrLen(buffer), ArrLen(buffer), "NULL"); + written = _snprintf_s(buffer, sizeOfBuffer, sizeOfBuffer, "NULL"); } else { - _snprintf_s(buffer, ArrLen(buffer), ArrLen(buffer), FMT_BB, b->bbNum); + written = _snprintf_s(buffer, sizeOfBuffer, sizeOfBuffer, FMT_BB, b->bbNum); + } + + const bool printEdgeLikelihoods = true; // TODO: parameterize this? + if (printEdgeLikelihoods) + { + if (e->hasLikelihood()) + { + written = _snprintf_s(buffer + written, sizeOfBuffer - written, sizeOfBuffer - written, "(" FMT_WT ")", + e->getLikelihood()); + } } return buffer; @@ -715,7 +738,7 @@ void BasicBlock::dspKind() const for (unsigned i = 0; i < jumpCnt; i++) { - printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]->getDestinationBlock())); + printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i])); } } @@ -728,11 +751,11 @@ void BasicBlock::dspKind() const break; case BBJ_EHFILTERRET: - printf(" -> %s (fltret)", dspBlockNum(GetTarget())); + printf(" -> %s (fltret)", dspBlockNum(GetTargetEdge())); break; case BBJ_EHCATCHRET: - printf(" -> %s (cret)", dspBlockNum(GetTarget())); + printf(" -> %s (cret)", dspBlockNum(GetTargetEdge())); break; case BBJ_THROW: @@ -746,28 +769,28 @@ void BasicBlock::dspKind() const case BBJ_ALWAYS: if (HasFlag(BBF_KEEP_BBJ_ALWAYS)) { - printf(" -> %s (ALWAYS)", dspBlockNum(GetTarget())); + printf(" -> %s (ALWAYS)", dspBlockNum(GetTargetEdge())); } else { - printf(" -> %s (always)", dspBlockNum(GetTarget())); + printf(" -> %s (always)", dspBlockNum(GetTargetEdge())); } break; case BBJ_LEAVE: - printf(" -> %s (leave)", dspBlockNum(GetTarget())); + printf(" -> %s (leave)", dspBlockNum(GetTargetEdge())); break; case BBJ_CALLFINALLY: - printf(" -> %s (callf)", dspBlockNum(GetTarget())); + printf(" -> %s (callf)", dspBlockNum(GetTargetEdge())); break; case BBJ_CALLFINALLYRET: - printf(" -> %s (callfr)", dspBlockNum(GetTarget())); + printf(" -> %s (callfr)", dspBlockNum(GetTargetEdge())); break; case BBJ_COND: - printf(" -> %s,%s (cond)", dspBlockNum(GetTrueTarget()), dspBlockNum(GetFalseTarget())); + printf(" -> %s,%s (cond)", dspBlockNum(GetTrueEdge()), dspBlockNum(GetFalseEdge())); break; case BBJ_SWITCH: @@ -779,7 +802,7 @@ void BasicBlock::dspKind() const for (unsigned i = 0; i < jumpCnt; i++) { - printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]->getDestinationBlock())); + printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i])); const bool isDefault = bbSwtTargets->bbsHasDefault && (i == jumpCnt - 1); if (isDefault) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index cd2a79fd098a5..ae881d99f7361 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -46,9 +46,13 @@ typedef BitVec_ValRet_T ASSERT_VALRET_TP; // Use this format for loop indices #define FMT_LP "L%02u" -// And this format for profile weights +// Use this format for profile weights #define FMT_WT "%.7g" +// Use this format for profile weights where we want to conserve horizontal space, at the expense of displaying +// less precision. +#define FMT_WT_NARROW "%.3g" + /***************************************************************************** * * Each basic block ends with a jump which is described as a value @@ -1037,6 +1041,27 @@ struct BasicBlock : private LIR::Range return (bbFalseEdge == nullptr) ? nullptr : bbFalseEdge->getDestinationBlock(); } + // Return the target edge; it might be null. Only used during dumping. + FlowEdge* GetTargetEdgeRaw() const + { + assert(HasTarget()); + return bbTargetEdge; + } + + // Return the BBJ_COND true target edge; it might be null. Only used during dumping. + FlowEdge* GetTrueEdgeRaw() const + { + assert(KindIs(BBJ_COND)); + return bbTrueEdge; + } + + // Return the BBJ_COND false target edge; it might be null. Only used during dumping. + FlowEdge* GetFalseEdgeRaw() const + { + assert(KindIs(BBJ_COND)); + return bbFalseEdge; + } + #endif // DEBUG private: @@ -1537,7 +1562,7 @@ struct BasicBlock : private LIR::Range } // PredBlocksEditing: convenience method for enabling range-based `for` iteration over predecessor blocks, e.g.: - // for (BasicBlock* const predBlock : block->PredBlocksList()) ... + // for (BasicBlock* const predBlock : block->PredBlocksEditing()) ... // This iterator tolerates modifications to bbPreds. // PredBlockList PredBlocksEditing() const diff --git a/src/coreclr/jit/clrjit.natvis b/src/coreclr/jit/clrjit.natvis index a15bf3cf6e73b..cfbc6a181e974 100644 --- a/src/coreclr/jit/clrjit.natvis +++ b/src/coreclr/jit/clrjit.natvis @@ -8,9 +8,8 @@ The .NET Foundation licenses this file to you under the MIT license. @@ -27,6 +26,11 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u BB{bbNum,d}; {bbKind,en} + + BB{m_sourceBlock->bbNum,d}->BB{m_destBlock->bbNum,d} ({m_likelihood,g}) (dup {m_dupCount,d}) + BB{m_sourceBlock->bbNum,d}->BB{m_destBlock->bbNum,d} ({m_likelihood,g}) + + REMOVED [BB{lpTop->bbNum,d}..BB{lpBottom->bbNum,d}] pre-h:BB{lpHead->bbNum,d} e:BB{lpEntry->bbNum,d} {lpFlags,en} diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 2158721861b93..43d9279376b19 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1584,7 +1584,7 @@ enum class ProfileChecks : unsigned int CHECK_NONE = 0, CHECK_CLASSIC = 1 << 0, // check "classic" jit weights CHECK_HASLIKELIHOOD = 1 << 1, // check all FlowEdges for hasLikelihood - CHECK_LIKELIHOODSUM = 1 << 2, // check block succesor likelihoods sum to 1 + CHECK_LIKELIHOODSUM = 1 << 2, // check block successor likelihoods sum to 1 CHECK_LIKELY = 1 << 3, // fully check likelihood based weights RAISE_ASSERT = 1 << 4, // assert on check failure CHECK_ALL_BLOCKS = 1 << 5, // check blocks even if bbHasProfileWeight is false @@ -6074,7 +6074,11 @@ class Compiler void fgDispBBLiveness(BasicBlock* block); void fgDispBBLiveness(); - void fgTableDispBasicBlock(const BasicBlock* block, const BasicBlock* nextBlock = nullptr, int blockTargetFieldWidth = 21, int ibcColWidth = 0); + void fgTableDispBasicBlock(const BasicBlock* block, + const BasicBlock* nextBlock = nullptr, + bool printEdgeLikelihoods = true, + int blockTargetFieldWidth = 21, + int ibcColWidth = 0); void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees); void fgDispBasicBlocks(bool dumpTrees = false); void fgDumpStmtTree(const BasicBlock* block, Statement* stmt); diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 200c72a4d4e1c..f389e7cbe9fbd 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -686,20 +686,56 @@ void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* oldTarget, Bas case BBJ_SWITCH: { - unsigned const jumpCnt = block->GetSwitchTargets()->bbsCount; - FlowEdge** const jumpTab = block->GetSwitchTargets()->bbsDstTab; - bool changed = false; + unsigned const jumpCnt = block->GetSwitchTargets()->bbsCount; + FlowEdge** const jumpTab = block->GetSwitchTargets()->bbsDstTab; + bool existingEdge = false; + FlowEdge* oldEdge = nullptr; + FlowEdge* newEdge = nullptr; + bool changed = false; for (unsigned i = 0; i < jumpCnt; i++) { + if (jumpTab[i]->getDestinationBlock() == newTarget) + { + // The new target already has an edge from this switch statement. + // We'll need to add the likelihood from the edge we're redirecting + // to the existing edge. Note that if there is no existing edge, + // then we'll copy the likelihood from the existing edge we pass to + // `fgAddRefPred`. Note also that we can visit the same edge multiple + // times if there are multiple switch cases with the same target. The + // edge has a dup count and a single likelihood for all the possible + // paths to the target, so we only want to add the likelihood once + // despite visiting the duplicated edges in the `jumpTab` array + // multiple times. + existingEdge = true; + } + if (jumpTab[i]->getDestinationBlock() == oldTarget) { - fgRemoveRefPred(jumpTab[i]); - jumpTab[i] = fgAddRefPred(newTarget, block, jumpTab[i]); + assert((oldEdge == nullptr) || (oldEdge == jumpTab[i])); + oldEdge = jumpTab[i]; + fgRemoveRefPred(oldEdge); + newEdge = fgAddRefPred(newTarget, block, oldEdge); + jumpTab[i] = newEdge; changed = true; } } + if (existingEdge) + { + assert(oldEdge != nullptr); + assert(oldEdge->getSourceBlock() == block); + assert(oldEdge->getDestinationBlock() == oldTarget); + assert(newEdge != nullptr); + assert(newEdge->getSourceBlock() == block); + assert(newEdge->getDestinationBlock() == newTarget); + + if (newEdge->hasLikelihood() && oldEdge->hasLikelihood()) + { + newEdge->addLikelihood(oldEdge->getLikelihood()); + } + } + assert(changed); InvalidateUniqueSwitchSuccMap(); break; diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index c78fe6f7124e9..33d806779eb93 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -1806,6 +1806,7 @@ void Compiler::fgDumpFlowGraphLoops(FILE* file) void Compiler::fgTableDispBasicBlock(const BasicBlock* block, const BasicBlock* nextBlock /* = nullptr */, + bool printEdgeLikelihoods /* = true */, int blockTargetFieldWidth /* = 21 */, int ibcColWidth /* = 0 */) { @@ -1931,27 +1932,41 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, // Call `dspBlockNum()` to get the block number to print, and update `printedBlockWidth` with the width // of the generated string. Note that any computation using `printedBlockWidth` must be done after all // calls to this function. - auto dspBlockNum = [terseNext, nextBlock, &printedBlockWidth](const BasicBlock* b) -> const char* { + auto dspBlockNum = [printEdgeLikelihoods, terseNext, nextBlock, + &printedBlockWidth](const FlowEdge* e) -> const char* { static char buffers[3][64]; // static array of 3 to allow 3 concurrent calls in one printf() static int nextBufferIndex = 0; - auto& buffer = buffers[nextBufferIndex]; - nextBufferIndex = (nextBufferIndex + 1) % ArrLen(buffers); + auto& buffer = buffers[nextBufferIndex]; + nextBufferIndex = (nextBufferIndex + 1) % ArrLen(buffers); + const size_t sizeOfBuffer = ArrLen(buffer); + int written; + const BasicBlock* b = e->getDestinationBlock(); if (b == nullptr) { - _snprintf_s(buffer, ArrLen(buffer), ArrLen(buffer), "NULL"); - printedBlockWidth += 4; + written = _snprintf_s(buffer, sizeOfBuffer, sizeOfBuffer, "NULL"); + printedBlockWidth += written; } else if (terseNext && (b == nextBlock)) { - _snprintf_s(buffer, ArrLen(buffer), ArrLen(buffer), "*"); - printedBlockWidth += 1; + written = _snprintf_s(buffer, sizeOfBuffer, sizeOfBuffer, "*"); + printedBlockWidth += written; } else { - _snprintf_s(buffer, ArrLen(buffer), ArrLen(buffer), FMT_BB, b->bbNum); - printedBlockWidth += 2 /* BB */ + max(CountDigits(b->bbNum), 2); + written = _snprintf_s(buffer, sizeOfBuffer, sizeOfBuffer, FMT_BB, b->bbNum); + printedBlockWidth += written; + } + + if (printEdgeLikelihoods) + { + if (e->hasLikelihood()) + { + written = _snprintf_s(buffer + written, sizeOfBuffer - written, sizeOfBuffer - written, + "(" FMT_WT_NARROW ")", e->getLikelihood()); + printedBlockWidth += written; + } } return buffer; @@ -1968,19 +1983,19 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, { case BBJ_COND: printedBlockWidth = 3 /* "-> " */ + 1 /* comma */ + 9 /* kind */; - printf("-> %s,%s", dspBlockNum(block->GetTrueTargetRaw()), dspBlockNum(block->GetFalseTargetRaw())); + printf("-> %s,%s", dspBlockNum(block->GetTrueEdgeRaw()), dspBlockNum(block->GetFalseEdgeRaw())); printf("%*s ( cond )", blockTargetFieldWidth - printedBlockWidth, ""); break; case BBJ_CALLFINALLY: printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetTargetRaw())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s (callf )", blockTargetFieldWidth - printedBlockWidth, ""); break; case BBJ_CALLFINALLYRET: printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetFinallyContinuation())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s (callfr)", blockTargetFieldWidth - printedBlockWidth, ""); break; @@ -1988,13 +2003,13 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, const char* label; label = (flags & BBF_KEEP_BBJ_ALWAYS) ? "ALWAYS" : "always"; printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetTargetRaw())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s (%s)", blockTargetFieldWidth - printedBlockWidth, "", label); break; case BBJ_LEAVE: printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetTargetRaw())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s (leave )", blockTargetFieldWidth - printedBlockWidth, ""); break; @@ -2019,7 +2034,7 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, for (unsigned i = 0; i < jumpCnt; i++) { printedBlockWidth += 1 /* space/comma */; - printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]->getDestinationBlock())); + printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i])); } } @@ -2039,13 +2054,13 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, case BBJ_EHFILTERRET: printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetTargetRaw())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s (fltret)", blockTargetFieldWidth - printedBlockWidth, ""); break; case BBJ_EHCATCHRET: printedBlockWidth = 3 /* "-> " */ + 9 /* kind */; - printf("-> %s", dspBlockNum(block->GetTargetRaw())); + printf("-> %s", dspBlockNum(block->GetTargetEdgeRaw())); printf("%*s ( cret )", blockTargetFieldWidth - printedBlockWidth, ""); break; @@ -2071,7 +2086,7 @@ void Compiler::fgTableDispBasicBlock(const BasicBlock* block, for (unsigned i = 0; i < jumpCnt; i++) { printedBlockWidth += 1 /* space/comma */; - printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]->getDestinationBlock())); + printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i])); const bool isDefault = jumpSwt->bbsHasDefault && (i == jumpCnt - 1); if (isDefault) @@ -2321,10 +2336,16 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, maxBlockNumWidth = max(maxBlockNumWidth, 2); int padWidth = maxBlockNumWidth - 2; // Account for functions with a large number of blocks. + const bool printEdgeLikelihoods = true; // TODO: parameterize? + + // Edge likelihoods are printed as "(0.123)", so take 7 characters maxmimum. + int edgeLikelihoodsWidth = printEdgeLikelihoods ? 7 : 0; + // Calculate the field width allocated for the block target. The field width is allocated to allow for two blocks // for BBJ_COND. It does not include any extra space for variable-sized BBJ_EHFINALLYRET and BBJ_SWITCH. - int blockTargetFieldWidth = 3 /* "-> " */ + 2 /* BB */ + maxBlockNumWidth + 1 /* comma */ + 2 /* BB */ + - maxBlockNumWidth + 1 /* space */ + 8 /* kind: "(xxxxxx)" */; + int blockTargetFieldWidth = 3 /* "-> " */ + 2 /* BB */ + maxBlockNumWidth + edgeLikelihoodsWidth + 1 /* comma */ + + 2 /* BB */ + maxBlockNumWidth + edgeLikelihoodsWidth + 1 /* space */ + + 8 /* kind: "(xxxxxx)" */; // clang-format off @@ -2332,7 +2353,7 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, printf("------%*s-------------------------------------%*s--------------------------%*s--------------------------\n", padWidth, "------------", // ibcColWidth, "------------", // - blockTargetFieldWidth, "-----------------------"); // + blockTargetFieldWidth, "----------------------------------------------"); // printf("BBnum %*sBBid ref try hnd %s weight %*s%s [IL range] [jump]%*s [EH region] [flags]\n", padWidth, "", (fgPredsComputed ? "preds " @@ -2345,7 +2366,7 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, printf("------%*s-------------------------------------%*s--------------------------%*s--------------------------\n", padWidth, "------------", // ibcColWidth, "------------", // - blockTargetFieldWidth, "-----------------------"); // + blockTargetFieldWidth, "----------------------------------------------"); // // clang-format on @@ -2377,9 +2398,9 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, { printf("~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~~~~~~~~~~~~~~~~~%*s~~~~~~~~~~" "~~~~~~~~~~~~~~~~\n", - padWidth, "~~~~~~~~~~~~", // - ibcColWidth, "~~~~~~~~~~~~", // - blockTargetFieldWidth, "~~~~~~~~~~~~~~~~~~~~~~~"); // + padWidth, "~~~~~~~~~~~~", // + ibcColWidth, "~~~~~~~~~~~~", // + blockTargetFieldWidth, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); // } #if defined(FEATURE_EH_FUNCLETS) @@ -2387,13 +2408,13 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, { printf("++++++%*s+++++++++++++++++++++++++++++++++++++%*s++++++++++++++++++++++++++%*s++++++++++" "++++++++++++++++ funclets follow\n", - padWidth, "++++++++++++", // - ibcColWidth, "++++++++++++", // - blockTargetFieldWidth, "+++++++++++++++++++++++"); // + padWidth, "++++++++++++", // + ibcColWidth, "++++++++++++", // + blockTargetFieldWidth, "++++++++++++++++++++++++++++++++++++++++++++++"); // } #endif // FEATURE_EH_FUNCLETS - fgTableDispBasicBlock(block, nextBlock, blockTargetFieldWidth, ibcColWidth); + fgTableDispBasicBlock(block, nextBlock, printEdgeLikelihoods, blockTargetFieldWidth, ibcColWidth); if (block == lastBlock) { @@ -2403,9 +2424,9 @@ void Compiler::fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, printf("------%*s-------------------------------------%*s--------------------------%*s------------------" "--------\n", - padWidth, "------------", // - ibcColWidth, "------------", // - blockTargetFieldWidth, "-----------------------"); // + padWidth, "------------", // + ibcColWidth, "------------", // + blockTargetFieldWidth, "----------------------------------------------"); // if (dumpTrees) { diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 3052d2fca63ea..29c865c74f1e9 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -1928,6 +1928,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) { printf("\nRemoving a switch jump with a single target (" FMT_BB ")\n", block->bbNum); printf("BEFORE:\n"); + fgDispBasicBlocks(); } #endif // DEBUG diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 82192c9f28ca6..4693107168ba6 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -5664,6 +5664,25 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks else { likelyWeightsValid = false; + +#ifdef DEBUG + if (verbose) + { + for (const FlowEdge* succEdge : block->SuccEdges(this)) + { + const BasicBlock* succBlock = succEdge->getDestinationBlock(); + if (succEdge->hasLikelihood()) + { + printf(" " FMT_BB " -> " FMT_BB ": " FMT_WT "\n", block->bbNum, succBlock->bbNum, + succEdge->getLikelihood()); + } + else + { + printf(" " FMT_BB " -> " FMT_BB ": no likelihood\n", block->bbNum, succBlock->bbNum); + } + } + } +#endif // DEBUG } } } diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index ee8320344ce42..7c16c29b0972f 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -144,9 +144,11 @@ CONFIG_INTEGER(JitPrintInlinedMethodsVerbose, W("JitPrintInlinedMethodsVerboseLe CONFIG_METHODSET(JitPrintInlinedMethods, W("JitPrintInlinedMethods")) CONFIG_METHODSET(JitPrintDevirtualizedMethods, W("JitPrintDevirtualizedMethods")) -// -1: just do internal checks -// Else bitflag: 0x1 check classic, 0x2 check likely, 0x4 enable asserts + +// -1: just do internal checks (CHECK_HASLIKELIHOOD | CHECK_LIKELIHOODSUM | RAISE_ASSERT) +// Else bitflag of ProfileChecks enum. CONFIG_INTEGER(JitProfileChecks, W("JitProfileChecks"), -1) + CONFIG_INTEGER(JitRequired, W("JITRequired"), -1) CONFIG_INTEGER(JitRoundFloat, W("JITRoundFloat"), DEFAULT_ROUND_LEVEL) CONFIG_INTEGER(JitStackAllocToLocalSize, W("JitStackAllocToLocalSize"), DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index e837dbfe72d21..a398a517c7af3 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -3118,6 +3118,9 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit) BasicBlock* newExit; + JITDUMP("Canonicalize exit " FMT_BB " for " FMT_LP " to have only loop predecessors\n", exit->bbNum, + loop->GetIndex()); + #if FEATURE_EH_CALLFINALLY_THUNKS if (exit->KindIs(BBJ_CALLFINALLY)) { @@ -3140,7 +3143,7 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit) } } else -#endif +#endif // FEATURE_EH_CALLFINALLY_THUNKS { newExit = fgNewBBbefore(BBJ_ALWAYS, exit, false); newExit->SetFlags(BBF_NONE_QUIRK); @@ -3154,9 +3157,6 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit) newExit->bbCodeOffs = exit->bbCodeOffs; - JITDUMP("Created new exit " FMT_BB " to replace " FMT_BB " for " FMT_LP "\n", newExit->bbNum, exit->bbNum, - loop->GetIndex()); - for (BasicBlock* pred : exit->PredBlocksEditing()) { if (loop->ContainsBlock(pred)) @@ -3166,6 +3166,9 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit) } optSetWeightForPreheaderOrExit(loop, newExit); + + JITDUMP("Created new exit " FMT_BB " to replace " FMT_BB " exit for " FMT_LP "\n", newExit->bbNum, exit->bbNum, + loop->GetIndex()); return true; }