Skip to content

Commit 96a35e0

Browse files
authored
JIT: Allow experimenting with different CSE subsets (#92918)
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 #92915.
1 parent 7498771 commit 96a35e0

File tree

8 files changed

+95
-7
lines changed

8 files changed

+95
-7
lines changed

src/coreclr/jit/codegencommon.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,11 @@ void CodeGen::genEmitMachineCode()
20082008
codeSize, prologSize, compiler->info.compPerfScore, instrCount,
20092009
GetEmitter()->emitTotalHotCodeSize + GetEmitter()->emitTotalColdCodeSize);
20102010

2011+
if (JitConfig.JitMetrics() > 0)
2012+
{
2013+
printf(", num cse %d", compiler->optCSEcount);
2014+
}
2015+
20112016
#if TRACK_LSRA_STATS
20122017
if (JitConfig.DisplayLsraStats() == 3)
20132018
{

src/coreclr/jit/compiler.cpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -2661,6 +2661,13 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
26612661
verboseDump = (JitConfig.JitDumpTier0() > 0);
26622662
}
26632663

2664+
// Optionally suppress dumping OSR jit requests.
2665+
//
2666+
if (verboseDump && jitFlags->IsSet(JitFlags::JIT_FLAG_OSR))
2667+
{
2668+
verboseDump = (JitConfig.JitDumpOSR() > 0);
2669+
}
2670+
26642671
// Optionally suppress dumping except for a specific OSR jit request.
26652672
//
26662673
const int dumpAtOSROffset = JitConfig.JitDumpAtOSROffset();
@@ -5190,10 +5197,18 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
51905197
char debugPart[128] = {0};
51915198
INDEBUG(sprintf_s(debugPart, 128, ", hash=0x%08x%s", info.compMethodHash(), compGetStressMessage()));
51925199

5200+
char metricPart[128] = {0};
5201+
#ifdef DEBUG
5202+
if (JitConfig.JitMetrics() > 0)
5203+
{
5204+
sprintf_s(metricPart, 128, ", perfScore=%.2f, numCse=%u", info.compPerfScore, optCSEcount);
5205+
}
5206+
#endif
5207+
51935208
const bool hasProf = fgHaveProfileData();
5194-
printf("%4d: JIT compiled %s [%s%s%s%s, IL size=%u, code size=%u%s]\n", methodsCompiled, fullName,
5209+
printf("%4d: JIT compiled %s [%s%s%s%s, IL size=%u, code size=%u%s%s]\n", methodsCompiled, fullName,
51955210
compGetTieringName(), osrBuffer, hasProf ? " with " : "", hasProf ? compGetPgoSourceName() : "",
5196-
info.compILCodeSize, *methodCodeSize, debugPart);
5211+
info.compILCodeSize, *methodCodeSize, debugPart, metricPart);
51975212
}
51985213

51995214
compFunctionTraceEnd(*methodCodePtr, *methodCodeSize, false);

src/coreclr/jit/compiler.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@ class LclVarDsc
638638

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

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

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

69896992
bool optIsCSEcandidate(GenTree* tree);

src/coreclr/jit/emit.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7613,7 +7613,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
76137613
// emit offsets after the loop with wrong value (for example for GC ref variables).
76147614
unsigned unusedSize = emitTotalCodeSize - actualCodeSize;
76157615

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

76197619
BYTE* cpRW = cp + writeableOffset;

src/coreclr/jit/jitconfigvalues.h

+29-2
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,9 @@ CONFIG_INTEGER(JitDisasmWithDebugInfo, W("JitDisasmWithDebugInfo"), 0) // Dump i
191191
// disassembled.
192192
CONFIG_INTEGER(JitDisasmSpilled, W("JitDisasmSpilled"), 0) // Display native code when any register spilling occurs
193193
CONFIG_METHODSET(JitDump, W("JitDump")) // Dumps trees for specified method
194-
CONFIG_INTEGER(JitDumpTier0, W("JitDumpTier0"), 1) // Dump tier0 requests
195-
CONFIG_INTEGER(JitDumpAtOSROffset, W("JitDumpAtOSROffset"), -1) // Only dump OSR requests for this offset
194+
CONFIG_INTEGER(JitDumpTier0, W("JitDumpTier0"), 1) // Dump tier0 jit compilations
195+
CONFIG_INTEGER(JitDumpOSR, W("JitDumpOSR"), 1) // Dump OSR jit compilations
196+
CONFIG_INTEGER(JitDumpAtOSROffset, W("JitDumpAtOSROffset"), -1) // Dump only OSR jit compilations with this offset
196197
CONFIG_INTEGER(JitDumpInlinePhases, W("JitDumpInlinePhases"), 1) // Dump inline compiler phases
197198
CONFIG_METHODSET(JitEHDump, W("JitEHDump")) // Dump the EH table for the method, as reported to the VM
198199
CONFIG_METHODSET(JitExclude, W("JitExclude"))
@@ -376,6 +377,32 @@ CONFIG_INTEGER(JitConstCSE, W("JitConstCSE"), 0)
376377
#define CONST_CSE_ENABLE_ALL 3
377378
#define CONST_CSE_ENABLE_ALL_NO_SHARING 4
378379

