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 @@ -25,6 +25,8 @@ #include #include +using namespace llvm::compression; + namespace clang { namespace clangd { namespace { @@ -190,10 +192,11 @@ RawTable.append(std::string(S)); RawTable.push_back(0); } - if (llvm::compression::zlib::isAvailable()) { + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { llvm::SmallVector Compressed; - llvm::compression::zlib::compress(llvm::arrayRefFromStringRef(RawTable), - Compressed); + CompressionImplementation->compress(llvm::arrayRefFromStringRef(RawTable), + Compressed); write32(RawTable.size(), OS); OS << llvm::toStringRef(Compressed); } else { @@ -224,23 +227,30 @@ 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 { + // Don't extratc to a CompressionKind CompressionScheme variable + // as ratio check is zlib specific + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { + // 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 = CompressionImplementation->decompress( + llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, + UncompressedSize)) + return std::move(E); + Uncompressed = toStringRef(UncompressedStorage); + } else + return error("Compressed string table, but {0} is unavailable", + getCompressionSpec(CompressionKind::Zlib)->Name); + } 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 (!getCompressionSpec(CompressionKind::Zlib)->Implementation) { 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 @@ -58,6 +58,7 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +using namespace llvm::compression; static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC, @@ -1139,7 +1140,7 @@ if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); } else if (Value == "zlib") { - if (llvm::compression::zlib::isAvailable()) { + if (getCompressionSpec(CompressionKind::Zlib)->Implementation) { 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,19 +1463,25 @@ unsigned RecCode = MaybeRecCode.get(); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { - if (!llvm::compression::zlib::isAvailable()) { - Error("zlib is not available"); - return nullptr; - } - SmallVector Uncompressed; - if (llvm::Error E = llvm::compression::zlib::uncompress( - llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) { - Error("could not decompress embedded file contents: " + - llvm::toString(std::move(E))); + CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::Zlib); + + if (CompressionImpl *CompressionImplementation = + CompressionScheme->Implementation) { + SmallVector Uncompressed; + if (llvm::Error E = CompressionImplementation->decompress( + llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) { + Error("could not decompress embedded file contents: " + + llvm::toString(std::move(E))); + return nullptr; + } + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::toStringRef(Uncompressed), Name); + } else { + Error("compression class " + + (CompressionScheme->Name + " is not available").str()); return nullptr; } - 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 @@ -118,6 +118,7 @@ using namespace clang; using namespace clang::serialization; +using namespace llvm::compression; template static StringRef bytes(const std::vector &v) { @@ -1999,9 +2000,11 @@ // 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( + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { + SmallVector CompressedBuffer; + + CompressionImplementation->compress( llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, 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 (!getCompressionSpec(CompressionKind::Zlib)->Implementation) + 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 @@ -28,6 +28,7 @@ using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; +using namespace llvm::compression; using namespace llvm::support::endian; using namespace llvm::sys; using namespace lld; @@ -119,7 +120,9 @@ uncompressedBuf = bAlloc().Allocate(size); } - if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size)) + if (Error e = + getCompressionSpec(CompressionKind::Zlib) + ->Implementation->decompress(rawData, uncompressedBuf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); rawData = makeArrayRef(uncompressedBuf, size); @@ -209,7 +212,7 @@ auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type == ELFCOMPRESS_ZLIB) { - if (!compression::zlib::isAvailable()) + if (!getCompressionSpec(CompressionKind::Zlib)->Implementation) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); } else { @@ -1220,7 +1223,8 @@ // to the buffer. if (uncompressedSize >= 0) { size_t size = uncompressedSize; - if (Error e = compression::zlib::uncompress(rawData, buf, size)) + if (Error e = getCompressionSpec(CompressionKind::Zlib) + ->Implementation->decompress(rawData, buf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); uint8_t *bufEnd = buf + size; 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::CompressionSpec *CompressionScheme = nullptr; }; } // 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::CompressionSpec *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,71 @@ #define LLVM_SUPPORT_COMPRESSION_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.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 CompressionKind : uint8_t { Zlib = 1, ZStd = 2, Unknown = 255 }; + +struct CompressionSpec; +struct CompressionImpl; + +CompressionSpec *getCompressionSpec(uint8_t Kind); +CompressionSpec *getCompressionSpec(CompressionKind Kind); + +struct CompressionSpec { + const CompressionKind Kind; + CompressionImpl *Implementation; + const StringRef Name; + const StringRef Status; // either "supported", or "unsupported: REASON" + +protected: + friend CompressionSpec *getCompressionSpec(uint8_t Kind); + CompressionSpec(CompressionKind Kind, CompressionImpl *Implementation, + StringRef Name, bool Supported, StringRef Status) + : Kind(Kind), Implementation(Supported ? Implementation : nullptr), + Name(Name), Status(Supported ? "supported" : Status) {} +}; + +struct CompressionImpl { + const CompressionKind Kind; + 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, 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: + CompressionImpl(CompressionKind Kind, int BestSpeedLevel, int DefaultLevel, + int BestSizeLevel) + : Kind(Kind), BestSpeedLevel(BestSpeedLevel), DefaultLevel(DefaultLevel), + BestSizeLevel(BestSizeLevel) {} +}; } // 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 @@ -59,6 +59,7 @@ #include using namespace llvm; +using namespace llvm::compression; #undef DEBUG_TYPE #define DEBUG_TYPE "reloc-info" @@ -847,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; @@ -864,13 +864,20 @@ SmallVector Compressed; const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( - makeArrayRef(reinterpret_cast(UncompressedData.data()), - UncompressedData.size()), - Compressed); - if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed, - Sec.getAlignment())) { + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { + CompressionImplementation->compress( + makeArrayRef(reinterpret_cast(UncompressedData.data()), + UncompressedData.size()), + Compressed); + + if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed, + Sec.getAlignment())) { + W.OS << UncompressedData; + return; + } + } else { 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 @@ -31,6 +31,7 @@ using namespace llvm; using namespace llvm::ELF; +using namespace llvm::compression; using namespace llvm::objcopy::elf; using namespace llvm::object; @@ -439,10 +440,27 @@ 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 = + getCompressionSpec(CompressionKind::Zlib) + ->Implementation->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 +530,14 @@ DebugCompressionType CompressionType) : SectionBase(Sec), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { - compression::zlib::compress(OriginalData, CompressedData); + switch (CompressionType) { + case DebugCompressionType::Z: + getCompressionSpec(CompressionKind::Zlib) + ->Implementation->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 @@ -14,16 +14,15 @@ #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::compression; using namespace llvm::support::endian; using namespace object; 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 +30,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 +39,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 = getCompressionSpec(CompressionKind::Zlib); + + if (!CompressionScheme) return createError("unsupported compression type"); + if (!CompressionScheme->Implementation) + return createError(CompressionScheme->Name + " is not available"); // Skip Elf64_Chdr::ch_reserved field. if (Is64Bit) @@ -57,6 +61,6 @@ Error Decompressor::decompress(MutableArrayRef Buffer) { size_t Size = Buffer.size(); - return compression::zlib::uncompress(arrayRefFromStringRef(SectionData), - Buffer.data(), Size); + return CompressionScheme->Implementation->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 @@ -39,6 +39,7 @@ #include using namespace llvm; +using namespace llvm::compression; using namespace coverage; using namespace object; @@ -119,28 +120,30 @@ return Err; if (CompressedLen > 0) { - if (!compression::zlib::isAvailable()) - 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::zlib::uncompress( - arrayRefFromStringRef(CompressedFilenames), StorageBuf, - UncompressedLen); - if (Err) { - consumeError(std::move(Err)); - return make_error( - coveragemap_error::decompression_failed); - } + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { + + // Allocate memory for the decompressed filenames. + SmallVector StorageBuf; + + // Read compressed filenames. + StringRef CompressedFilenames = Data.substr(0, CompressedLen); + Data = Data.substr(CompressedLen); + auto Err = CompressionImplementation->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); + } + return make_error( + coveragemap_error::decompression_failed); } 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 @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ADT/ArrayRef.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" @@ -24,6 +24,7 @@ #include using namespace llvm; +using namespace llvm::compression; using namespace coverage; CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter( @@ -47,12 +48,15 @@ } SmallVector CompressedStr; - bool doCompression = Compress && compression::zlib::isAvailable() && - DoInstrProfNameCompression; - if (doCompression) - compression::zlib::compress(arrayRefFromStringRef(FilenamesStr), - CompressedStr, - compression::zlib::BestSizeCompression); + CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::Zlib); + bool DoCompression = Compress && DoInstrProfNameCompression && + (CompressionScheme && CompressionScheme->Implementation); + if (DoCompression) { + CompressionScheme->Implementation->compress( + arrayRefFromStringRef(FilenamesStr), CompressedStr, + CompressionScheme->Implementation->BestSizeLevel); + } // ::= // @@ -60,8 +64,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, @@ -436,7 +437,8 @@ } Error collectPGOFuncNameStrings(ArrayRef NameStrs, - bool doCompression, std::string &Result) { + CompressionSpec *OptionalCompressionScheme, + std::string &Result) { assert(!NameStrs.empty() && "No name data to emit"); uint8_t Header[16], *P = Header; @@ -460,14 +462,15 @@ return Error::success(); }; - if (!doCompression) { + if ((!OptionalCompressionScheme) || + (!(OptionalCompressionScheme->Implementation))) return WriteStringToResult(0, UncompressedNameStrings); - } - + CompressionImpl *CompressionImplementation = + OptionalCompressionScheme->Implementation; SmallVector CompressedNameStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings), - CompressedNameStrings, - compression::zlib::BestSizeCompression); + CompressionImplementation->compress( + arrayRefFromStringRef(UncompressedNameStrings), CompressedNameStrings, + CompressionImplementation->BestSizeLevel); return WriteStringToResult(CompressedNameStrings.size(), toStringRef(CompressedNameStrings)); @@ -486,8 +489,10 @@ for (auto *NameVar : NameVars) { NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); } + CompressionSpec *OptionalCompressionScheme = + getCompressionSpec(CompressionKind::Zlib); return collectPGOFuncNameStrings( - NameStrs, compression::zlib::isAvailable() && doCompression, Result); + NameStrs, doCompression ? OptionalCompressionScheme : nullptr, Result); } Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { @@ -503,17 +508,21 @@ SmallVector UncompressedNameStrings; StringRef NameStrings; if (isCompressed) { - if (!llvm::compression::zlib::isAvailable()) + CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::Zlib); + if (CompressionImpl *CompressionImplementation = + CompressionScheme->Implementation) { + + if (Error E = CompressionImplementation->decompress( + makeArrayRef(P, CompressedSize), UncompressedNameStrings, + UncompressedSize)) { + consumeError(std::move(E)); + return make_error(instrprof_error::uncompress_failed); + } + P += CompressedSize; + NameStrings = toStringRef(UncompressedNameStrings); + } else return make_error(instrprof_error::zlib_unavailable); - - if (Error E = compression::zlib::uncompress( - makeArrayRef(P, CompressedSize), UncompressedNameStrings, - UncompressedSize)) { - consumeError(std::move(E)); - return make_error(instrprof_error::uncompress_failed); - } - P += CompressedSize; - NameStrings = toStringRef(UncompressedNameStrings); } else { NameStrings = StringRef(reinterpret_cast(P), UncompressedSize); 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 @@ -15,6 +15,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" @@ -148,8 +149,8 @@ return make_error( instrprof_error::unable_to_correlate_profile, "could not find any profile metadata in debug info"); - auto Result = - collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names); + auto Result = collectPGOFuncNameStrings(NamesVec, + /*CompressionScheme=*/nullptr, 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,17 +878,19 @@ if (std::error_code EC = CompressSize.getError()) return EC; - if (!llvm::compression::zlib::isAvailable()) - return sampleprof_error::zlib_unavailable; + if (CompressionImpl *CompressionImplementation = + getCompressionSpec(CompressionKind::Zlib)->Implementation) { - uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); - size_t UCSize = DecompressBufSize; - llvm::Error E = compression::zlib::uncompress( - makeArrayRef(Data, *CompressSize), Buffer, UCSize); - if (E) - return sampleprof_error::uncompress_failed; - DecompressBuf = reinterpret_cast(Buffer); - return sampleprof_error::success; + uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); + size_t UCSize = DecompressBufSize; + llvm::Error E = CompressionImplementation->decompress( + makeArrayRef(Data, *CompressSize), Buffer, UCSize); + if (E) + return sampleprof_error::uncompress_failed; + DecompressBuf = reinterpret_cast(Buffer); + return sampleprof_error::success; + } + return sampleprof_error::zlib_unavailable; } 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 @@ -38,6 +38,7 @@ #include using namespace llvm; +using namespace llvm::compression; using namespace sampleprof; std::error_code @@ -78,22 +79,28 @@ } std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { - if (!llvm::compression::zlib::isAvailable()) - 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; - compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), - CompressedStrings, - compression::zlib::BestSizeCompression); - encodeULEB128(UncompressedStrings.size(), OS); - encodeULEB128(CompressedStrings.size(), OS); - OS << toStringRef(CompressedStrings); - UncompressedStrings.clear(); - return sampleprof_error::success; + + if (CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::Zlib)) { + if (CompressionImpl *CompressionImplementation = + CompressionScheme->Implementation) { + std::string &UncompressedStrings = + static_cast(LocalBufStream.get())->str(); + if (UncompressedStrings.size() == 0) + return sampleprof_error::success; + auto &OS = *OutputStream; + SmallVector CompressedStrings; + CompressionImplementation->compress( + arrayRefFromStringRef(UncompressedStrings), CompressedStrings, + CompressionImplementation->BestSizeLevel); + encodeULEB128(UncompressedStrings.size(), OS); + encodeULEB128(CompressedStrings.size(), OS); + OS << toStringRef(CompressedStrings); + UncompressedStrings.clear(); + return sampleprof_error::success; + } + } + return sampleprof_error::zlib_unavailable; } /// Add a new section into section header table given the section type 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,10 @@ using namespace llvm; using namespace llvm::compression; +namespace llvm { + +namespace compression { + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { @@ -44,124 +48,145 @@ llvm_unreachable("unknown or unexpected zlib status code"); } } +#endif +struct ZlibCompressionAlgorithm : public CompressionImpl { +#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 CompressionSpec *getCompressionSpec(uint8_t Kind); + ZlibCompressionAlgorithm() + : CompressionImpl(CompressionKind::Zlib, 1, 6, 9) {} +}; + +struct ZStdCompressionAlgorithm : public CompressionImpl { #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"); +#endif + +protected: + friend CompressionSpec *getCompressionSpec(uint8_t Kind); + ZStdCompressionAlgorithm() + : CompressionImpl(CompressionKind::ZStd, 1, 5, 12) {} +}; + +CompressionSpec *getCompressionSpec(uint8_t Kind) { + switch (Kind) { + case uint8_t(0): + return nullptr; + case uint8_t(CompressionKind::Zlib): + static ZlibCompressionAlgorithm ZlibI; + static CompressionSpec ZlibD = CompressionSpec( + CompressionKind::Zlib, &ZlibI, "zlib", bool(LLVM_ENABLE_ZLIB), + "unsupported: either llvm was compiled without LLVM_ENABLE_ZLIB " + "enabled, or could not find zlib at compile time"); + return &ZlibD; + case uint8_t(CompressionKind::ZStd): + static ZStdCompressionAlgorithm ZStdI; + static CompressionSpec ZStdD = CompressionSpec( + CompressionKind::ZStd, &ZStdI, "zstd", bool(LLVM_ENABLE_ZSTD), + "unsupported: either llvm was compiled without LLVM_ENABLE_ZSTD " + "enabled, or could not find zstd at compile time"); + return &ZStdD; + default: + static CompressionSpec UnknownD = + CompressionSpec(CompressionKind::Unknown, nullptr, "unknown", false, + "unsupported: scheme of unknown kind"); + return &UnknownD; + } } -Error zstd::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); + +CompressionSpec *getCompressionSpec(CompressionKind Kind) { + return getCompressionSpec(uint8_t(Kind)); } -#endif + +} // namespace compression +} // namespace llvm 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 @@ -40,6 +40,7 @@ #include "llvm/Support/WithColor.h" using namespace llvm; +using namespace llvm::compression; static mc::RegisterMCTargetOptionsFlags MOF; @@ -401,7 +402,7 @@ MAI->setRelaxELFRelocations(RelaxELFRel); if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::zlib::isAvailable()) { + if (!getCompressionSpec(CompressionKind::Zlib)->Implementation) { 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 @@ -25,6 +25,7 @@ #include "llvm/Support/MemoryBuffer.h" using namespace llvm; +using namespace llvm::compression; using namespace llvm::objcopy; namespace { @@ -723,15 +724,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 (!getCompressionSpec(CompressionKind::Zlib)->Implementation) + 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 +998,8 @@ "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !compression::zlib::isAvailable()) + if (Config.DecompressDebugSections && + !getCompressionSpec(CompressionKind::Zlib)->Implementation) 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 @@ -22,6 +22,7 @@ #include using namespace llvm; +using namespace llvm::compression; LLVM_NODISCARD static ::testing::AssertionResult ErrorEquals(instrprof_error Expected, Error E) { @@ -1146,19 +1147,29 @@ 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 && + (getCompressionSpec(CompressionKind::Zlib) && + getCompressionSpec(CompressionKind::Zlib)->Implementation) + ? getCompressionSpec(CompressionKind::Zlib) + : nullptr, + FuncNameStrings1), + Succeeded()); // Compressing: std::string FuncNameStrings2; - EXPECT_THAT_ERROR(collectPGOFuncNameStrings( - FuncNames2, - (DoCompression && compression::zlib::isAvailable()), - FuncNameStrings2), - Succeeded()); + EXPECT_THAT_ERROR( + collectPGOFuncNameStrings( + FuncNames2, + DoCompression && + (getCompressionSpec(CompressionKind::Zlib) && + getCompressionSpec(CompressionKind::Zlib)->Implementation) + ? getCompressionSpec(CompressionKind::Zlib) + : nullptr, + 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,48 @@ namespace { -#if LLVM_ENABLE_ZLIB -static void testZlibCompression(StringRef Input, int Level) { +static void testCompressionAlgorithm( + StringRef Input, int Level, CompressionSpec *CompressionScheme, + std::string ExpectedDestinationBufferTooSmallErrorMessage) { SmallVector Compressed; SmallVector Uncompressed; - zlib::compress(arrayRefFromStringRef(Input), Compressed, Level); + CompressionScheme->Implementation->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->Implementation->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->Implementation->decompress(Compressed, Uncompressed, + Input.size() - 1); + EXPECT_EQ(ExpectedDestinationBufferTooSmallErrorMessage, + llvm::toString(std::move(E))); } } -TEST(CompressionTest, Zlib) { - testZlibCompression("", zlib::DefaultCompression); +#if LLVM_ENABLE_ZLIB +static void testZlibCompression(StringRef Input, int Level) { + testCompressionAlgorithm(Input, Level, + getCompressionSpec(CompressionKind::Zlib), + "zlib error: Z_BUF_ERROR"); +} - testZlibCompression("hello, world!", zlib::NoCompression); - testZlibCompression("hello, world!", zlib::BestSizeCompression); - testZlibCompression("hello, world!", zlib::BestSpeedCompression); - testZlibCompression("hello, world!", zlib::DefaultCompression); +TEST(CompressionTest, Zlib) { + CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::Zlib); + CompressionImpl *CompressionImplementation = + CompressionScheme->Implementation; + testZlibCompression("", CompressionImplementation->DefaultLevel); + + testZlibCompression("hello, world!", + CompressionImplementation->BestSizeLevel); + testZlibCompression("hello, world!", + CompressionImplementation->BestSpeedLevel); + testZlibCompression("hello, world!", CompressionImplementation->DefaultLevel); const size_t kSize = 1024; char BinaryData[kSize]; @@ -54,38 +71,31 @@ 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, CompressionImplementation->BestSizeLevel); + testZlibCompression(BinaryDataStr, CompressionImplementation->BestSpeedLevel); + testZlibCompression(BinaryDataStr, CompressionImplementation->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, + getCompressionSpec(CompressionKind::ZStd), + "Destination buffer is too small"); } -TEST(CompressionTest, Zstd) { - testZstdCompression("", zstd::DefaultCompression); +TEST(CompressionTest, ZStd) { + CompressionSpec *CompressionScheme = + getCompressionSpec(CompressionKind::ZStd); + CompressionImpl *CompressionImplementation = + CompressionScheme->Implementation; + testZStdCompression("", CompressionImplementation->DefaultLevel); - testZstdCompression("hello, world!", zstd::NoCompression); - testZstdCompression("hello, world!", zstd::BestSizeCompression); - testZstdCompression("hello, world!", zstd::BestSpeedCompression); - testZstdCompression("hello, world!", zstd::DefaultCompression); + testZStdCompression("hello, world!", + CompressionImplementation->BestSizeLevel); + testZStdCompression("hello, world!", + CompressionImplementation->BestSpeedLevel); + testZStdCompression("hello, world!", CompressionImplementation->DefaultLevel); const size_t kSize = 1024; char BinaryData[kSize]; @@ -93,10 +103,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, CompressionImplementation->BestSizeLevel); + testZStdCompression(BinaryDataStr, CompressionImplementation->BestSpeedLevel); + testZStdCompression(BinaryDataStr, CompressionImplementation->DefaultLevel); } #endif -} +} // namespace