[llvm] [llvm-dwarfdump][LineCov 3/3] Add IR analysis for variable coverage (PR #195342)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 04:31:42 PDT 2026


================
@@ -195,6 +215,124 @@ static const SmallVector<DWARFDie> getParentSubroutines(DWARFDie DIE) {
   return Parents;
 }
 
+static bool isInScope(MDNode *Scope, const DebugLoc &Loc) {
+  MDNode *Parent = Loc.getScope();
+  while (Parent != Scope) {
+    auto *S = dyn_cast_if_present<DIScope>(Parent);
+    if (!S)
+      return false;
+    Parent = S->getScope();
+  }
+  return true;
+}
+
+static bool isLoop(BasicBlock *Origin, BasicBlock *BB,
+                   SmallPtrSet<BasicBlock *, 8> &Visited) {
+  for (auto *P : predecessors(BB)) {
+    if (P == Origin)
+      return true;
+    if (!Visited.count(P)) {
+      Visited.insert(P);
+      if (isLoop(Origin, P, Visited))
+        return true;
+    }
+  }
+  return false;
+}
+
+struct VarState {
+  DbgVariableRecord &DVR;
+  DenseSet<std::pair<StringRef, uint32_t>> Lines;
+  SmallPtrSet<BasicBlock *, 8> LiveOut;
+};
+
+/// Given an instruction that stores to a variable and its basic block,
+/// recursively searches its successor instructions/basic blocks and adds lines
+/// where the variable has a defined value to the variable's line set.
+static void getSuccessorLines(VarState &Var, BasicBlock *BB, Instruction *I) {
+  // Process the basic block if it contains the store instruction or the
+  // variable is defined in all of its predecessors, excluding any that are part
+  // of a loop that contains the current block.
+  bool ShouldProcess = I;
+  if (!ShouldProcess) {
+    ShouldProcess = true;
+    for (auto *P : predecessors(BB)) {
+      SmallPtrSet<BasicBlock *, 8> Visited;
+      if (!Var.LiveOut.count(P) && !isLoop(BB, P, Visited)) {
+        ShouldProcess = false;
+        break;
+      }
+    }
+  }
+  if (!ShouldProcess || Var.LiveOut.count(BB))
+    return;
+  Var.LiveOut.insert(BB);
+
+  // Add lines that are within the variable's scope, starting from the store
+  // instruction or the start of the block if this is a successor block.
+  auto *Next = I ? I : &BB->front();
+  auto *VarScope = Var.DVR.getVariable()->getScope();
+  do {
+    auto &Loc = Next->getDebugLoc();
+    DIScope *Scope;
+    if (Loc && isInScope(VarScope, Loc) && Loc.getLine() &&
+        (Scope = dyn_cast_if_present<DIScope>(Loc.getScope()))) {
+      Var.Lines.insert({Scope->getFilename(), Loc.getLine()});
+    }
+  } while ((Next = Next->getNextNode()));
+  for (auto *S : successors(BB))
+    getSuccessorLines(Var, S, nullptr);
+}
+
+/// Computes the defined lines of all variables in an IR module.
+static LineMap processModule(Module *Mod) {
+  LineMap Result;
+
+  for (auto &F : Mod->functions()) {
+    std::vector<VarState> Vars;
+    for (auto &BB : F) {
+      for (auto &I : BB) {
+        for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
+          if (DVR.isDbgDeclare()) {
+            // For #dbg_declare, don't treat the variable as live until we find
+            // a store to it.
+            Vars.push_back({DVR, {}, {}});
+          } else if (DVR.isDbgValue()) {
+            // For #dbg_value, the variable is live immediately from this point.
+            auto Var = find_if(Vars, [&](auto &Var) {
+              return Var.DVR.getVariable() == DVR.getVariable();
+            });
+            if (Var != Vars.end()) {
+              getSuccessorLines(*Var, &BB, &I);
+            } else {
+              Vars.push_back({DVR, {}, {}});
+              getSuccessorLines(Vars.back(), &BB, &I);
+            }
+          }
+        }
+      }
+    }
+
+    // Search for stores to any declared variables. For the purposes of this
+    // analysis, we consider any instruction that isn't a load and has the
+    // variable as an operand to potentially store to it.
----------------
unexpectedlydefined wrote:

I've added a new `isStoreToLocation` function that mostly replicates the check in `at::trackAssignments`, but also treats call-like instructions as stores if the location is passed as an argument to the call.

https://github.com/llvm/llvm-project/pull/195342


More information about the llvm-commits mailing list