ckissane created this revision.
ckissane added reviewers: dblaikie, MaskRay.
Herald added subscribers: StephenFan, wenlei, kadircet, arphaman, hiraditya, 
arichardson, emaste.
Herald added a reviewer: alexander-shaposhnikov.
Herald added a reviewer: rupprecht.
Herald added a reviewer: jhenderson.
Herald added a project: All.
ckissane requested review of this revision.
Herald added projects: clang, LLVM, clang-tools-extra.
Herald added subscribers: cfe-commits, llvm-commits.

[compression] move to a enum->spec->impl approach 
+ None compression is signified by a nullptr for a CompressionSpecRef
+ Lack of support (lack of impl) is signified by a nullptr for a 
CompressionImplRef 
+ move away from fancy fake enum approach


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131992

Files:
  clang-tools-extra/clangd/index/Serialization.cpp
  clang-tools-extra/clangd/unittests/SerializationTests.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  lld/ELF/Driver.cpp
  lld/ELF/InputSection.cpp
  llvm/include/llvm/Object/Decompressor.h
  llvm/include/llvm/ProfileData/InstrProf.h
  llvm/include/llvm/Support/Compression.h
  llvm/lib/MC/ELFObjectWriter.cpp
  llvm/lib/ObjCopy/ELF/ELFObject.cpp
  llvm/lib/Object/Decompressor.cpp
  llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
  llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
  llvm/lib/ProfileData/InstrProf.cpp
  llvm/lib/ProfileData/InstrProfCorrelator.cpp
  llvm/lib/ProfileData/SampleProfReader.cpp
  llvm/lib/ProfileData/SampleProfWriter.cpp
  llvm/lib/Support/Compression.cpp
  llvm/tools/llvm-mc/llvm-mc.cpp
  llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
  llvm/unittests/ProfileData/InstrProfTest.cpp
  llvm/unittests/Support/CompressionTest.cpp

Index: llvm/unittests/Support/CompressionTest.cpp
===================================================================
--- llvm/unittests/Support/CompressionTest.cpp
+++ llvm/unittests/Support/CompressionTest.cpp
@@ -22,31 +22,42 @@
 
 namespace {
 
-#if LLVM_ENABLE_ZLIB
-static void testZlibCompression(StringRef Input, int Level) {
+static void testCompressionAlgorithm(
+    StringRef Input, int Level, CompressionSpecRef CompressionScheme,
+    std::string ExpectedDestinationBufferTooSmallErrorMessage) {
   SmallVector<uint8_t, 0> Compressed;
   SmallVector<uint8_t, 0> 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)));
   }
 }
 
+#if LLVM_ENABLE_ZLIB
+static void testZlibCompression(StringRef Input, int Level) {
+  testCompressionAlgorithm(Input, Level, CompressionSpecRefs::Zlib,
+                           "zlib error: Z_BUF_ERROR");
+}
+
 TEST(CompressionTest, Zlib) {
-  testZlibCompression("", zlib::DefaultCompression);
+  CompressionSpecRef CompressionScheme = CompressionSpecRefs::Zlib;
+  testZlibCompression("", CompressionScheme->DefaultLevel);
 
-  testZlibCompression("hello, world!", zlib::NoCompression);
-  testZlibCompression("hello, world!", zlib::BestSizeCompression);
-  testZlibCompression("hello, world!", zlib::BestSpeedCompression);
-  testZlibCompression("hello, world!", zlib::DefaultCompression);
+  testZlibCompression("hello, world!", CompressionScheme->BestSizeLevel);
+  testZlibCompression("hello, world!", CompressionScheme->BestSpeedLevel);
+  testZlibCompression("hello, world!", CompressionScheme->DefaultLevel);
 
   const size_t kSize = 1024;
   char BinaryData[kSize];
@@ -54,38 +65,26 @@
     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, CompressionScheme->BestSizeLevel);
+  testZlibCompression(BinaryDataStr, CompressionScheme->BestSpeedLevel);
+  testZlibCompression(BinaryDataStr, CompressionScheme->DefaultLevel);
 }
 #endif
 
 #if LLVM_ENABLE_ZSTD
