[llvm] [DebugInfo] Fix line 0 records incorrectly having is_stmt set (PR #166627)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 5 12:19:54 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: None (RoshanYSingh23)

<details>
<summary>Changes</summary>

Fixes issue #<!-- -->33870

Line 0 debug records should not have the is_stmt flag set in DWARF. This change ensures is_stmt is only set for non-zero line numbers.

Changes made in DwarfDebug.cpp:
- beginInstruction: Only set is_stmt for prologue_end if line != 0
- beginInstruction: Only set is_stmt for key instructions if line != 0
- emitInitialLocDirective: Set is_stmt=0 if scopeLine == 0

Test results: All 576 X86 DebugInfo tests pass.

---
Full diff: https://github.com/llvm/llvm-project/pull/166627.diff


1 Files Affected:

- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+84-79) 


``````````diff
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 567acf75d1b8d..31035e8085c36 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -101,13 +101,12 @@ static cl::opt<AccelTableKind> AccelTables(
                clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")),
     cl::init(AccelTableKind::Default));
 
-static cl::opt<DefaultOnOff>
-DwarfInlinedStrings("dwarf-inlined-strings", cl::Hidden,
-                 cl::desc("Use inlined strings rather than string section."),
-                 cl::values(clEnumVal(Default, "Default for platform"),
-                            clEnumVal(Enable, "Enabled"),
-                            clEnumVal(Disable, "Disabled")),
-                 cl::init(Default));
+static cl::opt<DefaultOnOff> DwarfInlinedStrings(
+    "dwarf-inlined-strings", cl::Hidden,
+    cl::desc("Use inlined strings rather than string section."),
+    cl::values(clEnumVal(Default, "Default for platform"),
+               clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")),
+    cl::init(Default));
 
 static cl::opt<bool>
     NoDwarfRangesSection("no-dwarf-ranges-section", cl::Hidden,
@@ -231,9 +230,7 @@ void DebugLocDwarfExpression::commitTemporaryBuffer() {
   TmpBuf->Comments.clear();
 }
 
-const DIType *DbgVariable::getType() const {
-  return getVariable()->getType();
-}
+const DIType *DbgVariable::getType() const { return getVariable()->getType(); }
 
 /// Get .debug_loc entry for the instruction range starting at MI.
 static DbgValueLoc getDebugLocValue(const MachineInstr *MI) {
@@ -371,8 +368,9 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
     UseAllLinkageNames = DwarfLinkageNames == AllLinkageNames;
 
   unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion;
-  unsigned DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber
-                                    : MMI->getModule()->getDwarfVersion();
+  unsigned DwarfVersion = DwarfVersionNumber
+                              ? DwarfVersionNumber
+                              : MMI->getModule()->getDwarfVersion();
   // Use dwarf 4 by default if nothing is requested. For NVPTX, use dwarf 2.
   DwarfVersion =
       TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION);
@@ -433,7 +431,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
   UseDebugMacroSection =
       DwarfVersion >= 5 || (UseGNUDebugMacro && !useSplitDwarf());
   if (DwarfOpConvert == Default)
-    EnableOpConvert = !((tuneForGDB() && useSplitDwarf()) || (tuneForLLDB() && !TT.isOSBinFormatMachO()));
+    EnableOpConvert = !((tuneForGDB() && useSplitDwarf()) ||
+                        (tuneForLLDB() && !TT.isOSBinFormatMachO()));
   else
     EnableOpConvert = (DwarfOpConvert == Enable);
 
@@ -857,14 +856,16 @@ static void collectCallSiteParameters(const MachineInstr *CallMI,
     assert(std::next(Suc) == BundleEnd &&
            "More than one instruction in call delay slot");
     // Try to interpret value loaded by instruction.
-    if (!interpretNextInstr(&*Suc, ForwardedRegWorklist, Params, ClobberedRegUnits))
+    if (!interpretNextInstr(&*Suc, ForwardedRegWorklist, Params,
+                            ClobberedRegUnits))
       return;
   }
 
   // Search for a loading value in forwarding registers.
   for (; I != MBB->rend(); ++I) {
     // Try to interpret values loaded by instruction.
-    if (!interpretNextInstr(&*I, ForwardedRegWorklist, Params, ClobberedRegUnits))
+    if (!interpretNextInstr(&*I, ForwardedRegWorklist, Params,
+                            ClobberedRegUnits))
       return;
   }
 
@@ -1106,8 +1107,7 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
   if (auto *CU = CUMap.lookup(DIUnit))
     return *CU;
 
-  if (useSplitDwarf() &&
-      !shareAcrossDWOCUs() &&
+  if (useSplitDwarf() && !shareAcrossDWOCUs() &&
       (!DIUnit->getSplitDebugInlining() ||
        DIUnit->getEmissionKind() == DICompileUnit::FullDebug) &&
       !CUMap.empty()) {
@@ -1201,7 +1201,6 @@ void DwarfDebug::beginModule(Module *M) {
     (useSplitDwarf() ? SkeletonHolder : InfoHolder)
         .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base"));
 
-
   // Create the symbols that designates the start of the DWARF v5 range list
   // and locations list tables. They are located past the table headers.
   if (getDwarfVersion() >= 5) {
@@ -1415,7 +1414,7 @@ void DwarfDebug::finalizeModuleInfo() {
                             TLOF.getDwarfMacinfoSection()->getBeginSymbol());
       }
     }
-    }
+  }
 
   // Emit all frontend-produced Skeleton CUs, i.e., Clang modules.
   for (auto *CUNode : MMI->getModule()->debug_compile_units())
@@ -1491,7 +1490,7 @@ void DwarfDebug::endModule() {
   emitDebugRanges();
 
   if (useSplitDwarf())
-  // Emit info into a debug macinfo.dwo section.
+    // Emit info into a debug macinfo.dwo section.
     emitDebugMacinfoDWO();
   else
     // Emit info into a debug macinfo/macro section.
@@ -1533,8 +1532,8 @@ void DwarfDebug::endModule() {
   // FIXME: AbstractVariables.clear();
 }
 
-void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
-    const DINode *Node, const MDNode *ScopeNode) {
+void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(
+    DwarfCompileUnit &CU, const DINode *Node, const MDNode *ScopeNode) {
   if (CU.getExistingAbstractEntity(Node))
     return;
 
@@ -1580,7 +1579,8 @@ void DwarfDebug::collectVariableInfoFromMFTable(
       continue;
     }
 
-    ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first, Scope->getScopeNode());
+    ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first,
+                                          Scope->getScopeNode());
 
     // If we have already seen information for this variable, add to what we
     // already know.
@@ -1607,7 +1607,7 @@ void DwarfDebug::collectVariableInfoFromMFTable(
     }
 
     auto RegVar = std::make_unique<DbgVariable>(
-                    cast<DILocalVariable>(Var.first), Var.second);
+        cast<DILocalVariable>(Var.first), Var.second);
     if (VI.inStackSlot())
       RegVar->emplace<Loc::MMI>(VI.Expr, VI.getStackSlot());
     else
@@ -1723,8 +1723,7 @@ static bool validThroughout(LexicalScopes &LScopes,
 // [4-)     [(@g, fragment 0, 96)]
 bool DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
                                    const DbgValueHistoryMap::Entries &Entries) {
-  using OpenRange =
-      std::pair<DbgValueHistoryMap::EntryIndex, DbgValueLoc>;
+  using OpenRange = std::pair<DbgValueHistoryMap::EntryIndex, DbgValueLoc>;
   SmallVector<OpenRange, 4> OpenRanges;
   bool isSafeForSingleLocation = true;
   const MachineInstr *StartDebugMI = nullptr;
@@ -1750,8 +1749,7 @@ bool DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
       EndLabel = Asm->MBBSectionRanges[EndMBB.getSectionID()].EndLabel;
       if (EI->isClobber())
         EndMI = EI->getInstr();
-    }
-    else if (std::next(EI)->isClobber())
+    } else if (std::next(EI)->isClobber())
       EndLabel = getLabelAfterInsn(std::next(EI)->getInstr());
     else
       EndLabel = getLabelBeforeInsn(std::next(EI)->getInstr());
