Skip to content

[DebugInfo] Fully implement DWARF issue 180201.1 #149226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4783,9 +4783,13 @@ struct MDField : public MDFieldImpl<Metadata *> {
};

struct MDStringField : public MDFieldImpl<MDString *> {
bool AllowEmpty;
MDStringField(bool AllowEmpty = true)
: ImplTy(nullptr), AllowEmpty(AllowEmpty) {}
enum class EmptyIs {
Null, //< Allow empty input string, map to nullptr
Empty, //< Allow empty input string, map to an empty MDString
Error, //< Disallow empty string, map to an error
} EmptyIs;
MDStringField(enum EmptyIs EmptyIs = EmptyIs::Null)
: ImplTy(nullptr), EmptyIs(EmptyIs) {}
};

struct MDFieldList : public MDFieldImpl<SmallVector<Metadata *, 4>> {
Expand Down Expand Up @@ -5257,10 +5261,19 @@ bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDStringField &Result) {
if (parseStringConstant(S))
return true;

if (!Result.AllowEmpty && S.empty())
return error(ValueLoc, "'" + Name + "' cannot be empty");
if (S.empty()) {
switch (Result.EmptyIs) {
case MDStringField::EmptyIs::Null:
Result.assign(nullptr);
return false;
case MDStringField::EmptyIs::Empty:
break;
case MDStringField::EmptyIs::Error:
return error(ValueLoc, "'" + Name + "' cannot be empty");
}
}

Result.assign(S.empty() ? nullptr : MDString::get(Context, S));
Result.assign(MDString::get(Context, S));
return false;
}

Expand Down Expand Up @@ -5778,7 +5791,7 @@ bool LLParser::parseDIFile(MDNode *&Result, bool IsDistinct) {
REQUIRED(directory, MDStringField, ); \
OPTIONAL(checksumkind, ChecksumKindField, (DIFile::CSK_MD5)); \
OPTIONAL(checksum, MDStringField, ); \
OPTIONAL(source, MDStringField, );
OPTIONAL(source, MDStringField, (MDStringField::EmptyIs::Empty));
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

Expand Down Expand Up @@ -6062,7 +6075,7 @@ bool LLParser::parseDITemplateValueParameter(MDNode *&Result, bool IsDistinct) {
/// declaration: !4, align: 8)
bool LLParser::parseDIGlobalVariable(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
OPTIONAL(name, MDStringField, (/* AllowEmpty */ false)); \
OPTIONAL(name, MDStringField, (MDStringField::EmptyIs::Error)); \
OPTIONAL(scope, MDField, ); \
OPTIONAL(linkageName, MDStringField, ); \
OPTIONAL(file, MDField, ); \
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2398,8 +2398,9 @@ static void writeDIFile(raw_ostream &Out, const DIFile *N, AsmWriterContext &) {
// Print all values for checksum together, or not at all.
if (N->getChecksum())
Printer.printChecksum(*N->getChecksum());
Printer.printString("source", N->getSource().value_or(StringRef()),
/* ShouldSkipEmpty */ true);
if (N->getSource())
Printer.printString("source", *N->getSource(),
/* ShouldSkipEmpty */ false);
Out << ")";
}

Expand Down
11 changes: 9 additions & 2 deletions llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,17 @@ static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile,
StringRef(reinterpret_cast<const char *>(Cksum.data()), Cksum.size()));
}
if (HasAnySource) {
// From https://dwarfstd.org/issues/180201.1.html
// * The value is an empty null-terminated string if no source is available
StringRef Source = DwarfFile.Source.value_or(StringRef());
// * If the source is available but is an empty file then the value is a
// null-terminated single "\n".
if (DwarfFile.Source && DwarfFile.Source->empty())
Source = "\n";
if (LineStr)
LineStr->emitRef(MCOS, DwarfFile.Source.value_or(StringRef()));
LineStr->emitRef(MCOS, Source);
else {
MCOS->emitBytes(DwarfFile.Source.value_or(StringRef())); // Source and...
MCOS->emitBytes(Source); // Source and...
MCOS->emitBytes(StringRef("\0", 1)); // its null terminator.
}
}
Expand Down
12 changes: 12 additions & 0 deletions llvm/test/Assembler/difile-empty-source.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
; RUN: verify-uselistorder

; CHECK: !DIFile({{.*}}, source: "")

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}

