Skip to content

Commit a761b9f

Browse files
authored
Some more precise debug info improvements (#61419)
* We were not recording precise info in inlinees except for at IL offset 0 because most of the logic that handles determining when to attach debug info did not run for inlinees. There are no changes in what the EE sees since we were normalizing debug info back to the root anyway. * Propagate debug info even further than just until rationalization, to make it simpler to dump the precise debug info. This means we create some more GT_IL_OFFSET nodes, in particular when the inlinee debug info is valid but the root info is invalid. This is currently happening for newobj IL instructions when the constructor is inlined. We generate two statements: GT_ASG(GT_LCL_VAR(X), ALLOCOBJ(CLS)); GT_CALL(CTOR, GT_LCL_VAR(X)) and the first statement ends up "consuming" the debug info, meaning we end up with no debug info for the GT_CALL, which eventually propagates into the inline tree. I have held off on fixing this for now since it causes debug info diffs in the data reported back to the EE. The additional nodes in LIR result in 0.15% more memory use and 0.015% more instructions retired for SPMI over libraries. There is also a small fix in gtlist.h for GT_BFIZ when MEASURE_NODE_SIZES is defined. No SPMI diffs.
1 parent 6f5de0b commit a761b9f

File tree

7 files changed

+98
-105
lines changed

7 files changed

+98
-105
lines changed

src/coreclr/jit/codegenlinear.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,14 @@ void CodeGen::genCodeForBBlist()
432432
if (node->OperGet() == GT_IL_OFFSET)
433433
{
434434
GenTreeILOffset* ilOffset = node->AsILOffset();
435-
genEnsureCodeEmitted(currentDI);
436-
currentDI = ilOffset->gtStmtDI;
437-
genIPmappingAdd(IPmappingDscKind::Normal, currentDI, firstMapping);
438-
firstMapping = false;
435+
DebugInfo rootDI = ilOffset->gtStmtDI.GetRoot();
436+
if (rootDI.IsValid())
437+
{
438+
genEnsureCodeEmitted(currentDI);
439+
currentDI = rootDI;
440+
genIPmappingAdd(IPmappingDscKind::Normal, currentDI, firstMapping);
441+
firstMapping = false;
442+
}
439443
#ifdef DEBUG
440444
assert(ilOffset->gtStmtLastILoffs <= compiler->info.compILCodeSize ||
441445
ilOffset->gtStmtLastILoffs == BAD_IL_OFFSET);

src/coreclr/jit/debuginfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class ILLocation
3434
return m_isStackEmpty;
3535
}
3636

37+
// Is this a call instruction? Used for managed return values.
3738
bool IsCall() const
3839
{
3940
return m_isCall;

src/coreclr/jit/fgbasic.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4240,10 +4240,10 @@ BasicBlock* Compiler::fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node)
42404240
if ((*riter)->gtOper == GT_IL_OFFSET)
42414241
{
42424242
GenTreeILOffset* ilOffset = (*riter)->AsILOffset();
4243-
if (ilOffset->gtStmtDI.IsValid())
4243+
DebugInfo rootDI = ilOffset->gtStmtDI.GetRoot();
4244+
if (rootDI.IsValid())
42444245
{
4245-
assert(ilOffset->gtStmtDI.GetInlineContext()->IsRoot());
4246-
splitPointILOffset = ilOffset->gtStmtDI.GetLocation().GetOffset();
4246+
splitPointILOffset = rootDI.GetLocation().GetOffset();
42474247
break;
42484248
}
42494249
}

src/coreclr/jit/gentree.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11478,15 +11478,8 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
1147811478
break;
1147911479

1148011480
case GT_IL_OFFSET:
11481-
printf(" IL offset: ");
11482-
if (!tree->AsILOffset()->gtStmtDI.IsValid())
11483-
{
11484-
printf("???");
11485-
}
11486-
else
11487-
{
11488-
printf("0x%x", tree->AsILOffset()->gtStmtDI.GetLocation().GetOffset());
11489-
}
11481+
printf(" ");
11482+
tree->AsILOffset()->gtStmtDI.Dump(true);
1149011483
break;
1149111484

1149211485
case GT_JCC:

src/coreclr/jit/gtlist.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ GTNODE(MADD , GenTreeOp ,0, GTK_BINOP) // Ge
293293
GTNODE(JMPTABLE , GenTree ,0, (GTK_LEAF|GTK_NOCONTAIN)) // Generates the jump table for switches
294294
GTNODE(SWITCH_TABLE , GenTreeOp ,0, (GTK_BINOP|GTK_NOVALUE)) // Jump Table based switch construct
295295
#ifdef TARGET_ARM64
296-
GTNODE(BFIZ, GenTreeBfiz ,0, GTK_BINOP) // Bitfield Insert in Zero
296+
GTNODE(BFIZ , GenTreeOp ,0, GTK_BINOP) // Bitfield Insert in Zero
297297
#endif
298298

299299
//-----------------------------------------------------------------------------

src/coreclr/jit/importer.cpp

Lines changed: 74 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ inline void Compiler::impAppendStmt(Statement* stmt, unsigned chkLevel)
618618
// Once we set the current offset as debug info in an appended tree, we are
619619
// ready to report the following offsets. Note that we need to compare
620620
// offsets here instead of debug info, since we do not set the "is call"
621-
// debug in impCurStmtDI.
621+
// bit in impCurStmtDI.
622622

623623
if (impLastStmt->GetDebugInfo().GetLocation().GetOffset() == impCurStmtDI.GetLocation().GetOffset())
624624
{
@@ -3021,11 +3021,6 @@ unsigned Compiler::impInitBlockLineInfo()
30213021
impCurStmtOffsSet(blockOffs);
30223022
}
30233023

3024-
if (false && (info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES))
3025-
{
3026-
impCurStmtOffsSet(blockOffs);
3027-
}
3028-
30293024
/* Always report IL offset 0 or some tests get confused.
30303025
Probably a good idea anyways */
30313026

@@ -11721,111 +11716,108 @@ void Compiler::impImportBlockCode(BasicBlock* block)
1172111716
if (opts.compDbgInfo)
1172211717
#endif
1172311718
{
11724-
if (!compIsForInlining())
11725-
{
11726-
nxtStmtOffs =
11727-
(nxtStmtIndex < info.compStmtOffsetsCount) ? info.compStmtOffsets[nxtStmtIndex] : BAD_IL_OFFSET;
11719+
nxtStmtOffs =
11720+
(nxtStmtIndex < info.compStmtOffsetsCount) ? info.compStmtOffsets[nxtStmtIndex] : BAD_IL_OFFSET;
11721+
11722+
/* Have we reached the next stmt boundary ? */
1172811723

11729-
/* Have we reached the next stmt boundary ? */
11724+
if (nxtStmtOffs != BAD_IL_OFFSET && opcodeOffs >= nxtStmtOffs)
11725+
{
11726+
assert(nxtStmtOffs == info.compStmtOffsets[nxtStmtIndex]);
1173011727

11731-
if (nxtStmtOffs != BAD_IL_OFFSET && opcodeOffs >= nxtStmtOffs)
11728+
if (verCurrentState.esStackDepth != 0 && opts.compDbgCode)
1173211729
{
11733-
assert(nxtStmtOffs == info.compStmtOffsets[nxtStmtIndex]);
11730+
/* We need to provide accurate IP-mapping at this point.
11731+
So spill anything on the stack so that it will form
11732+
gtStmts with the correct stmt offset noted */
1173411733

11735-
if (verCurrentState.esStackDepth != 0 && opts.compDbgCode)
11736-
{
11737-
/* We need to provide accurate IP-mapping at this point.
11738-
So spill anything on the stack so that it will form
11739-
gtStmts with the correct stmt offset noted */
11734+
impSpillStackEnsure(true);
11735+
}
1174011736

11741-
impSpillStackEnsure(true);
11742-
}
11737+
// Have we reported debug info for any tree?
1174311738

11744-
// Have we reported debug info for any tree?
11739+
if (impCurStmtDI.IsValid() && opts.compDbgCode)
11740+
{
11741+
GenTree* placeHolder = new (this, GT_NO_OP) GenTree(GT_NO_OP, TYP_VOID);
11742+
impAppendTree(placeHolder, (unsigned)CHECK_SPILL_NONE, impCurStmtDI);
1174511743

11746-
if (impCurStmtDI.IsValid() && opts.compDbgCode)
11747-
{
11748-
GenTree* placeHolder = new (this, GT_NO_OP) GenTree(GT_NO_OP, TYP_VOID);
11749-
impAppendTree(placeHolder, (unsigned)CHECK_SPILL_NONE, impCurStmtDI);
11744+
assert(!impCurStmtDI.IsValid());
11745+
}
1175011746

11751-
assert(!impCurStmtDI.IsValid());
11752-
}
11747+
if (!impCurStmtDI.IsValid())
11748+
{
11749+
/* Make sure that nxtStmtIndex is in sync with opcodeOffs.
11750+
If opcodeOffs has gone past nxtStmtIndex, catch up */
1175311751

11754-
if (!impCurStmtDI.IsValid())
11752+
while ((nxtStmtIndex + 1) < info.compStmtOffsetsCount &&
11753+
info.compStmtOffsets[nxtStmtIndex + 1] <= opcodeOffs)
1175511754
{
11756-
/* Make sure that nxtStmtIndex is in sync with opcodeOffs.
11757-
If opcodeOffs has gone past nxtStmtIndex, catch up */
11758-
11759-
while ((nxtStmtIndex + 1) < info.compStmtOffsetsCount &&
11760-
info.compStmtOffsets[nxtStmtIndex + 1] <= opcodeOffs)
11761-
{
11762-
nxtStmtIndex++;
11763-
}
11755+
nxtStmtIndex++;
11756+
}
1176411757

11765-
/* Go to the new stmt */
11758+
/* Go to the new stmt */
1176611759

11767-
impCurStmtOffsSet(info.compStmtOffsets[nxtStmtIndex]);
11760+
impCurStmtOffsSet(info.compStmtOffsets[nxtStmtIndex]);
1176811761

11769-
/* Update the stmt boundary index */
11762+
/* Update the stmt boundary index */
1177011763

11771-
nxtStmtIndex++;
11772-
assert(nxtStmtIndex <= info.compStmtOffsetsCount);
11764+
nxtStmtIndex++;
11765+
assert(nxtStmtIndex <= info.compStmtOffsetsCount);
1177311766

11774-
/* Are there any more line# entries after this one? */
11767+
/* Are there any more line# entries after this one? */
1177511768

11776-
if (nxtStmtIndex < info.compStmtOffsetsCount)
11777-
{
11778-
/* Remember where the next line# starts */
11769+
if (nxtStmtIndex < info.compStmtOffsetsCount)
11770+
{
11771+
/* Remember where the next line# starts */
1177911772

11780-
nxtStmtOffs = info.compStmtOffsets[nxtStmtIndex];
11781-
}
11782-
else
11783-
{
11784-
/* No more line# entries */
11773+
nxtStmtOffs = info.compStmtOffsets[nxtStmtIndex];
11774+
}
11775+
else
11776+
{
11777+
/* No more line# entries */
1178511778

11786-
nxtStmtOffs = BAD_IL_OFFSET;
11787-
}
11779+
nxtStmtOffs = BAD_IL_OFFSET;
1178811780
}
1178911781
}
11790-
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::STACK_EMPTY_BOUNDARIES) &&
11791-
(verCurrentState.esStackDepth == 0))
11792-
{
11793-
/* At stack-empty locations, we have already added the tree to
11794-
the stmt list with the last offset. We just need to update
11795-
impCurStmtDI
11796-
*/
11782+
}
11783+
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::STACK_EMPTY_BOUNDARIES) &&
11784+
(verCurrentState.esStackDepth == 0))
11785+
{
11786+
/* At stack-empty locations, we have already added the tree to
11787+
the stmt list with the last offset. We just need to update
11788+
impCurStmtDI
11789+
*/
1179711790

11791+
impCurStmtOffsSet(opcodeOffs);
11792+
}
11793+
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES) &&
11794+
impOpcodeIsCallSiteBoundary(prevOpcode))
11795+
{
11796+
/* Make sure we have a type cached */
11797+
assert(callTyp != TYP_COUNT);
11798+
11799+
if (callTyp == TYP_VOID)
11800+
{
1179811801
impCurStmtOffsSet(opcodeOffs);
1179911802
}
11800-
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES) &&
11801-
impOpcodeIsCallSiteBoundary(prevOpcode))
11803+
else if (opts.compDbgCode)
1180211804
{
11803-
/* Make sure we have a type cached */
11804-
assert(callTyp != TYP_COUNT);
11805-
11806-
if (callTyp == TYP_VOID)
11807-
{
11808-
impCurStmtOffsSet(opcodeOffs);
11809-
}
11810-
else if (opts.compDbgCode)
11811-
{
11812-
impSpillStackEnsure(true);
11813-
impCurStmtOffsSet(opcodeOffs);
11814-
}
11805+
impSpillStackEnsure(true);
11806+
impCurStmtOffsSet(opcodeOffs);
1181511807
}
11816-
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::NOP_BOUNDARIES) && (prevOpcode == CEE_NOP))
11808+
}
11809+
else if ((info.compStmtOffsetsImplicit & ICorDebugInfo::NOP_BOUNDARIES) && (prevOpcode == CEE_NOP))
11810+
{
11811+
if (opts.compDbgCode)
1181711812
{
11818-
if (opts.compDbgCode)
11819-
{
11820-
impSpillStackEnsure(true);
11821-
}
11822-
11823-
impCurStmtOffsSet(opcodeOffs);
11813+
impSpillStackEnsure(true);
1182411814
}
1182511815

11826-
assert(!impCurStmtDI.IsValid() || (nxtStmtOffs == BAD_IL_OFFSET) ||
11827-
(impCurStmtDI.GetLocation().GetOffset() <= nxtStmtOffs));
11816+
impCurStmtOffsSet(opcodeOffs);
1182811817
}
11818+
11819+
assert(!impCurStmtDI.IsValid() || (nxtStmtOffs == BAD_IL_OFFSET) ||
11820+
(impCurStmtDI.GetLocation().GetOffset() <= nxtStmtOffs));
1182911821
}
1183011822