@@ -1889,17 +1887,15 @@ DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU,
                                             const MCSymbol *Sym) {
   ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode());
   if (isa<const DILocalVariable>(Node)) {
-    ConcreteEntities.push_back(
-        std::make_unique<DbgVariable>(cast<const DILocalVariable>(Node),
-                                       Location));
-    InfoHolder.addScopeVariable(&Scope,
-        cast<DbgVariable>(ConcreteEntities.back().get()));
+    ConcreteEntities.push_back(std::make_unique<DbgVariable>(
+        cast<const DILocalVariable>(Node), Location));
+    InfoHolder.addScopeVariable(
+        &Scope, cast<DbgVariable>(ConcreteEntities.back().get()));
   } else if (isa<const DILabel>(Node)) {
     ConcreteEntities.push_back(
-        std::make_unique<DbgLabel>(cast<const DILabel>(Node),
-                                    Location, Sym));
+        std::make_unique<DbgLabel>(cast<const DILabel>(Node), Location, Sym));
     InfoHolder.addScopeLabel(&Scope,
-        cast<DbgLabel>(ConcreteEntities.back().get()));
+                             cast<DbgLabel>(ConcreteEntities.back().get()));
   }
   return ConcreteEntities.back().get();
 }
@@ -1935,8 +1931,8 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,
       continue;
 
     Processed.insert(IV);
