[DLCov] Origin-Tracking: Collect stack traces in DebugLoc (#146678)
This patch is part of a series that adds origin-tracking to the debugify source location coverage checks, allowing us to report symbolized stack traces of the point where missing source locations appear. This patch adds the logic for collecting stack traces in DebugLoc instances. We do not symbolize the stack traces in this patch - that only happens when we decide to actually print them, which will be the responsibility of debugify. The collection happens in the constructor of a DebugLoc that has neither a valid location nor an annotation; we also collect an extra stack trace every time we call setDebugLoc, as sometimes the more interesting point is not where the DebugLoc was constructed, but where it was applied to an instruction. This takes the form of a getCopied() method on DebugLoc, which is the identity function in normal builds, but adds an extra stack trace in origin-tracking builds.
This commit is contained in:
parent
30eb97c584
commit
4f047bc595
@ -27,6 +27,21 @@ namespace llvm {
|
|||||||
class Function;
|
class Function;
|
||||||
|
|
||||||
#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
#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
|
// Used to represent different "kinds" of DebugLoc, expressing that the
|
||||||
// instruction it is part of is either normal and should contain a valid
|
// instruction it is part of is either normal and should contain a valid
|
||||||
// DILocation, or otherwise describing the reason why the instruction does
|
// DILocation, or otherwise describing the reason why the instruction does
|
||||||
@ -55,22 +70,29 @@ namespace llvm {
|
|||||||
Temporary
|
Temporary
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extends TrackingMDNodeRef to also store a DebugLocKind, allowing Debugify
|
// Extends TrackingMDNodeRef to also store a DebugLocKind and Origin,
|
||||||
// to ignore intentionally-empty DebugLocs.
|
// allowing Debugify to ignore intentionally-empty DebugLocs and display the
|
||||||
class DILocAndCoverageTracking : public TrackingMDNodeRef {
|
// 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:
|
public:
|
||||||
DebugLocKind Kind;
|
DebugLocKind Kind;
|
||||||
// Default constructor for empty DebugLocs.
|
// Default constructor for empty DebugLocs.
|
||||||
DILocAndCoverageTracking()
|
DILocAndCoverageTracking()
|
||||||
: TrackingMDNodeRef(nullptr), Kind(DebugLocKind::Normal) {}
|
: TrackingMDNodeRef(nullptr), DbgLocOrigin(true),
|
||||||
// Valid or nullptr MDNode*, normal DebugLocKind.
|
Kind(DebugLocKind::Normal) {}
|
||||||
|
// Valid or nullptr MDNode*, no annotative DebugLocKind.
|
||||||
DILocAndCoverageTracking(const MDNode *Loc)
|
DILocAndCoverageTracking(const MDNode *Loc)
|
||||||
: TrackingMDNodeRef(const_cast<MDNode *>(Loc)),
|
: TrackingMDNodeRef(const_cast<MDNode *>(Loc)), DbgLocOrigin(!Loc),
|
||||||
Kind(DebugLocKind::Normal) {}
|
Kind(DebugLocKind::Normal) {}
|
||||||
LLVM_ABI DILocAndCoverageTracking(const DILocation *Loc);
|
LLVM_ABI DILocAndCoverageTracking(const DILocation *Loc);
|
||||||
// Explicit DebugLocKind, which always means a nullptr MDNode*.
|
// Explicit DebugLocKind, which always means a nullptr MDNode*.
|
||||||
DILocAndCoverageTracking(DebugLocKind Kind)
|
DILocAndCoverageTracking(DebugLocKind Kind)
|
||||||
: TrackingMDNodeRef(nullptr), Kind(Kind) {}
|
: TrackingMDNodeRef(nullptr),
|
||||||
|
DbgLocOrigin(Kind == DebugLocKind::Normal), Kind(Kind) {}
|
||||||
};
|
};
|
||||||
template <> struct simplify_type<DILocAndCoverageTracking> {
|
template <> struct simplify_type<DILocAndCoverageTracking> {
|
||||||
using SimpleType = MDNode *;
|
using SimpleType = MDNode *;
|
||||||
@ -187,6 +209,19 @@ namespace llvm {
|
|||||||
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
#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.
|
/// Get the underlying \a DILocation.
|
||||||
///
|
///
|
||||||
/// \pre !*this or \c isa<DILocation>(getAsMDNode()).
|
/// \pre !*this or \c isa<DILocation>(getAsMDNode()).
|
||||||
|
@ -507,7 +507,7 @@ public:
|
|||||||
LLVM_ABI bool extractProfTotalWeight(uint64_t &TotalVal) const;
|
LLVM_ABI bool extractProfTotalWeight(uint64_t &TotalVal) const;
|
||||||
|
|
||||||
/// Set the debug location information for this instruction.
|
/// 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.
|
/// Return the debug location for this node as a DebugLoc.
|
||||||
const DebugLoc &getDebugLoc() const { return DbgLoc; }
|
const DebugLoc &getDebugLoc() const { return DbgLoc; }
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "llvm/CodeGen/TargetPassConfig.h"
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
||||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||||
|
#include "llvm/Config/llvm-config.h"
|
||||||
#include "llvm/IR/DebugInfoMetadata.h"
|
#include "llvm/IR/DebugInfoMetadata.h"
|
||||||
#include "llvm/IR/DebugLoc.h"
|
#include "llvm/IR/DebugLoc.h"
|
||||||
#include "llvm/IR/Function.h"
|
#include "llvm/IR/Function.h"
|
||||||
@ -933,7 +934,13 @@ bool BranchFolder::TryTailMergeBlocks(MachineBasicBlock *SuccBB,
|
|||||||
|
|
||||||
// Sort by hash value so that blocks with identical end sequences sort
|
// Sort by hash value so that blocks with identical end sequences sort
|
||||||
// together.
|
// 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());
|
array_pod_sort(MergePotentials.begin(), MergePotentials.end());
|
||||||
|
#endif
|
||||||
|
|
||||||
// Walk through equivalence sets looking for actual exact matches.
|
// Walk through equivalence sets looking for actual exact matches.
|
||||||
while (MergePotentials.size() > 1) {
|
while (MergePotentials.size() > 1) {
|
||||||
|
@ -9,11 +9,35 @@
|
|||||||
#include "llvm/IR/DebugLoc.h"
|
#include "llvm/IR/DebugLoc.h"
|
||||||
#include "llvm/Config/llvm-config.h"
|
#include "llvm/Config/llvm-config.h"
|
||||||
#include "llvm/IR/DebugInfo.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;
|
using namespace llvm;
|
||||||
|
|
||||||
#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
#if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
||||||
DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
|
DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
|
||||||
: TrackingMDNodeRef(const_cast<DILocation *>(L)),
|
: TrackingMDNodeRef(const_cast<DILocation *>(L)), DbgLocOrigin(!L),
|
||||||
Kind(DebugLocKind::Normal) {}
|
Kind(DebugLocKind::Normal) {}
|
||||||
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user