[llvm] 19dc3cf - [Support] Add llvm::compression::{getReasonIfUnsupported,compress,decompress}
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 7 23:53:23 PDT 2022
Author: Fangrui Song
Date: 2022-09-07T23:53:14-07:00
New Revision: 19dc3cff0f771bb8933136ef68e782553e920d04
URL: https://github.com/llvm/llvm-project/commit/19dc3cff0f771bb8933136ef68e782553e920d04
DIFF: https://github.com/llvm/llvm-project/commit/19dc3cff0f771bb8933136ef68e782553e920d04.diff
LOG: [Support] Add llvm::compression::{getReasonIfUnsupported,compress,decompress}
as high-level API on top of `llvm::compression::{zlib,zstd}::*`:
* getReasonIfUnsupported: return nullptr if the specified format is
supported, or (if unsupported) a string like `LLVM was not built with LLVM_ENABLE_ZLIB ...`
* compress: dispatch to zlib::uncompress or zstd::uncompress
* decompress: dispatch to zlib::uncompress or zstd::uncompress
Move `llvm::DebugCompressionType` from MC to Support to avoid Support->MC cyclic
dependency. There are 40+ uses in llvm-project.
Add another enum class `llvm::compression::Format` to represent supported
compression formats, which may be a superset of ELF compression formats.
See D130458 (llvm-objcopy --{,de}compress-debug-sections for zstd) for a use
case.
Link: https://discourse.llvm.org/t/rfc-zstandard-as-a-second-compression-method-to-llvm/63399
("[RFC] Zstandard as a second compression method to LLVM")
Differential Revision: https://reviews.llvm.org/D130506
Added:
Modified:
llvm/include/llvm/MC/MCTargetOptions.h
llvm/include/llvm/Support/Compression.h
llvm/lib/Support/Compression.cpp
llvm/unittests/Support/CompressionTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index ae305564a3536..640b4aa99462b 100644
--- 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 <string>
#include <vector>
@@ -25,11 +26,6 @@ enum class ExceptionHandling {
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
index 8500396d88a0b..74ec2e90293b7 100644
--- a/llvm/include/llvm/Support/Compression.h
+++ b/llvm/include/llvm/Support/Compression.h
@@ -20,6 +20,16 @@ namespace llvm {
template <typename T> 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,51 @@ Error uncompress(ArrayRef<uint8_t> Input,
} // End of namespace zstd
+enum class Format {
+ Zlib,
+ Zstd,
+};
+
+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
+ //
diff erent threads may produce
diff erent 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<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output);
+
+// Decompress Input. The uncompressed size must be available.
+Error decompress(Format F, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output, size_t UncompressedSize);
+Error decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &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
index e8fb715aa770e..2e0a2c5a644b9 100644
--- a/llvm/lib/Support/Compression.cpp
+++ b/llvm/lib/Support/Compression.cpp
@@ -27,6 +27,50 @@
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<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &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(compression::Format F, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output,
+ size_t UncompressedSize) {
+ switch (F) {
+ case compression::Format::Zlib:
+ return zlib::uncompress(Input, Output, UncompressedSize);
+ case compression::Format::Zstd:
+ return zstd::uncompress(Input, Output, UncompressedSize);
+ }
+}
+
+Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output,
+ size_t UncompressedSize) {
+ return decompress(formatFor(T), 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
index a89dadf5f9ae8..46f3003842df0 100644
--- a/llvm/unittests/Support/CompressionTest.cpp
+++ b/llvm/unittests/Support/CompressionTest.cpp
@@ -30,9 +30,15 @@ static void testZlibCompression(StringRef Input, int Level) {
// 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));
+ // decompress with Z dispatches to zlib::uncompress.
+ E = compression::decompress(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 @@ static void testZstdCompression(StringRef Input, int Level) {
// 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(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);
More information about the llvm-commits
mailing list