Author: Stephen Tozer
Date: 2025-04-30T11:39:29+01:00
New Revision: 92195f6fc873cd27a5aa0852252dfe44ccdc6ea0

URL: 
https://github.com/llvm/llvm-project/commit/92195f6fc873cd27a5aa0852252dfe44ccdc6ea0
DIFF: 
https://github.com/llvm/llvm-project/commit/92195f6fc873cd27a5aa0852252dfe44ccdc6ea0.diff

LOG: Reapply "[DLCov] Implement DebugLoc coverage tracking (#107279)"

Reapplied after fixing the config issue that was causing issues following
the previous merge.

This reverts commit fdbf073a86573c9ac4d595fac8e06d252ce1469f.

Added: 
    

Modified: 
    clang/lib/CodeGen/BackendUtil.cpp
    llvm/docs/HowToUpdateDebugInfo.rst
    llvm/include/llvm/IR/DebugLoc.h
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/IR/DebugInfo.cpp
    llvm/lib/IR/DebugLoc.cpp
    llvm/lib/Transforms/Utils/Debugify.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index 2271f011b3a05..c9ceb49ce5ceb 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -962,6 +962,22 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
       Debugify.setOrigDIVerifyBugsReportFilePath(
           CodeGenOpts.DIBugsReportFilePath);
     Debugify.registerCallbacks(PIC, MAM);
