Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -4007,10 +4007,13 @@ .. code-block:: llvm - !0 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") + !0 = !DIFile(filename: "path/to/file", directory: "/path/to/dir", + checksumkind: CSK_MD5, + checksum: "000102030405060708090a0b0c0d0e0f") Files are sometimes used in ``scope:`` fields, and are the only valid target for ``file:`` fields. +Valid values for ``checksumkind:`` field are: {CSK_None, CSK_MD5, CSK_SHA1} .. _DIBasicType: Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -231,7 +231,7 @@ METADATA_SUBRANGE = 13, // [distinct, count, lo] METADATA_ENUMERATOR = 14, // [distinct, value, name] METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] - METADATA_FILE = 16, // [distinct, filename, directory] + METADATA_FILE = 16, // [distinct, filename, directory, checksumkind, checksum] METADATA_DERIVED_TYPE = 17, // [distinct, ...] METADATA_COMPOSITE_TYPE = 18, // [distinct, ...] METADATA_SUBROUTINE_TYPE = 19, // [distinct, flags, types, cc] Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -107,9 +107,14 @@ 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 file descriptor to hold debugging information for a file. + /// \param File File name. + /// \param Dir Directory. + /// \param CSKind Checksum kind (e.g. CSK_None, CSK_MD5, CSK_SHA1, etc.). + /// \param Checksum Checksum data. + DIFile *createFile(StringRef Filename, StringRef Directory, + DIFile::ChecksumKind CSKind = DIFile::CSK_None, + StringRef Checksum = StringRef()); /// 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 @@ -470,38 +470,62 @@ friend class LLVMContextImpl; friend class MDNode; - DIFile(LLVMContext &C, StorageType Storage, ArrayRef Ops) - : DIScope(C, DIFileKind, Storage, dwarf::DW_TAG_file_type, Ops) {} +public: + enum ChecksumKind { + CSK_None, + CSK_MD5, + CSK_SHA1, + CSK_Num // Should be last enumeration. + }; + +private: + ChecksumKind CSKind; + + DIFile(LLVMContext &C, StorageType Storage, ChecksumKind CSK, + ArrayRef Ops) + : DIScope(C, DIFileKind, Storage, dwarf::DW_TAG_file_type, Ops), + CSKind(CSK) {} ~DIFile() = default; static DIFile *getImpl(LLVMContext &Context, StringRef Filename, - StringRef Directory, StorageType Storage, - bool ShouldCreate = true) { + StringRef Directory, ChecksumKind CSK, StringRef CS, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, getCanonicalMDString(Context, Filename), - getCanonicalMDString(Context, Directory), Storage, - ShouldCreate); + getCanonicalMDString(Context, Directory), CSK, + getCanonicalMDString(Context, CS), Storage, ShouldCreate); } static DIFile *getImpl(LLVMContext &Context, MDString *Filename, - MDString *Directory, StorageType Storage, - bool ShouldCreate = true); + MDString *Directory, ChecksumKind CSK, MDString *CS, + StorageType Storage, bool ShouldCreate = true); TempDIFile cloneImpl() const { - return getTemporary(getContext(), getFilename(), getDirectory()); + return getTemporary(getContext(), getFilename(), getDirectory(), + getChecksumKind(), 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, + ChecksumKind CSK = CSK_None, + StringRef CS = StringRef()), + (Filename, Directory, CSK, CS)) + DEFINE_MDNODE_GET(DIFile, (MDString *Filename, MDString *Directory, + ChecksumKind CSK = CSK_None, + MDString *CS = nullptr), + (Filename, Directory, CSK, CS)) TempDIFile clone() const { return cloneImpl(); } StringRef getFilename() const { return getStringOperand(0); } StringRef getDirectory() const { return getStringOperand(1); } + StringRef getChecksum() const { return getStringOperand(2); } + ChecksumKind getChecksumKind() const { return CSKind; } + StringRef getChecksumKindAsString() const; MDString *getRawFilename() const { return getOperandAs(0); } MDString *getRawDirectory() const { return getOperandAs(1); } + MDString *getRawChecksum() const { return getOperandAs(2); } + + static ChecksumKind getChecksumKind(StringRef CSKindStr); static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIFileKind; 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("CSK_")) { + StrVal.assign(Keyword.begin(), Keyword.end()); + return lltok::ChecksumKind; + } + 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 ChecksumKindField : public MDFieldImpl { + ChecksumKindField() : ImplTy(DIFile::CSK_None) {} + ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {} +}; + } // end anonymous namespace namespace llvm { @@ -3739,6 +3744,20 @@ return false; } +template <> +bool LLParser::ParseMDField(LocTy Loc, StringRef Name, + ChecksumKindField &Result) { + if (Lex.getKind() != lltok::ChecksumKind) + return TokError( + "invalid checksum kind" + Twine(" '") + Lex.getStrVal() + "'"); + + DIFile::ChecksumKind CSKind = DIFile::getChecksumKind(Lex.getStrVal()); + + Result.assign(CSKind); + Lex.Lex(); + return false; +} + } // end namespace llvm template @@ -3968,15 +3987,20 @@ } /// ParseDIFileType: -/// ::= !DIFileType(filename: "path/to/file", directory: "/path/to/dir") +/// ::= !DIFileType(filename: "path/to/file", directory: "/path/to/dir" +/// checksumkind: CSK_MD5, +/// checksum: "000102030405060708090a0b0c0d0e0f") bool LLParser::ParseDIFile(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(filename, MDStringField, ); \ - REQUIRED(directory, MDStringField, ); + REQUIRED(directory, MDStringField, ); \ + OPTIONAL(checksumkind, ChecksumKindField, ); \ + OPTIONAL(checksum, MDStringField, ); 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, + checksumkind.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 + ChecksumKind, // CSK_foo // Type valued tokens (TyVal). Type, Index: lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- lib/Bitcode/Reader/MetadataLoader.cpp +++ lib/Bitcode/Reader/MetadataLoader.cpp @@ -770,13 +770,19 @@ } case bitc::METADATA_FILE: { - if (Record.size() != 3) + if (Record.size() != 3 && Record.size() != 5) return error("Invalid record"); IsDistinct = Record[0]; MetadataList.assignValue( - GET_OR_DISTINCT(DIFile, (Context, getMDString(Record[1]), - getMDString(Record[2]))), + GET_OR_DISTINCT(DIFile, + (Context, getMDString(Record[1]), + getMDString(Record[2]), + Record.size() == 3 ? + DIFile::CSK_None : + static_cast(Record[3]), + Record.size() == 3 ? nullptr : getMDString(Record[4]) + )), NextMetadataNo++); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1512,6 +1512,8 @@ Record.push_back(N->isDistinct()); Record.push_back(VE.getMetadataOrNullID(N->getRawFilename())); Record.push_back(VE.getMetadataOrNullID(N->getRawDirectory())); + Record.push_back(N->getChecksumKind()); + 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 printChecksumKind(const DIFile *N); void printString(StringRef Name, StringRef Value, bool ShouldSkipEmpty = true); void printMetadata(StringRef Name, const Metadata *MD, @@ -1441,6 +1442,13 @@ Out << N->getMacinfoType(); } +void MDFieldPrinter::printChecksumKind(const DIFile *N) { + if (N->getChecksumKind() == DIFile::CSK_None) + // Skip CSK_None checksum kind. + return; + Out << FS << "checksumkind: " << N->getChecksumKindAsString(); +} + void MDFieldPrinter::printString(StringRef Name, StringRef Value, bool ShouldSkipEmpty) { if (ShouldSkipEmpty && Value.empty()) @@ -1653,6 +1661,8 @@ /* ShouldSkipEmpty */ false); Printer.printString("directory", N->getDirectory(), /* ShouldSkipEmpty */ false); + Printer.printChecksumKind(N); + Printer.printString("checksum", N->getChecksum(), /* ShouldSkipEmpty */ true); Out << ")"; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -174,8 +174,9 @@ Context, Decl, Line, Name, AllImportedModules); } -DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory) { - return DIFile::get(VMContext, Filename, Directory); +DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, + DIFile::ChecksumKind CSKind, StringRef Checksum) { + return DIFile::get(VMContext, Filename, Directory, CSKind, Checksum); } DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -347,14 +347,34 @@ DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops); } +static const char *ChecksumKindName[DIFile::CSK_Num] = { + "CSK_None", + "CSK_MD5", + "CSK_SHA1" +}; + +DIFile::ChecksumKind DIFile::getChecksumKind(StringRef CSKindStr) { + return StringSwitch(CSKindStr) + .Case("CSK_MD5", DIFile::CSK_MD5) + .Case("CSK_SHA1", DIFile::CSK_SHA1) + .Default(DIFile::CSK_None); +} + +StringRef DIFile::getChecksumKindAsString() const { + return ChecksumKindName[CSKind]; +} + DIFile *DIFile::getImpl(LLVMContext &Context, MDString *Filename, - MDString *Directory, StorageType Storage, + MDString *Directory, DIFile::ChecksumKind CSKind, + MDString *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_STORE_NO_CONSTRUCTOR_ARGS(DIFile, Ops); + assert((CSKind == DIFile::CSK_None || isCanonical(Checksum)) && + "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIFile, (Filename, Directory, CSKind, Checksum)); + Metadata *Ops[] = {Filename, Directory, Checksum}; + DEFINE_GETIMPL_STORE(DIFile, (CSKind), Ops); } DICompileUnit *DICompileUnit::getImpl( Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -503,17 +503,26 @@ template <> struct MDNodeKeyImpl { MDString *Filename; MDString *Directory; + DIFile::ChecksumKind CSKind; + MDString *Checksum; - MDNodeKeyImpl(MDString *Filename, MDString *Directory) - : Filename(Filename), Directory(Directory) {} + MDNodeKeyImpl(MDString *Filename, MDString *Directory, + DIFile::ChecksumKind CSKind, MDString *Checksum) + : Filename(Filename), Directory(Directory), CSKind(CSKind), + Checksum(Checksum) {} MDNodeKeyImpl(const DIFile *N) - : Filename(N->getRawFilename()), Directory(N->getRawDirectory()) {} + : Filename(N->getRawFilename()), Directory(N->getRawDirectory()), + CSKind(N->getChecksumKind()), Checksum(N->getRawChecksum()) {} bool isKeyOf(const DIFile *RHS) const { return Filename == RHS->getRawFilename() && - Directory == RHS->getRawDirectory(); + Directory == RHS->getRawDirectory() && + CSKind == RHS->getChecksumKind() && + Checksum == RHS->getRawChecksum(); + } + unsigned getHashValue() const { + return hash_combine(Filename, Directory, CSKind, 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 @@ -966,6 +966,8 @@ void Verifier::visitDIFile(const DIFile &N) { AssertDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); + AssertDI((N.getChecksumKind() != DIFile::CSK_None || + N.getChecksum().empty()), "invalid checksum kind", &N); } void Verifier::visitDICompileUnit(const DICompileUnit &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, !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, !37} ; CHECK: !0 = !DISubrange(count: 3) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) @@ -79,3 +79,9 @@ !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: "file", directory: "dir", checksumkind: CSK_MD5, checksum: "000102030405060708090a0b0c0d0e0f") +; CHECK-NEXT: !33 = !DIFile(filename: "file", directory: "dir") +!35 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_MD5, checksum: "000102030405060708090a0b0c0d0e0f") +!36 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None) +!37 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None, checksum: "") \ No newline at end of file Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -1360,15 +1360,21 @@ TEST_F(DIFileTest, get) { StringRef Filename = "file"; StringRef Directory = "dir"; - auto *N = DIFile::get(Context, Filename, Directory); + DIFile::ChecksumKind CSKind = DIFile::CSK_MD5; + StringRef Checksum = "000102030405060708090a0b0c0d0e0f"; + auto *N = DIFile::get(Context, Filename, Directory, CSKind, Checksum); 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_NE(N, DIFile::get(Context, "other", Directory)); - EXPECT_NE(N, DIFile::get(Context, Filename, "other")); + EXPECT_EQ(CSKind, N->getChecksumKind()); + EXPECT_EQ(Checksum, N->getChecksum()); + EXPECT_EQ(N, DIFile::get(Context, Filename, Directory, CSKind, Checksum)); + + EXPECT_NE(N, DIFile::get(Context, "other", Directory, CSKind, Checksum)); + EXPECT_NE(N, DIFile::get(Context, Filename, "other", CSKind, Checksum)); + EXPECT_NE(N, DIFile::get(Context, Filename, Directory, DIFile::CSK_SHA1, Checksum)); + EXPECT_NE(N, DIFile::get(Context, Filename, Directory)); TempDIFile Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));