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 @@ -16,6 +16,7 @@ #include "support/Logger.h" #include "support/Trace.h" #include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" @@ -25,6 +26,8 @@ #include #include +using namespace llvm::compression; + namespace clang { namespace clangd { namespace { @@ -190,10 +193,10 @@ RawTable.append(std::string(S)); RawTable.push_back(0); } - if (llvm::compression::zlib::isAvailable()) { + if (CompressionKind::Zlib) { llvm::SmallVector Compressed; - llvm::compression::zlib::compress(llvm::arrayRefFromStringRef(RawTable), - Compressed); + CompressionKind::Zlib->compress(llvm::arrayRefFromStringRef(RawTable), + Compressed); write32(RawTable.size(), OS); OS << llvm::toStringRef(Compressed); } else { @@ -224,23 +227,29 @@ llvm::SmallVector UncompressedStorage; if (UncompressedSize == 0) // No compression Uncompressed = R.rest(); - else if (llvm::compression::zlib::isAvailable()) { - // 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 (UncompressedSize / MaxCompressionRatio > R.rest().size()) - 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)) - return std::move(E); - Uncompressed = toStringRef(UncompressedStorage); - } else - return error("Compressed string table, but zlib is unavailable"); + else { + CompressionKind CompressionScheme = 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 == 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; 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 @@ -25,6 +25,7 @@ using ::testing::Pair; using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; +using namespace llvm::compression; namespace clang { namespace clangd { @@ -391,7 +392,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 (!CompressionKind::Zlib) { 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::CompressionKind::Zlib) { 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 @@ -144,6 +144,7 @@ using namespace clang::serialization; using namespace clang::serialization::reader; using llvm::BitstreamCursor; +using namespace llvm::compression; //===----------------------------------------------------------------------===// // ChainedASTReaderListener implementation @@ -1462,12 +1463,14 @@ unsigned RecCode = MaybeRecCode.get(); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { - if (!llvm::compression::zlib::isAvailable()) { - Error("zlib is not available"); + CompressionKind CompressionScheme = CompressionKind::Zlib; + if (!CompressionScheme) { + 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 @@ -118,6 +118,7 @@ using namespace clang; using namespace clang::serialization; +using namespace llvm::compression; template static StringRef bytes(const std::vector &v) { @@ -1999,10 +2000,12 @@ // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. - SmallVector CompressedBuffer; - if (llvm::compression::zlib::isAvailable()) { - llvm::compression::zlib::compress( - llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); + CompressionKind CompressionScheme = CompressionKind::Zlib; + if (CompressionScheme) { + SmallVector CompressedBuffer; + + 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)); diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -70,6 +70,7 @@ using namespace llvm::object; using namespace llvm::sys; using namespace llvm::support; +using namespace llvm::compression; using namespace lld; using namespace lld::elf; @@ -954,12 +955,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 (!CompressionKind::Zlib) + 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 @@ -119,7 +119,8 @@ uncompressedBuf = bAlloc().Allocate(size); } - if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size)) + if (Error e = compression::CompressionKind::Zlib->decompress( + rawData, uncompressedBuf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); rawData = makeArrayRef(uncompressedBuf, size); @@ -209,7 +210,7 @@ auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type == ELFCOMPRESS_ZLIB) { - if (!compression::zlib::isAvailable()) + if (!compression::CompressionKind::Zlib) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); } else { @@ -220,7 +221,6 @@ uncompressedSize = hdr->ch_size; alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -1218,10 +1218,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::CompressionKind::Zlib) { + error(toString(this) + + " is compressed with ELFCOMPRESS_ZLIB, but lld is " + "not built with zlib support"); + } else { + if (Error e = compression::CompressionKind::Zlib->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,12 @@ private: Decompressor(StringRef Data); - Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian); + Error consumeCompressedSectionHeader(bool Is64Bit, bool IsLittleEndian); StringRef SectionData; uint64_t DecompressedSize; + compression::CompressionKind CompressionScheme = + compression::CompressionKind::Zlib; }; } // end namespace object 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 @@ -26,6 +26,7 @@ #include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" @@ -214,8 +215,10 @@ /// third field is the uncompressed strings; otherwise it is the /// compressed string. When the string compression is off, the /// second field will have value zero. -Error collectPGOFuncNameStrings(ArrayRef NameStrs, - bool doCompression, std::string &Result); +Error collectPGOFuncNameStrings( + ArrayRef NameStrs, + compression::OptionalCompressionKind OptionalCompressionScheme, + std::string &Result); /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. 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 @@ -14,56 +14,102 @@ #define LLVM_SUPPORT_COMPRESSION_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.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 +struct CompressionAlgorithm { + const StringRef Name; + const int BestSpeedLevel; + const int DefaultLevel; + const int BestSizeLevel; + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) = 0; + virtual Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) = 0; + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer) { + return compress(Input, CompressedBuffer, this->DefaultLevel); + } + + 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; + } + +protected: + CompressionAlgorithm(StringRef Name, int BestSpeedLevel, int DefaultLevel, + int BestSizeLevel) + : Name(Name), BestSpeedLevel(BestSpeedLevel), DefaultLevel(DefaultLevel), + BestSizeLevel(BestSizeLevel) {} +}; + +class CompressionKind { +private: + uint8_t CompressionID; + +protected: + friend constexpr llvm::Optional + getOptionalCompressionKind(uint8_t OptionalCompressionID); + // because getOptionalCompressionKind is the only friend: + // we can trust the value of y is valid + constexpr CompressionKind(uint8_t CompressionID) + : CompressionID(CompressionID) {} + +public: + constexpr operator uint8_t() const { return CompressionID; } + CompressionAlgorithm *operator->() const; + + constexpr operator bool() const; + + static const llvm::compression::CompressionKind Unknown, Zlib, ZStd; +}; +constexpr inline const llvm::compression::CompressionKind + llvm::compression::CompressionKind::Unknown{255}, ///< Abstract compression + llvm::compression::CompressionKind::Zlib{1}, ///< zlib style complession + llvm::compression::CompressionKind::ZStd{2}; ///< zstd style complession +typedef llvm::Optional OptionalCompressionKind; + +constexpr CompressionKind::operator bool() const { + switch (uint8_t(CompressionID)) { + case uint8_t(CompressionKind::Zlib): + return LLVM_ENABLE_ZLIB; + case uint8_t(CompressionKind::ZStd): + return LLVM_ENABLE_ZSTD; + default: + return false; + } +} + +constexpr bool operator==(CompressionKind Left, CompressionKind Right) { + return uint8_t(Left) == uint8_t(Right); +} + +constexpr OptionalCompressionKind +getOptionalCompressionKind(uint8_t OptionalCompressionID) { + switch (OptionalCompressionID) { + case uint8_t(0): + return NoneType(); + case uint8_t(CompressionKind::Zlib): + case uint8_t(CompressionKind::ZStd): + return CompressionKind(OptionalCompressionID); + default: + return CompressionKind::Unknown; + } +} } // 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 @@ -847,15 +847,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; @@ -864,7 +863,7 @@ SmallVector Compressed; const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( + compression::CompressionKind::Zlib->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::CompressionKind::Zlib->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,13 @@ DebugCompressionType CompressionType) : SectionBase(Sec), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { - compression::zlib::compress(OriginalData, CompressedData); + switch (CompressionType) { + case DebugCompressionType::Z: + compression::CompressionKind::Zlib->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::CompressionKind::Zlib; + } else { return createError("unsupported compression type"); + } + if (!CompressionScheme) + 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), + 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::CompressionKind::Zlib) 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::CompressionKind::Zlib->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 @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Compression.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" @@ -47,12 +48,17 @@ } SmallVector CompressedStr; - bool doCompression = Compress && compression::zlib::isAvailable() && - DoInstrProfNameCompression; - if (doCompression) - compression::zlib::compress(arrayRefFromStringRef(FilenamesStr), + compression::OptionalCompressionKind OptionalCompressionScheme = + compression::CompressionKind::Zlib; + + bool DoCompression = OptionalCompressionScheme && *OptionalCompressionScheme; + + if (DoCompression) { + compression::CompressionKind CompressionScheme = *OptionalCompressionScheme; + CompressionScheme->compress(arrayRefFromStringRef(FilenamesStr), CompressedStr, - compression::zlib::BestSizeCompression); + CompressionScheme->BestSizeLevel); + } // ::= // @@ -60,8 +66,8 @@ // ( | ) encodeULEB128(Filenames.size(), OS); encodeULEB128(FilenamesStr.size(), OS); - encodeULEB128(doCompression ? CompressedStr.size() : 0U, OS); - OS << (doCompression ? toStringRef(CompressedStr) : StringRef(FilenamesStr)); + encodeULEB128(DoCompression ? CompressedStr.size() : 0U, OS); + OS << (DoCompression ? toStringRef(CompressedStr) : StringRef(FilenamesStr)); } namespace { 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 @@ -55,6 +55,7 @@ #include using namespace llvm; +using namespace llvm::compression; static cl::opt StaticFuncFullModulePrefix( "static-func-full-module-prefix", cl::init(true), cl::Hidden, @@ -435,8 +436,9 @@ return 0; } -Error collectPGOFuncNameStrings(ArrayRef NameStrs, - bool doCompression, std::string &Result) { +Error collectPGOFuncNameStrings( + ArrayRef NameStrs, + OptionalCompressionKind OptionalCompressionScheme, std::string &Result) { assert(!NameStrs.empty() && "No name data to emit"); uint8_t Header[16], *P = Header; @@ -460,14 +462,13 @@ return Error::success(); }; - if (!doCompression) { + if ((!OptionalCompressionScheme) || (!(*OptionalCompressionScheme))) return WriteStringToResult(0, UncompressedNameStrings); - } - + CompressionKind CompressionScheme = *OptionalCompressionScheme; SmallVector CompressedNameStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings), + CompressionScheme->compress(arrayRefFromStringRef(UncompressedNameStrings), CompressedNameStrings, - compression::zlib::BestSizeCompression); + CompressionScheme->BestSizeLevel); return WriteStringToResult(CompressedNameStrings.size(), toStringRef(CompressedNameStrings)); @@ -486,8 +487,12 @@ for (auto *NameVar : NameVars) { NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); } - return collectPGOFuncNameStrings( - NameStrs, compression::zlib::isAvailable() && doCompression, Result); + OptionalCompressionKind OptionalCompressionScheme = CompressionKind::Zlib; + return collectPGOFuncNameStrings(NameStrs, + doCompression && OptionalCompressionScheme + ? OptionalCompressionScheme + : llvm::NoneType(), + Result); } Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { @@ -503,10 +508,11 @@ SmallVector UncompressedNameStrings; StringRef NameStrings; if (isCompressed) { - if (!llvm::compression::zlib::isAvailable()) + CompressionKind CompressionScheme = CompressionKind::Zlib; + if (!CompressionScheme) 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/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfCorrelator.h" +#include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" @@ -15,6 +16,7 @@ #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Object/MachO.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "correlator" @@ -149,7 +151,8 @@ instrprof_error::unable_to_correlate_profile, "could not find any profile metadata in debug info"); auto Result = - collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names); + collectPGOFuncNameStrings(NamesVec, + /*CompressionScheme=*/llvm::NoneType(), Names); CounterOffsets.clear(); NamesVec.clear(); return Result; 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 @@ -44,6 +44,7 @@ #include using namespace llvm; +using namespace llvm::compression; using namespace sampleprof; #define DEBUG_TYPE "samplepgo-reader" @@ -877,12 +878,12 @@ if (std::error_code EC = CompressSize.getError()) return EC; - if (!llvm::compression::zlib::isAvailable()) + if (!CompressionKind::Zlib) return sampleprof_error::zlib_unavailable; uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); size_t UCSize = DecompressBufSize; - llvm::Error E = compression::zlib::uncompress( + llvm::Error E = CompressionKind::Zlib->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::CompressionKind CompressionScheme = + compression::CompressionKind::Zlib; + if (!CompressionScheme) 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), + CompressionScheme->compress(arrayRefFromStringRef(UncompressedStrings), CompressedStrings, - compression::zlib::BestSizeCompression); + CompressionScheme->BestSizeLevel); 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,8 @@ using namespace llvm; using namespace llvm::compression; +namespace { + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { @@ -44,124 +46,145 @@ llvm_unreachable("unknown or unexpected zlib status code"); } } +#endif +struct ZlibCompressionAlgorithm : public CompressionAlgorithm { +#if LLVM_ENABLE_ZLIB -bool zlib::isAvailable() { return true; } - -void zlib::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, - (const Bytef *)Input.data(), Input.size(), Level); - if (Res == Z_MEM_ERROR) - report_bad_alloc_error("Allocation failed"); - assert(Res == Z_OK); - // 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); -} + void 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, + (const Bytef *)Input.data(), Input.size(), Level); + if (Res == Z_MEM_ERROR) + report_bad_alloc_error("Allocation failed"); + assert(Res == Z_OK); + // 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 decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + int Res = + ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, + (const Bytef *)Input.data(), Input.size()); + // Tell MemorySanitizer that zlib output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + __msan_unpoison(UncompressedBuffer, UncompressedSize); + return Res ? make_error(convertZlibCodeToString(Res), + inconvertibleErrorCode()) + : Error::success(); + }; -Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - int Res = - ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, - (const Bytef *)Input.data(), Input.size()); - // Tell MemorySanitizer that zlib output buffer is fully initialized. - // This avoids a false report when running LLVM with uninstrumented ZLib. - __msan_unpoison(UncompressedBuffer, UncompressedSize); - return Res ? make_error(convertZlibCodeToString(Res), - inconvertibleErrorCode()) - : Error::success(); -} +#else -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; -} + void 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 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\""); + }; -#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"); -} #endif +protected: + friend CompressionAlgorithm *CompressionKind::operator->() const; + ZlibCompressionAlgorithm() : CompressionAlgorithm("zlib", 1, 6, 9) {} +}; + +struct ZStdCompressionAlgorithm : public CompressionAlgorithm { #if LLVM_ENABLE_ZSTD -bool zstd::isAvailable() { return true; } - -void zstd::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); - CompressedBuffer.resize_for_overwrite(CompressedBufferSize); - unsigned long CompressedSize = - ::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize, - (const char *)Input.data(), Input.size(), Level); - if (ZSTD_isError(CompressedSize)) - report_bad_alloc_error("Allocation failed"); - // Tell MemorySanitizer that zstd 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); -} + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level) { + unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); + CompressedBuffer.resize_for_overwrite(CompressedBufferSize); + unsigned long CompressedSize = + ::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize, + (const char *)Input.data(), Input.size(), Level); + if (ZSTD_isError(CompressedSize)) + report_bad_alloc_error("Allocation failed"); + // Tell MemorySanitizer that zstd 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 decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + const size_t Res = + ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, + (const uint8_t *)Input.data(), Input.size()); + UncompressedSize = Res; + // Tell MemorySanitizer that zstd output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + __msan_unpoison(UncompressedBuffer, UncompressedSize); + return ZSTD_isError(Res) ? make_error(ZSTD_getErrorName(Res), + inconvertibleErrorCode()) + : Error::success(); + }; -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - const size_t Res = - ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, - (const uint8_t *)Input.data(), Input.size()); - UncompressedSize = Res; - // Tell MemorySanitizer that zstd output buffer is fully initialized. - // This avoids a false report when running LLVM with uninstrumented ZLib. - __msan_unpoison(UncompressedBuffer, UncompressedSize); - return ZSTD_isError(Res) ? make_error(ZSTD_getErrorName(Res), - inconvertibleErrorCode()) - : Error::success(); -} +#else -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; -} + void 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 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\""); + }; -#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"); -} #endif + +protected: + friend CompressionAlgorithm *CompressionKind::operator->() const; + ZStdCompressionAlgorithm() : CompressionAlgorithm("zstd", 1, 5, 12) {} +}; + +struct UnknownCompressionAlgorithm : public CompressionAlgorithm { + + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level) { + llvm_unreachable("method:\"compress\" is unsupported for compression " + "algorithm:\"unknown\", reason:\"can't call on unknown\""); + }; + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable("method:\"decompress\" is unsupported for compression " + "algorithm:\"unknown\", reason:\"can't call on unknown\""); + } + +protected: + friend CompressionAlgorithm *CompressionKind::operator->() const; + UnknownCompressionAlgorithm() + : CompressionAlgorithm("unknown", -999, -999, -999) {} +}; + +} // namespace + +CompressionAlgorithm *CompressionKind::operator->() const { + switch (uint8_t(CompressionID)) { + case uint8_t(CompressionKind::Zlib): + static ZlibCompressionAlgorithm ZlibI; + return &ZlibI; + case uint8_t(CompressionKind::ZStd): + static ZStdCompressionAlgorithm ZStdI; + return &ZStdI; + default: + static UnknownCompressionAlgorithm UnknownI; + return &UnknownI; + } +} \ 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::CompressionKind::Zlib) { 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 @@ -723,15 +723,19 @@ Config.CompressionType = StringSwitch(A->getValue()) .Case("zlib", DebugCompressionType::Z) .Default(DebugCompressionType::None); - if (Config.CompressionType == DebugCompressionType::None) + switch (Config.CompressionType) { + case DebugCompressionType::None: return createStringError( 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"); + case DebugCompressionType::Z: + if (!compression::CompressionKind::Zlib) + 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 +997,7 @@ "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !compression::zlib::isAvailable()) + if (Config.DecompressDebugSections && !compression::CompressionKind::Zlib) 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 @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/Optional.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" @@ -22,6 +23,7 @@ #include using namespace llvm; +using namespace llvm::compression; LLVM_NODISCARD static ::testing::AssertionResult ErrorEquals(instrprof_error Expected, Error E) { @@ -1146,19 +1148,25 @@ for (bool DoCompression : {false, true}) { // Compressing: std::string FuncNameStrings1; - EXPECT_THAT_ERROR(collectPGOFuncNameStrings( - FuncNames1, - (DoCompression && compression::zlib::isAvailable()), - FuncNameStrings1), - Succeeded()); + EXPECT_THAT_ERROR( + collectPGOFuncNameStrings(FuncNames1, + DoCompression && CompressionKind::Zlib + ? llvm::Optional( + compression::CompressionKind::Zlib) + : llvm::NoneType(), + FuncNameStrings1), + Succeeded()); // Compressing: std::string FuncNameStrings2; - EXPECT_THAT_ERROR(collectPGOFuncNameStrings( - FuncNames2, - (DoCompression && compression::zlib::isAvailable()), - FuncNameStrings2), - Succeeded()); + EXPECT_THAT_ERROR( + collectPGOFuncNameStrings(FuncNames2, + DoCompression && CompressionKind::Zlib + ? llvm::Optional( + compression::CompressionKind::Zlib) + : llvm::NoneType(), + FuncNameStrings2), + Succeeded()); for (int Padding = 0; Padding < 2; Padding++) { // Join with paddings : 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,41 @@ namespace { -#if LLVM_ENABLE_ZLIB -static void testZlibCompression(StringRef Input, int Level) { +static void testCompressionAlgorithm( + StringRef Input, int Level, CompressionKind 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, CompressionKind::Zlib, + "zlib error: Z_BUF_ERROR"); +} + TEST(CompressionTest, Zlib) { - testZlibCompression("", zlib::DefaultCompression); + CompressionKind CompressionScheme = CompressionKind::Zlib; + testZlibCompression("", CompressionScheme->DefaultLevel); - testZlibCompression("hello, world!", zlib::NoCompression); - testZlibCompression("hello, world!", zlib::BestSizeCompression); - testZlibCompression("hello, world!", zlib::BestSpeedCompression); - testZlibCompression("hello, world!", zlib::DefaultCompression); + testZlibCompression("hello, world!", CompressionScheme->BestSizeLevel); + testZlibCompression("hello, world!", CompressionScheme->BestSpeedLevel); + testZlibCompression("hello, world!", CompressionScheme->DefaultLevel); const size_t kSize = 1024; char BinaryData[kSize]; @@ -54,38 +64,26 @@ 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->BestSizeLevel); + testZlibCompression(BinaryDataStr, CompressionScheme->BestSpeedLevel); + testZlibCompression(BinaryDataStr, CompressionScheme->DefaultLevel); } #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, CompressionKind::ZStd, + "Destination buffer is too small"); } TEST(CompressionTest, Zstd) { - testZstdCompression("", zstd::DefaultCompression); + CompressionKind CompressionScheme = CompressionKind::ZStd; + testZStdCompression("", CompressionScheme->DefaultLevel); - testZstdCompression("hello, world!", zstd::NoCompression); - testZstdCompression("hello, world!", zstd::BestSizeCompression); - testZstdCompression("hello, world!", zstd::BestSpeedCompression); - testZstdCompression("hello, world!", zstd::DefaultCompression); + testZStdCompression("hello, world!", CompressionScheme->BestSizeLevel); + testZStdCompression("hello, world!", CompressionScheme->BestSpeedLevel); + testZStdCompression("hello, world!", CompressionScheme->DefaultLevel); const size_t kSize = 1024; char BinaryData[kSize]; @@ -93,10 +91,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->BestSizeLevel); + testZStdCompression(BinaryDataStr, CompressionScheme->BestSpeedLevel); + testZStdCompression(BinaryDataStr, CompressionScheme->DefaultLevel); } #endif }