Skip to content

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

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
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>;
Comment on lines +33 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I right in reading this as a 16-wide array stored in a vector that's either zero-lengthed or one (given that on initialization we add a single element to the vector)? I feel there must be a better pattern than storing an array in a vector -- a potentially empty unique_ptr to a std::array, and allocate the array off the heap when it's needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the time we store 0 stacktraces, but when we do store a stacktrace there may be any number of them - the addTrace function adds a new stacktrace to the vector, and is used whenever the DebugLoc is "transferred", so that we can track the motion of a missing debug location through the program.

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 {
Comment on lines +79 to +80
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reflex inside my head says "prefer composition to inheritance" -- is there a reason we need to inherit from DbgLocOrigin, instead of having it as a named member of DILocAndCoverageTracking?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could manage without it, but the reason I use inheritance here is that this allows DILocAndCoverageTracking to automatically have the same public functions as DbgLocOrigin, meaning we conditionally have the origin-tracking functions enabled without having to repeat ourselves here.

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
22 changes: 21 additions & 1 deletion llvm/lib/IR/DebugLoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,31 @@
#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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early exit instead?

auto &[Depth, StackTrace] = StackTraces.emplace_back();
Depth = sys::getStackTrace(StackTrace);
}
}
void DbgLocOrigin::addTrace() {
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