Skip to content

[DebugInfo] Shave even more users of DbgVariableIntrinsic from LLVM #149136

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 18, 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
5 changes: 1 addition & 4 deletions llvm/include/llvm/IR/DebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ class DebugInfoFinder {
LLVM_ABI void processVariable(DILocalVariable *DVI);
/// Process debug info location.
LLVM_ABI void processLocation(const Module &M, const DILocation *Loc);
/// Process a DbgRecord (e.g, treat a DbgVariableRecord like a
/// DbgVariableIntrinsic).
/// Process a DbgRecord.
LLVM_ABI void processDbgRecord(const Module &M, const DbgRecord &DR);

/// Process subprogram.
Expand Down Expand Up @@ -290,8 +289,6 @@ struct VarRecord {
DILocalVariable *Var;
DILocation *DL;

VarRecord(DbgVariableIntrinsic *DVI)
: Var(DVI->getVariable()), DL(getDebugValueLoc(DVI)) {}
VarRecord(DbgVariableRecord *DVR)
: Var(DVR->getVariable()), DL(getDebugValueLoc(DVR)) {}
VarRecord(DILocalVariable *Var, DILocation *DL) : Var(Var), DL(DL) {}
Expand Down
3 changes: 0 additions & 3 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ namespace dwarf {
enum Tag : uint16_t;
}

class DbgVariableIntrinsic;
class DbgVariableRecord;

LLVM_ABI extern cl::opt<bool> EnableFSDiscriminator;
Expand Down Expand Up @@ -4613,7 +4612,6 @@ class DebugVariable {
LLVM_ABI static const FragmentInfo DefaultFragment;

public:
LLVM_ABI DebugVariable(const DbgVariableIntrinsic *DII);
LLVM_ABI DebugVariable(const DbgVariableRecord *DVR);

DebugVariable(const DILocalVariable *Var,
Expand Down Expand Up @@ -4681,7 +4679,6 @@ template <> struct DenseMapInfo<DebugVariable> {
/// information).
class DebugVariableAggregate : public DebugVariable {
public:
LLVM_ABI DebugVariableAggregate(const DbgVariableIntrinsic *DVI);
DebugVariableAggregate(const DebugVariable &V)
: DebugVariable(V.getVariable(), std::nullopt, V.getInlinedAt()) {}
};
Expand Down
25 changes: 9 additions & 16 deletions llvm/lib/IR/DebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2288,39 +2288,36 @@ bool AssignmentTrackingPass::runOnFunction(Function &F) {
// Collect a map of {backing storage : dbg.declares} (currently "backing
// storage" is limited to Allocas). We'll use this to find dbg.declares to
// delete after running `trackAssignments`.
DenseMap<const AllocaInst *, SmallPtrSet<DbgDeclareInst *, 2>> DbgDeclares;
DenseMap<const AllocaInst *, SmallPtrSet<DbgVariableRecord *, 2>> DVRDeclares;
// Create another similar map of {storage : variables} that we'll pass to
// trackAssignments.
StorageToVarsMap Vars;
auto ProcessDeclare = [&](auto *Declare, auto &DeclareList) {
auto ProcessDeclare = [&](DbgVariableRecord &Declare) {
// FIXME: trackAssignments doesn't let you specify any modifiers to the
// variable (e.g. fragment) or location (e.g. offset), so we have to
// leave dbg.declares with non-empty expressions in place.
if (Declare->getExpression()->getNumElements() != 0)
if (Declare.getExpression()->getNumElements() != 0)
return;
if (!Declare->getAddress())
if (!Declare.getAddress())
return;
if (AllocaInst *Alloca =
dyn_cast<AllocaInst>(Declare->getAddress()->stripPointerCasts())) {
dyn_cast<AllocaInst>(Declare.getAddress()->stripPointerCasts())) {
// FIXME: Skip VLAs for now (let these variables use dbg.declares).
if (!Alloca->isStaticAlloca())
return;
// Similarly, skip scalable vectors (use dbg.declares instead).
if (auto Sz = Alloca->getAllocationSize(*DL); Sz && Sz->isScalable())
return;
DeclareList[Alloca].insert(Declare);
Vars[Alloca].insert(VarRecord(Declare));
DVRDeclares[Alloca].insert(&Declare);
Vars[Alloca].insert(VarRecord(&Declare));
}
};
for (auto &BB : F) {
for (auto &I : BB) {
for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
if (DVR.isDbgDeclare())
ProcessDeclare(&DVR, DVRDeclares);
ProcessDeclare(DVR);
}
if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(&I))
ProcessDeclare(DDI, DbgDeclares);
}
}

Expand All @@ -2336,8 +2333,8 @@ bool AssignmentTrackingPass::runOnFunction(Function &F) {
trackAssignments(F.begin(), F.end(), Vars, *DL);

// Delete dbg.declares for variables now tracked with assignment tracking.
auto DeleteSubsumedDeclare = [&](const auto &Markers, auto &Declares) {
(void)Markers;
for (auto &[Insts, Declares] : DVRDeclares) {
auto Markers = at::getDVRAssignmentMarkers(Insts);
for (auto *Declare : Declares) {
// Assert that the alloca that Declare uses is now linked to a dbg.assign
// describing the same variable (i.e. check that this dbg.declare has
Expand All @@ -2356,10 +2353,6 @@ bool AssignmentTrackingPass::runOnFunction(Function &F) {
Changed = true;
}
};
for (auto &P : DbgDeclares)
DeleteSubsumedDeclare(at::getAssignmentMarkers(P.first), P.second);
for (auto &P : DVRDeclares)
DeleteSubsumedDeclare(at::getDVRAssignmentMarkers(P.first), P.second);
return Changed;
}

Expand Down
9 changes: 0 additions & 9 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,11 @@ uint32_t DIType::getAlignInBits() const {
const DIExpression::FragmentInfo DebugVariable::DefaultFragment = {
std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::min()};

DebugVariable::DebugVariable(const DbgVariableIntrinsic *DII)
: Variable(DII->getVariable()),
Fragment(DII->getExpression()->getFragmentInfo()),
InlinedAt(DII->getDebugLoc().getInlinedAt()) {}

DebugVariable::DebugVariable(const DbgVariableRecord *DVR)
: Variable(DVR->getVariable()),
Fragment(DVR->getExpression()->getFragmentInfo()),
InlinedAt(DVR->getDebugLoc().getInlinedAt()) {}

DebugVariableAggregate::DebugVariableAggregate(const DbgVariableIntrinsic *DVI)
: DebugVariable(DVI->getVariable(), std::nullopt,
DVI->getDebugLoc()->getInlinedAt()) {}

DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Column, uint64_t AtomGroup, uint8_t AtomRank,
ArrayRef<Metadata *> MDs, bool ImplicitCode)
Expand Down
3 changes: 0 additions & 3 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -825,9 +825,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *EvaluateInDifferentType(Value *V, Type *Ty, bool isSigned);

bool tryToSinkInstruction(Instruction *I, BasicBlock *DestBlock);
void tryToSinkInstructionDbgValues(
Instruction *I, BasicBlock::iterator InsertPos, BasicBlock *SrcBlock,
BasicBlock *DestBlock, SmallVectorImpl<DbgVariableIntrinsic *> &DbgUsers);
void tryToSinkInstructionDbgVariableRecords(
Instruction *I, BasicBlock::iterator InsertPos, BasicBlock *SrcBlock,
BasicBlock *DestBlock, SmallVectorImpl<DbgVariableRecord *> &DPUsers);
Expand Down
67 changes: 4 additions & 63 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3575,6 +3575,7 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
std::unique_ptr<DIBuilder> DIB;
if (isa<AllocaInst>(MI)) {
findDbgUsers(DVIs, &MI, &DVRs);
assert(DVIs.empty());
DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false));
}

Expand Down Expand Up @@ -5253,8 +5254,7 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I,
SmallVector<DbgVariableIntrinsic *, 2> DbgUsers;
SmallVector<DbgVariableRecord *, 2> DbgVariableRecords;
findDbgUsers(DbgUsers, I, &DbgVariableRecords);
if (!DbgUsers.empty())
tryToSinkInstructionDbgValues(I, InsertPos, SrcBlock, DestBlock, DbgUsers);
assert(DbgUsers.empty());
if (!DbgVariableRecords.empty())
tryToSinkInstructionDbgVariableRecords(I, InsertPos, SrcBlock, DestBlock,
DbgVariableRecords);
Expand All @@ -5271,71 +5271,12 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I,
return true;
}

void InstCombinerImpl::tryToSinkInstructionDbgValues(
Instruction *I, BasicBlock::iterator InsertPos, BasicBlock *SrcBlock,
BasicBlock *DestBlock, SmallVectorImpl<DbgVariableIntrinsic *> &DbgUsers) {
// For all debug values in the destination block, the sunk instruction
// will still be available, so they do not need to be dropped.
SmallVector<DbgVariableIntrinsic *, 2> DbgUsersToSalvage;
for (auto &DbgUser : DbgUsers)
if (DbgUser->getParent() != DestBlock)
DbgUsersToSalvage.push_back(DbgUser);

// Process the sinking DbgUsersToSalvage in reverse order, as we only want
// to clone the last appearing debug intrinsic for each given variable.
SmallVector<DbgVariableIntrinsic *, 2> DbgUsersToSink;
for (DbgVariableIntrinsic *DVI : DbgUsersToSalvage)
if (DVI->getParent() == SrcBlock)
DbgUsersToSink.push_back(DVI);
llvm::sort(DbgUsersToSink,
[](auto *A, auto *B) { return B->comesBefore(A); });

SmallVector<DbgVariableIntrinsic *, 2> DIIClones;
SmallSet<DebugVariable, 4> SunkVariables;
for (auto *User : DbgUsersToSink) {
// A dbg.declare instruction should not be cloned, since there can only be
// one per variable fragment. It should be left in the original place
// because the sunk instruction is not an alloca (otherwise we could not be
// here).
if (isa<DbgDeclareInst>(User))
continue;

DebugVariable DbgUserVariable =
DebugVariable(User->getVariable(), User->getExpression(),
User->getDebugLoc()->getInlinedAt());

if (!SunkVariables.insert(DbgUserVariable).second)
continue;

// Leave dbg.assign intrinsics in their original positions and there should
// be no need to insert a clone.
if (isa<DbgAssignIntrinsic>(User))
continue;

DIIClones.emplace_back(cast<DbgVariableIntrinsic>(User->clone()));
if (isa<DbgDeclareInst>(User) && isa<CastInst>(I))
DIIClones.back()->replaceVariableLocationOp(I, I->getOperand(0));
LLVM_DEBUG(dbgs() << "CLONE: " << *DIIClones.back() << '\n');
}

// Perform salvaging without the clones, then sink the clones.
if (!DIIClones.empty()) {
salvageDebugInfoForDbgValues(*I, DbgUsersToSalvage, {});
// The clones are in reverse order of original appearance, reverse again to
// maintain the original order.
for (auto &DIIClone : llvm::reverse(DIIClones)) {
DIIClone->insertBefore(InsertPos);
LLVM_DEBUG(dbgs() << "SINK: " << *DIIClone << '\n');
}
}
}

void InstCombinerImpl::tryToSinkInstructionDbgVariableRecords(
Instruction *I, BasicBlock::iterator InsertPos, BasicBlock *SrcBlock,
BasicBlock *DestBlock,
SmallVectorImpl<DbgVariableRecord *> &DbgVariableRecords) {
// Implementation of tryToSinkInstructionDbgValues, but for the
// DbgVariableRecord of variable assignments rather than dbg.values.
// For all debug values in the destination block, the sunk instruction
// will still be available, so they do not need to be dropped.

// Fetch all DbgVariableRecords not already in the destination.
SmallVector<DbgVariableRecord *, 2> DbgVariableRecordsToSalvage;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,7 @@ static bool checkAndReplaceCondition(
SmallVector<DbgVariableIntrinsic *> DbgUsers;
SmallVector<DbgVariableRecord *> DVRUsers;
findDbgUsers(DbgUsers, Cmp, &DVRUsers);
assert(DbgUsers.empty());

for (auto *DVR : DVRUsers) {
auto *DTN = DT.getNode(DVR->getParent());
Expand Down
8 changes: 2 additions & 6 deletions llvm/lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1222,9 +1222,7 @@ static void eraseDebugIntrinsicsWithNonLocalRefs(Function &F) {
SmallVector<DbgVariableIntrinsic *, 4> DbgUsers;
SmallVector<DbgVariableRecord *, 4> DbgVariableRecords;
findDbgUsers(DbgUsers, &I, &DbgVariableRecords);
for (DbgVariableIntrinsic *DVI : DbgUsers)
if (DVI->getFunction() != &F)
DVI->eraseFromParent();
assert(DbgUsers.empty());
for (DbgVariableRecord *DVR : DbgVariableRecords)
if (DVR->getFunction() != &F)
DVR->eraseFromParent();
Expand Down Expand Up @@ -1289,14 +1287,12 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc,
SmallVector<DbgVariableIntrinsic *, 1> DbgUsers;
SmallVector<DbgVariableRecord *, 1> DPUsers;
findDbgUsers(DbgUsers, Input, &DPUsers);
assert(DbgUsers.empty());
DIExpression *Expr = DIB.createExpression();

// Iterate the debud users of the Input values. If they are in the extracted
// function then update their location with the new value. If they are in
// the parent function then create a similar debug record.
for (auto *DVI : DbgUsers)
UpdateOrInsertDebugRecord(DVI, Input, NewVal, Expr,
isa<DbgDeclareInst>(DVI));
for (auto *DVR : DPUsers)
UpdateOrInsertDebugRecord(DVR, Input, NewVal, Expr, DVR->isDbgDeclare());
}
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Transforms/Utils/InlineFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1978,14 +1978,13 @@ static at::StorageToVarsMap collectEscapedLocals(const DataLayout &DL,
continue;

// Find all local variables associated with the backing storage.
auto CollectAssignsForStorage = [&](auto *DbgAssign) {
auto CollectAssignsForStorage = [&](DbgVariableRecord *DbgAssign) {
// Skip variables from inlined functions - they are not local variables.
if (DbgAssign->getDebugLoc().getInlinedAt())
return;
LLVM_DEBUG(errs() << " > DEF : " << *DbgAssign << "\n");
EscapedLocals[Base].insert(at::VarRecord(DbgAssign));
};
for_each(at::getAssignmentMarkers(Base), CollectAssignsForStorage);
for_each(at::getDVRAssignmentMarkers(Base), CollectAssignsForStorage);
}
return EscapedLocals;
Expand Down
73 changes: 6 additions & 67 deletions llvm/lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,10 @@ bool llvm::replaceDbgUsesWithUndef(Instruction *I) {
SmallVector<DbgVariableIntrinsic *, 1> DbgUsers;
SmallVector<DbgVariableRecord *, 1> DPUsers;
findDbgUsers(DbgUsers, I, &DPUsers);
for (auto *DII : DbgUsers)
DII->setKillLocation();
assert(DbgUsers.empty());
for (auto *DVR : DPUsers)
DVR->setKillLocation();
return !DbgUsers.empty() || !DPUsers.empty();
return !DPUsers.empty();
}

/// areAllUsesEqual - Check whether the uses of a value are all the same.
Expand Down Expand Up @@ -2022,6 +2021,7 @@ void llvm::salvageDebugInfo(Instruction &I) {
SmallVector<DbgVariableIntrinsic *, 1> DbgUsers;
SmallVector<DbgVariableRecord *, 1> DPUsers;
findDbgUsers(DbgUsers, &I, &DPUsers);
assert(DbgUsers.empty());
salvageDebugInfoForDbgValues(I, DbgUsers, DPUsers);
}

Expand Down Expand Up @@ -2070,66 +2070,9 @@ void llvm::salvageDebugInfoForDbgValues(
const unsigned MaxExpressionSize = 128;
bool Salvaged = false;

for (auto *DII : DbgUsers) {
if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(DII)) {
if (DAI->getAddress() == &I) {
salvageDbgAssignAddress(DAI);
Salvaged = true;
}
if (DAI->getValue() != &I)
continue;
}

// Do not add DW_OP_stack_value for DbgDeclare, because they are implicitly
// pointing out the value as a DWARF memory location description.
bool StackValue = isa<DbgValueInst>(DII);
auto DIILocation = DII->location_ops();
assert(
is_contained(DIILocation, &I) &&
"DbgVariableIntrinsic must use salvaged instruction as its location");
SmallVector<Value *, 4> AdditionalValues;
// `I` may appear more than once in DII's location ops, and each use of `I`
// must be updated in the DIExpression and potentially have additional
// values added; thus we call salvageDebugInfoImpl for each `I` instance in
// DIILocation.
Value *Op0 = nullptr;
DIExpression *SalvagedExpr = DII->getExpression();
auto LocItr = find(DIILocation, &I);
while (SalvagedExpr && LocItr != DIILocation.end()) {
SmallVector<uint64_t, 16> Ops;
unsigned LocNo = std::distance(DIILocation.begin(), LocItr);
uint64_t CurrentLocOps = SalvagedExpr->getNumLocationOperands();
Op0 = salvageDebugInfoImpl(I, CurrentLocOps, Ops, AdditionalValues);
if (!Op0)
break;
SalvagedExpr =
DIExpression::appendOpsToArg(SalvagedExpr, Ops, LocNo, StackValue);
LocItr = std::find(++LocItr, DIILocation.end(), &I);
}
// salvageDebugInfoImpl should fail on examining the first element of
// DbgUsers, or none of them.
if (!Op0)
break;
// We should never see debug intrinsics nowadays.
assert(DbgUsers.empty());

SalvagedExpr = SalvagedExpr->foldConstantMath();
DII->replaceVariableLocationOp(&I, Op0);
bool IsValidSalvageExpr = SalvagedExpr->getNumElements() <= MaxExpressionSize;
if (AdditionalValues.empty() && IsValidSalvageExpr) {
DII->setExpression(SalvagedExpr);
} else if (isa<DbgValueInst>(DII) && IsValidSalvageExpr &&
DII->getNumVariableLocationOps() + AdditionalValues.size() <=
MaxDebugArgs) {
DII->addVariableLocationOps(AdditionalValues, SalvagedExpr);
} else {
// Do not salvage using DIArgList for dbg.declare, as it is not currently
// supported in those instructions. Also do not salvage if the resulting
// DIArgList would contain an unreasonably large number of values.
DII->setKillLocation();
}
LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n');
Salvaged = true;
}
// Duplicate of above block for DbgVariableRecords.
for (auto *DVR : DPUsers) {
if (DVR->isDbgAssign()) {
if (DVR->getAddress() == &I) {
Expand Down Expand Up @@ -2198,9 +2141,6 @@ void llvm::salvageDebugInfoForDbgValues(
if (Salvaged)
return;

for (auto *DII : DbgUsers)
DII->setKillLocation();

for (auto *DVR : DPUsers)
DVR->setKillLocation();
}
Expand Down Expand Up @@ -3429,8 +3369,7 @@ void llvm::dropDebugUsers(Instruction &I) {
SmallVector<DbgVariableIntrinsic *, 1> DbgUsers;
SmallVector<DbgVariableRecord *, 1> DPUsers;
findDbgUsers(DbgUsers, &I, &DPUsers);
for (auto *DII : DbgUsers)
DII->eraseFromParent();
assert(DbgUsers.empty());
for (auto *DVR : DPUsers)
DVR->eraseFromParent();
}
Expand Down
Loading
Loading