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 @@ -20,7 +20,36 @@ template class SmallVectorImpl; class Error; +enum class DebugCompressionType { + None, ///< No compression + Z, ///< zlib + Zstd, ///< Zstandard +}; + namespace compression { +constexpr int DefaultLevel = -1; + +struct Params { + DebugCompressionType Format = DebugCompressionType::None; + int Level = DefaultLevel; + // This may support multi-threading for zstd in the future. Note that + // different threads may produce different output, so be careful if certain + // output determinism is desired. +}; + +// Return true if LLVM was built with support (LLVM_ENABLE_ZLIB, +// LLVM_ENABLE_ZSTD) for the specified compression format. +bool isAvailable(DebugCompressionType Type); + +// Compress Input with the specified format P.Format. If Level is -1, use +// *::DefaultCompression for the format. +void compress(Params P, ArrayRef Input, + SmallVectorImpl &Output); + +// Decompress Input. The uncompressed size must be available. +Error uncompress(Params P, ArrayRef Input, + SmallVectorImpl &Output, size_t UncompressedSize); + 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 @@ -27,6 +27,51 @@ using namespace llvm; using namespace llvm::compression; +bool compression::isAvailable(DebugCompressionType Format) { + switch (Format) { + case DebugCompressionType::None: + assert(false && "expected a compression type"); + return false; + case DebugCompressionType::Z: + return zlib::isAvailable(); + case DebugCompressionType::Zstd: + return zstd::isAvailable(); + } +} + +void compression::compress(Params P, ArrayRef Input, + SmallVectorImpl &Output) { + switch (P.Format) { + case DebugCompressionType::None: + assert(false && "expected a compression type"); + break; + case DebugCompressionType::Z: + zlib::compress(Input, Output, + P.Level == DefaultLevel ? zlib::DefaultCompression + : P.Level); + break; + case DebugCompressionType::Zstd: + zstd::compress(Input, Output, + P.Level == DefaultLevel ? zstd::DefaultCompression + : P.Level); + break; + } +} + +Error compression::uncompress(Params P, ArrayRef Input, + SmallVectorImpl &Output, + size_t UncompressedSize) { + switch (P.Format) { + case DebugCompressionType::None: + assert(false && "expected a compression type"); + return Error::success(); + case DebugCompressionType::Z: + return zlib::uncompress(Input, Output, UncompressedSize); + case DebugCompressionType::Zstd: + return zstd::uncompress(Input, Output, UncompressedSize); + } +} + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { 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 @@ -30,9 +30,16 @@ // Check that uncompressed buffer is the same as original. Error E = zlib::uncompress(Compressed, Uncompressed, Input.size()); - consumeError(std::move(E)); + EXPECT_FALSE(std::move(E)); + EXPECT_EQ(Input, toStringRef(Uncompressed)); + // uncompress with Z dispatches to zlib::uncompress. + Params P; + P.Format = DebugCompressionType::Z; + E = compression::uncompress(P, Compressed, Uncompressed, Input.size()); + EXPECT_FALSE(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); @@ -69,9 +76,16 @@ // Check that uncompressed buffer is the same as original. Error E = zstd::uncompress(Compressed, Uncompressed, Input.size()); - consumeError(std::move(E)); + EXPECT_FALSE(std::move(E)); + EXPECT_EQ(Input, toStringRef(Uncompressed)); + // uncompress with Zstd dispatches to zstd::uncompress. + Param P; + P.Format = DebugCompressionType::Zstd; + E = compression::uncompress(P, Compressed, Uncompressed, Input.size()); + EXPECT_FALSE(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);