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 @@ -190,10 +190,12 @@ RawTable.append(std::string(S)); RawTable.push_back(0); } - if (llvm::compression::zlib::isAvailable()) { + llvm::compression::CompressionAlgorithm CompressionScheme = + llvm::compression::ZlibCompressionAlgorithm(); + if (CompressionScheme.supported()) { llvm::SmallVector Compressed; - llvm::compression::zlib::compress(llvm::arrayRefFromStringRef(RawTable), - Compressed); + CompressionScheme.compress( + llvm::arrayRefFromStringRef(RawTable), Compressed); write32(RawTable.size(), OS); OS << llvm::toStringRef(Compressed); } else { @@ -224,7 +226,10 @@ llvm::SmallVector UncompressedStorage; if (UncompressedSize == 0) // No compression Uncompressed = R.rest(); - else if (llvm::compression::zlib::isAvailable()) { + else { + llvm::compression::CompressionAlgorithm CompressionScheme = + llvm::compression::ZlibCompressionAlgorithm(); + if (CompressionScheme.supported()) { // 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. @@ -234,13 +239,16 @@ return error("Bad stri table: uncompress {0} -> {1} bytes is implausible", R.rest().size(), UncompressedSize); - if (llvm::Error E = llvm::compression::zlib::uncompress( - llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, - 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 zlib is unavailable"); + return error("Compressed string table, but " + + (CompressionScheme.name + " is unavailable").str()); + } StringTableIn Table; llvm::StringSaver Saver(Table.Arena); diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp --- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp +++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp @@ -391,7 +391,7 @@ // Check we detect invalid string table size size without allocating it first. // If this detection fails, the test should allocate a huge array and crash. TEST(SerializationTest, NoCrashOnBadStringTableSize) { - if (!llvm::compression::zlib::isAvailable()) { + if (!llvm::compression::ZlibCompressionAlgorithm().supported()) { log("skipping test, no zlib"); return; } 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 @@ -1139,7 +1139,7 @@ if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); } else if (Value == "zlib") { - if (llvm::compression::zlib::isAvailable()) { + if (llvm::compression::ZlibCompressionAlgorithm().supported()) { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { 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 @@ -1462,12 +1462,17 @@ unsigned RecCode = MaybeRecCode.get(); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { - if (!llvm::compression::zlib::isAvailable()) { - Error("zlib is not available"); + uint8_t CompressionSchemeId =static_cast( + llvm::compression::ZlibCompressionAlgorithm().AlgorithmId); + llvm::compression::CompressionAlgorithm CompressionScheme = + llvm::compression::CompressionAlgorithmFromId(CompressionSchemeId); + if (!CompressionScheme.supported()) { + Error("compression class " + + (CompressionScheme.name + " is not available").str()); return nullptr; } SmallVector Uncompressed; - if (llvm::Error E = llvm::compression::zlib::uncompress( + if (llvm::Error E = CompressionScheme.decompress( llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) { Error("could not decompress embedded file contents: " + llvm::toString(std::move(E))); 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 @@ -2000,11 +2000,17 @@ // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. + llvm::compression::CompressionAlgorithm CompressionScheme = + llvm::compression::ZlibCompressionAlgorithm(); + + if (CompressionScheme.supported()) { + SmallVector CompressedBuffer; - if (llvm::compression::zlib::isAvailable()) { - llvm::compression::zlib::compress( - llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); - RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; + + CompressionScheme.compress(llvm::arrayRefFromStringRef(Blob.drop_back(1)), + CompressedBuffer); + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, + Blob.size() - 1}; Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, llvm::toStringRef(CompressedBuffer)); return; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -953,12 +953,15 @@ static bool getCompressDebugSections(opt::InputArgList &args) { StringRef s = args.getLastArgValue(OPT_compress_debug_sections, "none"); - if (s == "none") + if (s == "none") { return false; - if (s != "zlib") + } else if (s == "zlib") { + if (!compression::ZlibCompressionAlgorithm().supported()) + error("--compress-debug-sections: zlib is not available"); + } else { error("unknown --compress-debug-sections value: " + s); - if (!compression::zlib::isAvailable()) - error("--compress-debug-sections: zlib is not available"); + } + return true; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -118,7 +118,7 @@ uncompressedBuf = bAlloc().Allocate(size); } - if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size)) + if (Error e = compression::ZlibCompressionAlgorithm().decompress(rawData, uncompressedBuf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); rawData = makeArrayRef(uncompressedBuf, size); @@ -208,7 +208,7 @@ auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type == ELFCOMPRESS_ZLIB) { - if (!compression::zlib::isAvailable()) + if (!compression::ZlibCompressionAlgorithm().supported()) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); } else { @@ -219,7 +219,6 @@ uncompressedSize = hdr->ch_size; alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -1217,10 +1216,24 @@ // If this is a compressed section, uncompress section contents directly // to the buffer. if (uncompressedSize >= 0) { + auto *hdr = reinterpret_cast(rawData.data()); size_t size = uncompressedSize; - if (Error e = compression::zlib::uncompress(rawData, buf, size)) - fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); + if (hdr->ch_type == ELFCOMPRESS_ZLIB) { + if (!compression::ZlibCompressionAlgorithm().supported()) { + error(toString(this) + + " is compressed with ELFCOMPRESS_ZLIB, but lld is " + "not built with zlib support"); + } else { + if (Error e = compression::ZlibCompressionAlgorithm().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) + ")"); + return; + } uint8_t *bufEnd = buf + size; relocate(buf, bufEnd); return; diff --git a/llvm/include/llvm/Object/Decompressor.h b/llvm/include/llvm/Object/Decompressor.h --- a/llvm/include/llvm/Object/Decompressor.h +++ b/llvm/include/llvm/Object/Decompressor.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace llvm { @@ -44,10 +45,11 @@ private: Decompressor(StringRef Data); - Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian); + Error consumeCompressedSectionHeader(bool Is64Bit, bool IsLittleEndian); StringRef SectionData; uint64_t DecompressedSize; + compression::CompressionAlgorithm CompressionScheme; }; } // end namespace object 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 @@ -15,55 +15,154 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" namespace llvm { template class SmallVectorImpl; class Error; namespace compression { -namespace zlib { -constexpr int NoCompression = 0; -constexpr int BestSpeedCompression = 1; -constexpr int DefaultCompression = 6; -constexpr int BestSizeCompression = 9; - -bool isAvailable(); - -void compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, - int Level = DefaultCompression); - -Error uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize); - -Error uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize); - -} // End of namespace zlib - -namespace zstd { - -constexpr int NoCompression = -5; -constexpr int BestSpeedCompression = 1; -constexpr int DefaultCompression = 5; -constexpr int BestSizeCompression = 12; - -bool isAvailable(); - -void compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, - int Level = DefaultCompression); - -Error uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize); - -Error uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize); - -} // End of namespace zstd +enum class SupportCompressionType : uint8_t { + Base = 255, ///< Abstract compression + None = 0, ///< No compression + Zlib = 1, ///< zlib style complession + ZStd = 2, ///< zstd style complession +}; + +// This is the base class of all compression algorithms that llvm support +// handles. +class CompressionAlgorithm { +public: + static constexpr SupportCompressionType AlgorithmId = + SupportCompressionType::Base; + static constexpr StringRef name = "base"; + static constexpr int BestSpeedCompression = -999; + static constexpr int DefaultCompression = -999; + static constexpr int BestSizeCompression = -999; + + // // estimates level to achive compression speed around scale*(speed at level + // which has max (speed*ratio) on mozilla-unified Bundle) int + // levelToTargetCompressionSpeed(float scale){ + // return 1; + // }; + bool supported(); + + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level = DefaultCompression); + + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + + Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = decompress(Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + constexpr CompressionAlgorithm(){}; +}; + +class NoneCompressionAlgorithm : public CompressionAlgorithm { + using super = CompressionAlgorithm; + +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::None; + constexpr static StringRef name = "none"; + constexpr static int BestSpeedCompression = 0; + constexpr static int DefaultCompression = 0; + constexpr static int BestSizeCompression = 0; + + bool supported(); + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level = DefaultCompression); + + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + + Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = decompress(Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + + constexpr NoneCompressionAlgorithm() : super(){}; +}; + +class ZlibCompressionAlgorithm : public CompressionAlgorithm { + using super = CompressionAlgorithm; + +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::Zlib; + constexpr static StringRef name = "zlib"; + constexpr static int BestSpeedCompression = 1; + constexpr static int DefaultCompression = 6; + constexpr static int BestSizeCompression = 9; + + bool supported(); + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level = DefaultCompression); + + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + + Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = decompress(Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + constexpr ZlibCompressionAlgorithm() : super(){}; +}; + +class ZStdCompressionAlgorithm : public CompressionAlgorithm { + using super = CompressionAlgorithm; + +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::ZStd; + constexpr static StringRef name = "zstd"; + constexpr static int BestSpeedCompression = 1; + constexpr static int DefaultCompression = 5; + constexpr static int BestSizeCompression = 12; + + bool supported(); + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level = DefaultCompression); + + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + + Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = decompress(Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + constexpr ZStdCompressionAlgorithm() : super(){}; +}; +llvm::compression::CompressionAlgorithm +CompressionAlgorithmFromId(uint8_t CompressionSchemeId); } // End of namespace compression 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 @@ -848,15 +848,14 @@ auto &MC = Asm.getContext(); const auto &MAI = MC.getAsmInfo(); - - bool CompressionEnabled = - MAI->compressDebugSections() != DebugCompressionType::None; + const DebugCompressionType CompressionType = MAI->compressDebugSections(); + bool CompressionEnabled = CompressionType != DebugCompressionType::None; if (!CompressionEnabled || !SectionName.startswith(".debug_")) { Asm.writeSectionData(W.OS, &Section, Layout); return; } - assert(MAI->compressDebugSections() == DebugCompressionType::Z && + assert(CompressionType == DebugCompressionType::Z && "expected zlib style compression"); SmallVector UncompressedData; @@ -865,7 +864,7 @@ SmallVector Compressed; const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( + compression::ZlibCompressionAlgorithm().compress( makeArrayRef(reinterpret_cast(UncompressedData.data()), UncompressedData.size()), Compressed); 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 @@ -439,10 +439,25 @@ ArrayRef Compressed = Sec.OriginalData.slice(sizeof(Elf_Chdr_Impl)); SmallVector DecompressedContent; - if (Error Err = compression::zlib::uncompress(Compressed, DecompressedContent, - static_cast(Sec.Size))) - return createStringError(errc::invalid_argument, - "'" + Sec.Name + "': " + toString(std::move(Err))); + DebugCompressionType CompressionType = + reinterpret_cast *>(Sec.OriginalData.data()) + ->ch_type == ELF::ELFCOMPRESS_ZLIB + ? DebugCompressionType::Z + : DebugCompressionType::None; + + switch (CompressionType) { + case DebugCompressionType::Z: + if (Error Err1 = compression::ZlibCompressionAlgorithm().decompress( + Compressed, DecompressedContent, static_cast(Sec.Size))) { + return createStringError(errc::invalid_argument, + "'" + Sec.Name + + "': " + toString(std::move(Err1))); + } + break; + case DebugCompressionType::None: + llvm_unreachable("unexpected DebugCompressionType::None"); + break; + } uint8_t *Buf = reinterpret_cast(Out.getBufferStart()) + Sec.Offset; std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); @@ -512,7 +527,14 @@ DebugCompressionType CompressionType) : SectionBase(Sec), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { - compression::zlib::compress(OriginalData, CompressedData); + switch (CompressionType) { + case DebugCompressionType::Z: + compression::ZlibCompressionAlgorithm().compress(OriginalData, + CompressedData); + break; + case DebugCompressionType::None: + break; + } assert(CompressionType != DebugCompressionType::None); Flags |= ELF::SHF_COMPRESSED; 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 @@ -19,11 +19,9 @@ Expected Decompressor::create(StringRef Name, StringRef Data, bool IsLE, bool Is64Bit) { - if (!compression::zlib::isAvailable()) - return createError("zlib is not available"); Decompressor D(Data); - if (Error Err = D.consumeCompressedZLibHeader(Is64Bit, IsLE)) + if (Error Err = D.consumeCompressedSectionHeader(Is64Bit, IsLE)) return std::move(Err); return D; } @@ -31,8 +29,8 @@ Decompressor::Decompressor(StringRef Data) : SectionData(Data), DecompressedSize(0) {} -Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit, - bool IsLittleEndian) { +Error Decompressor::consumeCompressedSectionHeader(bool Is64Bit, + bool IsLittleEndian) { using namespace ELF; uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); if (SectionData.size() < HdrSize) @@ -40,10 +38,15 @@ DataExtractor Extractor(SectionData, IsLittleEndian, 0); uint64_t Offset = 0; - if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) - : sizeof(Elf32_Word)) != - ELFCOMPRESS_ZLIB) + uint64_t ELFCompressionSchemeId = Extractor.getUnsigned( + &Offset, Is64Bit ? sizeof(Elf64_Word) : sizeof(Elf32_Word)); + if (ELFCompressionSchemeId == ELFCOMPRESS_ZLIB) { + CompressionScheme = compression::ZlibCompressionAlgorithm(); + } else { return createError("unsupported compression type"); + } + if (!CompressionScheme.supported()) + return createError(CompressionScheme.name + " is not available"); // Skip Elf64_Chdr::ch_reserved field. if (Is64Bit) @@ -57,6 +60,6 @@ Error Decompressor::decompress(MutableArrayRef Buffer) { size_t Size = Buffer.size(); - return compression::zlib::uncompress(arrayRefFromStringRef(SectionData), - Buffer.data(), Size); + return CompressionScheme.decompress(arrayRefFromStringRef(SectionData), + Buffer.data(), Size); } 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,7 +119,7 @@ return Err; if (CompressedLen > 0) { - if (!compression::zlib::isAvailable()) + if (!compression::ZlibCompressionAlgorithm().supported()) return make_error( coveragemap_error::decompression_failed); @@ -129,7 +129,7 @@ // Read compressed filenames. StringRef CompressedFilenames = Data.substr(0, CompressedLen); Data = Data.substr(CompressedLen); - auto Err = compression::zlib::uncompress( + auto Err = compression::ZlibCompressionAlgorithm().decompress( arrayRefFromStringRef(CompressedFilenames), StorageBuf, UncompressedLen); if (Err) { 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 @@ -47,12 +47,14 @@ } SmallVector CompressedStr; - bool doCompression = Compress && compression::zlib::isAvailable() && - DoInstrProfNameCompression; + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); + bool doCompression = + Compress && CompressionScheme.supported() && DoInstrProfNameCompression; if (doCompression) - compression::zlib::compress(arrayRefFromStringRef(FilenamesStr), - CompressedStr, - compression::zlib::BestSizeCompression); + CompressionScheme.compress(arrayRefFromStringRef(FilenamesStr), + CompressedStr, + CompressionScheme.BestSizeCompression); // ::= // 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 @@ -463,11 +463,12 @@ if (!doCompression) { return WriteStringToResult(0, UncompressedNameStrings); } - + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); SmallVector CompressedNameStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings), - CompressedNameStrings, - compression::zlib::BestSizeCompression); + CompressionScheme.compress(arrayRefFromStringRef(UncompressedNameStrings), + CompressedNameStrings, + CompressionScheme.BestSizeCompression); return WriteStringToResult(CompressedNameStrings.size(), toStringRef(CompressedNameStrings)); @@ -486,11 +487,16 @@ for (auto *NameVar : NameVars) { NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); } + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); return collectPGOFuncNameStrings( - NameStrs, compression::zlib::isAvailable() && doCompression, Result); + NameStrs, CompressionScheme.supported() && doCompression, Result); } Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); + const uint8_t *P = NameStrings.bytes_begin(); const uint8_t *EndP = NameStrings.bytes_end(); while (P < EndP) { @@ -503,10 +509,10 @@ SmallVector UncompressedNameStrings; StringRef NameStrings; if (isCompressed) { - if (!llvm::compression::zlib::isAvailable()) + if (!CompressionScheme.supported()) return make_error(instrprof_error::zlib_unavailable); - if (Error E = compression::zlib::uncompress( + if (Error E = CompressionScheme.decompress( makeArrayRef(P, CompressedSize), UncompressedNameStrings, UncompressedSize)) { consumeError(std::move(E)); 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,12 +877,12 @@ if (std::error_code EC = CompressSize.getError()) return EC; - if (!llvm::compression::zlib::isAvailable()) + if (!llvm::compression::ZlibCompressionAlgorithm().supported()) return sampleprof_error::zlib_unavailable; uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); size_t UCSize = DecompressBufSize; - llvm::Error E = compression::zlib::uncompress( + llvm::Error E = compression::ZlibCompressionAlgorithm().decompress( makeArrayRef(Data, *CompressSize), Buffer, UCSize); if (E) return sampleprof_error::uncompress_failed; 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,7 +78,9 @@ } std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { - if (!llvm::compression::zlib::isAvailable()) + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); + if (!CompressionScheme.supported()) return sampleprof_error::zlib_unavailable; std::string &UncompressedStrings = static_cast(LocalBufStream.get())->str(); @@ -86,9 +88,9 @@ return sampleprof_error::success; auto &OS = *OutputStream; SmallVector CompressedStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), - CompressedStrings, - compression::zlib::BestSizeCompression); + CompressionScheme.compress(arrayRefFromStringRef(UncompressedStrings), + CompressedStrings, + CompressionScheme.BestSizeCompression); encodeULEB128(UncompressedStrings.size(), OS); encodeULEB128(CompressedStrings.size(), OS); OS << toStringRef(CompressedStrings); diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -27,6 +27,71 @@ using namespace llvm; using namespace llvm::compression; +constexpr SupportCompressionType CompressionAlgorithm::AlgorithmId; +constexpr StringRef CompressionAlgorithm::name; +constexpr int CompressionAlgorithm::BestSpeedCompression; +constexpr int CompressionAlgorithm::DefaultCompression; +constexpr int CompressionAlgorithm::BestSizeCompression; + +bool CompressionAlgorithm::supported() { return false; }; + +void CompressionAlgorithm::compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable("method:\"compress\" is unsupported for compression " + "algorithm:\"base\", reason:\"can't call on base\""); +}; +Error CompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable("method:\"decompress\" is unsupported for compression " + "algorithm:\"base\", reason:\"can't call on base\""); +} + +constexpr SupportCompressionType NoneCompressionAlgorithm::AlgorithmId; +constexpr StringRef NoneCompressionAlgorithm::name; +constexpr int NoneCompressionAlgorithm::BestSpeedCompression; +constexpr int NoneCompressionAlgorithm::DefaultCompression; +constexpr int NoneCompressionAlgorithm::BestSizeCompression; + +bool NoneCompressionAlgorithm::supported() { return true; }; + +void NoneCompressionAlgorithm::compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + unsigned long CompressedSize = Input.size(); + CompressedBuffer.resize_for_overwrite(CompressedSize); + // SmallVectorImpl() + CompressedBuffer.assign(SmallVector(Input.begin(), Input.end())); + + // Tell MemorySanitizer that zlib output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + __msan_unpoison(CompressedBuffer.data(), CompressedSize); + if (CompressedSize < CompressedBuffer.size()) + CompressedBuffer.truncate(CompressedSize); +}; +Error NoneCompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + // Tell MemorySanitizer that zlib output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + if (UncompressedSize < Input.size()) { + return make_error("decompressed buffer target size too small", + inconvertibleErrorCode()); + } + UncompressedSize = Input.size(); + memcpy(UncompressedBuffer, Input.data(), UncompressedSize); + + __msan_unpoison(UncompressedBuffer, UncompressedSize); + return Error::success(); +} + +constexpr SupportCompressionType ZlibCompressionAlgorithm::AlgorithmId; +constexpr StringRef ZlibCompressionAlgorithm::name; +constexpr int ZlibCompressionAlgorithm::BestSpeedCompression; +constexpr int ZlibCompressionAlgorithm::DefaultCompression; +constexpr int ZlibCompressionAlgorithm::BestSizeCompression; + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { @@ -45,10 +110,11 @@ } } -bool zlib::isAvailable() { return true; } +bool ZlibCompressionAlgorithm::supported() { return true; }; -void zlib::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { +void ZlibCompressionAlgorithm::compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { unsigned long CompressedSize = ::compressBound(Input.size()); CompressedBuffer.resize_for_overwrite(CompressedSize); int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, @@ -61,10 +127,10 @@ __msan_unpoison(CompressedBuffer.data(), CompressedSize); if (CompressedSize < CompressedBuffer.size()) CompressedBuffer.truncate(CompressedSize); -} - -Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { +}; +Error ZlibCompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { int Res = ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, (const Bytef *)Input.data(), Input.size()); @@ -74,42 +140,41 @@ return Res ? make_error(convertZlibCodeToString(Res), inconvertibleErrorCode()) : Error::success(); -} - -Error zlib::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - UncompressedBuffer.resize_for_overwrite(UncompressedSize); - Error E = - zlib::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); - if (UncompressedSize < UncompressedBuffer.size()) - UncompressedBuffer.truncate(UncompressedSize); - return E; -} +}; #else -bool zlib::isAvailable() { return false; } -void zlib::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zlib::compress is unavailable"); -} -Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - llvm_unreachable("zlib::uncompress is unavailable"); -} -Error zlib::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - llvm_unreachable("zlib::uncompress is unavailable"); -} +bool ZlibCompressionAlgorithm::supported() { return false; }; + +void ZlibCompressionAlgorithm::compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable( + "method:\"compress\" is unsupported for compression algorithm:\"zlib\", " + "reason:\"llvm not compiled with zlib support\""); +}; +Error ZlibCompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable( + "method:\"decompress\" is unsupported for compression " + "algorithm:\"zlib\", reason:\"llvm not compiled with zlib support\""); +}; + #endif +constexpr SupportCompressionType ZStdCompressionAlgorithm::AlgorithmId; +constexpr StringRef ZStdCompressionAlgorithm::name; +constexpr int ZStdCompressionAlgorithm::BestSpeedCompression; +constexpr int ZStdCompressionAlgorithm::DefaultCompression; +constexpr int ZStdCompressionAlgorithm::BestSizeCompression; + #if LLVM_ENABLE_ZSTD -bool zstd::isAvailable() { return true; } +bool ZStdCompressionAlgorithm::supported() { return true; }; -void zstd::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { +void ZStdCompressionAlgorithm::compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); CompressedBuffer.resize_for_overwrite(CompressedBufferSize); unsigned long CompressedSize = @@ -122,10 +187,10 @@ __msan_unpoison(CompressedBuffer.data(), CompressedSize); if (CompressedSize < CompressedBuffer.size()) CompressedBuffer.truncate(CompressedSize); -} - -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { +}; +Error ZStdCompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { const size_t Res = ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, (const uint8_t *)Input.data(), Input.size()); @@ -136,32 +201,47 @@ return ZSTD_isError(Res) ? make_error(ZSTD_getErrorName(Res), inconvertibleErrorCode()) : Error::success(); -} - -Error zstd::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - UncompressedBuffer.resize_for_overwrite(UncompressedSize); - Error E = - zstd::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); - if (UncompressedSize < UncompressedBuffer.size()) - UncompressedBuffer.truncate(UncompressedSize); - return E; -} +}; #else -bool zstd::isAvailable() { return false; } -void zstd::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zstd::compress is unavailable"); -} -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); -} -Error zstd::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); -} +bool ZStdCompressionAlgorithm::supported() { return false; }; + +void ZStdCompressionAlgorithm::compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable( + "method:\"compress\" is unsupported for compression algorithm:\"zstd\", " + "reason:\"llvm not compiled with zstd support\""); +}; +Error ZStdCompressionAlgorithm::decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable( + "method:\"decompress\" is unsupported for compression " + "algorithm:\"zstd\", reason:\"llvm not compiled with zstd support\""); +}; + #endif + +llvm::compression::CompressionAlgorithm +llvm::compression::CompressionAlgorithmFromId(uint8_t CompressionSchemeId) { + llvm::compression::CompressionAlgorithm CompressionScheme = + llvm::compression::CompressionAlgorithm(); + switch (CompressionSchemeId) { + case static_cast( + llvm::compression::NoneCompressionAlgorithm().AlgorithmId): + CompressionScheme = llvm::compression::NoneCompressionAlgorithm(); + break; + case static_cast( + llvm::compression::ZlibCompressionAlgorithm().AlgorithmId): + CompressionScheme = llvm::compression::ZlibCompressionAlgorithm(); + break; + case static_cast( + llvm::compression::ZStdCompressionAlgorithm().AlgorithmId): + CompressionScheme = llvm::compression::ZStdCompressionAlgorithm(); + break; + default: + break; + } + return CompressionScheme; +} \ No newline at end of file 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,7 +401,7 @@ MAI->setRelaxELFRelocations(RelaxELFRel); if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::zlib::isAvailable()) { + if (!compression::ZlibCompressionAlgorithm().supported()) { WithColor::error(errs(), ProgName) << "build tools with zlib to enable -compress-debug-sections"; return 1; 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 @@ -728,10 +728,16 @@ errc::invalid_argument, "invalid or unsupported --compress-debug-sections format: %s", A->getValue()); - if (!compression::zlib::isAvailable()) - return createStringError( - errc::invalid_argument, - "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); + switch (Config.CompressionType) { + case DebugCompressionType::None: + break; + case DebugCompressionType::Z: + if (!compression::ZlibCompressionAlgorithm().supported()) + return createStringError( + errc::invalid_argument, + "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); + break; + } } Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); @@ -993,7 +999,8 @@ "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !compression::zlib::isAvailable()) + if (Config.DecompressDebugSections && + !compression::ZlibCompressionAlgorithm().supported()) return createStringError( errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); diff --git a/llvm/unittests/ProfileData/InstrProfTest.cpp b/llvm/unittests/ProfileData/InstrProfTest.cpp --- a/llvm/unittests/ProfileData/InstrProfTest.cpp +++ b/llvm/unittests/ProfileData/InstrProfTest.cpp @@ -1148,7 +1148,8 @@ std::string FuncNameStrings1; EXPECT_THAT_ERROR(collectPGOFuncNameStrings( FuncNames1, - (DoCompression && compression::zlib::isAvailable()), + (DoCompression && + compression::ZlibCompressionAlgorithm().supported()), FuncNameStrings1), Succeeded()); @@ -1156,7 +1157,8 @@ std::string FuncNameStrings2; EXPECT_THAT_ERROR(collectPGOFuncNameStrings( FuncNames2, - (DoCompression && compression::zlib::isAvailable()), + (DoCompression && + compression::ZlibCompressionAlgorithm().supported()), FuncNameStrings2), Succeeded()); diff --git a/llvm/unittests/Support/CompressionTest.cpp b/llvm/unittests/Support/CompressionTest.cpp --- a/llvm/unittests/Support/CompressionTest.cpp +++ b/llvm/unittests/Support/CompressionTest.cpp @@ -22,31 +22,43 @@ namespace { -#if LLVM_ENABLE_ZLIB -static void testZlibCompression(StringRef Input, int Level) { +static void testCompressionAlgorithm( + StringRef Input, int Level, + compression::CompressionAlgorithm CompressionScheme, + std::string ExpectedDestinationBufferTooSmallErrorMessage) { SmallVector Compressed; SmallVector Uncompressed; - zlib::compress(arrayRefFromStringRef(Input), Compressed, Level); + CompressionScheme.compress(arrayRefFromStringRef(Input), Compressed, Level); // Check that uncompressed buffer is the same as original. - Error E = zlib::uncompress(Compressed, Uncompressed, Input.size()); + Error E = + CompressionScheme.decompress(Compressed, Uncompressed, Input.size()); consumeError(std::move(E)); EXPECT_EQ(Input, toStringRef(Uncompressed)); if (Input.size() > 0) { // Uncompression fails if expected length is too short. - E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1); - EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E))); + E = CompressionScheme.decompress(Compressed, Uncompressed, + Input.size() - 1); + EXPECT_EQ(ExpectedDestinationBufferTooSmallErrorMessage, + llvm::toString(std::move(E))); } } +#if LLVM_ENABLE_ZLIB +static void testZlibCompression(StringRef Input, int Level) { + testCompressionAlgorithm(Input, Level, ZlibCompressionAlgorithm(), + "zlib error: Z_BUF_ERROR"); +} + TEST(CompressionTest, Zlib) { - testZlibCompression("", zlib::DefaultCompression); + compression::CompressionAlgorithm CompressionScheme = + compression::ZlibCompressionAlgorithm(); + testZlibCompression("", CompressionScheme.DefaultCompression); - testZlibCompression("hello, world!", zlib::NoCompression); - testZlibCompression("hello, world!", zlib::BestSizeCompression); - testZlibCompression("hello, world!", zlib::BestSpeedCompression); - testZlibCompression("hello, world!", zlib::DefaultCompression); + testZlibCompression("hello, world!", CompressionScheme.BestSizeCompression); + testZlibCompression("hello, world!", CompressionScheme.BestSpeedCompression); + testZlibCompression("hello, world!", CompressionScheme.DefaultCompression); const size_t kSize = 1024; char BinaryData[kSize]; @@ -54,38 +66,27 @@ BinaryData[i] = i & 255; StringRef BinaryDataStr(BinaryData, kSize); - testZlibCompression(BinaryDataStr, zlib::NoCompression); - testZlibCompression(BinaryDataStr, zlib::BestSizeCompression); - testZlibCompression(BinaryDataStr, zlib::BestSpeedCompression); - testZlibCompression(BinaryDataStr, zlib::DefaultCompression); + testZlibCompression(BinaryDataStr, CompressionScheme.BestSizeCompression); + testZlibCompression(BinaryDataStr, CompressionScheme.BestSpeedCompression); + testZlibCompression(BinaryDataStr, CompressionScheme.DefaultCompression); } #endif #if LLVM_ENABLE_ZSTD -static void testZstdCompression(StringRef Input, int Level) { - SmallVector Compressed; - SmallVector Uncompressed; - zstd::compress(arrayRefFromStringRef(Input), Compressed, Level); - // Check that uncompressed buffer is the same as original. - Error E = zstd::uncompress(Compressed, Uncompressed, Input.size()); - consumeError(std::move(E)); - - EXPECT_EQ(Input, toStringRef(Uncompressed)); - if (Input.size() > 0) { - // Uncompression fails if expected length is too short. - E = zstd::uncompress(Compressed, Uncompressed, Input.size() - 1); - EXPECT_EQ("Destination buffer is too small", llvm::toString(std::move(E))); - } +static void testZStdCompression(StringRef Input, int Level) { + testCompressionAlgorithm(Input, Level, ZStdCompressionAlgorithm(), + "Destination buffer is too small"); } TEST(CompressionTest, Zstd) { - testZstdCompression("", zstd::DefaultCompression); + compression::CompressionAlgorithm CompressionScheme = + compression::ZStdCompressionAlgorithm(); + testZStdCompression("", CompressionScheme.DefaultCompression); - testZstdCompression("hello, world!", zstd::NoCompression); - testZstdCompression("hello, world!", zstd::BestSizeCompression); - testZstdCompression("hello, world!", zstd::BestSpeedCompression); - testZstdCompression("hello, world!", zstd::DefaultCompression); + testZStdCompression("hello, world!", CompressionScheme.BestSizeCompression); + testZStdCompression("hello, world!", CompressionScheme.BestSpeedCompression); + testZStdCompression("hello, world!", CompressionScheme.DefaultCompression); const size_t kSize = 1024; char BinaryData[kSize]; @@ -93,10 +94,9 @@ BinaryData[i] = i & 255; StringRef BinaryDataStr(BinaryData, kSize); - testZstdCompression(BinaryDataStr, zstd::NoCompression); - testZstdCompression(BinaryDataStr, zstd::BestSizeCompression); - testZstdCompression(BinaryDataStr, zstd::BestSpeedCompression); - testZstdCompression(BinaryDataStr, zstd::DefaultCompression); + testZStdCompression(BinaryDataStr, CompressionScheme.BestSizeCompression); + testZStdCompression(BinaryDataStr, CompressionScheme.BestSpeedCompression); + testZStdCompression(BinaryDataStr, CompressionScheme.DefaultCompression); } #endif }