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,6 +20,16 @@ template class SmallVectorImpl; class Error; +// None indicates no compression. The other members are a subset of +// compression::Format, which is used for compressed debug sections in some +// object file formats (e.g. ELF). This is a separate class as we may add new +// compression::Format members for non-debugging purposes. +enum class DebugCompressionType { + None, ///< No compression + Z, ///< zlib + Zstd, ///< Zstandard +}; + namespace compression { namespace zlib { @@ -65,6 +75,49 @@ } // End of namespace zstd +enum class Format { + Zlib, ///< zlib + Zstd, ///< Zstandard +}; + +inline Format formatFor(DebugCompressionType Type) { + switch (Type) { + case DebugCompressionType::None: + llvm_unreachable("not a compression type"); + case DebugCompressionType::Z: + return Format::Zlib; + case DebugCompressionType::Zstd: + return Format::Zstd; + } +} + +struct Params { + constexpr Params(Format F) + : Format(F), Level(F == Format::Zlib ? zlib::DefaultCompression + : zstd::DefaultCompression) {} + Params(DebugCompressionType Type) : Params(formatFor(Type)) {} + + Format Format; + int Level; + // 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 nullptr if LLVM was built with support (LLVM_ENABLE_ZLIB, +// LLVM_ENABLE_ZSTD) for the specified compression format; otherwise +// return a string literal describing the reason. +const char *getReasonIfUnsupported(Format F); + +// 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 decompress(Params P, ArrayRef Input, + SmallVectorImpl &Output, size_t UncompressedSize); + } // End of namespace compression } // End of namespace llvm 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,44 @@ using namespace llvm; using namespace llvm::compression; +const char *compression::getReasonIfUnsupported(compression::Format F) { + switch (F) { + case compression::Format::Zlib: + if (zlib::isAvailable()) + return nullptr; + return "LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at " + "build time"; + case compression::Format::Zstd: + if (zstd::isAvailable()) + return nullptr; + return "LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at " + "build time"; + } +} + +void compression::compress(Params P, ArrayRef Input, + SmallVectorImpl &Output) { + switch (P.Format) { + case compression::Format::Zlib: + zlib::compress(Input, Output, P.Level); + break; + case compression::Format::Zstd: + zstd::compress(Input, Output, P.Level); + break; + } +} + +Error compression::decompress(Params P, ArrayRef Input, + SmallVectorImpl &Output, + size_t UncompressedSize) { + switch (P.Format) { + case compression::Format::Zlib: + return zlib::uncompress(Input, Output, UncompressedSize); + case compression::Format::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,15 @@ // 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. + E = compression::decompress(compression::Params(DebugCompressionType::Z), + 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 +75,15 @@ // 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. + E = compression::decompress(compression::Params(DebugCompressionType::Zstd), + 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);