//===- OffloadWrapper.cpp ---------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/Constants.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/OffloadBinary.h" #include "llvm/Support/Error.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/ModuleUtils.h" usingnamespacellvm; usingnamespacellvm::offloading; namespace { /// Magic number that begins the section containing the CUDA fatbinary. constexpr unsigned CudaFatMagic = …; constexpr unsigned HIPFatMagic = …; IntegerType *getSizeTTy(Module &M) { … } // struct __tgt_device_image { // void *ImageStart; // void *ImageEnd; // __tgt_offload_entry *EntriesBegin; // __tgt_offload_entry *EntriesEnd; // }; StructType *getDeviceImageTy(Module &M) { … } PointerType *getDeviceImagePtrTy(Module &M) { … } // struct __tgt_bin_desc { // int32_t NumDeviceImages; // __tgt_device_image *DeviceImages; // __tgt_offload_entry *HostEntriesBegin; // __tgt_offload_entry *HostEntriesEnd; // }; StructType *getBinDescTy(Module &M) { … } PointerType *getBinDescPtrTy(Module &M) { … } /// 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 /// library. It is defined as follows /// /// __attribute__((visibility("hidden"))) /// extern __tgt_offload_entry *__start_omp_offloading_entries; /// __attribute__((visibility("hidden"))) /// extern __tgt_offload_entry *__stop_omp_offloading_entries; /// /// static const char Image0[] = { <Bufs.front() contents> }; /// ... /// static const char ImageN[] = { <Bufs.back() contents> }; /// /// static const __tgt_device_image Images[] = { /// { /// Image0, /*ImageStart*/ /// Image0 + sizeof(Image0), /*ImageEnd*/ /// __start_omp_offloading_entries, /*EntriesBegin*/ /// __stop_omp_offloading_entries /*EntriesEnd*/ /// }, /// ... /// { /// ImageN, /*ImageStart*/ /// ImageN + sizeof(ImageN), /*ImageEnd*/ /// __start_omp_offloading_entries, /*EntriesBegin*/ /// __stop_omp_offloading_entries /*EntriesEnd*/ /// } /// }; /// /// static const __tgt_bin_desc BinDesc = { /// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/ /// Images, /*DeviceImages*/ /// __start_omp_offloading_entries, /*HostEntriesBegin*/ /// __stop_omp_offloading_entries /*HostEntriesEnd*/ /// }; /// /// Global variable that represents BinDesc is returned. GlobalVariable *createBinDesc(Module &M, ArrayRef<ArrayRef<char>> Bufs, EntryArrayTy EntryArray, StringRef Suffix, bool Relocatable) { … } Function *createUnregisterFunction(Module &M, GlobalVariable *BinDesc, StringRef Suffix) { … } void createRegisterFunction(Module &M, GlobalVariable *BinDesc, StringRef Suffix) { … } // struct fatbin_wrapper { // int32_t magic; // int32_t version; // void *image; // void *reserved; //}; StructType *getFatbinWrapperTy(Module &M) { … } /// Embed the image \p Image into the module \p M so it can be found by the /// runtime. GlobalVariable *createFatbinDesc(Module &M, ArrayRef<char> Image, bool IsHIP, StringRef Suffix) { … } /// Create the register globals function. We will iterate all of the offloading /// entries stored at the begin / end symbols and register them according to /// their type. This creates the following function in IR: /// /// extern struct __tgt_offload_entry __start_cuda_offloading_entries; /// extern struct __tgt_offload_entry __stop_cuda_offloading_entries; /// /// extern void __cudaRegisterFunction(void **, void *, void *, void *, int, /// void *, void *, void *, void *, int *); /// extern void __cudaRegisterVar(void **, void *, void *, void *, int32_t, /// int64_t, int32_t, int32_t); /// /// void __cudaRegisterTest(void **fatbinHandle) { /// for (struct __tgt_offload_entry *entry = &__start_cuda_offloading_entries; /// entry != &__stop_cuda_offloading_entries; ++entry) { /// if (!entry->size) /// __cudaRegisterFunction(fatbinHandle, entry->addr, entry->name, /// entry->name, -1, 0, 0, 0, 0, 0); /// else /// __cudaRegisterVar(fatbinHandle, entry->addr, entry->name, entry->name, /// 0, entry->size, 0, 0); /// } /// } Function *createRegisterGlobalsFunction(Module &M, bool IsHIP, EntryArrayTy EntryArray, StringRef Suffix, bool EmitSurfacesAndTextures) { … } // Create the constructor and destructor to register the fatbinary with the CUDA // runtime. void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc, bool IsHIP, EntryArrayTy EntryArray, StringRef Suffix, bool EmitSurfacesAndTextures) { … } } // namespace Error offloading::wrapOpenMPBinaries(Module &M, ArrayRef<ArrayRef<char>> Images, EntryArrayTy EntryArray, llvm::StringRef Suffix, bool Relocatable) { … } Error offloading::wrapCudaBinary(Module &M, ArrayRef<char> Image, EntryArrayTy EntryArray, llvm::StringRef Suffix, bool EmitSurfacesAndTextures) { … } Error offloading::wrapHIPBinary(Module &M, ArrayRef<char> Image, EntryArrayTy EntryArray, llvm::StringRef Suffix, bool EmitSurfacesAndTextures) { … }