Skip to content

JIT: Allow experimenting with different CSE subsets #92918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2677,6 +2677,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 @@ -5221,10 +5228,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 @@ -639,6 +639,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 @@ -6978,9 +6980,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 @@ -7611,7 +7611,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 @@ -7570,6 +7570,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