-    DbgVariable *RegVar = cast<DbgVariable>(createConcreteEntity(TheCU,
-                                            *Scope, LocalVar, IV.second));
+    DbgVariable *RegVar = cast<DbgVariable>(
+        createConcreteEntity(TheCU, *Scope, LocalVar, IV.second));
 
     const MachineInstr *MInsn = HistoryMapEntries.front().getInstr();
     assert(MInsn->isDebugValue() && "History must begin with debug value");
@@ -2150,7 +2146,8 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
       (!PrevInstBB ||
        PrevInstBB->getSectionID() == MI->getParent()->getSectionID());
   bool ForceIsStmt = ForceIsStmtInstrs.contains(MI);
-  if (PrevInstInSameSection && !ForceIsStmt && DL.isSameSourceLocation(PrevInstLoc)) {
+  if (PrevInstInSameSection && !ForceIsStmt &&
+      DL.isSameSourceLocation(PrevInstLoc)) {
     // If we have an ongoing unspecified location, nothing to do here.
     if (!DL)
       return;
@@ -2199,12 +2196,16 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
   if (DL.getLine() == 0 && LastAsmLine == 0)
     return;
   if (MI == PrologEndLoc) {
-    Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
+    Flags |= DWARF2_FLAG_PROLOGUE_END;
+    // Don't set is_stmt for line 0
+    if (DL.getLine() != 0)
+      Flags |= DWARF2_FLAG_IS_STMT;
     PrologEndLoc = nullptr;
   }
 
   if (ScopeUsesKeyInstructions) {
-    if (IsKey)
+    // Don't set is_stmt for line 0
+    if (IsKey && DL.getLine() != 0)
       Flags |= DWARF2_FLAG_IS_STMT;
   } else {
     // If the line changed, we call that a new statement; unless we went to
@@ -2370,7 +2371,8 @@ static void recordSourceLine(AsmPrinter &Asm, unsigned Line, unsigned Col,
 const MachineInstr *
 DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
   // Don't deal with functions that have no instructions.
-  if (llvm::all_of(MF, [](const MachineBasicBlock &MBB) { return MBB.empty(); }))
+  if (llvm::all_of(MF,
+                   [](const MachineBasicBlock &MBB) { return MBB.empty(); }))
     return nullptr;
 
   std::pair<const MachineInstr *, bool> PrologEnd = findPrologueEndLoc(&MF);
@@ -2400,8 +2402,11 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
   (void)getOrCreateDwarfCompileUnit(SP->getUnit());
   // We'd like to list the prologue as "not statements" but GDB behaves
   // poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
-  ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
-                     CUID, getDwarfVersion(), getUnits());
+  // However, we should not set is_stmt for line 0.
+  unsigned ScopeLine = SP->getScopeLine();
+  unsigned Flags = (ScopeLine != 0) ? DWARF2_FLAG_IS_STMT : 0;
+  ::recordSourceLine(*Asm, ScopeLine, 0, SP, Flags, CUID, getDwarfVersion(),
+                     getUnits());
   return PrologEndLoc;
 }
 
@@ -2677,7 +2682,8 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
   CurFn = MF;
 
   auto *SP = MF->getFunction().getSubprogram();
-  assert(LScopes.empty() || SP == LScopes.getCurrentFunctionScope()->getScopeNode());
+  assert(LScopes.empty() ||
+         SP == LScopes.getCurrentFunctionScope()->getScopeNode());
   if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
     return;
 
@@ -2738,7 +2744,8 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   const Function &F = MF->getFunction();
   const DISubprogram *SP = F.getSubprogram();
 
-  assert(CurFn == MF &&
+  assert(
+      CurFn == MF &&
       "endFunction should be called with the same function as beginFunction");
 
   // Set DwarfDwarfCompileUnitID in MCContext to default value.
@@ -3090,15 +3097,16 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
     Offset++;
     for (unsigned I = 0; I < Op.getDescription().Op.size(); ++I) {
       if (Op.getDescription().Op[I] == Encoding::BaseTypeRef) {
-        unsigned Length =
-          Streamer.emitDIERef(*CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die);
+        unsigned Length = Streamer.emitDIERef(
+            *CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die);
         // Make sure comments stay aligned.
         for (unsigned J = 0; J < Length; ++J)
           if (Comment != End)
             Comment++;
       } else {
         for (uint64_t J = Offset; J < Op.getOperandEndOffset(I); ++J)
-          Streamer.emitInt8(Data.getData()[J], Comment != End ? *(Comment++) : "");
+          Streamer.emitInt8(Data.getData()[J],
+                            Comment != End ? *(Comment++) : "");
       }
       Offset = Op.getOperandEndOffset(I);
     }
@@ -3205,8 +3213,7 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
 
 void DebugLocEntry::finalize(const AsmPrinter &AP,
                              DebugLocStream::ListBuilder &List,
-                             const DIBasicType *BT,
-                             DwarfCompileUnit &TheCU) {
+                             const DIBasicType *BT, DwarfCompileUnit &TheCU) {
   assert(!Values.empty() &&
          "location list entries without values are redundant");
   assert(Begin != End && "unexpected location list entry with empty range");
@@ -3216,9 +3223,8 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
   const DbgValueLoc &Value = Values[0];
   if (Value.isFragment()) {
     // Emit all fragments that belong to the same variable and range.
-    assert(llvm::all_of(Values, [](DbgValueLoc P) {
-          return P.isFragment();
-        }) && "all values are expected to be fragments");
+    assert(llvm::all_of(Values, [](DbgValueLoc P) { return P.isFragment(); }) &&
+           "all values are expected to be fragments");
     assert(llvm::is_sorted(Values) && "fragments are expected to be sorted");
 
     for (const auto &Fragment : Values)
@@ -3239,7 +3245,8 @@ void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry,
   Asm->OutStreamer->AddComment("Loc expr size");
   if (getDwarfVersion() >= 5)
     Asm->emitULEB128(DebugLocs.getBytes(Entry).size());
-  else if (DebugLocs.getBytes(Entry).size() <= std::numeric_limits<uint16_t>::max())
+  else if (DebugLocs.getBytes(Entry).size() <=
+           std::numeric_limits<uint16_t>::max())
     Asm->emitInt16(DebugLocs.getBytes(Entry).size());
   else {
     // The entry is too big to fit into 16 bit, drop it as there is nothing we
@@ -3291,13 +3298,12 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm,
 }
 
 template <typename Ranges, typename PayloadEmitter>
-static void emitRangeList(
-    DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R,
-    const DwarfCompileUnit &CU, unsigned BaseAddressx, unsigned OffsetPair,
-    unsigned StartxLength, unsigned EndOfList,
-    StringRef (*StringifyEnum)(unsigned),
-    bool ShouldUseBaseAddress,
-    PayloadEmitter EmitPayload) {
+static void
+emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R,
+              const DwarfCompileUnit &CU, unsigned BaseAddressx,
+              unsigned OffsetPair, unsigned StartxLength, unsigned EndOfList,
+              StringRef (*StringifyEnum)(unsigned), bool ShouldUseBaseAddress,
+              PayloadEmitter EmitPayload) {
 
   auto Size = Asm->MAI->getCodePointerSize();
   bool UseDwarf5 = DD.getDwarfVersion() >= 5;
@@ -3398,7 +3404,8 @@ static void emitRangeList(
 }
 
 // Handles emission of both debug_loclist / debug_loclist.dwo
-static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) {
+static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm,
+                        const DebugLocStream::List &List) {
   emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List),
                 *List.CU, dwarf::DW_LLE_base_addressx,
                 dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length,
@@ -3428,17 +3435,15 @@ void DwarfDebug::emitDebugLocImpl(MCSection *Sec) {
 
 // Emit locations into the .debug_loc/.debug_loclists section.
 void DwarfDebug::emitDebugLoc() {
-  emitDebugLocImpl(
-      getDwarfVersion() >= 5
-          ? Asm->getObjFileLowering().getDwarfLoclistsSection()
-          : Asm->getObjFileLowering().getDwarfLocSection());
+  emitDebugLocImpl(getDwarfVersion() >= 5
+                       ? Asm->getObjFileLowering().getDwarfLoclistsSection()
+                       : Asm->getObjFileLowering().getDwarfLocSection());
 }
 
 // Emit locations into the .debug_loc.dwo/.debug_loclists.dwo section.
 void DwarfDebug::emitDebugLocDWO() {
   if (getDwarfVersion() >= 5) {
-    emitDebugLocImpl(
-        Asm->getObjFileLowering().getDwarfLoclistsDWOSection());
+    emitDebugLocImpl(Asm->getObjFileLowering().getDwarfLoclistsDWOSection());
 
     return;
   }
@@ -3626,16 +3631,16 @@ void DwarfDebug::emitDebugARanges() {
 /// Emit a single range list. We handle both DWARF v5 and earlier.
 static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm,
                           const RangeSpanList &List) {
-  emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU,
-                dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair,
-                dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list,
-                llvm::dwarf::RangeListEncodingString,
-                List.CU->getCUNode()->getRangesBaseAddress() ||
-                    DD.getDwarfVersion() >= 5,
-                [](auto) {});
+  emitRangeList(
+      DD, Asm, List.Label, List.Ranges, *List.CU, dwarf::DW_RLE_base_addressx,
+      dwarf::DW_RLE_offset_pair, dwarf::DW_RLE_startx_length,
+      dwarf::DW_RLE_end_of_list, llvm::dwarf::RangeListEncodingString,
+      List.CU->getCUNode()->getRangesBaseAddress() || DD.getDwarfVersion() >= 5,
+      [](auto) {});
 }
 
-void DwarfDebug::emitDebugRangesImpl(const DwarfFile &Holder, MCSection *Section) {
+void DwarfDebug::emitDebugRangesImpl(const DwarfFile &Holder,
+                                     MCSection *Section) {
   if (Holder.getRangeLists().empty())
     return;
 
@@ -4059,11 +4064,11 @@ void DwarfDebug::addAccelNameImpl(
     assert(((&Current == &AccelTypeUnitsDebugNames) ||
             ((&Current == &AccelDebugNames) &&
              (Unit.getUnitDie().getTag() != dwarf::DW_TAG_type_unit))) &&
-               "Kind is CU but TU is being processed.");
+           "Kind is CU but TU is being processed.");
     assert(((&Current == &AccelDebugNames) ||
             ((&Current == &AccelTypeUnitsDebugNames) &&
              (Unit.getUnitDie().getTag() == dwarf::DW_TAG_type_unit))) &&
-               "Kind is TU but CU is being processed.");
+           "Kind is TU but CU is being processed.");
     // The type unit can be discarded, so need to add references to final
     // acceleration table once we know it's complete and we emit it.
     Current.addName(Ref, Die, Unit.getUniqueID(),

``````````

</details>


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


More information about the llvm-commits mailing list