-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
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 *; | ||
|
@@ -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()). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
||
|
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.