summaryrefslogtreecommitdiff
path: root/offload/plugins-nextgen/host/src/rtl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'offload/plugins-nextgen/host/src/rtl.cpp')
-rw-r--r--offload/plugins-nextgen/host/src/rtl.cpp442
1 files changed, 442 insertions, 0 deletions
diff --git a/offload/plugins-nextgen/host/src/rtl.cpp b/offload/plugins-nextgen/host/src/rtl.cpp
new file mode 100644
index 000000000000..f0ce24249301
--- /dev/null
+++ b/offload/plugins-nextgen/host/src/rtl.cpp
@@ -0,0 +1,442 @@
+//===-RTLs/generic-64bit/src/rtl.cpp - Target RTLs Implementation - 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
+//
+//===----------------------------------------------------------------------===//
+//
+// RTL NextGen for generic 64-bit machine
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstddef>
+#include <ffi.h>
+#include <string>
+#include <unordered_map>
+
+#include "Shared/Debug.h"
+#include "Shared/Environment.h"
+
+#include "GlobalHandler.h"
+#include "OpenMP/OMPT/Callback.h"
+#include "PluginInterface.h"
+#include "omptarget.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/Frontend/OpenMP/OMPDeviceConstants.h"
+#include "llvm/Frontend/OpenMP/OMPGridValues.h"
+#include "llvm/Support/DynamicLibrary.h"
+
+// The number of devices in this plugin.
+#define NUM_DEVICES 4
+
+// The ELF ID should be defined at compile-time by the build system.
+#ifndef TARGET_ELF_ID
+#define TARGET_ELF_ID EM_NONE
+#endif
+
+// The target triple should be defined at compile-time by the build system.
+#ifndef LIBOMPTARGET_NEXTGEN_GENERIC_PLUGIN_TRIPLE
+#define LIBOMPTARGET_NEXTGEN_GENERIC_PLUGIN_TRIPLE ""
+#endif
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace plugin {
+
+/// Forward declarations for all specialized data structures.
+struct GenELF64KernelTy;
+struct GenELF64DeviceTy;
+struct GenELF64PluginTy;
+
+using llvm::sys::DynamicLibrary;
+
+/// Class implementing kernel functionalities for GenELF64.
+struct GenELF64KernelTy : public GenericKernelTy {
+ /// Construct the kernel with a name and an execution mode.
+ GenELF64KernelTy(const char *Name) : GenericKernelTy(Name), Func(nullptr) {}
+
+ /// Initialize the kernel.
+ Error initImpl(GenericDeviceTy &Device, DeviceImageTy &Image) override {
+ // Functions have zero size.
+ GlobalTy Global(getName(), 0);
+
+ // Get the metadata (address) of the kernel function.
+ GenericGlobalHandlerTy &GHandler = Device.Plugin.getGlobalHandler();
+ if (auto Err = GHandler.getGlobalMetadataFromDevice(Device, Image, Global))
+ return Err;
+
+ // Check that the function pointer is valid.
+ if (!Global.getPtr())
+ return Plugin::error("Invalid function for kernel %s", getName());
+
+ // Save the function pointer.
+ Func = (void (*)())Global.getPtr();
+
+ KernelEnvironment.Configuration.ExecMode = OMP_TGT_EXEC_MODE_GENERIC;
+ KernelEnvironment.Configuration.MayUseNestedParallelism = /*Unknown=*/2;
+ KernelEnvironment.Configuration.UseGenericStateMachine = /*Unknown=*/2;
+
+ // Set the maximum number of threads to a single.
+ MaxNumThreads = 1;
+ return Plugin::success();
+ }
+
+ /// Launch the kernel using the libffi.
+ Error launchImpl(GenericDeviceTy &GenericDevice, uint32_t NumThreads,
+ uint64_t NumBlocks, KernelArgsTy &KernelArgs, void *Args,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) const override {
+ // Create a vector of ffi_types, one per argument.
+ SmallVector<ffi_type *, 16> ArgTypes(KernelArgs.NumArgs, &ffi_type_pointer);
+ ffi_type **ArgTypesPtr = (ArgTypes.size()) ? &ArgTypes[0] : nullptr;
+
+ // Prepare the cif structure before running the kernel function.
+ ffi_cif Cif;
+ ffi_status Status = ffi_prep_cif(&Cif, FFI_DEFAULT_ABI, KernelArgs.NumArgs,
+ &ffi_type_void, ArgTypesPtr);
+ if (Status != FFI_OK)
+ return Plugin::error("Error in ffi_prep_cif: %d", Status);
+
+ // Call the kernel function through libffi.
+ long Return;
+ ffi_call(&Cif, Func, &Return, (void **)Args);
+
+ return Plugin::success();
+ }
+
+private:
+ /// The kernel function to execute.
+ void (*Func)(void);
+};
+
+/// Class implementing the GenELF64 device images properties.
+struct GenELF64DeviceImageTy : public DeviceImageTy {
+ /// Create the GenELF64 image with the id and the target image pointer.
+ GenELF64DeviceImageTy(int32_t ImageId, GenericDeviceTy &Device,
+ const __tgt_device_image *TgtImage)
+ : DeviceImageTy(ImageId, Device, TgtImage), DynLib() {}
+
+ /// Getter and setter for the dynamic library.
+ DynamicLibrary &getDynamicLibrary() { return DynLib; }
+ void setDynamicLibrary(const DynamicLibrary &Lib) { DynLib = Lib; }
+
+private:
+ /// The dynamic library that loaded the image.
+ DynamicLibrary DynLib;
+};
+
+/// Class implementing the device functionalities for GenELF64.
+struct GenELF64DeviceTy : public GenericDeviceTy {
+ /// Create the device with a specific id.
+ GenELF64DeviceTy(GenericPluginTy &Plugin, int32_t DeviceId,
+ int32_t NumDevices)
+ : GenericDeviceTy(Plugin, DeviceId, NumDevices, GenELF64GridValues) {}
+
+ ~GenELF64DeviceTy() {}
+
+ /// Initialize the device, which is a no-op
+ Error initImpl(GenericPluginTy &Plugin) override { return Plugin::success(); }
+
+ /// Deinitialize the device, which is a no-op
+ Error deinitImpl() override { return Plugin::success(); }
+
+ /// See GenericDeviceTy::getComputeUnitKind().
+ std::string getComputeUnitKind() const override { return "generic-64bit"; }
+
+ /// Construct the kernel for a specific image on the device.
+ Expected<GenericKernelTy &> constructKernel(const char *Name) override {
+ // Allocate and construct the kernel.
+ GenELF64KernelTy *GenELF64Kernel = Plugin.allocate<GenELF64KernelTy>();
+ if (!GenELF64Kernel)
+ return Plugin::error("Failed to allocate memory for GenELF64 kernel");
+
+ new (GenELF64Kernel) GenELF64KernelTy(Name);
+
+ return *GenELF64Kernel;
+ }
+
+ /// Set the current context to this device, which is a no-op.
+ Error setContext() override { return Plugin::success(); }
+
+ /// Load the binary image into the device and allocate an image object.
+ Expected<DeviceImageTy *> loadBinaryImpl(const __tgt_device_image *TgtImage,
+ int32_t ImageId) override {
+ // Allocate and initialize the image object.
+ GenELF64DeviceImageTy *Image = Plugin.allocate<GenELF64DeviceImageTy>();
+ new (Image) GenELF64DeviceImageTy(ImageId, *this, TgtImage);
+
+ // Create a temporary file.
+ char TmpFileName[] = "/tmp/tmpfile_XXXXXX";
+ int TmpFileFd = mkstemp(TmpFileName);
+ if (TmpFileFd == -1)
+ return Plugin::error("Failed to create tmpfile for loading target image");
+
+ // Open the temporary file.
+ FILE *TmpFile = fdopen(TmpFileFd, "wb");
+ if (!TmpFile)
+ return Plugin::error("Failed to open tmpfile %s for loading target image",
+ TmpFileName);
+
+ // Write the image into the temporary file.
+ size_t Written = fwrite(Image->getStart(), Image->getSize(), 1, TmpFile);
+ if (Written != 1)
+ return Plugin::error("Failed to write target image to tmpfile %s",
+ TmpFileName);
+
+ // Close the temporary file.
+ int Ret = fclose(TmpFile);
+ if (Ret)
+ return Plugin::error("Failed to close tmpfile %s with the target image",
+ TmpFileName);
+
+ // Load the temporary file as a dynamic library.
+ std::string ErrMsg;
+ DynamicLibrary DynLib =
+ DynamicLibrary::getPermanentLibrary(TmpFileName, &ErrMsg);
+
+ // Check if the loaded library is valid.
+ if (!DynLib.isValid())
+ return Plugin::error("Failed to load target image: %s", ErrMsg.c_str());
+
+ // Save a reference of the image's dynamic library.
+ Image->setDynamicLibrary(DynLib);
+
+ return Image;
+ }
+
+ /// Allocate memory. Use std::malloc in all cases.
+ void *allocate(size_t Size, void *, TargetAllocTy Kind) override {
+ if (Size == 0)
+ return nullptr;
+
+ void *MemAlloc = nullptr;
+ switch (Kind) {
+ case TARGET_ALLOC_DEFAULT:
+ case TARGET_ALLOC_DEVICE:
+ case TARGET_ALLOC_HOST:
+ case TARGET_ALLOC_SHARED:
+ case TARGET_ALLOC_DEVICE_NON_BLOCKING:
+ MemAlloc = std::malloc(Size);
+ break;
+ }
+ return MemAlloc;
+ }
+
+ /// Free the memory. Use std::free in all cases.
+ int free(void *TgtPtr, TargetAllocTy Kind) override {
+ std::free(TgtPtr);
+ return OFFLOAD_SUCCESS;
+ }
+
+ /// This plugin does nothing to lock buffers. Do not return an error, just
+ /// return the same pointer as the device pointer.
+ Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) override {
+ return HstPtr;
+ }
+
+ /// Nothing to do when unlocking the buffer.
+ Error dataUnlockImpl(void *HstPtr) override { return Plugin::success(); }
+
+ /// Indicate that the buffer is not pinned.
+ Expected<bool> isPinnedPtrImpl(void *HstPtr, void *&BaseHstPtr,
+ void *&BaseDevAccessiblePtr,
+ size_t &BaseSize) const override {
+ return false;
+ }
+
+ /// Submit data to the device (host to device transfer).
+ Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ std::memcpy(TgtPtr, HstPtr, Size);
+ return Plugin::success();
+ }
+
+ /// Retrieve data from the device (device to host transfer).
+ Error dataRetrieveImpl(void *HstPtr, const void *TgtPtr, int64_t Size,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ std::memcpy(HstPtr, TgtPtr, Size);
+ return Plugin::success();
+ }
+
+ /// Exchange data between two devices within the plugin. This function is not
+ /// supported in this plugin.
+ Error dataExchangeImpl(const void *SrcPtr, GenericDeviceTy &DstGenericDevice,
+ void *DstPtr, int64_t Size,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ // This function should never be called because the function
+ // GenELF64PluginTy::isDataExchangable() returns false.
+ return Plugin::error("dataExchangeImpl not supported");
+ }
+
+ /// All functions are already synchronous. No need to do anything on this
+ /// synchronization function.
+ Error synchronizeImpl(__tgt_async_info &AsyncInfo) override {
+ return Plugin::success();
+ }
+
+ /// All functions are already synchronous. No need to do anything on this
+ /// query function.
+ Error queryAsyncImpl(__tgt_async_info &AsyncInfo) override {
+ return Plugin::success();
+ }
+
+ /// This plugin does not support interoperability
+ Error initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ return Plugin::error("initAsyncInfoImpl not supported");
+ }
+
+ /// This plugin does not support interoperability
+ Error initDeviceInfoImpl(__tgt_device_info *DeviceInfo) override {
+ return Plugin::error("initDeviceInfoImpl not supported");
+ }
+
+ /// This plugin does not support the event API. Do nothing without failing.
+ Error createEventImpl(void **EventPtrStorage) override {
+ *EventPtrStorage = nullptr;
+ return Plugin::success();
+ }
+ Error destroyEventImpl(void *EventPtr) override { return Plugin::success(); }
+ Error recordEventImpl(void *EventPtr,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ return Plugin::success();
+ }
+ Error waitEventImpl(void *EventPtr,
+ AsyncInfoWrapperTy &AsyncInfoWrapper) override {
+ return Plugin::success();
+ }
+ Error syncEventImpl(void *EventPtr) override { return Plugin::success(); }
+
+ /// Print information about the device.
+ Error obtainInfoImpl(InfoQueueTy &Info) override {
+ Info.add("Device Type", "Generic-elf-64bit");
+ return Plugin::success();
+ }
+
+ /// This plugin should not setup the device environment or memory pool.
+ virtual bool shouldSetupDeviceEnvironment() const override { return false; };
+ virtual bool shouldSetupDeviceMemoryPool() const override { return false; };
+
+ /// Getters and setters for stack size and heap size not relevant.
+ Error getDeviceStackSize(uint64_t &Value) override {
+ Value = 0;
+ return Plugin::success();
+ }
+ Error setDeviceStackSize(uint64_t Value) override {
+ return Plugin::success();
+ }
+ Error getDeviceHeapSize(uint64_t &Value) override {
+ Value = 0;
+ return Plugin::success();
+ }
+ Error setDeviceHeapSize(uint64_t Value) override { return Plugin::success(); }
+
+private:
+ /// Grid values for Generic ELF64 plugins.
+ static constexpr GV GenELF64GridValues = {
+ 1, // GV_Slot_Size
+ 1, // GV_Warp_Size
+ 1, // GV_Max_Teams
+ 1, // GV_Default_Num_Teams
+ 1, // GV_SimpleBufferSize
+ 1, // GV_Max_WG_Size
+ 1, // GV_Default_WG_Size
+ };
+};
+
+class GenELF64GlobalHandlerTy final : public GenericGlobalHandlerTy {
+public:
+ Error getGlobalMetadataFromDevice(GenericDeviceTy &GenericDevice,
+ DeviceImageTy &Image,
+ GlobalTy &DeviceGlobal) override {
+ const char *GlobalName = DeviceGlobal.getName().data();
+ GenELF64DeviceImageTy &GenELF64Image =
+ static_cast<GenELF64DeviceImageTy &>(Image);
+
+ // Get dynamic library that has loaded the device image.
+ DynamicLibrary &DynLib = GenELF64Image.getDynamicLibrary();
+
+ // Get the address of the symbol.
+ void *Addr = DynLib.getAddressOfSymbol(GlobalName);
+ if (Addr == nullptr) {
+ return Plugin::error("Failed to load global '%s'", GlobalName);
+ }
+
+ // Save the pointer to the symbol.
+ DeviceGlobal.setPtr(Addr);
+
+ return Plugin::success();
+ }
+};
+
+/// Class implementing the plugin functionalities for GenELF64.
+struct GenELF64PluginTy final : public GenericPluginTy {
+ /// Create the GenELF64 plugin.
+ GenELF64PluginTy() : GenericPluginTy(getTripleArch()) {}
+
+ /// This class should not be copied.
+ GenELF64PluginTy(const GenELF64PluginTy &) = delete;
+ GenELF64PluginTy(GenELF64PluginTy &&) = delete;
+
+ /// Initialize the plugin and return the number of devices.
+ Expected<int32_t> initImpl() override {
+#ifdef OMPT_SUPPORT
+ ompt::connectLibrary();
+#endif
+
+#ifdef USES_DYNAMIC_FFI
+ if (auto Err = Plugin::check(ffi_init(), "Failed to initialize libffi"))
+ return std::move(Err);
+#endif
+
+ return NUM_DEVICES;
+ }
+
+ /// Deinitialize the plugin.
+ Error deinitImpl() override { return Plugin::success(); }
+
+ /// Creates a generic ELF device.
+ GenericDeviceTy *createDevice(GenericPluginTy &Plugin, int32_t DeviceId,
+ int32_t NumDevices) override {
+ return new GenELF64DeviceTy(Plugin, DeviceId, NumDevices);
+ }
+
+ /// Creates a generic global handler.
+ GenericGlobalHandlerTy *createGlobalHandler() override {
+ return new GenELF64GlobalHandlerTy();
+ }
+
+ /// Get the ELF code to recognize the compatible binary images.
+ uint16_t getMagicElfBits() const override { return ELF::TARGET_ELF_ID; }
+
+ /// This plugin does not support exchanging data between two devices.
+ bool isDataExchangable(int32_t SrcDeviceId, int32_t DstDeviceId) override {
+ return false;
+ }
+
+ /// All images (ELF-compatible) should be compatible with this plugin.
+ Expected<bool> isELFCompatible(StringRef) const override { return true; }
+
+ Triple::ArchType getTripleArch() const override {
+ return llvm::Triple(LIBOMPTARGET_NEXTGEN_GENERIC_PLUGIN_TRIPLE).getArch();
+ }
+};
+
+GenericPluginTy *PluginTy::createPlugin() { return new GenELF64PluginTy(); }
+
+template <typename... ArgsTy>
+static Error Plugin::check(int32_t Code, const char *ErrMsg, ArgsTy... Args) {
+ if (Code == 0)
+ return Error::success();
+
+ return createStringError<ArgsTy..., const char *>(
+ inconvertibleErrorCode(), ErrMsg, Args..., std::to_string(Code).data());
+}
+
+} // namespace plugin
+} // namespace target
+} // namespace omp
+} // namespace llvm