brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · 3979ca6 Raw
245 lines · cpp
1//===--- Compression.cpp - Compression implementation ---------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  This file implements compression functions.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Support/Compression.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/Config/config.h"17#include "llvm/Support/Compiler.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/ErrorHandling.h"20#if LLVM_ENABLE_ZLIB21#include <zlib.h>22#endif23#if LLVM_ENABLE_ZSTD24#include <zstd.h>25#endif26 27using namespace llvm;28using namespace llvm::compression;29 30const char *compression::getReasonIfUnsupported(compression::Format F) {31  switch (F) {32  case compression::Format::Zlib:33    if (zlib::isAvailable())34      return nullptr;35    return "LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at "36           "build time";37  case compression::Format::Zstd:38    if (zstd::isAvailable())39      return nullptr;40    return "LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at "41           "build time";42  }43  llvm_unreachable("");44}45 46void compression::compress(Params P, ArrayRef<uint8_t> Input,47                           SmallVectorImpl<uint8_t> &Output) {48  switch (P.format) {49  case compression::Format::Zlib:50    zlib::compress(Input, Output, P.level);51    break;52  case compression::Format::Zstd:53    zstd::compress(Input, Output, P.level, P.zstdEnableLdm);54    break;55  }56}57 58Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,59                              uint8_t *Output, size_t UncompressedSize) {60  switch (formatFor(T)) {61  case compression::Format::Zlib:62    return zlib::decompress(Input, Output, UncompressedSize);63  case compression::Format::Zstd:64    return zstd::decompress(Input, Output, UncompressedSize);65  }66  llvm_unreachable("");67}68 69Error compression::decompress(compression::Format F, ArrayRef<uint8_t> Input,70                              SmallVectorImpl<uint8_t> &Output,71                              size_t UncompressedSize) {72  switch (F) {73  case compression::Format::Zlib:74    return zlib::decompress(Input, Output, UncompressedSize);75  case compression::Format::Zstd:76    return zstd::decompress(Input, Output, UncompressedSize);77  }78  llvm_unreachable("");79}80 81Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,82                              SmallVectorImpl<uint8_t> &Output,83                              size_t UncompressedSize) {84  return decompress(formatFor(T), Input, Output, UncompressedSize);85}86 87#if LLVM_ENABLE_ZLIB88 89static StringRef convertZlibCodeToString(int Code) {90  switch (Code) {91  case Z_MEM_ERROR:92    return "zlib error: Z_MEM_ERROR";93  case Z_BUF_ERROR:94    return "zlib error: Z_BUF_ERROR";95  case Z_STREAM_ERROR:96    return "zlib error: Z_STREAM_ERROR";97  case Z_DATA_ERROR:98    return "zlib error: Z_DATA_ERROR";99  case Z_OK:100  default:101    llvm_unreachable("unknown or unexpected zlib status code");102  }103}104 105bool zlib::isAvailable() { return true; }106 107void zlib::compress(ArrayRef<uint8_t> Input,108                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {109  unsigned long CompressedSize = ::compressBound(Input.size());110  CompressedBuffer.resize_for_overwrite(CompressedSize);111  int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,112                        (const Bytef *)Input.data(), Input.size(), Level);113  if (Res == Z_MEM_ERROR)114    report_bad_alloc_error("Allocation failed");115  assert(Res == Z_OK);116  // Tell MemorySanitizer that zlib output buffer is fully initialized.117  // This avoids a false report when running LLVM with uninstrumented ZLib.118  __msan_unpoison(CompressedBuffer.data(), CompressedSize);119  if (CompressedSize < CompressedBuffer.size())120    CompressedBuffer.truncate(CompressedSize);121}122 123Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,124                       size_t &UncompressedSize) {125  int Res = ::uncompress((Bytef *)Output, (uLongf *)&UncompressedSize,126                         (const Bytef *)Input.data(), Input.size());127  // Tell MemorySanitizer that zlib output buffer is fully initialized.128  // This avoids a false report when running LLVM with uninstrumented ZLib.129  __msan_unpoison(Output, UncompressedSize);130  return Res ? make_error<StringError>(convertZlibCodeToString(Res),131                                       inconvertibleErrorCode())132             : Error::success();133}134 135Error zlib::decompress(ArrayRef<uint8_t> Input,136                       SmallVectorImpl<uint8_t> &Output,137                       size_t UncompressedSize) {138  Output.resize_for_overwrite(UncompressedSize);139  Error E = zlib::decompress(Input, Output.data(), UncompressedSize);140  if (UncompressedSize < Output.size())141    Output.truncate(UncompressedSize);142  return E;143}144 145#else146bool zlib::isAvailable() { return false; }147void zlib::compress(ArrayRef<uint8_t> Input,148                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {149  llvm_unreachable("zlib::compress is unavailable");150}151Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,152                       size_t &UncompressedSize) {153  llvm_unreachable("zlib::decompress is unavailable");154}155Error zlib::decompress(ArrayRef<uint8_t> Input,156                       SmallVectorImpl<uint8_t> &UncompressedBuffer,157                       size_t UncompressedSize) {158  llvm_unreachable("zlib::decompress is unavailable");159}160#endif161 162#if LLVM_ENABLE_ZSTD163 164bool zstd::isAvailable() { return true; }165 166#include <zstd.h> // Ensure ZSTD library is included167 168void zstd::compress(ArrayRef<uint8_t> Input,169                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,170                    bool EnableLdm) {171  ZSTD_CCtx *Cctx = ZSTD_createCCtx();172  if (!Cctx)173    report_bad_alloc_error("Failed to create ZSTD_CCtx");174 175  if (ZSTD_isError(ZSTD_CCtx_setParameter(176          Cctx, ZSTD_c_enableLongDistanceMatching, EnableLdm ? 1 : 0))) {177    ZSTD_freeCCtx(Cctx);178    report_bad_alloc_error("Failed to set ZSTD_c_enableLongDistanceMatching");179  }180 181  if (ZSTD_isError(182          ZSTD_CCtx_setParameter(Cctx, ZSTD_c_compressionLevel, Level))) {183    ZSTD_freeCCtx(Cctx);184    report_bad_alloc_error("Failed to set ZSTD_c_compressionLevel");185  }186 187  unsigned long CompressedBufferSize = ZSTD_compressBound(Input.size());188  CompressedBuffer.resize_for_overwrite(CompressedBufferSize);189 190  size_t const CompressedSize =191      ZSTD_compress2(Cctx, CompressedBuffer.data(), CompressedBufferSize,192                     Input.data(), Input.size());193 194  ZSTD_freeCCtx(Cctx);195 196  if (ZSTD_isError(CompressedSize))197    report_bad_alloc_error("Compression failed");198 199  __msan_unpoison(CompressedBuffer.data(), CompressedSize);200  if (CompressedSize < CompressedBuffer.size())201    CompressedBuffer.truncate(CompressedSize);202}203 204Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,205                       size_t &UncompressedSize) {206  const size_t Res = ::ZSTD_decompress(207      Output, UncompressedSize, (const uint8_t *)Input.data(), Input.size());208  UncompressedSize = Res;209  if (ZSTD_isError(Res))210    return make_error<StringError>(ZSTD_getErrorName(Res),211                                   inconvertibleErrorCode());212  // Tell MemorySanitizer that zstd output buffer is fully initialized.213  // This avoids a false report when running LLVM with uninstrumented ZLib.214  __msan_unpoison(Output, UncompressedSize);215  return Error::success();216}217 218Error zstd::decompress(ArrayRef<uint8_t> Input,219                       SmallVectorImpl<uint8_t> &Output,220                       size_t UncompressedSize) {221  Output.resize_for_overwrite(UncompressedSize);222  Error E = zstd::decompress(Input, Output.data(), UncompressedSize);223  if (UncompressedSize < Output.size())224    Output.truncate(UncompressedSize);225  return E;226}227 228#else229bool zstd::isAvailable() { return false; }230void zstd::compress(ArrayRef<uint8_t> Input,231                    SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,232                    bool EnableLdm) {233  llvm_unreachable("zstd::compress is unavailable");234}235Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,236                       size_t &UncompressedSize) {237  llvm_unreachable("zstd::decompress is unavailable");238}239Error zstd::decompress(ArrayRef<uint8_t> Input,240                       SmallVectorImpl<uint8_t> &Output,241                       size_t UncompressedSize) {242  llvm_unreachable("zstd::decompress is unavailable");243}244#endif245