diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h index 2fa7d73e1fa25..b33c9f0c8e4d0 100644 --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -216,6 +216,9 @@ class MCDwarfLineEntry : public MCDwarfLoc { // Override the label with the given EndLabel. void setEndLabel(MCSymbol *EndLabel) { + // If we're setting this to be an end entry, make sure we don't have + // LineStreamLabel set. + assert(LineStreamLabel == nullptr); Label = EndLabel; IsEndEntry = true; } diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp index 2525ff02878e4..bb9bbd0a9e61b 100644 --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -144,19 +144,33 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) { void MCLineSection::addEndEntry(MCSymbol *EndLabel) { auto *Sec = &EndLabel->getSection(); // The line table may be empty, which we should skip adding an end entry. - // There are two cases: + // There are three cases: // (1) MCAsmStreamer - emitDwarfLocDirective emits a location directive in // place instead of adding a line entry if the target has // usesDwarfFileAndLocDirectives. // (2) MCObjectStreamer - if a function has incomplete debug info where // instructions don't have DILocations, the line entries are missing. + // (3) It's also possible that there are no prior line entries if the section + // itself is empty before this end label. auto I = MCLineDivisions.find(Sec); - if (I != MCLineDivisions.end()) { - auto &Entries = I->second; - auto EndEntry = Entries.back(); - EndEntry.setEndLabel(EndLabel); - Entries.push_back(EndEntry); - } + if (I == MCLineDivisions.end()) // If section not found, do nothing. + return; + + auto &Entries = I->second; + // If no entries in this section's list, nothing to base the end entry on. + if (Entries.empty()) + return; + + // Create the end entry based on the last existing entry. + MCDwarfLineEntry EndEntry = Entries.back(); + + // An end entry is just for marking the end of a sequence of code locations. + // It should not carry forward a LineStreamLabel from a previous special entry + // if Entries.back() happened to be such an entry. So here we clear + // LineStreamLabel. + EndEntry.LineStreamLabel = nullptr; + EndEntry.setEndLabel(EndLabel); + Entries.push_back(EndEntry); } // @@ -1227,7 +1241,7 @@ void MCGenDwarfInfo::Emit(MCStreamer *MCOS) { // a dwarf label. // void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS, - SourceMgr &SrcMgr, SMLoc &Loc) { + SourceMgr &SrcMgr, SMLoc &Loc) { // We won't create dwarf labels for temporary symbols. if (Symbol->isTemporary()) return; @@ -1295,7 +1309,7 @@ static unsigned getSizeForEncoding(MCStreamer &streamer, } static void emitFDESymbol(MCObjectStreamer &streamer, const MCSymbol &symbol, - unsigned symbolEncoding, bool isEH) { + unsigned symbolEncoding, bool isEH) { MCContext &context = streamer.getContext(); const MCAsmInfo *asmInfo = context.getAsmInfo(); const MCExpr *v = asmInfo->getExprForFDESymbol(&symbol, diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll new file mode 100644 index 0000000000000..553a05f12082e --- /dev/null +++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll @@ -0,0 +1,37 @@ +; RUN: llc -filetype=obj -emit-func-debug-line-table-offsets < %s -o %t_yes_off.o +; RUN: llc -filetype=obj < %s -o %t_no_off.o +; RUN: llvm-dwarfdump -v -all %t_no_off.o | FileCheck --check-prefix=CHECK-NO-OFF %s +; RUN: llvm-dwarfdump -v -all %t_yes_off.o | FileCheck --check-prefix=CHECK-YES-OFF %s + +; We don't need a line table for an empty function +; CHECK-NO-OFF-NOT: DW_LNE_set_address + +; CHECK-YES-OFF: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] ({{.*}}) +; CHECK-YES-OFF: Address +; CHECK-YES-OFF-NEXT: ------------------ +; CHECK-YES-OFF-NEXT: DW_LNE_set_address ({{.*}}) +; CHECK-YES-OFF-NEXT: DW_LNE_end_sequence +; CHECK-YES-OFF-NEXT: 0x0000000000000000 {{.*}} is_stmt end_sequence + +; IR generated by llvm-reduce from LTO repro +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define ptr @_my_test_function() !dbg !4 { +entry: + unreachable +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 21.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "repro_bug.cpp", directory: "/tmp/repro", checksumkind: CSK_MD5, checksum: "74e33e88b3108a4f94403da9fdb362f5") +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = distinct !DISubprogram(name: "east", linkageName: "_my_test_function", scope: !6, file: !5, line: 114, type: !8, scopeLine: 114, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, declaration: !9, retainedNodes: !2) +!5 = !DIFile(filename: "repro_bug.cpp", directory: "/tmp/repro", checksumkind: CSK_MD5, checksum: "74e33e88b3108a4f94403da9fdb362f5") +!6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "rectangle", file: !5, line: 103, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "shape", file: !5, line: 58, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !7, identifier: "_ZTS5shape") +!8 = distinct !DISubroutineType(types: !2) +!9 = !DISubprogram(name: "east", linkageName: "_my_test_function", scope: !6, file: !5, line: 114, type: !8, scopeLine: 114, containingType: !6, virtualIndex: 2, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual | DISPFlagOptimized)