diff --git a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h index 24017492e30b..dc99e29964af 100644 --- a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h +++ b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h @@ -56,18 +56,18 @@ LLVM_ABI llvm::Error wrapHIPBinary(llvm::Module &M, llvm::ArrayRef Images, bool EmitSurfacesAndTextures = true); struct SYCLJITOptions { - // Target/compiler specific options that are suggested to use to "compile" - // program at runtime. + // Target/compiler specific options that are passed to the device compiler at + // runtime. std::string CompileOptions; - // Target/compiler specific options that are suggested to use to "link" - // program at runtime. + // Target/compiler specific options that are passed to the device linker at + // runtime. std::string LinkOptions; }; /// Wraps OffloadBinaries in the given \p Buffers into the module \p M /// as global symbols and registers the images with the SYCL Runtime. /// \param Options Compiler and linker options to be encoded for the later -/// use by a runtime for JIT compilation. +/// use by a runtime for JIT compilation. Not used for AOT. LLVM_ABI llvm::Error wrapSYCLBinaries(llvm::Module &M, llvm::ArrayRef Buffer, SYCLJITOptions Options = SYCLJITOptions()); diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp index 86060d1d2b0b..288fa10fc04b 100644 --- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp +++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp @@ -640,15 +640,8 @@ void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc, } /// SYCLWrapper helper class that creates all LLVM IRs wrapping given images. -struct SYCLWrapper { - Module &M; - LLVMContext &C; - SYCLJITOptions Options; - - StructType *EntryTy = nullptr; - StructType *SyclDeviceImageTy = nullptr; - StructType *SyclBinDescTy = nullptr; - +class SYCLWrapper { +public: SYCLWrapper(Module &M, const SYCLJITOptions &Options) : M(M), C(M.getContext()), Options(Options) { EntryTy = offloading::getEntryTy(M); @@ -656,259 +649,6 @@ struct SYCLWrapper { SyclBinDescTy = getSyclBinDescTy(); } - IntegerType *getSizeTTy() { - switch (M.getDataLayout().getPointerSize()) { - case 4: - return Type::getInt32Ty(C); - case 8: - return Type::getInt64Ty(C); - } - llvm_unreachable("unsupported pointer type size"); - } - - SmallVector getSizetConstPair(size_t First, size_t Second) { - IntegerType *SizeTTy = getSizeTTy(); - return SmallVector{ConstantInt::get(SizeTTy, First), - ConstantInt::get(SizeTTy, Second)}; - } - - /// Note: Properties aren't supported and the support is going - /// to be added later. - /// Creates a structure corresponding to: - /// SYCL specific image descriptor type. - /// \code - /// struct __sycl.tgt_device_image { - /// // version of this structure - for backward compatibility; - /// // all modifications which change order/type/offsets of existing fields - /// // should increment the version. - /// uint16_t Version; - /// // the kind of offload model the image employs. - /// uint8_t OffloadKind; - /// // format of the image data - SPIRV, LLVMIR bitcode, etc - /// uint8_t Format; - /// // null-terminated string representation of the device's target - /// // architecture - /// const char *Arch; - /// // a null-terminated string; target- and compiler-specific options - /// // which are suggested to use to "compile" program at runtime - /// const char *CompileOptions; - /// // a null-terminated string; target- and compiler-specific options - /// // which are suggested to use to "link" program at runtime - /// const char *LinkOptions; - /// // Pointer to the device binary image start - /// void *ImageStart; - /// // Pointer to the device binary image end - /// void *ImageEnd; - /// // the entry table - /// __tgt_offload_entry *EntriesBegin; - /// __tgt_offload_entry *EntriesEnd; - /// const char *PropertiesBegin; - /// const char *PropertiesEnd; - /// }; - /// \endcode - StructType *getSyclDeviceImageTy() { - return StructType::create( - { - Type::getInt16Ty(C), // Version - Type::getInt8Ty(C), // OffloadKind - Type::getInt8Ty(C), // Format - PointerType::getUnqual(C), // Arch - PointerType::getUnqual(C), // CompileOptions - PointerType::getUnqual(C), // LinkOptions - PointerType::getUnqual(C), // ImageStart - PointerType::getUnqual(C), // ImageEnd - PointerType::getUnqual(C), // EntriesBegin - PointerType::getUnqual(C), // EntriesEnd - PointerType::getUnqual(C), // PropertiesBegin - PointerType::getUnqual(C) // PropertiesEnd - }, - "__sycl.tgt_device_image"); - } - - /// Creates a structure for SYCL specific binary descriptor type. Corresponds - /// to: - /// - /// \code - /// struct __sycl.tgt_bin_desc { - /// // version of this structure - for backward compatibility; - /// // all modifications which change order/type/offsets of existing fields - /// // should increment the version. - /// uint16_t Version; - /// uint16_t NumDeviceImages; - /// __sycl.tgt_device_image *DeviceImages; - /// // the offload entry table - /// __tgt_offload_entry *HostEntriesBegin; - /// __tgt_offload_entry *HostEntriesEnd; - /// }; - /// \endcode - StructType *getSyclBinDescTy() { - return StructType::create( - {Type::getInt16Ty(C), Type::getInt16Ty(C), PointerType::getUnqual(C), - PointerType::getUnqual(C), PointerType::getUnqual(C)}, - "__sycl.tgt_bin_desc"); - } - - /// Adds a global readonly variable that is initialized by given - /// \p Initializer to the module. - GlobalVariable *addGlobalArrayVariable(const Twine &Name, - ArrayRef Initializer, - const Twine &Section = "") { - auto *Arr = ConstantDataArray::get(M.getContext(), Initializer); - auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, Name); - Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - - SmallVector NameBuf; - auto SectionName = Section.toStringRef(NameBuf); - if (!SectionName.empty()) - Var->setSection(SectionName); - return Var; - } - - /// Adds given \p Buf as a global variable into the module. - /// \returns Pair of pointers that point at the beginning and the end of the - /// variable. - std::pair - addArrayToModule(ArrayRef Buf, const Twine &Name, - const Twine &Section = "") { - auto *Var = addGlobalArrayVariable(Name, Buf, Section); - auto *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, - getSizetConstPair(0, 0)); - auto *ImageE = ConstantExpr::getGetElementPtr( - Var->getValueType(), Var, getSizetConstPair(0, Buf.size())); - return std::make_pair(ImageB, ImageE); - } - - /// Adds given \p Data as constant byte array in the module. - /// \returns Constant pointer to the added data. The pointer type does not - /// carry size information. - Constant *addRawDataToModule(ArrayRef Data, const Twine &Name) { - auto *Var = addGlobalArrayVariable(Name, Data); - auto *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, - getSizetConstPair(0, 0)); - return DataPtr; - } - - /// Creates a global variable of const char* type and creates an - /// initializer that initializes it with \p Str. - /// - /// \returns Link-time constant pointer (constant expr) to that - /// variable. - Constant *addStringToModule(StringRef Str, const Twine &Name) { - auto *Arr = ConstantDataArray::getString(C, Str); - auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, Name); - Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - auto *Zero = ConstantInt::get(getSizeTTy(), 0); - Constant *ZeroZero[] = {Zero, Zero}; - return ConstantExpr::getGetElementPtr(Var->getValueType(), Var, ZeroZero); - } - - /// Each image contains its own set of symbols, which may contain different - /// symbols than other images. This function constructs an array of - /// symbol entries for a particular image. - /// - /// \returns Pointers to the beginning and end of the array. - std::pair - initOffloadEntriesPerImage(StringRef Entries, const Twine &OffloadKindTag) { - SmallVector EntriesInits; - std::unique_ptr MB = MemoryBuffer::getMemBuffer( - Entries, /*BufferName*/ "", /*RequiresNullTerminator*/ false); - for (line_iterator LI(*MB); !LI.is_at_eof(); ++LI) { - GlobalVariable *GV = - emitOffloadingEntry(M, /*Kind*/ OffloadKind::OFK_SYCL, - Constant::getNullValue(PointerType::getUnqual(C)), - /*Name*/ *LI, /*Size*/ 0, - /*Flags*/ 0, /*Data*/ 0); - EntriesInits.push_back(GV->getInitializer()); - } - - auto *Arr = ConstantArray::get(ArrayType::get(EntryTy, EntriesInits.size()), - EntriesInits); - auto *EntriesGV = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, - OffloadKindTag + "entries_arr"); - - auto *EntriesB = ConstantExpr::getGetElementPtr( - EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, 0)); - auto *EntriesE = ConstantExpr::getGetElementPtr( - EntriesGV->getValueType(), EntriesGV, - getSizetConstPair(0, EntriesInits.size())); - return std::make_pair(EntriesB, EntriesE); - } - - Constant *wrapImage(const OffloadBinary &OB, const Twine &ImageID, - StringRef OffloadKindTag) { - // Note: Intel DPC++ compiler had 2 versions of this structure - // and clang++ has a third different structure. To avoid ABI incompatibility - // between generated device images the Version here starts from 3. - constexpr uint16_t DeviceImageStructVersion = 3; - Constant *Version = - ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion); - Constant *OffloadKindConstant = ConstantInt::get( - Type::getInt8Ty(C), static_cast(OB.getOffloadKind())); - Constant *ImageKindConstant = ConstantInt::get( - Type::getInt8Ty(C), static_cast(OB.getImageKind())); - StringRef Triple = OB.getString("triple"); - Constant *TripleConstant = - addStringToModule(Triple, Twine(OffloadKindTag) + "target." + ImageID); - Constant *CompileOptions = - addStringToModule(Options.CompileOptions, - Twine(OffloadKindTag) + "opts.compile." + ImageID); - Constant *LinkOptions = addStringToModule( - Options.LinkOptions, Twine(OffloadKindTag) + "opts.link." + ImageID); - - // Note: NULL for now. - std::pair PropertiesConstants = { - Constant::getNullValue(PointerType::getUnqual(C)), - Constant::getNullValue(PointerType::getUnqual(C))}; - - StringRef RawImage = OB.getImage(); - std::pair Binary = addArrayToModule( - ArrayRef(RawImage.begin(), RawImage.end()), - Twine(OffloadKindTag) + ImageID + ".data", ".llvm.offloading"); - - // For SYCL images offload entries are defined here per image. - std::pair ImageEntriesPtrs = - initOffloadEntriesPerImage(OB.getString("symbols"), OffloadKindTag); - Constant *WrappedBinary = ConstantStruct::get( - SyclDeviceImageTy, Version, OffloadKindConstant, ImageKindConstant, - TripleConstant, CompileOptions, LinkOptions, Binary.first, - Binary.second, ImageEntriesPtrs.first, ImageEntriesPtrs.second, - PropertiesConstants.first, PropertiesConstants.second); - - return WrappedBinary; - } - - GlobalVariable *combineWrappedImages(ArrayRef WrappedImages, - StringRef OffloadKindTag) { - auto *ImagesData = ConstantArray::get( - ArrayType::get(SyclDeviceImageTy, WrappedImages.size()), WrappedImages); - auto *ImagesGV = - new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true, - GlobalValue::InternalLinkage, ImagesData, - Twine(OffloadKindTag) + "device_images"); - ImagesGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - - auto *Zero = ConstantInt::get(getSizeTTy(), 0); - Constant *ZeroZero[] = {Zero, Zero}; - auto *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(), - ImagesGV, ZeroZero); - - Constant *EntriesB = Constant::getNullValue(PointerType::getUnqual(C)); - Constant *EntriesE = Constant::getNullValue(PointerType::getUnqual(C)); - static constexpr uint16_t BinDescStructVersion = 1; - auto *DescInit = ConstantStruct::get( - SyclBinDescTy, - ConstantInt::get(Type::getInt16Ty(C), BinDescStructVersion), - ConstantInt::get(Type::getInt16Ty(C), WrappedImages.size()), ImagesB, - EntriesB, EntriesE); - - return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true, - GlobalValue::InternalLinkage, DescInit, - Twine(OffloadKindTag) + "descriptor"); - } - /// Creates binary descriptor for the given device images. Binary descriptor /// is an object that is passed to the offloading runtime at program startup /// and it describes all device images available in the executable or shared @@ -972,19 +712,20 @@ struct SYCLWrapper { } void createRegisterFatbinFunction(GlobalVariable *FatbinDesc) { - auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); - auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, - Twine("sycl") + ".descriptor_reg", &M); + FunctionType *FuncTy = + FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + Twine("sycl") + ".descriptor_reg", &M); Func->setSection(".text.startup"); // Get RegFuncName function declaration. - auto *RegFuncTy = + FunctionType *RegFuncTy = FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), /*isVarArg=*/false); FunctionCallee RegFuncC = M.getOrInsertFunction("__sycl_register_lib", RegFuncTy); - // Construct function body + // Construct function body. IRBuilder Builder(BasicBlock::Create(C, "entry", Func)); Builder.CreateCall(RegFuncC, FatbinDesc); Builder.CreateRetVoid(); @@ -994,13 +735,14 @@ struct SYCLWrapper { } void createUnregisterFunction(GlobalVariable *FatbinDesc) { - auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); - auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, - "sycl.descriptor_unreg", &M); + FunctionType *FuncTy = + FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + "sycl.descriptor_unreg", &M); Func->setSection(".text.startup"); // Get UnregFuncName function declaration. - auto *UnRegFuncTy = + FunctionType *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), /*isVarArg=*/false); FunctionCallee UnRegFuncC = @@ -1014,6 +756,273 @@ struct SYCLWrapper { // Add this function to global destructors. appendToGlobalDtors(M, Func, /*Priority*/ 1); } + +private: + IntegerType *getSizeTTy() { + switch (M.getDataLayout().getPointerSize()) { + case 4: + return Type::getInt32Ty(C); + case 8: + return Type::getInt64Ty(C); + } + llvm_unreachable("unsupported pointer type size"); + } + + SmallVector getSizetConstPair(size_t First, size_t Second) { + IntegerType *SizeTTy = getSizeTTy(); + return SmallVector{ConstantInt::get(SizeTTy, First), + ConstantInt::get(SizeTTy, Second)}; + } + + /// Note: Properties aren't supported and the support is going + /// to be added later. + /// Creates a structure corresponding to: + /// SYCL specific image descriptor type. + /// \code + /// struct __sycl.tgt_device_image { + /// // Version of this structure - for backward compatibility; + /// // all modifications which change order/type/offsets of existing fields + /// // should increment the version. + /// uint16_t Version; + /// // The kind of offload model the image employs. + /// uint8_t OffloadKind; + /// // Format of the image data - SPIRV, LLVMIR bitcode, etc. + /// uint8_t Format; + /// // Null-terminated string representation of the device's target + /// // architecture. + /// const char *Arch; + /// // A null-terminated string; target- and compiler-specific options + /// // which are passed to the device compiler at runtime. + /// const char *CompileOptions; + /// // A null-terminated string; target- and compiler-specific options + /// // which are passed to the device linker at runtime. + /// const char *LinkOptions; + /// // Pointer to the device binary image start. + /// void *ImageStart; + /// // Pointer to the device binary image end. + /// void *ImageEnd; + /// // The entry table. + /// __tgt_offload_entry *EntriesBegin; + /// __tgt_offload_entry *EntriesEnd; + /// const char *PropertiesBegin; + /// const char *PropertiesEnd; + /// }; + /// \endcode + StructType *getSyclDeviceImageTy() { + return StructType::create( + { + Type::getInt16Ty(C), // Version + Type::getInt8Ty(C), // OffloadKind + Type::getInt8Ty(C), // Format + PointerType::getUnqual(C), // Arch + PointerType::getUnqual(C), // CompileOptions + PointerType::getUnqual(C), // LinkOptions + PointerType::getUnqual(C), // ImageStart + PointerType::getUnqual(C), // ImageEnd + PointerType::getUnqual(C), // EntriesBegin + PointerType::getUnqual(C), // EntriesEnd + PointerType::getUnqual(C), // PropertiesBegin + PointerType::getUnqual(C) // PropertiesEnd + }, + "__sycl.tgt_device_image"); + } + + /// Creates a structure for SYCL specific binary descriptor type. Corresponds + /// to: + /// + /// \code + /// struct __sycl.tgt_bin_desc { + /// // version of this structure - for backward compatibility; + /// // all modifications which change order/type/offsets of existing fields + /// // should increment the version. + /// uint16_t Version; + /// uint16_t NumDeviceImages; + /// __sycl.tgt_device_image *DeviceImages; + /// // the offload entry table + /// __tgt_offload_entry *HostEntriesBegin; + /// __tgt_offload_entry *HostEntriesEnd; + /// }; + /// \endcode + StructType *getSyclBinDescTy() { + return StructType::create( + {Type::getInt16Ty(C), Type::getInt16Ty(C), PointerType::getUnqual(C), + PointerType::getUnqual(C), PointerType::getUnqual(C)}, + "__sycl.tgt_bin_desc"); + } + + /// Adds a global readonly variable that is initialized by given + /// \p Initializer to the module. + GlobalVariable *addGlobalArrayVariable(const Twine &Name, + ArrayRef Initializer, + const Twine &Section = "") { + Constant *Arr = ConstantDataArray::get(M.getContext(), Initializer); + GlobalVariable *Var = + new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, + GlobalVariable::InternalLinkage, Arr, Name); + Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + SmallVector NameBuf; + StringRef SectionName = Section.toStringRef(NameBuf); + if (!SectionName.empty()) + Var->setSection(SectionName); + return Var; + } + + /// Adds given \p Buf as a global variable into the module. + /// \returns Pair of pointers that point at the beginning and the end of the + /// variable. + std::pair + addArrayToModule(ArrayRef Buf, const Twine &Name, + const Twine &Section = "") { + GlobalVariable *Var = addGlobalArrayVariable(Name, Buf, Section); + Constant *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, + getSizetConstPair(0, 0)); + Constant *ImageE = ConstantExpr::getGetElementPtr( + Var->getValueType(), Var, getSizetConstPair(0, Buf.size())); + return std::make_pair(ImageB, ImageE); + } + + /// Adds given \p Data as constant byte array in the module. + /// \returns Constant pointer to the added data. The pointer type does not + /// carry size information. + Constant *addRawDataToModule(ArrayRef Data, const Twine &Name) { + GlobalVariable *Var = addGlobalArrayVariable(Name, Data); + Constant *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, + getSizetConstPair(0, 0)); + return DataPtr; + } + + /// Creates a global variable of const char* type and creates an + /// initializer that initializes it with \p Str. + /// + /// \returns Link-time constant pointer (constant expr) to that + /// variable. + Constant *addStringToModule(StringRef Str, const Twine &Name) { + Constant *Arr = ConstantDataArray::getString(C, Str); + GlobalVariable *Var = + new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, + GlobalVariable::InternalLinkage, Arr, Name); + Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0); + Constant *ZeroZero[] = {Zero, Zero}; + return ConstantExpr::getGetElementPtr(Var->getValueType(), Var, ZeroZero); + } + + /// Each image contains its own set of symbols, which may contain different + /// symbols than other images. This function constructs an array of + /// symbol entries for a particular image. + /// + /// \returns Pointers to the beginning and end of the array. + std::pair + initOffloadEntriesPerImage(StringRef Entries, const Twine &OffloadKindTag) { + SmallVector EntriesInits; + std::unique_ptr MB = MemoryBuffer::getMemBuffer( + Entries, /*BufferName*/ "", /*RequiresNullTerminator*/ false); + for (line_iterator LI(*MB); !LI.is_at_eof(); ++LI) { + GlobalVariable *GV = + emitOffloadingEntry(M, /*Kind*/ OffloadKind::OFK_SYCL, + Constant::getNullValue(PointerType::getUnqual(C)), + /*Name*/ *LI, /*Size*/ 0, + /*Flags*/ 0, /*Data*/ 0); + EntriesInits.push_back(GV->getInitializer()); + } + + Constant *Arr = ConstantArray::get( + ArrayType::get(EntryTy, EntriesInits.size()), EntriesInits); + GlobalVariable *EntriesGV = new GlobalVariable( + M, Arr->getType(), /*isConstant*/ true, GlobalVariable::InternalLinkage, + Arr, OffloadKindTag + "entries_arr"); + + Constant *EntriesB = ConstantExpr::getGetElementPtr( + EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, 0)); + Constant *EntriesE = ConstantExpr::getGetElementPtr( + EntriesGV->getValueType(), EntriesGV, + getSizetConstPair(0, EntriesInits.size())); + return std::make_pair(EntriesB, EntriesE); + } + + Constant *wrapImage(const OffloadBinary &OB, const Twine &ImageID, + StringRef OffloadKindTag) { + // Note: Intel DPC++ compiler had 2 versions of this structure + // and clang++ has a third different structure. To avoid ABI incompatibility + // between generated device images the Version here starts from 3. + constexpr uint16_t DeviceImageStructVersion = 3; + Constant *Version = + ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion); + Constant *OffloadKindConstant = ConstantInt::get( + Type::getInt8Ty(C), static_cast(OB.getOffloadKind())); + Constant *ImageKindConstant = ConstantInt::get( + Type::getInt8Ty(C), static_cast(OB.getImageKind())); + StringRef Triple = OB.getString("triple"); + Constant *TripleConstant = + addStringToModule(Triple, Twine(OffloadKindTag) + "target." + ImageID); + Constant *CompileOptions = + addStringToModule(Options.CompileOptions, + Twine(OffloadKindTag) + "opts.compile." + ImageID); + Constant *LinkOptions = addStringToModule( + Options.LinkOptions, Twine(OffloadKindTag) + "opts.link." + ImageID); + + // Note: NULL for now. + std::pair PropertiesConstants = { + Constant::getNullValue(PointerType::getUnqual(C)), + Constant::getNullValue(PointerType::getUnqual(C))}; + + StringRef RawImage = OB.getImage(); + std::pair Binary = addArrayToModule( + ArrayRef(RawImage.begin(), RawImage.end()), + Twine(OffloadKindTag) + ImageID + ".data", ".llvm.offloading"); + + // For SYCL images offload entries are defined here per image. + std::pair ImageEntriesPtrs = + initOffloadEntriesPerImage(OB.getString("symbols"), OffloadKindTag); + + // .first and .second arguments below correspond to start and end pointers + // respectively. + Constant *WrappedBinary = ConstantStruct::get( + SyclDeviceImageTy, Version, OffloadKindConstant, ImageKindConstant, + TripleConstant, CompileOptions, LinkOptions, Binary.first, + Binary.second, ImageEntriesPtrs.first, ImageEntriesPtrs.second, + PropertiesConstants.first, PropertiesConstants.second); + + return WrappedBinary; + } + + GlobalVariable *combineWrappedImages(ArrayRef WrappedImages, + StringRef OffloadKindTag) { + Constant *ImagesData = ConstantArray::get( + ArrayType::get(SyclDeviceImageTy, WrappedImages.size()), WrappedImages); + GlobalVariable *ImagesGV = + new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true, + GlobalValue::InternalLinkage, ImagesData, + Twine(OffloadKindTag) + "device_images"); + ImagesGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0); + Constant *ZeroZero[] = {Zero, Zero}; + Constant *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(), + ImagesGV, ZeroZero); + + Constant *EntriesB = Constant::getNullValue(PointerType::getUnqual(C)); + Constant *EntriesE = Constant::getNullValue(PointerType::getUnqual(C)); + static constexpr uint16_t BinDescStructVersion = 1; + Constant *DescInit = ConstantStruct::get( + SyclBinDescTy, + ConstantInt::get(Type::getInt16Ty(C), BinDescStructVersion), + ConstantInt::get(Type::getInt16Ty(C), WrappedImages.size()), ImagesB, + EntriesB, EntriesE); + + return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true, + GlobalValue::InternalLinkage, DescInit, + Twine(OffloadKindTag) + "descriptor"); + } + + Module &M; + LLVMContext &C; + SYCLJITOptions Options; + + StructType *EntryTy = nullptr; + StructType *SyclDeviceImageTy = nullptr; + StructType *SyclBinDescTy = nullptr; }; // end of SYCLWrapper } // namespace