1183111823
CORINFO_CLASS_HANDLE clsHnd = DUMMY_INIT(NULL);

src/coreclr/jit/rationalize.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -958,12 +958,15 @@ PhaseStatus Rationalizer::DoPhase()
958958
BlockRange().InsertAtEnd(LIR::Range(statement->GetTreeList(), statement->GetRootNode()));
959959

960960
// If this statement has correct debug information, change it
961-
// into a debug info node and insert it into the LIR. Currently
962-
// we do not support describing IL offsets in inlinees in the
963-
// emitter, so we normalize all debug info to be in the inline
964-
// root here.
965-
DebugInfo di = statement->GetDebugInfo().GetRoot();
966-
if (di.IsValid())
961+
// into a debug info node and insert it into the LIR. Note that
962+
// we are currently reporting root info only back to the EE, so
963+
// if the leaf debug info is invalid we still attach it.
964+
// Note that we would like to have the invariant di.IsValid()
965+
// => parent.IsValid() but it is currently not the case for
966+
// NEWOBJ IL instructions where the debug info ends up attached
967+
// to the allocation instead of the constructor call.
968+
DebugInfo di = statement->GetDebugInfo();
969+
if (di.IsValid() || di.GetRoot().IsValid())
967970
{
968971
GenTreeILOffset* ilOffset =
969972
new (comp, GT_IL_OFFSET) GenTreeILOffset(di DEBUGARG(statement->GetLastILOffset()));

0 commit comments

Comments
 (0)