Skip to content

[DLCov] Origin-Tracking: Collect stack traces in DebugLoc #146678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions llvm/include/llvm/IR/DebugLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ namespace llvm {
class Function;

#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
struct DbgLocOrigin {
static constexpr unsigned long MaxDepth = 16;
using StackTracesTy =
SmallVector<std::pair<int, std::array<void *, MaxDepth>>, 0>;
StackTracesTy StackTraces;
DbgLocOrigin(bool ShouldCollectTrace);
void addTrace();
const StackTracesTy &getOriginStackTraces() const { return StackTraces; };
};
#else
struct DbgLocOrigin {
DbgLocOrigin(bool) {}
};
#endif
// Used to represent different "kinds" of DebugLoc, expressing that the
// instruction it is part of is either normal and should contain a valid
// DILocation, or otherwise describing the reason why the instruction does
Expand Down Expand Up @@ -55,22 +70,29 @@ namespace llvm {
Temporary
};

// Extends TrackingMDNodeRef to also store a DebugLocKind, allowing Debugify
// to ignore intentionally-empty DebugLocs.
class DILocAndCoverageTracking : public TrackingMDNodeRef {
// Extends TrackingMDNodeRef to also store a DebugLocKind and Origin,
// allowing Debugify to ignore intentionally-empty DebugLocs and display the
// code responsible for generating unintentionally-empty DebugLocs.
// Currently we only need to track the Origin of this DILoc when using a
// DebugLoc that is not annotated (i.e. has DebugLocKind::Normal) and has a
// null DILocation, so only collect the origin stacktrace in those cases.
class DILocAndCoverageTracking : public TrackingMDNodeRef,
public DbgLocOrigin {
public:
DebugLocKind Kind;
// Default constructor for empty DebugLocs.
DILocAndCoverageTracking()
: TrackingMDNodeRef(nullptr), Kind(DebugLocKind::Normal) {}
// Valid or nullptr MDNode*, normal DebugLocKind.
: TrackingMDNodeRef(nullptr), DbgLocOrigin(true),
Kind(DebugLocKind::Normal) {}
// Valid or nullptr MDNode*, no annotative DebugLocKind.
DILocAndCoverageTracking(const MDNode *Loc)
: TrackingMDNodeRef(const_cast<MDNode *>(Loc)),
: TrackingMDNodeRef(const_cast<MDNode *>(Loc)), DbgLocOrigin(!Loc),
Kind(DebugLocKind::Normal) {}
LLVM_ABI DILocAndCoverageTracking(const DILocation *Loc);
// Explicit DebugLocKind, which always means a nullptr MDNode*.
DILocAndCoverageTracking(DebugLocKind Kind)
: TrackingMDNodeRef(nullptr), Kind(Kind) {}
: TrackingMDNodeRef(nullptr),
DbgLocOrigin(Kind == DebugLocKind::Normal), Kind(Kind) {}
};
template <> struct simplify_type<DILocAndCoverageTracking> {
using SimpleType = MDNode *;
Expand Down Expand Up @@ -187,6 +209,19 @@ namespace llvm {
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
}

#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
const DbgLocOrigin::StackTracesTy &getOriginStackTraces() const {
return Loc.getOriginStackTraces();
}
DebugLoc getCopied() const {
DebugLoc NewDL = *this;
NewDL.Loc.addTrace();
return NewDL;
}
#else
DebugLoc getCopied() const { return *this; }
#endif

/// Get the underlying \a DILocation.
///
/// \pre !*this or \c isa<DILocation>(getAsMDNode()).
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ class Instruction : public User,
LLVM_ABI bool extractProfTotalWeight(uint64_t &TotalVal) const;

/// Set the debug location information for this instruction.
void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); }
void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc).getCopied(); }

/// Return the debug location for this node as a DebugLoc.
const DebugLoc &getDebugLoc() const { return DbgLoc; }
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/CodeGen/BranchFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h"
Expand Down Expand Up @@ -933,7 +934,13 @@ bool BranchFolder::TryTailMergeBlocks(MachineBasicBlock *SuccBB,

// Sort by hash value so that blocks with identical end sequences sort
// together.
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
// If origin-tracking is enabled then MergePotentialElt is no longer a POD
// type, so we need std::sort instead.
std::sort(MergePotentials.begin(), MergePotentials.end());
#else
array_pod_sort(MergePotentials.begin(), MergePotentials.end());
#endif

// Walk through equivalence sets looking for actual exact matches.
while (MergePotentials.size() > 1) {
Expand Down
26 changes: 25 additions & 1 deletion llvm/lib/IR/DebugLoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,35 @@
#include "llvm/IR/DebugLoc.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DebugInfo.h"

#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
#include "llvm/Support/Signals.h"

namespace llvm {
DbgLocOrigin::DbgLocOrigin(bool ShouldCollectTrace) {
if (!ShouldCollectTrace)
return;
auto &[Depth, StackTrace] = StackTraces.emplace_back();
Depth = sys::getStackTrace(StackTrace);
}
void DbgLocOrigin::addTrace() {
// We only want to add new stacktraces if we already have one: addTrace exists
// to provide more context to how missing DebugLocs have propagated through
// the program, but by design if there is no existing stacktrace then we have
// decided not to track this DebugLoc as being "missing".
if (StackTraces.empty())
return;
auto &[Depth, StackTrace] = StackTraces.emplace_back();
Depth = sys::getStackTrace(StackTrace);
}
} // namespace llvm
#endif

using namespace llvm;

#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
: TrackingMDNodeRef(const_cast<DILocation *>(L)),
: TrackingMDNodeRef(const_cast<DILocation *>(L)), DbgLocOrigin(!L),
Kind(DebugLocKind::Normal) {}
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE

Expand Down
Loading