[llvm] [AssignmentTracking][NFC] Cache interesting debug records and instructions (PR #149514)
Orlando Cazalet-Hyams via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 18 06:43:21 PDT 2025
https://github.com/OCHyams created https://github.com/llvm/llvm-project/pull/149514
Rather than visit all instructions each iteration of the analysis, we can cache the interesting ones ahead of time while performing other setup related tasks.
Marginal performance improvement. Note in this compile-tim-tracker comparison I've enabled assignment tracking support with lto, which isn't the same as on main:
http://llvm-compile-time-tracker.com/compare.php?from=80d92fc648d0160e0bbd191ba67b0f05218d4b69&to=1a38acc6e758919bbce5a451b7fe39c89a134c01&stat=instructions%3Au
>From 32cadc141e6546283ede7998da29355378d60026 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Thu, 17 Jul 2025 14:13:25 +0100
Subject: [PATCH 1/3] NFC: stop treating every store as unknown. unknown
---
llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
index ff265b505b5da..d0c69e47fa214 100644
--- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
+++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
@@ -2150,7 +2150,10 @@ static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
for (auto &I : BB) {
for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
ProcessDbgRecord(&DVR);
- if (auto Info = getUntaggedStoreAssignmentInfo(I, Fn.getDataLayout())) {
+ if (I.getMetadata(LLVMContext::MD_DIAssignID)) {
+ // Do nothing.
+ } else if (auto Info =
+ getUntaggedStoreAssignmentInfo(I, Fn.getDataLayout())) {
// Find markers linked to this alloca.
auto HandleDbgAssignForStore = [&](DbgVariableRecord *Assign) {
std::optional<DIExpression::FragmentInfo> FragInfo;
>From 49a9a98e493e25b697a573d716506194205de4f3 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Thu, 17 Jul 2025 10:04:16 +0100
Subject: [PATCH 2/3] cache interesting insts
---
.../CodeGen/AssignmentTrackingAnalysis.cpp | 124 ++++++++++--------
1 file changed, 71 insertions(+), 53 deletions(-)
diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
index d0c69e47fa214..09c0525e4ef83 100644
--- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
+++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
@@ -11,6 +11,8 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
@@ -981,6 +983,16 @@ class MemLocFragmentFill {
}
};
+/// A { DbgVariableRecord | Instruction | Bit } union. If Bit value is 1
+/// that means the DbgVariableRecords that follow the current Instruction
+/// come immediately after it. Else there's a gap of one or more instructions.
+using DbgOrInst =
+ PointerIntPair<PointerUnion<DbgVariableRecord *, Instruction *>, 1>;
+using DbgOrInstBlock = SmallVector<DbgOrInst>;
+/// Map of BasicBlock to a list of the instructions and debug records that are
+/// interesting.
+using DbgOrInstCacheTy = DenseMap<BasicBlock *, DbgOrInstBlock>;
+
/// AssignmentTrackingLowering encapsulates a dataflow analysis over a function
/// that interprets assignment tracking debug info metadata and stores in IR to
/// create a map of variable locations.
@@ -1097,6 +1109,10 @@ class AssignmentTrackingLowering {
/// to the variables they may assign to. Used by processUntaggedInstruction.
UnknownStoreAssignmentMap UnknownStoreVars;
+ // Rather than iterating over all instructions ever time, cache the
+ // interesting ones.
+ DbgOrInstCacheTy DbgOrInstCache;
+
// Machinery to defer inserting dbg.values.
using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
InstInsertMap InsertBeforeMap;
@@ -1862,47 +1878,31 @@ void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) {
}
void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) {
- // If the block starts with DbgRecords, we need to process those DbgRecords as
- // their own frame without processing any instructions first.
- bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords();
- for (auto II = BB.begin(), EI = BB.end(); II != EI;) {
- assert(VarsTouchedThisFrame.empty());
- // Process the instructions in "frames". A "frame" includes a single
- // non-debug instruction followed any debug instructions before the
- // next non-debug instruction.
-
- // Skip the current instruction if it has unprocessed DbgRecords attached
- // (see comment above `ProcessedLeadingDbgRecords`).
- if (ProcessedLeadingDbgRecords) {
- // II is now either a debug intrinsic, a non-debug instruction with no
- // attached DbgRecords, or a non-debug instruction with attached processed
- // DbgRecords.
- // II has not been processed.
- if (II->isTerminator())
- break;
- resetInsertionPoint(*II);
- processNonDbgInstruction(*II, LiveSet);
- assert(LiveSet->isValid());
- ++II;
+ auto &BBCache = DbgOrInstCache[&BB];
+ // Process the instructions in "frames". A "frame" includes a single
+ // non-debug instruction followed any debug instructions before the
+ // next non-debug instruction. A pointer-int int value of 1 on an
+ // instruction means non-debug instructions follow (end of frame).
+ for (auto II = BBCache.begin(), EI = BBCache.end(); II != EI;) {
+ LLVM_DEBUG(dbgs() << "---------------------------- new frame "
+ "------------------------------\n");
+ bool DbgInstsInThisFrame = true;
+ if (Instruction *Inst = II->getPointer().dyn_cast<Instruction *>()) {
+ resetInsertionPoint(*Inst);
+ processNonDbgInstruction(*Inst, LiveSet);
+ DbgInstsInThisFrame = II++->getInt();
}
- // II is now either a debug intrinsic, a non-debug instruction with no
- // attached DbgRecords, or a non-debug instruction with attached unprocessed
- // DbgRecords.
- if (II != EI && II->hasDbgRecords()) {
- // Skip over non-variable debug records (i.e., labels). They're going to
- // be read from IR (possibly re-ordering them within the debug record
- // range) rather than from the analysis results.
- for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) {
- resetInsertionPoint(DVR);
- processDbgVariableRecord(DVR, LiveSet);
- assert(LiveSet->isValid());
+
+ // Process a wedge of debug records.
+ if (DbgInstsInThisFrame) {
+ DbgVariableRecord *DVR;
+ while (II != EI &&
+ (DVR = II->getPointer().dyn_cast<DbgVariableRecord *>())) {
+ resetInsertionPoint(*DVR);
+ processDbgVariableRecord(*DVR, LiveSet);
+ ++II;
}
}
- ProcessedLeadingDbgRecords = true;
- // II is now a non-debug instruction either with no attached DbgRecords, or
- // with attached processed DbgRecords. II has not been processed, and all
- // debug instructions or DbgRecords in the frame preceding II have been
- // processed.
// We've processed everything in the "frame". Now determine which variables
// cannot be represented by a dbg.declare.
@@ -2121,7 +2121,7 @@ static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
const DenseSet<DebugAggregate> &VarsWithStackSlot,
AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
AssignmentTrackingLowering::UnknownStoreAssignmentMap &UnknownStoreVars,
- unsigned &TrackedVariablesVectorSize) {
+ DbgOrInstCacheTy &DbgOrInstCache, unsigned &TrackedVariablesVectorSize) {
DenseSet<DebugVariable> Seen;
// Map of Variable: [Fragments].
DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap;
@@ -2134,24 +2134,40 @@ static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
// We need to add fragments for untagged stores too so that we can correctly
// clobber overlapped fragment locations later.
SmallVector<DbgVariableRecord *> DPDeclares;
- auto ProcessDbgRecord = [&](DbgVariableRecord *Record) {
- if (Record->isDbgDeclare()) {
- DPDeclares.push_back(Record);
- return;
- }
- DebugVariable DV = DebugVariable(Record);
- DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
- if (!VarsWithStackSlot.contains(DA))
- return;
- if (Seen.insert(DV).second)
- FragmentMap[DA].push_back(DV);
- };
for (auto &BB : Fn) {
+ auto &BBCache = DbgOrInstCache[&BB];
+
+ auto ProcessDbgRecord = [&](DbgVariableRecord *Record) {
+ if (Record->isDbgDeclare()) {
+ DPDeclares.push_back(Record);
+ return;
+ }
+ DebugVariable DV = DebugVariable(Record);
+ DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
+ if (!VarsWithStackSlot.contains(DA))
+ return;
+
+ if (Seen.insert(DV).second)
+ FragmentMap[DA].push_back(DV);
+
+ BBCache.push_back({Record, 0});
+ };
+
for (auto &I : BB) {
+ auto TFBlockSize = BBCache.size();
for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
ProcessDbgRecord(&DVR);
+
+ if (TFBlockSize && TFBlockSize != BBCache.size() &&
+ BBCache[TFBlockSize - 1].getPointer().dyn_cast<Instruction *>() &&
+ &*std::next(BBCache[TFBlockSize - 1]
+ .getPointer()
+ .dyn_cast<Instruction *>()
+ ->getIterator()) == &I)
+ BBCache[TFBlockSize - 1].setInt(1);
+
if (I.getMetadata(LLVMContext::MD_DIAssignID)) {
- // Do nothing.
+ BBCache.push_back({&I, 0});
} else if (auto Info =
getUntaggedStoreAssignmentInfo(I, Fn.getDataLayout())) {
// Find markers linked to this alloca.
@@ -2190,6 +2206,7 @@ static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
};
for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base))
HandleDbgAssignForStore(DVR);
+ BBCache.push_back({&I, 0});
} else if (auto *AI = getUnknownStore(I, Fn.getDataLayout())) {
// Find markers linked to this alloca.
auto HandleDbgAssignForUnknownStore = [&](DbgVariableRecord *Assign) {
@@ -2207,6 +2224,7 @@ static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
};
for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(AI))
HandleDbgAssignForUnknownStore(DVR);
+ BBCache.push_back({&I, 0});
}
}
}
@@ -2279,7 +2297,7 @@ bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
// appears to be rare occurance.
VarContains = buildOverlapMapAndRecordDeclares(
Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, UnknownStoreVars,
- TrackedVariablesVectorSize);
+ DbgOrInstCache, TrackedVariablesVectorSize);
// Prepare for traversal.
ReversePostOrderTraversal<Function *> RPOT(&Fn);
>From 4c79194d086735c4e0ef4a58932a009c33da0859 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Fri, 18 Jul 2025 14:40:57 +0100
Subject: [PATCH 3/3] Downgrade if to assert now that not-stack-homed variables
are pre-filtered out
---
llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
index 09c0525e4ef83..bfbe5fa5c35d7 100644
--- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
+++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
@@ -1780,10 +1780,9 @@ void AssignmentTrackingLowering::processTaggedInstruction(
void AssignmentTrackingLowering::processDbgAssign(DbgVariableRecord *DbgAssign,
BlockInfo *LiveSet) {
- // Only bother tracking variables that are at some point stack homed. Other
- // variables can be dealt with trivially later.
- if (!VarsWithStackSlot->count(getAggregate(DbgAssign)))
- return;
+ // Fully promoted variables are dealt with later.
+ assert(VarsWithStackSlot->count(getAggregate(DbgAssign)) &&
+ "Not a stack variable");
VariableID Var = getVariableID(DebugVariable(DbgAssign));
Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign);
@@ -1822,10 +1821,9 @@ void AssignmentTrackingLowering::processDbgAssign(DbgVariableRecord *DbgAssign,
void AssignmentTrackingLowering::processDbgValue(DbgVariableRecord *DbgValue,
BlockInfo *LiveSet) {
- // Only other tracking variables that are at some point stack homed.
- // Other variables can be dealt with trivally later.
- if (!VarsWithStackSlot->count(getAggregate(DbgValue)))
- return;
+ // Fully promoted variables are dealt with later.
+ assert(VarsWithStackSlot->count(getAggregate(DbgValue)) &&
+ "Not a stack variable");
VariableID Var = getVariableID(DebugVariable(DbgValue));
// We have no ID to create an Assignment with so we mark this assignment as
More information about the llvm-commits
mailing list