1330d8983SJohannes Doerfert //===-RTLs/generic-64bit/src/rtl.cpp - Target RTLs Implementation - C++ -*-===// 2330d8983SJohannes Doerfert // 3330d8983SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4330d8983SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information. 5330d8983SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6330d8983SJohannes Doerfert // 7330d8983SJohannes Doerfert //===----------------------------------------------------------------------===// 8330d8983SJohannes Doerfert // 9330d8983SJohannes Doerfert // RTL NextGen for generic 64-bit machine 10330d8983SJohannes Doerfert // 11330d8983SJohannes Doerfert //===----------------------------------------------------------------------===// 12330d8983SJohannes Doerfert 13330d8983SJohannes Doerfert #include <cassert> 14330d8983SJohannes Doerfert #include <cstddef> 15330d8983SJohannes Doerfert #include <ffi.h> 16330d8983SJohannes Doerfert #include <string> 17330d8983SJohannes Doerfert #include <unordered_map> 18330d8983SJohannes Doerfert 19330d8983SJohannes Doerfert #include "Shared/Debug.h" 20330d8983SJohannes Doerfert #include "Shared/Environment.h" 21e3938f4dSJoseph Huber #include "Utils/ELF.h" 22330d8983SJohannes Doerfert 23330d8983SJohannes Doerfert #include "GlobalHandler.h" 24330d8983SJohannes Doerfert #include "OpenMP/OMPT/Callback.h" 25330d8983SJohannes Doerfert #include "PluginInterface.h" 26330d8983SJohannes Doerfert #include "omptarget.h" 27330d8983SJohannes Doerfert 28330d8983SJohannes Doerfert #include "llvm/ADT/SmallVector.h" 29330d8983SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPConstants.h" 30330d8983SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPDeviceConstants.h" 31330d8983SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPGridValues.h" 32330d8983SJohannes Doerfert #include "llvm/Support/DynamicLibrary.h" 33330d8983SJohannes Doerfert 343e54768dSJoseph Huber #if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \ 353e54768dSJoseph Huber !defined(__ORDER_BIG_ENDIAN__) 363e54768dSJoseph Huber #error "Missing preprocessor definitions for endianness detection." 373e54768dSJoseph Huber #endif 383e54768dSJoseph Huber 393e54768dSJoseph Huber #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 403e54768dSJoseph Huber #define LITTLEENDIAN_CPU 413e54768dSJoseph Huber #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) 423e54768dSJoseph Huber #define BIGENDIAN_CPU 433e54768dSJoseph Huber #endif 443e54768dSJoseph Huber 45330d8983SJohannes Doerfert // The number of devices in this plugin. 46330d8983SJohannes Doerfert #define NUM_DEVICES 4 47330d8983SJohannes Doerfert 48330d8983SJohannes Doerfert namespace llvm { 49330d8983SJohannes Doerfert namespace omp { 50330d8983SJohannes Doerfert namespace target { 51330d8983SJohannes Doerfert namespace plugin { 52330d8983SJohannes Doerfert 53330d8983SJohannes Doerfert /// Forward declarations for all specialized data structures. 54330d8983SJohannes Doerfert struct GenELF64KernelTy; 55330d8983SJohannes Doerfert struct GenELF64DeviceTy; 56330d8983SJohannes Doerfert struct GenELF64PluginTy; 57330d8983SJohannes Doerfert 58330d8983SJohannes Doerfert using llvm::sys::DynamicLibrary; 59330d8983SJohannes Doerfert 60330d8983SJohannes Doerfert /// Class implementing kernel functionalities for GenELF64. 61330d8983SJohannes Doerfert struct GenELF64KernelTy : public GenericKernelTy { 62330d8983SJohannes Doerfert /// Construct the kernel with a name and an execution mode. 63330d8983SJohannes Doerfert GenELF64KernelTy(const char *Name) : GenericKernelTy(Name), Func(nullptr) {} 64330d8983SJohannes Doerfert 65330d8983SJohannes Doerfert /// Initialize the kernel. 66330d8983SJohannes Doerfert Error initImpl(GenericDeviceTy &Device, DeviceImageTy &Image) override { 67330d8983SJohannes Doerfert // Functions have zero size. 68330d8983SJohannes Doerfert GlobalTy Global(getName(), 0); 69330d8983SJohannes Doerfert 70330d8983SJohannes Doerfert // Get the metadata (address) of the kernel function. 71330d8983SJohannes Doerfert GenericGlobalHandlerTy &GHandler = Device.Plugin.getGlobalHandler(); 72330d8983SJohannes Doerfert if (auto Err = GHandler.getGlobalMetadataFromDevice(Device, Image, Global)) 73330d8983SJohannes Doerfert return Err; 74330d8983SJohannes Doerfert 75330d8983SJohannes Doerfert // Check that the function pointer is valid. 76330d8983SJohannes Doerfert if (!Global.getPtr()) 77330d8983SJohannes Doerfert return Plugin::error("Invalid function for kernel %s", getName()); 78330d8983SJohannes Doerfert 79330d8983SJohannes Doerfert // Save the function pointer. 80330d8983SJohannes Doerfert Func = (void (*)())Global.getPtr(); 81330d8983SJohannes Doerfert 82330d8983SJohannes Doerfert KernelEnvironment.Configuration.ExecMode = OMP_TGT_EXEC_MODE_GENERIC; 83330d8983SJohannes Doerfert KernelEnvironment.Configuration.MayUseNestedParallelism = /*Unknown=*/2; 84330d8983SJohannes Doerfert KernelEnvironment.Configuration.UseGenericStateMachine = /*Unknown=*/2; 85330d8983SJohannes Doerfert 86330d8983SJohannes Doerfert // Set the maximum number of threads to a single. 87330d8983SJohannes Doerfert MaxNumThreads = 1; 88330d8983SJohannes Doerfert return Plugin::success(); 89330d8983SJohannes Doerfert } 90330d8983SJohannes Doerfert 91330d8983SJohannes Doerfert /// Launch the kernel using the libffi. 9292376c3fSShilei Tian Error launchImpl(GenericDeviceTy &GenericDevice, uint32_t NumThreads[3], 9392376c3fSShilei Tian uint32_t NumBlocks[3], KernelArgsTy &KernelArgs, 9454b5c76dSJohannes Doerfert KernelLaunchParamsTy LaunchParams, 95330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) const override { 96330d8983SJohannes Doerfert // Create a vector of ffi_types, one per argument. 97330d8983SJohannes Doerfert SmallVector<ffi_type *, 16> ArgTypes(KernelArgs.NumArgs, &ffi_type_pointer); 98330d8983SJohannes Doerfert ffi_type **ArgTypesPtr = (ArgTypes.size()) ? &ArgTypes[0] : nullptr; 99330d8983SJohannes Doerfert 100330d8983SJohannes Doerfert // Prepare the cif structure before running the kernel function. 101330d8983SJohannes Doerfert ffi_cif Cif; 102330d8983SJohannes Doerfert ffi_status Status = ffi_prep_cif(&Cif, FFI_DEFAULT_ABI, KernelArgs.NumArgs, 103330d8983SJohannes Doerfert &ffi_type_void, ArgTypesPtr); 104330d8983SJohannes Doerfert if (Status != FFI_OK) 105330d8983SJohannes Doerfert return Plugin::error("Error in ffi_prep_cif: %d", Status); 106330d8983SJohannes Doerfert 107330d8983SJohannes Doerfert // Call the kernel function through libffi. 108330d8983SJohannes Doerfert long Return; 10954b5c76dSJohannes Doerfert ffi_call(&Cif, Func, &Return, (void **)LaunchParams.Ptrs); 110330d8983SJohannes Doerfert 111330d8983SJohannes Doerfert return Plugin::success(); 112330d8983SJohannes Doerfert } 113330d8983SJohannes Doerfert 114330d8983SJohannes Doerfert private: 115330d8983SJohannes Doerfert /// The kernel function to execute. 116330d8983SJohannes Doerfert void (*Func)(void); 117330d8983SJohannes Doerfert }; 118330d8983SJohannes Doerfert 119330d8983SJohannes Doerfert /// Class implementing the GenELF64 device images properties. 120330d8983SJohannes Doerfert struct GenELF64DeviceImageTy : public DeviceImageTy { 121330d8983SJohannes Doerfert /// Create the GenELF64 image with the id and the target image pointer. 122330d8983SJohannes Doerfert GenELF64DeviceImageTy(int32_t ImageId, GenericDeviceTy &Device, 123330d8983SJohannes Doerfert const __tgt_device_image *TgtImage) 124330d8983SJohannes Doerfert : DeviceImageTy(ImageId, Device, TgtImage), DynLib() {} 125330d8983SJohannes Doerfert 126330d8983SJohannes Doerfert /// Getter and setter for the dynamic library. 127330d8983SJohannes Doerfert DynamicLibrary &getDynamicLibrary() { return DynLib; } 128330d8983SJohannes Doerfert void setDynamicLibrary(const DynamicLibrary &Lib) { DynLib = Lib; } 129330d8983SJohannes Doerfert 130330d8983SJohannes Doerfert private: 131330d8983SJohannes Doerfert /// The dynamic library that loaded the image. 132330d8983SJohannes Doerfert DynamicLibrary DynLib; 133330d8983SJohannes Doerfert }; 134330d8983SJohannes Doerfert 135330d8983SJohannes Doerfert /// Class implementing the device functionalities for GenELF64. 136330d8983SJohannes Doerfert struct GenELF64DeviceTy : public GenericDeviceTy { 137330d8983SJohannes Doerfert /// Create the device with a specific id. 138330d8983SJohannes Doerfert GenELF64DeviceTy(GenericPluginTy &Plugin, int32_t DeviceId, 139330d8983SJohannes Doerfert int32_t NumDevices) 140330d8983SJohannes Doerfert : GenericDeviceTy(Plugin, DeviceId, NumDevices, GenELF64GridValues) {} 141330d8983SJohannes Doerfert 142330d8983SJohannes Doerfert ~GenELF64DeviceTy() {} 143330d8983SJohannes Doerfert 144330d8983SJohannes Doerfert /// Initialize the device, which is a no-op 145330d8983SJohannes Doerfert Error initImpl(GenericPluginTy &Plugin) override { return Plugin::success(); } 146330d8983SJohannes Doerfert 147330d8983SJohannes Doerfert /// Deinitialize the device, which is a no-op 148330d8983SJohannes Doerfert Error deinitImpl() override { return Plugin::success(); } 149330d8983SJohannes Doerfert 150330d8983SJohannes Doerfert /// See GenericDeviceTy::getComputeUnitKind(). 151330d8983SJohannes Doerfert std::string getComputeUnitKind() const override { return "generic-64bit"; } 152330d8983SJohannes Doerfert 153330d8983SJohannes Doerfert /// Construct the kernel for a specific image on the device. 154330d8983SJohannes Doerfert Expected<GenericKernelTy &> constructKernel(const char *Name) override { 155330d8983SJohannes Doerfert // Allocate and construct the kernel. 156330d8983SJohannes Doerfert GenELF64KernelTy *GenELF64Kernel = Plugin.allocate<GenELF64KernelTy>(); 157330d8983SJohannes Doerfert if (!GenELF64Kernel) 158330d8983SJohannes Doerfert return Plugin::error("Failed to allocate memory for GenELF64 kernel"); 159330d8983SJohannes Doerfert 160330d8983SJohannes Doerfert new (GenELF64Kernel) GenELF64KernelTy(Name); 161330d8983SJohannes Doerfert 162330d8983SJohannes Doerfert return *GenELF64Kernel; 163330d8983SJohannes Doerfert } 164330d8983SJohannes Doerfert 165330d8983SJohannes Doerfert /// Set the current context to this device, which is a no-op. 166330d8983SJohannes Doerfert Error setContext() override { return Plugin::success(); } 167330d8983SJohannes Doerfert 168330d8983SJohannes Doerfert /// Load the binary image into the device and allocate an image object. 169330d8983SJohannes Doerfert Expected<DeviceImageTy *> loadBinaryImpl(const __tgt_device_image *TgtImage, 170330d8983SJohannes Doerfert int32_t ImageId) override { 171330d8983SJohannes Doerfert // Allocate and initialize the image object. 172330d8983SJohannes Doerfert GenELF64DeviceImageTy *Image = Plugin.allocate<GenELF64DeviceImageTy>(); 173330d8983SJohannes Doerfert new (Image) GenELF64DeviceImageTy(ImageId, *this, TgtImage); 174330d8983SJohannes Doerfert 175330d8983SJohannes Doerfert // Create a temporary file. 176330d8983SJohannes Doerfert char TmpFileName[] = "/tmp/tmpfile_XXXXXX"; 177330d8983SJohannes Doerfert int TmpFileFd = mkstemp(TmpFileName); 178330d8983SJohannes Doerfert if (TmpFileFd == -1) 179330d8983SJohannes Doerfert return Plugin::error("Failed to create tmpfile for loading target image"); 180330d8983SJohannes Doerfert 181330d8983SJohannes Doerfert // Open the temporary file. 182330d8983SJohannes Doerfert FILE *TmpFile = fdopen(TmpFileFd, "wb"); 183330d8983SJohannes Doerfert if (!TmpFile) 184330d8983SJohannes Doerfert return Plugin::error("Failed to open tmpfile %s for loading target image", 185330d8983SJohannes Doerfert TmpFileName); 186330d8983SJohannes Doerfert 187330d8983SJohannes Doerfert // Write the image into the temporary file. 188330d8983SJohannes Doerfert size_t Written = fwrite(Image->getStart(), Image->getSize(), 1, TmpFile); 189330d8983SJohannes Doerfert if (Written != 1) 190330d8983SJohannes Doerfert return Plugin::error("Failed to write target image to tmpfile %s", 191330d8983SJohannes Doerfert TmpFileName); 192330d8983SJohannes Doerfert 193330d8983SJohannes Doerfert // Close the temporary file. 194330d8983SJohannes Doerfert int Ret = fclose(TmpFile); 195330d8983SJohannes Doerfert if (Ret) 196330d8983SJohannes Doerfert return Plugin::error("Failed to close tmpfile %s with the target image", 197330d8983SJohannes Doerfert TmpFileName); 198330d8983SJohannes Doerfert 199330d8983SJohannes Doerfert // Load the temporary file as a dynamic library. 200330d8983SJohannes Doerfert std::string ErrMsg; 201330d8983SJohannes Doerfert DynamicLibrary DynLib = 202330d8983SJohannes Doerfert DynamicLibrary::getPermanentLibrary(TmpFileName, &ErrMsg); 203330d8983SJohannes Doerfert 204330d8983SJohannes Doerfert // Check if the loaded library is valid. 205330d8983SJohannes Doerfert if (!DynLib.isValid()) 206330d8983SJohannes Doerfert return Plugin::error("Failed to load target image: %s", ErrMsg.c_str()); 207330d8983SJohannes Doerfert 208330d8983SJohannes Doerfert // Save a reference of the image's dynamic library. 209330d8983SJohannes Doerfert Image->setDynamicLibrary(DynLib); 210330d8983SJohannes Doerfert 211330d8983SJohannes Doerfert return Image; 212330d8983SJohannes Doerfert } 213330d8983SJohannes Doerfert 214330d8983SJohannes Doerfert /// Allocate memory. Use std::malloc in all cases. 215330d8983SJohannes Doerfert void *allocate(size_t Size, void *, TargetAllocTy Kind) override { 216330d8983SJohannes Doerfert if (Size == 0) 217330d8983SJohannes Doerfert return nullptr; 218330d8983SJohannes Doerfert 219330d8983SJohannes Doerfert void *MemAlloc = nullptr; 220330d8983SJohannes Doerfert switch (Kind) { 221330d8983SJohannes Doerfert case TARGET_ALLOC_DEFAULT: 222330d8983SJohannes Doerfert case TARGET_ALLOC_DEVICE: 223330d8983SJohannes Doerfert case TARGET_ALLOC_HOST: 224330d8983SJohannes Doerfert case TARGET_ALLOC_SHARED: 225330d8983SJohannes Doerfert case TARGET_ALLOC_DEVICE_NON_BLOCKING: 226330d8983SJohannes Doerfert MemAlloc = std::malloc(Size); 227330d8983SJohannes Doerfert break; 228330d8983SJohannes Doerfert } 229330d8983SJohannes Doerfert return MemAlloc; 230330d8983SJohannes Doerfert } 231330d8983SJohannes Doerfert 232330d8983SJohannes Doerfert /// Free the memory. Use std::free in all cases. 233330d8983SJohannes Doerfert int free(void *TgtPtr, TargetAllocTy Kind) override { 234330d8983SJohannes Doerfert std::free(TgtPtr); 235330d8983SJohannes Doerfert return OFFLOAD_SUCCESS; 236330d8983SJohannes Doerfert } 237330d8983SJohannes Doerfert 238330d8983SJohannes Doerfert /// This plugin does nothing to lock buffers. Do not return an error, just 239330d8983SJohannes Doerfert /// return the same pointer as the device pointer. 240330d8983SJohannes Doerfert Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) override { 241330d8983SJohannes Doerfert return HstPtr; 242330d8983SJohannes Doerfert } 243330d8983SJohannes Doerfert 244330d8983SJohannes Doerfert /// Nothing to do when unlocking the buffer. 245330d8983SJohannes Doerfert Error dataUnlockImpl(void *HstPtr) override { return Plugin::success(); } 246330d8983SJohannes Doerfert 247330d8983SJohannes Doerfert /// Indicate that the buffer is not pinned. 248330d8983SJohannes Doerfert Expected<bool> isPinnedPtrImpl(void *HstPtr, void *&BaseHstPtr, 249330d8983SJohannes Doerfert void *&BaseDevAccessiblePtr, 250330d8983SJohannes Doerfert size_t &BaseSize) const override { 251330d8983SJohannes Doerfert return false; 252330d8983SJohannes Doerfert } 253330d8983SJohannes Doerfert 254330d8983SJohannes Doerfert /// Submit data to the device (host to device transfer). 255330d8983SJohannes Doerfert Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size, 256330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) override { 257330d8983SJohannes Doerfert std::memcpy(TgtPtr, HstPtr, Size); 258330d8983SJohannes Doerfert return Plugin::success(); 259330d8983SJohannes Doerfert } 260330d8983SJohannes Doerfert 261330d8983SJohannes Doerfert /// Retrieve data from the device (device to host transfer). 262330d8983SJohannes Doerfert Error dataRetrieveImpl(void *HstPtr, const void *TgtPtr, int64_t Size, 263330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) override { 264330d8983SJohannes Doerfert std::memcpy(HstPtr, TgtPtr, Size); 265330d8983SJohannes Doerfert return Plugin::success(); 266330d8983SJohannes Doerfert } 267330d8983SJohannes Doerfert 268330d8983SJohannes Doerfert /// Exchange data between two devices within the plugin. This function is not 269330d8983SJohannes Doerfert /// supported in this plugin. 270330d8983SJohannes Doerfert Error dataExchangeImpl(const void *SrcPtr, GenericDeviceTy &DstGenericDevice, 271330d8983SJohannes Doerfert void *DstPtr, int64_t Size, 272330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) override { 273330d8983SJohannes Doerfert // This function should never be called because the function 274330d8983SJohannes Doerfert // GenELF64PluginTy::isDataExchangable() returns false. 275330d8983SJohannes Doerfert return Plugin::error("dataExchangeImpl not supported"); 276330d8983SJohannes Doerfert } 277330d8983SJohannes Doerfert 278330d8983SJohannes Doerfert /// All functions are already synchronous. No need to do anything on this 279330d8983SJohannes Doerfert /// synchronization function. 280330d8983SJohannes Doerfert Error synchronizeImpl(__tgt_async_info &AsyncInfo) override { 281330d8983SJohannes Doerfert return Plugin::success(); 282330d8983SJohannes Doerfert } 283330d8983SJohannes Doerfert 284330d8983SJohannes Doerfert /// All functions are already synchronous. No need to do anything on this 285330d8983SJohannes Doerfert /// query function. 286330d8983SJohannes Doerfert Error queryAsyncImpl(__tgt_async_info &AsyncInfo) override { 287330d8983SJohannes Doerfert return Plugin::success(); 288330d8983SJohannes Doerfert } 289330d8983SJohannes Doerfert 290330d8983SJohannes Doerfert /// This plugin does not support interoperability 291330d8983SJohannes Doerfert Error initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) override { 292330d8983SJohannes Doerfert return Plugin::error("initAsyncInfoImpl not supported"); 293330d8983SJohannes Doerfert } 294330d8983SJohannes Doerfert 295330d8983SJohannes Doerfert /// This plugin does not support interoperability 296330d8983SJohannes Doerfert Error initDeviceInfoImpl(__tgt_device_info *DeviceInfo) override { 297330d8983SJohannes Doerfert return Plugin::error("initDeviceInfoImpl not supported"); 298330d8983SJohannes Doerfert } 299330d8983SJohannes Doerfert 300330d8983SJohannes Doerfert /// This plugin does not support the event API. Do nothing without failing. 301330d8983SJohannes Doerfert Error createEventImpl(void **EventPtrStorage) override { 302330d8983SJohannes Doerfert *EventPtrStorage = nullptr; 303330d8983SJohannes Doerfert return Plugin::success(); 304330d8983SJohannes Doerfert } 305330d8983SJohannes Doerfert Error destroyEventImpl(void *EventPtr) override { return Plugin::success(); } 306330d8983SJohannes Doerfert Error recordEventImpl(void *EventPtr, 307330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) override { 308330d8983SJohannes Doerfert return Plugin::success(); 309330d8983SJohannes Doerfert } 310330d8983SJohannes Doerfert Error waitEventImpl(void *EventPtr, 311330d8983SJohannes Doerfert AsyncInfoWrapperTy &AsyncInfoWrapper) override { 312330d8983SJohannes Doerfert return Plugin::success(); 313330d8983SJohannes Doerfert } 314330d8983SJohannes Doerfert Error syncEventImpl(void *EventPtr) override { return Plugin::success(); } 315330d8983SJohannes Doerfert 316330d8983SJohannes Doerfert /// Print information about the device. 317330d8983SJohannes Doerfert Error obtainInfoImpl(InfoQueueTy &Info) override { 318330d8983SJohannes Doerfert Info.add("Device Type", "Generic-elf-64bit"); 319330d8983SJohannes Doerfert return Plugin::success(); 320330d8983SJohannes Doerfert } 321330d8983SJohannes Doerfert 322330d8983SJohannes Doerfert /// This plugin should not setup the device environment or memory pool. 323330d8983SJohannes Doerfert virtual bool shouldSetupDeviceEnvironment() const override { return false; }; 324330d8983SJohannes Doerfert virtual bool shouldSetupDeviceMemoryPool() const override { return false; }; 325330d8983SJohannes Doerfert 326330d8983SJohannes Doerfert /// Getters and setters for stack size and heap size not relevant. 327330d8983SJohannes Doerfert Error getDeviceStackSize(uint64_t &Value) override { 328330d8983SJohannes Doerfert Value = 0; 329330d8983SJohannes Doerfert return Plugin::success(); 330330d8983SJohannes Doerfert } 331330d8983SJohannes Doerfert Error setDeviceStackSize(uint64_t Value) override { 332330d8983SJohannes Doerfert return Plugin::success(); 333330d8983SJohannes Doerfert } 334330d8983SJohannes Doerfert Error getDeviceHeapSize(uint64_t &Value) override { 335330d8983SJohannes Doerfert Value = 0; 336330d8983SJohannes Doerfert return Plugin::success(); 337330d8983SJohannes Doerfert } 338330d8983SJohannes Doerfert Error setDeviceHeapSize(uint64_t Value) override { return Plugin::success(); } 339330d8983SJohannes Doerfert 340330d8983SJohannes Doerfert private: 341330d8983SJohannes Doerfert /// Grid values for Generic ELF64 plugins. 342330d8983SJohannes Doerfert static constexpr GV GenELF64GridValues = { 343330d8983SJohannes Doerfert 1, // GV_Slot_Size 344330d8983SJohannes Doerfert 1, // GV_Warp_Size 345330d8983SJohannes Doerfert 1, // GV_Max_Teams 346330d8983SJohannes Doerfert 1, // GV_Default_Num_Teams 347330d8983SJohannes Doerfert 1, // GV_SimpleBufferSize 348330d8983SJohannes Doerfert 1, // GV_Max_WG_Size 349330d8983SJohannes Doerfert 1, // GV_Default_WG_Size 350330d8983SJohannes Doerfert }; 351330d8983SJohannes Doerfert }; 352330d8983SJohannes Doerfert 353330d8983SJohannes Doerfert class GenELF64GlobalHandlerTy final : public GenericGlobalHandlerTy { 354330d8983SJohannes Doerfert public: 355330d8983SJohannes Doerfert Error getGlobalMetadataFromDevice(GenericDeviceTy &GenericDevice, 356330d8983SJohannes Doerfert DeviceImageTy &Image, 357330d8983SJohannes Doerfert GlobalTy &DeviceGlobal) override { 358330d8983SJohannes Doerfert const char *GlobalName = DeviceGlobal.getName().data(); 359330d8983SJohannes Doerfert GenELF64DeviceImageTy &GenELF64Image = 360330d8983SJohannes Doerfert static_cast<GenELF64DeviceImageTy &>(Image); 361330d8983SJohannes Doerfert 362330d8983SJohannes Doerfert // Get dynamic library that has loaded the device image. 363330d8983SJohannes Doerfert DynamicLibrary &DynLib = GenELF64Image.getDynamicLibrary(); 364330d8983SJohannes Doerfert 365330d8983SJohannes Doerfert // Get the address of the symbol. 366330d8983SJohannes Doerfert void *Addr = DynLib.getAddressOfSymbol(GlobalName); 367330d8983SJohannes Doerfert if (Addr == nullptr) { 368330d8983SJohannes Doerfert return Plugin::error("Failed to load global '%s'", GlobalName); 369330d8983SJohannes Doerfert } 370330d8983SJohannes Doerfert 371330d8983SJohannes Doerfert // Save the pointer to the symbol. 372330d8983SJohannes Doerfert DeviceGlobal.setPtr(Addr); 373330d8983SJohannes Doerfert 374330d8983SJohannes Doerfert return Plugin::success(); 375330d8983SJohannes Doerfert } 376330d8983SJohannes Doerfert }; 377330d8983SJohannes Doerfert 378330d8983SJohannes Doerfert /// Class implementing the plugin functionalities for GenELF64. 379330d8983SJohannes Doerfert struct GenELF64PluginTy final : public GenericPluginTy { 380330d8983SJohannes Doerfert /// Create the GenELF64 plugin. 381330d8983SJohannes Doerfert GenELF64PluginTy() : GenericPluginTy(getTripleArch()) {} 382330d8983SJohannes Doerfert 383330d8983SJohannes Doerfert /// This class should not be copied. 384330d8983SJohannes Doerfert GenELF64PluginTy(const GenELF64PluginTy &) = delete; 385330d8983SJohannes Doerfert GenELF64PluginTy(GenELF64PluginTy &&) = delete; 386330d8983SJohannes Doerfert 387330d8983SJohannes Doerfert /// Initialize the plugin and return the number of devices. 388330d8983SJohannes Doerfert Expected<int32_t> initImpl() override { 389330d8983SJohannes Doerfert #ifdef USES_DYNAMIC_FFI 390330d8983SJohannes Doerfert if (auto Err = Plugin::check(ffi_init(), "Failed to initialize libffi")) 391330d8983SJohannes Doerfert return std::move(Err); 392330d8983SJohannes Doerfert #endif 393330d8983SJohannes Doerfert 394330d8983SJohannes Doerfert return NUM_DEVICES; 395330d8983SJohannes Doerfert } 396330d8983SJohannes Doerfert 397330d8983SJohannes Doerfert /// Deinitialize the plugin. 398330d8983SJohannes Doerfert Error deinitImpl() override { return Plugin::success(); } 399330d8983SJohannes Doerfert 400330d8983SJohannes Doerfert /// Creates a generic ELF device. 401330d8983SJohannes Doerfert GenericDeviceTy *createDevice(GenericPluginTy &Plugin, int32_t DeviceId, 402330d8983SJohannes Doerfert int32_t NumDevices) override { 403330d8983SJohannes Doerfert return new GenELF64DeviceTy(Plugin, DeviceId, NumDevices); 404330d8983SJohannes Doerfert } 405330d8983SJohannes Doerfert 406330d8983SJohannes Doerfert /// Creates a generic global handler. 407330d8983SJohannes Doerfert GenericGlobalHandlerTy *createGlobalHandler() override { 408330d8983SJohannes Doerfert return new GenELF64GlobalHandlerTy(); 409330d8983SJohannes Doerfert } 410330d8983SJohannes Doerfert 411330d8983SJohannes Doerfert /// Get the ELF code to recognize the compatible binary images. 412e3938f4dSJoseph Huber uint16_t getMagicElfBits() const override { 413e3938f4dSJoseph Huber return utils::elf::getTargetMachine(); 414e3938f4dSJoseph Huber } 415330d8983SJohannes Doerfert 416330d8983SJohannes Doerfert /// This plugin does not support exchanging data between two devices. 417330d8983SJohannes Doerfert bool isDataExchangable(int32_t SrcDeviceId, int32_t DstDeviceId) override { 418330d8983SJohannes Doerfert return false; 419330d8983SJohannes Doerfert } 420330d8983SJohannes Doerfert 421330d8983SJohannes Doerfert /// All images (ELF-compatible) should be compatible with this plugin. 422435aa766SJoseph Huber Expected<bool> isELFCompatible(uint32_t, StringRef) const override { 423435aa766SJoseph Huber return true; 424435aa766SJoseph Huber } 425330d8983SJohannes Doerfert 426330d8983SJohannes Doerfert Triple::ArchType getTripleArch() const override { 4273e54768dSJoseph Huber #if defined(__x86_64__) 4283e54768dSJoseph Huber return llvm::Triple::x86_64; 4293e54768dSJoseph Huber #elif defined(__s390x__) 4303e54768dSJoseph Huber return llvm::Triple::systemz; 4313e54768dSJoseph Huber #elif defined(__aarch64__) 4323e54768dSJoseph Huber #ifdef LITTLEENDIAN_CPU 433e9be1292STulio Magno Quites Machado Filho return llvm::Triple::aarch64; 4343e54768dSJoseph Huber #else 4353e54768dSJoseph Huber return llvm::Triple::aarch64_be; 4363e54768dSJoseph Huber #endif 4373e54768dSJoseph Huber #elif defined(__powerpc64__) 4383e54768dSJoseph Huber #ifdef LITTLEENDIAN_CPU 4393e54768dSJoseph Huber return llvm::Triple::ppc64le; 4403e54768dSJoseph Huber #else 4413e54768dSJoseph Huber return llvm::Triple::ppc64; 4423e54768dSJoseph Huber #endif 443b6bd7477Saurel32 #elif defined(__riscv) && (__riscv_xlen == 64) 444b6bd7477Saurel32 return llvm::Triple::riscv64; 445*bdf72706Swanglei #elif defined(__loongarch__) && (__loongarch_grlen == 64) 446*bdf72706Swanglei return llvm::Triple::loongarch64; 4473e54768dSJoseph Huber #else 4483e54768dSJoseph Huber return llvm::Triple::UnknownArch; 4493e54768dSJoseph Huber #endif 450330d8983SJohannes Doerfert } 451330d8983SJohannes Doerfert 452fa9e90f5SJoseph Huber const char *getName() const override { return GETNAME(TARGET_NAME); } 453fa9e90f5SJoseph Huber }; 454e5e66073SJoseph Huber 455330d8983SJohannes Doerfert template <typename... ArgsTy> 456330d8983SJohannes Doerfert static Error Plugin::check(int32_t Code, const char *ErrMsg, ArgsTy... Args) { 457330d8983SJohannes Doerfert if (Code == 0) 458330d8983SJohannes Doerfert return Error::success(); 459330d8983SJohannes Doerfert 460330d8983SJohannes Doerfert return createStringError<ArgsTy..., const char *>( 461330d8983SJohannes Doerfert inconvertibleErrorCode(), ErrMsg, Args..., std::to_string(Code).data()); 462330d8983SJohannes Doerfert } 463330d8983SJohannes Doerfert 464330d8983SJohannes Doerfert } // namespace plugin 465330d8983SJohannes Doerfert } // namespace target 466330d8983SJohannes Doerfert } // namespace omp 467330d8983SJohannes Doerfert } // namespace llvm 468fa9e90f5SJoseph Huber 469fa9e90f5SJoseph Huber extern "C" { 470fa9e90f5SJoseph Huber llvm::omp::target::plugin::GenericPluginTy *createPlugin_host() { 471fa9e90f5SJoseph Huber return new llvm::omp::target::plugin::GenELF64PluginTy(); 472fa9e90f5SJoseph Huber } 473fa9e90f5SJoseph Huber } 474