From dbfda63695272c2d12a6a61b18b52d3961d8e1a8 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 3 Nov 2016 19:42:02 +0000 Subject: [PATCH] Add DWARF debug info support for C++11 inline namespaces. This implements the DWARF 5 DW_AT_export_symbols feature: http://dwarfstd.org/ShowIssue.php?issue=141212.1 llvm-svn: 285959 --- llvm/include/llvm/Bitcode/LLVMBitCodes.h | 14 +++---- llvm/include/llvm/IR/DIBuilder.h | 3 +- llvm/include/llvm/IR/DebugInfoMetadata.h | 27 +++++++------ llvm/lib/AsmParser/LLParser.cpp | 5 ++- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 10 +++-- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 2 + llvm/lib/IR/AsmWriter.cpp | 1 + llvm/lib/IR/DIBuilder.cpp | 5 ++- llvm/lib/IR/DebugInfoMetadata.cpp | 7 ++-- llvm/lib/IR/LLVMContextImpl.h | 12 ++++-- llvm/test/Assembler/dinamespace.ll | 7 +++- llvm/test/Bitcode/DINamespace.ll | 23 +++++++++++ llvm/test/Bitcode/DINamespace.ll.bc | Bin 0 -> 1152 bytes llvm/test/DebugInfo/X86/inline-namespace.ll | 40 ++++++++++++++++++++ llvm/unittests/IR/MetadataTest.cpp | 20 +++++++--- 16 files changed, 135 insertions(+), 43 deletions(-) create mode 100644 llvm/test/Bitcode/DINamespace.ll create mode 100644 llvm/test/Bitcode/DINamespace.ll.bc create mode 100644 llvm/test/DebugInfo/X86/inline-namespace.ll diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 782bce554ea8..c8b0302b7541 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -239,13 +239,13 @@ enum MetadataCodes { METADATA_SUBPROGRAM = 21, // [distinct, ...] METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column] METADATA_LEXICAL_BLOCK_FILE = 23, //[distinct, scope, file, discriminator] - METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line] - METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] - METADATA_TEMPLATE_VALUE = 26, // [distinct, scope, name, type, value, ...] - METADATA_GLOBAL_VAR = 27, // [distinct, ...] - METADATA_LOCAL_VAR = 28, // [distinct, ...] - METADATA_EXPRESSION = 29, // [distinct, n x element] - METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] + METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line, exportSymbols] + METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] + METADATA_TEMPLATE_VALUE = 26, // [distinct, scope, name, type, value, ...] + METADATA_GLOBAL_VAR = 27, // [distinct, ...] + METADATA_LOCAL_VAR = 28, // [distinct, ...] + METADATA_EXPRESSION = 29, // [distinct, n x element] + METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] METADATA_IMPORTED_ENTITY = 31, // [distinct, tag, scope, entity, line, name] METADATA_MODULE = 32, // [distinct, scope, name, ...] METADATA_MACRO = 33, // [distinct, macinfo, line, name, value] diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index b40377863317..391bef69cf73 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -598,8 +598,9 @@ namespace llvm { /// \param Name Name of this namespace /// \param File Source file /// \param LineNo Line number + /// \param ExportSymbols True for C++ inline namespaces. DINamespace *createNameSpace(DIScope *Scope, StringRef Name, DIFile *File, - unsigned LineNo); + unsigned LineNo, bool ExportSymbols); /// This creates new descriptor for a module with the specified /// parent scope. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 15d12734301b..c6a2661dbf12 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1636,40 +1636,45 @@ class DINamespace : public DIScope { friend class MDNode; unsigned Line; + unsigned ExportSymbols : 1; DINamespace(LLVMContext &Context, StorageType Storage, unsigned Line, - ArrayRef Ops) + bool ExportSymbols, ArrayRef Ops) : DIScope(Context, DINamespaceKind, Storage, dwarf::DW_TAG_namespace, Ops), - Line(Line) {} + Line(Line), ExportSymbols(ExportSymbols) {} ~DINamespace() = default; static DINamespace *getImpl(LLVMContext &Context, DIScope *Scope, DIFile *File, StringRef Name, unsigned Line, - StorageType Storage, bool ShouldCreate = true) { + bool ExportSymbols, StorageType Storage, + bool ShouldCreate = true) { return getImpl(Context, Scope, File, getCanonicalMDString(Context, Name), - Line, Storage, ShouldCreate); + Line, ExportSymbols, Storage, ShouldCreate); } static DINamespace *getImpl(LLVMContext &Context, Metadata *Scope, Metadata *File, MDString *Name, unsigned Line, - StorageType Storage, bool ShouldCreate = true); + bool ExportSymbols, StorageType Storage, + bool ShouldCreate = true); TempDINamespace cloneImpl() const { return getTemporary(getContext(), getScope(), getFile(), getName(), - getLine()); + getLine(), getExportSymbols()); } public: DEFINE_MDNODE_GET(DINamespace, (DIScope * Scope, DIFile *File, StringRef Name, - unsigned Line), - (Scope, File, Name, Line)) - DEFINE_MDNODE_GET(DINamespace, (Metadata * Scope, Metadata *File, - MDString *Name, unsigned Line), - (Scope, File, Name, Line)) + unsigned Line, bool ExportSymbols), + (Scope, File, Name, Line, ExportSymbols)) + DEFINE_MDNODE_GET(DINamespace, + (Metadata * Scope, Metadata *File, MDString *Name, + unsigned Line, bool ExportSymbols), + (Scope, File, Name, Line, ExportSymbols)) TempDINamespace clone() const { return cloneImpl(); } unsigned getLine() const { return Line; } + bool getExportSymbols() const { return ExportSymbols; } DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(2); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 961ae65425b8..2b8d2f810119 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4092,12 +4092,13 @@ bool LLParser::ParseDINamespace(MDNode *&Result, bool IsDistinct) { REQUIRED(scope, MDField, ); \ OPTIONAL(file, MDField, ); \ OPTIONAL(name, MDStringField, ); \ - OPTIONAL(line, LineField, ); + OPTIONAL(line, LineField, ); \ + OPTIONAL(exportSymbols, MDBoolField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS Result = GET_OR_DISTINCT(DINamespace, - (Context, scope.Val, file.Val, name.Val, line.Val)); + (Context, scope.Val, file.Val, name.Val, line.Val, exportSymbols.Val)); return false; } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 954d482c5a99..7cdeb01a28dc 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2628,11 +2628,13 @@ std::error_code BitcodeReader::parseMetadata(bool ModuleLevel) { if (Record.size() != 5) return error("Invalid record"); - IsDistinct = Record[0]; + IsDistinct = Record[0] & 1; + bool ExportSymbols = Record[0] & 2; MetadataList.assignValue( - GET_OR_DISTINCT(DINamespace, (Context, getMDOrNull(Record[1]), - getMDOrNull(Record[2]), - getMDString(Record[3]), Record[4])), + GET_OR_DISTINCT(DINamespace, + (Context, getMDOrNull(Record[1]), + getMDOrNull(Record[2]), getMDString(Record[3]), + Record[4], ExportSymbols)), NextMetadataNo++); break; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index ac1c18b49a7f..997dcdb9b0b4 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1627,7 +1627,7 @@ void ModuleBitcodeWriter::writeDILexicalBlockFile( void ModuleBitcodeWriter::writeDINamespace(const DINamespace *N, SmallVectorImpl &Record, unsigned Abbrev) { - Record.push_back(N->isDistinct()); + Record.push_back(N->isDistinct() | N->getExportSymbols() << 1); Record.push_back(VE.getMetadataOrNullID(N->getScope())); Record.push_back(VE.getMetadataOrNullID(N->getFile())); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 2dcb616a67f7..a49518a378f8 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1083,6 +1083,8 @@ DIE *DwarfUnit::getOrCreateNameSpace(const DINamespace *NS) { DD->addAccelNamespace(Name, NDie); addGlobalName(Name, NDie, NS->getScope()); addSourceLine(NDie, NS); + if (NS->getExportSymbols()) + addFlag(NDie, dwarf::DW_AT_export_symbols); return &NDie; } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index ea00baf3d97c..f93739d14c71 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1740,6 +1740,7 @@ static void writeDINamespace(raw_ostream &Out, const DINamespace *N, Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false); Printer.printMetadata("file", N->getRawFile()); Printer.printInt("line", N->getLine()); + Printer.printBool("exportSymbols", N->getExportSymbols(), false); Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 741a3a27f136..aa67da2a3e0d 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -685,9 +685,10 @@ DISubprogram *DIBuilder::createMethod(DIScope *Context, StringRef Name, } DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, - DIFile *File, unsigned LineNo) { + DIFile *File, unsigned LineNo, + bool ExportSymbols) { return DINamespace::get(VMContext, getNonCompileUnitScope(Scope), File, Name, - LineNo); + LineNo, ExportSymbols); } DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index ae75f80b827f..278eb8989664 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -471,11 +471,12 @@ DILexicalBlockFile *DILexicalBlockFile::getImpl(LLVMContext &Context, DINamespace *DINamespace::getImpl(LLVMContext &Context, Metadata *Scope, Metadata *File, MDString *Name, unsigned Line, - StorageType Storage, bool ShouldCreate) { + bool ExportSymbols, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DINamespace, (Scope, File, Name, Line)); + DEFINE_GETIMPL_LOOKUP(DINamespace, (Scope, File, Name, Line, ExportSymbols)); Metadata *Ops[] = {File, Scope, Name}; - DEFINE_GETIMPL_STORE(DINamespace, (Line), Ops); + DEFINE_GETIMPL_STORE(DINamespace, (Line, ExportSymbols), Ops); } DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index e796f091f197..20f00e2ac434 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -674,16 +674,20 @@ template <> struct MDNodeKeyImpl { Metadata *File; MDString *Name; unsigned Line; + bool ExportSymbols; - MDNodeKeyImpl(Metadata *Scope, Metadata *File, MDString *Name, unsigned Line) - : Scope(Scope), File(File), Name(Name), Line(Line) {} + MDNodeKeyImpl(Metadata *Scope, Metadata *File, MDString *Name, unsigned Line, + bool ExportSymbols) + : Scope(Scope), File(File), Name(Name), Line(Line), + ExportSymbols(ExportSymbols) {} MDNodeKeyImpl(const DINamespace *N) : Scope(N->getRawScope()), File(N->getRawFile()), Name(N->getRawName()), - Line(N->getLine()) {} + Line(N->getLine()), ExportSymbols(N->getExportSymbols()) {} bool isKeyOf(const DINamespace *RHS) const { return Scope == RHS->getRawScope() && File == RHS->getRawFile() && - Name == RHS->getRawName() && Line == RHS->getLine(); + Name == RHS->getRawName() && Line == RHS->getLine() && + ExportSymbols == RHS->getExportSymbols(); } unsigned getHashValue() const { return hash_combine(Scope, File, Name, Line); diff --git a/llvm/test/Assembler/dinamespace.ll b/llvm/test/Assembler/dinamespace.ll index 5d8b6b3fa7d7..346fcfb11117 100644 --- a/llvm/test/Assembler/dinamespace.ll +++ b/llvm/test/Assembler/dinamespace.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !1, !2, !3, !4, !4} -!named = !{!0, !1, !2, !3, !4, !5} +; CHECK: !named = !{!0, !1, !2, !3, !4, !4, !4, !5} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7} !0 = !DIFile(filename: "file.cpp", directory: "/path/to/dir") !1 = distinct !{} @@ -14,3 +14,6 @@ ; CHECK: !4 = !DINamespace(scope: !0) !4 = !DINamespace(name: "", scope: !0, file: null, line: 0) !5 = !DINamespace(scope: !0) +!6 = !DINamespace(scope: !0, exportSymbols: false) +; CHECK: !5 = !DINamespace(scope: !0, exportSymbols: true) +!7 = !DINamespace(name: "", scope: !0, exportSymbols: true) diff --git a/llvm/test/Bitcode/DINamespace.ll b/llvm/test/Bitcode/DINamespace.ll new file mode 100644 index 000000000000..2807cb02d3dd --- /dev/null +++ b/llvm/test/Bitcode/DINamespace.ll @@ -0,0 +1,23 @@ +; RUN: llvm-dis %s.bc -o - | FileCheck %s +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + +@_ZN1N1iE = global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DIGlobalVariable(name: "i", linkageName: "_ZN1N1iE", scope: !1, file: !2, line: 2, type: !3, isLocal: false, isDefinition: true) +; Test bitcode upgrade for DINamespace without an exportSymbols field. +; CHECK: !DINamespace(name: "N", scope: null, file: !{{[0-9]+}}, line: 1) +!1 = !DINamespace(name: "N", scope: null, file: !2, line: 1) +!2 = !DIFile(filename: "dinamespace.cpp", directory: "/") +!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!4 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "clang version 4.0.0 (trunk 283228) (llvm/trunk 283225)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, globals: !6) +!5 = !{} +!6 = !{!0} +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"clang version 4.0.0 (trunk 283228) (llvm/trunk 283225)"} diff --git a/llvm/test/Bitcode/DINamespace.ll.bc b/llvm/test/Bitcode/DINamespace.ll.bc new file mode 100644 index 0000000000000000000000000000000000000000..90ccb8c783a0bff70c3661d6caecb190419f491a GIT binary patch literal 1152 zcmYjRZ){ps6u~j);mI8@S2mk~?V5etS4pbyo{q~Q?UVQC>TvR}~P6~ib z0DxqY1Qp1p8VQ`JyVz0?c2>$wmP>-9be{-UX@%##EZ$mSza+6cPh35RhO#`Ij%0LLh~(F{DB!puy<%wvby#BRTf z7+fO8OT-{g#B6Zf4Wmnyn=E9qaEOHQrOIs};z3x~;Px7Xw_!onjmA+M`zbpUZi zZ(Z`cM{UMCkBpvAj=lTA_eSqsRrsUdN~P;t-fR1sa77FUpiqJML0kfpHX~J4Ir;Ri z`u3Yb+AGZB;+*uQa@ydE5`Z_+-hi{}g*A0RA!ts~=43u?XW>{J4rhj>n?Ux5oOr?# z4N|*yeok{crw&k}9kWDD5o<2c&1tN;7*9tTcm{`K9UQ~JaR!UUIfmp^#VTTpC)Oxg zn3AoRh?0wFkS}Ofb?RlEX5OO>Q0J^S64oW!@(p(MM&f7^vldH=m>ZrMfQJXT2+}Oa z@Eqetl)~6k5pp}qa;I=^NXbPq+*oGfh3yit{ebv$me`^&Zy~4N$f=7vdc~t&)TtLH zG>e|fdpvC^(3Z@OzMeNv(dHCpoyr?g(7z_FKVjCHy!2L(V|uv=lZXz$xSNYAxoDPC z-R_ZX1KDF2vB4ATHrX0UY@sShy=G-jJKv(ct5dH`XjdMnH`X-23$y`cw|Ry>@@c|a zbnSgsh?^UY!+56K`Gl7t1^^gCytgCXYugKa_km((xfd_HVGBiGm@1!r!LVo0Kg@Xg z{DwY;G4_Q#;eImaj|>M-hsj0*WuQoXG%^x?n>3jlOeXVwQXdM%295v24(;y>2E)-) zZ*(2(Iv8wqjCvvg^7VgQIQ-s`ezG$hIQ=i;>ZD1hKjsgCYN0Jdg1k^b*5kG-gS)=` zC6yH8!2PO1{sT%)-T^29kV~IuZOb5pf94SZhhydzD9i$k(l<#Z^C9Jj)AuR!;#Hlp zaZe^|C?{s{dHW50BR!K}RMlL5>+5tK7TmcQxWn} zfW^K-9F;!?i8!K1J%{7HOonbot(&1OOZmx7_08Pwhb`ri+|+3v>NKl!8ZblxfMy@O kLda`getTag()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(File, N->getFile()); EXPECT_EQ(Name, N->getName()); EXPECT_EQ(Line, N->getLine()); - EXPECT_EQ(N, DINamespace::get(Context, Scope, File, Name, Line)); + EXPECT_EQ(N, + DINamespace::get(Context, Scope, File, Name, Line, ExportSymbols)); - EXPECT_NE(N, DINamespace::get(Context, getFile(), File, Name, Line)); - EXPECT_NE(N, DINamespace::get(Context, Scope, getFile(), Name, Line)); - EXPECT_NE(N, DINamespace::get(Context, Scope, File, "other", Line)); - EXPECT_NE(N, DINamespace::get(Context, Scope, File, Name, Line + 1)); + EXPECT_NE(N, + DINamespace::get(Context, getFile(), File, Name, Line, ExportSymbols)); + EXPECT_NE(N, + DINamespace::get(Context, Scope, getFile(), Name, Line, ExportSymbols)); + EXPECT_NE(N, + DINamespace::get(Context, Scope, File, "other", Line, ExportSymbols)); + EXPECT_NE(N, + DINamespace::get(Context, Scope, File, Name, Line + 1, ExportSymbols)); + EXPECT_NE(N, + DINamespace::get(Context, Scope, File, Name, Line, !ExportSymbols)); TempDINamespace Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));