[DebugInfo] Fortran module DebugInfo support in LLVM

This patch extends DIModule Debug metadata in LLVM to support
Fortran modules. DIModule is extended to contain File and Line
fields, these fields will be used by Flang FE to create debug
information necessary for representing Fortran modules at IR level.

Furthermore DW_TAG_module is also extended to contain these fields.
If these fields are missing, debuggers like GDB won't be able to
show Fortran modules information correctly.

Reviewed By: aprantl

Differential Revision: https://reviews.llvm.org/D79484
This commit is contained in:
Sourabh Singh Tomar 2020-05-08 11:31:41 +05:30
parent eef95f2746
commit e59744fd9b
17 changed files with 223 additions and 79 deletions

View File

@ -742,9 +742,14 @@ namespace llvm {
/// definitions as they would appear on a command line. /// definitions as they would appear on a command line.
/// \param IncludePath The path to the module map file. /// \param IncludePath The path to the module map file.
/// \param APINotesFile The path to an API notes file for this module. /// \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, DIModule *createModule(DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef ConfigurationMacros, StringRef IncludePath,
StringRef IncludePath, StringRef APINotesFile = {}); StringRef APINotesFile = {}, DIFile *File = nullptr,
unsigned LineNo = 0);
/// This creates a descriptor for a lexical block with a new file /// This creates a descriptor for a lexical block with a new file
/// attached. This merely extends the existing /// attached. This merely extends the existing

View File

