[llvm] [llvm-dwarfdump][LineCov 1/3] Add variable coverage metrics (PR #169646)

Stephen Tozer via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 06:29:32 PST 2025


================
@@ -0,0 +1,244 @@
+//===-- Coverage.cpp - Debug info coverage metrics ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-dwarfdump.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DebugProgramInstruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include <set>
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+
+typedef std::pair<std::string, std::string> StringPair;
+
+static std::optional<std::set<std::pair<uint16_t, uint32_t>>>
+computeVariableCoverage(DWARFContext &DICtx, DWARFDie DIE,
+                        const DWARFDebugLine::LineTable *const LineTable) {
+  auto addLines = [](const DWARFDebugLine::LineTable *LineTable,
+                     std::set<std::pair<uint16_t, uint32_t>> &Lines,
+                     DWARFAddressRange Range,
+                     std::map<std::string, uint16_t, std::less<>> &FileNames) {
+    std::vector<uint32_t> Rows;
+    if (LineTable->lookupAddressRange({Range.LowPC, Range.SectionIndex},
+                                      Range.HighPC - Range.LowPC, Rows)) {
+      for (const auto &RowI : Rows) {
+        const auto Row = LineTable->Rows[RowI];
+        if (Row.Address.Address < Range.LowPC)
+          continue;
+        const auto FileIndex = Row.File;
+
+        if (!any_of(FileNames,
+                    [FileIndex](auto &FN) { return FN.second == FileIndex; })) {
+          std::string Name;
+          LineTable->getFileNameByIndex(
+              FileIndex, "",
+              DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath, Name);
+          FileNames.emplace(Name, FileIndex);
+        }
+
+        const auto Line = Row.Line;
+        if (Line) // ignore zero lines
+          Lines.insert({FileIndex, Line});
+      }
+    }
+  };
+
+  std::map<std::string, uint16_t, std::less<>> FileNames;
+
+  auto Locations = DIE.getLocations(DW_AT_location);
+  std::optional<std::set<std::pair<uint16_t, uint32_t>>> Lines;
----------------
SLTozer wrote:

Regarding this and the other `std::optional<std::set<...>>` instances, it may be worth explicitly noting the purpose of the optional in a comment; as far as I can tell, after these blocks, we'll see an empty optional if there were no location ranges, and a present optional containing an empty set if location ranges were found that cover no source locations (e.g. if all lines were line 0), and this is relevant for the logic below that determines whether or not to fallback to or intersect with the parent's location ranges, is that correct?

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


More information about the llvm-commits mailing list