-static void testZstdCompression(StringRef Input, int Level) {
-  SmallVector<uint8_t, 0> Compressed;
-  SmallVector<uint8_t, 0> 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, CompressionSpecRefs::ZStd,
+                           "Destination buffer is too small");
 }
 
 TEST(CompressionTest, Zstd) {
-  testZstdCompression("", zstd::DefaultCompression);
+  CompressionSpecRef CompressionScheme = CompressionSpecRefs::ZStd;
+  testZStdCompression("", CompressionScheme->DefaultLevel);
 
-  testZstdCompression("hello, world!", zstd::NoCompression);
-  testZstdCompression("hello, world!", zstd::BestSizeCompression);
-  testZstdCompression("hello, world!", zstd::BestSpeedCompression);
-  testZstdCompression("hello, world!", zstd::DefaultCompression);
+  testZStdCompression("hello, world!", CompressionScheme->BestSizeLevel);
+  testZStdCompression("hello, world!", CompressionScheme->BestSpeedLevel);
+  testZStdCompression("hello, world!", CompressionScheme->DefaultLevel);
 
   const size_t kSize = 1024;
   char BinaryData[kSize];
@@ -93,10 +92,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, CompressionScheme->BestSizeLevel);
+  testZStdCompression(BinaryDataStr, CompressionScheme->BestSpeedLevel);
+  testZStdCompression(BinaryDataStr, CompressionScheme->DefaultLevel);
 }
 #endif
 }
Index: llvm/unittests/ProfileData/InstrProfTest.cpp
===================================================================
--- llvm/unittests/ProfileData/InstrProfTest.cpp
+++ llvm/unittests/ProfileData/InstrProfTest.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LLVMContext.h"
@@ -22,6 +23,7 @@
 #include <cstdarg>
 
 using namespace llvm;
+using namespace llvm::compression;
 
 LLVM_NODISCARD static ::testing::AssertionResult
 ErrorEquals(instrprof_error Expected, Error E) {
@@ -1146,19 +1148,27 @@
   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 && (CompressionSpecRefs::Zlib &&
+                              CompressionSpecRefs::Zlib->Implementation)
+                ? CompressionSpecRefs::Zlib
+                : CompressionSpecRefs::None,
+            FuncNameStrings1),
+        Succeeded());
 
     // Compressing:
     std::string FuncNameStrings2;
