Path: blob/main/contrib/llvm-project/llvm/lib/Support/Compression.cpp
35232 views
//===--- Compression.cpp - Compression implementation ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements compression functions.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Support/Compression.h"13#include "llvm/ADT/SmallVector.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Config/config.h"16#include "llvm/Support/Compiler.h"17#include "llvm/Support/Error.h"18#include "llvm/Support/ErrorHandling.h"19#if LLVM_ENABLE_ZLIB20#include <zlib.h>21#endif22#if LLVM_ENABLE_ZSTD23#include <zstd.h>24#endif2526using namespace llvm;27using namespace llvm::compression;2829const char *compression::getReasonIfUnsupported(compression::Format F) {30switch (F) {31case compression::Format::Zlib:32if (zlib::isAvailable())33return nullptr;34return "LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at "35"build time";36case compression::Format::Zstd:37if (zstd::isAvailable())38return nullptr;39return "LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at "40"build time";41}42llvm_unreachable("");43}4445void compression::compress(Params P, ArrayRef<uint8_t> Input,46SmallVectorImpl<uint8_t> &Output) {47switch (P.format) {48case compression::Format::Zlib:49zlib::compress(Input, Output, P.level);50break;51case compression::Format::Zstd:52zstd::compress(Input, Output, P.level, P.zstdEnableLdm);53break;54}55}5657Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,58uint8_t *Output, size_t UncompressedSize) {59switch (formatFor(T)) {60case compression::Format::Zlib:61return zlib::decompress(Input, Output, UncompressedSize);62case compression::Format::Zstd:63return zstd::decompress(Input, Output, UncompressedSize);64}65llvm_unreachable("");66}6768Error compression::decompress(compression::Format F, ArrayRef<uint8_t> Input,69SmallVectorImpl<uint8_t> &Output,70size_t UncompressedSize) {71switch (F) {72case compression::Format::Zlib:73return zlib::decompress(Input, Output, UncompressedSize);74case compression::Format::Zstd:75return zstd::decompress(Input, Output, UncompressedSize);76}77llvm_unreachable("");78}7980Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,81SmallVectorImpl<uint8_t> &Output,82size_t UncompressedSize) {83return decompress(formatFor(T), Input, Output, UncompressedSize);84}8586#if LLVM_ENABLE_ZLIB8788static StringRef convertZlibCodeToString(int Code) {89switch (Code) {90case Z_MEM_ERROR:91return "zlib error: Z_MEM_ERROR";92case Z_BUF_ERROR:93return "zlib error: Z_BUF_ERROR";94case Z_STREAM_ERROR:95return "zlib error: Z_STREAM_ERROR";96case Z_DATA_ERROR:97return "zlib error: Z_DATA_ERROR";98case Z_OK:99default:100llvm_unreachable("unknown or unexpected zlib status code");101}102}103104bool zlib::isAvailable() { return true; }105106void zlib::compress(ArrayRef<uint8_t> Input,107SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {108unsigned long CompressedSize = ::compressBound(Input.size());109CompressedBuffer.resize_for_overwrite(CompressedSize);110int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,111(const Bytef *)Input.data(), Input.size(), Level);112if (Res == Z_MEM_ERROR)113report_bad_alloc_error("Allocation failed");114assert(Res == Z_OK);115// Tell MemorySanitizer that zlib output buffer is fully initialized.116// This avoids a false report when running LLVM with uninstrumented ZLib.117__msan_unpoison(CompressedBuffer.data(), CompressedSize);118if (CompressedSize < CompressedBuffer.size())119CompressedBuffer.truncate(CompressedSize);120}121122Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,123size_t &UncompressedSize) {124int Res = ::uncompress((Bytef *)Output, (uLongf *)&UncompressedSize,125(const Bytef *)Input.data(), Input.size());126// Tell MemorySanitizer that zlib output buffer is fully initialized.127// This avoids a false report when running LLVM with uninstrumented ZLib.128__msan_unpoison(Output, UncompressedSize);129return Res ? make_error<StringError>(convertZlibCodeToString(Res),130inconvertibleErrorCode())131: Error::success();132}133134Error zlib::decompress(ArrayRef<uint8_t> Input,135SmallVectorImpl<uint8_t> &Output,136size_t UncompressedSize) {137Output.resize_for_overwrite(UncompressedSize);138Error E = zlib::decompress(Input, Output.data(), UncompressedSize);139if (UncompressedSize < Output.size())140Output.truncate(UncompressedSize);141return E;142}143144#else145bool zlib::isAvailable() { return false; }146void zlib::compress(ArrayRef<uint8_t> Input,147SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {148llvm_unreachable("zlib::compress is unavailable");149}150Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,151size_t &UncompressedSize) {152llvm_unreachable("zlib::decompress is unavailable");153}154Error zlib::decompress(ArrayRef<uint8_t> Input,155SmallVectorImpl<uint8_t> &UncompressedBuffer,156size_t UncompressedSize) {157llvm_unreachable("zlib::decompress is unavailable");158}159#endif160161#if LLVM_ENABLE_ZSTD162163bool zstd::isAvailable() { return true; }164165#include <zstd.h> // Ensure ZSTD library is included166167void zstd::compress(ArrayRef<uint8_t> Input,168SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,169bool EnableLdm) {170ZSTD_CCtx *Cctx = ZSTD_createCCtx();171if (!Cctx)172report_bad_alloc_error("Failed to create ZSTD_CCtx");173174if (ZSTD_isError(ZSTD_CCtx_setParameter(175Cctx, ZSTD_c_enableLongDistanceMatching, EnableLdm ? 1 : 0))) {176ZSTD_freeCCtx(Cctx);177report_bad_alloc_error("Failed to set ZSTD_c_enableLongDistanceMatching");178}179180if (ZSTD_isError(181ZSTD_CCtx_setParameter(Cctx, ZSTD_c_compressionLevel, Level))) {182ZSTD_freeCCtx(Cctx);183report_bad_alloc_error("Failed to set ZSTD_c_compressionLevel");184}185186unsigned long CompressedBufferSize = ZSTD_compressBound(Input.size());187CompressedBuffer.resize_for_overwrite(CompressedBufferSize);188189size_t const CompressedSize =190ZSTD_compress2(Cctx, CompressedBuffer.data(), CompressedBufferSize,191Input.data(), Input.size());192193ZSTD_freeCCtx(Cctx);194195if (ZSTD_isError(CompressedSize))196report_bad_alloc_error("Compression failed");197198__msan_unpoison(CompressedBuffer.data(), CompressedSize);199if (CompressedSize < CompressedBuffer.size())200CompressedBuffer.truncate(CompressedSize);201}202203Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,204size_t &UncompressedSize) {205const size_t Res = ::ZSTD_decompress(206Output, UncompressedSize, (const uint8_t *)Input.data(), Input.size());207UncompressedSize = Res;208// Tell MemorySanitizer that zstd output buffer is fully initialized.209// This avoids a false report when running LLVM with uninstrumented ZLib.210__msan_unpoison(Output, UncompressedSize);211return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res),212inconvertibleErrorCode())213: Error::success();214}215216Error zstd::decompress(ArrayRef<uint8_t> Input,217SmallVectorImpl<uint8_t> &Output,218size_t UncompressedSize) {219Output.resize_for_overwrite(UncompressedSize);220Error E = zstd::decompress(Input, Output.data(), UncompressedSize);221if (UncompressedSize < Output.size())222Output.truncate(UncompressedSize);223return E;224}225226#else227bool zstd::isAvailable() { return false; }228void zstd::compress(ArrayRef<uint8_t> Input,229SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,230bool EnableLdm) {231llvm_unreachable("zstd::compress is unavailable");232}233Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,234size_t &UncompressedSize) {235llvm_unreachable("zstd::decompress is unavailable");236}237Error zstd::decompress(ArrayRef<uint8_t> Input,238SmallVectorImpl<uint8_t> &Output,239size_t UncompressedSize) {240llvm_unreachable("zstd::decompress is unavailable");241}242#endif243244245