xref: /llvm-project/offload/plugins-nextgen/host/src/rtl.cpp (revision bdf727065b581c45b68a81090272f497f1ce5485)
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