@ -2097,64 +2097,72 @@ public:
} }
}; };
/// 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 { class DIModule : public DIScope {
friend class LLVMContextImpl; friend class LLVMContextImpl;
friend class MDNode; friend class MDNode;
unsigned LineNo;
DIModule(LLVMContext &Context, StorageType Storage, ArrayRef<Metadata *> Ops) DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo,
: DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) {} ArrayRef<Metadata *> Ops)
: DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops),
LineNo(LineNo) {}
~DIModule() = default; ~DIModule() = default;
static DIModule *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, static DIModule *getImpl(LLVMContext &Context, DIFile *File, DIScope *Scope,
StringRef ConfigurationMacros, StringRef IncludePath, StringRef Name, StringRef ConfigurationMacros,
StringRef APINotesFile, StorageType Storage, StringRef IncludePath, StringRef APINotesFile,
unsigned LineNo, StorageType Storage,
bool ShouldCreate = true) { bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name), return getImpl(Context, File, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, ConfigurationMacros), getCanonicalMDString(Context, ConfigurationMacros),
getCanonicalMDString(Context, IncludePath), getCanonicalMDString(Context, IncludePath),
getCanonicalMDString(Context, APINotesFile), getCanonicalMDString(Context, APINotesFile), LineNo, Storage,
Storage, ShouldCreate); ShouldCreate);
} }
static DIModule *getImpl(LLVMContext &Context, Metadata *Scope, static DIModule *getImpl(LLVMContext &Context, Metadata *File,
MDString *Name, MDString *ConfigurationMacros, Metadata *Scope, MDString *Name,
MDString *IncludePath, MDString *APINotesFile, MDString *ConfigurationMacros, MDString *IncludePath,
MDString *APINotesFile, unsigned LineNo,
StorageType Storage, bool ShouldCreate = true); StorageType Storage, bool ShouldCreate = true);
TempDIModule cloneImpl() const { TempDIModule cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), return getTemporary(getContext(), getFile(), getScope(), getName(),
getConfigurationMacros(), getIncludePath(), getConfigurationMacros(), getIncludePath(),
getAPINotesFile()); getAPINotesFile(), getLineNo());
} }
public: public:
DEFINE_MDNODE_GET(DIModule, DEFINE_MDNODE_GET(DIModule,
(DIScope * Scope, StringRef Name, (DIFile * File, DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef IncludePath, StringRef ConfigurationMacros, StringRef IncludePath,
StringRef APINotesFile), StringRef APINotesFile, unsigned LineNo),
(Scope, Name, ConfigurationMacros, IncludePath, (File, Scope, Name, ConfigurationMacros, IncludePath,
APINotesFile)) APINotesFile, LineNo))
DEFINE_MDNODE_GET(DIModule, DEFINE_MDNODE_GET(DIModule,
(Metadata * Scope, MDString *Name, (Metadata * File, Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros, MDString *IncludePath, MDString *ConfigurationMacros, MDString *IncludePath,
MDString *APINotesFile), MDString *APINotesFile, unsigned LineNo),
(Scope, Name, ConfigurationMacros, IncludePath, (File, Scope, Name, ConfigurationMacros, IncludePath,
APINotesFile)) APINotesFile, LineNo))
TempDIModule clone() const { return cloneImpl(); } TempDIModule clone() const { return cloneImpl(); }
DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); } DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); }
StringRef getName() const { return getStringOperand(1); } StringRef getName() const { return getStringOperand(2); }
StringRef getConfigurationMacros() const { return getStringOperand(2); } StringRef getConfigurationMacros() const { return getStringOperand(3); }
StringRef getIncludePath() const { return getStringOperand(3); } StringRef getIncludePath() const { return getStringOperand(4); }
StringRef getAPINotesFile() const { return getStringOperand(4); } StringRef getAPINotesFile() const { return getStringOperand(5); }
unsigned getLineNo() const { return LineNo; }
Metadata *getRawScope() const { return getOperand(0); } Metadata *getRawScope() const { return getOperand(1); }
MDString *getRawName() const { return getOperandAs<MDString>(1); } MDString *getRawName() const { return getOperandAs<MDString>(2); }
MDString *getRawConfigurationMacros() const { return getOperandAs<MDString>(2); } MDString *getRawConfigurationMacros() const {
MDString *getRawIncludePath() const { return getOperandAs<MDString>(3); } return getOperandAs<MDString>(3);
MDString *getRawAPINotesFile() const { return getOperandAs<MDString>(4); } }
MDString *getRawIncludePath() const { return getOperandAs<MDString>(4); }
MDString *getRawAPINotesFile() const { return getOperandAs<MDString>(5); }
static bool classof(const Metadata *MD) { static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIModuleKind; return MD->getMetadataID() == DIModuleKind;

View File

@ -4880,21 +4880,24 @@ bool LLParser::ParseDIMacroFile(MDNode *&Result, bool IsDistinct) {
} }
/// ParseDIModule: /// ParseDIModule:
/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG", /// ::= !DIModule(scope: !0, name: "SomeModule", configMacros:
/// includePath: "/usr/include", apinotes: "module.apinotes") /// "-DNDEBUG", includePath: "/usr/include", apinotes: "module.apinotes",
/// file: !1, line: 4)
bool LLParser::ParseDIModule(MDNode *&Result, bool IsDistinct) { bool LLParser::ParseDIModule(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
REQUIRED(scope, MDField, ); \ REQUIRED(scope, MDField, ); \
REQUIRED(name, MDStringField, ); \ REQUIRED(name, MDStringField, ); \
OPTIONAL(configMacros, MDStringField, ); \ OPTIONAL(configMacros, MDStringField, ); \
OPTIONAL(includePath, MDStringField, ); \ OPTIONAL(includePath, MDStringField, ); \
OPTIONAL(apinotes, MDStringField, ); OPTIONAL(apinotes, MDStringField, ); \
OPTIONAL(file, MDField, ); \
OPTIONAL(line, LineField, );
PARSE_MD_FIELDS(); PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS #undef VISIT_MD_FIELDS
Result = Result = GET_OR_DISTINCT(DIModule, (Context, file.Val, scope.Val, name.Val,
GET_OR_DISTINCT(DIModule, (Context, scope.Val, name.Val, configMacros.Val, configMacros.Val, includePath.Val,
includePath.Val, apinotes.Val)); apinotes.Val, line.Val));
return false; return false;
} }

View File

