diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -10,6 +10,7 @@ #define LLVM_MC_MCTARGETOPTIONS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Compression.h" #include #include @@ -25,11 +26,6 @@ AIX, ///< AIX Exception Handling }; -enum class DebugCompressionType { - None, ///< No compression - Z, ///< zlib style complession -}; - enum class EmitDwarfUnwindType { Always, // Always emit dwarf unwind NoCompactUnwind, // Only emit if compact unwind isn't available 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,13 +14,58 @@ #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; +enum class DebugCompressionType { None, Z, Zstd }; + namespace compression { + +struct CompressionAlgorithm { + const StringRef Name; + const int BestSpeedLevel; + const int DefaultLevel; + const int BestSizeLevel; + const bool Available; + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) const = 0; + virtual Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) const = 0; + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer) const { + return compress(Input, CompressedBuffer, this->DefaultLevel); + } + + Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) const { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = decompress(Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + + explicit operator bool() const { return Available; } + +protected: + CompressionAlgorithm(StringRef Name, int BestSpeedLevel, int DefaultLevel, + int BestSizeLevel, bool Available) + : Name(Name), BestSpeedLevel(BestSpeedLevel), DefaultLevel(DefaultLevel), + BestSizeLevel(BestSizeLevel), Available(Available) {} + ~CompressionAlgorithm() = default; +}; + +const CompressionAlgorithm &getCompressionAlgorithm(DebugCompressionType Kind); + +// deprecated API namespace zlib { constexpr int NoCompression = 0; 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 @@ -498,6 +498,8 @@ case DebugCompressionType::Z: Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB; break; + case DebugCompressionType::Zstd: + llvm_unreachable("unsupported"); } Chdr.ch_size = Sec.DecompressedSize; Chdr.ch_addralign = Sec.DecompressedAlign; 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 @@ -21,12 +21,14 @@ #include #endif #if LLVM_ENABLE_ZSTD -#include +#include #endif using namespace llvm; using namespace llvm::compression; +namespace { + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { @@ -44,124 +46,158 @@ llvm_unreachable("unknown or unexpected zlib status code"); } } +#endif +namespace { +struct ZlibCompressionAlgorithm final : public CompressionAlgorithm { +#if LLVM_ENABLE_ZLIB + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) const override { + 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) const override { + 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 + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) const override { + 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) const override { + llvm_unreachable( + "method:\"decompress\" is unsupported for compression " + "algorithm:\"zlib\", reason:\"llvm not compiled with zlib support\""); + }; +#endif + ZlibCompressionAlgorithm() + : CompressionAlgorithm("zlib", 1, 6, 9, LLVM_ENABLE_ZLIB) {} +}; -bool zlib::isAvailable() { return true; } +struct ZStdCompressionAlgorithm final : public CompressionAlgorithm { +#if LLVM_ENABLE_ZSTD + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) const override { + 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 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) const override { + const size_t Res = + ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, + (const uint8_t *)Input.data(), Input.size()); + UncompressedSize = Res; + // 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 ZSTD_isError(Res) ? make_error(ZSTD_getErrorName(Res), + inconvertibleErrorCode()) + : Error::success(); + }; +#else + void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) const override { + llvm_unreachable("zstd compression unsupported"); + } + Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) const override { + llvm_unreachable("zstd decompression unsupported"); + } +#endif -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); -} + ZStdCompressionAlgorithm() + : CompressionAlgorithm("zlib", 1, 5, 12, LLVM_ENABLE_ZSTD) {} +}; +} // namespace -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(); -} +} // namespace -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; +const CompressionAlgorithm & +compression::getCompressionAlgorithm(DebugCompressionType Kind) { + switch (Kind) { + case DebugCompressionType::Z: + static ZlibCompressionAlgorithm ZlibI; + return ZlibI; + case DebugCompressionType::Zstd: + static ZStdCompressionAlgorithm ZStdI; + return ZStdI; + case DebugCompressionType::None: + llvm_unreachable("Only query for actual compression types."); + } + llvm_unreachable("Unknown compression kind"); } -#else -bool zlib::isAvailable() { return false; } -void zlib::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zlib::compress is unavailable"); +// Deprecated implementation +bool zstd::isAvailable() { + return !!getCompressionAlgorithm(DebugCompressionType::Zstd); } -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 - -#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); + getCompressionAlgorithm(DebugCompressionType::Zstd) + .compress(Input, CompressedBuffer, Level); } - 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(); + return getCompressionAlgorithm(DebugCompressionType::Zstd) + .decompress(Input, UncompressedBuffer, UncompressedSize); } - 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; + return getCompressionAlgorithm(DebugCompressionType::Zstd) + .decompress(Input, UncompressedBuffer, UncompressedSize); } - -#else -bool zstd::isAvailable() { return false; } -void zstd::compress(ArrayRef Input, +bool zlib::isAvailable() { + return !!getCompressionAlgorithm(DebugCompressionType::Z); +} +void zlib::compress(ArrayRef Input, SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zstd::compress is unavailable"); + getCompressionAlgorithm(DebugCompressionType::Z) + .compress(Input, CompressedBuffer, Level); } -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, +Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, size_t &UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); + return getCompressionAlgorithm(DebugCompressionType::Z) + .decompress(Input, UncompressedBuffer, UncompressedSize); } -Error zstd::uncompress(ArrayRef Input, +Error zlib::uncompress(ArrayRef Input, SmallVectorImpl &UncompressedBuffer, size_t UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); + return getCompressionAlgorithm(DebugCompressionType::Z) + .decompress(Input, UncompressedBuffer, UncompressedSize); } -#endif