Skip to content

Commit db90a84

Browse files
Refine usage of late disassembler and emitter unit tests (#96467)
* Refine usage of late disassembler and emitter unit tests Introduce `DOTNET_JitEmitUnitTests`. Set this to the function or functions into which you want the unit tests to be written. E.g., `DOTNET_JitEmitUnitTests=Main` or `DOTNET_JitEmitUnitTests=*`. Rename `DOTNET_JitDumpEmitUnitTests` to `DOTNET_JitEmitUnitTestsSections`. Make late disassembler work for altjit: use the "RW" address for the generated code. * Update src/coreclr/jit/codegenlinear.cpp Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com> --------- Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
1 parent fac60d0 commit db90a84

File tree

10 files changed

+82
-41
lines changed

10 files changed

+82
-41
lines changed

src/coreclr/jit/codegen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,13 @@ class CodeGen final : public CodeGenInterface
190190
BasicBlock* genPendingCallLabel;
191191

192192
void** codePtr;
193+
void* codePtrRW;
193194
uint32_t* nativeSizeOfCode;
194195
unsigned codeSize;
195196
void* coldCodePtr;
197+
void* coldCodePtrRW;
196198
void* consPtr;
199+
void* consPtrRW;
197200

198201
// Last instr we have displayed for dspInstrs
199202
unsigned genCurDispOffset;

src/coreclr/jit/codegencommon.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,9 +1990,10 @@ void CodeGen::genEmitMachineCode()
19901990
printf("; BEGIN METHOD %s\n", compiler->eeGetMethodFullName(compiler->info.compMethodHnd));
19911991
}
19921992

1993-
codeSize = GetEmitter()->emitEndCodeGen(compiler, trackedStackPtrsContig, GetInterruptible(),
1994-
IsFullPtrRegMapRequired(), compiler->compHndBBtabCount, &prologSize,
1995-
&epilogSize, codePtr, &coldCodePtr, &consPtr DEBUGARG(&instrCount));
1993+
codeSize =
1994+
GetEmitter()->emitEndCodeGen(compiler, trackedStackPtrsContig, GetInterruptible(), IsFullPtrRegMapRequired(),
1995+
compiler->compHndBBtabCount, &prologSize, &epilogSize, codePtr, &codePtrRW,
1996+
&coldCodePtr, &coldCodePtrRW, &consPtr, &consPtrRW DEBUGARG(&instrCount));
19961997

19971998
#ifdef DEBUG
19981999
assert(compiler->compCodeGenDone == false);
@@ -2085,7 +2086,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()
20852086

20862087
genSetScopeInfo();
20872088

2088-
#ifdef LATE_DISASM
2089+
#if defined(LATE_DISASM) || defined(DEBUG)
20892090
unsigned finalHotCodeSize;
20902091
unsigned finalColdCodeSize;
20912092
if (compiler->fgFirstColdBlock != nullptr)
@@ -2107,14 +2108,21 @@ void CodeGen::genEmitUnwindDebugGCandEH()
21072108
finalHotCodeSize = codeSize;
21082109
finalColdCodeSize = 0;
21092110
}
2110-
getDisAssembler().disAsmCode((BYTE*)*codePtr, finalHotCodeSize, (BYTE*)coldCodePtr, finalColdCodeSize);
2111+
#endif // defined(LATE_DISASM) || defined(DEBUG)
2112+
2113+
#ifdef LATE_DISASM
2114+
getDisAssembler().disAsmCode((BYTE*)*codePtr, (BYTE*)codePtrRW, finalHotCodeSize, (BYTE*)coldCodePtr,
2115+
(BYTE*)coldCodePtrRW, finalColdCodeSize);
21112116
#endif // LATE_DISASM
21122117

21132118
#ifdef DEBUG
21142119
if (JitConfig.JitRawHexCode().contains(compiler->info.compMethodHnd, compiler->info.compClassHnd,
21152120
&compiler->info.compMethodInfo->args))
21162121
{
2117-
BYTE* addr = (BYTE*)*codePtr + compiler->GetEmitter()->writeableOffset;
2122+
// NOTE: code in cold region is not supported.
2123+
2124+
BYTE* dumpAddr = (BYTE*)codePtrRW;
2125+
size_t dumpSize = finalHotCodeSize;
21182126

21192127
const WCHAR* rawHexCodeFilePath = JitConfig.JitRawHexCodeFile();
21202128
if (rawHexCodeFilePath)
@@ -2124,7 +2132,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()
21242132
if (ec == 0)
21252133
{
21262134
assert(hexDmpf);
2127-
hexDump(hexDmpf, addr, codeSize);
2135+
hexDump(hexDmpf, dumpAddr, dumpSize);
21282136
fclose(hexDmpf);
21292137
}
21302138
}
@@ -2133,7 +2141,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()
21332141
FILE* dmpf = jitstdout();
21342142