@ -1428,15 +1428,19 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
} }
case bitc::METADATA_MODULE: { case bitc::METADATA_MODULE: {
if (Record.size() < 5 || Record.size() > 7) if (Record.size() < 5 || Record.size() > 8)
return error("Invalid record"); return error("Invalid record");
unsigned Offset = Record.size() >= 7 ? 2 : 1;
IsDistinct = Record[0]; IsDistinct = Record[0];
MetadataList.assignValue( MetadataList.assignValue(
GET_OR_DISTINCT(DIModule, GET_OR_DISTINCT(
(Context, getMDOrNull(Record[1]), DIModule,
getMDString(Record[2]), getMDString(Record[3]), (Context, Record.size() >= 7 ? getMDOrNull(Record[1]) : nullptr,
getMDString(Record[4]), getMDString(Record[5]))), 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);
NextMetadataNo++; NextMetadataNo++;
break; break;

View File

@ -1809,6 +1809,7 @@ void ModuleBitcodeWriter::writeDIModule(const DIModule *N,
Record.push_back(N->isDistinct()); Record.push_back(N->isDistinct());
for (auto &I : N->operands()) for (auto &I : N->operands())
Record.push_back(VE.getMetadataOrNullID(I)); Record.push_back(VE.getMetadataOrNullID(I));
Record.push_back(N->getLineNo());
Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev); Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev);
Record.clear(); Record.clear();

View File

@ -1128,6 +1128,11 @@ DIE *DwarfUnit::getOrCreateModule(const DIModule *M) {
addString(MDie, dwarf::DW_AT_LLVM_include_path, M->getIncludePath()); addString(MDie, dwarf::DW_AT_LLVM_include_path, M->getIncludePath());
if (!M->getAPINotesFile().empty()) if (!M->getAPINotesFile().empty())
addString(MDie, dwarf::DW_AT_LLVM_apinotes, M->getAPINotesFile()); 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; return &MDie;
} }

View File

@ -2103,6 +2103,8 @@ static void writeDIModule(raw_ostream &Out, const DIModule *N,
Printer.printString("configMacros", N->getConfigurationMacros()); Printer.printString("configMacros", N->getConfigurationMacros());
Printer.printString("includePath", N->getIncludePath()); Printer.printString("includePath", N->getIncludePath());
Printer.printString("apinotes", N->getAPINotesFile()); Printer.printString("apinotes", N->getAPINotesFile());
Printer.printMetadata("file", N->getRawFile());
Printer.printInt("line", N->getLineNo());
Out << ")"; Out << ")";
} }

View File

@ -832,10 +832,10 @@ DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name,
DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name,
StringRef ConfigurationMacros, StringRef ConfigurationMacros,
StringRef IncludePath, StringRef IncludePath, StringRef APINotesFile,
StringRef APINotesFile) { DIFile *File, unsigned LineNo) {
return DIModule::get(VMContext, getNonCompileUnitScope(Scope), Name, return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name,
ConfigurationMacros, IncludePath, APINotesFile); ConfigurationMacros, IncludePath, APINotesFile, LineNo);
} }
DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope,

View File

@ -732,16 +732,18 @@ DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope,
DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops); DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops);
} }
DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *File,
MDString *Name, MDString *ConfigurationMacros, Metadata *Scope, MDString *Name,
MDString *ConfigurationMacros,
MDString *IncludePath, MDString *APINotesFile, MDString *IncludePath, MDString *APINotesFile,
StorageType Storage, bool ShouldCreate) { unsigned LineNo, StorageType Storage,
bool ShouldCreate) {
assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(Name) && "Expected canonical MDString");
DEFINE_GETIMPL_LOOKUP( DEFINE_GETIMPL_LOOKUP(DIModule, (File, Scope, Name, ConfigurationMacros,
DIModule, (Scope, Name, ConfigurationMacros, IncludePath, APINotesFile)); IncludePath, APINotesFile, LineNo));
Metadata *Ops[] = {Scope, Name, ConfigurationMacros, IncludePath, Metadata *Ops[] = {File, Scope, Name, ConfigurationMacros,
APINotesFile}; IncludePath, APINotesFile};
DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIModule, Ops); DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops);
} }
DITemplateTypeParameter * DITemplateTypeParameter *

View File