-    EXPECT_THAT_ERROR(collectPGOFuncNameStrings(
-                          FuncNames2,
-                          (DoCompression && compression::zlib::isAvailable()),
-                          FuncNameStrings2),
-                      Succeeded());
+    EXPECT_THAT_ERROR(
+        collectPGOFuncNameStrings(
+            FuncNames2,
+            DoCompression && (CompressionSpecRefs::Zlib &&
+                              CompressionSpecRefs::Zlib->Implementation)
+                ? CompressionSpecRefs::Zlib
+                : CompressionSpecRefs::None,
+            FuncNameStrings2),
+        Succeeded());
 
     for (int Padding = 0; Padding < 2; Padding++) {
       // Join with paddings :
Index: llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
===================================================================
--- llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -723,15 +723,19 @@
     Config.CompressionType = StringSwitch<DebugCompressionType>(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 (!compression::CompressionSpecRefs::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 +997,8 @@
         "--decompress-debug-sections");
   }
 
-  if (Config.DecompressDebugSections && !compression::zlib::isAvailable())
+  if (Config.DecompressDebugSections &&
+      !compression::CompressionSpecRefs::Zlib->Implementation)
     return createStringError(
         errc::invalid_argument,
         "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
Index: llvm/tools/llvm-mc/llvm-mc.cpp
===================================================================
--- llvm/tools/llvm-mc/llvm-mc.cpp
+++ llvm/tools/llvm-mc/llvm-mc.cpp
@@ -401,7 +401,7 @@
   MAI->setRelaxELFRelocations(RelaxELFRel);
 
   if (CompressDebugSections != DebugCompressionType::None) {
-    if (!compression::zlib::isAvailable()) {
+    if (!compression::CompressionSpecRefs::Zlib->Implementation) {
       WithColor::error(errs(), ProgName)
           << "build tools with zlib to enable -compress-debug-sections";
       return 1;
Index: llvm/lib/Support/Compression.cpp
===================================================================
--- llvm/lib/Support/Compression.cpp
+++ 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,157 @@
     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<uint8_t> Input,
-                    SmallVectorImpl<uint8_t> &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<uint8_t> Input,
+                SmallVectorImpl<uint8_t> &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<uint8_t> 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<StringError>(convertZlibCodeToString(Res),
+                                         inconvertibleErrorCode())
+               : Error::success();
+  };
 
-Error zlib::uncompress(ArrayRef<uint8_t> 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<StringError>(convertZlibCodeToString(Res),
-                                       inconvertibleErrorCode())
-             : Error::success();
-}
+#else
 
-Error zlib::uncompress(ArrayRef<uint8_t> Input,
-                       SmallVectorImpl<uint8_t> &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<uint8_t> Input,
+                SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
+    llvm_unreachable("method:\"compress\" is unsupported for compression "
+                     "algorithm:\"zlib\", "
+                     "reason:\"llvm not compiled with zlib support\"");
+  };
+  Error decompress(ArrayRef<uint8_t> 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<uint8_t> Input,
-                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
-  llvm_unreachable("zlib::compress is unavailable");
-}
-Error zlib::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
-                       size_t &UncompressedSize) {
-  llvm_unreachable("zlib::uncompress is unavailable");
-}
-Error zlib::uncompress(ArrayRef<uint8_t> Input,
-                       SmallVectorImpl<uint8_t> &UncompressedBuffer,
-                       size_t UncompressedSize) {
-  llvm_unreachable("zlib::uncompress is unavailable");
-}
 #endif
 
+protected:
+  friend CompressionSpecRef getCompressionSpec(uint8_t Kind);
+  ZlibCompressionAlgorithm() : CompressionImpl(CompressionKind::Zlib) {}
+};
+
+struct ZStdCompressionAlgorithm : public CompressionImpl {
 #if LLVM_ENABLE_ZSTD
 
-bool zstd::isAvailable() { return true; }
-
-void zstd::compress(ArrayRef<uint8_t> Input,
-                    SmallVectorImpl<uint8_t> &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<uint8_t> Input,
+                SmallVectorImpl<uint8_t> &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<uint8_t> 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<StringError>(ZSTD_getErrorName(Res),
+                                                       inconvertibleErrorCode())
+                             : Error::success();
+  };
 
-Error zstd::uncompress(ArrayRef<uint8_t> 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<StringError>(ZSTD_getErrorName(Res),
-                                                     inconvertibleErrorCode())
-                           : Error::success();
-}
+#else
 
-Error zstd::uncompress(ArrayRef<uint8_t> Input,
-                       SmallVectorImpl<uint8_t> &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<uint8_t> Input,
+                SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
+    llvm_unreachable("method:\"compress\" is unsupported for compression "
+                     "algorithm:\"zstd\", "
+                     "reason:\"llvm not compiled with zstd support\"");
+  };
+  Error decompress(ArrayRef<uint8_t> 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<uint8_t> Input,
-                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
-  llvm_unreachable("zstd::compress is unavailable");
+#endif
+
+protected:
+  friend CompressionSpecRef getCompressionSpec(uint8_t Kind);
+  ZStdCompressionAlgorithm() : CompressionImpl(CompressionKind::ZStd) {}
+};
+
+CompressionSpecRef 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",
+        1, 6, 9);
+    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",
+        1, 5, 12);
+    return &ZStdD;
+  default:
+    static CompressionSpec UnknownD = CompressionSpec(
+        CompressionKind::Unknown, nullptr, "unknown", false,
+        "unsupported: scheme of unknown kind", -999, -999, -999);
+    return &UnknownD;
+  }
 }
-Error zstd::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
-                       size_t &UncompressedSize) {
-  llvm_unreachable("zstd::uncompress is unavailable");
+
+CompressionSpecRef getCompressionSpec(CompressionKind Kind) {
+  return getCompressionSpec(uint8_t(Kind));
 }
-Error zstd::uncompress(ArrayRef<uint8_t> Input,
-                       SmallVectorImpl<uint8_t> &UncompressedBuffer,
-                       size_t UncompressedSize) {
-  llvm_unreachable("zstd::uncompress is unavailable");
+CompressionSpecRef getSchemeDetails(CompressionImpl *Implementation) {
+  return Implementation == nullptr ? nullptr
+                                   : getCompressionSpec(Implementation->Kind);
 }
-#endif
+
+CompressionSpecRef CompressionSpecRefs::Unknown =
+    getCompressionSpec(CompressionKind::Unknown);       ///< Unknown compression
+CompressionSpecRef CompressionSpecRefs::None = nullptr; ///< Lack of compression
+CompressionSpecRef CompressionSpecRefs::Zlib =
+    getCompressionSpec(CompressionKind::Zlib); ///< zlib style complession
+CompressionSpecRef CompressionSpecRefs::ZStd =
+    getCompressionSpec(CompressionKind::ZStd); ///< zstd style complession
+
+} // namespace compression
+} // namespace llvm
Index: llvm/lib/ProfileData/SampleProfWriter.cpp
===================================================================
--- llvm/lib/ProfileData/SampleProfWriter.cpp
+++ llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -78,22 +78,28 @@
 }
 
 std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