21352143
fprintf(dmpf, "Generated native code for %s:\n", compiler->info.compFullName);
2136-
hexDump(dmpf, addr, codeSize);
2144+
hexDump(dmpf, dumpAddr, dumpSize);
21372145
fprintf(dmpf, "\n\n");
21382146
}
21392147
}

src/coreclr/jit/codegenlinear.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,12 +2672,12 @@ void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
26722672
#endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64
26732673

26742674
/*****************************************************************************
2675-
* Unit testing of the emitter: If JitDumpEmitUnitTests is set, generate
2676-
* a bunch of instructions, then:
2677-
* Use DOTNET_JitLateDisasm=* to see if the late disassembler thinks the instructions are the same as we do.
2678-
* Or, use DOTNET_JitRawHexCode and DOTNET_JitRawHexCodeFile and disassemble the output file.
2675+
* Unit testing of the emitter: If JitEmitUnitTests is set for this function, generate
2676+
* a bunch of instructions, then either:
2677+
* 1. Use DOTNET_JitLateDisasm=* to see if the late disassembler thinks the instructions are the same as we do. Or,
2678+
* 2. Use DOTNET_JitRawHexCode and DOTNET_JitRawHexCodeFile and disassemble the output file with an external disassembler.
26792679
*
2680-
* Possible values for JitDumpEmitUnitTests:
2680+
* Possible values for JitEmitUnitTestsSections:
26812681
* Amd64: all, sse2
26822682
* Arm64: all, general, advsimd, sve
26832683
*/
@@ -2686,7 +2686,13 @@ void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
26862686

