[llvm] [CodeExtractor] Copy live-in dbg records whole instead of rebuilding (PR #227794)
Oliver Hunt via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 18:11:27 PDT 2026
================
@@ -1270,13 +1270,77 @@ static void eraseDebugIntrinsicsWithNonLocalRefs(Function &F) {
}
}
+/// Does \p DVR describe its variable for the whole function, rather than from
+/// its position until the next record for the same variable?
+static bool isFunctionWideDbgRecord(const DbgVariableRecord &DVR) {
+ return DVR.isDbgDeclare() || DVR.isDbgDeclareValue();
+}
+
+/// Collect the debug records in the parent function that describe variables
+/// on entry to the extracted region, whose place is now taken by \p TheCall.
+///
+/// A #dbg_declare or #dbg_declare_value holds for the whole function, so one
+/// that uses any of \p Inputs is live on entry wherever it is. A #dbg_value or
+/// #dbg_assign holds only until the next record for the same variable, so only
+/// the last one before the region matters. Those are found by walking back from
+/// the call along the chain of unique predecessors, keeping the first record
+/// found for each variable. At a merge point the incoming paths may disagree,
+/// so the walk stops there: a variable it has not resolved gets no location in
+/// the new function, which is better than a wrong one.
+static void
+collectLiveInDbgRecords(CallInst &TheCall, const SetVector<Value *> &Inputs,
+ SmallSetVector<DbgVariableRecord *, 8> &LiveIn) {
+ Function *OldFunc = TheCall.getFunction();
+ for (Value *Input : Inputs) {
+ SmallVector<DbgVariableRecord *, 1> Users;
+ findDbgUsers(Input, Users);
+ for (DbgVariableRecord *DVR : Users)
+ if (isFunctionWideDbgRecord(*DVR) && DVR->getFunction() == OldFunc)
+ LiveIn.insert(DVR);
+ }
+
+ // Fragments of each variable already described closer to the call. A record
+ // is superseded if a later one covers an overlapping fragment.
+ DenseMap<std::pair<const DILocalVariable *, const DILocation *>,
+ SmallVector<DIExpression::FragmentInfo, 1>>
+ Described;
+ SmallVector<DbgVariableRecord *, 8> Values;
+ auto Visit = [&](DbgVariableRecord &DVR) {
+ DebugVariable Var(&DVR);
+ DIExpression::FragmentInfo Frag = Var.getFragmentOrDefault();
+ auto &Frags = Described[{Var.getVariable(), Var.getInlinedAt()}];
+ bool Superseded = any_of(Frags, [&](const DIExpression::FragmentInfo &F) {
+ return DIExpression::fragmentsOverlap(F, Frag);
+ });
+ Frags.push_back(Frag);
+ if (!Superseded)
+ Values.push_back(&DVR);
+ };
+
+ BasicBlock *BB = TheCall.getParent();
+ Instruction *From = &TheCall;
+ SmallPtrSet<BasicBlock *, 8> Visited{BB};
+ while (true) {
+ for (Instruction *I = From; I; I = I->getPrevNode())
+ for (DbgRecord &DR : reverse(I->getDbgRecordRange()))
+ if (auto *DVR = dyn_cast<DbgVariableRecord>(&DR))
+ if (!isFunctionWideDbgRecord(*DVR))
+ Visit(*DVR);
+ BB = BB->getUniquePredecessor();
+ if (!BB || !Visited.insert(BB).second)
+ break;
+ From = BB->getTerminator();
+ }
+ // Found nearest first; keep them in program order.
+ LiveIn.insert_range(reverse(Values));
+}
----------------
ojhunt wrote:
This loop is quadratic time - for each instruction you scan all of its predecessors, which includes prior instructions.
https://github.com/llvm/llvm-project/pull/227794
More information about the llvm-commits
mailing list