+
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+    // If we're using debug location coverage tracking, mark all the
+    // instructions coming out of the frontend without a DebugLoc as being
+    // compiler-generated, to prevent both those instructions and new
+    // instructions that inherit their location from being treated as
+    // incorrectly empty locations.
+    for (Function &F : *TheModule) {
+      if (!F.getSubprogram())
+        continue;
+      for (BasicBlock &BB : F)
+        for (Instruction &I : BB)
+          if (!I.getDebugLoc())
+            I.setDebugLoc(DebugLoc::getCompilerGenerated());
+    }
+#endif
   }
   // Attempt to load pass plugins and register their callbacks with PB.
   for (auto &PluginFN : CodeGenOpts.PassPlugins) {

diff  --git a/llvm/docs/HowToUpdateDebugInfo.rst 
b/llvm/docs/HowToUpdateDebugInfo.rst
index 3088f59c1066a..a87efe7e6e43f 100644
--- a/llvm/docs/HowToUpdateDebugInfo.rst
+++ b/llvm/docs/HowToUpdateDebugInfo.rst
@@ -169,6 +169,47 @@ See the discussion in the section about
 :ref:`merging locations<WhenToMergeLocation>` for examples of when the rule for
 dropping locations applies.
 
+.. _NewInstLocations:
+
+Setting locations for new instructions
+--------------------------------------
+
+Whenever a new instruction is created and there is no suitable location for 
that
+instruction, that instruction should be annotated accordingly. There are a set
+of special ``DebugLoc`` values that can be set on an instruction to annotate 
the
+reason that it does not have a valid location. These are as follows:
+
+* ``DebugLoc::getCompilerGenerated()``: This indicates that the instruction is 
a
+  compiler-generated instruction, i.e. it is not associated with any user 
source
+  code.
+
+* ``DebugLoc::getDropped()``: This indicates that the instruction has
+  intentionally had its source location removed, according to the rules for
+  :ref:`dropping locations<WhenToDropLocation>`; this is set automatically by
+  ``Instruction::dropLocation()``.
+
+* ``DebugLoc::getUnknown()``: This indicates that the instruction does not have
+  a known or currently knowable source location, e.g. that it is infeasible to
+  determine the correct source location, or that the source location is
+  ambiguous in a way that LLVM cannot currently represent.
+
+* ``DebugLoc::getTemporary()``: This is used for instructions that we don't
+  expect to be emitted (e.g. ``UnreachableInst``), and so should not need a
+  valid location; if we ever try to emit a temporary location into an 
object/asm
+  file, this indicates that something has gone wrong.
+
+Where applicable, these should be used instead of leaving an instruction 
without
+an assigned location or explicitly setting the location as ``DebugLoc()``.
+Ordinarily these special locations are identical to an absent location, but 
LLVM
+built with coverage-tracking
+(``-DLLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING="COVERAGE"``) will keep track of
+these special locations in order to detect unintentionally-missing locations;
+for this reason, the most important rule is to *not* apply any of these if it
+isn't clear which, if any, is appropriate - an absent location can be detected
+and fixed, while an incorrectly annotated instruction is much harder to detect.
+On the other hand, if any of these clearly apply, then they should be used to
+prevent false positives from being flagged up.
+
 Rules for updating debug values
 ===============================
 

diff  --git a/llvm/include/llvm/IR/DebugLoc.h b/llvm/include/llvm/IR/DebugLoc.h
index c22d3e9b10d27..255ceb9571909 100644
--- a/llvm/include/llvm/IR/DebugLoc.h
+++ b/llvm/include/llvm/IR/DebugLoc.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_IR_DEBUGLOC_H
 #define LLVM_IR_DEBUGLOC_H
 
+#include "llvm/Config/llvm-config.h"
 #include "llvm/IR/TrackingMDRef.h"
 #include "llvm/Support/DataTypes.h"
 
@@ -22,6 +23,73 @@ namespace llvm {
   class LLVMContext;
   class raw_ostream;
   class DILocation;
+  class Function;
+
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+  // Used to represent 
diff erent "kinds" of DebugLoc, expressing that the
+  // instruction it is part of is either normal and should contain a valid
+  // DILocation, or otherwise describing the reason why the instruction does
+  // not contain a valid DILocation.
+  enum class DebugLocKind : uint8_t {
+    // The instruction is expected to contain a valid DILocation.
+    Normal,
+    // The instruction is compiler-generated, i.e. it is not associated with 
any
+    // line in the original source.
+    CompilerGenerated,
+    // The instruction has intentionally had its source location removed,
+    // typically because it was moved outside of its original control-flow and
+    // presenting the prior source location would be misleading for debuggers
+    // or profilers.
+    Dropped,
+    // The instruction does not have a known or currently knowable source
+    // location, e.g. the attribution is ambiguous in a way that can't be
+    // represented, or determining the correct location is complicated and
+    // requires future developer effort.
+    Unknown,
+    // DebugLoc is attached to an instruction that we don't expect to be
+    // emitted, and so can omit a valid DILocation; we don't expect to ever try
+    // and emit these into the line table, and trying to do so is a sign that
+    // something has gone wrong (most likely a DebugLoc leaking from a 
transient
+    // compiler-generated instruction).
+    Temporary
+  };
+
+  // Extends TrackingMDNodeRef to also store a DebugLocKind, allowing Debugify
+  // to ignore intentionally-empty DebugLocs.
+  class DILocAndCoverageTracking : public TrackingMDNodeRef {
+  public:
+    DebugLocKind Kind;
+    // Default constructor for empty DebugLocs.
+    DILocAndCoverageTracking()
+        : TrackingMDNodeRef(nullptr), Kind(DebugLocKind::Normal) {}
+    // Valid or nullptr MDNode*, normal DebugLocKind.
+    DILocAndCoverageTracking(const MDNode *Loc)
+        : TrackingMDNodeRef(const_cast<MDNode *>(Loc)),
+          Kind(DebugLocKind::Normal) {}
+    DILocAndCoverageTracking(const DILocation *Loc);
+    // Explicit DebugLocKind, which always means a nullptr MDNode*.
+    DILocAndCoverageTracking(DebugLocKind Kind)
+        : TrackingMDNodeRef(nullptr), Kind(Kind) {}
+  };
+  template <> struct simplify_type<DILocAndCoverageTracking> {
+    using SimpleType = MDNode *;
+
+    static MDNode *getSimplifiedValue(DILocAndCoverageTracking &MD) {
+      return MD.get();
+    }
+  };
+  template <> struct simplify_type<const DILocAndCoverageTracking> {
+    using SimpleType = MDNode *;
+
+    static MDNode *getSimplifiedValue(const DILocAndCoverageTracking &MD) {
+      return MD.get();
+    }
+  };
+
+  using DebugLocTrackingRef = DILocAndCoverageTracking;
+#else
+  using DebugLocTrackingRef = TrackingMDNodeRef;
+#endif // LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
 
   /// A debug info location.
   ///
@@ -31,7 +99,8 @@ namespace llvm {
   /// To avoid extra includes, \a DebugLoc doubles the \a DILocation API with a
   /// one based on relatively opaque \a MDNode pointers.
   class DebugLoc {
-    TrackingMDNodeRef Loc;
+
+    DebugLocTrackingRef Loc;
 
   public:
     DebugLoc() = default;
@@ -47,6 +116,31 @@ namespace llvm {
     /// IR.
     explicit DebugLoc(const MDNode *N);
 
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+    DebugLoc(DebugLocKind Kind) : Loc(Kind) {}
+    DebugLocKind getKind() const { return Loc.Kind; }
+#endif
+
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+    static inline DebugLoc getTemporary() {
+      return DebugLoc(DebugLocKind::Temporary);
+    }
+    static inline DebugLoc getUnknown() {
+      return DebugLoc(DebugLocKind::Unknown);
+    }
+    static inline DebugLoc getCompilerGenerated() {
+      return DebugLoc(DebugLocKind::CompilerGenerated);
+    }
+    static inline DebugLoc getDropped() {
+      return DebugLoc(DebugLocKind::Dropped);
+    }
+#else
+    static inline DebugLoc getTemporary() { return DebugLoc(); }
+    static inline DebugLoc getUnknown() { return DebugLoc(); }
+    static inline DebugLoc getCompilerGenerated() { return DebugLoc(); }
+    static inline DebugLoc getDropped() { return DebugLoc(); }
+#endif // LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+
     /// Get the underlying \a DILocation.
     ///
     /// \pre !*this or \c isa<DILocation>(getAsMDNode()).

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 5dcb1cde25331..b331854d1ee8f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2098,6 +2098,10 @@ void DwarfDebug::beginInstruction(const MachineInstr 
*MI) {
   }
 
   if (!DL) {
+    // FIXME: We could assert that `DL.getKind() != DebugLocKind::Temporary`
+    // here, or otherwise record any temporary DebugLocs seen to ensure that
+    // transient compiler-generated instructions aren't leaking their DLs to
+    // other instructions.
     // We have an unspecified location, which might want to be line 0.
     // If we have already emitted a line-0 record, don't repeat it.
     if (LastAsmLine == 0)

diff  --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp
index 557b57d911160..dff9a08c2c8e0 100644
--- a/llvm/lib/IR/DebugInfo.cpp
+++ b/llvm/lib/IR/DebugInfo.cpp
@@ -988,8 +988,10 @@ void Instruction::updateLocationAfterHoist() { 
dropLocation(); }
 
 void Instruction::dropLocation() {
   const DebugLoc &DL = getDebugLoc();
-  if (!DL)
+  if (!DL) {
+    setDebugLoc(DebugLoc::getDropped());
     return;
+  }
 
   // If this isn't a call, drop the location to allow a location from a
   // preceding instruction to propagate.
@@ -1001,7 +1003,7 @@ void Instruction::dropLocation() {
   }
 
   if (!MayLowerToCall) {
-    setDebugLoc(DebugLoc());
+    setDebugLoc(DebugLoc::getDropped());
     return;
   }
 
@@ -1020,7 +1022,7 @@ void Instruction::dropLocation() {
     //
     // One alternative is to set a line 0 location with the existing scope and
     // inlinedAt info. The location might be sensitive to when inlining occurs.
-    setDebugLoc(DebugLoc());
+    setDebugLoc(DebugLoc::getDropped());
 }
 
 
//===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/IR/DebugLoc.cpp b/llvm/lib/IR/DebugLoc.cpp
index bdea52180f74a..10affe3468171 100644
--- a/llvm/lib/IR/DebugLoc.cpp
+++ b/llvm/lib/IR/DebugLoc.cpp
@@ -11,6 +11,12 @@
 #include "llvm/IR/DebugInfo.h"
 using namespace llvm;
 
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
+    : TrackingMDNodeRef(const_cast<DILocation *>(L)),
+      Kind(DebugLocKind::Normal) {}
+#endif // LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+
 
//===----------------------------------------------------------------------===//
 // DebugLoc Implementation
 
//===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/Transforms/Utils/Debugify.cpp 
b/llvm/lib/Transforms/Utils/Debugify.cpp
index e6b5e267d192b..d67a563f531f6 100644
--- a/llvm/lib/Transforms/Utils/Debugify.cpp
+++ b/llvm/lib/Transforms/Utils/Debugify.cpp
@@ -290,6 +290,16 @@ bool llvm::stripDebugifyMetadata(Module &M) {
   return Changed;
 }
 
+bool hasLoc(const Instruction &I) {
+  const DILocation *Loc = I.getDebugLoc().get();
+#if LLVM_ENABLE_DEBUGLOC_COVERAGE_TRACKING
+  DebugLocKind Kind = I.getDebugLoc().getKind();
+  return Loc || Kind != DebugLocKind::Normal;
+#else
+  return Loc;
+#endif
+}
+
 bool llvm::collectDebugInfoMetadata(Module &M,
                                     iterator_range<Module::iterator> Functions,
                                     DebugInfoPerPass &DebugInfoBeforePass,
@@ -362,9 +372,7 @@ bool llvm::collectDebugInfoMetadata(Module &M,
         LLVM_DEBUG(dbgs() << "  Collecting info for inst: " << I << '\n');
         DebugInfoBeforePass.InstToDelete.insert({&I, &I});
 
-        const DILocation *Loc = I.getDebugLoc().get();
-        bool HasLoc = Loc != nullptr;
-        DebugInfoBeforePass.DILocations.insert({&I, HasLoc});
+        DebugInfoBeforePass.DILocations.insert({&I, hasLoc(I)});
       }
     }
   }
@@ -607,10 +615,7 @@ bool llvm::checkDebugInfoMetadata(Module &M,
 
         LLVM_DEBUG(dbgs() << "  Collecting info for inst: " << I << '\n');
 
-        const DILocation *Loc = I.getDebugLoc().get();
-        bool HasLoc = Loc != nullptr;
-
-        DebugInfoAfterPass.DILocations.insert({&I, HasLoc});
+        DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
       }
     }
   }


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to