/// 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.
+ /// \param File Source file of the module.
/// Used for Fortran modules.
+ /// \param LineNo Source line number of the module.
+ /// Used for Fortran modules.
+ /// \param IsDecl This is a module declaration; default to false;
+ /// when set to true, only Scope and Name are required
+ /// as this entry is just a hint for the debugger to find
+ /// the corresponding definition in the global scope.
DIModule *createModule(DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef IncludePath,
StringRef APINotesFile = {}, DIFile *File = nullptr,
- unsigned LineNo = 0);
+ unsigned LineNo = 0, bool IsDecl = false);
/// This creates a descriptor for a lexical block with a new file
/// attached. This merely extends the existing
friend class LLVMContextImpl;
friend class MDNode;
unsigned LineNo;
+ bool IsDecl;
DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo,
- ArrayRef<Metadata *> Ops)
+ bool IsDecl, ArrayRef<Metadata *> Ops)
: DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops),
- LineNo(LineNo) {}
+ LineNo(LineNo), IsDecl(IsDecl) {}
~DIModule() = default;
static DIModule *getImpl(LLVMContext &Context, DIFile *File, DIScope *Scope,
StringRef Name, StringRef ConfigurationMacros,
StringRef IncludePath, StringRef APINotesFile,
- unsigned LineNo, StorageType Storage,
+ unsigned LineNo, bool IsDecl, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, File, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, ConfigurationMacros),
getCanonicalMDString(Context, IncludePath),
- getCanonicalMDString(Context, APINotesFile), LineNo, Storage,
- ShouldCreate);
+ getCanonicalMDString(Context, APINotesFile), LineNo, IsDecl,
+ Storage, ShouldCreate);
}
static DIModule *getImpl(LLVMContext &Context, Metadata *File,
Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros, MDString *IncludePath,
- MDString *APINotesFile, unsigned LineNo,
+ MDString *APINotesFile, unsigned LineNo, bool IsDecl,
StorageType Storage, bool ShouldCreate = true);
TempDIModule cloneImpl() const {
return getTemporary(getContext(), getFile(), getScope(), getName(),
getConfigurationMacros(), getIncludePath(),
- getAPINotesFile(), getLineNo());
+ getAPINotesFile(), getLineNo(), getIsDecl());
}
public:
DEFINE_MDNODE_GET(DIModule,
(DIFile * File, DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef IncludePath,
- StringRef APINotesFile, unsigned LineNo),
+ StringRef APINotesFile, unsigned LineNo,
+ bool IsDecl = false),
(File, Scope, Name, ConfigurationMacros, IncludePath,
- APINotesFile, LineNo))
+ APINotesFile, LineNo, IsDecl))
DEFINE_MDNODE_GET(DIModule,
(Metadata * File, Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros, MDString *IncludePath,
- MDString *APINotesFile, unsigned LineNo),
+ MDString *APINotesFile, unsigned LineNo,
+ bool IsDecl = false),
(File, Scope, Name, ConfigurationMacros, IncludePath,
- APINotesFile, LineNo))
+ APINotesFile, LineNo, IsDecl))
TempDIModule clone() const { return cloneImpl(); }
StringRef getIncludePath() const { return getStringOperand(4); }
StringRef getAPINotesFile() const { return getStringOperand(5); }
unsigned getLineNo() const { return LineNo; }
+ bool getIsDecl() const { return IsDecl; }
Metadata *getRawScope() const { return getOperand(1); }
MDString *getRawName() const { return getOperandAs<MDString>(2); }
/// parseDIModule:
/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros:
/// "-DNDEBUG", includePath: "/usr/include", apinotes: "module.apinotes",
-/// file: !1, line: 4)
+/// file: !1, line: 4, isDecl: false)
bool LLParser::parseDIModule(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
REQUIRED(scope, MDField, ); \
OPTIONAL(includePath, MDStringField, ); \
OPTIONAL(apinotes, MDStringField, ); \
OPTIONAL(file, MDField, ); \
- OPTIONAL(line, LineField, );
+ OPTIONAL(line, LineField, ); \
+ OPTIONAL(isDecl, MDBoolField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS
Result = GET_OR_DISTINCT(DIModule, (Context, file.Val, scope.Val, name.Val,
configMacros.Val, includePath.Val,
- apinotes.Val, line.Val));
+ apinotes.Val, line.Val, isDecl.Val));
return false;
}
}
case bitc::METADATA_MODULE: {
- if (Record.size() < 5 || Record.size() > 8)
+ if (Record.size() < 5 || Record.size() > 9)
return error("Invalid record");
- unsigned Offset = Record.size() >= 7 ? 2 : 1;
+ unsigned Offset = Record.size() >= 8 ? 2 : 1;
IsDistinct = Record[0];
MetadataList.assignValue(
GET_OR_DISTINCT(
DIModule,
- (Context, Record.size() >= 7 ? getMDOrNull(Record[1]) : nullptr,
+ (Context, Record.size() >= 8 ? 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])),
+ Record.size() <= 7 ? 0 : Record[7],
+ Record.size() <= 8 ? false : Record[8])),
NextMetadataNo);
NextMetadataNo++;
break;
for (auto &I : N->operands())
Record.push_back(VE.getMetadataOrNullID(I));
Record.push_back(N->getLineNo());
+ Record.push_back(N->getIsDecl());
Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev);
Record.clear();
getOrCreateSourceID(M->getFile()));
if (M->getLineNo())
addUInt(MDie, dwarf::DW_AT_decl_line, None, M->getLineNo());
+ if (M->getIsDecl())
+ addFlag(MDie, dwarf::DW_AT_declaration);
return &MDie;
}
Printer.printString("apinotes", N->getAPINotesFile());
Printer.printMetadata("file", N->getRawFile());
Printer.printInt("line", N->getLineNo());
+ Printer.printBool("isDecl", N->getIsDecl(), /* Default */ false);
Out << ")";
}
DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros,
StringRef IncludePath, StringRef APINotesFile,
- DIFile *File, unsigned LineNo) {
+ DIFile *File, unsigned LineNo, bool IsDecl) {
return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name,
- ConfigurationMacros, IncludePath, APINotesFile, LineNo);
+ ConfigurationMacros, IncludePath, APINotesFile, LineNo,
+ IsDecl);
}
DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope,
Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros,
MDString *IncludePath, MDString *APINotesFile,
- unsigned LineNo, StorageType Storage,
+ unsigned LineNo, bool IsDecl, StorageType Storage,
bool ShouldCreate) {
assert(isCanonical(Name) && "Expected canonical MDString");
DEFINE_GETIMPL_LOOKUP(DIModule, (File, Scope, Name, ConfigurationMacros,
- IncludePath, APINotesFile, LineNo));
+ IncludePath, APINotesFile, LineNo, IsDecl));
Metadata *Ops[] = {File, Scope, Name, ConfigurationMacros,
IncludePath, APINotesFile};
- DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops);
+ DEFINE_GETIMPL_STORE(DIModule, (LineNo, IsDecl), Ops);
}
DITemplateTypeParameter *
MDString *IncludePath;
MDString *APINotesFile;
unsigned LineNo;
+ bool IsDecl;
MDNodeKeyImpl(Metadata *File, Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros, MDString *IncludePath,
- MDString *APINotesFile, unsigned LineNo)
+ MDString *APINotesFile, unsigned LineNo, bool IsDecl)
: File(File), Scope(Scope), Name(Name),
ConfigurationMacros(ConfigurationMacros), IncludePath(IncludePath),
- APINotesFile(APINotesFile), LineNo(LineNo) {}
+ APINotesFile(APINotesFile), LineNo(LineNo), IsDecl(IsDecl) {}
MDNodeKeyImpl(const DIModule *N)
: File(N->getRawFile()), Scope(N->getRawScope()), Name(N->getRawName()),
ConfigurationMacros(N->getRawConfigurationMacros()),
IncludePath(N->getRawIncludePath()),
- APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()) {}
+ APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()),
+ IsDecl(N->getIsDecl()) {}
bool isKeyOf(const DIModule *RHS) const {
return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
ConfigurationMacros == RHS->getRawConfigurationMacros() &&
IncludePath == RHS->getRawIncludePath() &&
APINotesFile == RHS->getRawAPINotesFile() &&
- File == RHS->getRawFile() && LineNo == RHS->getLineNo();
+ File == RHS->getRawFile() && LineNo == RHS->getLineNo() &&
+ IsDecl == RHS->getIsDecl();
}
unsigned getHashValue() const {
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
; RUN: verify-uselistorder %s
-; CHECK: !named = !{!0, !1, !2, !1, !3}
-!named = !{!0, !1, !2, !3, !4}
+; CHECK: !named = !{!0, !1, !2, !1, !3, !4}
+!named = !{!0, !1, !2, !3, !4, !5}
!0 = distinct !{}
; 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)
+
+; CHECK: !4 = !DIModule(scope: !0, name: "Module", isDecl: true)
+!5 = !DIModule(scope: !0, name: "Module", isDecl: true)
--- /dev/null
+; RUN: llvm-as -o - %s | llvm-dis -o - | FileCheck %s
+; CHECK: DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+; CHECK: DIModule(scope: !2, name: "external_module", isDecl: true)
+
+; ModuleID = 'em.f90'
+source_filename = "em.f90"
+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"
+
+@external_module_mp_dummy_ = available_externally global float 0.000000e+00, align 8, !dbg !0
+@0 = internal unnamed_addr constant i32 2
+
+; Function Attrs: noinline nounwind uwtable
+define void @MAIN__() #0 !dbg !2 {
+alloca_0:
+ %"var$1" = alloca [8 x i64], align 8
+ %"use_external_module_$X" = alloca float, align 8
+ call void @llvm.dbg.declare(metadata float* %"use_external_module_$X", metadata !13, metadata !DIExpression()), !dbg !17
+ %func_result = call i32 @for_set_reentrancy(i32* @0), !dbg !18
+ %external_module_mp_dummy__fetch = load float, float* @external_module_mp_dummy_, align 1, !dbg !19
+ %add = fadd reassoc ninf nsz arcp contract afn float 2.000000e+00, %external_module_mp_dummy__fetch, !dbg !20
+ store float %add, float* %"use_external_module_$X", align 1, !dbg !19
+ ret void, !dbg !21
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare i32 @for_set_reentrancy(i32*)
+
+attributes #0 = { noinline nounwind uwtable "intel-lang"="fortran" "min-legal-vector-width"="0" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.module.flags = !{!15, !16}
+!llvm.dbg.cu = !{!6}
+!omp_offload.info = !{}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "dummy", linkageName: "external_module_mp_dummy_", scope: !2, file: !3, line: 1, type: !14, isLocal: false, isDefinition: true)
+!2 = distinct !DISubprogram(name: "use_external_module", linkageName: "MAIN__", scope: !3, file: !3, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !12)
+!3 = !DIFile(filename: "em.f90", directory: "tests")
+!4 = !DISubroutineType(types: !5)
+!5 = !{null}
+!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, imports: !9, splitDebugInlining: false, nameTableKind: None)
+!7 = !{}
+!8 = !{!0}
+!9 = !{!10}
+!10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+!11 = !DIModule(scope: !2, name: "external_module", isDecl: true)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 5, type: !14)
+!14 = !DIBasicType(name: "REAL*4", size: 32, encoding: DW_ATE_float)
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !DILocation(line: 5, column: 12, scope: !2)
+!18 = !DILocation(line: 1, column: 9, scope: !2)
+!19 = !DILocation(line: 6, column: 4, scope: !2)
+!20 = !DILocation(line: 6, column: 12, scope: !2)
+!21 = !DILocation(line: 8, column: 1, scope: !2)
--- /dev/null
+; This test verifies that the debug info for an external Fortran module
+; is correctly generated.
+;
+; To generate the test source, compile the following two files in order in
+; the same directory (as the second compilation uses the .mod from the first):
+; external_module.f90 (to compile: <fortran compiler> -g -c external_module.f90)
+; module external_module
+; real :: dummy
+; end module external_module
+;
+; em.f90 (to compile: <fortran compierl> -g -llvm-emit -c -S em.f90)
+; program use_external_module
+; use external_module
+; implicit none
+;
+; real :: x
+; x = 2.0 + dummy
+;
+; end program use_external_module
+;
+; The test would be in em.ll.
+
+; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s
+
+; CHECK: [[DIE_ID:0x[0-9a-f]+]]: DW_TAG_module
+; CHECK-NEXT: DW_AT_name ("external_module")
+; CHECK-NEXT: DW_AT_declaration (true)
+
+; CHECK: DW_TAG_imported_module
+; CHECK-NEXT: DW_AT_decl_file
+; CHECK-NEXT: DW_AT_decl_line
+; CHECK-NEXT: DW_AT_import ([[DIE_ID]])
+
+; When the debugger sees the module being imported is a declaration,
+; it should go to the global scope to find the module's definition.
+
+; ModuleID = 'em.f90'
+source_filename = "em.f90"
+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"
+
+@external_module_mp_dummy_ = available_externally global float 0.000000e+00, align 8, !dbg !0
+@0 = internal unnamed_addr constant i32 2
+
+; Function Attrs: noinline nounwind uwtable
+define void @MAIN__() #0 !dbg !2 {
+alloca_0:
+ %"var$1" = alloca [8 x i64], align 8
+ %"use_external_module_$X" = alloca float, align 8
+ call void @llvm.dbg.declare(metadata float* %"use_external_module_$X", metadata !13, metadata !DIExpression()), !dbg !17
+ %func_result = call i32 @for_set_reentrancy(i32* @0), !dbg !18
+ %external_module_mp_dummy__fetch = load float, float* @external_module_mp_dummy_, align 1, !dbg !19
+ %add = fadd reassoc ninf nsz arcp contract afn float 2.000000e+00, %external_module_mp_dummy__fetch, !dbg !20
+ store float %add, float* %"use_external_module_$X", align 1, !dbg !19
+ ret void, !dbg !21
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare i32 @for_set_reentrancy(i32*)
+
+attributes #0 = { noinline nounwind uwtable "intel-lang"="fortran" "min-legal-vector-width"="0" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.module.flags = !{!15, !16}
+!llvm.dbg.cu = !{!6}
+!omp_offload.info = !{}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "dummy", linkageName: "external_module_mp_dummy_", scope: !2, file: !3, line: 1, type: !14, isLocal: false, isDefinition: true)
+!2 = distinct !DISubprogram(name: "use_external_module", linkageName: "MAIN__", scope: !3, file: !3, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !12)
+!3 = !DIFile(filename: "em.f90", directory: "tests")
+!4 = !DISubroutineType(types: !5)
+!5 = !{null}
+!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, imports: !9, splitDebugInlining: false, nameTableKind: None)
+!7 = !{}
+!8 = !{!0}
+!9 = !{!10}
+!10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
+!11 = !DIModule(scope: !2, name: "external_module", isDecl: true)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 5, type: !14)
+!14 = !DIBasicType(name: "REAL*4", size: 32, encoding: DW_ATE_float)
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !DILocation(line: 5, column: 12, scope: !2)
+!18 = !DILocation(line: 1, column: 9, scope: !2)
+!19 = !DILocation(line: 6, column: 4, scope: !2)
+!20 = !DILocation(line: 6, column: 12, scope: !2)
+!21 = !DILocation(line: 8, column: 1, scope: !2)
StringRef Includes = "-I.";
StringRef APINotes = "/tmp/m.apinotes";
unsigned LineNo = 4;
+ bool IsDecl = true;
auto *N = DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
- APINotes, LineNo);
+ APINotes, LineNo, IsDecl);
EXPECT_EQ(dwarf::DW_TAG_module, N->getTag());
EXPECT_EQ(File, N->getFile());
EXPECT_EQ(Includes, N->getIncludePath());
EXPECT_EQ(APINotes, N->getAPINotesFile());
EXPECT_EQ(LineNo, N->getLineNo());
+ EXPECT_EQ(IsDecl, N->getIsDecl());
EXPECT_EQ(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
- APINotes, LineNo));
+ APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, getFile(), getFile(), Name, ConfigMacro,
- Includes, APINotes, LineNo));
+ Includes, APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, File, Scope, "other", ConfigMacro,
- Includes, APINotes, LineNo));
+ Includes, APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, "other", Includes,
- APINotes, LineNo));
+ APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, "other",
- APINotes, LineNo));
+ APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
- "other", LineNo));
+ "other", LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, getFile(), Scope, Name, ConfigMacro,
- Includes, APINotes, LineNo));
+ Includes, APINotes, LineNo, IsDecl));
EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
- APINotes, 5));
+ APINotes, 5, IsDecl));
+ EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
+ APINotes, LineNo, false));
TempDIModule Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));