380+
#if defined(DEBUG)
381+
// Allow fine-grained controls of CSEs done in a particular method
382+
//
383+
// Specify method that will respond to the CSEMask.
384+
// 0 means feature disabled and all methods run CSE normally.
385+
CONFIG_INTEGER(JitCSEHash, W("JitCSEHash"), 0)
386+
387+
// Bitmask of allowed CSEs in methods specified by JitCSEHash.
388+
// These bits control the "cse attempts" made by normal jitting,
389+
// for the first 32 CSEs attempted (Note this is not the same as
390+
// the CSE candidate number, which reflects the order
391+
// in which CSEs were discovered).
392+
//
393+
// 0: do no CSEs
394+
// 1: do only the first CSE
395+
// 2: do only the second CSE
396+
// C: do only the third and fourth CSEs
397+
// F: do only the first four CSEs
398+
// ...etc...
399+
// FFFFFFFF : do all the CSEs normally done
400+
CONFIG_INTEGER(JitCSEMask, W("JitCSEMask"), 0)
401+
402+
// Enable metric output in jit disasm & elsewhere
403+
CONFIG_INTEGER(JitMetrics, W("JitMetrics"), 0)
404+
#endif
405+
379406
///
380407
/// JIT
381408
///

src/coreclr/jit/lclvars.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -7569,6 +7569,14 @@ void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t r
75697569
{
75707570
printf(" tier0-frame");
75717571
}
7572+
if (varDsc->lvIsHoist)
7573+
{
7574+
printf(" hoist");
7575+
}
7576+
if (varDsc->lvIsMultiDefCSE)
7577+
{
7578+
printf(" multi-def");
7579+
}
75727580

75737581
#ifndef TARGET_64BIT
75747582
if (varDsc->lvStructDoubleAlign)

src/coreclr/jit/optcse.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -2808,6 +2808,10 @@ class CSE_Heuristic
28082808
cseSsaNum = lclDsc->lvPerSsaData.AllocSsaNum(allocator);
28092809
ssaVarDsc = lclDsc->GetPerSsaData(cseSsaNum);
28102810
}
2811+
else
2812+
{
2813+
INDEBUG(lclDsc->lvIsMultiDefCSE = 1);
2814+
}
28112815

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

33203325
#ifdef DEBUG
3326+
3327+
if (doCSE)
3328+
{
3329+
const int attempt = m_pCompiler->optCSEattempt++;
3330+
3331+
if (m_pCompiler->info.compMethodHash() == (unsigned)JitConfig.JitCSEHash())
3332+
{
3333+
// We can only mask the first 32 CSE attempts, so suppress anything beyond that.
3334+
// Note methods with >= 32 CSEs are currently quite rare.
3335+
//
3336+
if (attempt >= 32)
3337+
{
3338+
doCSE = false;
3339+
JITDUMP(FMT_CSE " attempt %u disabled, out of mask range\n", candidate.CseIndex(), attempt);
3340+
}
3341+
else
3342+
{
3343+
doCSE = ((1 << attempt) & ((unsigned)JitConfig.JitCSEMask())) != 0;
3344+
JITDUMP(FMT_CSE " attempt %u mask 0x%08x: %s\n", candidate.CseIndex(), attempt,
3345+
JitConfig.JitCSEMask(), doCSE ? "allowed" : "disabled");
3346+
}
3347+
}
3348+
}
3349+
33213350
if (m_pCompiler->verbose)
33223351
{
33233352
if (doCSE)

src/coreclr/jit/optimizer.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void Compiler::optInit()
4141
optAssertionDep = nullptr;
4242
optCSEstart = BAD_VAR_NUM;
4343
optCSEcount = 0;
44+
optCSEattempt = 0;
4445
}
4546

4647
DataFlow::DataFlow(Compiler* pCompiler) : m_pCompiler(pCompiler)

0 commit comments

Comments
 (0)