-  if (!llvm::compression::zlib::isAvailable())
-    return sampleprof_error::zlib_unavailable;
-  std::string &UncompressedStrings =
-      static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
-  if (UncompressedStrings.size() == 0)
-    return sampleprof_error::success;
-  auto &OS = *OutputStream;
-  SmallVector<uint8_t, 128> 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 (compression::CompressionSpecRef CompressionScheme =
+          compression::CompressionSpecRefs::Zlib) {
+    if (compression::CompressionImplRef CompressionImplementation =
+            CompressionScheme->Implementation) {
+      std::string &UncompressedStrings =
+          static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
+      if (UncompressedStrings.size() == 0)
+        return sampleprof_error::success;
+      auto &OS = *OutputStream;
+      SmallVector<uint8_t, 128> CompressedStrings;
+      CompressionImplementation->compress(
+          arrayRefFromStringRef(UncompressedStrings), CompressedStrings,
+          CompressionImplementation->spec()->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
Index: llvm/lib/ProfileData/SampleProfReader.cpp
===================================================================
--- llvm/lib/ProfileData/SampleProfReader.cpp
+++ llvm/lib/ProfileData/SampleProfReader.cpp
@@ -44,6 +44,7 @@
 #include <vector>
 
 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 (CompressionImplRef CompressionImplementation =
+          CompressionSpecRefs::Zlib->Implementation) {
 
-  uint8_t *Buffer = Allocator.Allocate<uint8_t>(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<const uint8_t *>(Buffer);
-  return sampleprof_error::success;
+    uint8_t *Buffer = Allocator.Allocate<uint8_t>(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<const uint8_t *>(Buffer);
+    return sampleprof_error::success;
+  }
+  return sampleprof_error::zlib_unavailable;
 }
 
 std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
Index: llvm/lib/ProfileData/InstrProfCorrelator.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/InstrProfCorrelator.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
@@ -15,6 +16,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 +150,9 @@
     return make_error<InstrProfError>(
         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=*/compression::CompressionSpecRefs::None, Names);
   CounterOffsets.clear();
   NamesVec.clear();
   return Result;
Index: llvm/lib/ProfileData/InstrProf.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProf.cpp
+++ llvm/lib/ProfileData/InstrProf.cpp
@@ -55,6 +55,7 @@
 #include <vector>
 
 using namespace llvm;
+using namespace llvm::compression;
 
 static cl::opt<bool> StaticFuncFullModulePrefix(
     "static-func-full-module-prefix", cl::init(true), cl::Hidden,
@@ -436,7 +437,8 @@
 }
 
 Error collectPGOFuncNameStrings(ArrayRef<std::string> NameStrs,
-                                bool doCompression, std::string &Result) {
+                                CompressionSpecRef 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);
-  }
-
+  CompressionImplRef CompressionImplementation =
+      OptionalCompressionScheme->Implementation;
   SmallVector<uint8_t, 128> CompressedNameStrings;
-  compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings),
-                              CompressedNameStrings,
-                              compression::zlib::BestSizeCompression);
+  CompressionImplementation->compress(
+      arrayRefFromStringRef(UncompressedNameStrings), CompressedNameStrings,
+      OptionalCompressionScheme->BestSizeLevel);
 
   return WriteStringToResult(CompressedNameStrings.size(),
                              toStringRef(CompressedNameStrings));
@@ -486,8 +489,11 @@
   for (auto *NameVar : NameVars) {
     NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar)));
   }