!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, emissionKind: FullDebug)
!1 = !DIFile(filename: "-", directory: "/", checksumkind: CSK_MD5, checksum: "d41d8cd98f00b204e9800998ecf8427e", source: "")
!2 = !{i32 7, !"Dwarf Version", i32 5}
!3 = !{i32 2, !"Debug Info Version", i32 3}
58 changes: 44 additions & 14 deletions llvm/test/DebugInfo/Generic/mixed-source.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,66 @@

; CHECK: include_directories[ 0] = "dir"
; CHECK-NEXT: file_names[ 0]:
; CHECK-NEXT: name: "main.c"
; CHECK-NEXT: dir_index: 0
; CHECK-NOT: source:
; CHECK-NEXT: file_names[ 1]:
; CHECK-NEXT: name: "foo.c"
; CHECK-NEXT: dir_index: 0
; CHECK-NEXT: source: "void foo() { }\n"
; CHECK-NEXT: file_names[ 1]:
; CHECK-NEXT: name: "bar.h"
; CHECK-NEXT: file_names[ 2]:
; CHECK-NEXT: name: "newline.h"
; CHECK-NEXT: dir_index: 0
; CHECK-NEXT: source: "\n"
; CHECK-NEXT: file_names[ 3]:
; CHECK-NEXT: name: "empty.h"
; CHECK-NEXT: dir_index: 0
; CHECK-NEXT: source: "\n"
; CHECK-NEXT: file_names[ 4]:
; CHECK-NEXT: name: "absent.h"
; CHECK-NEXT: dir_index: 0
; CHECK-NOT: source:

; Test that DIFiles mixing source and no-source within a DICompileUnit works.

define dso_local void @foo() !dbg !5 {
define dso_local void @foo() !dbg !6 {
ret void, !dbg !7
}

define dso_local void @bar() !dbg !6 {
ret void, !dbg !8
define dso_local void @newline() !dbg !9 {
ret void, !dbg !10
}

!llvm.dbg.cu = !{!4}
define dso_local void @empty() !dbg !12 {
ret void, !dbg !13
}

define dso_local void @absent() !dbg !15 {
ret void, !dbg !16
}

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!0, !1}

!0 = !{i32 2, !"Dwarf Version", i32 5}
!1 = !{i32 2, !"Debug Info Version", i32 3}

!2 = !DIFile(filename: "foo.c", directory: "dir", source: "void foo() { }\0A")
!3 = !DIFile(filename: "bar.h", directory: "dir")
!2 = distinct !DICompileUnit(language: DW_LANG_C99, emissionKind: FullDebug, file: !4)
!3 = !DISubroutineType(types: !{})
!4 = !DIFile(filename: "main.c", directory: "dir")

!5 = !DIFile(filename: "foo.c", directory: "dir", source: "void foo() { }\0A")
!6 = distinct !DISubprogram(name: "foo", file: !5, line: 1, type: !3, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
!7 = !DILocation(line: 1, scope: !6)

!8 = !DIFile(filename: "newline.h", directory: "dir", source: "\0A")
!9 = distinct !DISubprogram(name: "newline", file: !8, line: 1, type: !3, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
!10 = !DILocation(line: 1, scope: !9)

!11 = !DIFile(filename: "empty.h", directory: "dir", source: "")
!12 = distinct !DISubprogram(name: "empty", file: !11, line: 1, type: !3, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
!13 = !DILocation(line: 1, scope: !12)

!4 = distinct !DICompileUnit(language: DW_LANG_C99, emissionKind: FullDebug, file: !2)
!5 = distinct !DISubprogram(name: "foo", file: !2, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !4)
!6 = distinct !DISubprogram(name: "bar", file: !3, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !4)
!7 = !DILocation(line: 1, scope: !5)
!8 = !DILocation(line: 1, scope: !6)
!9 = !DISubroutineType(types: !{})
!14 = !DIFile(filename: "absent.h", directory: "dir")
!15 = distinct !DISubprogram(name: "absent", file: !14, line: 1, type: !3, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
!16 = !DILocation(line: 1, scope: !15)
Loading