Skip to content

Commit

Permalink
Refine usage of late disassembler and emitter unit tests (#96467)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

---------

Co-authored-by: Kunal Pathak <[email protected]>
  • Loading branch information
BruceForstall and kunalspathak authored Jan 4, 2024
1 parent fac60d0 commit db90a84
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 41 deletions.
3 changes: 3 additions & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,13 @@ class CodeGen final : public CodeGenInterface
BasicBlock* genPendingCallLabel;

void** codePtr;
void* codePtrRW;
uint32_t* nativeSizeOfCode;
unsigned codeSize;
void* coldCodePtr;
void* coldCodePtrRW;
void* consPtr;
void* consPtrRW;

// Last instr we have displayed for dspInstrs
unsigned genCurDispOffset;
Expand Down
24 changes: 16 additions & 8 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1990,9 +1990,10 @@ void CodeGen::genEmitMachineCode()
printf("; BEGIN METHOD %s\n", compiler->eeGetMethodFullName(compiler->info.compMethodHnd));
}

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

#ifdef DEBUG
assert(compiler->compCodeGenDone == false);
Expand Down Expand Up @@ -2085,7 +2086,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()

genSetScopeInfo();

#ifdef LATE_DISASM
#if defined(LATE_DISASM) || defined(DEBUG)
unsigned finalHotCodeSize;
unsigned finalColdCodeSize;
if (compiler->fgFirstColdBlock != nullptr)
Expand All @@ -2107,14 +2108,21 @@ void CodeGen::genEmitUnwindDebugGCandEH()
finalHotCodeSize = codeSize;
finalColdCodeSize = 0;
}
getDisAssembler().disAsmCode((BYTE*)*codePtr, finalHotCodeSize, (BYTE*)coldCodePtr, finalColdCodeSize);
#endif // defined(LATE_DISASM) || defined(DEBUG)

#ifdef LATE_DISASM
getDisAssembler().disAsmCode((BYTE*)*codePtr, (BYTE*)codePtrRW, finalHotCodeSize, (BYTE*)coldCodePtr,
(BYTE*)coldCodePtrRW, finalColdCodeSize);
#endif // LATE_DISASM

#ifdef DEBUG
if (JitConfig.JitRawHexCode().contains(compiler->info.compMethodHnd, compiler->info.compClassHnd,
&compiler->info.compMethodInfo->args))
{
BYTE* addr = (BYTE*)*codePtr + compiler->GetEmitter()->writeableOffset;
// NOTE: code in cold region is not supported.

BYTE* dumpAddr = (BYTE*)codePtrRW;
size_t dumpSize = finalHotCodeSize;

const WCHAR* rawHexCodeFilePath = JitConfig.JitRawHexCodeFile();
if (rawHexCodeFilePath)
Expand All @@ -2124,7 +2132,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()
if (ec == 0)
{
assert(hexDmpf);
hexDump(hexDmpf, addr, codeSize);
hexDump(hexDmpf, dumpAddr, dumpSize);
fclose(hexDmpf);
}
}
Expand All @@ -2133,7 +2141,7 @@ void CodeGen::genEmitUnwindDebugGCandEH()
FILE* dmpf = jitstdout();

fprintf(dmpf, "Generated native code for %s:\n", compiler->info.compFullName);
hexDump(dmpf, addr, codeSize);
hexDump(dmpf, dumpAddr, dumpSize);
fprintf(dmpf, "\n\n");
}
}
Expand Down
18 changes: 12 additions & 6 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2672,12 +2672,12 @@ void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
#endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64

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