-  return collectPGOFuncNameStrings(
-      NameStrs, compression::zlib::isAvailable() && doCompression, Result);
+  CompressionSpecRef OptionalCompressionScheme = CompressionSpecRefs::Zlib;
+  return collectPGOFuncNameStrings(NameStrs,
+                                   doCompression ? OptionalCompressionScheme
+                                                 : CompressionSpecRefs::None,
+                                   Result);
 }
 
 Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) {
@@ -503,17 +509,20 @@
     SmallVector<uint8_t, 128> UncompressedNameStrings;
     StringRef NameStrings;
     if (isCompressed) {
-      if (!llvm::compression::zlib::isAvailable())
+      CompressionSpecRef CompressionScheme = CompressionSpecRefs::Zlib;
+      if (CompressionImplRef CompressionImplementation =
+              CompressionScheme->Implementation) {
+
+        if (Error E = CompressionImplementation->decompress(
+                makeArrayRef(P, CompressedSize), UncompressedNameStrings,
+                UncompressedSize)) {
+          consumeError(std::move(E));
+          return make_error<InstrProfError>(instrprof_error::uncompress_failed);
+        }
+        P += CompressedSize;
+        NameStrings = toStringRef(UncompressedNameStrings);
+      } else
         return make_error<InstrProfError>(instrprof_error::zlib_unavailable);
-
-      if (Error E = compression::zlib::uncompress(
-              makeArrayRef(P, CompressedSize), UncompressedNameStrings,
-              UncompressedSize)) {
-        consumeError(std::move(E));
-        return make_error<InstrProfError>(instrprof_error::uncompress_failed);
-      }
-      P += CompressedSize;
-      NameStrings = toStringRef(UncompressedNameStrings);
     } else {
       NameStrings =
           StringRef(reinterpret_cast<const char *>(P), UncompressedSize);
Index: llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
===================================================================
--- llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
+++ llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
@@ -11,10 +11,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.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 +25,7 @@
 #include <vector>
 
 using namespace llvm;
+using namespace llvm::compression;
 using namespace coverage;
 
 CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter(
@@ -47,12 +49,14 @@
   }
 
   SmallVector<uint8_t, 128> CompressedStr;
-  bool doCompression = Compress && compression::zlib::isAvailable() &&
-                       DoInstrProfNameCompression;
-  if (doCompression)
-    compression::zlib::compress(arrayRefFromStringRef(FilenamesStr),
-                                CompressedStr,
-                                compression::zlib::BestSizeCompression);
+  CompressionSpecRef CompressionScheme = CompressionSpecRefs::Zlib;
+  bool DoCompression = Compress && DoInstrProfNameCompression &&
+                       (CompressionScheme && CompressionScheme->Implementation);
+  if (DoCompression) {
+    CompressionScheme->Implementation->compress(
+        arrayRefFromStringRef(FilenamesStr), CompressedStr,
+        CompressionScheme->BestSizeLevel);
+  }
 
   // ::= <num-filenames>
   //     <uncompressed-len>
@@ -60,8 +64,8 @@
   //     (<compressed-filenames> | <uncompressed-filenames>)
   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 {
Index: llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
===================================================================
--- llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -39,6 +39,7 @@
 #include <vector>
 
 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<CoverageMapError>(
-          coveragemap_error::decompression_failed);
-
-    // Allocate memory for the decompressed filenames.
-    SmallVector<uint8_t, 0> 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<CoverageMapError>(
-          coveragemap_error::decompression_failed);
-    }
+    if (CompressionImplRef CompressionImplementation =
+            CompressionSpecRefs::Zlib->Implementation) {
+
+      // Allocate memory for the decompressed filenames.
+      SmallVector<uint8_t, 0> 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<CoverageMapError>(
+            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<CoverageMapError>(
+        coveragemap_error::decompression_failed);
   }
 
   return readUncompressed(Version, NumFilenames);
Index: llvm/lib/Object/Decompressor.cpp
===================================================================
--- llvm/lib/Object/Decompressor.cpp
+++ llvm/lib/Object/Decompressor.cpp
@@ -19,11 +19,9 @@
 
 Expected<Decompressor> 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 +29,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 +38,18 @@
 
   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 = compression::CompressionSpecRefs::Zlib;
+  } else {
     return createError("unsupported compression type");
+  }
+  if (!CompressionScheme)
+    return createError(
+        "Decompressor provided nullptr (None) CompressionScheme*");
+  if (!CompressionScheme->Implementation)
+    return createError(CompressionScheme->Name + " is not available");
 
   // Skip Elf64_Chdr::ch_reserved field.
   if (Is64Bit)
@@ -57,6 +63,6 @@
 
 Error Decompressor::decompress(MutableArrayRef<uint8_t> Buffer) {
   size_t Size = Buffer.size();
-  return compression::zlib::uncompress(arrayRefFromStringRef(SectionData),
-                                       Buffer.data(), Size);
+  return CompressionScheme->Implementation->decompress(
+      arrayRefFromStringRef(SectionData), Buffer.data(), Size);
 }
Index: llvm/lib/ObjCopy/ELF/ELFObject.cpp
===================================================================
--- llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -439,10 +439,27 @@
   ArrayRef<uint8_t> Compressed =
       Sec.OriginalData.slice(sizeof(Elf_Chdr_Impl<ELFT>));
   SmallVector<uint8_t, 128> DecompressedContent;
-  if (Error Err = compression::zlib::uncompress(Compressed, DecompressedContent,
-                                                static_cast<size_t>(Sec.Size)))
-    return createStringError(errc::invalid_argument,
-                             "'" + Sec.Name + "': " + toString(std::move(Err)));
+  DebugCompressionType CompressionType =
+      reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Sec.OriginalData.data())
+                  ->ch_type == ELF::ELFCOMPRESS_ZLIB
+          ? DebugCompressionType::Z
+          : DebugCompressionType::None;
+
+  switch (CompressionType) {
+  case DebugCompressionType::Z:
+    if (Error Err1 =
+            compression::CompressionSpecRefs::Zlib->Implementation->decompress(
+                Compressed, DecompressedContent,
+                static_cast<size_t>(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<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
   std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
@@ -512,7 +529,14 @@
                                      DebugCompressionType CompressionType)
     : SectionBase(Sec), CompressionType(CompressionType),
       DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
-  compression::zlib::compress(OriginalData, CompressedData);
+  switch (CompressionType) {
+  case DebugCompressionType::Z:
+    compression::CompressionSpecRefs::Zlib->Implementation->compress(
+        OriginalData, CompressedData);
+    break;
+  case DebugCompressionType::None:
+    break;
+  }
 
   assert(CompressionType != DebugCompressionType::None);
   Flags |= ELF::SHF_COMPRESSED;
Index: llvm/lib/MC/ELFObjectWriter.cpp
===================================================================
--- llvm/lib/MC/ELFObjectWriter.cpp
+++ llvm/lib/MC/ELFObjectWriter.cpp
@@ -847,15 +847,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<char, 128> UncompressedData;
@@ -864,13 +863,20 @@
 
   SmallVector<uint8_t, 128> Compressed;
   const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB;
-  compression::zlib::compress(
-      makeArrayRef(reinterpret_cast<uint8_t *>(UncompressedData.data()),
-                   UncompressedData.size()),
-      Compressed);
 
-  if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed,
-                             Sec.getAlignment())) {
+  if (compression::CompressionImplRef CompressionImplementation =
+          compression::CompressionSpecRefs::Zlib->Implementation) {
+    CompressionImplementation->compress(
+        makeArrayRef(reinterpret_cast<uint8_t *>(UncompressedData.data()),
+                     UncompressedData.size()),
+        Compressed);
+
+    if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed,
+                               Sec.getAlignment())) {
+      W.OS << UncompressedData;
+      return;
+    }
+  } else {
     W.OS << UncompressedData;
     return;
   }
Index: llvm/include/llvm/Support/Compression.h
===================================================================
--- llvm/include/llvm/Support/Compression.h
+++ llvm/include/llvm/Support/Compression.h
@@ -14,56 +14,89 @@
 #define LLVM_SUPPORT_COMPRESSION_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.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 <typename T> 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<uint8_t> Input,
-              SmallVectorImpl<uint8_t> &CompressedBuffer,
-              int Level = DefaultCompression);
-
-Error uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
-                 size_t &UncompressedSize);
-
-Error uncompress(ArrayRef<uint8_t> Input,
-                 SmallVectorImpl<uint8_t> &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<uint8_t> Input,
-              SmallVectorImpl<uint8_t> &CompressedBuffer,
-              int Level = DefaultCompression);
-
-Error uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
-                 size_t &UncompressedSize);
-
-Error uncompress(ArrayRef<uint8_t> Input,
-                 SmallVectorImpl<uint8_t> &UncompressedBuffer,
-                 size_t UncompressedSize);
-
-} // End of namespace zstd
+enum class CompressionKind : uint8_t { Zlib = 1, ZStd = 2, Unknown = 255 };
+
+struct CompressionSpec;
+struct CompressionImpl;
+
+typedef CompressionSpec *CompressionSpecRef;
+typedef CompressionImpl *CompressionImplRef;
+
+CompressionSpecRef getCompressionSpec(uint8_t Kind);
+CompressionSpecRef getCompressionSpec(CompressionKind Kind);
+CompressionSpecRef getSchemeDetails(CompressionImplRef Implementation);
+
+struct CompressionSpec {
+  const CompressionKind Kind;
+  CompressionImpl *Implementation;
+  const StringRef Name;
+  const bool Supported;
+  const StringRef Status; // either "supported", or "unsupported: REASON"
+  const int BestSpeedLevel;
+  const int DefaultLevel;
+  const int BestSizeLevel;
+
+protected:
+  friend CompressionSpecRef getCompressionSpec(uint8_t Kind);
+  CompressionSpec(CompressionKind Kind, CompressionImpl *Implementation,
+                  StringRef Name, bool Supported, StringRef Status,
+                  int BestSpeedLevel, int DefaultLevel, int BestSizeLevel)
+      : Kind(Kind), Supported(Supported),
+        Implementation(Supported ? Implementation : nullptr), Name(Name),
+        Status(Supported ? "supported" : Status),
+        BestSpeedLevel(BestSpeedLevel), DefaultLevel(DefaultLevel),
+        BestSizeLevel(BestSizeLevel) {}
+};
+
+struct CompressionImpl {
+  const CompressionKind Kind;
+  virtual void compress(ArrayRef<uint8_t> Input,
+                        SmallVectorImpl<uint8_t> &CompressedBuffer,
+                        int Level) = 0;
+  virtual Error decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
+                           size_t &UncompressedSize) = 0;
+  void compress(ArrayRef<uint8_t> Input,
+                SmallVectorImpl<uint8_t> &CompressedBuffer) {
+    return compress(Input, CompressedBuffer,
+                    getCompressionSpec(uint8_t(this->Kind))->DefaultLevel);
+  }
+
+  Error decompress(ArrayRef<uint8_t> Input,
+                   SmallVectorImpl<uint8_t> &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;
+  }
+
+  CompressionSpecRef spec() { return getCompressionSpec(Kind); }
+
+protected:
+  CompressionImpl(CompressionKind Kind) : Kind(Kind) {}
+};
+
+class CompressionSpecRefs {
+public:
+  static CompressionSpecRef Unknown;
+  static CompressionSpecRef None;
+  static CompressionSpecRef Zlib;
+  static CompressionSpecRef ZStd;
+};
 
 } // End of namespace compression
 