26872687
void CodeGen::genEmitterUnitTests()
26882688
{
2689-
const WCHAR* unitTestSection = JitConfig.JitDumpEmitUnitTests();
2689+
if (!JitConfig.JitEmitUnitTests().contains(compiler->info.compMethodHnd, compiler->info.compClassHnd,
2690+
&compiler->info.compMethodInfo->args))
2691+
{
2692+
return;
2693+
}
2694+
2695+
const WCHAR* unitTestSection = JitConfig.JitEmitUnitTestsSections();
26902696

26912697
if (unitTestSection == nullptr)
26922698
{

src/coreclr/jit/codegenxarch.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9037,7 +9037,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
90379037

90389038
void CodeGen::genAmd64EmitterUnitTestsSse2()
90399039
{
9040-
assert(verbose);
90419040
emitter* theEmitter = GetEmitter();
90429041

90439042
//

src/coreclr/jit/disasm.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,12 @@ void DisAssembler::disRecordRelocation(size_t relocAddr, size_t targetAddr)
14641464
* Disassemble the code which has been generated
14651465
*/
14661466

1467-
void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCodePtr, size_t coldCodeSize)
1467+
void DisAssembler::disAsmCode(BYTE* hotCodePtr,
1468+
BYTE* hotCodePtrRW,
1469+
size_t hotCodeSize,
1470+
BYTE* coldCodePtr,
1471+
BYTE* coldCodePtrRW,
1472+
size_t coldCodeSize)
14681473
{
14691474
if (!disComp->opts.doLateDisasm)
14701475
{
@@ -1511,22 +1516,22 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo
15111516
fprintf(disAsmFile, "************************** %hs:%hs size 0x%04IX **************************\n\n",
15121517
disCurClassName, disCurMethodName, hotCodeSize);
15131518

1514-
fprintf(disAsmFile, "Base address : %ph\n", dspAddr(hotCodePtr));
1519+
fprintf(disAsmFile, "Base address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW));
15151520
}
15161521
else
15171522
{
15181523
fprintf(disAsmFile,
15191524
"************************** %hs:%hs hot size 0x%04IX cold size 0x%04IX **************************\n\n",
15201525
disCurClassName, disCurMethodName, hotCodeSize, coldCodeSize);
15211526

1522-
fprintf(disAsmFile, "Hot address : %ph\n", dspAddr(hotCodePtr));
1523-
fprintf(disAsmFile, "Cold address : %ph\n", dspAddr(coldCodePtr));
1527+
fprintf(disAsmFile, "Hot address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW));
1528+
fprintf(disAsmFile, "Cold address : %ph (RW: %ph)\n", dspAddr(coldCodePtr), dspAddr(coldCodePtrRW));
15241529
}
15251530

15261531
disStartAddr = 0;
1527-
disHotCodeBlock = (size_t)hotCodePtr;
1532+
disHotCodeBlock = (size_t)hotCodePtrRW;
15281533
disHotCodeSize = hotCodeSize;
1529-
disColdCodeBlock = (size_t)coldCodePtr;
1534+
disColdCodeBlock = (size_t)coldCodePtrRW;
15301535
disColdCodeSize = coldCodeSize;
15311536

15321537
disTotalCodeSize = disHotCodeSize + disColdCodeSize;

src/coreclr/jit/disasm.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ class DisAssembler
9393
void disOpenForLateDisAsm(const char* curMethodName, const char* curClassName, PCCOR_SIGNATURE sig);
9494

9595
// Disassemble a buffer: called after code for a method is generated.
96-
void disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCodePtr, size_t coldCodeSize);
96+
void disAsmCode(BYTE* hotCodePtr,
97+
BYTE* hotCodePtrRW,
98+
size_t hotCodeSize,
99+
BYTE* coldCodePtr,
100+
BYTE* coldCodePtrRW,
101+
size_t coldCodeSize);
97102

98103
// Register an address to be associated with a method handle.
99104
void disSetMethod(size_t addr, CORINFO_METHOD_HANDLE methHnd);

src/coreclr/jit/emit.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6612,19 +6612,23 @@ void emitter::emitComputeCodeSizes()
66126612
}
66136613

66146614
//------------------------------------------------------------------------
6615-
// emitEndCodeGen: called at end of code generation to create code, data, and gc info
6615+
// emitEndCodeGen: called at end of code generation to create code, data, and GC info
66166616
//
66176617
// Arguments:
6618-
// comp - compiler instance
6618+
// comp - compiler instance
66196619
// contTrkPtrLcls - true if tracked stack pointers are contiguous on the stack
6620-
// fullInt - true if method has fully interruptible gc reporting
6621-
// fullPtrMap - true if gc reporting should use full register pointer map
6622-
// xcptnsCount - number of EH clauses to report for the method
6623-
// prologSize [OUT] - prolog size in bytes
6624-
// epilogSize [OUT] - epilog size in bytes (see notes)
6625-
// codeAddr [OUT] - address of the code buffer
6626-
// coldCodeAddr [OUT] - address of the cold code buffer (if any)
6627-
// consAddr [OUT] - address of the read only constant buffer (if any)
6620+
// fullyInt - true if method has fully interruptible GC reporting
6621+
// fullPtrMap - true if gc reporting should use full register pointer map
6622+
// xcptnsCount - number of EH clauses to report for the method
6623+
// prologSize - [OUT] prolog size in bytes
6624+
// epilogSize - [OUT] epilog size in bytes (see notes)
6625+
// codeAddr - [OUT] address of the code buffer
6626+
// codeAddrRW - [OUT] Read/write address of the code buffer
6627+
// coldCodeAddr - [OUT] address of the cold code buffer (if any)
6628+
// coldCodeAddrRW - [OUT] Read/write address of the cold code buffer (if any)
6629+
// consAddr - [OUT] address of the read only constant buffer (if any)
6630+
// consAddrRW - [OUT] Read/write address of the read only constant buffer (if any)
6631+
// instrCount - [OUT] [DEBUG ONLY] number of instructions generated.
66286632
//
66296633
// Notes:
66306634
// Currently, in methods with multiple epilogs, all epilogs must have the same
@@ -6642,8 +6646,11 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
66426646
unsigned* prologSize,
66436647
unsigned* epilogSize,
66446648
void** codeAddr,
6649+
void** codeAddrRW,
66456650
void** coldCodeAddr,
6646-
void** consAddr DEBUGARG(unsigned* instrCount))
6651+
void** coldCodeAddrRW,
6652+
void** consAddr,
6653+
void** consAddrRW DEBUGARG(unsigned* instrCount))
66476654
{
66486655
#ifdef DEBUG
66496656
if (emitComp->verbose)
@@ -6900,8 +6907,11 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
69006907
/* Give the block addresses to the caller and other functions here */
69016908

69026909
*codeAddr = emitCodeBlock = codeBlock;
6910+
*codeAddrRW = codeBlockRW;
69036911
*coldCodeAddr = emitColdCodeBlock = coldCodeBlock;
6912+
*coldCodeAddrRW = coldCodeBlockRW;
69046913
*consAddr = emitConsBlock = consBlock;
6914+
*consAddrRW = consBlockRW;
69056915

69066916
/* Nothing has been pushed on the stack */
69076917
CLANG_FORMAT_COMMENT_ANCHOR;

src/coreclr/jit/emitpub.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ unsigned emitEndCodeGen(Compiler* comp,
3030
unsigned* prologSize,
3131
unsigned* epilogSize,
3232
void** codeAddr,
33+
void** codeAddrRW,
3334
void** coldCodeAddr,
34-
void** consAddr DEBUGARG(unsigned* instrCount));
35+
void** coldCodeAddrRW,
36+
void** consAddr,
37+
void** consAddrRW DEBUGARG(unsigned* instrCount));
3538

3639
/************************************************************************/
3740
/* Method prolog and epilog */

src/coreclr/jit/jitconfigvalues.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,10 @@ CONFIG_METHODSET(JitGCDump, W("JitGCDump"))
199199
CONFIG_METHODSET(JitDebugDump, W("JitDebugDump"))
200200
CONFIG_METHODSET(JitHalt, W("JitHalt")) // Emits break instruction into jitted code
201201
CONFIG_METHODSET(JitInclude, W("JitInclude"))
202-
CONFIG_METHODSET(JitLateDisasm, W("JitLateDisasm"))
203-
CONFIG_METHODSET(JitMinOptsName, W("JITMinOptsName")) // Forces MinOpts for a named function
202+
CONFIG_METHODSET(JitLateDisasm, W("JitLateDisasm")) // Generate late disassembly for the specified methods.
203+
CONFIG_STRING(JitLateDisasmTo, W("JitLateDisasmTo")) // If set, sends late disassembly output to this file instead of
204+
// stdout/JitStdOutFile.
205+
CONFIG_METHODSET(JitMinOptsName, W("JITMinOptsName")) // Forces MinOpts for a named function
204206
CONFIG_METHODSET(JitNoProcedureSplitting, W("JitNoProcedureSplitting")) // Disallow procedure splitting for specified
205207
// methods
206208
CONFIG_METHODSET(JitNoProcedureSplittingEH, W("JitNoProcedureSplittingEH")) // Disallow procedure splitting for
@@ -235,15 +237,15 @@ CONFIG_INTEGER(JitDumpFgBlockOrder, W("JitDumpFgBlockOrder"), 0) // 0 == bbNext
235237
// order
236238
CONFIG_INTEGER(JitDumpFgMemorySsa, W("JitDumpFgMemorySsa"), 0) // non-zero: show memory phis + SSA/VNs
237239

238-
CONFIG_STRING(JitLateDisasmTo, W("JITLateDisasmTo"))
239240
CONFIG_STRING(JitRange, W("JitRange"))
240241
CONFIG_STRING(JitStressModeNames, W("JitStressModeNames")) // Internal Jit stress mode: stress using the given set of
241242
// stress mode names, e.g. STRESS_REGS, STRESS_TAILCALL
242243
CONFIG_STRING(JitStressModeNamesNot, W("JitStressModeNamesNot")) // Internal Jit stress mode: do NOT stress using the
243244
// given set of stress mode names, e.g. STRESS_REGS,
244245
// STRESS_TAILCALL
245246
CONFIG_STRING(JitStressRange, W("JitStressRange")) // Internal Jit stress mode
246-
CONFIG_STRING(JitDumpEmitUnitTests, W("JitDumpEmitUnitTests")) // Dump unit tests from Emit
247+
CONFIG_METHODSET(JitEmitUnitTests, W("JitEmitUnitTests")) // Generate emitter unit tests in the specified functions
248+
CONFIG_STRING(JitEmitUnitTestsSections, W("JitEmitUnitTestsSections")) // Generate this set of unit tests
247249

248250
///
249251
/// JIT Hardware Intrinsics

src/coreclr/jit/utils.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,14 +1321,14 @@ int SimpleSprintf_s(_In_reads_(cbBufSize - (pWriteStart - pBufStart)) char* pWri
13211321

13221322
void hexDump(FILE* dmpf, BYTE* addr, size_t size)
13231323
{
1324-
if (!size)
1324+
if (size == 0)
13251325
{
13261326
return;
13271327
}
13281328

1329-
assert(addr);
1329+
assert(addr != nullptr);
13301330

1331-
for (unsigned i = 0; i < size; i++)
1331+
for (size_t i = 0; i < size; i++)
13321332
{
13331333
fprintf(dmpf, "%02X", *addr++);
13341334
}

0 commit comments

Comments
 (0)