void CodeGen::genEmitterUnitTests()
{
const WCHAR* unitTestSection = JitConfig.JitDumpEmitUnitTests();
if (!JitConfig.JitEmitUnitTests().contains(compiler->info.compMethodHnd, compiler->info.compClassHnd,
&compiler->info.compMethodInfo->args))
{
return;
}

const WCHAR* unitTestSection = JitConfig.JitEmitUnitTestsSections();

if (unitTestSection == nullptr)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9037,7 +9037,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,

void CodeGen::genAmd64EmitterUnitTestsSse2()
{
assert(verbose);
emitter* theEmitter = GetEmitter();

//
Expand Down
17 changes: 11 additions & 6 deletions src/coreclr/jit/disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,12 @@ void DisAssembler::disRecordRelocation(size_t relocAddr, size_t targetAddr)
* Disassemble the code which has been generated
*/

void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCodePtr, size_t coldCodeSize)
void DisAssembler::disAsmCode(BYTE* hotCodePtr,
BYTE* hotCodePtrRW,
size_t hotCodeSize,
BYTE* coldCodePtr,
BYTE* coldCodePtrRW,
size_t coldCodeSize)
{
if (!disComp->opts.doLateDisasm)
{
Expand Down Expand Up @@ -1511,22 +1516,22 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo
fprintf(disAsmFile, "************************** %hs:%hs size 0x%04IX **************************\n\n",
disCurClassName, disCurMethodName, hotCodeSize);

fprintf(disAsmFile, "Base address : %ph\n", dspAddr(hotCodePtr));
fprintf(disAsmFile, "Base address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW));
}
else
{
fprintf(disAsmFile,
"************************** %hs:%hs hot size 0x%04IX cold size 0x%04IX **************************\n\n",
disCurClassName, disCurMethodName, hotCodeSize, coldCodeSize);

fprintf(disAsmFile, "Hot address : %ph\n", dspAddr(hotCodePtr));
fprintf(disAsmFile, "Cold address : %ph\n", dspAddr(coldCodePtr));
fprintf(disAsmFile, "Hot address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW));
fprintf(disAsmFile, "Cold address : %ph (RW: %ph)\n", dspAddr(coldCodePtr), dspAddr(coldCodePtrRW));
}

disStartAddr = 0;
disHotCodeBlock = (size_t)hotCodePtr;
disHotCodeBlock = (size_t)hotCodePtrRW;
disHotCodeSize = hotCodeSize;
disColdCodeBlock = (size_t)coldCodePtr;
disColdCodeBlock = (size_t)coldCodePtrRW;
disColdCodeSize = coldCodeSize;

disTotalCodeSize = disHotCodeSize + disColdCodeSize;
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/jit/disasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ class DisAssembler
void disOpenForLateDisAsm(const char* curMethodName, const char* curClassName, PCCOR_SIGNATURE sig);

// Disassemble a buffer: called after code for a method is generated.
void disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCodePtr, size_t coldCodeSize);
void disAsmCode(BYTE* hotCodePtr,
BYTE* hotCodePtrRW,
size_t hotCodeSize,
BYTE* coldCodePtr,
BYTE* coldCodePtrRW,
size_t coldCodeSize);

// Register an address to be associated with a method handle.
void disSetMethod(size_t addr, CORINFO_METHOD_HANDLE methHnd);
Expand Down
32 changes: 21 additions & 11 deletions src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6612,19 +6612,23 @@ void emitter::emitComputeCodeSizes()
}

//------------------------------------------------------------------------
// emitEndCodeGen: called at end of code generation to create code, data, and gc info
// emitEndCodeGen: called at end of code generation to create code, data, and GC info
//
// Arguments:
// comp - compiler instance
// comp - compiler instance
// contTrkPtrLcls - true if tracked stack pointers are contiguous on the stack
// fullInt - true if method has fully interruptible gc reporting
// fullPtrMap - true if gc reporting should use full register pointer map
// xcptnsCount - number of EH clauses to report for the method
// prologSize [OUT] - prolog size in bytes
// epilogSize [OUT] - epilog size in bytes (see notes)
// codeAddr [OUT] - address of the code buffer
// coldCodeAddr [OUT] - address of the cold code buffer (if any)
// consAddr [OUT] - address of the read only constant buffer (if any)
// fullyInt - true if method has fully interruptible GC reporting
// fullPtrMap - true if gc reporting should use full register pointer map
// xcptnsCount - number of EH clauses to report for the method
// prologSize - [OUT] prolog size in bytes
// epilogSize - [OUT] epilog size in bytes (see notes)
// codeAddr - [OUT] address of the code buffer
// codeAddrRW - [OUT] Read/write address of the code buffer
// coldCodeAddr - [OUT] address of the cold code buffer (if any)
// coldCodeAddrRW - [OUT] Read/write address of the cold code buffer (if any)
// consAddr - [OUT] address of the read only constant buffer (if any)
// consAddrRW - [OUT] Read/write address of the read only constant buffer (if any)
// instrCount - [OUT] [DEBUG ONLY] number of instructions generated.
//
// Notes:
// Currently, in methods with multiple epilogs, all epilogs must have the same
Expand All @@ -6642,8 +6646,11 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
unsigned* prologSize,
unsigned* epilogSize,
void** codeAddr,
void** codeAddrRW,
void** coldCodeAddr,
void** consAddr DEBUGARG(unsigned* instrCount))
void** coldCodeAddrRW,
void** consAddr,
void** consAddrRW DEBUGARG(unsigned* instrCount))
{
#ifdef DEBUG
if (emitComp->verbose)
Expand Down Expand Up @@ -6900,8 +6907,11 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
/* Give the block addresses to the caller and other functions here */

*codeAddr = emitCodeBlock = codeBlock;
*codeAddrRW = codeBlockRW;
*coldCodeAddr = emitColdCodeBlock = coldCodeBlock;
*coldCodeAddrRW = coldCodeBlockRW;
*consAddr = emitConsBlock = consBlock;
*consAddrRW = consBlockRW;

/* Nothing has been pushed on the stack */
CLANG_FORMAT_COMMENT_ANCHOR;
Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/jit/emitpub.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ unsigned emitEndCodeGen(Compiler* comp,
unsigned* prologSize,
unsigned* epilogSize,
void** codeAddr,
void** codeAddrRW,
void** coldCodeAddr,
void** consAddr DEBUGARG(unsigned* instrCount));
void** coldCodeAddrRW,
void** consAddr,
void** consAddrRW DEBUGARG(unsigned* instrCount));

