Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -742,9 +742,13 @@ /// definitions as they would appear on a command line. /// \param IncludePath The path to the module map file. /// \param APINotesFile The path to an API notes file for this module. + /// \param File Source file of the module declaration. Used for + /// Fortran modules. \param LineNo Source line no. of the module + /// declaration. Used for Fortran modules. DIModule *createModule(DIScope *Scope, StringRef Name, - StringRef ConfigurationMacros, - StringRef IncludePath, StringRef APINotesFile = {}); + StringRef ConfigurationMacros, StringRef IncludePath, + StringRef APINotesFile = {}, DIFile *File = {}, + unsigned LineNo = 0); /// This creates a descriptor for a lexical block with a new file /// attached. This merely extends the existing Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2078,50 +2078,55 @@ } }; -/// A (clang) module that has been imported by the compile unit. -/// +/// Represents a module in the programming language, for example, a Clang +/// module, or a Fortran module. class DIModule : public DIScope { friend class LLVMContextImpl; friend class MDNode; + unsigned LineNo; - DIModule(LLVMContext &Context, StorageType Storage, ArrayRef Ops) - : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) {} + DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo, + ArrayRef Ops) + : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops), + LineNo(LineNo) {} ~DIModule() = default; static DIModule *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, StringRef IncludePath, - StringRef APINotesFile, StorageType Storage, + StringRef APINotesFile, DIFile *File, + unsigned LineNo, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, ConfigurationMacros), getCanonicalMDString(Context, IncludePath), - getCanonicalMDString(Context, APINotesFile), + getCanonicalMDString(Context, APINotesFile), File, LineNo, Storage, ShouldCreate); } static DIModule *getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *APINotesFile, - StorageType Storage, bool ShouldCreate = true); + Metadata *File, unsigned LineNo, StorageType Storage, + bool ShouldCreate = true); TempDIModule cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getConfigurationMacros(), getIncludePath(), - getAPINotesFile()); + getAPINotesFile(), getFile(), getLineNo()); } public: DEFINE_MDNODE_GET(DIModule, (DIScope * Scope, StringRef Name, StringRef ConfigurationMacros, StringRef IncludePath, - StringRef APINotesFile), + StringRef APINotesFile, DIFile *File, unsigned LineNo), (Scope, Name, ConfigurationMacros, IncludePath, - APINotesFile)) + APINotesFile, File, LineNo)) DEFINE_MDNODE_GET(DIModule, (Metadata * Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, - MDString *APINotesFile), + MDString *APINotesFile, Metadata *File, unsigned LineNo), (Scope, Name, ConfigurationMacros, IncludePath, - APINotesFile)) + APINotesFile, File, LineNo)) TempDIModule clone() const { return cloneImpl(); } @@ -2130,12 +2135,15 @@ StringRef getConfigurationMacros() const { return getStringOperand(2); } StringRef getIncludePath() const { return getStringOperand(3); } StringRef getAPINotesFile() const { return getStringOperand(4); } + DIFile *getFile() const { return cast_or_null(getRawFile()); } + unsigned getLineNo() const { return LineNo; } 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 *getRawAPINotesFile() const { return getOperandAs(4); } + Metadata *getRawFile() const { return getOperand(5); } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIModuleKind; Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -4828,20 +4828,23 @@ /// ParseDIModule: /// ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG", -/// includePath: "/usr/include", apinotes: "module.apinotes") +/// includePath: "/usr/include", apinotes: "module.apinotes", +/// file: !1, line: 4) 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(apinotes, MDStringField, ); + OPTIONAL(apinotes, MDStringField, ); \ + OPTIONAL(file, MDField, ); \ + OPTIONAL(line, LineField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = - GET_OR_DISTINCT(DIModule, (Context, scope.Val, name.Val, configMacros.Val, - includePath.Val, apinotes.Val)); + Result = GET_OR_DISTINCT(DIModule, + (Context, scope.Val, name.Val, configMacros.Val, + includePath.Val, apinotes.Val, file.Val, line.Val)); return false; } Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1418,7 +1418,7 @@ } case bitc::METADATA_MODULE: { - if (Record.size() < 5 || Record.size() > 7) + if (Record.size() < 5 || Record.size() > 8) return error("Invalid record"); IsDistinct = Record[0]; @@ -1426,7 +1426,8 @@ GET_OR_DISTINCT(DIModule, (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), - getMDString(Record[4]), getMDString(Record[5]))), + getMDString(Record[4]), getMDString(Record[5]), + getMDOrNull(Record[6]), Record[7])), NextMetadataNo); NextMetadataNo++; break; Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1785,6 +1785,7 @@ Record.push_back(N->isDistinct()); for (auto &I : N->operands()) Record.push_back(VE.getMetadataOrNullID(I)); + Record.push_back(N->getLineNo()); Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev); Record.clear(); Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1128,6 +1128,11 @@ addString(MDie, dwarf::DW_AT_LLVM_include_path, M->getIncludePath()); if (!M->getAPINotesFile().empty()) addString(MDie, dwarf::DW_AT_LLVM_apinotes, M->getAPINotesFile()); + if (M->getFile()) + addUInt(MDie, dwarf::DW_AT_decl_file, None, + getOrCreateSourceID(M->getFile())); + if (M->getLineNo()) + addUInt(MDie, dwarf::DW_AT_decl_line, None, M->getLineNo()); return &MDie; } Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -2092,6 +2092,8 @@ Printer.printString("configMacros", N->getConfigurationMacros()); Printer.printString("includePath", N->getIncludePath()); Printer.printString("apinotes", N->getAPINotesFile()); + Printer.printMetadata("file", N->getRawFile()); + Printer.printInt("line", N->getLineNo()); Out << ")"; } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -831,10 +831,11 @@ DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, - StringRef IncludePath, - StringRef APINotesFile) { + StringRef IncludePath, StringRef APINotesFile, + DIFile *File, unsigned LineNo) { return DIModule::get(VMContext, getNonCompileUnitScope(Scope), Name, - ConfigurationMacros, IncludePath, APINotesFile); + ConfigurationMacros, IncludePath, APINotesFile, File, + LineNo); } DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -720,13 +720,14 @@ DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *APINotesFile, + Metadata *File, unsigned LineNo, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP( - DIModule, (Scope, Name, ConfigurationMacros, IncludePath, APINotesFile)); - Metadata *Ops[] = {Scope, Name, ConfigurationMacros, IncludePath, - APINotesFile}; - DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIModule, Ops); + DEFINE_GETIMPL_LOOKUP(DIModule, (Scope, Name, ConfigurationMacros, + IncludePath, APINotesFile, File, LineNo)); + Metadata *Ops[] = {Scope, Name, ConfigurationMacros, + IncludePath, APINotesFile, File}; + DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops); } DITemplateTypeParameter * Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -820,16 +820,21 @@ MDString *ConfigurationMacros; MDString *IncludePath; MDString *APINotesFile; + Metadata *File; + unsigned LineNo; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, - MDString *IncludePath, MDString *APINotesFile) + MDString *IncludePath, MDString *APINotesFile, Metadata *File, + unsigned LineNo) : Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), - IncludePath(IncludePath), APINotesFile(APINotesFile) {} + IncludePath(IncludePath), APINotesFile(APINotesFile), File(File), + LineNo(LineNo) {} MDNodeKeyImpl(const DIModule *N) : Scope(N->getRawScope()), Name(N->getRawName()), ConfigurationMacros(N->getRawConfigurationMacros()), IncludePath(N->getRawIncludePath()), - APINotesFile(N->getRawAPINotesFile()) {} + APINotesFile(N->getRawAPINotesFile()), File(N->getRawFile()), + LineNo(N->getLineNo()) {} bool isKeyOf(const DIModule *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && Index: llvm/test/Assembler/dimodule.ll =================================================================== --- llvm/test/Assembler/dimodule.ll +++ llvm/test/Assembler/dimodule.ll @@ -14,5 +14,5 @@ !3 = !DIModule(scope: !0, name: "Module", configMacros: "") -; CHECK: !3 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes") -!4 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes") +; CHECK: !3 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes", file: !0, line: 1) +!4 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes", file: !0, line: 1) Index: llvm/test/Bitcode/DIModule-clang-module.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/DIModule-clang-module.ll @@ -0,0 +1,22 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +; CHECK: DIModule(scope: null, name: "DebugModule", configMacros: "-DMODULES=0", includePath: "/", apinotes: "m.apinotes") + +; ModuleID = 'DIModule-clang-module.ll' + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7} +!llvm.ident = !{!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_ObjC_plus_plus, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !3) +!1 = !DIFile(filename: "/test.cpp", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !5, file: !1, line: 5) +!5 = !DIModule(scope: null, name: "DebugModule", configMacros: "-DMODULES=0", includePath: "/", apinotes: "m.apinotes") +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{!"clang version 11.0.0"} Index: llvm/test/Bitcode/DIModule-fortran-module.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/DIModule-fortran-module.ll @@ -0,0 +1,34 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +; CHECK: DIModule(scope: !3, name: "dummy", file: !4, line: 2) + +; ModuleID = '/tmp/module-b198fa.ll' +source_filename = "/tmp/module-b198fa.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct_dummy_0_ = type <{ [4 x i8] }> + +@_dummy_0_ = common global %struct_dummy_0_ zeroinitializer, align 64, !dbg !0 + +; Function Attrs: noinline +define float @dummy_() #0 { +.L.entry: + ret float undef +} + +attributes #0 = { noinline "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" } + +!llvm.module.flags = !{!8, !9} +!llvm.dbg.cu = !{!3} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !4, type: !7, isLocal: false, isDefinition: true) +!2 = !DIModule(scope: !3, name: "dummy", file: !4, line: 2) +!3 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !4, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5) +!4 = !DIFile(filename: "module.f90", directory: "/fortran") +!5 = !{} +!6 = !{!0} +!7 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} Index: llvm/test/DebugInfo/X86/Fortran-DIModule.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/Fortran-DIModule.ll @@ -0,0 +1,44 @@ +; This test checks attributes of a Fortran module. +; RUN: %llc_dwarf %s -filetype=obj -o - | \ +; RUN: llvm-dwarfdump - | FileCheck %s + +; CHECK: DW_TAG_module +; CHECK-NEXT: DW_AT_name ("dummy") +; CHECK-NEXT: DW_AT_decl_file ("/fortran/module.f90") +; CHECK-NEXT: DW_AT_decl_line (2) + +; Generated from flang compiler, Fortran source to regenerate: +; module dummy +; integer :: foo +; end module dummy + +; ModuleID = '/tmp/module-b198fa.ll' +source_filename = "/tmp/module-b198fa.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct_dummy_0_ = type <{ [4 x i8] }> + +@_dummy_0_ = common global %struct_dummy_0_ zeroinitializer, align 64, !dbg !0 + +; Function Attrs: noinline +define float @dummy_() #0 { +.L.entry: + ret float undef +} + +attributes #0 = { noinline "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" } + +!llvm.module.flags = !{!8, !9} +!llvm.dbg.cu = !{!3} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !4, type: !7, isLocal: false, isDefinition: true) +!2 = !DIModule(scope: !3, name: "dummy", file: !4, line: 2) +!3 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !4, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5) +!4 = !DIFile(filename: "module.f90", directory: "/fortran") +!5 = !{} +!6 = !{!0} +!7 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} Index: llvm/unittests/IR/MetadataTest.cpp =================================================================== --- llvm/unittests/IR/MetadataTest.cpp +++ llvm/unittests/IR/MetadataTest.cpp @@ -2058,8 +2058,11 @@ StringRef ConfigMacro = "-DNDEBUG"; StringRef Includes = "-I."; StringRef APINotes = "/tmp/m.apinotes"; + DIFile *File = getFile(); + unsigned LineNo = {}; - auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes); + auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes, + File, LineNo); EXPECT_EQ(dwarf::DW_TAG_module, N->getTag()); EXPECT_EQ(Scope, N->getScope()); @@ -2067,18 +2070,20 @@ EXPECT_EQ(ConfigMacro, N->getConfigurationMacros()); EXPECT_EQ(Includes, N->getIncludePath()); EXPECT_EQ(APINotes, N->getAPINotesFile()); - EXPECT_EQ( - N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes)); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(LineNo, N->getLineNo()); + EXPECT_EQ(N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, + APINotes, File, LineNo)); EXPECT_NE(N, DIModule::get(Context, getFile(), Name, ConfigMacro, Includes, - APINotes)); + APINotes, File, LineNo)); EXPECT_NE(N, DIModule::get(Context, Scope, "other", ConfigMacro, Includes, - APINotes)); - EXPECT_NE(N, - DIModule::get(Context, Scope, Name, "other", Includes, APINotes)); - EXPECT_NE( - N, DIModule::get(Context, Scope, Name, ConfigMacro, "other", APINotes)); - EXPECT_NE( - N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, "other")); + APINotes, File, LineNo)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, "other", Includes, APINotes, + File, LineNo)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, ConfigMacro, "other", + APINotes, File, LineNo)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, + "other", File, LineNo)); TempDIModule Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));