[llvm] [llvm-dwarfdump][LineCov 3/3] Add IR analysis for variable coverage (PR #195342)
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 07:16:54 PDT 2026
================
@@ -195,6 +221,143 @@ 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;
+}
+
+/// Determines whether an instruction stores to a location. For the purposes of
+/// this analysis, we consider any call-like instruction with the location as an
+/// argument to be a store to it.
+static bool isStoreToLocation(const DataLayout &DL, Instruction &I,
+ Value *Loc) {
+ std::optional<at::AssignmentInfo> Info;
+ if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ if (SI->getPointerOperand() == Loc)
+ return true;
+ Info = at::getAssignmentInfo(DL, SI);
+ } else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&I)) {
+ if (MI->getDest() == Loc)
+ return true;
+ Info = at::getAssignmentInfo(DL, MI);
+ } else if (CallBase *CI = dyn_cast<CallBase>(&I)) {
+ return CI->hasArgument(Loc);
+ }
+ return Info && Info->Base == Loc;
+}
+
+typedef SmallDenseMap<BasicBlock *, Instruction *, 8> VarDefinitionMap;
+
+struct VarState {
+ DbgVariableRecord &DVR;
+ VarDefinitionMap Definitions;
+};
+
+/// Adds source locations to the line set for instructions in a basic block,
+/// starting with a specific instruction.
+static void addModuleLines(Instruction *I, VarState &Var,
+ DenseSet<std::pair<StringRef, uint32_t>> &Lines) {
+ auto *VarScope = Var.DVR.getVariable()->getScope();
+ do {
+ auto &Loc = I->getDebugLoc();
+ DIScope *Scope;
+ if (Loc && isInScope(VarScope, Loc) && Loc.getLine() &&
+ (Scope = dyn_cast_if_present<DIScope>(Loc.getScope()))) {
+ Lines.insert({Scope->getFilename(), Loc.getLine()});
+ }
+ } while ((I = I->getNextNode()));
+}
+
+/// Computes the defined lines of all variables in an IR module.
+static BitcodeLineMap processModule(Module *Mod) {
+ BitcodeLineMap Result;
+ std::vector<VarState> Vars;
+ for (auto &F : Mod->functions()) {
+ Vars.clear();
+ for (auto &BB : F) {
+ for (auto &I : BB) {
+ for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
+ if (DVR.isKillLocation()) {
+ assert("Variable in bitcode has been optimized out");
+ continue;
+ }
+ if (DVR.isDbgDeclare()) {
+ // For #dbg_declare, don't treat the variable as live until we find
+ // a store to it.
+ Vars.push_back(VarState{DVR, VarDefinitionMap()});
+ } else if (DVR.isDbgValue()) {
+ // For #dbg_value, the variable is live immediately from this point.
+ if (DVR.getDebugLoc().getInlinedAt() != nullptr) {
+ assert("Variable in bitcode has been inlined");
+ continue;
+ }
+ auto Var = find_if(Vars, [&](auto &Var) {
+ return Var.DVR.getVariable() == DVR.getVariable();
+ });
+ if (Var != Vars.end())
+ // If a basic block contains multiple stores to a variable, use
+ // the earliest one by allowing the insertion to silently fail if
+ // the basic block is already in the map.
+ Var->Definitions.insert({&BB, &I});
+ else
+ Vars.push_back(VarState{DVR, {{&BB, &I}}});
+ }
+ }
+ }
+ }
+
+ for (auto &BB : F)
+ for (auto &I : BB)
+ for (auto &Var : Vars)
+ if (isStoreToLocation(Mod->getDataLayout(), I, Var.DVR.getValue()))
+ // The variable is live from the instruction after the store. As
+ // above, the earliest store in this basic block will be used.
+ Var.Definitions.insert({&BB, I.getNextNode()});
----------------
SLTozer wrote:
Each of the `for`s and the `if` will need braces.
https://github.com/llvm/llvm-project/pull/195342
More information about the llvm-commits
mailing list