@ -816,27 +816,32 @@ template <> struct MDNodeKeyImpl<DICommonBlock> {
}; };
template <> struct MDNodeKeyImpl<DIModule> { template <> struct MDNodeKeyImpl<DIModule> {
Metadata *File;
Metadata *Scope; Metadata *Scope;
MDString *Name; MDString *Name;
MDString *ConfigurationMacros; MDString *ConfigurationMacros;
MDString *IncludePath; MDString *IncludePath;
MDString *APINotesFile; MDString *APINotesFile;
unsigned LineNo;
MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDNodeKeyImpl(Metadata *File, Metadata *Scope, MDString *Name,
MDString *IncludePath, MDString *APINotesFile) MDString *ConfigurationMacros, MDString *IncludePath,
: Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), MDString *APINotesFile, unsigned LineNo)
IncludePath(IncludePath), APINotesFile(APINotesFile) {} : File(File), Scope(Scope), Name(Name),
ConfigurationMacros(ConfigurationMacros), IncludePath(IncludePath),
APINotesFile(APINotesFile), LineNo(LineNo) {}
MDNodeKeyImpl(const DIModule *N) MDNodeKeyImpl(const DIModule *N)
: Scope(N->getRawScope()), Name(N->getRawName()), : File(N->getRawFile()), Scope(N->getRawScope()), Name(N->getRawName()),
ConfigurationMacros(N->getRawConfigurationMacros()), ConfigurationMacros(N->getRawConfigurationMacros()),
IncludePath(N->getRawIncludePath()), IncludePath(N->getRawIncludePath()),
APINotesFile(N->getRawAPINotesFile()) {} APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()) {}
bool isKeyOf(const DIModule *RHS) const { bool isKeyOf(const DIModule *RHS) const {
return Scope == RHS->getRawScope() && Name == RHS->getRawName() && return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
ConfigurationMacros == RHS->getRawConfigurationMacros() && ConfigurationMacros == RHS->getRawConfigurationMacros() &&
IncludePath == RHS->getRawIncludePath() && IncludePath == RHS->getRawIncludePath() &&
APINotesFile == RHS->getRawAPINotesFile(); APINotesFile == RHS->getRawAPINotesFile() &&
File == RHS->getRawFile() && LineNo == RHS->getLineNo();
} }
unsigned getHashValue() const { unsigned getHashValue() const {

View File

@ -14,5 +14,5 @@
!3 = !DIModule(scope: !0, name: "Module", configMacros: "") !3 = !DIModule(scope: !0, name: "Module", configMacros: "")
; CHECK: !3 = !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") !4 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes", file: !0, line: 1)

View File

@ -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"}

Binary file not shown.

View File

@ -0,0 +1,34 @@
; 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}

Binary file not shown.

View File

@ -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}

View File

@ -2062,32 +2062,41 @@ TEST_F(DINamespaceTest, get) {
typedef MetadataTest DIModuleTest; typedef MetadataTest DIModuleTest;
TEST_F(DIModuleTest, get) { TEST_F(DIModuleTest, get) {
DIFile *File = getFile();
DIScope *Scope = getFile(); DIScope *Scope = getFile();
StringRef Name = "module"; StringRef Name = "module";
StringRef ConfigMacro = "-DNDEBUG"; StringRef ConfigMacro = "-DNDEBUG";
StringRef Includes = "-I."; StringRef Includes = "-I.";
StringRef APINotes = "/tmp/m.apinotes"; 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(dwarf::DW_TAG_module, N->getTag());
EXPECT_EQ(File, N->getFile());
EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(Name, N->getName()); EXPECT_EQ(Name, N->getName());
EXPECT_EQ(ConfigMacro, N->getConfigurationMacros()); EXPECT_EQ(ConfigMacro, N->getConfigurationMacros());
EXPECT_EQ(Includes, N->getIncludePath()); EXPECT_EQ(Includes, N->getIncludePath());
EXPECT_EQ(APINotes, N->getAPINotesFile()); EXPECT_EQ(APINotes, N->getAPINotesFile());
EXPECT_EQ( EXPECT_EQ(LineNo, N->getLineNo());
N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes)); EXPECT_EQ(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes,
EXPECT_NE(N, DIModule::get(Context, getFile(), Name, ConfigMacro, Includes, APINotes, LineNo));
APINotes)); EXPECT_NE(N, DIModule::get(Context, getFile(), getFile(), Name, ConfigMacro,
EXPECT_NE(N, DIModule::get(Context, Scope, "other", ConfigMacro, Includes, Includes, APINotes, LineNo));
APINotes)); EXPECT_NE(N, DIModule::get(Context, File, Scope, "other", ConfigMacro,
EXPECT_NE(N, Includes, APINotes, LineNo));
DIModule::get(Context, Scope, Name, "other", Includes, APINotes)); EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, "other", Includes,
EXPECT_NE( APINotes, LineNo));
N, DIModule::get(Context, Scope, Name, ConfigMacro, "other", APINotes)); EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, "other",
EXPECT_NE( APINotes, LineNo));
N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, "other")); 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(); TempDIModule Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));