Skip to content

Commit

Permalink
JIT: Allow experimenting with different CSE subsets (dotnet#92918)
Browse files Browse the repository at this point in the history
Introduce two config vars for experimenting with CSEs:
* `JitCSEHash`: identifies a method for CSE experimentatin
* `JitCSEMask`: specifies a bitmask of allowed CSEs (by "attempt")

When the hash is nonzero, any method whose hash matches will perform
only the subset of CSEs specified by the mask (up to 32 CSEs).

Also introduce a config var to dump the total number of CSEs to either
the assemby listing footer or the one-liner from the disassembly summary.
* `JitMetrics`

This can perhaps be generalized eventually to report more metrics
and perhaps to report them back to SPMI when it is the jit host.

Finally, note CSE lcl vars that represent hoisted trees and or are
"multiple-def" CSEs in the local var table.

Contributes to dotnet#92915.
  • Loading branch information
AndyAyersMS committed Oct 6, 2023
1 parent 7498771 commit 96a35e0
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 7 deletions.
5 changes: 5 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2008,6 +2008,11 @@ void CodeGen::genEmitMachineCode()
codeSize, prologSize, compiler->info.compPerfScore, instrCount,
GetEmitter()->emitTotalHotCodeSize + GetEmitter()->emitTotalColdCodeSize);

if (JitConfig.JitMetrics() > 0)
{
printf(", num cse %d", compiler->optCSEcount);
}

#if TRACK_LSRA_STATS
if (JitConfig.DisplayLsraStats() == 3)
{
Expand Down
19 changes: 17 additions & 2 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2661,6 +2661,13 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
verboseDump = (JitConfig.JitDumpTier0() > 0);
}

// Optionally suppress dumping OSR jit requests.
//
if (verboseDump && jitFlags->IsSet(JitFlags::JIT_FLAG_OSR))
{
verboseDump = (JitConfig.JitDumpOSR() > 0);
}

// Optionally suppress dumping except for a specific OSR jit request.
//
const int dumpAtOSROffset = JitConfig.JitDumpAtOSROffset();
Expand Down Expand Up @@ -5190,10 +5197,18 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
char debugPart[128] = {0};
INDEBUG(sprintf_s(debugPart, 128, ", hash=0x%08x%s", info.compMethodHash(), compGetStressMessage()));

char metricPart[128] = {0};
#ifdef DEBUG
if (JitConfig.JitMetrics() > 0)
{
sprintf_s(metricPart, 128, ", perfScore=%.2f, numCse=%u", info.compPerfScore, optCSEcount);
}
#endif

const bool hasProf = fgHaveProfileData();
printf("%4d: JIT compiled %s [%s%s%s%s, IL size=%u, code size=%u%s]\n", methodsCompiled, fullName,
printf("%4d: JIT compiled %s [%s%s%s%s, IL size=%u, code size=%u%s%s]\n", methodsCompiled, fullName,
compGetTieringName(), osrBuffer, hasProf ? " with " : "", hasProf ? compGetPgoSourceName() : "",
info.compILCodeSize, *methodCodeSize, debugPart);
info.compILCodeSize, *methodCodeSize, debugPart, metricPart);
}

compFunctionTraceEnd(*methodCodePtr, *methodCodeSize, false);
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,8 @@ class LclVarDsc

#ifdef DEBUG
unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
unsigned char lvIsHoist : 1; // CSE temp for a hoisted tree
unsigned char lvIsMultiDefCSE : 1; // CSE temp for a multi-def CSE
#endif

unsigned char lvImplicitlyReferenced : 1; // true if there are non-IR references to this local (prolog, epilog, gc,
Expand Down Expand Up @@ -6981,9 +6983,10 @@ class Compiler

bool optDoCSE; // True when we have found a duplicate CSE tree
bool optValnumCSE_phase; // True when we are executing the optOptimizeValnumCSEs() phase
unsigned optCSECandidateCount; // Count of CSE's candidates
unsigned optCSECandidateCount; // Count of CSE candidates
unsigned optCSEstart; // The first local variable number that is a CSE
unsigned optCSEcount; // The total count of CSE's introduced.
unsigned optCSEattempt; // The number of CSEs attempted so far.
unsigned optCSEcount; // The total count of CSEs introduced.
weight_t optCSEweight; // The weight of the current block when we are doing PerformCSE

bool optIsCSEcandidate(GenTree* tree);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7613,7 +7613,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
// emit offsets after the loop with wrong value (for example for GC ref variables).
unsigned unusedSize = emitTotalCodeSize - actualCodeSize;

