diff --git a/src/coreclr/src/jit/compiler.cpp b/src/coreclr/src/jit/compiler.cpp index 8e9508b706354d..936ca7ab92197b 100644 --- a/src/coreclr/src/jit/compiler.cpp +++ b/src/coreclr/src/jit/compiler.cpp @@ -4026,29 +4026,39 @@ bool Compiler::compRsvdRegCheck(FrameLayoutState curState) // compGetTieringName: get a string describing tiered compilation settings // for this method // +// Arguments: +// wantShortName - true if a short name is ok (say for using in file names) +// // Returns: // String describing tiering decisions for this method, including cases // where the jit codegen will differ from what the runtime requested. // -const char* Compiler::compGetTieringName() const +const char* Compiler::compGetTieringName(bool wantShortName) const { - bool tier0 = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0); - bool tier1 = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1); + const bool tier0 = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0); + const bool tier1 = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1); assert(!tier0 || !tier1); // We don't expect multiple TIER flags to be set at one time. if (tier0) { - return "Tier-0"; + return "Tier0"; } else if (tier1) { - return "Tier-1"; + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_OSR)) + { + return "Tier1-OSR"; + } + else + { + return "Tier1"; + } } else if (opts.OptimizationEnabled()) { if (compSwitchedToOptimized) { - return "Tier-0 switched to FullOpts"; + return wantShortName ? "Tier0-FullOpts" : "Tier-0 switched to FullOpts"; } else { @@ -4061,11 +4071,11 @@ const char* Compiler::compGetTieringName() const { if (compSwitchedToOptimized) { - return "Tier-0 switched to FullOpts, then to MinOpts"; + return wantShortName ? "Tier0-FullOpts-MinOpts" : "Tier-0 switched to FullOpts, then to MinOpts"; } else { - return "Tier-1/FullOpts switched to MinOpts"; + return wantShortName ? "Tier0-MinOpts" : "Tier-0 switched MinOpts"; } } else @@ -4079,7 +4089,7 @@ const char* Compiler::compGetTieringName() const } else { - return "Unknown optimization level"; + return wantShortName ? "Unknown" : "Unknown optimization level"; } } diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 164da5e65224dc..ebfe1e2194f371 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -9043,7 +9043,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif } - const char* compGetTieringName() const; + const char* compGetTieringName(bool wantShortName = false) const; const char* compGetStressMessage() const; codeOptimize compCodeOpt() diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index 4cb1428d969e4b..2a1449af3c43fd 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -20199,16 +20199,21 @@ FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR typ ONE_FILE_PER_METHOD:; - escapedString = fgProcessEscapes(info.compFullName, s_EscapeFileMapping); - size_t wCharCount = strlen(escapedString) + wcslen(phaseName) + 1 + strlen("~999") + wcslen(type) + 1; + escapedString = fgProcessEscapes(info.compFullName, s_EscapeFileMapping); + + const char* tierName = compGetTieringName(true); + size_t wCharCount = + strlen(escapedString) + wcslen(phaseName) + 1 + strlen("~999") + wcslen(type) + strlen(tierName) + 1; if (pathname != nullptr) { wCharCount += wcslen(pathname) + 1; } filename = (LPCWSTR)alloca(wCharCount * sizeof(WCHAR)); + if (pathname != nullptr) { - swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S-%s.%s"), pathname, escapedString, phaseName, type); + swprintf_s((LPWSTR)filename, wCharCount, W("%s\\%S-%s-%S.%s"), pathname, escapedString, phaseName, tierName, + type); } else { @@ -20356,8 +20361,9 @@ bool Compiler::fgDumpFlowGraph(Phases phase) if (createDotFile) { - fprintf(fgxFile, "digraph %s\n{\n", info.compMethodName); - fprintf(fgxFile, "/* Method %d, after phase %s */", Compiler::jitTotalMethodCompiled, PhaseNames[phase]); + fprintf(fgxFile, "digraph FlowGraph {\n"); + fprintf(fgxFile, " graph [label = \"%s\\nafter\\n%s\"];\n", info.compMethodName, PhaseNames[phase]); + fprintf(fgxFile, " node [shape = \"Box\"];\n"); } else { @@ -20418,24 +20424,37 @@ bool Compiler::fgDumpFlowGraph(Phases phase) { if (createDotFile) { - // Add constraint edges to try to keep nodes ordered. - // It seems to work best if these edges are all created first. - switch (block->bbJumpKind) + fprintf(fgxFile, " BB%02u [label = \"BB%02u\\n\\n", block->bbNum, block->bbNum); + + // "Raw" Profile weight + if (block->hasProfileWeight()) { - case BBJ_COND: - case BBJ_NONE: - assert(block->bbNext != nullptr); - fprintf(fgxFile, " " FMT_BB " -> " FMT_BB "\n", block->bbNum, block->bbNext->bbNum); - break; - default: - // These may or may not have an edge to the next block. - // Add a transparent edge to keep nodes ordered. - if (block->bbNext != nullptr) - { - fprintf(fgxFile, " " FMT_BB " -> " FMT_BB " [arrowtail=none,color=transparent]\n", - block->bbNum, block->bbNext->bbNum); - } + fprintf(fgxFile, "%7.2f", ((double)block->getBBWeight(this)) / BB_UNITY_WEIGHT); + } + + // end of block label + fprintf(fgxFile, "\""); + + // other node attributes + // + if (block == fgFirstBB) + { + fprintf(fgxFile, ", shape = \"house\""); + } + else if (block->bbJumpKind == BBJ_RETURN) + { + fprintf(fgxFile, ", shape = \"invhouse\""); + } + else if (block->bbJumpKind == BBJ_THROW) + { + fprintf(fgxFile, ", shape = \"trapezium\""); + } + else if (block->bbFlags & BBF_INTERNAL) + { + fprintf(fgxFile, ", shape = \"note\""); } + + fprintf(fgxFile, "];\n"); } else { @@ -20482,104 +20501,156 @@ bool Compiler::fgDumpFlowGraph(Phases phase) fprintf(fgxFile, ">"); } - unsigned edgeNum = 1; - BasicBlock* bTarget; - for (bTarget = fgFirstBB; bTarget != nullptr; bTarget = bTarget->bbNext) + if (fgComputePredsDone) { - double targetWeightDivisor; - if (bTarget->bbWeight == BB_ZERO_WEIGHT) - { - targetWeightDivisor = 1.0; - } - else + unsigned edgeNum = 1; + BasicBlock* bTarget; + for (bTarget = fgFirstBB; bTarget != nullptr; bTarget = bTarget->bbNext) { - targetWeightDivisor = (double)bTarget->bbWeight; - } - - flowList* edge; - for (edge = bTarget->bbPreds; edge != nullptr; edge = edge->flNext, edgeNum++) - { - BasicBlock* bSource = edge->flBlock; - double sourceWeightDivisor; - if (bSource->bbWeight == BB_ZERO_WEIGHT) + double targetWeightDivisor; + if (bTarget->bbWeight == BB_ZERO_WEIGHT) { - sourceWeightDivisor = 1.0; + targetWeightDivisor = 1.0; } else { - sourceWeightDivisor = (double)bSource->bbWeight; + targetWeightDivisor = (double)bTarget->bbWeight; } - if (createDotFile) + + flowList* edge; + for (edge = bTarget->bbPreds; edge != nullptr; edge = edge->flNext, edgeNum++) { - // Don't duplicate the edges we added above. - if ((bSource->bbNum == (bTarget->bbNum - 1)) && - ((bSource->bbJumpKind == BBJ_NONE) || (bSource->bbJumpKind == BBJ_COND))) + BasicBlock* bSource = edge->flBlock; + double sourceWeightDivisor; + if (bSource->bbWeight == BB_ZERO_WEIGHT) { - continue; - } - fprintf(fgxFile, " " FMT_BB " -> " FMT_BB, bSource->bbNum, bTarget->bbNum); - if ((bSource->bbNum > bTarget->bbNum)) - { - fprintf(fgxFile, "[arrowhead=normal,arrowtail=none,color=green]\n"); + sourceWeightDivisor = 1.0; } else { - fprintf(fgxFile, "\n"); + sourceWeightDivisor = (double)bSource->bbWeight; } - } - else - { - fprintf(fgxFile, "\n bbNum); - fprintf(fgxFile, "\n target=\"%d\"", bTarget->bbNum); - if (bSource->bbJumpKind == BBJ_SWITCH) + if (createDotFile) { - if (edge->flDupCount >= 2) + fprintf(fgxFile, " " FMT_BB " -> " FMT_BB, bSource->bbNum, bTarget->bbNum); + + if (bSource->bbNum > bTarget->bbNum) { - fprintf(fgxFile, "\n switchCases=\"%d\"", edge->flDupCount); + // Lexical backedge + fprintf(fgxFile, " [color=green]\n"); } - if (bSource->bbJumpSwt->getDefault() == bTarget) + else if ((bSource->bbNum + 1) == bTarget->bbNum) { - fprintf(fgxFile, "\n switchDefault=\"true\""); + // Lexical successor + fprintf(fgxFile, " [color=blue, weight=20]\n"); + } + else + { + fprintf(fgxFile, ";\n"); } } - if (validWeights) + else { - unsigned edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; - fprintf(fgxFile, "\n weight="); - fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor); - - if (edge->edgeWeightMin() != edge->edgeWeightMax()) + fprintf(fgxFile, "\n bbNum); + fprintf(fgxFile, "\n target=\"%d\"", bTarget->bbNum); + if (bSource->bbJumpKind == BBJ_SWITCH) { - fprintf(fgxFile, "\n minWeight="); - fprintfDouble(fgxFile, ((double)edge->edgeWeightMin()) / weightDivisor); - fprintf(fgxFile, "\n maxWeight="); - fprintfDouble(fgxFile, ((double)edge->edgeWeightMax()) / weightDivisor); + if (edge->flDupCount >= 2) + { + fprintf(fgxFile, "\n switchCases=\"%d\"", edge->flDupCount); + } + if (bSource->bbJumpSwt->getDefault() == bTarget) + { + fprintf(fgxFile, "\n switchDefault=\"true\""); + } } - - if (edgeWeight > 0) + if (validWeights) { - if (edgeWeight < bSource->bbWeight) + unsigned edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; + fprintf(fgxFile, "\n weight="); + fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor); + + if (edge->edgeWeightMin() != edge->edgeWeightMax()) { - fprintf(fgxFile, "\n out="); - fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor); + fprintf(fgxFile, "\n minWeight="); + fprintfDouble(fgxFile, ((double)edge->edgeWeightMin()) / weightDivisor); + fprintf(fgxFile, "\n maxWeight="); + fprintfDouble(fgxFile, ((double)edge->edgeWeightMax()) / weightDivisor); } - if (edgeWeight < bTarget->bbWeight) + + if (edgeWeight > 0) { - fprintf(fgxFile, "\n in="); - fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor); + if (edgeWeight < bSource->bbWeight) + { + fprintf(fgxFile, "\n out="); + fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor); + } + if (edgeWeight < bTarget->bbWeight) + { + fprintf(fgxFile, "\n in="); + fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor); + } } } } + if (!createDotFile) + { + fprintf(fgxFile, ">"); + fprintf(fgxFile, "\n "); + } } - if (!createDotFile) + } + } + + // For dot, show edges w/o pred lists, and add invisible bbNext links. + // + if (createDotFile) + { + for (BasicBlock* bSource = fgFirstBB; bSource != nullptr; bSource = bSource->bbNext) + { + // Invisible edge for bbNext chain + // + if (bSource->bbNext != nullptr) { - fprintf(fgxFile, ">"); - fprintf(fgxFile, "\n "); + fprintf(fgxFile, " " FMT_BB " -> " FMT_BB " [style=\"invis\", weight=25];\n", bSource->bbNum, + bSource->bbNext->bbNum); + } + + if (fgComputePredsDone) + { + // Already emitted pred edges above. + // + continue; + } + + // Emit successor edges + // + const unsigned numSuccs = bSource->NumSucc(); + + for (unsigned i = 0; i < numSuccs; i++) + { + BasicBlock* const bTarget = bSource->GetSucc(i); + fprintf(fgxFile, " " FMT_BB " -> " FMT_BB, bSource->bbNum, bTarget->bbNum); + if (bSource->bbNum > bTarget->bbNum) + { + // Lexical backedge + fprintf(fgxFile, " [color=green]\n"); + } + else if ((bSource->bbNum + 1) == bTarget->bbNum) + { + // Lexical successor + fprintf(fgxFile, " [color=blue]\n"); + } + else + { + fprintf(fgxFile, ";\n"); + } } } } + if (createDotFile) { fprintf(fgxFile, "}\n");