Index: llvm/include/llvm/ProfileData/InstrProf.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProf.h
+++ 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<std::string> NameStrs,
-                                bool doCompression, std::string &Result);
+Error collectPGOFuncNameStrings(
+    ArrayRef<std::string> NameStrs,
+    compression::CompressionSpecRef 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.
Index: llvm/include/llvm/Object/Decompressor.h
===================================================================
--- llvm/include/llvm/Object/Decompressor.h
+++ 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,12 @@
 private:
   Decompressor(StringRef Data);
 
-  Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian);
+  Error consumeCompressedSectionHeader(bool Is64Bit, bool IsLittleEndian);
 
   StringRef SectionData;
   uint64_t DecompressedSize;
+  compression::CompressionSpecRef CompressionScheme =
+      compression::CompressionSpecRefs::Zlib;
 };
 
 } // end namespace object
Index: lld/ELF/InputSection.cpp
===================================================================
--- lld/ELF/InputSection.cpp
+++ 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,8 @@
     uncompressedBuf = bAlloc().Allocate<uint8_t>(size);
   }
 
-  if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size))
+  if (Error e = CompressionSpecRefs::Zlib->Implementation->decompress(
+          rawData, uncompressedBuf, size))
     fatal(toString(this) +
           ": uncompress failed: " + llvm::toString(std::move(e)));
   rawData = makeArrayRef(uncompressedBuf, size);
