| 
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