[llvm] 2d829f6 - [Debugify] Simplify debugify for locations (#207374)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 8 04:01:22 PDT 2026
Author: Stephen Tozer
Date: 2026-07-08T12:01:15+01:00
New Revision: 2d829f66147850c1fa9cd49c207b40c69aff5f17
URL: https://github.com/llvm/llvm-project/commit/2d829f66147850c1fa9cd49c207b40c69aff5f17
DIFF: https://github.com/llvm/llvm-project/commit/2d829f66147850c1fa9cd49c207b40c69aff5f17.diff
LOG: [Debugify] Simplify debugify for locations (#207374)
This patch attempts to improve the performance of debugify for
locations, by relying on coverage tracking to replace most of the
functionality provided via the DILocations map, in exchange for losing
the ability to distinguish between "dropped" and "not-generated" bugs,
and requiring coverage tracking to determine when new bugs appear in a
pass instead of reporting the same bug repeatedly across passes.
This patch is not without cost; the justifications for using it are
that:
- Debugify locations is incredibly expensive; on a local build, without
using any coverage-tracking, this patch takes the build time for sqlite3
down from ~15 minutes to ~10 seconds.
- The difference between "dropped" and "not-generated" is a minor detail
of a bug - besides helping to determine the cause of the bug, which
origin-tracking can do with more accuracy, there's no fundamental
difference in the correctness of either. Furthermore, almost no
"dropped" bugs appear in the compiler anymore (since the debug location
coverage tracker bot has been online).
- Requiring coverage tracking to prevent repeated bugs is a loss, but
coverage tracking is not a very expensive feature to enable compared to
using debugify itself, and the only public automated tests that use
debugify already enable coverage tracking.
Added:
Modified:
llvm/docs/HowToUpdateDebugInfo.rst
llvm/include/llvm/Transforms/Utils/Debugify.h
llvm/lib/Transforms/Utils/Debugify.cpp
llvm/unittests/Transforms/Utils/DebugifyTest.cpp
Removed:
################################################################################
diff --git a/llvm/docs/HowToUpdateDebugInfo.rst b/llvm/docs/HowToUpdateDebugInfo.rst
index d062010ecdb36..428e3c1407a26 100644
--- a/llvm/docs/HowToUpdateDebugInfo.rst
+++ b/llvm/docs/HowToUpdateDebugInfo.rst
@@ -432,13 +432,13 @@ Using Coverage Tracking to remove false positives
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As described :ref:`above<WhenToDropLocation>`, there are valid reasons for
-instructions to not have source locations. Therefore, when detecting dropped or
-not-generated source locations, it may be preferable to avoid detecting cases
-where the missing source location is intentional. For this, you can use the
-"coverage tracking" feature in LLVM to prevent these from appearing in the
-``debugify`` output. This is enabled in a build of LLVM by setting the CMake
-flag ``-DLLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING=COVERAGE``. When this has been
-set, LLVM will enable runtime tracking of
+instructions to not have source locations. Therefore, when detecting missing
+source locations, it may be preferable to avoid detecting cases where the
+missing source location is intentional. For this, you can use the "coverage
+tracking" feature in LLVM to prevent these from appearing in the ``debugify``
+output. This is enabled in a build of LLVM by setting the CMake flag
+``-DLLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING=COVERAGE``. When this has been set,
+LLVM will enable runtime tracking of
:ref:`DebugLoc annotations<NewInstLocations>`, allowing ``debugify`` to ignore
instructions that have an explicitly recorded reason given for not having a
source location.
diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h
index 4e9c91e9844ba..c6b9c0c2352b7 100644
--- a/llvm/include/llvm/Transforms/Utils/Debugify.h
+++ b/llvm/include/llvm/Transforms/Utils/Debugify.h
@@ -37,8 +37,6 @@ using WeakInstValueMap =
struct DebugInfoPerPass {
// This maps a function name to its associated DISubprogram.
DebugFnMap DIFunctions;
- // This maps an instruction and the info about whether it has !dbg attached.
- DebugInstMap DILocations;
// This tracks value (instruction) deletion. If an instruction gets deleted,
// WeakVH nulls itself.
WeakInstValueMap InstToDelete;
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp
index e501b6f2a4e34..8656a7c973451 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -446,16 +446,13 @@ bool llvm::collectDebugInfoMetadata(Module &M,
}
}
}
-
- for (BasicBlock &BB : F) {
- // Collect debug locations (!dbg) and debug variable intrinsics.
- for (Instruction &I : BB) {
- // Skip PHIs.
- if (isa<PHINode>(I))
- continue;
-
- // Cllect dbg.values and dbg.declare.
- if (DebugifyLevel > Level::Locations) {
+ if (DebugifyLevel > Level::Locations) {
+ for (BasicBlock &BB : F) {
+ // Collect debug variable records.
+ for (Instruction &I : BB) {
+ // PHIs have no variable records.
+ if (isa<PHINode>(I))
+ continue;
auto HandleDbgVariable = [&](DbgVariableRecord *DbgVar) {
if (!SP)
return;
@@ -472,13 +469,6 @@ bool llvm::collectDebugInfoMetadata(Module &M,
for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
HandleDbgVariable(&DVR);
}
-
- LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
- DebugInfoBeforePass.InstToDelete.insert({&I, &I});
-
- // Track the addresses to symbolize, if the feature is enabled.
- collectStackAddresses(I);
- DebugInfoBeforePass.DILocations.insert({&I, hasLoc(I)});
}
}
}
@@ -527,73 +517,43 @@ static bool checkFunctions(const DebugFnMap &DIFunctionsBefore,
return Preserved;
}
-// This checks the preservation of the original debug info attached to
-// instructions.
-static bool checkInstructions(const DebugInstMap &DILocsBefore,
- const DebugInstMap &DILocsAfter,
- const WeakInstValueMap &InstToDelete,
- StringRef NameOfWrappedPass,
- StringRef FileNameFromCU,
- bool ShouldWriteIntoJSON,
- llvm::json::Array &Bugs) {
- bool Preserved = true;
- for (const auto &L : DILocsAfter) {
- if (L.second)
- continue;
- auto Instr = L.first;
-
- // In order to avoid pointer reuse/recycling, skip the values that might
- // have been deleted during a pass.
- auto WeakInstrPtr = InstToDelete.find(Instr);
- if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second)
- continue;
-
- auto FnName = Instr->getFunction()->getName();
- auto BB = Instr->getParent();
- auto BBName = BB->hasName() ? BB->getName() : "no-name";
- auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
-
- auto CreateJSONBugEntry = [&](const char *Action) {
- auto BugEntry = llvm::json::Object({
- {"metadata", "DILocation"},
- {"fn-name", FnName.str()},
- {"bb-name", BBName.str()},
- {"instr", InstName},
- {"action", Action},
- });
+static bool checkInstructionCoverage(Instruction &I,
+ StringRef NameOfWrappedPass,
+ StringRef FileNameFromCU,
+ bool ShouldWriteIntoJSON,
+ llvm::json::Array &Bugs) {
+ if (hasLoc(I))
+ return true;
+
+ Instruction *Instr = &I;
+ collectStackAddresses(I);
+ auto FnName = Instr->getFunction()->getName();
+ auto BB = Instr->getParent();
+ auto BBName = BB->hasName() ? BB->getName() : "no-name";
+ auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
+
+ auto CreateJSONBugEntry = [&](const char *Action) {
+ auto BugEntry = llvm::json::Object({
+ {"metadata", "DILocation"},
+ {"fn-name", FnName.str()},
+ {"bb-name", BBName.str()},
+ {"instr", InstName},
+ {"action", Action},
+ });
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
- if (!Instr->getDebugLoc().getOriginStackTraces().empty())
- BugEntry.insert({"origin", symbolizeStackTrace(Instr)});
+ if (!Instr->getDebugLoc().getOriginStackTraces().empty())
+ BugEntry.insert({"origin", symbolizeStackTrace(Instr)});
#endif
- Bugs.push_back(std::move(BugEntry));
- };
-
- auto InstrIt = DILocsBefore.find(Instr);
- if (InstrIt == DILocsBefore.end()) {
- if (ShouldWriteIntoJSON)
- CreateJSONBugEntry("not-generate");
- else
- dbg() << "WARNING: " << NameOfWrappedPass
- << " did not generate DILocation for " << *Instr
- << " (BB: " << BBName << ", Fn: " << FnName
- << ", File: " << FileNameFromCU << ")\n";
- Preserved = false;
- } else {
- if (!InstrIt->second)
- continue;
- // If the instr had the !dbg attached before the pass, consider it as
- // a debug info issue.
- if (ShouldWriteIntoJSON)
- CreateJSONBugEntry("drop");
- else
- dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
- << *Instr << " (BB: " << BBName << ", Fn: " << FnName
- << ", File: " << FileNameFromCU << ")\n";
- Preserved = false;
- }
- }
+ Bugs.push_back(std::move(BugEntry));
+ };
- return Preserved;
+ if (ShouldWriteIntoJSON)
+ CreateJSONBugEntry("not-generate");
+ else
+ dbg() << "WARNING: " << NameOfWrappedPass
+ << " did not generate DILocation for " << *Instr << " (BB: " << BBName
+ << ", Fn: " << FnName << ", File: " << FileNameFromCU << ")\n";
+ return false;
}
// This checks the preservation of original debug variable intrinsics.
@@ -673,6 +633,16 @@ bool llvm::checkDebugInfoMetadata(Module &M,
// Map the debug info holding DIs after a pass.
DebugInfoPerPass DebugInfoAfterPass;
+ bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
+
+ // TODO: The name of the module could be read better?
+ StringRef FileNameFromCU =
+ (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
+ ->getFilename();
+ llvm::json::Array Bugs;
+
+ bool ResultForInsts = true;
+
// Visit each instruction.
for (Function &F : Functions) {
if (isFunctionSkipped(F))
@@ -724,46 +694,26 @@ bool llvm::checkDebugInfoMetadata(Module &M,
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
// Track the addresses to symbolize, if the feature is enabled.
- collectStackAddresses(I);
- DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
+ bool InstResult = checkInstructionCoverage(
+ I, NameOfWrappedPass, FileNameFromCU, ShouldWriteIntoJSON, Bugs);
+ if (!InstResult)
+ I.setDebugLoc(DebugLoc::getUnknown());
+ ResultForInsts &= InstResult;
}
}
}
- // TODO: The name of the module could be read better?
- StringRef FileNameFromCU =
- (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0)))
- ->getFilename();
-
auto DIFunctionsBefore = DebugInfoBeforePass.DIFunctions;
auto DIFunctionsAfter = DebugInfoAfterPass.DIFunctions;
- auto DILocsBefore = DebugInfoBeforePass.DILocations;
- auto DILocsAfter = DebugInfoAfterPass.DILocations;
-
auto InstToDelete = DebugInfoBeforePass.InstToDelete;
auto DIVarsBefore = DebugInfoBeforePass.DIVariables;
auto DIVarsAfter = DebugInfoAfterPass.DIVariables;
- bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty();
- llvm::json::Array Bugs;
-
bool ResultForFunc =
checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass,
FileNameFromCU, ShouldWriteIntoJSON, Bugs);
- bool ResultForInsts = checkInstructions(
- DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass,
- FileNameFromCU, ShouldWriteIntoJSON, Bugs);
-
-#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
- // If we are tracking DebugLoc coverage, replace each empty DebugLoc with an
- // annotated location now so that it does not show up in future passes even if
- // it is propagated to other instructions.
- for (auto &L : DILocsAfter)
- if (!L.second)
- const_cast<Instruction *>(L.first)->setDebugLoc(DebugLoc::getUnknown());
-#endif
bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass,
FileNameFromCU, ShouldWriteIntoJSON, Bugs);
diff --git a/llvm/unittests/Transforms/Utils/DebugifyTest.cpp b/llvm/unittests/Transforms/Utils/DebugifyTest.cpp
index 1daf381ee2862..9cd3fe86be058 100644
--- a/llvm/unittests/Transforms/Utils/DebugifyTest.cpp
+++ b/llvm/unittests/Transforms/Utils/DebugifyTest.cpp
@@ -132,7 +132,7 @@ TEST(DebugInfoDrop, DropOriginalDebugInfo) {
std::string StdOut = testing::internal::GetCapturedStderr();
std::string ErrorForSP = "ERROR: dropped DISubprogram of";
- std::string WarningForLoc = "WARNING: dropped DILocation of";
+ std::string WarningForLoc = "WARNING: did not generate DILocation for";
std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos);
More information about the llvm-commits
mailing list