/************************************************************************/
/* Method prolog and epilog */
Expand Down
10 changes: 6 additions & 4 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,10 @@ CONFIG_METHODSET(JitGCDump, W("JitGCDump"))
CONFIG_METHODSET(JitDebugDump, W("JitDebugDump"))
CONFIG_METHODSET(JitHalt, W("JitHalt")) // Emits break instruction into jitted code
CONFIG_METHODSET(JitInclude, W("JitInclude"))
CONFIG_METHODSET(JitLateDisasm, W("JitLateDisasm"))
CONFIG_METHODSET(JitMinOptsName, W("JITMinOptsName")) // Forces MinOpts for a named function
CONFIG_METHODSET(JitLateDisasm, W("JitLateDisasm")) // Generate late disassembly for the specified methods.
CONFIG_STRING(JitLateDisasmTo, W("JitLateDisasmTo")) // If set, sends late disassembly output to this file instead of
// stdout/JitStdOutFile.
CONFIG_METHODSET(JitMinOptsName, W("JITMinOptsName")) // Forces MinOpts for a named function
CONFIG_METHODSET(JitNoProcedureSplitting, W("JitNoProcedureSplitting")) // Disallow procedure splitting for specified
// methods
CONFIG_METHODSET(JitNoProcedureSplittingEH, W("JitNoProcedureSplittingEH")) // Disallow procedure splitting for
Expand Down Expand Up @@ -235,15 +237,15 @@ CONFIG_INTEGER(JitDumpFgBlockOrder, W("JitDumpFgBlockOrder"), 0) // 0 == bbNext
// order
CONFIG_INTEGER(JitDumpFgMemorySsa, W("JitDumpFgMemorySsa"), 0) // non-zero: show memory phis + SSA/VNs

CONFIG_STRING(JitLateDisasmTo, W("JITLateDisasmTo"))
CONFIG_STRING(JitRange, W("JitRange"))
CONFIG_STRING(JitStressModeNames, W("JitStressModeNames")) // Internal Jit stress mode: stress using the given set of
// stress mode names, e.g. STRESS_REGS, STRESS_TAILCALL
CONFIG_STRING(JitStressModeNamesNot, W("JitStressModeNamesNot")) // Internal Jit stress mode: do NOT stress using the
// given set of stress mode names, e.g. STRESS_REGS,
// STRESS_TAILCALL
CONFIG_STRING(JitStressRange, W("JitStressRange")) // Internal Jit stress mode
CONFIG_STRING(JitDumpEmitUnitTests, W("JitDumpEmitUnitTests")) // Dump unit tests from Emit
CONFIG_METHODSET(JitEmitUnitTests, W("JitEmitUnitTests")) // Generate emitter unit tests in the specified functions
CONFIG_STRING(JitEmitUnitTestsSections, W("JitEmitUnitTestsSections")) // Generate this set of unit tests

///
/// JIT Hardware Intrinsics
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,14 +1321,14 @@ int SimpleSprintf_s(_In_reads_(cbBufSize - (pWriteStart - pBufStart)) char* pWri

void hexDump(FILE* dmpf, BYTE* addr, size_t size)
{
if (!size)
if (size == 0)
{
return;
}

assert(addr);
assert(addr != nullptr);

for (unsigned i = 0; i < size; i++)
for (size_t i = 0; i < size; i++)
{
fprintf(dmpf, "%02X", *addr++);
}
Expand Down

0 comments on commit db90a84

Please sign in to comment.