14df029ccSDimitry Andric //===- OffloadWrapper.cpp ---------------------------------------*- C++ -*-===//
24df029ccSDimitry Andric //
34df029ccSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44df029ccSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
54df029ccSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64df029ccSDimitry Andric //
74df029ccSDimitry Andric //===----------------------------------------------------------------------===//
84df029ccSDimitry Andric
94df029ccSDimitry Andric #include "llvm/Frontend/Offloading/OffloadWrapper.h"
104df029ccSDimitry Andric #include "llvm/ADT/ArrayRef.h"
114df029ccSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
124df029ccSDimitry Andric #include "llvm/Frontend/Offloading/Utility.h"
134df029ccSDimitry Andric #include "llvm/IR/Constants.h"
144df029ccSDimitry Andric #include "llvm/IR/GlobalVariable.h"
154df029ccSDimitry Andric #include "llvm/IR/IRBuilder.h"
164df029ccSDimitry Andric #include "llvm/IR/LLVMContext.h"
174df029ccSDimitry Andric #include "llvm/IR/Module.h"
184df029ccSDimitry Andric #include "llvm/Object/OffloadBinary.h"
194df029ccSDimitry Andric #include "llvm/Support/Error.h"
204df029ccSDimitry Andric #include "llvm/TargetParser/Triple.h"
214df029ccSDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
224df029ccSDimitry Andric
234df029ccSDimitry Andric using namespace llvm;
244df029ccSDimitry Andric using namespace llvm::offloading;
254df029ccSDimitry Andric
264df029ccSDimitry Andric namespace {
274df029ccSDimitry Andric /// Magic number that begins the section containing the CUDA fatbinary.
284df029ccSDimitry Andric constexpr unsigned CudaFatMagic = 0x466243b1;
294df029ccSDimitry Andric constexpr unsigned HIPFatMagic = 0x48495046;
304df029ccSDimitry Andric
getSizeTTy(Module & M)314df029ccSDimitry Andric IntegerType *getSizeTTy(Module &M) {
324df029ccSDimitry Andric return M.getDataLayout().getIntPtrType(M.getContext());
334df029ccSDimitry Andric }
344df029ccSDimitry Andric
354df029ccSDimitry Andric // struct __tgt_device_image {
364df029ccSDimitry Andric // void *ImageStart;
374df029ccSDimitry Andric // void *ImageEnd;
384df029ccSDimitry Andric // __tgt_offload_entry *EntriesBegin;
394df029ccSDimitry Andric // __tgt_offload_entry *EntriesEnd;
404df029ccSDimitry Andric // };
getDeviceImageTy(Module & M)414df029ccSDimitry Andric StructType *getDeviceImageTy(Module &M) {
424df029ccSDimitry Andric LLVMContext &C = M.getContext();
434df029ccSDimitry Andric StructType *ImageTy = StructType::getTypeByName(C, "__tgt_device_image");
444df029ccSDimitry Andric if (!ImageTy)
454df029ccSDimitry Andric ImageTy =
464df029ccSDimitry Andric StructType::create("__tgt_device_image", PointerType::getUnqual(C),
474df029ccSDimitry Andric PointerType::getUnqual(C), PointerType::getUnqual(C),
484df029ccSDimitry Andric PointerType::getUnqual(C));
494df029ccSDimitry Andric return ImageTy;
504df029ccSDimitry Andric }
514df029ccSDimitry Andric
getDeviceImagePtrTy(Module & M)524df029ccSDimitry Andric PointerType *getDeviceImagePtrTy(Module &M) {
534df029ccSDimitry Andric return PointerType::getUnqual(getDeviceImageTy(M));
544df029ccSDimitry Andric }
554df029ccSDimitry Andric
564df029ccSDimitry Andric // struct __tgt_bin_desc {
574df029ccSDimitry Andric // int32_t NumDeviceImages;
584df029ccSDimitry Andric // __tgt_device_image *DeviceImages;
594df029ccSDimitry Andric // __tgt_offload_entry *HostEntriesBegin;
604df029ccSDimitry Andric // __tgt_offload_entry *HostEntriesEnd;
614df029ccSDimitry Andric // };
getBinDescTy(Module & M)624df029ccSDimitry Andric StructType *getBinDescTy(Module &M) {
634df029ccSDimitry Andric LLVMContext &C = M.getContext();
644df029ccSDimitry Andric StructType *DescTy = StructType::getTypeByName(C, "__tgt_bin_desc");
654df029ccSDimitry Andric if (!DescTy)
664df029ccSDimitry Andric DescTy = StructType::create(
674df029ccSDimitry Andric "__tgt_bin_desc", Type::getInt32Ty(C), getDeviceImagePtrTy(M),
684df029ccSDimitry Andric PointerType::getUnqual(C), PointerType::getUnqual(C));
694df029ccSDimitry Andric return DescTy;
704df029ccSDimitry Andric }
714df029ccSDimitry Andric
getBinDescPtrTy(Module & M)724df029ccSDimitry Andric PointerType *getBinDescPtrTy(Module &M) {
734df029ccSDimitry Andric return PointerType::getUnqual(getBinDescTy(M));
744df029ccSDimitry Andric }
754df029ccSDimitry Andric
764df029ccSDimitry Andric /// Creates binary descriptor for the given device images. Binary descriptor
774df029ccSDimitry Andric /// is an object that is passed to the offloading runtime at program startup
784df029ccSDimitry Andric /// and it describes all device images available in the executable or shared
794df029ccSDimitry Andric /// library. It is defined as follows
804df029ccSDimitry Andric ///
814df029ccSDimitry Andric /// __attribute__((visibility("hidden")))
824df029ccSDimitry Andric /// extern __tgt_offload_entry *__start_omp_offloading_entries;
834df029ccSDimitry Andric /// __attribute__((visibility("hidden")))
844df029ccSDimitry Andric /// extern __tgt_offload_entry *__stop_omp_offloading_entries;
854df029ccSDimitry Andric ///
864df029ccSDimitry Andric /// static const char Image0[] = { <Bufs.front() contents> };
874df029ccSDimitry Andric /// ...
884df029ccSDimitry Andric /// static const char ImageN[] = { <Bufs.back() contents> };
894df029ccSDimitry Andric ///
904df029ccSDimitry Andric /// static const __tgt_device_image Images[] = {
914df029ccSDimitry Andric /// {
924df029ccSDimitry Andric /// Image0, /*ImageStart*/
934df029ccSDimitry Andric /// Image0 + sizeof(Image0), /*ImageEnd*/
944df029ccSDimitry Andric /// __start_omp_offloading_entries, /*EntriesBegin*/
954df029ccSDimitry Andric /// __stop_omp_offloading_entries /*EntriesEnd*/
964df029ccSDimitry Andric /// },
974df029ccSDimitry Andric /// ...
984df029ccSDimitry Andric /// {
994df029ccSDimitry Andric /// ImageN, /*ImageStart*/
1004df029ccSDimitry Andric /// ImageN + sizeof(ImageN), /*ImageEnd*/
1014df029ccSDimitry Andric /// __start_omp_offloading_entries, /*EntriesBegin*/
1024df029ccSDimitry Andric /// __stop_omp_offloading_entries /*EntriesEnd*/
1034df029ccSDimitry Andric /// }
1044df029ccSDimitry Andric /// };
1054df029ccSDimitry Andric ///
1064df029ccSDimitry Andric /// static const __tgt_bin_desc BinDesc = {
1074df029ccSDimitry Andric /// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/
1084df029ccSDimitry Andric /// Images, /*DeviceImages*/
1094df029ccSDimitry Andric /// __start_omp_offloading_entries, /*HostEntriesBegin*/
1104df029ccSDimitry Andric /// __stop_omp_offloading_entries /*HostEntriesEnd*/
1114df029ccSDimitry Andric /// };
1124df029ccSDimitry Andric ///
1134df029ccSDimitry Andric /// Global variable that represents BinDesc is returned.
createBinDesc(Module & M,ArrayRef<ArrayRef<char>> Bufs,EntryArrayTy EntryArray,StringRef Suffix,bool Relocatable)1144df029ccSDimitry Andric GlobalVariable *createBinDesc(Module &M, ArrayRef<ArrayRef<char>> Bufs,
115ac9a064cSDimitry Andric EntryArrayTy EntryArray, StringRef Suffix,
116ac9a064cSDimitry Andric bool Relocatable) {
1174df029ccSDimitry Andric LLVMContext &C = M.getContext();
1184df029ccSDimitry Andric auto [EntriesB, EntriesE] = EntryArray;
1194df029ccSDimitry Andric
1204df029ccSDimitry Andric auto *Zero = ConstantInt::get(getSizeTTy(M), 0u);
1214df029ccSDimitry Andric Constant *ZeroZero[] = {Zero, Zero};
1224df029ccSDimitry Andric
1234df029ccSDimitry Andric // Create initializer for the images array.
1244df029ccSDimitry Andric SmallVector<Constant *, 4u> ImagesInits;
1254df029ccSDimitry Andric ImagesInits.reserve(Bufs.size());
1264df029ccSDimitry Andric for (ArrayRef<char> Buf : Bufs) {
1274df029ccSDimitry Andric // We embed the full offloading entry so the binary utilities can parse it.
1284df029ccSDimitry Andric auto *Data = ConstantDataArray::get(C, Buf);
1294df029ccSDimitry Andric auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant=*/true,
1304df029ccSDimitry Andric GlobalVariable::InternalLinkage, Data,
1314df029ccSDimitry Andric ".omp_offloading.device_image" + Suffix);
1324df029ccSDimitry Andric Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
133ac9a064cSDimitry Andric Image->setSection(Relocatable ? ".llvm.offloading.relocatable"
134ac9a064cSDimitry Andric : ".llvm.offloading");
1354df029ccSDimitry Andric Image->setAlignment(Align(object::OffloadBinary::getAlignment()));
1364df029ccSDimitry Andric
1374df029ccSDimitry Andric StringRef Binary(Buf.data(), Buf.size());
1384df029ccSDimitry Andric assert(identify_magic(Binary) == file_magic::offload_binary &&
1394df029ccSDimitry Andric "Invalid binary format");
1404df029ccSDimitry Andric
1414df029ccSDimitry Andric // The device image struct contains the pointer to the beginning and end of
1424df029ccSDimitry Andric // the image stored inside of the offload binary. There should only be one
1434df029ccSDimitry Andric // of these for each buffer so we parse it out manually.
1444df029ccSDimitry Andric const auto *Header =
1454df029ccSDimitry Andric reinterpret_cast<const object::OffloadBinary::Header *>(
1464df029ccSDimitry Andric Binary.bytes_begin());
1474df029ccSDimitry Andric const auto *Entry = reinterpret_cast<const object::OffloadBinary::Entry *>(
1484df029ccSDimitry Andric Binary.bytes_begin() + Header->EntryOffset);
1494df029ccSDimitry Andric
1504df029ccSDimitry Andric auto *Begin = ConstantInt::get(getSizeTTy(M), Entry->ImageOffset);
1514df029ccSDimitry Andric auto *Size =
1524df029ccSDimitry Andric ConstantInt::get(getSizeTTy(M), Entry->ImageOffset + Entry->ImageSize);
1534df029ccSDimitry Andric Constant *ZeroBegin[] = {Zero, Begin};
1544df029ccSDimitry Andric Constant *ZeroSize[] = {Zero, Size};
1554df029ccSDimitry Andric
1564df029ccSDimitry Andric auto *ImageB =
1574df029ccSDimitry Andric ConstantExpr::getGetElementPtr(Image->getValueType(), Image, ZeroBegin);
1584df029ccSDimitry Andric auto *ImageE =
1594df029ccSDimitry Andric ConstantExpr::getGetElementPtr(Image->getValueType(), Image, ZeroSize);
1604df029ccSDimitry Andric
1614df029ccSDimitry Andric ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(M), ImageB,
1624df029ccSDimitry Andric ImageE, EntriesB, EntriesE));
1634df029ccSDimitry Andric }
1644df029ccSDimitry Andric
1654df029ccSDimitry Andric // Then create images array.
1664df029ccSDimitry Andric auto *ImagesData = ConstantArray::get(
1674df029ccSDimitry Andric ArrayType::get(getDeviceImageTy(M), ImagesInits.size()), ImagesInits);
1684df029ccSDimitry Andric
1694df029ccSDimitry Andric auto *Images =
1704df029ccSDimitry Andric new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
1714df029ccSDimitry Andric GlobalValue::InternalLinkage, ImagesData,
1724df029ccSDimitry Andric ".omp_offloading.device_images" + Suffix);
1734df029ccSDimitry Andric Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
1744df029ccSDimitry Andric
1754df029ccSDimitry Andric auto *ImagesB =
1764df029ccSDimitry Andric ConstantExpr::getGetElementPtr(Images->getValueType(), Images, ZeroZero);
1774df029ccSDimitry Andric
1784df029ccSDimitry Andric // And finally create the binary descriptor object.
1794df029ccSDimitry Andric auto *DescInit = ConstantStruct::get(
1804df029ccSDimitry Andric getBinDescTy(M),
1814df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB,
1824df029ccSDimitry Andric EntriesB, EntriesE);
1834df029ccSDimitry Andric
1844df029ccSDimitry Andric return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
1854df029ccSDimitry Andric GlobalValue::InternalLinkage, DescInit,
1864df029ccSDimitry Andric ".omp_offloading.descriptor" + Suffix);
1874df029ccSDimitry Andric }
1884df029ccSDimitry Andric
createUnregisterFunction(Module & M,GlobalVariable * BinDesc,StringRef Suffix)189ac9a064cSDimitry Andric Function *createUnregisterFunction(Module &M, GlobalVariable *BinDesc,
1904df029ccSDimitry Andric StringRef Suffix) {
1914df029ccSDimitry Andric LLVMContext &C = M.getContext();
1924df029ccSDimitry Andric auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
1934df029ccSDimitry Andric auto *Func =
1944df029ccSDimitry Andric Function::Create(FuncTy, GlobalValue::InternalLinkage,
1954df029ccSDimitry Andric ".omp_offloading.descriptor_unreg" + Suffix, &M);
1964df029ccSDimitry Andric Func->setSection(".text.startup");
1974df029ccSDimitry Andric
1984df029ccSDimitry Andric // Get __tgt_unregister_lib function declaration.
1994df029ccSDimitry Andric auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(M),
2004df029ccSDimitry Andric /*isVarArg*/ false);
2014df029ccSDimitry Andric FunctionCallee UnRegFuncC =
2024df029ccSDimitry Andric M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy);
2034df029ccSDimitry Andric
2044df029ccSDimitry Andric // Construct function body
2054df029ccSDimitry Andric IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
2064df029ccSDimitry Andric Builder.CreateCall(UnRegFuncC, BinDesc);
2074df029ccSDimitry Andric Builder.CreateRetVoid();
2084df029ccSDimitry Andric
209ac9a064cSDimitry Andric return Func;
210ac9a064cSDimitry Andric }
211ac9a064cSDimitry Andric
createRegisterFunction(Module & M,GlobalVariable * BinDesc,StringRef Suffix)212ac9a064cSDimitry Andric void createRegisterFunction(Module &M, GlobalVariable *BinDesc,
213ac9a064cSDimitry Andric StringRef Suffix) {
214ac9a064cSDimitry Andric LLVMContext &C = M.getContext();
215ac9a064cSDimitry Andric auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
216ac9a064cSDimitry Andric auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
217ac9a064cSDimitry Andric ".omp_offloading.descriptor_reg" + Suffix, &M);
218ac9a064cSDimitry Andric Func->setSection(".text.startup");
219ac9a064cSDimitry Andric
220ac9a064cSDimitry Andric // Get __tgt_register_lib function declaration.
221ac9a064cSDimitry Andric auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(M),
222ac9a064cSDimitry Andric /*isVarArg*/ false);
223ac9a064cSDimitry Andric FunctionCallee RegFuncC =
224ac9a064cSDimitry Andric M.getOrInsertFunction("__tgt_register_lib", RegFuncTy);
225ac9a064cSDimitry Andric
226ac9a064cSDimitry Andric auto *AtExitTy = FunctionType::get(
227ac9a064cSDimitry Andric Type::getInt32Ty(C), PointerType::getUnqual(C), /*isVarArg=*/false);
228ac9a064cSDimitry Andric FunctionCallee AtExit = M.getOrInsertFunction("atexit", AtExitTy);
229ac9a064cSDimitry Andric
230ac9a064cSDimitry Andric Function *UnregFunc = createUnregisterFunction(M, BinDesc, Suffix);
231ac9a064cSDimitry Andric
232ac9a064cSDimitry Andric // Construct function body
233ac9a064cSDimitry Andric IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
234ac9a064cSDimitry Andric
235ac9a064cSDimitry Andric Builder.CreateCall(RegFuncC, BinDesc);
236ac9a064cSDimitry Andric
237ac9a064cSDimitry Andric // Register the destructors with 'atexit'. This is expected by the CUDA
238ac9a064cSDimitry Andric // runtime and ensures that we clean up before dynamic objects are destroyed.
239ac9a064cSDimitry Andric // This needs to be done after plugin initialization to ensure that it is
240ac9a064cSDimitry Andric // called before the plugin runtime is destroyed.
241ac9a064cSDimitry Andric Builder.CreateCall(AtExit, UnregFunc);
242ac9a064cSDimitry Andric Builder.CreateRetVoid();
243ac9a064cSDimitry Andric
244ac9a064cSDimitry Andric // Add this function to constructors.
245ac9a064cSDimitry Andric appendToGlobalCtors(M, Func, /*Priority=*/101);
2464df029ccSDimitry Andric }
2474df029ccSDimitry Andric
2484df029ccSDimitry Andric // struct fatbin_wrapper {
2494df029ccSDimitry Andric // int32_t magic;
2504df029ccSDimitry Andric // int32_t version;
2514df029ccSDimitry Andric // void *image;
2524df029ccSDimitry Andric // void *reserved;
2534df029ccSDimitry Andric //};
getFatbinWrapperTy(Module & M)2544df029ccSDimitry Andric StructType *getFatbinWrapperTy(Module &M) {
2554df029ccSDimitry Andric LLVMContext &C = M.getContext();
2564df029ccSDimitry Andric StructType *FatbinTy = StructType::getTypeByName(C, "fatbin_wrapper");
2574df029ccSDimitry Andric if (!FatbinTy)
2584df029ccSDimitry Andric FatbinTy = StructType::create(
2594df029ccSDimitry Andric "fatbin_wrapper", Type::getInt32Ty(C), Type::getInt32Ty(C),
2604df029ccSDimitry Andric PointerType::getUnqual(C), PointerType::getUnqual(C));
2614df029ccSDimitry Andric return FatbinTy;
2624df029ccSDimitry Andric }
2634df029ccSDimitry Andric
2644df029ccSDimitry Andric /// Embed the image \p Image into the module \p M so it can be found by the
2654df029ccSDimitry Andric /// runtime.
createFatbinDesc(Module & M,ArrayRef<char> Image,bool IsHIP,StringRef Suffix)2664df029ccSDimitry Andric GlobalVariable *createFatbinDesc(Module &M, ArrayRef<char> Image, bool IsHIP,
2674df029ccSDimitry Andric StringRef Suffix) {
2684df029ccSDimitry Andric LLVMContext &C = M.getContext();
2694df029ccSDimitry Andric llvm::Type *Int8PtrTy = PointerType::getUnqual(C);
2704df029ccSDimitry Andric llvm::Triple Triple = llvm::Triple(M.getTargetTriple());
2714df029ccSDimitry Andric
2724df029ccSDimitry Andric // Create the global string containing the fatbinary.
2734df029ccSDimitry Andric StringRef FatbinConstantSection =
2744df029ccSDimitry Andric IsHIP ? ".hip_fatbin"
2754df029ccSDimitry Andric : (Triple.isMacOSX() ? "__NV_CUDA,__nv_fatbin" : ".nv_fatbin");
2764df029ccSDimitry Andric auto *Data = ConstantDataArray::get(C, Image);
2774df029ccSDimitry Andric auto *Fatbin = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
2784df029ccSDimitry Andric GlobalVariable::InternalLinkage, Data,
2794df029ccSDimitry Andric ".fatbin_image" + Suffix);
2804df029ccSDimitry Andric Fatbin->setSection(FatbinConstantSection);
2814df029ccSDimitry Andric
2824df029ccSDimitry Andric // Create the fatbinary wrapper
2834df029ccSDimitry Andric StringRef FatbinWrapperSection = IsHIP ? ".hipFatBinSegment"
2844df029ccSDimitry Andric : Triple.isMacOSX() ? "__NV_CUDA,__fatbin"
2854df029ccSDimitry Andric : ".nvFatBinSegment";
2864df029ccSDimitry Andric Constant *FatbinWrapper[] = {
2874df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), IsHIP ? HIPFatMagic : CudaFatMagic),
2884df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 1),
2894df029ccSDimitry Andric ConstantExpr::getPointerBitCastOrAddrSpaceCast(Fatbin, Int8PtrTy),
2904df029ccSDimitry Andric ConstantPointerNull::get(PointerType::getUnqual(C))};
2914df029ccSDimitry Andric
2924df029ccSDimitry Andric Constant *FatbinInitializer =
2934df029ccSDimitry Andric ConstantStruct::get(getFatbinWrapperTy(M), FatbinWrapper);
2944df029ccSDimitry Andric
2954df029ccSDimitry Andric auto *FatbinDesc =
2964df029ccSDimitry Andric new GlobalVariable(M, getFatbinWrapperTy(M),
2974df029ccSDimitry Andric /*isConstant*/ true, GlobalValue::InternalLinkage,
2984df029ccSDimitry Andric FatbinInitializer, ".fatbin_wrapper" + Suffix);
2994df029ccSDimitry Andric FatbinDesc->setSection(FatbinWrapperSection);
3004df029ccSDimitry Andric FatbinDesc->setAlignment(Align(8));
3014df029ccSDimitry Andric
3024df029ccSDimitry Andric return FatbinDesc;
3034df029ccSDimitry Andric }
3044df029ccSDimitry Andric
3054df029ccSDimitry Andric /// Create the register globals function. We will iterate all of the offloading
3064df029ccSDimitry Andric /// entries stored at the begin / end symbols and register them according to
3074df029ccSDimitry Andric /// their type. This creates the following function in IR:
3084df029ccSDimitry Andric ///
3094df029ccSDimitry Andric /// extern struct __tgt_offload_entry __start_cuda_offloading_entries;
3104df029ccSDimitry Andric /// extern struct __tgt_offload_entry __stop_cuda_offloading_entries;
3114df029ccSDimitry Andric ///
3124df029ccSDimitry Andric /// extern void __cudaRegisterFunction(void **, void *, void *, void *, int,
3134df029ccSDimitry Andric /// void *, void *, void *, void *, int *);
3144df029ccSDimitry Andric /// extern void __cudaRegisterVar(void **, void *, void *, void *, int32_t,
3154df029ccSDimitry Andric /// int64_t, int32_t, int32_t);
3164df029ccSDimitry Andric ///
3174df029ccSDimitry Andric /// void __cudaRegisterTest(void **fatbinHandle) {
3184df029ccSDimitry Andric /// for (struct __tgt_offload_entry *entry = &__start_cuda_offloading_entries;
3194df029ccSDimitry Andric /// entry != &__stop_cuda_offloading_entries; ++entry) {
3204df029ccSDimitry Andric /// if (!entry->size)
3214df029ccSDimitry Andric /// __cudaRegisterFunction(fatbinHandle, entry->addr, entry->name,
3224df029ccSDimitry Andric /// entry->name, -1, 0, 0, 0, 0, 0);
3234df029ccSDimitry Andric /// else
3244df029ccSDimitry Andric /// __cudaRegisterVar(fatbinHandle, entry->addr, entry->name, entry->name,
3254df029ccSDimitry Andric /// 0, entry->size, 0, 0);
3264df029ccSDimitry Andric /// }
3274df029ccSDimitry Andric /// }
createRegisterGlobalsFunction(Module & M,bool IsHIP,EntryArrayTy EntryArray,StringRef Suffix,bool EmitSurfacesAndTextures)3284df029ccSDimitry Andric Function *createRegisterGlobalsFunction(Module &M, bool IsHIP,
3294df029ccSDimitry Andric EntryArrayTy EntryArray,
3304df029ccSDimitry Andric StringRef Suffix,
3314df029ccSDimitry Andric bool EmitSurfacesAndTextures) {
3324df029ccSDimitry Andric LLVMContext &C = M.getContext();
3334df029ccSDimitry Andric auto [EntriesB, EntriesE] = EntryArray;
3344df029ccSDimitry Andric
3354df029ccSDimitry Andric // Get the __cudaRegisterFunction function declaration.
3364df029ccSDimitry Andric PointerType *Int8PtrTy = PointerType::get(C, 0);
3374df029ccSDimitry Andric PointerType *Int8PtrPtrTy = PointerType::get(C, 0);
3384df029ccSDimitry Andric PointerType *Int32PtrTy = PointerType::get(C, 0);
3394df029ccSDimitry Andric auto *RegFuncTy = FunctionType::get(
3404df029ccSDimitry Andric Type::getInt32Ty(C),
3414df029ccSDimitry Andric {Int8PtrPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy, Type::getInt32Ty(C),
3424df029ccSDimitry Andric Int8PtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy, Int32PtrTy},
3434df029ccSDimitry Andric /*isVarArg*/ false);
3444df029ccSDimitry Andric FunctionCallee RegFunc = M.getOrInsertFunction(
3454df029ccSDimitry Andric IsHIP ? "__hipRegisterFunction" : "__cudaRegisterFunction", RegFuncTy);
3464df029ccSDimitry Andric
3474df029ccSDimitry Andric // Get the __cudaRegisterVar function declaration.
3484df029ccSDimitry Andric auto *RegVarTy = FunctionType::get(
3494df029ccSDimitry Andric Type::getVoidTy(C),
3504df029ccSDimitry Andric {Int8PtrPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy, Type::getInt32Ty(C),
3514df029ccSDimitry Andric getSizeTTy(M), Type::getInt32Ty(C), Type::getInt32Ty(C)},
3524df029ccSDimitry Andric /*isVarArg*/ false);
3534df029ccSDimitry Andric FunctionCallee RegVar = M.getOrInsertFunction(
3544df029ccSDimitry Andric IsHIP ? "__hipRegisterVar" : "__cudaRegisterVar", RegVarTy);
3554df029ccSDimitry Andric
3564df029ccSDimitry Andric // Get the __cudaRegisterSurface function declaration.
3574df029ccSDimitry Andric FunctionType *RegSurfaceTy =
3584df029ccSDimitry Andric FunctionType::get(Type::getVoidTy(C),
3594df029ccSDimitry Andric {Int8PtrPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy,
3604df029ccSDimitry Andric Type::getInt32Ty(C), Type::getInt32Ty(C)},
3614df029ccSDimitry Andric /*isVarArg=*/false);
3624df029ccSDimitry Andric FunctionCallee RegSurface = M.getOrInsertFunction(
3634df029ccSDimitry Andric IsHIP ? "__hipRegisterSurface" : "__cudaRegisterSurface", RegSurfaceTy);
3644df029ccSDimitry Andric
3654df029ccSDimitry Andric // Get the __cudaRegisterTexture function declaration.
3664df029ccSDimitry Andric FunctionType *RegTextureTy = FunctionType::get(
3674df029ccSDimitry Andric Type::getVoidTy(C),
3684df029ccSDimitry Andric {Int8PtrPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy, Type::getInt32Ty(C),
3694df029ccSDimitry Andric Type::getInt32Ty(C), Type::getInt32Ty(C)},
3704df029ccSDimitry Andric /*isVarArg=*/false);
3714df029ccSDimitry Andric FunctionCallee RegTexture = M.getOrInsertFunction(
3724df029ccSDimitry Andric IsHIP ? "__hipRegisterTexture" : "__cudaRegisterTexture", RegTextureTy);
3734df029ccSDimitry Andric
3744df029ccSDimitry Andric auto *RegGlobalsTy = FunctionType::get(Type::getVoidTy(C), Int8PtrPtrTy,
3754df029ccSDimitry Andric /*isVarArg*/ false);
3764df029ccSDimitry Andric auto *RegGlobalsFn =
3774df029ccSDimitry Andric Function::Create(RegGlobalsTy, GlobalValue::InternalLinkage,
3784df029ccSDimitry Andric IsHIP ? ".hip.globals_reg" : ".cuda.globals_reg", &M);
3794df029ccSDimitry Andric RegGlobalsFn->setSection(".text.startup");
3804df029ccSDimitry Andric
3814df029ccSDimitry Andric // Create the loop to register all the entries.
3824df029ccSDimitry Andric IRBuilder<> Builder(BasicBlock::Create(C, "entry", RegGlobalsFn));
3834df029ccSDimitry Andric auto *EntryBB = BasicBlock::Create(C, "while.entry", RegGlobalsFn);
3844df029ccSDimitry Andric auto *IfThenBB = BasicBlock::Create(C, "if.then", RegGlobalsFn);
3854df029ccSDimitry Andric auto *IfElseBB = BasicBlock::Create(C, "if.else", RegGlobalsFn);
3864df029ccSDimitry Andric auto *SwGlobalBB = BasicBlock::Create(C, "sw.global", RegGlobalsFn);
3874df029ccSDimitry Andric auto *SwManagedBB = BasicBlock::Create(C, "sw.managed", RegGlobalsFn);
3884df029ccSDimitry Andric auto *SwSurfaceBB = BasicBlock::Create(C, "sw.surface", RegGlobalsFn);
3894df029ccSDimitry Andric auto *SwTextureBB = BasicBlock::Create(C, "sw.texture", RegGlobalsFn);
3904df029ccSDimitry Andric auto *IfEndBB = BasicBlock::Create(C, "if.end", RegGlobalsFn);
3914df029ccSDimitry Andric auto *ExitBB = BasicBlock::Create(C, "while.end", RegGlobalsFn);
3924df029ccSDimitry Andric
3934df029ccSDimitry Andric auto *EntryCmp = Builder.CreateICmpNE(EntriesB, EntriesE);
3944df029ccSDimitry Andric Builder.CreateCondBr(EntryCmp, EntryBB, ExitBB);
3954df029ccSDimitry Andric Builder.SetInsertPoint(EntryBB);
3964df029ccSDimitry Andric auto *Entry = Builder.CreatePHI(PointerType::getUnqual(C), 2, "entry");
3974df029ccSDimitry Andric auto *AddrPtr =
3984df029ccSDimitry Andric Builder.CreateInBoundsGEP(offloading::getEntryTy(M), Entry,
3994df029ccSDimitry Andric {ConstantInt::get(getSizeTTy(M), 0),
4004df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 0)});
4014df029ccSDimitry Andric auto *Addr = Builder.CreateLoad(Int8PtrTy, AddrPtr, "addr");
4024df029ccSDimitry Andric auto *NamePtr =
4034df029ccSDimitry Andric Builder.CreateInBoundsGEP(offloading::getEntryTy(M), Entry,
4044df029ccSDimitry Andric {ConstantInt::get(getSizeTTy(M), 0),
4054df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 1)});
4064df029ccSDimitry Andric auto *Name = Builder.CreateLoad(Int8PtrTy, NamePtr, "name");
4074df029ccSDimitry Andric auto *SizePtr =
4084df029ccSDimitry Andric Builder.CreateInBoundsGEP(offloading::getEntryTy(M), Entry,
4094df029ccSDimitry Andric {ConstantInt::get(getSizeTTy(M), 0),
4104df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 2)});
4114df029ccSDimitry Andric auto *Size = Builder.CreateLoad(getSizeTTy(M), SizePtr, "size");
4124df029ccSDimitry Andric auto *FlagsPtr =
4134df029ccSDimitry Andric Builder.CreateInBoundsGEP(offloading::getEntryTy(M), Entry,
4144df029ccSDimitry Andric {ConstantInt::get(getSizeTTy(M), 0),
4154df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 3)});
4164df029ccSDimitry Andric auto *Flags = Builder.CreateLoad(Type::getInt32Ty(C), FlagsPtr, "flags");
4174df029ccSDimitry Andric auto *DataPtr =
4184df029ccSDimitry Andric Builder.CreateInBoundsGEP(offloading::getEntryTy(M), Entry,
4194df029ccSDimitry Andric {ConstantInt::get(getSizeTTy(M), 0),
4204df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), 4)});
4214df029ccSDimitry Andric auto *Data = Builder.CreateLoad(Type::getInt32Ty(C), DataPtr, "textype");
4224df029ccSDimitry Andric auto *Kind = Builder.CreateAnd(
4234df029ccSDimitry Andric Flags, ConstantInt::get(Type::getInt32Ty(C), 0x7), "type");
4244df029ccSDimitry Andric
4254df029ccSDimitry Andric // Extract the flags stored in the bit-field and convert them to C booleans.
4264df029ccSDimitry Andric auto *ExternBit = Builder.CreateAnd(
4274df029ccSDimitry Andric Flags, ConstantInt::get(Type::getInt32Ty(C),
4284df029ccSDimitry Andric llvm::offloading::OffloadGlobalExtern));
4294df029ccSDimitry Andric auto *Extern = Builder.CreateLShr(
4304df029ccSDimitry Andric ExternBit, ConstantInt::get(Type::getInt32Ty(C), 3), "extern");
4314df029ccSDimitry Andric auto *ConstantBit = Builder.CreateAnd(
4324df029ccSDimitry Andric Flags, ConstantInt::get(Type::getInt32Ty(C),
4334df029ccSDimitry Andric llvm::offloading::OffloadGlobalConstant));
4344df029ccSDimitry Andric auto *Const = Builder.CreateLShr(
4354df029ccSDimitry Andric ConstantBit, ConstantInt::get(Type::getInt32Ty(C), 4), "constant");
4364df029ccSDimitry Andric auto *NormalizedBit = Builder.CreateAnd(
4374df029ccSDimitry Andric Flags, ConstantInt::get(Type::getInt32Ty(C),
4384df029ccSDimitry Andric llvm::offloading::OffloadGlobalNormalized));
4394df029ccSDimitry Andric auto *Normalized = Builder.CreateLShr(
4404df029ccSDimitry Andric NormalizedBit, ConstantInt::get(Type::getInt32Ty(C), 5), "normalized");
4414df029ccSDimitry Andric auto *FnCond =
4424df029ccSDimitry Andric Builder.CreateICmpEQ(Size, ConstantInt::getNullValue(getSizeTTy(M)));
4434df029ccSDimitry Andric Builder.CreateCondBr(FnCond, IfThenBB, IfElseBB);
4444df029ccSDimitry Andric
4454df029ccSDimitry Andric // Create kernel registration code.
4464df029ccSDimitry Andric Builder.SetInsertPoint(IfThenBB);
4474df029ccSDimitry Andric Builder.CreateCall(RegFunc, {RegGlobalsFn->arg_begin(), Addr, Name, Name,
4484df029ccSDimitry Andric ConstantInt::get(Type::getInt32Ty(C), -1),
4494df029ccSDimitry Andric ConstantPointerNull::get(Int8PtrTy),
4504df029ccSDimitry Andric ConstantPointerNull::get(Int8PtrTy),
4514df029ccSDimitry Andric ConstantPointerNull::get(Int8PtrTy),
4524df029ccSDimitry Andric ConstantPointerNull::get(Int8PtrTy),
4534df029ccSDimitry Andric ConstantPointerNull::get(Int32PtrTy)});
4544df029ccSDimitry Andric Builder.CreateBr(IfEndBB);
4554df029ccSDimitry Andric Builder.SetInsertPoint(IfElseBB);
4564df029ccSDimitry Andric
4574df029ccSDimitry Andric auto *Switch = Builder.CreateSwitch(Kind, IfEndBB);
4584df029ccSDimitry Andric // Create global variable registration code.
4594df029ccSDimitry Andric Builder.SetInsertPoint(SwGlobalBB);
4604df029ccSDimitry Andric Builder.CreateCall(RegVar,
4614df029ccSDimitry Andric {RegGlobalsFn->arg_begin(), Addr, Name, Name, Extern, Size,
4624df029ccSDimitry Andric Const, ConstantInt::get(Type::getInt32Ty(C), 0)});
4634df029ccSDimitry Andric Builder.CreateBr(IfEndBB);
4644df029ccSDimitry Andric Switch->addCase(Builder.getInt32(llvm::offloading::OffloadGlobalEntry),
4654df029ccSDimitry Andric SwGlobalBB);
4664df029ccSDimitry Andric
4674df029ccSDimitry Andric // Create managed variable registration code.
4684df029ccSDimitry Andric Builder.SetInsertPoint(SwManagedBB);
4694df029ccSDimitry Andric Builder.CreateBr(IfEndBB);
4704df029ccSDimitry Andric Switch->addCase(Builder.getInt32(llvm::offloading::OffloadGlobalManagedEntry),
4714df029ccSDimitry Andric SwManagedBB);
4724df029ccSDimitry Andric // Create surface variable registration code.
4734df029ccSDimitry Andric Builder.SetInsertPoint(SwSurfaceBB);
4744df029ccSDimitry Andric if (EmitSurfacesAndTextures)
4754df029ccSDimitry Andric Builder.CreateCall(RegSurface, {RegGlobalsFn->arg_begin(), Addr, Name, Name,
4764df029ccSDimitry Andric Data, Extern});
4774df029ccSDimitry Andric Builder.CreateBr(IfEndBB);
4784df029ccSDimitry Andric Switch->addCase(Builder.getInt32(llvm::offloading::OffloadGlobalSurfaceEntry),
4794df029ccSDimitry Andric SwSurfaceBB);
4804df029ccSDimitry Andric
4814df029ccSDimitry Andric // Create texture variable registration code.
4824df029ccSDimitry Andric Builder.SetInsertPoint(SwTextureBB);
4834df029ccSDimitry Andric if (EmitSurfacesAndTextures)
4844df029ccSDimitry Andric Builder.CreateCall(RegTexture, {RegGlobalsFn->arg_begin(), Addr, Name, Name,
4854df029ccSDimitry Andric Data, Normalized, Extern});
4864df029ccSDimitry Andric Builder.CreateBr(IfEndBB);
4874df029ccSDimitry Andric Switch->addCase(Builder.getInt32(llvm::offloading::OffloadGlobalTextureEntry),
4884df029ccSDimitry Andric SwTextureBB);
4894df029ccSDimitry Andric
4904df029ccSDimitry Andric Builder.SetInsertPoint(IfEndBB);
4914df029ccSDimitry Andric auto *NewEntry = Builder.CreateInBoundsGEP(
4924df029ccSDimitry Andric offloading::getEntryTy(M), Entry, ConstantInt::get(getSizeTTy(M), 1));
4934df029ccSDimitry Andric auto *Cmp = Builder.CreateICmpEQ(
4944df029ccSDimitry Andric NewEntry,
4954df029ccSDimitry Andric ConstantExpr::getInBoundsGetElementPtr(
4964df029ccSDimitry Andric ArrayType::get(offloading::getEntryTy(M), 0), EntriesE,
4974df029ccSDimitry Andric ArrayRef<Constant *>({ConstantInt::get(getSizeTTy(M), 0),
4984df029ccSDimitry Andric ConstantInt::get(getSizeTTy(M), 0)})));
4994df029ccSDimitry Andric Entry->addIncoming(
5004df029ccSDimitry Andric ConstantExpr::getInBoundsGetElementPtr(
5014df029ccSDimitry Andric ArrayType::get(offloading::getEntryTy(M), 0), EntriesB,
5024df029ccSDimitry Andric ArrayRef<Constant *>({ConstantInt::get(getSizeTTy(M), 0),
5034df029ccSDimitry Andric ConstantInt::get(getSizeTTy(M), 0)})),
5044df029ccSDimitry Andric &RegGlobalsFn->getEntryBlock());
5054df029ccSDimitry Andric Entry->addIncoming(NewEntry, IfEndBB);
5064df029ccSDimitry Andric Builder.CreateCondBr(Cmp, ExitBB, EntryBB);
5074df029ccSDimitry Andric Builder.SetInsertPoint(ExitBB);
5084df029ccSDimitry Andric Builder.CreateRetVoid();
5094df029ccSDimitry Andric
5104df029ccSDimitry Andric return RegGlobalsFn;
5114df029ccSDimitry Andric }
5124df029ccSDimitry Andric
5134df029ccSDimitry Andric // Create the constructor and destructor to register the fatbinary with the CUDA
5144df029ccSDimitry Andric // runtime.
createRegisterFatbinFunction(Module & M,GlobalVariable * FatbinDesc,bool IsHIP,EntryArrayTy EntryArray,StringRef Suffix,bool EmitSurfacesAndTextures)5154df029ccSDimitry Andric void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc,
5164df029ccSDimitry Andric bool IsHIP, EntryArrayTy EntryArray,
5174df029ccSDimitry Andric StringRef Suffix,
5184df029ccSDimitry Andric bool EmitSurfacesAndTextures) {
5194df029ccSDimitry Andric LLVMContext &C = M.getContext();
5204df029ccSDimitry Andric auto *CtorFuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
5214df029ccSDimitry Andric auto *CtorFunc = Function::Create(
5224df029ccSDimitry Andric CtorFuncTy, GlobalValue::InternalLinkage,
5234df029ccSDimitry Andric (IsHIP ? ".hip.fatbin_reg" : ".cuda.fatbin_reg") + Suffix, &M);
5244df029ccSDimitry Andric CtorFunc->setSection(".text.startup");
5254df029ccSDimitry Andric
5264df029ccSDimitry Andric auto *DtorFuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
5274df029ccSDimitry Andric auto *DtorFunc = Function::Create(
5284df029ccSDimitry Andric DtorFuncTy, GlobalValue::InternalLinkage,
5294df029ccSDimitry Andric (IsHIP ? ".hip.fatbin_unreg" : ".cuda.fatbin_unreg") + Suffix, &M);
5304df029ccSDimitry Andric DtorFunc->setSection(".text.startup");
5314df029ccSDimitry Andric
5324df029ccSDimitry Andric auto *PtrTy = PointerType::getUnqual(C);
5334df029ccSDimitry Andric
5344df029ccSDimitry Andric // Get the __cudaRegisterFatBinary function declaration.
5354df029ccSDimitry Andric auto *RegFatTy = FunctionType::get(PtrTy, PtrTy, /*isVarArg=*/false);
5364df029ccSDimitry Andric FunctionCallee RegFatbin = M.getOrInsertFunction(
5374df029ccSDimitry Andric IsHIP ? "__hipRegisterFatBinary" : "__cudaRegisterFatBinary", RegFatTy);
5384df029ccSDimitry Andric // Get the __cudaRegisterFatBinaryEnd function declaration.
5394df029ccSDimitry Andric auto *RegFatEndTy =
5404df029ccSDimitry Andric FunctionType::get(Type::getVoidTy(C), PtrTy, /*isVarArg=*/false);
5414df029ccSDimitry Andric FunctionCallee RegFatbinEnd =
5424df029ccSDimitry Andric M.getOrInsertFunction("__cudaRegisterFatBinaryEnd", RegFatEndTy);
5434df029ccSDimitry Andric // Get the __cudaUnregisterFatBinary function declaration.
5444df029ccSDimitry Andric auto *UnregFatTy =
5454df029ccSDimitry Andric FunctionType::get(Type::getVoidTy(C), PtrTy, /*isVarArg=*/false);
5464df029ccSDimitry Andric FunctionCallee UnregFatbin = M.getOrInsertFunction(
5474df029ccSDimitry Andric IsHIP ? "__hipUnregisterFatBinary" : "__cudaUnregisterFatBinary",
5484df029ccSDimitry Andric UnregFatTy);
5494df029ccSDimitry Andric
5504df029ccSDimitry Andric auto *AtExitTy =
5514df029ccSDimitry Andric FunctionType::get(Type::getInt32Ty(C), PtrTy, /*isVarArg=*/false);
5524df029ccSDimitry Andric FunctionCallee AtExit = M.getOrInsertFunction("atexit", AtExitTy);
5534df029ccSDimitry Andric
5544df029ccSDimitry Andric auto *BinaryHandleGlobal = new llvm::GlobalVariable(
5554df029ccSDimitry Andric M, PtrTy, false, llvm::GlobalValue::InternalLinkage,
5564df029ccSDimitry Andric llvm::ConstantPointerNull::get(PtrTy),
5574df029ccSDimitry Andric (IsHIP ? ".hip.binary_handle" : ".cuda.binary_handle") + Suffix);
5584df029ccSDimitry Andric
5594df029ccSDimitry Andric // Create the constructor to register this image with the runtime.
5604df029ccSDimitry Andric IRBuilder<> CtorBuilder(BasicBlock::Create(C, "entry", CtorFunc));
5614df029ccSDimitry Andric CallInst *Handle = CtorBuilder.CreateCall(
5624df029ccSDimitry Andric RegFatbin,
5634df029ccSDimitry Andric ConstantExpr::getPointerBitCastOrAddrSpaceCast(FatbinDesc, PtrTy));
5644df029ccSDimitry Andric CtorBuilder.CreateAlignedStore(
5654df029ccSDimitry Andric Handle, BinaryHandleGlobal,
5664df029ccSDimitry Andric Align(M.getDataLayout().getPointerTypeSize(PtrTy)));
5674df029ccSDimitry Andric CtorBuilder.CreateCall(createRegisterGlobalsFunction(M, IsHIP, EntryArray,
5684df029ccSDimitry Andric Suffix,
5694df029ccSDimitry Andric EmitSurfacesAndTextures),
5704df029ccSDimitry Andric Handle);
5714df029ccSDimitry Andric if (!IsHIP)
5724df029ccSDimitry Andric CtorBuilder.CreateCall(RegFatbinEnd, Handle);
5734df029ccSDimitry Andric CtorBuilder.CreateCall(AtExit, DtorFunc);
5744df029ccSDimitry Andric CtorBuilder.CreateRetVoid();
5754df029ccSDimitry Andric
5764df029ccSDimitry Andric // Create the destructor to unregister the image with the runtime. We cannot
5774df029ccSDimitry Andric // use a standard global destructor after CUDA 9.2 so this must be called by
5784df029ccSDimitry Andric // `atexit()` intead.
5794df029ccSDimitry Andric IRBuilder<> DtorBuilder(BasicBlock::Create(C, "entry", DtorFunc));
5804df029ccSDimitry Andric LoadInst *BinaryHandle = DtorBuilder.CreateAlignedLoad(
5814df029ccSDimitry Andric PtrTy, BinaryHandleGlobal,
5824df029ccSDimitry Andric Align(M.getDataLayout().getPointerTypeSize(PtrTy)));
5834df029ccSDimitry Andric DtorBuilder.CreateCall(UnregFatbin, BinaryHandle);
5844df029ccSDimitry Andric DtorBuilder.CreateRetVoid();
5854df029ccSDimitry Andric
5864df029ccSDimitry Andric // Add this function to constructors.
587ac9a064cSDimitry Andric appendToGlobalCtors(M, CtorFunc, /*Priority=*/101);
5884df029ccSDimitry Andric }
5894df029ccSDimitry Andric } // namespace
5904df029ccSDimitry Andric
wrapOpenMPBinaries(Module & M,ArrayRef<ArrayRef<char>> Images,EntryArrayTy EntryArray,llvm::StringRef Suffix,bool Relocatable)5914df029ccSDimitry Andric Error offloading::wrapOpenMPBinaries(Module &M, ArrayRef<ArrayRef<char>> Images,
5924df029ccSDimitry Andric EntryArrayTy EntryArray,
593ac9a064cSDimitry Andric llvm::StringRef Suffix, bool Relocatable) {
594ac9a064cSDimitry Andric GlobalVariable *Desc =
595ac9a064cSDimitry Andric createBinDesc(M, Images, EntryArray, Suffix, Relocatable);
5964df029ccSDimitry Andric if (!Desc)
5974df029ccSDimitry Andric return createStringError(inconvertibleErrorCode(),
5984df029ccSDimitry Andric "No binary descriptors created.");
5994df029ccSDimitry Andric createRegisterFunction(M, Desc, Suffix);
6004df029ccSDimitry Andric return Error::success();
6014df029ccSDimitry Andric }
6024df029ccSDimitry Andric
wrapCudaBinary(Module & M,ArrayRef<char> Image,EntryArrayTy EntryArray,llvm::StringRef Suffix,bool EmitSurfacesAndTextures)6034df029ccSDimitry Andric Error offloading::wrapCudaBinary(Module &M, ArrayRef<char> Image,
6044df029ccSDimitry Andric EntryArrayTy EntryArray,
6054df029ccSDimitry Andric llvm::StringRef Suffix,
6064df029ccSDimitry Andric bool EmitSurfacesAndTextures) {
6074df029ccSDimitry Andric GlobalVariable *Desc = createFatbinDesc(M, Image, /*IsHip=*/false, Suffix);
6084df029ccSDimitry Andric if (!Desc)
6094df029ccSDimitry Andric return createStringError(inconvertibleErrorCode(),
6104df029ccSDimitry Andric "No fatbin section created.");
6114df029ccSDimitry Andric
6124df029ccSDimitry Andric createRegisterFatbinFunction(M, Desc, /*IsHip=*/false, EntryArray, Suffix,
6134df029ccSDimitry Andric EmitSurfacesAndTextures);
6144df029ccSDimitry Andric return Error::success();
6154df029ccSDimitry Andric }
6164df029ccSDimitry Andric
wrapHIPBinary(Module & M,ArrayRef<char> Image,EntryArrayTy EntryArray,llvm::StringRef Suffix,bool EmitSurfacesAndTextures)6174df029ccSDimitry Andric Error offloading::wrapHIPBinary(Module &M, ArrayRef<char> Image,
6184df029ccSDimitry Andric EntryArrayTy EntryArray, llvm::StringRef Suffix,
6194df029ccSDimitry Andric bool EmitSurfacesAndTextures) {
6204df029ccSDimitry Andric GlobalVariable *Desc = createFatbinDesc(M, Image, /*IsHip=*/true, Suffix);
6214df029ccSDimitry Andric if (!Desc)
6224df029ccSDimitry Andric return createStringError(inconvertibleErrorCode(),
6234df029ccSDimitry Andric "No fatbin section created.");
6244df029ccSDimitry Andric
6254df029ccSDimitry Andric createRegisterFatbinFunction(M, Desc, /*IsHip=*/true, EntryArray, Suffix,
6264df029ccSDimitry Andric EmitSurfacesAndTextures);
6274df029ccSDimitry Andric return Error::success();
6284df029ccSDimitry Andric }
629