|
67 | 67 | #include <string>
|
68 | 68 | #include <tuple>
|
69 | 69 |
|
| 70 | +// For device image compression. |
| 71 | +#include <llvm/Support/Compression.h> |
| 72 | + |
70 | 73 | #define OPENMP_OFFLOAD_IMAGE_VERSION "1.0"
|
71 | 74 |
|
72 | 75 | using namespace llvm;
|
@@ -139,15 +142,35 @@ static cl::list<std::string> Inputs(cl::Positional, cl::OneOrMore,
|
139 | 142 | cl::desc("<input files>"),
|
140 | 143 | cl::cat(ClangOffloadWrapperCategory));
|
141 | 144 |
|
| 145 | +// CLI options for device image compression. |
| 146 | +static cl::opt<bool> OffloadCompressDevImgs( |
| 147 | + "offload-compress", cl::init(false), cl::Optional, |
| 148 | + cl::desc("Enable device image compression using ZSTD."), |
| 149 | + cl::cat(ClangOffloadWrapperCategory)); |
| 150 | + |
| 151 | +static cl::opt<int> |
| 152 | + OffloadCompressLevel("offload-compression-level", cl::init(10), |
| 153 | + cl::Optional, |
| 154 | + cl::desc("ZSTD Compression level. Default: 10"), |
| 155 | + cl::cat(ClangOffloadWrapperCategory)); |
| 156 | + |
| 157 | +static cl::opt<int> |
| 158 | + OffloadCompressThreshold("offload-compression-threshold", cl::init(512), |
| 159 | + cl::Optional, |
| 160 | + cl::desc("Threshold (in bytes) over which to " |
| 161 | + "compress images. Default: 512"), |
| 162 | + cl::cat(ClangOffloadWrapperCategory)); |
| 163 | + |
142 | 164 | // Binary image formats supported by this tool. The support basically means
|
143 | 165 | // mapping string representation given at the command line to a value from this
|
144 | 166 | // enum. No format checking is performed.
|
145 | 167 | enum BinaryImageFormat {
|
146 | 168 | none, // image kind is not determined
|
147 | 169 | native, // image kind is native
|
148 | 170 | // portable image kinds go next
|
149 |
| - spirv, // SPIR-V |
150 |
| - llvmbc // LLVM bitcode |
| 171 | + spirv, // SPIR-V |
| 172 | + llvmbc, // LLVM bitcode |
| 173 | + compressed_none // compressed image with unknown format |
151 | 174 | };
|
152 | 175 |
|
153 | 176 | /// Sets offload kind.
|
@@ -265,6 +288,8 @@ static StringRef formatToString(BinaryImageFormat Fmt) {
|
265 | 288 | return "llvmbc";
|
266 | 289 | case BinaryImageFormat::native:
|
267 | 290 | return "native";
|
| 291 | + case BinaryImageFormat::compressed_none: |
| 292 | + return "compressed_none"; |
268 | 293 | }
|
269 | 294 | llvm_unreachable("bad format");
|
270 | 295 |
|
@@ -1083,10 +1108,66 @@ class BinaryWrapper {
|
1083 | 1108 | return FBinOrErr.takeError();
|
1084 | 1109 | Fbin = *FBinOrErr;
|
1085 | 1110 | } else {
|
1086 |
| - Fbin = addDeviceImageToModule( |
1087 |
| - ArrayRef<char>(Bin->getBufferStart(), Bin->getBufferSize()), |
1088 |
| - Twine(OffloadKindTag) + Twine(ImgId) + Twine(".data"), Kind, |
1089 |
| - Img.Tgt); |
| 1111 | + |
| 1112 | + // If '--offload-compress' option is specified and zstd is not |
| 1113 | + // available, throw an error. |
| 1114 | + if (OffloadCompressDevImgs && !llvm::compression::zstd::isAvailable()) { |
| 1115 | + return createStringError( |
| 1116 | + inconvertibleErrorCode(), |
| 1117 | + "'--offload-compress' option is specified but zstd " |
| 1118 | + "is not available. The device image will not be " |
| 1119 | + "compressed."); |
| 1120 | + } |
| 1121 | + |
| 1122 | + // Don't compress if the user explicitly specifies the binary image |
| 1123 | + // format or if the image is smaller than OffloadCompressThreshold |
| 1124 | + // bytes. |
| 1125 | + if (Kind != OffloadKind::SYCL || !OffloadCompressDevImgs || |
| 1126 | + Img.Fmt != BinaryImageFormat::none || |
| 1127 | + !llvm::compression::zstd::isAvailable() || |
| 1128 | + static_cast<int>(Bin->getBufferSize()) < OffloadCompressThreshold) { |
| 1129 | + Fbin = addDeviceImageToModule( |
| 1130 | + ArrayRef<char>(Bin->getBufferStart(), Bin->getBufferSize()), |
| 1131 | + Twine(OffloadKindTag) + Twine(ImgId) + Twine(".data"), Kind, |
| 1132 | + Img.Tgt); |
| 1133 | + } else { |
| 1134 | + |
| 1135 | + // Compress the image using zstd. |
| 1136 | + SmallVector<uint8_t, 512> CompressedBuffer; |
| 1137 | +#if LLVM_ENABLE_EXCEPTIONS |
| 1138 | + try { |
| 1139 | +#endif |
| 1140 | + llvm::compression::zstd::compress( |
| 1141 | + ArrayRef<unsigned char>( |
| 1142 | + (const unsigned char *)(Bin->getBufferStart()), |
| 1143 | + Bin->getBufferSize()), |
| 1144 | + CompressedBuffer, OffloadCompressLevel); |
| 1145 | +#if LLVM_ENABLE_EXCEPTIONS |
| 1146 | + } catch (const std::exception &ex) { |
| 1147 | + return createStringError(inconvertibleErrorCode(), |
| 1148 | + std::string("Failed to compress the device image: \n") + |
| 1149 | + std::string(ex.what())); |
| 1150 | + } |
| 1151 | +#endif |
| 1152 | + if (Verbose) |
| 1153 | + errs() << "[Compression] Original image size: " |
| 1154 | + << Bin->getBufferSize() << "\n" |
| 1155 | + << "[Compression] Compressed image size: " |
| 1156 | + << CompressedBuffer.size() << "\n" |
| 1157 | + << "[Compression] Compression level used: " |
| 1158 | + << OffloadCompressLevel << "\n"; |
| 1159 | + |
| 1160 | + // Add the compressed image to the module. |
| 1161 | + Fbin = addDeviceImageToModule( |
| 1162 | + ArrayRef<char>((const char *)CompressedBuffer.data(), |
| 1163 | + CompressedBuffer.size()), |
| 1164 | + Twine(OffloadKindTag) + Twine(ImgId) + Twine(".data"), Kind, |
| 1165 | + Img.Tgt); |
| 1166 | + |
| 1167 | + // Change image format to compressed_none. |
| 1168 | + Ffmt = ConstantInt::get(Type::getInt8Ty(C), |
| 1169 | + BinaryImageFormat::compressed_none); |
| 1170 | + } |
1090 | 1171 | }
|
1091 | 1172 |
|
1092 | 1173 | if (Kind == OffloadKind::SYCL) {
|
|
0 commit comments