[llvm] [DLCov] Origin-Tracking: Add debugify support (PR #143594)
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 3 10:06:41 PDT 2025
https://github.com/SLTozer updated https://github.com/llvm/llvm-project/pull/143594
>From 9ecf81100cc6c9cd41303375eb4800ec78c123fc Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 10 Jun 2025 20:02:36 +0100
Subject: [PATCH 1/7] [DLCov] Origin-Tracking: Add debugify support
---
llvm/include/llvm/Support/Signals.h | 6 +-
llvm/lib/Transforms/Utils/Debugify.cpp | 81 ++++++++++++++++++---
llvm/utils/llvm-original-di-preservation.py | 24 +++---
3 files changed, 88 insertions(+), 23 deletions(-)
diff --git a/llvm/include/llvm/Support/Signals.h b/llvm/include/llvm/Support/Signals.h
index 5969a0a6b230b..21b425fffef53 100644
--- a/llvm/include/llvm/Support/Signals.h
+++ b/llvm/include/llvm/Support/Signals.h
@@ -26,10 +26,8 @@
namespace llvm {
// Typedefs that are convenient but only used by the stack-trace-collection code
// added if DebugLoc origin-tracking is enabled.
-using AddressSet = DenseSet<void *, DenseMapInfo<void *, void>>;
-using SymbolizedAddressMap =
- DenseMap<void *, SmallVector<std::string, 0>, DenseMapInfo<void *, void>,
- detail::DenseMapPair<void *, SmallVector<std::string, 0>>>;
+using AddressSet = DenseSet<void *>;
+using SymbolizedAddressMap = DenseMap<void *, SmallVector<std::string, 0>>;
} // namespace llvm
#endif
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp
index 5f70bc442d2f0..0b57c4a2f9dae 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -16,6 +16,7 @@
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/InstIterator.h"
@@ -28,6 +29,11 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/JSON.h"
#include <optional>
+#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
+// We need the Signals header to operate on stacktraces if we're using DebugLoc
+// origin-tracking.
+#include "llvm/Support/Signals.h"
+#endif
#define DEBUG_TYPE "debugify"
@@ -59,6 +65,52 @@ cl::opt<Level> DebugifyLevel(
raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
+#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
+// These maps refer to addresses in this instance of LLVM, so we can reuse them
+// everywhere - therefore, we store them at file scope.
+static SymbolizedAddressMap SymbolizedAddrs;
+static AddressSet UnsymbolizedAddrs;
+
+std::string symbolizeStackTrace(const Instruction *I) {
+ // We flush the set of unsymbolized addresses at the latest possible moment,
+ // i.e. now.
+ if (!UnsymbolizedAddrs.empty()) {
+ sys::symbolizeAddresses(UnsymbolizedAddrs, SymbolizedAddrs);
+ UnsymbolizedAddrs.clear();
+ }
+ auto OriginStackTraces = I->getDebugLoc().getOriginStackTraces();
+ std::string Result;
+ raw_string_ostream OS(Result);
+ for (size_t TraceIdx = 0; TraceIdx < OriginStackTraces.size(); ++TraceIdx) {
+ if (TraceIdx != 0)
+ OS << "========================================\n";
+ auto &[Depth, StackTrace] = OriginStackTraces[TraceIdx];
+ unsigned VirtualFrameNo = 0;
+ for (int Frame = 0; Frame < Depth; ++Frame) {
+ assert(SymbolizedAddrs.contains(StackTrace[Frame]) &&
+ "Expected each address to have been symbolized.");
+ for (std::string &SymbolizedFrame : SymbolizedAddrs[StackTrace[Frame]]) {
+ OS << right_justify(formatv("#{0}", VirtualFrameNo++).str(), std::log10(Depth) + 2)
+ << ' ' << SymbolizedFrame << '\n';
+ }
+ }
+ }
+ return Result;
+}
+void collectStackAddresses(Instruction &I) {
+ auto &OriginStackTraces = I.getDebugLoc().getOriginStackTraces();
+ for (auto &[Depth, StackTrace] : OriginStackTraces) {
+ for (int Frame = 0; Frame < Depth; ++Frame) {
+ void *Addr = StackTrace[Frame];
+ if (!SymbolizedAddrs.contains(Addr))
+ UnsymbolizedAddrs.insert(Addr);
+ }
+ }
+}
+#else
+void collectStackAddresses(Instruction &I) {}
+#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
+
uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
}
@@ -375,6 +427,8 @@ bool llvm::collectDebugInfoMetadata(Module &M,
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)});
}
}
@@ -450,14 +504,23 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
auto BBName = BB->hasName() ? BB->getName() : "no-name";
auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
+ auto CreateJSONBugEntry = [&](const char *Action) {
+ Bugs.push_back(llvm::json::Object({
+ {"metadata", "DILocation"},
+ {"fn-name", FnName.str()},
+ {"bb-name", BBName.str()},
+ {"instr", InstName},
+ {"action", Action},
+#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
+ {"origin", symbolizeStackTrace(Instr)},
+#endif
+ }));
+ };
+
auto InstrIt = DILocsBefore.find(Instr);
if (InstrIt == DILocsBefore.end()) {
if (ShouldWriteIntoJSON)
- Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
- {"fn-name", FnName.str()},
- {"bb-name", BBName.str()},
- {"instr", InstName},
- {"action", "not-generate"}}));
+ CreateJSONBugEntry("not-generate");
else
dbg() << "WARNING: " << NameOfWrappedPass
<< " did not generate DILocation for " << *Instr
@@ -470,11 +533,7 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
// If the instr had the !dbg attached before the pass, consider it as
// a debug info issue.
if (ShouldWriteIntoJSON)
- Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
- {"fn-name", FnName.str()},
- {"bb-name", BBName.str()},
- {"instr", InstName},
- {"action", "drop"}}));
+ CreateJSONBugEntry("drop");
else
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
@@ -612,6 +671,8 @@ 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)});
}
}
diff --git a/llvm/utils/llvm-original-di-preservation.py b/llvm/utils/llvm-original-di-preservation.py
index dc1fa518ca8e6..7a8752da00667 100755
--- a/llvm/utils/llvm-original-di-preservation.py
+++ b/llvm/utils/llvm-original-di-preservation.py
@@ -13,14 +13,15 @@
class DILocBug:
- def __init__(self, action, bb_name, fn_name, instr):
+ def __init__(self, origin, action, bb_name, fn_name, instr):
+ self.origin = origin
self.action = action
self.bb_name = bb_name
self.fn_name = fn_name
self.instr = instr
def __str__(self):
- return self.action + self.bb_name + self.fn_name + self.instr
+ return self.action + self.bb_name + self.fn_name + self.instr + self.origin
class DISPBug:
@@ -86,6 +87,7 @@ def generate_html_report(
"Function Name",
"Basic Block Name",
"Action",
+ "Origin",
]
for column in header_di_loc:
@@ -112,6 +114,9 @@ def generate_html_report(
row.append(x.fn_name)
row.append(x.bb_name)
row.append(x.action)
+ row.append(
+ f"<details><summary>View Origin StackTrace</summary><pre>{x.origin}</pre></details>"
+ )
row.append(" </tr>\n")
# Dump the bugs info into the table.
for column in row:
@@ -428,9 +433,9 @@ def Main():
sys.exit(1)
# Use the defaultdict in order to make multidim dicts.
- di_location_bugs = defaultdict(lambda: defaultdict(dict))
- di_subprogram_bugs = defaultdict(lambda: defaultdict(dict))
- di_variable_bugs = defaultdict(lambda: defaultdict(dict))
+ di_location_bugs = defaultdict(lambda: defaultdict(list))
+ di_subprogram_bugs = defaultdict(lambda: defaultdict(list))
+ di_variable_bugs = defaultdict(lambda: defaultdict(list))
# Use the ordered dict to make a summary.
di_location_bugs_summary = OrderedDict()
@@ -470,9 +475,9 @@ def Main():
skipped_lines += 1
continue
- di_loc_bugs = []
- di_sp_bugs = []
- di_var_bugs = []
+ di_loc_bugs = di_location_bugs[bugs_file][bugs_pass]
+ di_sp_bugs = di_subprogram_bugs[bugs_file][bugs_pass]
+ di_var_bugs = di_variable_bugs[bugs_file][bugs_pass]
# Omit duplicated bugs.
di_loc_set = set()
@@ -487,6 +492,7 @@ def Main():
if bugs_metadata == "DILocation":
try:
+ origin = bug.get("origin")
action = bug["action"]
bb_name = bug["bb-name"]
fn_name = bug["fn-name"]
@@ -494,7 +500,7 @@ def Main():
except:
skipped_bugs += 1
continue
- di_loc_bug = DILocBug(action, bb_name, fn_name, instr)
+ di_loc_bug = DILocBug(origin, action, bb_name, fn_name, instr)
if not str(di_loc_bug) in di_loc_set:
di_loc_set.add(str(di_loc_bug))
if opts.compress:
>From fa5ad66acaed8a6823e19cfbb6b06678f5235823 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 15:06:32 +0100
Subject: [PATCH 2/7] Update comments, replace auto type, add docs
---
llvm/docs/HowToUpdateDebugInfo.rst | 36 +++++++++++++++++++++++++-
llvm/lib/Transforms/Utils/Debugify.cpp | 8 +++---
2 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/llvm/docs/HowToUpdateDebugInfo.rst b/llvm/docs/HowToUpdateDebugInfo.rst
index a87efe7e6e43f..f2fecbf865892 100644
--- a/llvm/docs/HowToUpdateDebugInfo.rst
+++ b/llvm/docs/HowToUpdateDebugInfo.rst
@@ -420,7 +420,39 @@ tests. Changes to this pass are not allowed to break existing tests.
check lines. In cases where this can't be avoided (say, if a test wouldn't
be precise enough), moving the test to its own file is preferred.
-.. _MIRDebugify:
+Using Coverage Tracking to remove false positives
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As described :ref:`above<WhenToDropLocation>`, there are valid reasons for
+instructions to have missing source locations. Therefore, when detecting dropped
+or not-generated source locations, it may be preferred 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 explicit reason given for not having a source
+location.
+
+For triaging source location bugs detected with ``debugify``, you may find it
+helpful to instead set the CMake flag
+``-DLLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING=COVERAGE_AND_ORIGIN``. This flag adds
+more detail to ``debugify``'s output, by including one or more stacktraces with
+every missing source location, capturing the point at which the empty source
+location was created, and every point at which it was copied to an instruction,
+making it trivial in most cases to find the origin of the underlying bug.
+
+.. note::
+
+ The coverage tracking feature has been designed primarily for use with the
+ :ref:`original debug info preservation` mode of ``debugify``, and so may not
+ be reliable in other settings. When using this mode, the stacktraces produced
+ by the ``COVERAGE_AND_ORIGIN`` setting will be printed in an easy-to-read
+ format as part of the reports generated by the
+ ``llvm-original-di-preservation.py`` script.
+
+.. _OriginalDI:
Test original debug info preservation in optimizations
------------------------------------------------------
@@ -478,6 +510,8 @@ as follows:
Please do note that there are some known false positives, for source locations
and debug record checking, so that will be addressed as a future work.
+.. _MIRDebugify:
+
Mutation testing for MIR-level transformations
----------------------------------------------
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp
index 0b57c4a2f9dae..875c9d8e6b0fa 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -19,6 +19,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -66,8 +67,8 @@ cl::opt<Level> DebugifyLevel(
raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
-// These maps refer to addresses in this instance of LLVM, so we can reuse them
-// everywhere - therefore, we store them at file scope.
+// These maps refer to addresses in the current LLVM process, so we can reuse
+// them everywhere - therefore, we store them at file scope.
static SymbolizedAddressMap SymbolizedAddrs;
static AddressSet UnsymbolizedAddrs;
@@ -78,7 +79,8 @@ std::string symbolizeStackTrace(const Instruction *I) {
sys::symbolizeAddresses(UnsymbolizedAddrs, SymbolizedAddrs);
UnsymbolizedAddrs.clear();
}
- auto OriginStackTraces = I->getDebugLoc().getOriginStackTraces();
+ const DbgLocOrigin::StackTracesTy &OriginStackTraces =
+ I->getDebugLoc().getOriginStackTraces();
std::string Result;
raw_string_ostream OS(Result);
for (size_t TraceIdx = 0; TraceIdx < OriginStackTraces.size(); ++TraceIdx) {
>From 3a91e60870533250a4a7cbaa5c2d67d1442ecf5d Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 15:07:15 +0100
Subject: [PATCH 3/7] clang-format
---
llvm/lib/Transforms/Utils/Debugify.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp
index 875c9d8e6b0fa..0e48a3200a5ad 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -92,8 +92,9 @@ std::string symbolizeStackTrace(const Instruction *I) {
assert(SymbolizedAddrs.contains(StackTrace[Frame]) &&
"Expected each address to have been symbolized.");
for (std::string &SymbolizedFrame : SymbolizedAddrs[StackTrace[Frame]]) {
- OS << right_justify(formatv("#{0}", VirtualFrameNo++).str(), std::log10(Depth) + 2)
- << ' ' << SymbolizedFrame << '\n';
+ OS << right_justify(formatv("#{0}", VirtualFrameNo++).str(),
+ std::log10(Depth) + 2)
+ << ' ' << SymbolizedFrame << '\n';
}
}
}
@@ -508,13 +509,10 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
auto CreateJSONBugEntry = [&](const char *Action) {
Bugs.push_back(llvm::json::Object({
- {"metadata", "DILocation"},
- {"fn-name", FnName.str()},
- {"bb-name", BBName.str()},
- {"instr", InstName},
- {"action", Action},
+ {"metadata", "DILocation"}, {"fn-name", FnName.str()},
+ {"bb-name", BBName.str()}, {"instr", InstName}, {"action", Action},
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
- {"origin", symbolizeStackTrace(Instr)},
+ {"origin", symbolizeStackTrace(Instr)},
#endif
}));
};
>From 07bc7ebac8684a1d7df5deda9c4096f148faadac Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 15:09:37 +0100
Subject: [PATCH 4/7] Update doc wording slightly
---
llvm/docs/HowToUpdateDebugInfo.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/docs/HowToUpdateDebugInfo.rst b/llvm/docs/HowToUpdateDebugInfo.rst
index f2fecbf865892..44ff73a0c0d86 100644
--- a/llvm/docs/HowToUpdateDebugInfo.rst
+++ b/llvm/docs/HowToUpdateDebugInfo.rst
@@ -424,16 +424,16 @@ Using Coverage Tracking to remove false positives
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As described :ref:`above<WhenToDropLocation>`, there are valid reasons for
-instructions to have missing source locations. Therefore, when detecting dropped
-or not-generated source locations, it may be preferred to avoid detecting cases
+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
:ref:`DebugLoc annotations<_NewInstLocations>`, allowing ``debugify`` to ignore
-instructions that have an explicit reason given for not having a source
-location.
+instructions that have an explicitly recorded reason given for not having a
+source location.
For triaging source location bugs detected with ``debugify``, you may find it
helpful to instead set the CMake flag
>From 5b1762e2ccc461e496be881bece17b010fcd927c Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 15:50:13 +0100
Subject: [PATCH 5/7] Fix reference links, adjust wording slightly
---
llvm/docs/HowToUpdateDebugInfo.rst | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/llvm/docs/HowToUpdateDebugInfo.rst b/llvm/docs/HowToUpdateDebugInfo.rst
index 44ff73a0c0d86..c3262a96b62e4 100644
--- a/llvm/docs/HowToUpdateDebugInfo.rst
+++ b/llvm/docs/HowToUpdateDebugInfo.rst
@@ -431,25 +431,27 @@ where the missing source location is intentional. For this, you can use 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
+:ref:`DebugLoc annotations<NewInstLocations>`, allowing ``debugify`` to ignore
instructions that have an explicitly recorded reason given for not having a
source location.
For triaging source location bugs detected with ``debugify``, you may find it
-helpful to instead set the CMake flag
+helpful to instead set the CMake flag to enable "origin tracking",
``-DLLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING=COVERAGE_AND_ORIGIN``. This flag adds
more detail to ``debugify``'s output, by including one or more stacktraces with
every missing source location, capturing the point at which the empty source
location was created, and every point at which it was copied to an instruction,
-making it trivial in most cases to find the origin of the underlying bug.
+making it trivial in most cases to find the origin of the underlying bug. If
+using origin tracking, it is recommended to also build LLVM with debug info
+enabled, so that the stacktrace can be accurately symbolized.
.. note::
The coverage tracking feature has been designed primarily for use with the
- :ref:`original debug info preservation` mode of ``debugify``, and so may not
- be reliable in other settings. When using this mode, the stacktraces produced
- by the ``COVERAGE_AND_ORIGIN`` setting will be printed in an easy-to-read
- format as part of the reports generated by the
+ :ref:`original debug info preservation<OriginalDI>` mode of ``debugify``, and
+ so may not be reliable in other settings. When using this mode, the
+ stacktraces produced by the ``COVERAGE_AND_ORIGIN`` setting will be printed
+ in an easy-to-read format as part of the reports generated by the
``llvm-original-di-preservation.py`` script.
.. _OriginalDI:
>From 5dcfe7498dce415fbeb49433fbd2387ac0241907 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 17:58:08 +0100
Subject: [PATCH 6/7] Fix original-di script, add tests
---
.../Inputs/expected-origin.html | 124 ++++++++++++++++++
.../Inputs/expected-skipped.html | 9 ++
.../Inputs/origin.json | 1 +
.../llvm-original-di-preservation/basic.test | 4 +
llvm/utils/llvm-original-di-preservation.py | 24 +++-
5 files changed, 157 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/tools/llvm-original-di-preservation/Inputs/expected-origin.html
create mode 100644 llvm/test/tools/llvm-original-di-preservation/Inputs/origin.json
diff --git a/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-origin.html b/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-origin.html
new file mode 100644
index 0000000000000..ed08c850cb4ad
--- /dev/null
+++ b/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-origin.html
@@ -0,0 +1,124 @@
+ <html>
+ <head>
+ <style>
+ table, th, td {
+ border: 1px solid black;
+ }
+ table.center {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <caption><b>Location Bugs found by the Debugify</b></caption>
+ <tr>
+ <th>File</th>
+ <th>LLVM Pass Name</th>
+ <th>LLVM IR Instruction</th>
+ <th>Function Name</th>
+ <th>Basic Block Name</th>
+ <th>Action</th>
+ <th>Origin</th>
+ </tr>
+ </tr>
+ <tr>
+ <td>test.ll</td>
+ <td>LoopVectorizePass</td>
+ <td>add</td>
+ <td>fn</td>
+ <td>no-name</td>
+ <td>not-generate</td>
+ <td><details><summary>View Origin StackTrace</summary><pre>Stack Trace 0:
+ #0 0x00005895d035c935 llvm::DbgLocOrigin::DbgLocOrigin(bool) /tmp/llvm-project/llvm/lib/IR/DebugLoc.cpp:22:9
+ #1 0x00005895d03af013 llvm::DILocAndCoverageTracking::DILocAndCoverageTracking() /tmp/llvm-project/llvm/include/llvm/IR/DebugLoc.h:90:11
+ #2 0x00005895d03af013 llvm::DebugLoc::DebugLoc() /tmp/llvm-project/llvm/include/llvm/IR/DebugLoc.h:133:5
+ #3 0x00005895d03af013 llvm::Instruction::Instruction(llvm::Type*, unsigned int, llvm::User::AllocInfo, llvm::InsertPosition) /tmp/llvm-project/llvm/lib/IR/Instruction.cpp:37:14
+ #4 0x00005895d06862b5 llvm::PHINode::PHINode(llvm::Type*, unsigned int, llvm::Twine const&, llvm::InsertPosition) /tmp/llvm-project/llvm/include/llvm/IR/Instructions.h:0:9
+ #5 0x00005895d06862b5 llvm::PHINode::Create(llvm::Type*, unsigned int, llvm::Twine const&, llvm::InsertPosition) /tmp/llvm-project/llvm/include/llvm/IR/Instructions.h:2651:9
+ #6 0x00005895d06862b5 llvm::InstCombinerImpl::foldPHIArgGEPIntoPHI(llvm::PHINode&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp:617:9
+ #7 0x00005895d0688fe0 llvm::InstCombinerImpl::visitPHINode(llvm::PHINode&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp:1456:22
+ #8 0x00005895d05cd21f llvm::InstCombinerImpl::run() /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5327:22
+ #9 0x00005895d05d067e combineInstructionsOverFunction(llvm::Function&, llvm::InstructionWorklist&, llvm::AAResults*, llvm::AssumptionCache&, llvm::TargetLibraryInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::OptimizationRemarkEmitter&, llvm::BlockFrequencyInfo*, llvm::BranchProbabilityInfo*, llvm::ProfileSummaryInfo*, llvm::InstCombineOptions const&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5643:31
+#10 0x00005895d05cf9a9 llvm::InstCombinePass::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5706:8
+#11 0x00005895d107d07d llvm::detail::PassModel>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5
+#12 0x00005895d04204a7 llvm::PassManager>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:8
+#13 0x00005895ce4cb09d llvm::detail::PassModel>, llvm::AnalysisManager>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5
+#14 0x00005895cfae2865 llvm::CGSCCToFunctionPassAdaptor::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:0:38
+#15 0x00005895ce4cad5d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5
+#16 0x00005895cfade813 llvm::PassManager, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:93:12
+#17 0x00005895d1e3968d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::AnalysisManager, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5
+#18 0x00005895cfae1224 llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:0:38
+#19 0x00005895d1e5067d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5</pre></details></td>
+ </tr>
+ <tr>
+</table>
+<br>
+<table>
+ <caption><b>Summary of Location Bugs</b></caption>
+ <tr>
+ <th>LLVM Pass Name</th>
+ <th>Number of bugs</th>
+ </tr>
+ <tr>
+ <td>LoopVectorizePass</td>
+ <td>1</td>
+ </tr>
+ <tr>
+</table>
+<br>
+<br>
+<table>
+ <caption><b>SP Bugs found by the Debugify</b></caption>
+ <tr>
+ <th>File</th>
+ <th>LLVM Pass Name</th>
+ <th>Function Name</th>
+ <th>Action</th>
+ </tr>
+<tr>
+ <td colspan='4'> No bugs found </td>
+ </tr>
+ </table>
+<br>
+<table>
+ <caption><b>Summary of SP Bugs</b></caption>
+ <tr>
+ <th>LLVM Pass Name</th>
+ <th>Number of bugs</th>
+ </tr>
+ <tr>
+<tr>
+ <td colspan='2'> No bugs found </td>
+ </tr>
+ </table>
+<br>
+<br>
+<table>
+ <caption><b>Variable Location Bugs found by the Debugify</b></caption>
+ <tr>
+ <th>File</th>
+ <th>LLVM Pass Name</th>
+ <th>Variable</th>
+ <th>Function</th>
+ <th>Action</th>
+ </tr>
+<tr>
+ <td colspan='4'> No bugs found </td>
+ </tr>
+ </table>
+<br>
+<table>
+ <caption><b>Summary of Variable Location Bugs</b></caption>
+ <tr>
+ <th>LLVM Pass Name</th>
+ <th>Number of bugs</th>
+ </tr>
+ <tr>
+<tr>
+ <td colspan='2'> No bugs found </td>
+ </tr>
+ </table>
+</body>
+ </html>
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-skipped.html b/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-skipped.html
index f70ebbf86b0a2..d8941cbdedbef 100644
--- a/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-skipped.html
+++ b/llvm/test/tools/llvm-original-di-preservation/Inputs/expected-skipped.html
@@ -128,6 +128,15 @@
<td>drop</td>
</tr>
<tr>
+ </tr>
+ <tr>
+ <td>wrstabs.c</td>
+ <td>Simplify the CFG</td>
+ <td>tindex</td>
+ <td>stab_bool_type</td>
+ <td>drop</td>
+ </tr>
+ <tr>
</tr>
<tr>
<td>prdbg.c</td>
diff --git a/llvm/test/tools/llvm-original-di-preservation/Inputs/origin.json b/llvm/test/tools/llvm-original-di-preservation/Inputs/origin.json
new file mode 100644
index 0000000000000..ab59bc295add1
--- /dev/null
+++ b/llvm/test/tools/llvm-original-di-preservation/Inputs/origin.json
@@ -0,0 +1 @@
+{"file":"test.ll", "pass":"LoopVectorizePass", "bugs": [[{"action":"not-generate","bb-name":"no-name","fn-name":"fn","instr":"add","metadata":"DILocation", "origin": "Stack Trace 0:\n #0 0x00005895d035c935 llvm::DbgLocOrigin::DbgLocOrigin(bool) /tmp/llvm-project/llvm/lib/IR/DebugLoc.cpp:22:9\n #1 0x00005895d03af013 llvm::DILocAndCoverageTracking::DILocAndCoverageTracking() /tmp/llvm-project/llvm/include/llvm/IR/DebugLoc.h:90:11\n #2 0x00005895d03af013 llvm::DebugLoc::DebugLoc() /tmp/llvm-project/llvm/include/llvm/IR/DebugLoc.h:133:5\n #3 0x00005895d03af013 llvm::Instruction::Instruction(llvm::Type*, unsigned int, llvm::User::AllocInfo, llvm::InsertPosition) /tmp/llvm-project/llvm/lib/IR/Instruction.cpp:37:14\n #4 0x00005895d06862b5 llvm::PHINode::PHINode(llvm::Type*, unsigned int, llvm::Twine const&, llvm::InsertPosition) /tmp/llvm-project/llvm/include/llvm/IR/Instructions.h:0:9\n #5 0x00005895d06862b5 llvm::PHINode::Create(llvm::Type*, unsigned int, llvm::Twine const&, llvm::InsertPosition) /tmp/llvm-project/llvm/include/llvm/IR/Instructions.h:2651:9\n #6 0x00005895d06862b5 llvm::InstCombinerImpl::foldPHIArgGEPIntoPHI(llvm::PHINode&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp:617:9\n #7 0x00005895d0688fe0 llvm::InstCombinerImpl::visitPHINode(llvm::PHINode&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp:1456:22\n #8 0x00005895d05cd21f llvm::InstCombinerImpl::run() /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5327:22\n #9 0x00005895d05d067e combineInstructionsOverFunction(llvm::Function&, llvm::InstructionWorklist&, llvm::AAResults*, llvm::AssumptionCache&, llvm::TargetLibraryInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::OptimizationRemarkEmitter&, llvm::BlockFrequencyInfo*, llvm::BranchProbabilityInfo*, llvm::ProfileSummaryInfo*, llvm::InstCombineOptions const&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5643:31\n#10 0x00005895d05cf9a9 llvm::InstCombinePass::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp:5706:8\n#11 0x00005895d107d07d llvm::detail::PassModel>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5\n#12 0x00005895d04204a7 llvm::PassManager>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:8\n#13 0x00005895ce4cb09d llvm::detail::PassModel>, llvm::AnalysisManager>::run(llvm::Function&, llvm::AnalysisManager&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5\n#14 0x00005895cfae2865 llvm::CGSCCToFunctionPassAdaptor::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:0:38\n#15 0x00005895ce4cad5d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5\n#16 0x00005895cfade813 llvm::PassManager, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:93:12\n#17 0x00005895d1e3968d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::AnalysisManager, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5\n#18 0x00005895cfae1224 llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/lib/Analysis/CGSCCPassManager.cpp:0:38\n#19 0x00005895d1e5067d llvm::detail::PassModel, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) /tmp/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:91:5"}]]}
diff --git a/llvm/test/tools/llvm-original-di-preservation/basic.test b/llvm/test/tools/llvm-original-di-preservation/basic.test
index 81f987aa221bb..5ef670b42c667 100644
--- a/llvm/test/tools/llvm-original-di-preservation/basic.test
+++ b/llvm/test/tools/llvm-original-di-preservation/basic.test
@@ -1,5 +1,6 @@
RUN: %llvm-original-di-preservation %p/Inputs/sample.json %t.html | FileCheck %s
RUN: diff -w %p/Inputs/expected-sample.html %t.html
+CHECK: The {{.+}}.html generated.
CHECK-NOT: Skipped lines:
RUN: %llvm-original-di-preservation %p/Inputs/corrupted.json %t2.html | FileCheck %s -check-prefix=CORRUPTED
@@ -9,5 +10,8 @@ CORRUPTED: Skipped bugs: 1
RUN: %llvm-original-di-preservation -compress %p/Inputs/sample.json %t3.html | FileCheck %s -check-prefix=COMPRESSED
RUN: diff -w %p/Inputs/expected-compressed.html %t3.html
+COMPRESSED: The {{.+}}.html generated.
COMPRESSED-NOT: Skipped lines:
+RUN: %llvm-original-di-preservation %p/Inputs/origin.json %t4.html | FileCheck %s
+RUN: diff -w %p/Inputs/expected-origin.html %t4.html
diff --git a/llvm/utils/llvm-original-di-preservation.py b/llvm/utils/llvm-original-di-preservation.py
index 7a8752da00667..03793b1136f8d 100755
--- a/llvm/utils/llvm-original-di-preservation.py
+++ b/llvm/utils/llvm-original-di-preservation.py
@@ -21,7 +21,7 @@ def __init__(self, origin, action, bb_name, fn_name, instr):
self.instr = instr
def __str__(self):
- return self.action + self.bb_name + self.fn_name + self.instr + self.origin
+ return self.action + self.bb_name + self.fn_name + self.instr
class DISPBug:
@@ -80,6 +80,15 @@ def generate_html_report(
table_title_di_loc
)
+ # If any DILocation bug has an origin stack trace, we emit an extra column in the table, which we must therefore
+ # determine up-front.
+ has_origin_col = any(
+ x.origin is not None
+ for per_file_bugs in di_location_bugs.values()
+ for per_pass_bugs in per_file_bugs.values()
+ for x in per_pass_bugs
+ )
+
header_di_loc = [
"File",
"LLVM Pass Name",
@@ -87,8 +96,9 @@ def generate_html_report(
"Function Name",
"Basic Block Name",
"Action",
- "Origin",
]
+ if has_origin_col:
+ header_di_loc.append("Origin")
for column in header_di_loc:
table_di_loc += " <th>{0}</th>\n".format(column.strip())
@@ -114,9 +124,13 @@ def generate_html_report(
row.append(x.fn_name)
row.append(x.bb_name)
row.append(x.action)
- row.append(
- f"<details><summary>View Origin StackTrace</summary><pre>{x.origin}</pre></details>"
- )
+ if has_origin_col:
+ if x.origin is not None:
+ row.append(
+ f"<details><summary>View Origin StackTrace</summary><pre>{x.origin}</pre></details>"
+ )
+ else:
+ row.append("")
row.append(" </tr>\n")
# Dump the bugs info into the table.
for column in row:
>From 8d2d9ad77541b650a64a0e7ce0ec906e60dd6aa1 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 3 Jul 2025 18:06:15 +0100
Subject: [PATCH 7/7] clang-format
---
llvm/lib/Transforms/Utils/Debugify.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp
index 0e48a3200a5ad..a1f030a336c15 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -509,10 +509,13 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
auto CreateJSONBugEntry = [&](const char *Action) {
Bugs.push_back(llvm::json::Object({
- {"metadata", "DILocation"}, {"fn-name", FnName.str()},
- {"bb-name", BBName.str()}, {"instr", InstName}, {"action", Action},
+ {"metadata", "DILocation"},
+ {"fn-name", FnName.str()},
+ {"bb-name", BBName.str()},
+ {"instr", InstName},
+ {"action", Action},
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
- {"origin", symbolizeStackTrace(Instr)},
+ {"origin", symbolizeStackTrace(Instr)},
#endif
}));
};
More information about the llvm-commits
mailing list