JITDUMP("Allocated method code size = %4u , actual size = %4u, unused size = %4u\n", emitTotalCodeSize,
JITDUMP("\n\nAllocated method code size = %4u , actual size = %4u, unused size = %4u\n", emitTotalCodeSize,
actualCodeSize, unusedSize);

BYTE* cpRW = cp + writeableOffset;
Expand Down
31 changes: 29 additions & 2 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,9 @@ CONFIG_INTEGER(JitDisasmWithDebugInfo, W("JitDisasmWithDebugInfo"), 0) // Dump i
// disassembled.
CONFIG_INTEGER(JitDisasmSpilled, W("JitDisasmSpilled"), 0) // Display native code when any register spilling occurs
CONFIG_METHODSET(JitDump, W("JitDump")) // Dumps trees for specified method
CONFIG_INTEGER(JitDumpTier0, W("JitDumpTier0"), 1) // Dump tier0 requests
CONFIG_INTEGER(JitDumpAtOSROffset, W("JitDumpAtOSROffset"), -1) // Only dump OSR requests for this offset
CONFIG_INTEGER(JitDumpTier0, W("JitDumpTier0"), 1) // Dump tier0 jit compilations
CONFIG_INTEGER(JitDumpOSR, W("JitDumpOSR"), 1) // Dump OSR jit compilations
CONFIG_INTEGER(JitDumpAtOSROffset, W("JitDumpAtOSROffset"), -1) // Dump only OSR jit compilations with this offset
CONFIG_INTEGER(JitDumpInlinePhases, W("JitDumpInlinePhases"), 1) // Dump inline compiler phases
CONFIG_METHODSET(JitEHDump, W("JitEHDump")) // Dump the EH table for the method, as reported to the VM
CONFIG_METHODSET(JitExclude, W("JitExclude"))
Expand Down Expand Up @@ -376,6 +377,32 @@ CONFIG_INTEGER(JitConstCSE, W("JitConstCSE"), 0)
#define CONST_CSE_ENABLE_ALL 3
#define CONST_CSE_ENABLE_ALL_NO_SHARING 4

#if defined(DEBUG)
// Allow fine-grained controls of CSEs done in a particular method
//
// Specify method that will respond to the CSEMask.
// 0 means feature disabled and all methods run CSE normally.
CONFIG_INTEGER(JitCSEHash, W("JitCSEHash"), 0)

// Bitmask of allowed CSEs in methods specified by JitCSEHash.
// These bits control the "cse attempts" made by normal jitting,
// for the first 32 CSEs attempted (Note this is not the same as
// the CSE candidate number, which reflects the order
// in which CSEs were discovered).
//
// 0: do no CSEs
// 1: do only the first CSE
// 2: do only the second CSE
// C: do only the third and fourth CSEs
// F: do only the first four CSEs
// ...etc...
// FFFFFFFF : do all the CSEs normally done
CONFIG_INTEGER(JitCSEMask, W("JitCSEMask"), 0)

// Enable metric output in jit disasm & elsewhere
CONFIG_INTEGER(JitMetrics, W("JitMetrics"), 0)
#endif

///
/// JIT
///
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7569,6 +7569,14 @@ void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t r
{
printf(" tier0-frame");
}
if (varDsc->lvIsHoist)
{
printf(" hoist");
}
if (varDsc->lvIsMultiDefCSE)
{
printf(" multi-def");
}

#ifndef TARGET_64BIT
if (varDsc->lvStructDoubleAlign)
Expand Down
29 changes: 29 additions & 0 deletions src/coreclr/jit/optcse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2808,6 +2808,10 @@ class CSE_Heuristic
cseSsaNum = lclDsc->lvPerSsaData.AllocSsaNum(allocator);
ssaVarDsc = lclDsc->GetPerSsaData(cseSsaNum);
}
else
{
INDEBUG(lclDsc->lvIsMultiDefCSE = 1);
}

// Verify that all of the ValueNumbers in this list are correct as
// Morph will change them when it performs a mutating operation.
Expand Down Expand Up @@ -2888,6 +2892,7 @@ class CSE_Heuristic
if (isDef)
{
lclDsc->incRefCnts(curWeight, m_pCompiler);
INDEBUG(lclDsc->lvIsHoist |= ((lst->tslTree->gtFlags & GTF_MAKE_CSE) != 0));
}
}
lst = lst->tslNext;
Expand Down Expand Up @@ -3318,6 +3323,30 @@ class CSE_Heuristic
bool doCSE = PromotionCheck(&candidate);

#ifdef DEBUG

if (doCSE)
{
const int attempt = m_pCompiler->optCSEattempt++;

if (m_pCompiler->info.compMethodHash() == (unsigned)JitConfig.JitCSEHash())
{
// We can only mask the first 32 CSE attempts, so suppress anything beyond that.
// Note methods with >= 32 CSEs are currently quite rare.
//
if (attempt >= 32)
{
doCSE = false;
JITDUMP(FMT_CSE " attempt %u disabled, out of mask range\n", candidate.CseIndex(), attempt);
}
else
{
doCSE = ((1 << attempt) & ((unsigned)JitConfig.JitCSEMask())) != 0;
JITDUMP(FMT_CSE " attempt %u mask 0x%08x: %s\n", candidate.CseIndex(), attempt,
JitConfig.JitCSEMask(), doCSE ? "allowed" : "disabled");
}
}
}

if (m_pCompiler->verbose)
{
if (doCSE)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void Compiler::optInit()
optAssertionDep = nullptr;
optCSEstart = BAD_VAR_NUM;
optCSEcount = 0;
optCSEattempt = 0;
}

DataFlow::DataFlow(Compiler* pCompiler) : m_pCompiler(pCompiler)
Expand Down

0 comments on commit 96a35e0

Please sign in to comment.