diff --git a/clang-tools-extra/clangd/index/Serialization.h b/clang-tools-extra/clangd/index/Serialization.h --- a/clang-tools-extra/clangd/index/Serialization.h +++ b/clang-tools-extra/clangd/index/Serialization.h @@ -28,11 +28,14 @@ #include "index/Index.h" #include "index/Symbol.h" #include "clang/Tooling/CompilationDatabase.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace clang { namespace clangd { +extern llvm::compression::OptionalCompressionKind StringTableCompressionScheme; + enum class IndexFileFormat { RIFF, // Versioned binary format, suitable for production use. YAML, // Human-readable format, suitable for experiments and debugging. diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -28,6 +28,10 @@ namespace clang { namespace clangd { + +llvm::compression::OptionalCompressionKind StringTableCompressionScheme = + llvm::compression::CompressionKind::Zlib; + namespace { // IO PRIMITIVES @@ -192,9 +196,7 @@ RawTable.push_back(0); } llvm::compression::OptionalCompressionKind OptionalCompressionScheme = - llvm::compression::CompressionKind::Zlib; - OptionalCompressionScheme = - compression::noneIfUnsupported(OptionalCompressionScheme); + compression::noneIfUnsupported(StringTableCompressionScheme); if (OptionalCompressionScheme) { llvm::compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; @@ -232,28 +234,34 @@ if (UncompressedSize == 0) // No compression Uncompressed = R.rest(); else { - llvm::compression::CompressionKind CompressionScheme = - llvm::compression::CompressionKind::Zlib; - if (CompressionScheme) { - // Don't allocate a massive buffer if UncompressedSize was corrupted - // This is effective for sharded index, but not big monolithic ones, as - // once compressed size reaches 4MB nothing can be ruled out. - // Theoretical max ratio from https://zlib.net/zlib_tech.html - constexpr int MaxCompressionRatio = 1032; - if ((CompressionScheme == llvm::compression::CompressionKind::Zlib) && - UncompressedSize / MaxCompressionRatio > R.rest().size()) - return error( - "Bad stri table: uncompress {0} -> {1} bytes is implausible", - R.rest().size(), UncompressedSize); - - if (llvm::Error E = CompressionScheme->decompress( - llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, - UncompressedSize)) - return std::move(E); - Uncompressed = toStringRef(UncompressedStorage); - } else - return error("Compressed string table, but " + - (CompressionScheme->Name + " is unavailable").str()); + llvm::compression::OptionalCompressionKind OptionalCompressionScheme = + StringTableCompressionScheme; + if (!OptionalCompressionScheme) { + Uncompressed = R.rest(); + } else { + llvm::compression::CompressionKind CompressionScheme = + *OptionalCompressionScheme; + if (CompressionScheme) { + // Don't allocate a massive buffer if UncompressedSize was corrupted + // This is effective for sharded index, but not big monolithic ones, as + // once compressed size reaches 4MB nothing can be ruled out. + // Theoretical max ratio from https://zlib.net/zlib_tech.html + constexpr int MaxCompressionRatio = 1032; + if ((CompressionScheme == llvm::compression::CompressionKind::Zlib) && + UncompressedSize / MaxCompressionRatio > R.rest().size()) + return error( + "Bad stri table: uncompress {0} -> {1} bytes is implausible", + R.rest().size(), UncompressedSize); + + if (llvm::Error E = CompressionScheme->decompress( + llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, + UncompressedSize)) + return std::move(E); + Uncompressed = toStringRef(UncompressedStorage); + } + } + else return error("Compressed string table, but " + + (CompressionScheme->Name + " is unavailable").str()); } StringTableIn Table; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -726,7 +726,12 @@ /// Describes a source location entry (SLocEntry) for a /// macro expansion. - SM_SLOC_EXPANSION_ENTRY = 5 + SM_SLOC_EXPANSION_ENTRY = 5, + + /// Describes a compressed blob that contains the data for + /// a buffer entry with a size header (like SM_SLOC_BUFFER_BLOB_COMPRESSED) + /// but also a part in the record to indicate which compression algorithm. + SM_SLOC_BUFFER_BLOB_COMPRESSED_DYNAMIC = 6, }; /// Record types used within a preprocessor block. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -35,6 +35,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Support/Compression.h" #include #include #include @@ -93,6 +94,7 @@ using RecordDataRef = ArrayRef; private: + llvm::compression::OptionalCompressionKind OptionalCompressionScheme; /// Map that provides the ID numbers of each type within the /// output stream, plus those deserialized from a chained PCH. /// @@ -538,10 +540,12 @@ public: /// Create a new precompiled header writer that outputs to /// the given bitstream. - ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl &Buffer, - InMemoryModuleCache &ModuleCache, - ArrayRef> Extensions, - bool IncludeTimestamps = true); + ASTWriter( + llvm::BitstreamWriter &Stream, SmallVectorImpl &Buffer, + InMemoryModuleCache &ModuleCache, + ArrayRef> Extensions, + llvm::compression::OptionalCompressionKind OptionalCompressionScheme, + bool IncludeTimestamps = true); ~ASTWriter() override; ASTContext &getASTContext() const { diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -24,6 +24,7 @@ #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -1704,7 +1705,8 @@ std::string Filenames; { llvm::raw_string_ostream OS(Filenames); - CoverageFilenamesSectionWriter(FilenameStrs).write(OS); + CoverageFilenamesSectionWriter(FilenameStrs) + .write(OS, llvm::compression::ZlibCompression); } auto *FilenamesVal = llvm::ConstantDataArray::getString(Ctx, Filenames, false); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1145,6 +1145,13 @@ } else { D.Diag(diag::warn_debug_compression_unavailable); } + } else if (Value == "zstd") { + if (llvm::compression::CompressionKind::ZStd->supported()) { + CmdArgs.push_back( + Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable); + } } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -80,6 +80,7 @@ #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/DJB.h" #include "llvm/Support/ErrorHandling.h" @@ -221,7 +222,8 @@ ASTWriter Writer; ASTWriterData(InMemoryModuleCache &ModuleCache) - : Stream(Buffer), Writer(Stream, Buffer, ModuleCache, {}) {} + : Stream(Buffer), Writer(Stream, Buffer, ModuleCache, {}, + llvm::compression::ZlibCompression) {} }; void ASTUnit::clearFileLevelDecls() { @@ -2323,7 +2325,8 @@ SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); InMemoryModuleCache ModuleCache; - ASTWriter Writer(Stream, Buffer, ModuleCache, {}); + ASTWriter Writer(Stream, Buffer, ModuleCache, {}, + llvm::compression::ZlibCompression); return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1461,8 +1461,12 @@ } unsigned RecCode = MaybeRecCode.get(); - if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { - uint8_t CompressionSchemeId = llvm::compression::CompressionKind::Zlib; + if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED || + RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED_DYNAMIC) { + uint8_t CompressionSchemeId = + RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED + ? uint8_t(llvm::compression::CompressionKind::Zlib) + : Record[1]; llvm::compression::OptionalCompressionKind OptionalCompressionScheme = llvm::compression::getOptionalCompressionKind(CompressionSchemeId); if (!OptionalCompressionScheme) { @@ -1484,6 +1488,7 @@ } return llvm::MemoryBuffer::getMemBufferCopy( llvm::toStringRef(Uncompressed), Name); + } else if (RecCode == SM_SLOC_BUFFER_BLOB) { return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true); } else { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -866,6 +866,7 @@ RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_BUFFER_BLOB_COMPRESSED); RECORD(SM_SLOC_EXPANSION_ENTRY); + RECORD(SM_SLOC_BUFFER_BLOB_COMPRESSED_DYNAMIC); // Preprocessor Block. BLOCK(PREPROCESSOR_BLOCK); @@ -1693,14 +1694,21 @@ /// Create an abbreviation for the SLocEntry that refers to a /// buffer's blob. static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream, - bool Compressed) { + bool Compressed, + bool CompressedDynamic) { using namespace llvm; auto Abbrev = std::make_shared(); - Abbrev->Add(BitCodeAbbrevOp(Compressed ? SM_SLOC_BUFFER_BLOB_COMPRESSED - : SM_SLOC_BUFFER_BLOB)); - if (Compressed) + Abbrev->Add(BitCodeAbbrevOp(CompressedDynamic + ? SM_SLOC_BUFFER_BLOB_COMPRESSED_DYNAMIC + : (Compressed ? SM_SLOC_BUFFER_BLOB_COMPRESSED + : SM_SLOC_BUFFER_BLOB))); + + if (Compressed || CompressedDynamic) Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Uncompressed size + if (CompressedDynamic) { + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Compression Scheme + } Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob return Stream.EmitAbbrev(std::move(Abbrev)); } @@ -1992,15 +2000,16 @@ free(const_cast(SavedStrings[I])); } -static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, - unsigned SLocBufferBlobCompressedAbbrv, - unsigned SLocBufferBlobAbbrv) { +static void +emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, + unsigned SLocBufferBlobCompressedAbbrv, + unsigned SLocBufferBlobCompressedDynamicAbbrv, + unsigned SLocBufferBlobAbbrv, + llvm::compression::OptionalCompressionKind OptionalCompressionScheme) { using RecordDataType = ASTWriter::RecordData::value_type; // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. - llvm::compression::OptionalCompressionKind OptionalCompressionScheme = - llvm::compression::CompressionKind::Zlib; OptionalCompressionScheme = compression::noneIfUnsupported(OptionalCompressionScheme); @@ -2011,8 +2020,19 @@ CompressionScheme->compress(llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); - RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; - Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, + // if our chosen CompressionAlgorithm happens to be zlib output old format + // for extra back compat + if (CompressionScheme == llvm::compression::CompressionKind::Zlib) { + + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, + Blob.size() - 1}; + Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, + llvm::toStringRef(CompressedBuffer)); + return; + } + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED_DYNAMIC, + Blob.size() - 1, uint8_t(CompressionScheme)}; + Stream.EmitRecordWithBlob(SLocBufferBlobCompressedDynamicAbbrv, Record, llvm::toStringRef(CompressedBuffer)); return; } @@ -2040,9 +2060,12 @@ // Abbreviations for the various kinds of source-location entries. unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); - unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream, false); + unsigned SLocBufferBlobAbbrv = + CreateSLocBufferBlobAbbrev(Stream, false, false); unsigned SLocBufferBlobCompressedAbbrv = - CreateSLocBufferBlobAbbrev(Stream, true); + CreateSLocBufferBlobAbbrev(Stream, true, false); + unsigned SLocBufferBlobCompressedDynamicAbbrv = + CreateSLocBufferBlobAbbrev(Stream, true, true); unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream); // Write out the source location entry table. We skip the first @@ -2142,7 +2165,8 @@ Buffer = llvm::MemoryBufferRef("<<>>", ""); StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1); emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv, - SLocBufferBlobAbbrv); + SLocBufferBlobCompressedDynamicAbbrv, SLocBufferBlobAbbrv, + CompressionScheme); } } else { // The source location entry is a macro expansion. @@ -4464,12 +4488,14 @@ SelectorOffsets[ID - FirstSelectorID] = Offset; } -ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream, - SmallVectorImpl &Buffer, - InMemoryModuleCache &ModuleCache, - ArrayRef> Extensions, - bool IncludeTimestamps) +ASTWriter::ASTWriter( + llvm::BitstreamWriter &Stream, SmallVectorImpl &Buffer, + InMemoryModuleCache &ModuleCache, + ArrayRef> Extensions, + llvm::compression::OptionalCompressionKind OptionalCompressionScheme, + bool IncludeTimestamps) : Stream(Stream), Buffer(Buffer), ModuleCache(ModuleCache), + CompressionScheme(CompressionScheme), IncludeTimestamps(IncludeTimestamps) { for (const auto &Ext : Extensions) { if (auto Writer = Ext->createExtensionWriter(*this)) diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Support/Compression.h" using namespace clang; @@ -29,7 +30,7 @@ : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()), SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data), Writer(Stream, this->Buffer->Data, ModuleCache, Extensions, - IncludeTimestamps), + llvm::compression::ZlibCompression, IncludeTimestamps), AllowASTWithErrors(AllowASTWithErrors), ShouldCacheASTInMemory(ShouldCacheASTInMemory), OutputPathIndependent(OutputPathIndependent) { diff --git a/clang/test/CodeGen/coverage-compilation-dir.c b/clang/test/CodeGen/coverage-compilation-dir.c --- a/clang/test/CodeGen/coverage-compilation-dir.c +++ b/clang/test/CodeGen/coverage-compilation-dir.c @@ -1,6 +1,6 @@ // RUN: mkdir -p %t.dir && cd %t.dir // RUN: cp %s rel.c -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-compilation-dir=/nonsense -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false rel.c -o - | FileCheck -check-prefix=CHECK-NONSENSE %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-compilation-dir=/nonsense -fcoverage-mapping -emit-llvm -mllvm -name-compression=none rel.c -o - | FileCheck -check-prefix=CHECK-NONSENSE %s // CHECK-NONSENSE: nonsense diff --git a/clang/test/CoverageMapping/abspath.cpp b/clang/test/CoverageMapping/abspath.cpp --- a/clang/test/CoverageMapping/abspath.cpp +++ b/clang/test/CoverageMapping/abspath.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %S/Inputs/../abspath.cpp -o - | FileCheck -check-prefix=RMDOTS %s +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -name-compression=none -emit-llvm -main-file-name abspath.cpp %S/Inputs/../abspath.cpp -o - | FileCheck -check-prefix=RMDOTS %s // RMDOTS: @__llvm_coverage_mapping = {{.*}}"\02 // RMDOTS-NOT: Inputs @@ -6,7 +6,7 @@ // RUN: mkdir -p %t/test && cd %t/test // RUN: echo "void f1(void) {}" > f1.c -// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %t/test/f1.c -o - | FileCheck -check-prefix=ABSPATH %s +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -name-compression=none -emit-llvm -main-file-name abspath.cpp %t/test/f1.c -o - | FileCheck -check-prefix=ABSPATH %s // RELPATH: @__llvm_coverage_mapping = {{.*}}"\02 // RELPATH: {{..(/|\\\\)test(/|\\\\)f1}}.c diff --git a/clang/test/CoverageMapping/ir.c b/clang/test/CoverageMapping/ir.c --- a/clang/test/CoverageMapping/ir.c +++ b/clang/test/CoverageMapping/ir.c @@ -1,7 +1,7 @@ // Check the data structures emitted by coverage mapping -// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64-apple-macosx10.9 -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -no-opaque-pointers | FileCheck %s -check-prefixes=COMMON,DARWIN -// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64-apple-macosx10.9 -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -opaque-pointers | FileCheck %s -check-prefixes=COMMON,DARWIN -// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64--windows-msvc -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false | FileCheck %s -check-prefixes=COMMON,WINDOWS +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64-apple-macosx10.9 -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -name-compression=none -no-opaque-pointers | FileCheck %s -check-prefixes=COMMON,DARWIN +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64-apple-macosx10.9 -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -name-compression=none -opaque-pointers | FileCheck %s -check-prefixes=COMMON,DARWIN +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64--windows-msvc -main-file-name ir.c %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -mllvm -name-compression=none | FileCheck %s -check-prefixes=COMMON,WINDOWS static inline void unused(void) {} diff --git a/clang/test/Profile/coverage-prefix-map.c b/clang/test/Profile/coverage-prefix-map.c --- a/clang/test/Profile/coverage-prefix-map.c +++ b/clang/test/Profile/coverage-prefix-map.c @@ -5,17 +5,17 @@ // RUN: echo "void f1(void) {}" > %t/root/nested/coverage-prefix-map.c // RUN: cd %t/root -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -name-compression=none -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s // // ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\02.*root.*nested.*coverage-prefix-map\.c}} -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c ../root/nested/coverage-prefix-map.c -o - | FileCheck --check-prefix=RELATIVE %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -name-compression=none -main-file-name coverage-prefix-map.c ../root/nested/coverage-prefix-map.c -o - | FileCheck --check-prefix=RELATIVE %s // // RELATIVE: @__llvm_coverage_mapping = {{.*"\\02.*}}..{{/|\\+}}root{{/|\\+}}nested{{.*coverage-prefix-map\.c}} -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP %s -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c ../root/nested/coverage-prefix-map.c -fcoverage-prefix-map=../root=. -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -name-compression=none -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -name-compression=none -main-file-name coverage-prefix-map.c ../root/nested/coverage-prefix-map.c -fcoverage-prefix-map=../root=. -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP %s // COVERAGE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\02.*}}.{{/|\\+}}nested{{.*coverage-prefix-map\.c}} -// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-compilation-dir=/custom -fcoverage-prefix-map=/custom=/nonsense -o - | FileCheck --check-prefix=COVERAGE-COMPILATION-DIR %s +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -name-compression=none -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-compilation-dir=/custom -fcoverage-prefix-map=/custom=/nonsense -o - | FileCheck --check-prefix=COVERAGE-COMPILATION-DIR %s // COVERAGE-COMPILATION-DIR: @__llvm_coverage_mapping = {{.*"\\02.*}}nonsense diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -648,11 +648,11 @@ /* FIXME: Please remedy the fixme in the header before bumping the version. */ /* Raw profile format version (start from 1). */ -#define INSTR_PROF_RAW_VERSION 8 +#define INSTR_PROF_RAW_VERSION 9 /* Indexed profile format version (start from 1). */ -#define INSTR_PROF_INDEX_VERSION 8 +#define INSTR_PROF_INDEX_VERSION 9 /* Coverage mapping format version (start from 0). */ -#define INSTR_PROF_COVMAP_VERSION 5 +#define INSTR_PROF_COVMAP_VERSION 6 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 diff --git a/compiler-rt/test/profile/instrprof-darwin-dead-strip.c b/compiler-rt/test/profile/instrprof-darwin-dead-strip.c --- a/compiler-rt/test/profile/instrprof-darwin-dead-strip.c +++ b/compiler-rt/test/profile/instrprof-darwin-dead-strip.c @@ -1,7 +1,7 @@ // REQUIRES: osx-ld64-live_support // REQUIRES: lto -// RUN: %clang_profgen=%t.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -Wl,-dead_strip -o %t %s +// RUN: %clang_profgen=%t.profraw -fcoverage-mapping -mllvm -name-compression=none -DCODE=1 -Wl,-dead_strip -o %t %s // RUN: %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw // RUN: llvm-profdata show --all-functions %t.profdata | FileCheck %s -check-prefix=PROF @@ -10,7 +10,7 @@ // RUN: otool -V -s __DATA __llvm_prf_names %t | FileCheck %s -check-prefix=PRF_NAMES // RUN: otool -V -s __DATA __llvm_prf_cnts %t | FileCheck %s -check-prefix=PRF_CNTS -// RUN: %clang_lto_profgen=%t.lto.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -Wl,-dead_strip -flto -o %t.lto %s +// RUN: %clang_lto_profgen=%t.lto.profraw -fcoverage-mapping -mllvm -name-compression=none -DCODE=1 -Wl,-dead_strip -flto -o %t.lto %s // RUN: %run %t.lto // RUN: llvm-profdata merge -o %t.lto.profdata %t.lto.profraw // RUN: llvm-profdata show --all-functions %t.lto.profdata | FileCheck %s -check-prefix=PROF diff --git a/compiler-rt/test/profile/instrprof-gc-sections.c b/compiler-rt/test/profile/instrprof-gc-sections.c --- a/compiler-rt/test/profile/instrprof-gc-sections.c +++ b/compiler-rt/test/profile/instrprof-gc-sections.c @@ -1,7 +1,7 @@ // REQUIRES: linux, lld-available // RUN: rm -rf %t.profraw -// RUN: %clang_profgen=%t.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -o %t %s +// RUN: %clang_profgen=%t.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -name-compression=none -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -o %t %s // RUN: %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw // RUN: llvm-profdata show --all-functions %t.profdata | FileCheck %s -check-prefix=PROF @@ -11,7 +11,7 @@ // RUN: llvm-size -A %t | FileCheck %s -check-prefix=PRF_CNTS // RUN: rm -rf %t.lto.profraw -// RUN: %clang_lto_profgen=%t.lto.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -flto -o %t.lto %s +// RUN: %clang_lto_profgen=%t.lto.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -name-compression=none -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -flto -o %t.lto %s // RUN: %run %t.lto // RUN: llvm-profdata merge -o %t.lto.profdata %t.lto.profraw // RUN: llvm-profdata show --all-functions %t.lto.profdata | FileCheck %s -check-prefix=PROF diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -959,6 +959,9 @@ } else if (s == "zlib") { if (!compression::CompressionKind::Zlib) error("--compress-debug-sections: zlib is not available"); + } else if (s == "zstd") { + if (!compression::CompressionKind::ZStd->supported()) + error("--compress-debug-sections: zstd is not available"); } else { error("unknown --compress-debug-sections value: " + s); } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -110,6 +110,22 @@ return rawData.size() - bytesDropped; } +template +static void uncompressAux(const InputSectionBase *sec, uint8_t *out, + size_t size) { + auto *hdr = + reinterpret_cast(sec->rawData.data()); + ArrayRef compressed = + sec->rawData.slice(sizeof(typename ELFT::Chdr)); + if (Error e = (hdr->ch_type == ELFCOMPRESS_ZLIB + ? compression::CompressionKind::Zlib->decompress( + compressed, out, size) + : compression::CompressionKind::ZStd->decompress( + compressed, out, size))) + fatal(toString(sec) + + ": uncompress failed: " + llvm::toString(std::move(e))); +} + void InputSectionBase::uncompress() const { size_t size = uncompressedSize; uint8_t *uncompressedBuf; @@ -118,11 +134,7 @@ std::lock_guard lock(mu); uncompressedBuf = bAlloc().Allocate(size); } - - if (Error e = compression::CompressionKind::Zlib->decompress( - rawData, uncompressedBuf, size)) - fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); + invokeELFT(uncompressAux, this, uncompressedBuf, size); rawData = makeArrayRef(uncompressedBuf, size); uncompressedSize = -1; } @@ -197,7 +209,7 @@ } // When a section is compressed, `rawData` consists with a header followed -// by zlib-compressed data. This function parses a header to initialize +// by zlib or zstd-compressed data. This function parses a header to initialize // `uncompressedSize` member and remove the header from `rawData`. template void InputSectionBase::parseCompressedHeader() { flags &= ~(uint64_t)SHF_COMPRESSED; @@ -213,6 +225,10 @@ if (!compression::CompressionKind::Zlib) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); + } else if (hdr->ch_type == ELFCOMPRESS_ZSTD) { + if (!compression::CompressionKind::ZStd->supported()) + error(toString(this) + " is compressed with ELFCOMPRESS_ZSTD, but lld is " + "not built with zstd support"); } else { error(toString(this) + ": unsupported compression type (" + Twine(hdr->ch_type) + ")"); @@ -1231,6 +1247,17 @@ fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); } + } else if (hdr->ch_type == ELFCOMPRESS_ZSTD) { + if (!compression::CompressionKind::ZStd->supported()) { + error(toString(this) + + " is compressed with ELFCOMPRESS_ZSTD, but lld is " + "not built with zstd support"); + } else { + if (Error e = compression::CompressionKind::ZStd->decompress( + rawData.slice(sizeof(typename ELFT::Chdr)), buf, size)) + fatal(toString(this) + + ": uncompress failed: " + llvm::toString(std::move(e))); + } } else { error(toString(this) + ": unsupported compression type (" + Twine(hdr->ch_type) + ")"); diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt --- a/lld/test/CMakeLists.txt +++ b/lld/test/CMakeLists.txt @@ -1,6 +1,7 @@ llvm_canonicalize_cmake_booleans( ENABLE_BACKTRACES LLVM_ENABLE_ZLIB + LLVM_ENABLE_ZSTD LLVM_ENABLE_LIBXML2 LLD_DEFAULT_LD_LLD_IS_MINGW LLVM_HAVE_LIBXAR diff --git a/lld/test/ELF/compressed-debug-input-zstd.s b/lld/test/ELF/compressed-debug-input-zstd.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/compressed-debug-input-zstd.s @@ -0,0 +1,42 @@ +# REQUIRES: x86, zstd + +# RUN: llvm-mc -filetype=obj -triple=x86_64 --compress-debug-sections=zstd %s -o %t.o + +# RUN: ld.lld %t.o -o %t.so -shared +# RUN: llvm-readobj --sections --section-data %t.so | FileCheck -check-prefix=DATA %s + +# DATA: Section { +# DATA: Index: 6 +# DATA: Name: .debug_str +# DATA-NEXT: Type: SHT_PROGBITS +# DATA-NEXT: Flags [ +# DATA-NEXT: SHF_MERGE (0x10) +# DATA-NEXT: SHF_STRINGS (0x20) +# DATA-NEXT: ] +# DATA-NEXT: Address: 0x0 +# DATA-NEXT: Offset: +# DATA-NEXT: Size: 69 +# DATA-NEXT: Link: 0 +# DATA-NEXT: Info: 0 +# DATA-NEXT: AddressAlignment: 1 +# DATA-NEXT: EntrySize: 1 +# DATA-NEXT: SectionData ( +# DATA-NEXT: 0000: 756E7369 676E6564 20696E74 00636861 |unsigned int.cha| +# DATA-NEXT: 0010: 7200756E 7369676E 65642063 68617200 |r.unsigned char.| +# DATA-NEXT: 0020: 73686F72 7420756E 7369676E 65642069 |short unsigned i| +# DATA-NEXT: 0030: 6E74006C 6F6E6720 756E7369 676E6564 |nt.long unsigned| +# DATA-NEXT: 0040: 20696E74 00 | int.| +# DATA-NEXT: ) +# DATA-NEXT: } + +.section .debug_str,"MS",@progbits,1 +.LASF2: + .string "short unsigned int" +.LASF3: + .string "unsigned int" +.LASF0: + .string "long unsigned int" +.LASF8: + .string "char" +.LASF1: + .string "unsigned char" diff --git a/lld/test/ELF/compressed-input-err-zstd.s b/lld/test/ELF/compressed-input-err-zstd.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/compressed-input-err-zstd.s @@ -0,0 +1,18 @@ +# UNSUPPORTED: zstd +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}.o:(.debug_info) is compressed with ELFCOMPRESS_ZSTD, but lld is not built with zstd support + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .debug_info + Flags: [ SHF_COMPRESSED ] + AddressAlign: 8 + Content: "020000000000000000000000000000000100000000000000789c030000000001" diff --git a/lld/test/lit.site.cfg.py.in b/lld/test/lit.site.cfg.py.in --- a/lld/test/lit.site.cfg.py.in +++ b/lld/test/lit.site.cfg.py.in @@ -18,6 +18,7 @@ config.target_triple = "@LLVM_TARGET_TRIPLE@" config.python_executable = "@Python3_EXECUTABLE@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +config.have_zstd = @LLVM_ENABLE_ZSTD@ config.have_libxar = @LLVM_HAVE_LIBXAR@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ config.sizeof_void_p = @CMAKE_SIZEOF_VOID_P@ diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1798,6 +1798,7 @@ // Legal values for ch_type field of compressed section header. enum { ELFCOMPRESS_ZLIB = 1, // ZLIB/DEFLATE algorithm. + ELFCOMPRESS_ZSTD = 2, // ZStandard algorithm. ELFCOMPRESS_LOOS = 0x60000000, // Start of OS-specific. ELFCOMPRESS_HIOS = 0x6fffffff, // End of OS-specific. ELFCOMPRESS_LOPROC = 0x70000000, // Start of processor-specific. diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -28,6 +28,7 @@ enum class DebugCompressionType { None, ///< No compression Z, ///< zlib style complession + ZStd, ///< zstd style complession }; enum class EmitDwarfUnwindType { diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -1005,7 +1005,9 @@ // Compilation directory is stored separately and combined with relative // filenames to produce an absolute file path. Version6 = 5, - // The current version is Version6. + // not just zlib compression + Version7 = 6, + // The current version is Version7. CurrentVersion = INSTR_PROF_COVMAP_VERSION }; diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -17,6 +17,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" +#include "llvm/Support/Compression.h" namespace llvm { @@ -32,9 +33,12 @@ public: CoverageFilenamesSectionWriter(ArrayRef Filenames); - /// Write encoded filenames to the given output stream. If \p Compress is - /// true, attempt to compress the filenames. - void write(raw_ostream &OS, bool Compress = true); + /// Write encoded filenames to the given output stream. If \p + /// CompressionScheme is not an instance of + /// llvm::compression::NoneCompressionAlgorithm, attempt to compress the + /// filenames. + void write(raw_ostream &OS, + compression::OptionalCompressionKind OptionalCompressionScheme); }; /// Writer for instrumentation based coverage mapping data. diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -222,8 +222,9 @@ /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. -Error collectPGOFuncNameStrings(ArrayRef NameVars, - std::string &Result, bool doCompression = true); +Error collectPGOFuncNameStrings( + ArrayRef NameVars, std::string &Result, + compression::OptionalCompressionKind OptionalCompressionScheme); /// \c NameStrings is a string composed of one of more sub-strings encoded in /// the format described above. The substrings are separated by 0 or more zero @@ -1024,7 +1025,9 @@ Version7 = 7, // An additional (optional) memory profile type is added. Version8 = 8, - // The current version is 8. + // more compression types + Version9 = 9, + // The current version is 9. CurrentVersion = INSTR_PROF_INDEX_VERSION }; const uint64_t Version = ProfVersion::CurrentVersion; @@ -1201,7 +1204,8 @@ // Whether to compress function names in profile records, and filenames in // code coverage mappings. Used by the Instrumentation library and unit tests. -extern cl::opt DoInstrProfNameCompression; +extern cl::opt + InstrProfNameCompressionScheme; } // end namespace llvm #endif // LLVM_PROFILEDATA_INSTRPROF_H diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc --- a/llvm/include/llvm/ProfileData/InstrProfData.inc +++ b/llvm/include/llvm/ProfileData/InstrProfData.inc @@ -648,11 +648,11 @@ /* FIXME: Please remedy the fixme in the header before bumping the version. */ /* Raw profile format version (start from 1). */ -#define INSTR_PROF_RAW_VERSION 8 +#define INSTR_PROF_RAW_VERSION 9 /* Indexed profile format version (start from 1). */ -#define INSTR_PROF_INDEX_VERSION 8 +#define INSTR_PROF_INDEX_VERSION 9 /* Coverage mapping format version (start from 0). */ -#define INSTR_PROF_COVMAP_VERSION 5 +#define INSTR_PROF_COVMAP_VERSION 6 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h --- a/llvm/include/llvm/ProfileData/SampleProfWriter.h +++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include @@ -56,12 +57,14 @@ /// /// Create a new file writer based on the value of \p Format. static ErrorOr> - create(StringRef Filename, SampleProfileFormat Format); + create(StringRef Filename, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme); /// Create a new stream writer based on the value of \p Format. /// For testing. static ErrorOr> - create(std::unique_ptr &OS, SampleProfileFormat Format); + create(std::unique_ptr &OS, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme); virtual void setProfileSymbolList(ProfileSymbolList *PSL) {} virtual void setToCompressAllSections() {} @@ -70,8 +73,11 @@ virtual void resetSecLayout(SectionLayout SL) {} protected: - SampleProfileWriter(std::unique_ptr &OS) - : OutputStream(std::move(OS)) {} + SampleProfileWriter( + std::unique_ptr &OS, + compression::OptionalCompressionKind OptionalCompressionScheme) + : OutputStream(std::move(OS)), + OptionalCompressionScheme(OptionalCompressionScheme) {} /// Write a file header for the profile file. virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0; @@ -90,6 +96,9 @@ /// Profile format. SampleProfileFormat Format = SPF_None; + + /// Compression scheme; + compression::OptionalCompressionKind OptionalCompressionScheme; }; /// Sample-based profile writer (text format). @@ -98,8 +107,10 @@ std::error_code writeSample(const FunctionSamples &S) override; protected: - SampleProfileWriterText(std::unique_ptr &OS) - : SampleProfileWriter(OS), Indent(0) {} + SampleProfileWriterText( + std::unique_ptr &OS, + compression::OptionalCompressionKind OptionalCompressionScheme) + : SampleProfileWriter(OS, OptionalCompressionScheme), Indent(0) {} std::error_code writeHeader(const SampleProfileMap &ProfileMap) override { return sampleprof_error::success; @@ -112,15 +123,18 @@ unsigned Indent; friend ErrorOr> - SampleProfileWriter::create(std::unique_ptr &OS, - SampleProfileFormat Format); + SampleProfileWriter::create( + std::unique_ptr &OS, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme); }; /// Sample-based profile writer (binary format). class SampleProfileWriterBinary : public SampleProfileWriter { public: - SampleProfileWriterBinary(std::unique_ptr &OS) - : SampleProfileWriter(OS) {} + SampleProfileWriterBinary( + std::unique_ptr &OS, + compression::OptionalCompressionKind OptionalCompressionScheme) + : SampleProfileWriter(OS, OptionalCompressionScheme) {} std::error_code writeSample(const FunctionSamples &S) override; @@ -144,8 +158,9 @@ private: friend ErrorOr> - SampleProfileWriter::create(std::unique_ptr &OS, - SampleProfileFormat Format); + SampleProfileWriter::create( + std::unique_ptr &OS, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme); }; class SampleProfileWriterRawBinary : public SampleProfileWriterBinary { @@ -324,8 +339,10 @@ class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase { public: - SampleProfileWriterExtBinary(std::unique_ptr &OS) - : SampleProfileWriterExtBinaryBase(OS) {} + SampleProfileWriterExtBinary( + std::unique_ptr &OS, + compression::OptionalCompressionKind OptionalCompressionScheme) + : SampleProfileWriterExtBinaryBase(OS, OptionalCompressionScheme) {} private: std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap); diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -27,8 +27,10 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" @@ -1157,6 +1159,30 @@ //-------------------------------------------------- +extern template class basic_parser; + +template <> +class parser + : public basic_parser { +public: + parser(Option &O) : basic_parser(O) {} + + // Return true on error. + bool parse(Option &, StringRef, StringRef Arg, + compression::OptionalCompressionKind &Value); + + // Overload in subclass to provide a better default value. + StringRef getValueName() const override { return "compression scheme"; } + + void printOptionDiff(const Option &O, compression::OptionalCompressionKind V, + OptVal Default, size_t GlobalWidth) const; + + // An out-of-line virtual method to provide a 'home' for this class. + void anchor() override; +}; + +//-------------------------------------------------- + extern template class basic_parser; template <> class parser : public basic_parser { diff --git a/llvm/include/llvm/Support/Compression.h b/llvm/include/llvm/Support/Compression.h --- a/llvm/include/llvm/Support/Compression.h +++ b/llvm/include/llvm/Support/Compression.h @@ -93,6 +93,13 @@ } } +// so that commanbd line option implementation works +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const CompressionKind &B) { + OS << (B->Name); + return OS; +} + constexpr bool operator==(CompressionKind left, CompressionKind right) { return uint8_t(left) == uint8_t(right); } diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h --- a/llvm/include/llvm/Transforms/Instrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation.h @@ -19,6 +19,7 @@ #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" +#include "llvm/Support/Compression.h" #include #include #include @@ -120,6 +121,8 @@ // Name of the profile file to use as output std::string InstrProfileOutput; + compression::OptionalCompressionKind OptionalCompressionScheme; + InstrProfOptions() = default; }; diff --git a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h --- a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h +++ b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h @@ -18,6 +18,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PassManager.h" #include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Compression.h" #include "llvm/Transforms/Instrumentation.h" #include #include @@ -134,6 +135,7 @@ /// Create a static initializer for our data, on platforms that need it, /// and for any profile output file that was specified. void emitInitialization(); + compression::OptionalCompressionKind OptionalCompressionScheme; }; } // end namespace llvm diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -144,7 +144,8 @@ uint64_t align(unsigned Alignment); - bool maybeWriteCompression(uint32_t ChType, uint64_t Size, + bool maybeWriteCompression(DebugCompressionType CompressionType, + uint64_t Size, SmallVectorImpl &CompressedContents, unsigned Alignment); @@ -818,12 +819,24 @@ // Include the debug info compression header. bool ELFWriter::maybeWriteCompression( - uint32_t ChType, uint64_t Size, + DebugCompressionType CompressionType, uint64_t Size, SmallVectorImpl &CompressedContents, unsigned Alignment) { uint64_t HdrSize = is64Bit() ? sizeof(ELF::Elf32_Chdr) : sizeof(ELF::Elf64_Chdr); if (Size <= HdrSize + CompressedContents.size()) return false; + uint64_t ChType; + switch (CompressionType) { + case DebugCompressionType::Z: + ChType = ELF::ELFCOMPRESS_ZLIB; + break; + case DebugCompressionType::ZStd: + ChType = ELF::ELFCOMPRESS_ZSTD; + break; + default: + return false; + } + // Platform specific header is followed by compressed data. if (is64Bit()) { // Write Elf64_Chdr header. @@ -854,22 +867,34 @@ return; } - assert(CompressionType == DebugCompressionType::Z && - "expected zlib style compression"); + assert((CompressionType == DebugCompressionType::Z || + CompressionType == DebugCompressionType::ZStd) && + "expected zlib or zstd style compression"); SmallVector UncompressedData; raw_svector_ostream VecOS(UncompressedData); Asm.writeSectionData(VecOS, &Section, Layout); SmallVector Compressed; - const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::CompressionKind::Zlib->compress( - makeArrayRef(reinterpret_cast(UncompressedData.data()), - UncompressedData.size()), - Compressed); - - if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed, - Sec.getAlignment())) { + switch (CompressionType) { + case DebugCompressionType::Z: + compression::CompressionKind::Zlib->compress( + makeArrayRef(reinterpret_cast(UncompressedData.data()), + UncompressedData.size()), + Compressed); + break; + case DebugCompressionType::ZStd: + compression::CompressionKind::ZStd->compress( + makeArrayRef(reinterpret_cast(UncompressedData.data()), + UncompressedData.size()), + Compressed); + break; + case DebugCompressionType::None: + break; + } + + if (!maybeWriteCompression(CompressionType, UncompressedData.size(), + Compressed, Sec.getAlignment())) { W.OS << UncompressedData; return; } diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -441,9 +441,9 @@ SmallVector DecompressedContent; DebugCompressionType CompressionType = reinterpret_cast *>(Sec.OriginalData.data()) - ->ch_type == ELF::ELFCOMPRESS_ZLIB - ? DebugCompressionType::Z - : DebugCompressionType::None; + ->ch_type == ELF::ELFCOMPRESS_ZSTD + ? DebugCompressionType::ZStd + : DebugCompressionType::Z; switch (CompressionType) { case DebugCompressionType::Z: @@ -454,6 +454,14 @@ "': " + toString(std::move(Err1))); } break; + case DebugCompressionType::ZStd: + if (Error Err = compression::CompressionKind::ZStd->decompress( + Compressed, DecompressedContent, static_cast(Sec.Size))) { + return createStringError(errc::invalid_argument, + "'" + Sec.Name + + "': " + toString(std::move(Err))); + } + break; case DebugCompressionType::None: llvm_unreachable("unexpected DebugCompressionType::None"); break; @@ -513,6 +521,9 @@ case DebugCompressionType::Z: Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB; break; + case DebugCompressionType::ZStd: + Chdr.ch_type = ELF::ELFCOMPRESS_ZSTD; + break; } Chdr.ch_size = Sec.DecompressedSize; Chdr.ch_addralign = Sec.DecompressedAlign; @@ -531,6 +542,9 @@ case DebugCompressionType::Z: compression::CompressionKind::Zlib->compress(OriginalData, CompressedData); break; + case DebugCompressionType::ZStd: + compression::CompressionKind::ZStd->compress(OriginalData, CompressedData); + break; case DebugCompressionType::None: break; } diff --git a/llvm/lib/Object/Decompressor.cpp b/llvm/lib/Object/Decompressor.cpp --- a/llvm/lib/Object/Decompressor.cpp +++ b/llvm/lib/Object/Decompressor.cpp @@ -42,6 +42,8 @@ &Offset, Is64Bit ? sizeof(Elf64_Word) : sizeof(Elf32_Word)); if (ELFCompressionSchemeId == ELFCOMPRESS_ZLIB) { CompressionScheme = compression::CompressionKind::Zlib; + } else if (ELFCompressionSchemeId == ELFCOMPRESS_ZSTD) { + CompressionScheme = compression::CompressionKind::ZStd; } else { return createError("unsupported compression type"); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -119,28 +119,47 @@ return Err; if (CompressedLen > 0) { - if (!compression::CompressionKind::Zlib) - return make_error( - coveragemap_error::decompression_failed); - - // Allocate memory for the decompressed filenames. - SmallVector StorageBuf; - - // Read compressed filenames. - StringRef CompressedFilenames = Data.substr(0, CompressedLen); - Data = Data.substr(CompressedLen); - auto Err = compression::CompressionKind::Zlib->decompress( - arrayRefFromStringRef(CompressedFilenames), StorageBuf, - UncompressedLen); - if (Err) { - consumeError(std::move(Err)); - return make_error( - coveragemap_error::decompression_failed); + compression::OptionalCompressionKind OptionalCompressionScheme = + compression::CompressionKind::Zlib; + if (Version >= CovMapVersion::Version7) { + uint64_t CompressionSchemeId; + if (auto Err = readULEB128(CompressionSchemeId)) + return Err; + OptionalCompressionScheme = + compression::getOptionalCompressionKind(CompressionSchemeId); } + if (OptionalCompressionScheme) { + compression::CompressionKind CompressionScheme = + *OptionalCompressionScheme; + if (!CompressionScheme) + return make_error( + coveragemap_error::decompression_failed); + + // Allocate memory for the decompressed filenames. + SmallVector StorageBuf; + + // Read compressed filenames. + StringRef CompressedFilenames = Data.substr(0, CompressedLen); + Data = Data.substr(CompressedLen); + auto Err = CompressionScheme->decompress( + arrayRefFromStringRef(CompressedFilenames), StorageBuf, + UncompressedLen); + if (Err) { + consumeError(std::move(Err)); + return make_error( + coveragemap_error::decompression_failed); + } - RawCoverageFilenamesReader Delegate(toStringRef(StorageBuf), Filenames, - CompilationDir); - return Delegate.readUncompressed(Version, NumFilenames); + RawCoverageFilenamesReader Delegate(toStringRef(StorageBuf), Filenames, + CompilationDir); + return Delegate.readUncompressed(Version, NumFilenames); + } else { + StringRef CompressedFilenames = Data.substr(0, CompressedLen); + Data = Data.substr(CompressedLen); + RawCoverageFilenamesReader Delegate(CompressedFilenames, Filenames, + CompilationDir); + return Delegate.readUncompressed(Version, NumFilenames); + } } return readUncompressed(Version, NumFilenames); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -37,7 +37,9 @@ #endif } -void CoverageFilenamesSectionWriter::write(raw_ostream &OS, bool Compress) { +void CoverageFilenamesSectionWriter::write( + raw_ostream &OS, + compression::OptionalCompressionKind OptionalCompressionScheme) { std::string FilenamesStr; { raw_string_ostream FilenamesOS{FilenamesStr}; @@ -48,17 +50,15 @@ } SmallVector CompressedStr; - compression::OptionalCompressionKind OptionalCompressionScheme = - compression::CompressionKind::Zlib; - - OptionalCompressionScheme = compression::noneIfUnsupported( - (Compress && DoInstrProfNameCompression) ? OptionalCompressionScheme - : llvm::NoneType()); + OptionalCompressionScheme = + compression::noneIfUnsupported(OptionalCompressionScheme); + compression::CompressionKind CompressionScheme = + compression::CompressionKind::Unknown; bool doCompression = bool(OptionalCompressionScheme); if (doCompression) { - compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; + CompressionScheme = *OptionalCompressionScheme; CompressionScheme->compress(arrayRefFromStringRef(FilenamesStr), CompressedStr, CompressionScheme->BestSizeLevel); @@ -67,10 +67,14 @@ // ::= // // + // IF compressed: + // // ( | ) encodeULEB128(Filenames.size(), OS); encodeULEB128(FilenamesStr.size(), OS); encodeULEB128(doCompression ? CompressedStr.size() : 0U, OS); + if (doCompression) + encodeULEB128(uint8_t(CompressionScheme), OS); OS << (doCompression ? toStringRef(CompressedStr) : StringRef(FilenamesStr)); } diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -205,9 +205,11 @@ namespace llvm { -cl::opt DoInstrProfNameCompression( - "enable-name-compression", - cl::desc("Enable name/filename string compression"), cl::init(true)); +cl::opt InstrProfNameCompressionScheme( + "name-compression", + cl::desc("Scheme for name/filename string compression (none/zlib/ztsd), " + "defaults to zstd"), + cl::init(compression::CompressionKind::ZStd)); std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, @@ -452,25 +454,39 @@ unsigned EncLen = encodeULEB128(UncompressedNameStrings.length(), P); P += EncLen; - auto WriteStringToResult = [&](size_t CompressedLen, StringRef InputStr) { - EncLen = encodeULEB128(CompressedLen, P); - P += EncLen; - char *HeaderStr = reinterpret_cast(&Header[0]); - unsigned HeaderLen = P - &Header[0]; - Result.append(HeaderStr, HeaderLen); - Result += InputStr; - return Error::success(); + auto WriteStringToResult = [&](size_t CompressedLen, + uint8_t CompressionSchemeId, + StringRef InputStr) { + if (CompressedLen == 0) { + EncLen = encodeULEB128(CompressedLen, P); + P += EncLen; + char *HeaderStr = reinterpret_cast(&Header[0]); + unsigned HeaderLen = P - &Header[0]; + Result.append(HeaderStr, HeaderLen); + Result += InputStr; + return Error::success(); + } else { + EncLen = encodeULEB128(CompressedLen, P); + P += EncLen; + EncLen = encodeULEB128(CompressionSchemeId, P); + P += EncLen; + char *HeaderStr = reinterpret_cast(&Header[0]); + unsigned HeaderLen = P - &Header[0]; + Result.append(HeaderStr, HeaderLen); + Result += InputStr; + return Error::success(); + } }; if ((!OptionalCompressionScheme) || (!(*OptionalCompressionScheme))) - return WriteStringToResult(0, UncompressedNameStrings); + return WriteStringToResult(0, 0, UncompressedNameStrings); compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; SmallVector CompressedNameStrings; CompressionScheme->compress(arrayRefFromStringRef(UncompressedNameStrings), CompressedNameStrings, CompressionScheme->BestSizeLevel); - return WriteStringToResult(CompressedNameStrings.size(), + return WriteStringToResult(CompressedNameStrings.size(), CompressionScheme, toStringRef(CompressedNameStrings)); } @@ -481,18 +497,16 @@ return NameStr; } -Error collectPGOFuncNameStrings(ArrayRef NameVars, - std::string &Result, bool doCompression) { +Error collectPGOFuncNameStrings( + ArrayRef NameVars, std::string &Result, + compression::OptionalCompressionKind OptionalCompressionScheme) { std::vector NameStrs; for (auto *NameVar : NameVars) { NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); } - compression::OptionalCompressionKind OptionalCompressionScheme = - compression::CompressionKind::Zlib; + return collectPGOFuncNameStrings( - NameStrs, - compression::noneIfUnsupported(doCompression ? OptionalCompressionScheme - : llvm::NoneType()), + NameStrs, compression::noneIfUnsupported(OptionalCompressionScheme), Result); } @@ -506,11 +520,19 @@ uint64_t CompressedSize = decodeULEB128(P, &N); P += N; bool isCompressed = (CompressedSize != 0); + compression::OptionalCompressionKind OptionalCompressionScheme = + llvm::NoneType(); + if (isCompressed) { + uint64_t CompressionSchemeId = decodeULEB128(P, &N); + P += N; + OptionalCompressionScheme = + compression::getOptionalCompressionKind(CompressionSchemeId); + } SmallVector UncompressedNameStrings; StringRef NameStrings; - if (isCompressed) { + if (isCompressed && bool(OptionalCompressionScheme)) { compression::CompressionKind CompressionScheme = - compression::CompressionKind::Zlib; + *OptionalCompressionScheme; if (!CompressionScheme) return make_error(instrprof_error::zlib_unavailable); @@ -522,6 +544,7 @@ } P += CompressedSize; NameStrings = toStringRef(UncompressedNameStrings); + } else { NameStrings = StringRef(reinterpret_cast(P), UncompressedSize); @@ -1352,7 +1375,7 @@ // When a new field is added in the header add a case statement here to // populate it. static_assert( - IndexedInstrProf::ProfVersion::CurrentVersion == Version8, + IndexedInstrProf::ProfVersion::CurrentVersion == Version9, "Please update the reading code below if a new field has been added, " "if not add a case statement to fall through to the latest version."); case 8ull: @@ -1371,7 +1394,7 @@ // When a new field is added to the header add a case statement here to // compute the size as offset of the new field + size of the new field. This // relies on the field being added to the end of the list. - static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version8, + static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version9, "Please update the size computation below if a new field has " "been added to the header, if not add a case statement to " "fall through to the latest version."); diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -877,17 +877,32 @@ if (std::error_code EC = CompressSize.getError()) return EC; - if (!llvm::compression::CompressionKind::Zlib) - return sampleprof_error::zlib_unavailable; - - uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); - size_t UCSize = DecompressBufSize; - llvm::Error E = compression::CompressionKind::Zlib->decompress( - makeArrayRef(Data, *CompressSize), Buffer, UCSize); - if (E) - return sampleprof_error::uncompress_failed; - DecompressBuf = reinterpret_cast(Buffer); - return sampleprof_error::success; + auto CompressionSchemeId = readNumber(); + if (std::error_code EC = CompressionSchemeId.getError()) + return EC; + compression::OptionalCompressionKind OptionalCompressionScheme = + compression::getOptionalCompressionKind(*CompressionSchemeId); + if (OptionalCompressionScheme) { + compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; + if (!CompressionScheme) + return sampleprof_error::zlib_unavailable; + + uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); + size_t UCSize = DecompressBufSize; + llvm::Error E = CompressionScheme->decompress( + makeArrayRef(Data, *CompressSize), Buffer, UCSize); + if (E) + return sampleprof_error::uncompress_failed; + DecompressBuf = reinterpret_cast(Buffer); + return sampleprof_error::success; + } else { + + DecompressBufSize = *CompressSize; + uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); + memcpy(Buffer, Data, DecompressBufSize); + DecompressBuf = reinterpret_cast(Buffer); + return sampleprof_error::success; + } } std::error_code SampleProfileReaderExtBinaryBase::readImpl() { diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp --- a/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -78,24 +78,39 @@ } std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { - compression::CompressionKind CompressionScheme = - compression::CompressionKind::Zlib; - if (!CompressionScheme) - return sampleprof_error::zlib_unavailable; - std::string &UncompressedStrings = - static_cast(LocalBufStream.get())->str(); - if (UncompressedStrings.size() == 0) + if (!OptionalCompressionScheme) { + std::string &UncompressedStrings = + static_cast(LocalBufStream.get())->str(); + if (UncompressedStrings.size() == 0) + return sampleprof_error::success; + auto &OS = *OutputStream; + encodeULEB128(UncompressedStrings.size(), OS); + encodeULEB128(UncompressedStrings.size(), OS); + encodeULEB128(uint8_t(0), OS); + OS << UncompressedStrings; + UncompressedStrings.clear(); return sampleprof_error::success; - auto &OS = *OutputStream; - SmallVector CompressedStrings; - CompressionScheme->compress(arrayRefFromStringRef(UncompressedStrings), - CompressedStrings, - CompressionScheme->BestSizeLevel); - encodeULEB128(UncompressedStrings.size(), OS); - encodeULEB128(CompressedStrings.size(), OS); - OS << toStringRef(CompressedStrings); - UncompressedStrings.clear(); - return sampleprof_error::success; + } else { + compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; + + if (!CompressionScheme) + return sampleprof_error::zlib_unavailable; + std::string &UncompressedStrings = + static_cast(LocalBufStream.get())->str(); + if (UncompressedStrings.size() == 0) + return sampleprof_error::success; + auto &OS = *OutputStream; + SmallVector CompressedStrings; + CompressionScheme->compress(arrayRefFromStringRef(UncompressedStrings), + CompressedStrings, + CompressionScheme->BestSizeLevel); + encodeULEB128(UncompressedStrings.size(), OS); + encodeULEB128(CompressedStrings.size(), OS); + encodeULEB128(uint8_t(CompressionScheme), OS); + OS << toStringRef(CompressedStrings); + UncompressedStrings.clear(); + return sampleprof_error::success; + } } /// Add a new section into section header table given the section type @@ -842,8 +857,9 @@ /// \param Format Encoding format for the profile file. /// /// \returns an error code indicating the status of the created writer. -ErrorOr> -SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { +ErrorOr> SampleProfileWriter::create( + StringRef Filename, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme) { std::error_code EC; std::unique_ptr OS; if (Format == SPF_Binary || Format == SPF_Ext_Binary || @@ -854,7 +870,7 @@ if (EC) return EC; - return create(OS, Format); + return create(OS, Format, OptionalCompressionScheme); } /// Create a sample profile stream writer based on the specified format. @@ -864,9 +880,9 @@ /// \param Format Encoding format for the profile file. /// /// \returns an error code indicating the status of the created writer. -ErrorOr> -SampleProfileWriter::create(std::unique_ptr &OS, - SampleProfileFormat Format) { +ErrorOr> SampleProfileWriter::create( + std::unique_ptr &OS, SampleProfileFormat Format, + compression::OptionalCompressionKind OptionalCompressionScheme) { std::error_code EC; std::unique_ptr Writer; @@ -876,13 +892,16 @@ return sampleprof_error::unsupported_writing_format; if (Format == SPF_Binary) - Writer.reset(new SampleProfileWriterRawBinary(OS)); + Writer.reset( + new SampleProfileWriterRawBinary(OS, OptionalCompressionScheme)); else if (Format == SPF_Ext_Binary) - Writer.reset(new SampleProfileWriterExtBinary(OS)); + Writer.reset( + new SampleProfileWriterExtBinary(OS, OptionalCompressionScheme)); else if (Format == SPF_Compact_Binary) - Writer.reset(new SampleProfileWriterCompactBinary(OS)); + Writer.reset( + new SampleProfileWriterCompactBinary(OS, OptionalCompressionScheme)); else if (Format == SPF_Text) - Writer.reset(new SampleProfileWriterText(OS)); + Writer.reset(new SampleProfileWriterText(OS, OptionalCompressionScheme)); else if (Format == SPF_GCC) EC = sampleprof_error::unsupported_writing_format; else diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -43,6 +44,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -67,6 +69,7 @@ template class basic_parser; template class basic_parser; template class basic_parser; +template class basic_parser; template class basic_parser; template class opt; @@ -74,6 +77,7 @@ template class opt; template class opt; template class opt; +template class opt; } // namespace cl } // namespace llvm @@ -95,6 +99,7 @@ void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} +void parser::anchor() {} //===----------------------------------------------------------------------===// @@ -1767,7 +1772,12 @@ else Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName, 0); - Errs << " option: " << Message << "\n"; + Errs << " option:\n"; + Errs << "- "; + Errs.changeColor(raw_ostream::RED, true); + Errs << "error:"; + Errs.resetColor(); + Errs << " " << Message << "\n"; return true; } @@ -1913,6 +1923,33 @@ "' is invalid value for boolean argument! Try 0 or 1"); } +// parser implementation +// +bool parser::parse( + Option &O, StringRef, StringRef Arg, + compression::OptionalCompressionKind &Value) { + Value = llvm::StringSwitch(Arg.str()) + .Case("none", NoneType()) + .Case("zlib", compression::CompressionKind::Zlib) + .Case("zstd", compression::CompressionKind::ZStd) + .Default(compression::CompressionKind::Unknown); + if (bool(Value) && ((*Value) == compression::CompressionKind::Unknown)) { + + StringRef ArgName = O.ArgStr; + errs() << GlobalParser->ProgramName << ": "; + errs() << "for the " << PrintArg(ArgName, 0) << " option:\n"; + errs() << "- "; + WithColor::error() << ("'" + Arg.str() + + "' is not a recognized compression scheme!") + << "\n"; + outs() << "- "; + WithColor::note() << "Try one of none, zstd, or zlib" + << "\n"; + return true; + } + return false; +} + // parser implementation // bool parser::parse(Option &O, StringRef ArgName, StringRef Arg, @@ -2158,6 +2195,7 @@ PRINT_OPT_DIFF(unsigned long long) PRINT_OPT_DIFF(double) PRINT_OPT_DIFF(float) +PRINT_OPT_DIFF(compression::OptionalCompressionKind) PRINT_OPT_DIFF(char) void parser::printOptionDiff(const Option &O, StringRef V, diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -1118,7 +1118,7 @@ std::string CompressedNameStr; if (Error E = collectPGOFuncNameStrings(ReferencedNames, CompressedNameStr, - DoInstrProfNameCompression)) { + InstrProfNameCompressionScheme)) { report_fatal_error(Twine(toString(std::move(E))), false); } diff --git a/llvm/test/tools/llvm-cov/coverage-prefix-map.test b/llvm/test/tools/llvm-cov/coverage-prefix-map.test --- a/llvm/test/tools/llvm-cov/coverage-prefix-map.test +++ b/llvm/test/tools/llvm-cov/coverage-prefix-map.test @@ -20,7 +20,7 @@ # cd %S/Inputs/coverage_prefix_map cp -r . /tmp/coverage_prefix_map -clang -fprofile-instr-generate -mllvm -enable-name-compression=false -fcoverage-mapping -fcoverage-prefix-map=$PWD=. main.cc -o main +clang -fprofile-instr-generate -mllvm -name-compression=none -fcoverage-mapping -fcoverage-prefix-map=$PWD=. main.cc -o main LLVM_PROFILE_FILE="main.raw" ./main llvm-profdata merge main.raw -o main.profdata llvm-cov convert-for-testing ./main -o ./main.covmapping diff --git a/llvm/test/tools/llvm-cov/multiple-objects-not-all-instrumented.test b/llvm/test/tools/llvm-cov/multiple-objects-not-all-instrumented.test --- a/llvm/test/tools/llvm-cov/multiple-objects-not-all-instrumented.test +++ b/llvm/test/tools/llvm-cov/multiple-objects-not-all-instrumented.test @@ -7,6 +7,6 @@ Instructions for regenerating the test: clang -std=c++11 not_instrumented.cc -o not_instrumented -clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping instrumented.cc -o instrumented +clang -std=c++11 -mllvm -name-compression=none -fprofile-instr-generate -fcoverage-mapping instrumented.cc -o instrumented LLVM_PROFILE_FILE="instrumented.raw" ./instrumented llvm-profdata merge instrumented.raw -o instrumented.profdata diff --git a/llvm/test/tools/llvm-cov/multiple-objects.test b/llvm/test/tools/llvm-cov/multiple-objects.test --- a/llvm/test/tools/llvm-cov/multiple-objects.test +++ b/llvm/test/tools/llvm-cov/multiple-objects.test @@ -13,8 +13,8 @@ Instructions for regenerating the test: -clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping use_1.cc -o use_1 -clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping use_2.cc -o use_2 +clang -std=c++11 -mllvm -name-compression=none -fprofile-instr-generate -fcoverage-mapping use_1.cc -o use_1 +clang -std=c++11 -mllvm -name-compression=none -fprofile-instr-generate -fcoverage-mapping use_2.cc -o use_2 LLVM_PROFILE_FILE="use_1.raw" ./use_1 LLVM_PROFILE_FILE="use_2.raw" ./use_2 llvm-profdata merge use_{1,2}.raw -o merged.profdata diff --git a/llvm/test/tools/llvm-cov/multithreaded-report.test b/llvm/test/tools/llvm-cov/multithreaded-report.test --- a/llvm/test/tools/llvm-cov/multithreaded-report.test +++ b/llvm/test/tools/llvm-cov/multithreaded-report.test @@ -84,7 +84,7 @@ cp -r . /tmp/multithreaded_report -clang++ -std=c++11 -mllvm -enable-name-compression=false \ +clang++ -std=c++11 -mllvm -name-compression=none \ -fprofile-instr-generate -fcoverage-mapping \ /tmp/multithreaded_report/*.cc -o main diff --git a/llvm/test/tools/llvm-cov/sources-specified.test b/llvm/test/tools/llvm-cov/sources-specified.test --- a/llvm/test/tools/llvm-cov/sources-specified.test +++ b/llvm/test/tools/llvm-cov/sources-specified.test @@ -53,7 +53,7 @@ # cd %S/Inputs/sources_specified cp -r . /tmp/sources_specified -clang -mllvm -enable-name-compression=false -fprofile-instr-generate \ +clang -mllvm -name-compression=none -fprofile-instr-generate \ -fcoverage-mapping /tmp/sources_specified/main.cc -o main LLVM_PROFILE_FILE="main.raw" ./main diff --git a/llvm/test/tools/llvm-profdata/c-general.test b/llvm/test/tools/llvm-profdata/c-general.test --- a/llvm/test/tools/llvm-profdata/c-general.test +++ b/llvm/test/tools/llvm-profdata/c-general.test @@ -5,7 +5,7 @@ $ CFE=$SRC/tools/clang $ TESTDIR=$SRC/test/tools/llvm-profdata $ CFE_TESTDIR=$CFE/test/Profile -$ clang -o a.out -fprofile-instr-generate $CFE_TESTDIR/c-general.c -mllvm -enable-name-compression=false +$ clang -o a.out -fprofile-instr-generate $CFE_TESTDIR/c-general.c -mllvm -name-compression=none $ LLVM_PROFILE_FILE=$TESTDIR/Inputs/c-general.profraw ./a.out RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s diff --git a/llvm/test/tools/llvm-profdata/memprof-merge.test b/llvm/test/tools/llvm-profdata/memprof-merge.test --- a/llvm/test/tools/llvm-profdata/memprof-merge.test +++ b/llvm/test/tools/llvm-profdata/memprof-merge.test @@ -21,7 +21,7 @@ ``` # Collect instrprof profile with name compression disabled since some buildbots # do not have zlib. -clang -mllvm -enable-name-compression=false -fprofile-generate source.c -o instr.out +clang -mllvm -name-compression=none -fprofile-generate source.c -o instr.out ./instr.out mv *.profraw basic.profraw diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -401,10 +401,18 @@ MAI->setRelaxELFRelocations(RelaxELFRel); if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::CompressionKind::Zlib) { - WithColor::error(errs(), ProgName) - << "build tools with zlib to enable -compress-debug-sections"; - return 1; + if (CompressDebugSections == DebugCompressionType::Z) { + if (!compression::CompressionKind::Zlib) { + WithColor::error(errs(), ProgName) + << "build tools with zlib to enable -compress-debug-sections=zlib"; + return 1; + } + } else if (CompressDebugSections == DebugCompressionType::ZStd) { + if (!compression::CompressionKind::ZStd) { + WithColor::error(errs(), ProgName) + << "build tools with zstd to enable -compress-debug-sections=zstd"; + return 1; + } } MAI->setCompressDebugSections(CompressDebugSections); } diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -722,7 +722,9 @@ if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) { Config.CompressionType = StringSwitch(A->getValue()) .Case("zlib", DebugCompressionType::Z) + .Case("zstd", DebugCompressionType::ZStd) .Default(DebugCompressionType::None); + if (Config.CompressionType == DebugCompressionType::None) return createStringError( errc::invalid_argument, @@ -737,6 +739,12 @@ errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); break; + case DebugCompressionType::ZStd: + if (!compression::CompressionKind::ZStd) + return createStringError( + errc::invalid_argument, + "LLVM was not compiled with LLVM_ENABLE_ZSTD: can not compress"); + break; } } @@ -999,11 +1007,6 @@ "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !compression::CompressionKind::Zlib) - return createStringError( - errc::invalid_argument, - "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); - if (Config.ExtractPartition && Config.ExtractMainPartition) return createStringError(errc::invalid_argument, "cannot specify --extract-partition together with " diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td --- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -33,7 +33,7 @@ : Joined<["--"], "compress-debug-sections=">, MetaVarName<"format">, HelpText<"Compress DWARF debug sections using specified format. Supported " - "formats: zlib">; + "formats: zlib, zstd">; def : Flag<["--"], "compress-debug-sections">, Alias, AliasArgs<["zlib"]>; def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">, diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -25,6 +25,7 @@ #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Discriminator.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" @@ -829,7 +830,8 @@ } auto WriterOrErr = - SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); + SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat], + compression::CompressionKind::Zlib); if (std::error_code EC = WriterOrErr.getError()) exitWithErrorCode(EC, OutputFilename); diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/llvm/tools/llvm-profgen/ProfileGenerator.cpp --- a/llvm/tools/llvm-profgen/ProfileGenerator.cpp +++ b/llvm/tools/llvm-profgen/ProfileGenerator.cpp @@ -160,7 +160,8 @@ } void ProfileGeneratorBase::write() { - auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); + auto WriterOrErr = SampleProfileWriter::create( + OutputFilename, OutputFormat, compression::CompressionKind::Zlib); if (std::error_code EC = WriterOrErr.getError()) exitWithError(EC, OutputFilename); diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp --- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp +++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp @@ -932,7 +932,9 @@ { raw_string_ostream OS(EncodedFilenames); CoverageFilenamesSectionWriter Writer(Paths); - Writer.write(OS, Compress); + Writer.write(OS, Compress ? (compression::OptionalCompressionKind) + compression::CompressionKind::Zlib + : NoneType()); } std::vector ReadFilenames; @@ -956,7 +958,9 @@ { raw_string_ostream OS(EncodedFilenames); CoverageFilenamesSectionWriter Writer(Paths); - Writer.write(OS, Compress); + Writer.write(OS, Compress ? (compression::OptionalCompressionKind) + compression::CompressionKind::Zlib + : NoneType()); } StringRef CompilationDir = "out"; diff --git a/llvm/unittests/ProfileData/SampleProfTest.cpp b/llvm/unittests/ProfileData/SampleProfTest.cpp --- a/llvm/unittests/ProfileData/SampleProfTest.cpp +++ b/llvm/unittests/ProfileData/SampleProfTest.cpp @@ -50,7 +50,8 @@ std::error_code EC; std::unique_ptr OS( new raw_fd_ostream(Profile, EC, sys::fs::OF_None)); - auto WriterOrErr = SampleProfileWriter::create(OS, Format); + auto WriterOrErr = SampleProfileWriter::create( + OS, Format, compression::CompressionKind::Zlib); ASSERT_TRUE(NoError(WriterOrErr.getError())); Writer = std::move(WriterOrErr.get()); }