10b57cec5SDimitry Andric //===--- Compression.cpp - Compression implementation ---------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements compression functions. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/Support/Compression.h" 140b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 160b57cec5SDimitry Andric #include "llvm/Config/config.h" 170b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 180b57cec5SDimitry Andric #include "llvm/Support/Error.h" 190b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 20e8d8bef9SDimitry Andric #if LLVM_ENABLE_ZLIB 210b57cec5SDimitry Andric #include <zlib.h> 220b57cec5SDimitry Andric #endif 23fcaf7f86SDimitry Andric #if LLVM_ENABLE_ZSTD 24fcaf7f86SDimitry Andric #include <zstd.h> 25fcaf7f86SDimitry Andric #endif 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace llvm; 28753f127fSDimitry Andric using namespace llvm::compression; 290b57cec5SDimitry Andric 30bdd1243dSDimitry Andric const char *compression::getReasonIfUnsupported(compression::Format F) { 31bdd1243dSDimitry Andric switch (F) { 32bdd1243dSDimitry Andric case compression::Format::Zlib: 33bdd1243dSDimitry Andric if (zlib::isAvailable()) 34bdd1243dSDimitry Andric return nullptr; 35bdd1243dSDimitry Andric return "LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at " 36bdd1243dSDimitry Andric "build time"; 37bdd1243dSDimitry Andric case compression::Format::Zstd: 38bdd1243dSDimitry Andric if (zstd::isAvailable()) 39bdd1243dSDimitry Andric return nullptr; 40bdd1243dSDimitry Andric return "LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at " 41bdd1243dSDimitry Andric "build time"; 42bdd1243dSDimitry Andric } 43bdd1243dSDimitry Andric llvm_unreachable(""); 44bdd1243dSDimitry Andric } 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric void compression::compress(Params P, ArrayRef<uint8_t> Input, 47bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output) { 48bdd1243dSDimitry Andric switch (P.format) { 49bdd1243dSDimitry Andric case compression::Format::Zlib: 50bdd1243dSDimitry Andric zlib::compress(Input, Output, P.level); 51bdd1243dSDimitry Andric break; 52bdd1243dSDimitry Andric case compression::Format::Zstd: 53*0fca6ea1SDimitry Andric zstd::compress(Input, Output, P.level, P.zstdEnableLdm); 54bdd1243dSDimitry Andric break; 55bdd1243dSDimitry Andric } 56bdd1243dSDimitry Andric } 57bdd1243dSDimitry Andric 58bdd1243dSDimitry Andric Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input, 59bdd1243dSDimitry Andric uint8_t *Output, size_t UncompressedSize) { 60bdd1243dSDimitry Andric switch (formatFor(T)) { 61bdd1243dSDimitry Andric case compression::Format::Zlib: 62bdd1243dSDimitry Andric return zlib::decompress(Input, Output, UncompressedSize); 63bdd1243dSDimitry Andric case compression::Format::Zstd: 64bdd1243dSDimitry Andric return zstd::decompress(Input, Output, UncompressedSize); 65bdd1243dSDimitry Andric } 66bdd1243dSDimitry Andric llvm_unreachable(""); 67bdd1243dSDimitry Andric } 68bdd1243dSDimitry Andric 69bdd1243dSDimitry Andric Error compression::decompress(compression::Format F, ArrayRef<uint8_t> Input, 70bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output, 71bdd1243dSDimitry Andric size_t UncompressedSize) { 72bdd1243dSDimitry Andric switch (F) { 73bdd1243dSDimitry Andric case compression::Format::Zlib: 74bdd1243dSDimitry Andric return zlib::decompress(Input, Output, UncompressedSize); 75bdd1243dSDimitry Andric case compression::Format::Zstd: 76bdd1243dSDimitry Andric return zstd::decompress(Input, Output, UncompressedSize); 77bdd1243dSDimitry Andric } 78bdd1243dSDimitry Andric llvm_unreachable(""); 79bdd1243dSDimitry Andric } 80bdd1243dSDimitry Andric 81bdd1243dSDimitry Andric Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input, 82bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output, 83bdd1243dSDimitry Andric size_t UncompressedSize) { 84bdd1243dSDimitry Andric return decompress(formatFor(T), Input, Output, UncompressedSize); 85bdd1243dSDimitry Andric } 86bdd1243dSDimitry Andric 87e8d8bef9SDimitry Andric #if LLVM_ENABLE_ZLIB 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric static StringRef convertZlibCodeToString(int Code) { 900b57cec5SDimitry Andric switch (Code) { 910b57cec5SDimitry Andric case Z_MEM_ERROR: 920b57cec5SDimitry Andric return "zlib error: Z_MEM_ERROR"; 930b57cec5SDimitry Andric case Z_BUF_ERROR: 940b57cec5SDimitry Andric return "zlib error: Z_BUF_ERROR"; 950b57cec5SDimitry Andric case Z_STREAM_ERROR: 960b57cec5SDimitry Andric return "zlib error: Z_STREAM_ERROR"; 970b57cec5SDimitry Andric case Z_DATA_ERROR: 980b57cec5SDimitry Andric return "zlib error: Z_DATA_ERROR"; 990b57cec5SDimitry Andric case Z_OK: 1000b57cec5SDimitry Andric default: 1010b57cec5SDimitry Andric llvm_unreachable("unknown or unexpected zlib status code"); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric bool zlib::isAvailable() { return true; } 1060b57cec5SDimitry Andric 107753f127fSDimitry Andric void zlib::compress(ArrayRef<uint8_t> Input, 108753f127fSDimitry Andric SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 109753f127fSDimitry Andric unsigned long CompressedSize = ::compressBound(Input.size()); 1100eae32dcSDimitry Andric CompressedBuffer.resize_for_overwrite(CompressedSize); 111753f127fSDimitry Andric int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, 112753f127fSDimitry Andric (const Bytef *)Input.data(), Input.size(), Level); 11381ad6265SDimitry Andric if (Res == Z_MEM_ERROR) 11481ad6265SDimitry Andric report_bad_alloc_error("Allocation failed"); 11581ad6265SDimitry Andric assert(Res == Z_OK); 1160b57cec5SDimitry Andric // Tell MemorySanitizer that zlib output buffer is fully initialized. 1170b57cec5SDimitry Andric // This avoids a false report when running LLVM with uninstrumented ZLib. 1180b57cec5SDimitry Andric __msan_unpoison(CompressedBuffer.data(), CompressedSize); 119753f127fSDimitry Andric if (CompressedSize < CompressedBuffer.size()) 1200eae32dcSDimitry Andric CompressedBuffer.truncate(CompressedSize); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 123bdd1243dSDimitry Andric Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 1240b57cec5SDimitry Andric size_t &UncompressedSize) { 125bdd1243dSDimitry Andric int Res = ::uncompress((Bytef *)Output, (uLongf *)&UncompressedSize, 126753f127fSDimitry Andric (const Bytef *)Input.data(), Input.size()); 1270b57cec5SDimitry Andric // Tell MemorySanitizer that zlib output buffer is fully initialized. 1280b57cec5SDimitry Andric // This avoids a false report when running LLVM with uninstrumented ZLib. 129bdd1243dSDimitry Andric __msan_unpoison(Output, UncompressedSize); 130753f127fSDimitry Andric return Res ? make_error<StringError>(convertZlibCodeToString(Res), 131753f127fSDimitry Andric inconvertibleErrorCode()) 132753f127fSDimitry Andric : Error::success(); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 135bdd1243dSDimitry Andric Error zlib::decompress(ArrayRef<uint8_t> Input, 136bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output, 1370b57cec5SDimitry Andric size_t UncompressedSize) { 138bdd1243dSDimitry Andric Output.resize_for_overwrite(UncompressedSize); 139bdd1243dSDimitry Andric Error E = zlib::decompress(Input, Output.data(), UncompressedSize); 140bdd1243dSDimitry Andric if (UncompressedSize < Output.size()) 141bdd1243dSDimitry Andric Output.truncate(UncompressedSize); 1420b57cec5SDimitry Andric return E; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric #else 1460b57cec5SDimitry Andric bool zlib::isAvailable() { return false; } 147753f127fSDimitry Andric void zlib::compress(ArrayRef<uint8_t> Input, 148753f127fSDimitry Andric SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 1490b57cec5SDimitry Andric llvm_unreachable("zlib::compress is unavailable"); 1500b57cec5SDimitry Andric } 151bdd1243dSDimitry Andric Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 1520b57cec5SDimitry Andric size_t &UncompressedSize) { 153bdd1243dSDimitry Andric llvm_unreachable("zlib::decompress is unavailable"); 1540b57cec5SDimitry Andric } 155bdd1243dSDimitry Andric Error zlib::decompress(ArrayRef<uint8_t> Input, 156753f127fSDimitry Andric SmallVectorImpl<uint8_t> &UncompressedBuffer, 1570b57cec5SDimitry Andric size_t UncompressedSize) { 158bdd1243dSDimitry Andric llvm_unreachable("zlib::decompress is unavailable"); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric #endif 161fcaf7f86SDimitry Andric 162fcaf7f86SDimitry Andric #if LLVM_ENABLE_ZSTD 163fcaf7f86SDimitry Andric 164fcaf7f86SDimitry Andric bool zstd::isAvailable() { return true; } 165fcaf7f86SDimitry Andric 166*0fca6ea1SDimitry Andric #include <zstd.h> // Ensure ZSTD library is included 167*0fca6ea1SDimitry Andric 168fcaf7f86SDimitry Andric void zstd::compress(ArrayRef<uint8_t> Input, 169*0fca6ea1SDimitry Andric SmallVectorImpl<uint8_t> &CompressedBuffer, int Level, 170*0fca6ea1SDimitry Andric bool EnableLdm) { 171*0fca6ea1SDimitry Andric ZSTD_CCtx *Cctx = ZSTD_createCCtx(); 172*0fca6ea1SDimitry Andric if (!Cctx) 173*0fca6ea1SDimitry Andric report_bad_alloc_error("Failed to create ZSTD_CCtx"); 174*0fca6ea1SDimitry Andric 175*0fca6ea1SDimitry Andric if (ZSTD_isError(ZSTD_CCtx_setParameter( 176*0fca6ea1SDimitry Andric Cctx, ZSTD_c_enableLongDistanceMatching, EnableLdm ? 1 : 0))) { 177*0fca6ea1SDimitry Andric ZSTD_freeCCtx(Cctx); 178*0fca6ea1SDimitry Andric report_bad_alloc_error("Failed to set ZSTD_c_enableLongDistanceMatching"); 179*0fca6ea1SDimitry Andric } 180*0fca6ea1SDimitry Andric 181*0fca6ea1SDimitry Andric if (ZSTD_isError( 182*0fca6ea1SDimitry Andric ZSTD_CCtx_setParameter(Cctx, ZSTD_c_compressionLevel, Level))) { 183*0fca6ea1SDimitry Andric ZSTD_freeCCtx(Cctx); 184*0fca6ea1SDimitry Andric report_bad_alloc_error("Failed to set ZSTD_c_compressionLevel"); 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric 187*0fca6ea1SDimitry Andric unsigned long CompressedBufferSize = ZSTD_compressBound(Input.size()); 188fcaf7f86SDimitry Andric CompressedBuffer.resize_for_overwrite(CompressedBufferSize); 189*0fca6ea1SDimitry Andric 190*0fca6ea1SDimitry Andric size_t const CompressedSize = 191*0fca6ea1SDimitry Andric ZSTD_compress2(Cctx, CompressedBuffer.data(), CompressedBufferSize, 192*0fca6ea1SDimitry Andric Input.data(), Input.size()); 193*0fca6ea1SDimitry Andric 194*0fca6ea1SDimitry Andric ZSTD_freeCCtx(Cctx); 195*0fca6ea1SDimitry Andric 196fcaf7f86SDimitry Andric if (ZSTD_isError(CompressedSize)) 197*0fca6ea1SDimitry Andric report_bad_alloc_error("Compression failed"); 198*0fca6ea1SDimitry Andric 199fcaf7f86SDimitry Andric __msan_unpoison(CompressedBuffer.data(), CompressedSize); 200fcaf7f86SDimitry Andric if (CompressedSize < CompressedBuffer.size()) 201fcaf7f86SDimitry Andric CompressedBuffer.truncate(CompressedSize); 202fcaf7f86SDimitry Andric } 203fcaf7f86SDimitry Andric 204bdd1243dSDimitry Andric Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 205fcaf7f86SDimitry Andric size_t &UncompressedSize) { 206bdd1243dSDimitry Andric const size_t Res = ::ZSTD_decompress( 207bdd1243dSDimitry Andric Output, UncompressedSize, (const uint8_t *)Input.data(), Input.size()); 208fcaf7f86SDimitry Andric UncompressedSize = Res; 209fcaf7f86SDimitry Andric // Tell MemorySanitizer that zstd output buffer is fully initialized. 210fcaf7f86SDimitry Andric // This avoids a false report when running LLVM with uninstrumented ZLib. 211bdd1243dSDimitry Andric __msan_unpoison(Output, UncompressedSize); 212fcaf7f86SDimitry Andric return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res), 213fcaf7f86SDimitry Andric inconvertibleErrorCode()) 214fcaf7f86SDimitry Andric : Error::success(); 215fcaf7f86SDimitry Andric } 216fcaf7f86SDimitry Andric 217bdd1243dSDimitry Andric Error zstd::decompress(ArrayRef<uint8_t> Input, 218bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output, 219fcaf7f86SDimitry Andric size_t UncompressedSize) { 220bdd1243dSDimitry Andric Output.resize_for_overwrite(UncompressedSize); 221bdd1243dSDimitry Andric Error E = zstd::decompress(Input, Output.data(), UncompressedSize); 222bdd1243dSDimitry Andric if (UncompressedSize < Output.size()) 223bdd1243dSDimitry Andric Output.truncate(UncompressedSize); 224fcaf7f86SDimitry Andric return E; 225fcaf7f86SDimitry Andric } 226fcaf7f86SDimitry Andric 227fcaf7f86SDimitry Andric #else 228fcaf7f86SDimitry Andric bool zstd::isAvailable() { return false; } 229fcaf7f86SDimitry Andric void zstd::compress(ArrayRef<uint8_t> Input, 230*0fca6ea1SDimitry Andric SmallVectorImpl<uint8_t> &CompressedBuffer, int Level, 231*0fca6ea1SDimitry Andric bool EnableLdm) { 232fcaf7f86SDimitry Andric llvm_unreachable("zstd::compress is unavailable"); 233fcaf7f86SDimitry Andric } 234bdd1243dSDimitry Andric Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 235fcaf7f86SDimitry Andric size_t &UncompressedSize) { 236bdd1243dSDimitry Andric llvm_unreachable("zstd::decompress is unavailable"); 237fcaf7f86SDimitry Andric } 238bdd1243dSDimitry Andric Error zstd::decompress(ArrayRef<uint8_t> Input, 239bdd1243dSDimitry Andric SmallVectorImpl<uint8_t> &Output, 240fcaf7f86SDimitry Andric size_t UncompressedSize) { 241bdd1243dSDimitry Andric llvm_unreachable("zstd::decompress is unavailable"); 242fcaf7f86SDimitry Andric } 243fcaf7f86SDimitry Andric #endif 244