@@ -209,7 +211,7 @@
 
   auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data());
   if (hdr->ch_type == ELFCOMPRESS_ZLIB) {
-    if (!compression::zlib::isAvailable())
+    if (!CompressionSpecRefs::Zlib->Implementation)
       error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is "
                              "not built with zlib support");
   } else {
@@ -1220,7 +1222,8 @@
   // to the buffer.
   if (uncompressedSize >= 0) {
     size_t size = uncompressedSize;
-    if (Error e = compression::zlib::uncompress(rawData, buf, size))
+    if (Error e = CompressionSpecRefs::Zlib->Implementation->decompress(
+            rawData, buf, size))
       fatal(toString(this) +
             ": uncompress failed: " + llvm::toString(std::move(e)));
     uint8_t *bufEnd = buf + size;
Index: lld/ELF/Driver.cpp
===================================================================
--- lld/ELF/Driver.cpp
+++ 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 (!CompressionSpecRefs::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;
 }
 
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -118,6 +118,7 @@
 
 using namespace clang;
 using namespace clang::serialization;
+using namespace llvm::compression;
 
 template <typename T, typename Allocator>
 static StringRef bytes(const std::vector<T, Allocator> &v) {
@@ -1999,9 +2000,11 @@
 
   // Compress the buffer if possible. We expect that almost all PCM
   // consumers will not want its contents.
-  SmallVector<uint8_t, 0> CompressedBuffer;
-  if (llvm::compression::zlib::isAvailable()) {
-    llvm::compression::zlib::compress(
+  if (CompressionImplRef CompressionImplementation =
+          CompressionSpecRefs::Zlib->Implementation) {
+    SmallVector<uint8_t, 0> CompressedBuffer;
+
+    CompressionImplementation->compress(
         llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer);
     RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1};
     Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record,
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ 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,24 @@
     unsigned RecCode = MaybeRecCode.get();
 
     if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) {
-      if (!llvm::compression::zlib::isAvailable()) {
-        Error("zlib is not available");
-        return nullptr;
-      }
-      SmallVector<uint8_t, 0> 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)));
+      CompressionSpecRef CompressionScheme = CompressionSpecRefs::Zlib;
+
+      if (CompressionImplRef CompressionImplementation =
+              CompressionScheme->Implementation) {
+        SmallVector<uint8_t, 0> 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 {
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -1139,7 +1139,7 @@
     if (Value == "none") {
       CmdArgs.push_back("--compress-debug-sections=none");
     } else if (Value == "zlib") {
-      if (llvm::compression::zlib::isAvailable()) {
+      if (llvm::compression::CompressionSpecRefs::Zlib->Implementation) {
         CmdArgs.push_back(
             Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
       } else {
Index: clang-tools-extra/clangd/unittests/SerializationTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SerializationTests.cpp
+++ 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 (!CompressionSpecRefs::Zlib->Implementation) {
     log("skipping test, no zlib");
     return;
   }
Index: clang-tools-extra/clangd/index/Serialization.cpp
===================================================================
--- clang-tools-extra/clangd/index/Serialization.cpp
+++ clang-tools-extra/clangd/index/Serialization.cpp
@@ -16,6 +16,7 @@
 #include "support/Logger.h"
 #include "support/Trace.h"
 #include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Compression.h"
@@ -25,6 +26,8 @@
 #include <cstdint>
 #include <vector>
 
+using namespace llvm::compression;
+
 namespace clang {
 namespace clangd {
 namespace {
@@ -190,10 +193,11 @@
       RawTable.append(std::string(S));
       RawTable.push_back(0);
     }
-    if (llvm::compression::zlib::isAvailable()) {
+    if (CompressionImplRef CompressionImplementation =
+            CompressionSpecRefs::Zlib->Implementation) {
       llvm::SmallVector<uint8_t, 0> 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 +228,30 @@
   llvm::SmallVector<uint8_t, 0> 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 (CompressionImplRef CompressionImplementation =
+            CompressionSpecRefs::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",
+                   CompressionSpecRefs::Zlib->Name);
+  }
 
   StringTableIn Table;
   llvm::StringSaver Saver(Table.Arena);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to