Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -168,6 +168,7 @@ METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name] METADATA_EXTERNAL_TYPE_REF=32,// [distinct, tag, file, uid] + METADATA_MODULE=33, // [distinct, scope, name, ...] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -573,6 +573,20 @@ DINamespace *createNameSpace(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo); + /// createModule - This creates new descriptor for a module + /// with the specified parent scope. + /// @param Scope Parent scope + /// @param Name Name of this module + /// @param ConfigurationMacros + /// A space-separated shell-quoted list of -D macro + /// definitions as they would appear on a command line. + /// @param IncludePath The path to the module map file. + /// @param ISysRoot The clang system root (value of -isysroot). + DIModule *createModule(DIScope *Scope, StringRef Name, + StringRef ConfigurationMacros, + StringRef IncludePath, + StringRef ISysRoot); + /// createLexicalBlockFile - This creates a descriptor for a lexical /// block with a new file attached. This merely extends the existing /// lexical block as it crosses a file. @@ -605,6 +619,13 @@ DIImportedEntity *createImportedModule(DIScope *Context, DIImportedEntity *NS, unsigned Line); + /// \brief Create a descriptor for an imported module. + /// @param Context The scope this module is imported into + /// @param M The module being imported here + /// @param Line Line number + DIImportedEntity *createImportedModule(DIScope *Context, DIModule *M, + unsigned Line); + /// \brief Create a descriptor for an imported function. /// @param Context The scope this module is imported into /// @param Decl The declaration (or definition) of a function, type, or Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -219,6 +219,7 @@ case DILocalVariableKind: case DIObjCPropertyKind: case DIImportedEntityKind: + case DIModuleKind: return true; } } @@ -445,6 +446,7 @@ case DILexicalBlockKind: case DILexicalBlockFileKind: case DINamespaceKind: + case DIModuleKind: return true; } } @@ -1669,6 +1671,66 @@ } }; +/// \brief A (clang) module that has been imported by the compile unit. +/// +class DIModule : public DIScope { + friend class LLVMContextImpl; + friend class MDNode; + + DIModule(LLVMContext &Context, StorageType Storage, ArrayRef Ops) + : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) {} + ~DIModule() {} + + static DIModule *getImpl(LLVMContext &Context, DIScope *Scope, + StringRef Name, StringRef ConfigurationMacros, + StringRef IncludePath, StringRef ISysRoot, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Scope, getCanonicalMDString(Context, Name), + getCanonicalMDString(Context, ConfigurationMacros), + getCanonicalMDString(Context, IncludePath), + getCanonicalMDString(Context, ISysRoot), + Storage, ShouldCreate); + } + static DIModule *getImpl(LLVMContext &Context, Metadata *Scope, + MDString *Name, MDString *ConfigurationMacros, + MDString *IncludePath, MDString *ISysRoot, + StorageType Storage, bool ShouldCreate = true); + + TempDIModule cloneImpl() const { + return getTemporary(getContext(), getScope(), getName(), + getConfigurationMacros(), getIncludePath(), + getISysRoot()); + } + +public: + DEFINE_MDNODE_GET(DIModule, (DIScope *Scope, StringRef Name, + StringRef ConfigurationMacros, StringRef IncludePath, + StringRef ISysRoot), + (Scope, Name, ConfigurationMacros, IncludePath, ISysRoot)) + DEFINE_MDNODE_GET(DIModule, + (Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, + MDString *IncludePath, MDString *ISysRoot), + (Scope, Name, ConfigurationMacros, IncludePath, ISysRoot)) + + TempDIModule clone() const { return cloneImpl(); } + + DIScope *getScope() const { return cast_or_null(getRawScope()); } + StringRef getName() const { return getStringOperand(1); } + StringRef getConfigurationMacros() const { return getStringOperand(2); } + StringRef getIncludePath() const { return getStringOperand(3); } + StringRef getISysRoot() const { return getStringOperand(4); } + + Metadata *getRawScope() const { return getOperand(0); } + MDString *getRawName() const { return getOperandAs(1); } + MDString *getRawConfigurationMacros() const { return getOperandAs(2); } + MDString *getRawIncludePath() const { return getOperandAs(3); } + MDString *getRawISysRoot() const { return getOperandAs(4); } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIModuleKind; + } +}; + /// \brief Base class for template parameters. class DITemplateParameter : public DINode { protected: Index: include/llvm/IR/Metadata.h =================================================================== --- include/llvm/IR/Metadata.h +++ include/llvm/IR/Metadata.h @@ -74,6 +74,7 @@ DILexicalBlockKind, DILexicalBlockFileKind, DINamespaceKind, + DIModuleKind, DITemplateTypeParameterKind, DITemplateValueParameterKind, DIGlobalVariableKind, Index: include/llvm/IR/Metadata.def =================================================================== --- include/llvm/IR/Metadata.def +++ include/llvm/IR/Metadata.def @@ -83,6 +83,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF(DILexicalBlock) HANDLE_SPECIALIZED_MDNODE_LEAF(DILexicalBlockFile) HANDLE_SPECIALIZED_MDNODE_LEAF(DINamespace) +HANDLE_SPECIALIZED_MDNODE_LEAF(DIModule) HANDLE_SPECIALIZED_MDNODE_BRANCH(DITemplateParameter) HANDLE_SPECIALIZED_MDNODE_LEAF(DITemplateTypeParameter) HANDLE_SPECIALIZED_MDNODE_LEAF(DITemplateValueParameter) Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -3678,6 +3678,24 @@ return false; } +/// ParseDIModule: +/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG", +/// includePath: "/usr/include", isysroot: "/") +bool LLParser::ParseDIModule(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(scope, MDField, ); \ + REQUIRED(name, MDStringField, ); \ + OPTIONAL(configMacros, MDStringField, ); \ + OPTIONAL(includePath, MDStringField, ); \ + OPTIONAL(isysroot, MDStringField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DIModule, (Context, scope.Val, name.Val, + configMacros.Val, includePath.Val, isysroot.Val)); + return false; +} + /// ParseDITemplateTypeParameter: /// ::= !DITemplateTypeParameter(name: "Ty", type: !1) bool LLParser::ParseDITemplateTypeParameter(MDNode *&Result, bool IsDistinct) { Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1835,6 +1835,20 @@ NextMDValueNo++); break; } + + case bitc::METADATA_MODULE: { + if (Record.size() != 6) + return Error("Invalid record"); + + MDValueList.AssignValue( + GET_OR_DISTINCT(DIModule, Record[0], + (Context, getMDOrNull(Record[1]), + getMDString(Record[2]), getMDString(Record[3]), + getMDString(Record[4]), getMDString(Record[5]))), + NextMDValueNo++); + break; + } + case bitc::METADATA_FILE: { if (Record.size() != 3) return Error("Invalid record"); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1040,6 +1040,17 @@ Record.clear(); } +static void WriteDIModule(const DIModule *N, const ValueEnumerator &VE, + BitstreamWriter &Stream, + SmallVectorImpl &Record, unsigned Abbrev) { + Record.push_back(N->isDistinct()); + for (auto &I : N->operands()) + Record.push_back(VE.getMetadataOrNullID(I)); + + Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev); + Record.clear(); +} + static void WriteDITemplateTypeParameter(const DITemplateTypeParameter *N, const ValueEnumerator &VE, BitstreamWriter &Stream, Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1704,6 +1704,20 @@ Out << ")"; } +static void writeDIModule(raw_ostream &Out, const DIModule *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DIModule("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false); + Printer.printString("name", N->getName()); + Printer.printString("configMacros", N->getConfigurationMacros()); + Printer.printString("includePath", N->getIncludePath()); + Printer.printString("isysroot", N->getISysRoot()); + Out << ")"; +} + + static void writeDITemplateTypeParameter(raw_ostream &Out, const DITemplateTypeParameter *N, TypePrinting *TypePrinter, Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -184,6 +184,12 @@ Context, NS, Line, StringRef(), AllImportedModules); } +DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, DIModule *M, + unsigned Line) { + return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module, + Context, M, Line, StringRef(), AllImportedModules); +} + DIImportedEntity *DIBuilder::createImportedDeclaration(DIScope *Context, DINode *Decl, unsigned Line, @@ -705,6 +711,14 @@ LineNo); } +DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, + StringRef ConfigurationMacros, + StringRef IncludePath, + StringRef ISysRoot) { + return DIModule::get(VMContext, getNonCompileUnitScope(Scope), Name, + ConfigurationMacros, IncludePath, ISysRoot); +} + DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, DIFile *File, unsigned Discriminator) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -150,6 +150,8 @@ return SP->getName(); if (auto *NS = dyn_cast(this)) return NS->getName(); + if (auto *M = dyn_cast(this)) + return M->getName(); assert((isa(this) || isa(this) || isa(this)) && "Unhandled type of scope."); @@ -422,6 +424,18 @@ DEFINE_GETIMPL_STORE(DINamespace, (Line), Ops); } +DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, + MDString *Name, MDString *ConfigurationMacros, + MDString *IncludePath, MDString *ISysRoot, + StorageType Storage, bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIModule, + (Scope, getString(Name), getString(ConfigurationMacros), + getString(IncludePath), getString(ISysRoot))); + Metadata *Ops[] = {Scope, Name, ConfigurationMacros, IncludePath, ISysRoot}; + DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIModule, Ops); +} + DITemplateTypeParameter *DITemplateTypeParameter::getImpl(LLVMContext &Context, MDString *Name, Metadata *Type, Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -669,6 +669,35 @@ } }; +template <> struct MDNodeKeyImpl { + Metadata *Scope; + StringRef Name; + StringRef ConfigurationMacros; + StringRef IncludePath; + StringRef ISysRoot; + MDNodeKeyImpl(Metadata *Scope, StringRef Name, + StringRef ConfigurationMacros, + StringRef IncludePath, + StringRef ISysRoot) + : Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), + IncludePath(IncludePath), ISysRoot(ISysRoot) {} + MDNodeKeyImpl(const DIModule *N) + : Scope(N->getRawScope()), Name(N->getName()), + ConfigurationMacros(N->getConfigurationMacros()), + IncludePath(N->getIncludePath()), ISysRoot(N->getISysRoot()) {} + + bool isKeyOf(const DIModule *RHS) const { + return Scope == RHS->getRawScope() && Name == RHS->getName() && + ConfigurationMacros == RHS->getConfigurationMacros() && + IncludePath == RHS->getIncludePath() && + ISysRoot == RHS->getISysRoot(); + } + unsigned getHashValue() const { + return hash_combine(Scope, Name, + ConfigurationMacros, IncludePath, ISysRoot); + } +}; + template <> struct MDNodeKeyImpl { StringRef Name; Metadata *Type; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1024,6 +1024,10 @@ Assert(isa(S), "invalid scope ref", &N, S); } +void Verifier::visitDIModule(const DIModule &N) { + Assert(!N.getName().empty(), "anonymous module", &N); +} + void Verifier::visitDITemplateParameter(const DITemplateParameter &N) { Assert(isTypeRef(N, N.getType()), "invalid type ref", &N, N.getType()); } Index: test/Assembler/dimodule.ll =================================================================== --- /dev/null +++ test/Assembler/dimodule.ll @@ -0,0 +1,15 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; CHECK: !named = !{!0, !1, !2, !1} +!named = !{!0, !1, !2, !3} + +!0 = distinct !{} + +; CHECK: !1 = !DIModule(scope: !0, name: "Module") +!1 = !DIModule(scope: !0, name: "Module") + +; CHECK: !2 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", isysroot: "/") +!2 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", isysroot: "/") + +!3 = !DIModule(scope: !0, name: "Module", configMacros: "")