Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -3998,11 +3998,24 @@ .. code-block:: llvm - !0 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") + !0 = !DIFile(filename: "path/to/file", directory: "/path/to/dir", + checksum: !1) Files are sometimes used in ``scope:`` fields, and are the only valid target for ``file:`` fields. +.. _DIChecksum: + +DIChecksum +"""""""""" + +``DIChecksum`` nodes represent file checksum. + +.. code-block:: llvm + + !0 = !DIChecksum(type: ChecksumType_MD5, + data: "000102030405060708090a0b0c0d0e0f") + .. _DIBasicType: DIBasicType Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -252,6 +252,7 @@ METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] METADATA_STRINGS = 35, // [count, offset] blob([lengths][chars]) METADATA_GLOBAL_DECL_ATTACHMENT = 36, // [valueid, n x [id, mdnode]] + METADATA_CHECKSUM = 37, // [distinct, type, data] }; // 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 @@ -85,6 +85,8 @@ /// \param Lang Source programming language, eg. dwarf::DW_LANG_C99 /// \param File File name /// \param Dir Directory + /// \param ChecksumType Checksum type (e.g. MD5, SHA1, etc.). + /// \param Checksum Checksum data. /// \param Producer Identify the producer of debugging information /// and code. Usually this is a compiler /// version string. @@ -102,15 +104,21 @@ /// \param DWOId The DWOId if this is a split skeleton compile unit. DICompileUnit * createCompileUnit(unsigned Lang, StringRef File, StringRef Dir, + DIChecksum::ChecksumType ChecksumType, StringRef Checksum, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), DICompileUnit::DebugEmissionKind Kind = DICompileUnit::DebugEmissionKind::FullDebug, uint64_t DWOId = 0, bool SplitDebugInlining = true); - /// Create a file descriptor to hold debugging information - /// for a file. - DIFile *createFile(StringRef Filename, StringRef Directory); + /// Create a checksum descriptor to hold checksum information for a file. + /// \param Type Checksum type (e.g. MD5, SHA1, etc.). + /// \param Data Checksum data. + DIChecksum *createChecksum(DIChecksum::ChecksumType Type, StringRef Data); + + /// Create a file descriptor to hold debugging information for a file. + DIFile *createFile(StringRef Filename, StringRef Directory, + DIChecksum *Checksum = nullptr); /// Create a single enumerator value. DIEnumerator *createEnumerator(StringRef Name, int64_t Val); Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -427,6 +427,7 @@ inline StringRef getFilename() const; inline StringRef getDirectory() const; + inline DIChecksum *getChecksum() const; StringRef getName() const; DIScopeRef getScope() const; @@ -462,6 +463,66 @@ } }; +/// File checksum. +class DIChecksum : public DINode { + friend class LLVMContextImpl; + friend class MDNode; + +public: + enum ChecksumType { + None, + MD5, + SHA1, + ChecksumTypeNum // Should be last enumeration. + }; + +private: + ChecksumType Type; + + DIChecksum(LLVMContext &C, StorageType Storage, ChecksumType Type, + ArrayRef Ops) + : DINode(C, DIChecksumKind, Storage, dwarf::DW_TAG_null, Ops), Type(Type) + {} + ~DIChecksum() = default; + + static DIChecksum *getImpl(LLVMContext &Context, ChecksumType Type, + StringRef Data, StorageType Storage, + bool ShouldCreate = true) { + // Do not create checksum with "None" checksum type. + if (Type == None) + return nullptr; + return getImpl(Context, Type, getCanonicalMDString(Context, Data), + Storage, ShouldCreate); + } + static DIChecksum *getImpl(LLVMContext &Context, ChecksumType Type, + MDString *Data, StorageType Storage, + bool ShouldCreate = true); + + TempDIChecksum cloneImpl() const { + return getTemporary(getContext(), getType(), getData()); + } + +public: + DEFINE_MDNODE_GET(DIChecksum, (ChecksumType Type, StringRef Data), + (Type, Data)) + DEFINE_MDNODE_GET(DIChecksum, (ChecksumType Type, MDString *Data), + (Type, Data)) + + TempDIChecksum clone() const { return cloneImpl(); } + + ChecksumType getType() const { return Type; } + StringRef getData() const { return getStringOperand(0); } + StringRef getTypeAsString() const; + + MDString *getRawData() const { return getOperandAs(0); } + + static ChecksumType getChecksumType(StringRef TypeStr); + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIChecksumKind; + } +}; + /// File. /// /// TODO: Merge with directory/file node (including users). @@ -475,33 +536,40 @@ ~DIFile() = default; static DIFile *getImpl(LLVMContext &Context, StringRef Filename, - StringRef Directory, StorageType Storage, - bool ShouldCreate = true) { + StringRef Directory, DIChecksum *Checksum, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, getCanonicalMDString(Context, Filename), - getCanonicalMDString(Context, Directory), Storage, + getCanonicalMDString(Context, Directory), Checksum, Storage, ShouldCreate); } static DIFile *getImpl(LLVMContext &Context, MDString *Filename, - MDString *Directory, StorageType Storage, - bool ShouldCreate = true); + MDString *Directory, Metadata *Checksum, + StorageType Storage, bool ShouldCreate = true); TempDIFile cloneImpl() const { - return getTemporary(getContext(), getFilename(), getDirectory()); + return getTemporary(getContext(), getFilename(), getDirectory(), + getChecksum()); } public: - DEFINE_MDNODE_GET(DIFile, (StringRef Filename, StringRef Directory), - (Filename, Directory)) - DEFINE_MDNODE_GET(DIFile, (MDString * Filename, MDString *Directory), - (Filename, Directory)) + DEFINE_MDNODE_GET(DIFile, (StringRef Filename, StringRef Directory, + DIChecksum *Checksum), + (Filename, Directory, Checksum)) + DEFINE_MDNODE_GET(DIFile, (MDString *Filename, MDString *Directory, + Metadata *Checksum), + (Filename, Directory, Checksum)) TempDIFile clone() const { return cloneImpl(); } StringRef getFilename() const { return getStringOperand(0); } StringRef getDirectory() const { return getStringOperand(1); } + DIChecksum *getChecksum() const { + return cast_or_null(getRawChecksum()); + } MDString *getRawFilename() const { return getOperandAs(0); } MDString *getRawDirectory() const { return getOperandAs(1); } + Metadata *getRawChecksum() const { return getOperand(2); } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIFileKind; @@ -520,6 +588,12 @@ return ""; } +DIChecksum *DIScope::getChecksum() const { + if (auto *F = getFile()) + return F->getChecksum(); + return nullptr; +} + /// Base class for types. /// /// TODO: Remove the hardcoded name and context, since many types don't use @@ -1254,6 +1328,7 @@ DIFile *getFile() const { return getScope()->getFile(); } StringRef getFilename() const { return getScope()->getFilename(); } StringRef getDirectory() const { return getScope()->getDirectory(); } + //DIChecksum *getChecksum() const { return getScope()->getChecksum(); } /// Get the scope where this is inlined. /// Index: include/llvm/IR/Metadata.def =================================================================== --- include/llvm/IR/Metadata.def +++ include/llvm/IR/Metadata.def @@ -93,6 +93,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICompositeType) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubroutineType) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIFile) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIChecksum) HANDLE_SPECIALIZED_MDNODE_LEAF(DICompileUnit) HANDLE_SPECIALIZED_MDNODE_BRANCH(DILocalScope) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubprogram) Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -808,6 +808,12 @@ StrVal.assign(Keyword.begin(), Keyword.end()); return lltok::DIFlag; } + + if (Keyword.startswith("ChecksumType_")) { + StrVal.assign(Keyword.begin(), Keyword.end()); + return lltok::ChecksumType; + } + if (Keyword == "NoDebug" || Keyword == "FullDebug" || Keyword == "LineTablesOnly") { StrVal.assign(Keyword.begin(), Keyword.end()); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -3462,6 +3462,11 @@ MDFieldList() : ImplTy(SmallVector()) {} }; +struct ChecksumTypeField : public MDFieldImpl { + ChecksumTypeField() : ImplTy(DIChecksum::None) {} + ChecksumTypeField(DIChecksum::ChecksumType Type) : ImplTy(Type) {} +}; + } // end anonymous namespace namespace llvm { @@ -3739,6 +3744,23 @@ return false; } +template <> +bool LLParser::ParseMDField(LocTy Loc, StringRef Name, + ChecksumTypeField &Result) { + if (Lex.getKind() != lltok::ChecksumType) + return TokError( + "invalid checksum type" + Twine(" '") + Lex.getStrVal() + "'"); + + DIChecksum::ChecksumType Type = DIChecksum::getChecksumType(Lex.getStrVal()); + if (Type == DIChecksum::None) + return TokError( + "invalid checksum type" + Twine(" '") + Lex.getStrVal() + "'"); + + Result.assign(Type); + Lex.Lex(); + return false; +} + } // end namespace llvm template @@ -3967,16 +3989,32 @@ return false; } +/// ParseDIChecksum: +/// ::= !DIChecksum(type: ChecksumType_MD5, +/// data: "000102030405060708090a0b0c0d0e0f") +bool LLParser::ParseDIChecksum(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(type, ChecksumTypeField, ); \ + REQUIRED(data, MDStringField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DIChecksum, (Context, type.Val, data.Val)); + return false; +} + /// ParseDIFileType: /// ::= !DIFileType(filename: "path/to/file", directory: "/path/to/dir") bool LLParser::ParseDIFile(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(filename, MDStringField, ); \ - REQUIRED(directory, MDStringField, ); + REQUIRED(directory, MDStringField, ); \ + OPTIONAL(checksum, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIFile, (Context, filename.Val, directory.Val)); + Result = GET_OR_DISTINCT(DIFile, (Context, filename.Val, directory.Val, + checksum.Val)); return false; } Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -353,6 +353,7 @@ DwarfOp, // DW_OP_foo DIFlag, // DIFlagFoo DwarfMacinfo, // DW_MACINFO_foo + ChecksumType, // ChecksumType_foo // Type valued tokens (TyVal). Type, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2749,14 +2749,30 @@ break; } - case bitc::METADATA_FILE: { + case bitc::METADATA_CHECKSUM: { if (Record.size() != 3) return error("Invalid record"); IsDistinct = Record[0]; MetadataList.assignValue( - GET_OR_DISTINCT(DIFile, (Context, getMDString(Record[1]), - getMDString(Record[2]))), + GET_OR_DISTINCT(DIChecksum, + (Context, (DIChecksum::ChecksumType)Record[1], + getMDString(Record[2]))), + NextMetadataNo++); + break; + } + + case bitc::METADATA_FILE: { + if (Record.size() < 3 || Record.size() > 4) + return error("Invalid record"); + + IsDistinct = Record[0]; + MetadataList.assignValue( + GET_OR_DISTINCT(DIFile, + (Context, getMDString(Record[1]), + getMDString(Record[2]), + Record.size() == 3 ? nullptr : getMDOrNull(Record[3]) + )), NextMetadataNo++); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -178,6 +178,8 @@ void writeDISubroutineType(const DISubroutineType *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIChecksum(const DIChecksum *N, SmallVectorImpl &Record, + unsigned Abbrev); void writeDIFile(const DIFile *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDICompileUnit(const DICompileUnit *N, @@ -1506,12 +1508,24 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDIChecksum(const DIChecksum *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getType()); + Record.push_back(VE.getMetadataOrNullID(N->getRawData())); + + Stream.EmitRecord(bitc::METADATA_CHECKSUM, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDIFile(const DIFile *N, SmallVectorImpl &Record, unsigned Abbrev) { Record.push_back(N->isDistinct()); Record.push_back(VE.getMetadataOrNullID(N->getRawFilename())); Record.push_back(VE.getMetadataOrNullID(N->getRawDirectory())); + Record.push_back(VE.getMetadataOrNullID(N->getRawChecksum())); Stream.EmitRecord(bitc::METADATA_FILE, Record, Abbrev); Record.clear(); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1408,6 +1408,7 @@ } void printTag(const DINode *N); void printMacinfoType(const DIMacroNode *N); + void printChecksumType(const DIChecksum *N); void printString(StringRef Name, StringRef Value, bool ShouldSkipEmpty = true); void printMetadata(StringRef Name, const Metadata *MD, @@ -1441,6 +1442,10 @@ Out << N->getMacinfoType(); } +void MDFieldPrinter::printChecksumType(const DIChecksum *N) { + Out << FS << "type: " << N->getTypeAsString(); +} + void MDFieldPrinter::printString(StringRef Name, StringRef Value, bool ShouldSkipEmpty) { if (ShouldSkipEmpty && Value.empty()) @@ -1645,14 +1650,26 @@ Out << ")"; } -static void writeDIFile(raw_ostream &Out, const DIFile *N, TypePrinting *, - SlotTracker *, const Module *) { - Out << "!DIFile("; +static void writeDIChecksum(raw_ostream &Out, const DIChecksum *N, + TypePrinting *, SlotTracker *, const Module *) { + Out << "!DIChecksum("; MDFieldPrinter Printer(Out); + Printer.printChecksumType(N); + Printer.printString("data", N->getData(), /* ShouldSkipEmpty */ false); + Out << ")"; +} + +static void writeDIFile(raw_ostream &Out, const DIFile *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DIFile("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); Printer.printString("filename", N->getFilename(), /* ShouldSkipEmpty */ false); Printer.printString("directory", N->getDirectory(), /* ShouldSkipEmpty */ false); + Printer.printMetadata("checksum", N->getRawChecksum(), + /* ShouldSkipEmpty */ true); Out << ")"; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -109,9 +109,10 @@ } DICompileUnit *DIBuilder::createCompileUnit( - unsigned Lang, StringRef Filename, StringRef Directory, StringRef Producer, - bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName, - DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, + unsigned Lang, StringRef Filename, StringRef Directory, + DIChecksum::ChecksumType ChecksumType, StringRef Checksum, + StringRef Producer, bool isOptimized, StringRef Flags, unsigned RunTimeVer, + StringRef SplitName, DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, bool SplitDebugInlining) { assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) || @@ -122,9 +123,11 @@ assert(!CUNode && "Can only make one compile unit per DIBuilder instance"); CUNode = DICompileUnit::getDistinct( - VMContext, Lang, DIFile::get(VMContext, Filename, Directory), Producer, - isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, nullptr, - nullptr, nullptr, nullptr, DWOId, SplitDebugInlining); + VMContext, Lang, + DIFile::get(VMContext, Filename, Directory, + DIChecksum::get(VMContext, ChecksumType, Checksum)), + Producer, isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, + nullptr, nullptr, nullptr, nullptr, DWOId, SplitDebugInlining); // Create a named metadata so that it is easier to find cu in a module. NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); @@ -176,8 +179,14 @@ Context, Decl, Line, Name, AllImportedModules); } -DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory) { - return DIFile::get(VMContext, Filename, Directory); +DIChecksum *DIBuilder::createChecksum(DIChecksum::ChecksumType Type, + StringRef Data) { + return DIChecksum::get(VMContext, Type, Data); +} + +DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, + DIChecksum *Checksum) { + return DIFile::get(VMContext, Filename, Directory, Checksum); } DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -347,13 +347,37 @@ DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops); } +static const char *ChecksumTypeName[DIChecksum::ChecksumTypeNum] = { + "ChecksumType_none", + "ChecksumType_MD5", + "ChecksumType_SHA1", +}; + +StringRef DIChecksum::getTypeAsString() const { return ChecksumTypeName[Type]; } + +DIChecksum::ChecksumType DIChecksum::getChecksumType(StringRef TypeStr) { + return StringSwitch(TypeStr) + .Case("ChecksumType_MD5", DIChecksum::MD5) + .Case("ChecksumType_SHA1", DIChecksum::SHA1) + .Default(DIChecksum::None); +} + +DIChecksum *DIChecksum::getImpl(LLVMContext &Context, ChecksumType Type, + MDString *Data, StorageType Storage, + bool ShouldCreate) { + assert(isCanonical(Data) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIChecksum, (Type, Data)); + Metadata *Ops[] = { Data }; + DEFINE_GETIMPL_STORE(DIChecksum, (Type), Ops); +} + DIFile *DIFile::getImpl(LLVMContext &Context, MDString *Filename, - MDString *Directory, StorageType Storage, - bool ShouldCreate) { + MDString *Directory, Metadata *Checksum, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Filename) && "Expected canonical MDString"); assert(isCanonical(Directory) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIFile, (Filename, Directory)); - Metadata *Ops[] = {Filename, Directory}; + DEFINE_GETIMPL_LOOKUP(DIFile, (Filename, Directory, Checksum)); + Metadata *Ops[] = {Filename, Directory, Checksum}; DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIFile, Ops); } Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -500,20 +500,42 @@ unsigned getHashValue() const { return hash_combine(Flags, CC, TypeArray); } }; +template <> struct MDNodeKeyImpl { + DIChecksum::ChecksumType Type; + MDString *Data; + + MDNodeKeyImpl(DIChecksum::ChecksumType Type, MDString *Data) + : Type(Type), Data(Data) {} + MDNodeKeyImpl(const DIChecksum *N) + : Type(N->getType()), Data(N->getRawData()) {} + + bool isKeyOf(const DIChecksum *RHS) const { + return Type == RHS->getType() && Data == RHS->getRawData(); + } + unsigned getHashValue() const { + return hash_combine(Type, Data); + } +}; + template <> struct MDNodeKeyImpl { MDString *Filename; MDString *Directory; + Metadata *Checksum; - MDNodeKeyImpl(MDString *Filename, MDString *Directory) - : Filename(Filename), Directory(Directory) {} + MDNodeKeyImpl(MDString *Filename, MDString *Directory, Metadata *Checksum) + : Filename(Filename), Directory(Directory), Checksum(Checksum) {} MDNodeKeyImpl(const DIFile *N) - : Filename(N->getRawFilename()), Directory(N->getRawDirectory()) {} + : Filename(N->getRawFilename()), Directory(N->getRawDirectory()), + Checksum(N->getRawChecksum()) {} bool isKeyOf(const DIFile *RHS) const { return Filename == RHS->getRawFilename() && - Directory == RHS->getRawDirectory(); + Directory == RHS->getRawDirectory() && + Checksum == RHS->getRawChecksum(); + } + unsigned getHashValue() const { + return hash_combine(Filename, Directory, Checksum); } - unsigned getHashValue() const { return hash_combine(Filename, Directory); } }; template <> struct MDNodeKeyImpl { Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -937,6 +937,11 @@ "invalid reference flags", &N); } +void Verifier::visitDIChecksum(const DIChecksum &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_null, "invalid tag", &N); + AssertDI(N.getType() != DIChecksum::None, "invalid checksum type", &N); +} + void Verifier::visitDIFile(const DIFile &N) { AssertDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); } Index: test/Assembler/debug-info.ll =================================================================== --- test/Assembler/debug-info.ll +++ test/Assembler/debug-info.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34} +; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36} ; CHECK: !0 = !DISubrange(count: 3) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) @@ -79,3 +79,8 @@ !32 = distinct !{!31} !33 = !DIMacroFile(line: 9, file: !14, nodes: !32) !34 = !DIMacroFile(type: DW_MACINFO_start_file, line: 11, file: !14) + +; CHECK-NEXT: !32 = !DIFile(filename: "path/to/file", directory: "/path/to/dir", checksum: !33) +; CHECK-NEXT: !33 = !DIChecksum(type: ChecksumType_MD5, data: "000102030405060708090a0b0c0d0e0f") +!35 = !DIFile(filename: "path/to/file", directory: "/path/to/dir", checksum: !36) +!36 = !DIChecksum(type: ChecksumType_MD5, data: "000102030405060708090a0b0c0d0e0f") Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -341,7 +341,8 @@ DIBuilder DIB(*M); auto File = DIB.createFile("F.CBL", "/"); auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/", - "llvm-cobol74", true, "", 0); + DIChecksum::None, "", "llvm-cobol74", true, + "", 0); auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); auto SP = DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1, DINode::FlagZero, true); @@ -393,7 +394,7 @@ DIBuilder DIB(*M); auto File = DIB.createFile("tmp.cpp", "/"); auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C_plus_plus_11, "tmp.cpp", "/", - "", true, "", 0); + DIChecksum::None, "", "", true, "", 0); auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); auto SP = DIB.createFunction(CU, "foo", "foo", File, 1, SPType, false, true, 1); @@ -423,7 +424,8 @@ IRBuilder<> Builder(BB); DIBuilder DIB(*M); auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/", - "llvm-cobol74", true, "", 0); + DIChecksum::None, "", "llvm-cobol74", true, + "", 0); DIB.createImportedDeclaration(CU, nullptr, 1); DIB.createImportedDeclaration(CU, nullptr, 1); DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, 2); Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -89,7 +89,7 @@ DINode::FlagZero, false, nullptr); } DIFile *getFile() { - return DIFile::getDistinct(Context, "file.c", "/path/to/dir"); + return DIFile::getDistinct(Context, "file.c", "/path/to/dir", nullptr); } DICompileUnit *getUnit() { return DICompileUnit::getDistinct(Context, 1, getFile(), "clang", false, @@ -1355,20 +1355,40 @@ EXPECT_EQ("", N->getName()); } +typedef MetadataTest DIChecksumTest; + +TEST_F(DIChecksumTest, get) { + StringRef Checksum = "000102030405060708090a0b0c0d0e0f"; + auto *N = DIChecksum::get(Context, DIChecksum::MD5, Checksum); + + EXPECT_EQ(DIChecksum::MD5, N->getType()); + EXPECT_EQ(Checksum, N->getData()); + + EXPECT_NE(N, DIChecksum::get(Context, DIChecksum::SHA1, Checksum)); + EXPECT_NE(N, DIChecksum::get(Context, DIChecksum::MD5, "other")); + + TempDIChecksum Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + typedef MetadataTest DIFileTest; TEST_F(DIFileTest, get) { StringRef Filename = "file"; StringRef Directory = "dir"; - auto *N = DIFile::get(Context, Filename, Directory); + StringRef Checksum = "000102030405060708090a0b0c0d0e0f"; + auto *C = DIChecksum::get(Context, DIChecksum::MD5, Checksum); + auto *N = DIFile::get(Context, Filename, Directory, C); EXPECT_EQ(dwarf::DW_TAG_file_type, N->getTag()); EXPECT_EQ(Filename, N->getFilename()); EXPECT_EQ(Directory, N->getDirectory()); - EXPECT_EQ(N, DIFile::get(Context, Filename, Directory)); + EXPECT_EQ(C, N->getChecksum()); + EXPECT_EQ(N, DIFile::get(Context, Filename, Directory, C)); - EXPECT_NE(N, DIFile::get(Context, "other", Directory)); - EXPECT_NE(N, DIFile::get(Context, Filename, "other")); + EXPECT_NE(N, DIFile::get(Context, "other", Directory, C)); + EXPECT_NE(N, DIFile::get(Context, Filename, "other", C)); + EXPECT_NE(N, DIFile::get(Context, Filename, Directory, nullptr)); TempDIFile Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1376,7 +1396,7 @@ TEST_F(DIFileTest, ScopeGetFile) { // Ensure that DIScope::getFile() returns itself. - DIScope *N = DIFile::get(Context, "file", "dir"); + DIScope *N = DIFile::get(Context, "file", "dir", nullptr); EXPECT_EQ(N, N->getFile()); } Index: unittests/IR/VerifierTest.cpp =================================================================== --- unittests/IR/VerifierTest.cpp +++ unittests/IR/VerifierTest.cpp @@ -154,8 +154,8 @@ LLVMContext C; Module M("M", C); DIBuilder DIB(M); - DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", "unittest", - false, "", 0); + DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", DIChecksum::None, + "", "unittest", false, "", 0); DIB.finalize(); EXPECT_FALSE(verifyModule(M)); @@ -177,7 +177,8 @@ Module M("M", C); DIBuilder DIB(M); auto *CU = DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", - "unittest", false, "", 0); + DIChecksum::None, "", "unittest", false, + "", 0); new GlobalVariable(M, Type::getInt8Ty(C), false, GlobalValue::ExternalLinkage, nullptr, "g"); @@ -208,8 +209,8 @@ LLVMContext C; Module M("M", C); DIBuilder DIB(M); - DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", - "unittest", false, "", 0); + DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", DIChecksum::None, + "", "unittest", false, "", 0); DIB.finalize(); EXPECT_FALSE(verifyModule(M)); Index: unittests/Transforms/Utils/Cloning.cpp =================================================================== --- unittests/Transforms/Utils/Cloning.cpp +++ unittests/Transforms/Utils/Cloning.cpp @@ -233,7 +233,8 @@ DBuilder.createSubroutineType(ParamTypes); auto *CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c", - "/file/dir", "CloneFunc", false, "", 0); + "/file/dir", DIChecksum::None, "", + "CloneFunc", false, "", 0); auto *Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4, FuncType, true, true, 3, @@ -267,8 +268,9 @@ // Create another, empty, compile unit DIBuilder DBuilder2(*M); - DBuilder2.createCompileUnit(dwarf::DW_LANG_C99, - "extra.c", "/file/dir", "CloneFunc", false, "", 0); + DBuilder2.createCompileUnit(dwarf::DW_LANG_C99, "extra.c", "/file/dir", + DIChecksum::None, "", "CloneFunc", false, "", + 0); DBuilder2.finalize(); } @@ -422,9 +424,9 @@ auto *File = DBuilder.createFile("filename.c", "/file/dir/"); DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None); DISubroutineType *DFuncType = DBuilder.createSubroutineType(ParamTypes); - auto *CU = - DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c", - "/file/dir", "CloneModule", false, "", 0); + auto *CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c", + "/file/dir", DIChecksum::None, "", + "CloneModule", false, "", 0); // Function DI auto *Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4, DFuncType, true, true, 3,