/// 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 number 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 = nullptr,
+ unsigned LineNo = 0);
/// This creates a descriptor for a lexical block with a new file
/// attached. This merely extends the existing
}
};
-/// 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<Metadata *> Ops)
- : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) {}
+ DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo,
+ ArrayRef<Metadata *> 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,
+ static DIModule *getImpl(LLVMContext &Context, DIFile *File, DIScope *Scope,
+ StringRef Name, StringRef ConfigurationMacros,
+ StringRef IncludePath, StringRef APINotesFile,
+ unsigned LineNo, StorageType Storage,
bool ShouldCreate = true) {
- return getImpl(Context, Scope, getCanonicalMDString(Context, Name),
+ return getImpl(Context, File, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, ConfigurationMacros),
getCanonicalMDString(Context, IncludePath),
- getCanonicalMDString(Context, APINotesFile),
- Storage, ShouldCreate);
+ getCanonicalMDString(Context, APINotesFile), LineNo, Storage,
+ ShouldCreate);
}
- static DIModule *getImpl(LLVMContext &Context, Metadata *Scope,
- MDString *Name, MDString *ConfigurationMacros,
- MDString *IncludePath, MDString *APINotesFile,
+ static DIModule *getImpl(LLVMContext &Context, Metadata *File,
+ Metadata *Scope, MDString *Name,
+ MDString *ConfigurationMacros, MDString *IncludePath,
+ MDString *APINotesFile, unsigned LineNo,
StorageType Storage, bool ShouldCreate = true);
TempDIModule cloneImpl() const {
- return getTemporary(getContext(), getScope(), getName(),
+ return getTemporary(getContext(), getFile(), getScope(), getName(),
getConfigurationMacros(), getIncludePath(),
- getAPINotesFile());
+ getAPINotesFile(), getLineNo());
}
public:
DEFINE_MDNODE_GET(DIModule,
- (DIScope * Scope, StringRef Name,
+ (DIFile * File, DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef IncludePath,
- StringRef APINotesFile),
- (Scope, Name, ConfigurationMacros, IncludePath,
- APINotesFile))
+ StringRef APINotesFile, unsigned LineNo),
+ (File, Scope, Name, ConfigurationMacros, IncludePath,
+ APINotesFile, LineNo))
DEFINE_MDNODE_GET(DIModule,
- (Metadata * Scope, MDString *Name,
+ (Metadata * File, Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros, MDString *IncludePath,
- MDString *APINotesFile),
- (Scope, Name, ConfigurationMacros, IncludePath,
- APINotesFile))
+ MDString *APINotesFile, unsigned LineNo),
+ (File, Scope, Name, ConfigurationMacros, IncludePath,
+ APINotesFile, LineNo))
TempDIModule clone() const { return cloneImpl(); }
DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); }
- StringRef getName() const { return getStringOperand(1); }
- StringRef getConfigurationMacros() const { return getStringOperand(2); }
- StringRef getIncludePath() const { return getStringOperand(3); }
- StringRef getAPINotesFile() const { return getStringOperand(4); }
+ StringRef getName() const { return getStringOperand(2); }
+ StringRef getConfigurationMacros() const { return getStringOperand(3); }
+ StringRef getIncludePath() const { return getStringOperand(4); }
+ StringRef getAPINotesFile() const { return getStringOperand(5); }
+ unsigned getLineNo() const { return LineNo; }
- Metadata *getRawScope() const { return getOperand(0); }
- MDString *getRawName() const { return getOperandAs<MDString>(1); }
- MDString *getRawConfigurationMacros() const { return getOperandAs<MDString>(2); }
- MDString *getRawIncludePath() const { return getOperandAs<MDString>(3); }
- MDString *getRawAPINotesFile() const { return getOperandAs<MDString>(4); }
+ Metadata *getRawScope() const { return getOperand(1); }
+ MDString *getRawName() const { return getOperandAs<MDString>(2); }
+ MDString *getRawConfigurationMacros() const {
+ return getOperandAs<MDString>(3);
+ }
+ MDString *getRawIncludePath() const { return getOperandAs<MDString>(4); }
+ MDString *getRawAPINotesFile() const { return getOperandAs<MDString>(5); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIModuleKind;
}
/// ParseDIModule:
-/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG",
-/// includePath: "/usr/include", apinotes: "module.apinotes")
+/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros:
+/// "-DNDEBUG", 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, file.Val, scope.Val, name.Val,
+ configMacros.Val, includePath.Val,
+ apinotes.Val, line.Val));
return false;
}
}
case bitc::METADATA_MODULE: {
- if (Record.size() < 5 || Record.size() > 7)
+ if (Record.size() < 5 || Record.size() > 8)
return error("Invalid record");
+ unsigned Offset = Record.size() >= 7 ? 2 : 1;
IsDistinct = Record[0];
MetadataList.assignValue(
- GET_OR_DISTINCT(DIModule,
- (Context, getMDOrNull(Record[1]),
- getMDString(Record[2]), getMDString(Record[3]),
- getMDString(Record[4]), getMDString(Record[5]))),
+ GET_OR_DISTINCT(
+ DIModule,
+ (Context, Record.size() >= 7 ? getMDOrNull(Record[1]) : nullptr,
+ getMDOrNull(Record[0 + Offset]), getMDString(Record[1 + Offset]),
+ getMDString(Record[2 + Offset]), getMDString(Record[3 + Offset]),
+ getMDString(Record[4 + Offset]),
+ Record.size() <= 7 ? 0 : Record[7])),
NextMetadataNo);
NextMetadataNo++;
break;
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();
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;
}
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 << ")";
}
DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros,
- StringRef IncludePath,
- StringRef APINotesFile) {
- return DIModule::get(VMContext, getNonCompileUnitScope(Scope), Name,
- ConfigurationMacros, IncludePath, APINotesFile);
+ StringRef IncludePath, StringRef APINotesFile,
+ DIFile *File, unsigned LineNo) {
+ return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name,
+ ConfigurationMacros, IncludePath, APINotesFile, LineNo);
}
DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope,
DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops);
}
-DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope,
- MDString *Name, MDString *ConfigurationMacros,
+DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *File,
+ Metadata *Scope, MDString *Name,
+ MDString *ConfigurationMacros,
MDString *IncludePath, MDString *APINotesFile,
- StorageType Storage, bool ShouldCreate) {
+ 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, (File, Scope, Name, ConfigurationMacros,
+ IncludePath, APINotesFile, LineNo));
+ Metadata *Ops[] = {File, Scope, Name, ConfigurationMacros,
+ IncludePath, APINotesFile};
+ DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops);
}
DITemplateTypeParameter *
};
template <> struct MDNodeKeyImpl<DIModule> {
+ Metadata *File;
Metadata *Scope;
MDString *Name;
MDString *ConfigurationMacros;
MDString *IncludePath;
MDString *APINotesFile;
+ unsigned LineNo;
- MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *ConfigurationMacros,
- MDString *IncludePath, MDString *APINotesFile)
- : Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros),
- IncludePath(IncludePath), APINotesFile(APINotesFile) {}
+ MDNodeKeyImpl(Metadata *File, Metadata *Scope, MDString *Name,
+ MDString *ConfigurationMacros, MDString *IncludePath,
+ MDString *APINotesFile, unsigned LineNo)
+ : File(File), Scope(Scope), Name(Name),
+ ConfigurationMacros(ConfigurationMacros), IncludePath(IncludePath),
+ APINotesFile(APINotesFile), LineNo(LineNo) {}
MDNodeKeyImpl(const DIModule *N)
- : Scope(N->getRawScope()), Name(N->getRawName()),
+ : File(N->getRawFile()), Scope(N->getRawScope()), Name(N->getRawName()),
ConfigurationMacros(N->getRawConfigurationMacros()),
IncludePath(N->getRawIncludePath()),
- APINotesFile(N->getRawAPINotesFile()) {}
+ APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()) {}
bool isKeyOf(const DIModule *RHS) const {
return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
ConfigurationMacros == RHS->getRawConfigurationMacros() &&
IncludePath == RHS->getRawIncludePath() &&
- APINotesFile == RHS->getRawAPINotesFile();
+ APINotesFile == RHS->getRawAPINotesFile() &&
+ File == RHS->getRawFile() && LineNo == RHS->getLineNo();
}
unsigned getHashValue() const {
!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)
--- /dev/null
+; 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"}
--- /dev/null
+; RUN: llvm-dis -o - %s.bc | FileCheck %s
+
+; CHECK: DIModule(scope: !4, name: "dummy", file: !3, line: 2)
+
+; ModuleID = 'DIModule-fortran-module.bc'
+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 = !{!4}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, type: !7, isLocal: false, isDefinition: true)
+!2 = !DIModule(scope: !4, name: "dummy", file: !3, line: 2)
+!3 = !DIFile(filename: "module.f90", directory: "/fortran")
+!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5)
+!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}
--- /dev/null
+; 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}
typedef MetadataTest DIModuleTest;
TEST_F(DIModuleTest, get) {
+ DIFile *File = getFile();
DIScope *Scope = getFile();
StringRef Name = "module";
StringRef ConfigMacro = "-DNDEBUG";
StringRef Includes = "-I.";
StringRef APINotes = "/tmp/m.apinotes";
+ unsigned LineNo = 4;
- auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes);
+ auto *N = DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+ APINotes, LineNo);
EXPECT_EQ(dwarf::DW_TAG_module, N->getTag());
+ EXPECT_EQ(File, N->getFile());
EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(Name, N->getName());
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_NE(N, DIModule::get(Context, getFile(), Name, ConfigMacro, Includes,
- APINotes));
- 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"));
+ EXPECT_EQ(LineNo, N->getLineNo());
+ EXPECT_EQ(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+ APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, getFile(), getFile(), Name, ConfigMacro,
+ Includes, APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, "other", ConfigMacro,
+ Includes, APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, "other", Includes,
+ APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, "other",
+ APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+ "other", LineNo));
+ EXPECT_NE(N, DIModule::get(Context, getFile(), Scope, Name, ConfigMacro,
+ Includes, APINotes, LineNo));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+ APINotes, 5));
TempDIModule Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));