From c159108d3c8048b952cc01fb7258ff4fd54dcb80 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 19 Nov 2021 01:49:21 +0100 Subject: [PATCH] Add JitDisasmWithDebugInfo (#61780) Add COMPlus_JitDisasmWithDebugInfo. When set and in verbose/disasm mode, JIT will display inline comments with debug information before the instructions that debug info applies to. Change superpmi with --debuginfo to use this mode. Also small change to dotnet-pgo flow graph dump to write offsets in the same format. --- src/coreclr/jit/codegenlinear.cpp | 5 ++- src/coreclr/jit/emit.cpp | 43 +++++++++++++++++-- src/coreclr/jit/emit.h | 9 ++++ src/coreclr/jit/emitarm.cpp | 16 +++++++ src/coreclr/jit/emitarm.h | 8 ---- src/coreclr/jit/emitarm64.cpp | 21 ++++++--- src/coreclr/jit/emitarm64.h | 9 ---- src/coreclr/jit/emitxarch.cpp | 21 ++++++--- src/coreclr/jit/emitxarch.h | 9 ---- src/coreclr/jit/jitconfigvalues.h | 1 + src/coreclr/scripts/superpmi.py | 3 +- .../dotnet-pgo/PgoCompareMethodFlowGraph.cs | 2 +- 12 files changed, 105 insertions(+), 42 deletions(-) diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index c85da2837a7b3..88788fa097e2a 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -424,6 +424,9 @@ void CodeGen::genCodeForBBlist() } } } + + bool addPreciseMappings = + (JitConfig.JitDumpPreciseDebugInfoFile() != nullptr) || (JitConfig.JitDisasmWithDebugInfo() != 0); #endif // DEBUG DebugInfo currentDI; @@ -443,7 +446,7 @@ void CodeGen::genCodeForBBlist() } #ifdef DEBUG - if ((JitConfig.JitDumpPreciseDebugInfoFile() != nullptr) && ilOffset->gtStmtDI.IsValid()) + if (addPreciseMappings && ilOffset->gtStmtDI.IsValid()) { genAddPreciseIPMappingHere(ilOffset->gtStmtDI); } diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index f81de138b8bcb..9e80771938cfe 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -3381,6 +3381,15 @@ const size_t hexEncodingSize = 11; #ifdef DEBUG //------------------------------------------------------------------------ +// emitDispInsIndent: Print indentation corresponding to an instruction's +// indentation. +// +void emitter::emitDispInsIndent() +{ + size_t indent = emitComp->opts.disDiffable ? basicIndent : basicIndent + hexEncodingSize; + printf("%.*s", indent, " "); +} +//------------------------------------------------------------------------ // emitDispGCDeltaTitle: Print an appropriately indented title for a GC info delta // // Arguments: @@ -3388,8 +3397,8 @@ const size_t hexEncodingSize = 11; // void emitter::emitDispGCDeltaTitle(const char* title) { - size_t indent = emitComp->opts.disDiffable ? basicIndent : basicIndent + hexEncodingSize; - printf("%.*s; %s", indent, " ", title); + emitDispInsIndent(); + printf("; %s", title); } //------------------------------------------------------------------------ @@ -6233,7 +6242,8 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #define DEFAULT_CODE_BUFFER_INIT 0xcc #ifdef DEBUG - *instrCount = 0; + *instrCount = 0; + PreciseIPMapping* nextMapping = emitComp->genPreciseIPMappingsHead; #endif for (insGroup* ig = emitIGlist; ig != nullptr; ig = ig->igNext) { @@ -6402,6 +6412,33 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #ifdef DEBUG size_t curInstrAddr = (size_t)cp; instrDesc* curInstrDesc = id; + + if ((emitComp->opts.disAsm || emitComp->verbose) && (JitConfig.JitDisasmWithDebugInfo() != 0)) + { + UNATIVE_OFFSET curCodeOffs = emitCurCodeOffs(cp); + while (nextMapping != nullptr) + { + UNATIVE_OFFSET mappingOffs = nextMapping->nativeLoc.CodeOffset(this); + + if (mappingOffs > curCodeOffs) + { + // Still haven't reached instruction that next mapping belongs to. + break; + } + + // We reached the mapping or went past it. + if (mappingOffs == curCodeOffs) + { + emitDispInsIndent(); + printf("; "); + nextMapping->debugInfo.Dump(true); + printf("\n"); + } + + nextMapping = nextMapping->next; + } + } + #endif castto(id, BYTE*) += emitIssue1Instr(ig, id, &cp); diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index c851df9df80a1..ade4f7c3ca2c1 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -1548,6 +1548,7 @@ class emitter regPtrDsc* debugPrevRegPtrDsc; regMaskTP debugPrevGCrefRegs; regMaskTP debugPrevByrefRegs; + void emitDispInsIndent(); void emitDispGCDeltaTitle(const char* title); void emitDispGCRegDelta(const char* title, regMaskTP prevRegs, regMaskTP curRegs); void emitDispGCVarDelta(); @@ -1563,6 +1564,14 @@ class emitter void emitDispInsAddr(BYTE* code); void emitDispInsOffs(unsigned offs, bool doffs); void emitDispInsHex(instrDesc* id, BYTE* code, size_t sz); + void emitDispIns(instrDesc* id, + bool isNew, + bool doffs, + bool asmfm, + unsigned offs = 0, + BYTE* pCode = nullptr, + size_t sz = 0, + insGroup* ig = nullptr); #else // !DEBUG #define emitVarRefOffs 0 diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index 9c51dbc7c54f2..5f7ef33565e93 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -7670,6 +7670,22 @@ void emitter::emitDispInsHelp( printf("\n"); } +//-------------------------------------------------------------------- +// emitDispIns: Dump the given instruction to jitstdout. +// +// Arguments: +// id - The instruction +// isNew - Whether the instruction is newly generated (before encoding). +// doffs - If true, always display the passed-in offset. +// asmfm - Whether the instruction should be displayed in assembly format. +// If false some additional information may be printed for the instruction. +// offset - The offset of the instruction. Only displayed if doffs is true or if +// !isNew && !asmfm. +// code - Pointer to the actual code, used for displaying the address and encoded bytes +// if turned on. +// sz - The size of the instruction, used to display the encoded bytes. +// ig - The instruction group containing the instruction. +// void emitter::emitDispIns( instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig) { diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h index c93c15dff8ea9..9dd2c175190dc 100644 --- a/src/coreclr/jit/emitarm.h +++ b/src/coreclr/jit/emitarm.h @@ -52,14 +52,6 @@ void emitDispInsHelp(instrDesc* id, BYTE* code = 0, size_t sz = 0, insGroup* ig = NULL); -void emitDispIns(instrDesc* id, - bool isNew, - bool doffs, - bool asmfm, - unsigned offs = 0, - BYTE* code = 0, - size_t sz = 0, - insGroup* ig = NULL); #endif // DEBUG diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 3de8faafc13c6..004871baf9fe2 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -12228,11 +12228,22 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) } } -/**************************************************************************** - * - * Display the given instruction. - */ - +//-------------------------------------------------------------------- +// emitDispIns: Dump the given instruction to jitstdout. +// +// Arguments: +// id - The instruction +// isNew - Whether the instruction is newly generated (before encoding). +// doffs - If true, always display the passed-in offset. +// asmfm - Whether the instruction should be displayed in assembly format. +// If false some additional information may be printed for the instruction. +// offset - The offset of the instruction. Only displayed if doffs is true or if +// !isNew && !asmfm. +// code - Pointer to the actual code, used for displaying the address and encoded bytes +// if turned on. +// sz - The size of the instruction, used to display the encoded bytes. +// ig - The instruction group containing the instruction. +// void emitter::emitDispIns( instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) { diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index ab06c5e25c700..05909f6d2e175 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -45,15 +45,6 @@ void emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAttr attr); void emitDispExtendReg(regNumber reg, insOpts opt, ssize_t imm); void emitDispAddrRI(regNumber reg, insOpts opt, ssize_t imm); void emitDispAddrRRExt(regNumber reg1, regNumber reg2, insOpts opt, bool isScaled, emitAttr size); - -void emitDispIns(instrDesc* id, - bool isNew, - bool doffs, - bool asmfm, - unsigned offs = 0, - BYTE* pCode = 0, - size_t sz = 0, - insGroup* ig = NULL); #endif // DEBUG /************************************************************************/ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 8246f2de377fb..e67029d3cf132 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -8722,11 +8722,22 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) } } -/***************************************************************************** - * - * Display the given instruction. - */ - +//-------------------------------------------------------------------- +// emitDispIns: Dump the given instruction to jitstdout. +// +// Arguments: +// id - The instruction +// isNew - Whether the instruction is newly generated (before encoding). +// doffs - If true, always display the passed-in offset. +// asmfm - Whether the instruction should be displayed in assembly format. +// If false some additional information may be printed for the instruction. +// offset - The offset of the instruction. Only displayed if doffs is true or if +// !isNew && !asmfm. +// code - Pointer to the actual code, used for displaying the address and encoded bytes +// if turned on. +// sz - The size of the instruction, used to display the encoded bytes. +// ig - The instruction group containing the instruction. Not used on xarch. +// void emitter::emitDispIns( instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig) { diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h index d57b986623a13..54575044f1386 100644 --- a/src/coreclr/jit/emitxarch.h +++ b/src/coreclr/jit/emitxarch.h @@ -222,15 +222,6 @@ void emitDispReloc(ssize_t value); void emitDispAddrMode(instrDesc* id, bool noDetail = false); void emitDispShift(instruction ins, int cnt = 0); -void emitDispIns(instrDesc* id, - bool isNew, - bool doffs, - bool asmfm, - unsigned offs = 0, - BYTE* code = nullptr, - size_t sz = 0, - insGroup* ig = nullptr); - const char* emitXMMregName(unsigned reg); const char* emitYMMregName(unsigned reg); diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index bad8ed6de2446..06211a597c8ed 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -233,6 +233,7 @@ CONFIG_INTEGER(JitDumpFgBlockID, W("JitDumpFgBlockID"), 0) // 0 == display block // bbNum and bbID CONFIG_STRING(JitDumpPreciseDebugInfoFile, W("JitDumpPreciseDebugInfoFile")) +CONFIG_INTEGER(JitDisasmWithDebugInfo, W("JitDisasmWithDebugInfo"), 0) CONFIG_STRING(JitLateDisasmTo, W("JITLateDisasmTo")) CONFIG_STRING(JitRange, W("JitRange")) diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 86ab04a9b4d92..267879c5a9eb5 100755 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -1363,7 +1363,8 @@ def replay_with_asm_diffs(self): if self.coreclr_args.debuginfo: asm_complus_vars.update({ "COMPlus_JitDebugDump": "*", - "COMPlus_NgenDebugDump": "*" }) + "COMPlus_NgenDebugDump": "*", + "COMPlus_JitDisasmWithDebugInfo": "1" }) jit_dump_complus_vars = asm_complus_vars.copy() jit_dump_complus_vars.update({ diff --git a/src/coreclr/tools/dotnet-pgo/PgoCompareMethodFlowGraph.cs b/src/coreclr/tools/dotnet-pgo/PgoCompareMethodFlowGraph.cs index af55de3e9f747..fd7556ecce6a0 100644 --- a/src/coreclr/tools/dotnet-pgo/PgoCompareMethodFlowGraph.cs +++ b/src/coreclr/tools/dotnet-pgo/PgoCompareMethodFlowGraph.cs @@ -91,7 +91,7 @@ string createWeightLabel(long weight1, long totalWeight1, long weight2, long tot string getLabel(PgoCompareMethodBasicBlock bb) { - string label = $"@ {bb.ILOffset:000}"; + string label = $"@ {bb.ILOffset:x3}"; if (ProfilesHadBasicBlocks && (totalBlockCount1 != 0 || totalBlockCount2 != 0)) { label += $"\\n{createWeightLabel(bb.BlockCount1, totalBlockCount1, bb.BlockCount2, totalBlockCount2)}";