Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
##===----------------------------------------------------------------------===##
#
# 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
#
##===----------------------------------------------------------------------===##
#
# Common parts which can be used by all plugins
#
##===----------------------------------------------------------------------===##

# Plugin Interface library.
add_library(PluginInterface OBJECT PluginInterface.cpp GlobalHandler.cpp)

# Define the TARGET_NAME.
add_definitions("-DTARGET_NAME=PluginInterface")

# Define the DEBUG_PREFIX.
add_definitions(-DDEBUG_PREFIX="PluginInterface")

set_property(TARGET PluginInterface PROPERTY POSITION_INDEPENDENT_CODE ON)
llvm_update_compile_flags(PluginInterface)
set(LINK_LLVM_LIBS LLVMSupport)
if (LLVM_LINK_LLVM_DYLIB)
set(LINK_LLVM_LIBS LLVM)
endif()
target_link_libraries(PluginInterface INTERFACE ${LINK_LLVM_LIBS} PRIVATE elf_common MemoryManager)
add_dependencies(PluginInterface ${LINK_LLVM_LIBS})

target_include_directories(PluginInterface INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(PluginInterface PRIVATE ${LIBOMPTARGET_INCLUDE_DIR})
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//===- GlobalHandler.cpp - Target independent global & env. var handling --===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Target independent global handler and environment manager.
//
//===----------------------------------------------------------------------===//

#include "GlobalHandler.h"
#include "ELFSymbols.h"
#include "PluginInterface.h"

#include <cstring>

using namespace llvm;
using namespace omp;
using namespace target;
using namespace plugin;

const ELF64LEObjectFile *
GenericGlobalHandlerTy::getOrCreateELFObjectFile(const GenericDeviceTy &Device,
DeviceImageTy &Image) {

auto Search = ELFObjectFiles.find(Image.getId());
if (Search != ELFObjectFiles.end())
// The ELF object file was already there.
return &Search->second;

// The ELF object file we are checking is not created yet.
Expected<ELF64LEObjectFile> ElfOrErr =
ELF64LEObjectFile::create(Image.getMemoryBuffer());
if (!ElfOrErr) {
consumeError(ElfOrErr.takeError());
return nullptr;
}

auto Result =
ELFObjectFiles.try_emplace(Image.getId(), std::move(ElfOrErr.get()));
assert(Result.second && "Map insertion failed");
assert(Result.first != ELFObjectFiles.end() && "Map insertion failed");

return &Result.first->second;
}

Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal,
bool Device2Host) {

GlobalTy DeviceGlobal(HostGlobal.getName(), HostGlobal.getSize());

// Get the metadata from the global on the device.
if (auto Err = getGlobalMetadataFromDevice(Device, Image, DeviceGlobal))
return Err;

// Perform the actual transfer.
return moveGlobalBetweenDeviceAndHost(Device, Image, HostGlobal, DeviceGlobal,
Device2Host);
}

/// Actually move memory between host and device. See readGlobalFromDevice and
/// writeGlobalToDevice for the interface description.
Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
GenericDeviceTy &Device, DeviceImageTy &DeviceImage,
const GlobalTy &HostGlobal, const GlobalTy &DeviceGlobal,
bool Device2Host) {

// Transfer the data from the source to the destination.
if (Device2Host) {
if (auto Err =
Device.dataRetrieve(HostGlobal.getPtr(), DeviceGlobal.getPtr(),
HostGlobal.getSize(), nullptr))
return Err;
} else {
if (auto Err = Device.dataSubmit(DeviceGlobal.getPtr(), HostGlobal.getPtr(),
HostGlobal.getSize(), nullptr))
return Err;
}

DP("Succesfully %s %u bytes associated with global symbol '%s' %s the device "
"(%p -> %p).\n",
Device2Host ? "read" : "write", HostGlobal.getSize(),
HostGlobal.getName().data(), Device2Host ? "from" : "to",
DeviceGlobal.getPtr(), HostGlobal.getPtr());

return Plugin::success();
}

Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) {

// Get the ELF object file for the image. Notice the ELF object may already
// be created in previous calls, so we can reuse it.
const ELF64LEObjectFile *ELFObj = getOrCreateELFObjectFile(Device, Image);
if (!ELFObj)
return Plugin::error("Unable to create ELF object for image %p",
Image.getStart());

// Search the ELF symbol using the the symbol name.
auto SymOrErr = getELFSymbol(*ELFObj, ImageGlobal.getName());
if (!SymOrErr)
return Plugin::error("Failed ELF lookup of global '%s': %s",
ImageGlobal.getName().data(),
toString(SymOrErr.takeError()).data());

if (!*SymOrErr)
return Plugin::error("Failed to find global symbol '%s' in the ELF image",
ImageGlobal.getName().data());

// Get the section to which the symbol belongs.
auto SymSecOrErr = ELFObj->getELFFile().getSection((*SymOrErr)->st_shndx);
if (!SymSecOrErr)
return Plugin::error("Failed to get ELF section from global '%s': %s",
ImageGlobal.getName().data(),
toString(SymOrErr.takeError()).data());

// Save the global symbol's address and size. The address of the global is the
// image base address + the section offset + the symbol value.
ImageGlobal.setPtr((char *)Image.getStart() + (*SymSecOrErr)->sh_offset +
(*SymOrErr)->st_value);
ImageGlobal.setSize((*SymOrErr)->st_size);

return Plugin::success();
}

Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device,
DeviceImageTy &Image,
const GlobalTy &HostGlobal) {

GlobalTy ImageGlobal(HostGlobal.getName(), -1);
if (auto Err = getGlobalMetadataFromImage(Device, Image, ImageGlobal))
return Err;

if (ImageGlobal.getSize() != HostGlobal.getSize())
return Plugin::error("Transfer failed because global symbol '%s' has "
"%u bytes in the ELF image but %u bytes on the host",
HostGlobal.getName().data(), ImageGlobal.getSize(),
HostGlobal.getSize());

DP("Global symbol '%s' was found in the ELF image and %u bytes will copied "
"from %p to %p.\n",
HostGlobal.getName().data(), HostGlobal.getSize(), ImageGlobal.getPtr(),
HostGlobal.getPtr());

// Perform the copy from the image to the host memory.
std::memcpy(HostGlobal.getPtr(), ImageGlobal.getPtr(), HostGlobal.getSize());

return Plugin::success();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
//===- GlobalHandler.h - Target independent global & enviroment handling --===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Target independent global handler and environment manager.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_GLOBALHANDLER_H
#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_GLOBALHANDLER_H

#include <string>

#include "llvm/ADT/DenseMap.h"
#include "llvm/Object/ELFObjectFile.h"

#include "Debug.h"
#include "Utilities.h"
#include "omptarget.h"

namespace llvm {
namespace omp {
namespace target {
namespace plugin {

struct DeviceImageTy;
struct GenericDeviceTy;

using namespace llvm::object;

/// Common abstraction for globals that live on the host and device.
/// It simply encapsulates the symbol name, symbol size, and symbol address
/// (which might be host or device depending on the context).
class GlobalTy {
// NOTE: Maybe we can have a pointer to the offload entry name instead of
// holding a private copy of the name as a std::string.
std::string Name;
uint32_t Size;
void *Ptr;

public:
GlobalTy(const std::string &Name, uint32_t Size, void *Ptr = nullptr)
: Name(Name), Size(Size), Ptr(Ptr) {}

GlobalTy(const __tgt_offload_entry &Entry)
: Name(Entry.name), Size(Entry.size), Ptr(Entry.addr) {}

const std::string &getName() const { return Name; }
uint32_t getSize() const { return Size; }
void *getPtr() const { return Ptr; }

void setSize(int32_t S) { Size = S; }
void setPtr(void *P) { Ptr = P; }
};

/// Subclass of GlobalTy that holds the memory for a global of \p Ty.
template <typename Ty> class StaticGlobalTy : public GlobalTy {
Ty Data;

public:
template <typename... Args>
StaticGlobalTy(const std::string &Name, Args &&...args)
: GlobalTy(Name, sizeof(Ty), &Data),
Data(Ty{std::forward<Args>(args)...}) {}

template <typename... Args>
StaticGlobalTy(const char *Name, Args &&...args)
: GlobalTy(Name, sizeof(Ty), &Data),
Data(Ty{std::forward<Args>(args)...}) {}

template <typename... Args>
StaticGlobalTy(const char *Name, const char *Suffix, Args &&...args)
: GlobalTy(std::string(Name) + Suffix, sizeof(Ty), &Data),
Data(Ty{std::forward<Args>(args)...}) {}

Ty &getValue() { return Data; }
const Ty &getValue() const { return Data; }
void setValue(const Ty &V) { Data = V; }
};

/// Helper class to do the heavy lifting when it comes to moving globals between
/// host and device. Through the GenericDeviceTy we access memcpy DtoH and HtoD,
/// which means the only things specialized by the subclass is the retrival of
/// global metadata (size, addr) from the device.
/// \see getGlobalMetadataFromDevice
class GenericGlobalHandlerTy {
/// Map to store the ELF object files that have been loaded.
llvm::DenseMap<int32_t, ELF64LEObjectFile> ELFObjectFiles;

/// Get the cached ELF64LEObjectFile previosuly created for a specific
/// device image or create it if did not exist.
const ELF64LEObjectFile *
getOrCreateELFObjectFile(const GenericDeviceTy &Device, DeviceImageTy &Image);

/// Actually move memory between host and device. See readGlobalFromDevice and
/// writeGlobalToDevice for the interface description.
Error moveGlobalBetweenDeviceAndHost(GenericDeviceTy &Device,
DeviceImageTy &Image,
const GlobalTy &HostGlobal,
bool Device2Host);

/// Actually move memory between host and device. See readGlobalFromDevice and
/// writeGlobalToDevice for the interface description.
Error moveGlobalBetweenDeviceAndHost(GenericDeviceTy &Device,
DeviceImageTy &Image,
const GlobalTy &HostGlobal,
const GlobalTy &DeviceGlobal,
bool Device2Host);

public:
virtual ~GenericGlobalHandlerTy() {}

/// Get the address and size of a global in the image. Address and size are
/// return in \p ImageGlobal, the global name is passed in \p ImageGlobal.
Error getGlobalMetadataFromImage(GenericDeviceTy &Device,
DeviceImageTy &Image, GlobalTy &ImageGlobal);

/// Read the memory associated with a global from the image and store it on
/// the host. The name, size, and destination are defined by \p HostGlobal.
Error readGlobalFromImage(GenericDeviceTy &Device, DeviceImageTy &Image,
const GlobalTy &HostGlobal);

/// Get the address and size of a global from the device. Address is return in
/// \p DeviceGlobal, the global name and expected size are passed in
/// \p DeviceGlobal.
virtual Error getGlobalMetadataFromDevice(GenericDeviceTy &Device,
DeviceImageTy &Image,
GlobalTy &DeviceGlobal) = 0;

/// Copy the memory associated with a global from the device to its
/// counterpart on the host. The name, size, and destination are defined by
/// \p HostGlobal. The origin is defined by \p DeviceGlobal.
Error readGlobalFromDevice(GenericDeviceTy &Device, DeviceImageTy &Image,
const GlobalTy &HostGlobal,
const GlobalTy &DeviceGlobal) {
return moveGlobalBetweenDeviceAndHost(Device, Image, HostGlobal,
DeviceGlobal,
/* D2H */ true);
}

/// Copy the memory associated with a global from the device to its
/// counterpart on the host. The name, size, and destination are defined by
/// \p HostGlobal. The origin is automatically resolved.
Error readGlobalFromDevice(GenericDeviceTy &Device, DeviceImageTy &Image,
const GlobalTy &HostGlobal) {
return moveGlobalBetweenDeviceAndHost(Device, Image, HostGlobal,
/* D2H */ true);
}

/// Copy the memory associated with a global from the host to its counterpart
/// on the device. The name, size, and origin are defined by \p HostGlobal.
/// The destination is defined by \p DeviceGlobal.
Error writeGlobalToDevice(GenericDeviceTy &Device, DeviceImageTy &Image,
const GlobalTy &HostGlobal,
const GlobalTy &DeviceGlobal) {
return moveGlobalBetweenDeviceAndHost(Device, Image, HostGlobal,
DeviceGlobal,
/* D2H */ false);
}

/// Copy the memory associated with a global from the host to its counterpart
/// on the device. The name, size, and origin are defined by \p HostGlobal.
/// The destination is automatically resolved.
Error writeGlobalToDevice(GenericDeviceTy &Device, DeviceImageTy &Image,
const GlobalTy &HostGlobal) {
return moveGlobalBetweenDeviceAndHost(Device, Image, HostGlobal,
/* D2H */ false);
}
};

} // namespace plugin
} // namespace target
} // namespace omp
} // namespace llvm

#endif // LLVM_OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_GLOBALHANDLER_H

Large diffs are not rendered by default.

Large diffs are not rendered by default.

98 changes: 98 additions & 0 deletions openmp/libomptarget/plugins-nextgen/cuda/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
##===----------------------------------------------------------------------===##
#
# 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
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a CUDA machine if available.
#
##===----------------------------------------------------------------------===##
set(LIBOMPTARGET_BUILD_CUDA_PLUGIN TRUE CACHE BOOL
"Whether to build CUDA plugin")
if (NOT LIBOMPTARGET_BUILD_CUDA_PLUGIN)
libomptarget_say("Not building CUDA NextGen offloading plugin: LIBOMPTARGET_BUILD_CUDA_PLUGIN is false")
return()
endif()

if (NOT(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(ppc64le)|(aarch64)$" AND CMAKE_SYSTEM_NAME MATCHES "Linux"))
libomptarget_say("Not building CUDA NextGen offloading plugin: only support CUDA in Linux x86_64, ppc64le, or aarch64 hosts.")
return()
endif()

libomptarget_say("Building CUDA NextGen offloading plugin.")

# Define the suffix for the runtime messaging dumps.
add_definitions("-DTARGET_NAME=CUDA")

# Define debug prefix. TODO: This should be automatized in the Debug.h but it
# requires changing the original plugins.
add_definitions(-DDEBUG_PREFIX="TARGET CUDA RTL")

set(LIBOMPTARGET_DLOPEN_LIBCUDA OFF)
option(LIBOMPTARGET_FORCE_DLOPEN_LIBCUDA "Build with dlopened libcuda" ${LIBOMPTARGET_DLOPEN_LIBCUDA})

set(LIBOMPTARGET_CAN_LINK_LIBCUDA FALSE)
if (LIBOMPTARGET_DEP_CUDA_FOUND AND LIBOMPTARGET_DEP_CUDA_DRIVER_FOUND)
set(LIBOMPTARGET_CAN_LINK_LIBCUDA TRUE)
endif()

if (LIBOMPTARGET_CAN_LINK_LIBCUDA AND NOT LIBOMPTARGET_FORCE_DLOPEN_LIBCUDA)
libomptarget_say("Building CUDA NextGen plugin linked against libcuda")
include_directories(${LIBOMPTARGET_DEP_CUDA_INCLUDE_DIRS})
add_llvm_library(omptarget.rtl.cuda.nextgen SHARED

src/rtl.cpp

ADDITIONAL_HEADER_DIRS
${LIBOMPTARGET_INCLUDE_DIR}

LINK_LIBS
PRIVATE
elf_common
MemoryManager
PluginInterface
${LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
"-Wl,-z,defs"

NO_INSTALL_RPATH
)
else()
libomptarget_say("Building CUDA NextGen plugin for dlopened libcuda")
include_directories(../../plugins/cuda/dynamic_cuda)
add_llvm_library(omptarget.rtl.cuda.nextgen
SHARED

src/rtl.cpp
../../plugins/cuda/dynamic_cuda/cuda.cpp

ADDITIONAL_HEADER_DIRS
${LIBOMPTARGET_INCLUDE_DIR}

LINK_LIBS
PRIVATE
elf_common
MemoryManager
PluginInterface
${CMAKE_DL_LIBS}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
"-Wl,-z,defs"

NO_INSTALL_RPATH
)
endif()
add_dependencies(omptarget.rtl.cuda.nextgen omptarget.devicertl.nvptx)

# Install plugin under the lib destination folder.
install(TARGETS omptarget.rtl.cuda.nextgen LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
set_target_properties(omptarget.rtl.cuda.nextgen PROPERTIES
INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/.."
CXX_VISIBILITY_PRESET protected)

target_include_directories(omptarget.rtl.cuda.nextgen PRIVATE
${LIBOMPTARGET_INCLUDE_DIR}
)
1,051 changes: 1,051 additions & 0 deletions openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions openmp/libomptarget/plugins-nextgen/exports
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
VERS1.0 {
global:
__tgt_rtl*;
local:
*;
};
401 changes: 401 additions & 0 deletions openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions openmp/libomptarget/plugins-nextgen/ppc64/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
##===----------------------------------------------------------------------===##
#
# 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
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a ppc64 machine if available.
#
##===----------------------------------------------------------------------===##

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64_nextgen("ppc64" "PPC64" "ppc64" "powerpc64-ibm-linux-gnu" "21")
else()
libomptarget_say("Not building ppc64 NextGen offloading plugin: machine not found in the system.")
endif()
17 changes: 17 additions & 0 deletions openmp/libomptarget/plugins-nextgen/ppc64le/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
##===----------------------------------------------------------------------===##
#
# 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
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a ppc64le machine if available.
#
##===----------------------------------------------------------------------===##

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64_nextgen("ppc64le" "PPC64le" "ppc64" "powerpc64le-ibm-linux-gnu" "21")
else()
libomptarget_say("Not building ppc64le NextGen offloading plugin: machine not found in the system.")
endif()
17 changes: 17 additions & 0 deletions openmp/libomptarget/plugins-nextgen/x86_64/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
##===----------------------------------------------------------------------===##
#
# 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
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a x86_64 machine if available.
#
##===----------------------------------------------------------------------===##

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64_nextgen("x86_64" "x86_64" "x86_64" "x86_64-pc-linux-gnu" "62")
else()
libomptarget_say("Not building x86_64 NextGen offloading plugin: machine not found in the system.")
endif()
3 changes: 3 additions & 0 deletions openmp/libomptarget/plugins/cuda/dynamic_cuda/cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ typedef struct CUfunc_st *CUfunction;
typedef struct CUstream_st *CUstream;
typedef struct CUevent_st *CUevent;

#define CU_DEVICE_INVALID ((CUdevice)-2)

typedef enum cudaError_enum {
CUDA_SUCCESS = 0,
CUDA_ERROR_INVALID_VALUE = 1,
CUDA_ERROR_NO_DEVICE = 100,
CUDA_ERROR_INVALID_HANDLE = 400,
CUDA_ERROR_TOO_MANY_PEERS = 711,
} CUresult;

typedef enum CUstream_flags_enum {
Expand Down
293 changes: 155 additions & 138 deletions openmp/libomptarget/src/rtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "private.h"
#include "rtl.h"

#include "Utilities.h"

#include <cassert>
#include <cstdlib>
#include <cstring>
Expand All @@ -24,16 +26,17 @@

using namespace llvm;
using namespace llvm::sys;
using namespace llvm::omp::target;

// List of all plugins that can support offloading.
static const char *RTLNames[] = {
/* PowerPC target */ "libomptarget.rtl.ppc64.so",
/* x86_64 target */ "libomptarget.rtl.x86_64.so",
/* CUDA target */ "libomptarget.rtl.cuda.so",
/* AArch64 target */ "libomptarget.rtl.aarch64.so",
/* SX-Aurora VE target */ "libomptarget.rtl.ve.so",
/* AMDGPU target */ "libomptarget.rtl.amdgpu.so",
/* Remote target */ "libomptarget.rtl.rpc.so",
/* PowerPC target */ "libomptarget.rtl.ppc64",
/* x86_64 target */ "libomptarget.rtl.x86_64",
/* CUDA target */ "libomptarget.rtl.cuda",
/* AArch64 target */ "libomptarget.rtl.aarch64",
/* SX-Aurora VE target */ "libomptarget.rtl.ve",
/* AMDGPU target */ "libomptarget.rtl.amdgpu",
/* Remote target */ "libomptarget.rtl.rpc",
};

PluginManager *PM;
Expand Down Expand Up @@ -86,152 +89,166 @@ void RTLsTy::loadRTLs() {

DP("Loading RTLs...\n");

BoolEnvar NextGenPlugins("LIBOMPTARGET_NEXTGEN_PLUGINS", false);

// Attempt to open all the plugins and, if they exist, check if the interface
// is correct and if they are supporting any devices.
for (auto *Name : RTLNames) {
DP("Loading library '%s'...\n", Name);
std::string ErrMsg;
auto DynLibrary = std::make_unique<sys::DynamicLibrary>(
sys::DynamicLibrary::getPermanentLibrary(Name, &ErrMsg));

if (!DynLibrary->isValid()) {
// Library does not exist or cannot be found.
DP("Unable to load library '%s': %s!\n", Name, ErrMsg.c_str());
continue;
}

DP("Successfully loaded library '%s'!\n", Name);

for (const char *Name : RTLNames) {
AllRTLs.emplace_back();

// Retrieve the RTL information from the runtime library.
RTLInfoTy &R = AllRTLs.back();

// Remove plugin on failure to call optional init_plugin
*((void **)&R.init_plugin) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_plugin");
if (R.init_plugin) {
int32_t Rc = R.init_plugin();
if (Rc != OFFLOAD_SUCCESS) {
DP("Unable to initialize library '%s': %u!\n", Name, Rc);
AllRTLs.pop_back();
RTLInfoTy &RTL = AllRTLs.back();

const std::string BaseRTLName(Name);
if (NextGenPlugins) {
if (attemptLoadRTL(BaseRTLName + ".nextgen.so", RTL))
continue;
}
}

bool ValidPlugin = true;

if (!(*((void **)&R.is_valid_binary) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary")))
ValidPlugin = false;
if (!(*((void **)&R.number_of_devices) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_number_of_devices")))
ValidPlugin = false;
if (!(*((void **)&R.init_device) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device")))
ValidPlugin = false;
if (!(*((void **)&R.load_binary) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_load_binary")))
ValidPlugin = false;
if (!(*((void **)&R.data_alloc) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_alloc")))
ValidPlugin = false;
if (!(*((void **)&R.data_submit) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit")))
ValidPlugin = false;
if (!(*((void **)&R.data_retrieve) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve")))
ValidPlugin = false;
if (!(*((void **)&R.data_delete) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_delete")))
ValidPlugin = false;
if (!(*((void **)&R.run_region) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_region")))
ValidPlugin = false;
if (!(*((void **)&R.run_team_region) = DynLibrary->getAddressOfSymbol(
"__tgt_rtl_run_target_team_region")))
ValidPlugin = false;

// Invalid plugin
if (!ValidPlugin) {
DP("Invalid plugin as necessary interface is not found.\n");
AllRTLs.pop_back();
continue;
DP("Falling back to original plugin...\n");
}

// No devices are supported by this RTL?
if (!(R.NumberOfDevices = R.number_of_devices())) {
// The RTL is invalid! Will pop the object from the RTLs list.
DP("No devices supported in this RTL\n");
if (!attemptLoadRTL(BaseRTLName + ".so", RTL))
AllRTLs.pop_back();
continue;
}

DP("RTLs loaded!\n");
}

bool RTLsTy::attemptLoadRTL(const std::string &RTLName, RTLInfoTy &RTL) {
const char *Name = RTLName.c_str();

DP("Loading library '%s'...\n", Name);

std::string ErrMsg;
auto DynLibrary = std::make_unique<sys::DynamicLibrary>(
sys::DynamicLibrary::getPermanentLibrary(Name, &ErrMsg));

if (!DynLibrary->isValid()) {
// Library does not exist or cannot be found.
DP("Unable to load library '%s': %s!\n", Name, ErrMsg.c_str());
return false;
}

DP("Successfully loaded library '%s'!\n", Name);

// Remove plugin on failure to call optional init_plugin
*((void **)&RTL.init_plugin) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_plugin");
if (RTL.init_plugin) {
int32_t Rc = RTL.init_plugin();
if (Rc != OFFLOAD_SUCCESS) {
DP("Unable to initialize library '%s': %u!\n", Name, Rc);
return false;
}
}

#ifdef OMPTARGET_DEBUG
R.RTLName = Name;
#endif
bool ValidPlugin = true;

if (!(*((void **)&RTL.is_valid_binary) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary")))
ValidPlugin = false;
if (!(*((void **)&RTL.number_of_devices) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_number_of_devices")))
ValidPlugin = false;
if (!(*((void **)&RTL.init_device) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device")))
ValidPlugin = false;
if (!(*((void **)&RTL.load_binary) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_load_binary")))
ValidPlugin = false;
if (!(*((void **)&RTL.data_alloc) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_alloc")))
ValidPlugin = false;
if (!(*((void **)&RTL.data_submit) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit")))
ValidPlugin = false;
if (!(*((void **)&RTL.data_retrieve) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve")))
ValidPlugin = false;
if (!(*((void **)&RTL.data_delete) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_delete")))
ValidPlugin = false;
if (!(*((void **)&RTL.run_region) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_region")))
ValidPlugin = false;
if (!(*((void **)&RTL.run_team_region) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_team_region")))
ValidPlugin = false;

// Invalid plugin
if (!ValidPlugin) {
DP("Invalid plugin as necessary interface is not found.\n");
return false;
}

DP("Registering RTL %s supporting %d devices!\n", R.RTLName.c_str(),
R.NumberOfDevices);

// Optional functions
*((void **)&R.deinit_plugin) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_deinit_plugin");
*((void **)&R.is_valid_binary_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary_info");
*((void **)&R.deinit_device) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_deinit_device");
*((void **)&R.init_requires) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_requires");
*((void **)&R.data_submit_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit_async");
*((void **)&R.data_retrieve_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve_async");
*((void **)&R.run_region_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_region_async");
*((void **)&R.run_team_region_async) = DynLibrary->getAddressOfSymbol(
"__tgt_rtl_run_target_team_region_async");
*((void **)&R.synchronize) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_synchronize");
*((void **)&R.data_exchange) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange");
*((void **)&R.data_exchange_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange_async");
*((void **)&R.is_data_exchangable) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_data_exchangable");
*((void **)&R.register_lib) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_register_lib");
*((void **)&R.unregister_lib) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_unregister_lib");
*((void **)&R.supports_empty_images) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_supports_empty_images");
*((void **)&R.set_info_flag) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_set_info_flag");
*((void **)&R.print_device_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_print_device_info");
*((void **)&R.create_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_create_event");
*((void **)&R.record_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_record_event");
*((void **)&R.wait_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_wait_event");
*((void **)&R.sync_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_sync_event");
*((void **)&R.destroy_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_destroy_event");
*((void **)&R.release_async_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_release_async_info");
*((void **)&R.init_async_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_async_info");
*((void **)&R.init_device_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device_info");

R.LibraryHandler = std::move(DynLibrary);
// No devices are supported by this RTL?
if (!(RTL.NumberOfDevices = RTL.number_of_devices())) {
// The RTL is invalid! Will pop the object from the RTLs list.
DP("No devices supported in this RTL\n");
return false;
}

DP("RTLs loaded!\n");
#ifdef LIBOMPTARGET_DEBUG
RTL.RTLName = Name;
#endif

return;
DP("Registering RTL %s supporting %d devices!\n", Name, RTL.NumberOfDevices);

// Optional functions
*((void **)&RTL.deinit_plugin) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_deinit_plugin");
*((void **)&RTL.is_valid_binary_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary_info");
*((void **)&RTL.deinit_device) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_deinit_device");
*((void **)&RTL.init_requires) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_requires");
*((void **)&RTL.data_submit_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit_async");
*((void **)&RTL.data_retrieve_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve_async");
*((void **)&RTL.run_region_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_region_async");
*((void **)&RTL.run_team_region_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_run_target_team_region_async");
*((void **)&RTL.synchronize) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_synchronize");
*((void **)&RTL.data_exchange) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange");
*((void **)&RTL.data_exchange_async) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange_async");
*((void **)&RTL.is_data_exchangable) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_is_data_exchangable");
*((void **)&RTL.register_lib) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_register_lib");
*((void **)&RTL.unregister_lib) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_unregister_lib");
*((void **)&RTL.supports_empty_images) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_supports_empty_images");
*((void **)&RTL.set_info_flag) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_set_info_flag");
*((void **)&RTL.print_device_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_print_device_info");
*((void **)&RTL.create_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_create_event");
*((void **)&RTL.record_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_record_event");
*((void **)&RTL.wait_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_wait_event");
*((void **)&RTL.sync_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_sync_event");
*((void **)&RTL.destroy_event) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_destroy_event");
*((void **)&RTL.release_async_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_release_async_info");
*((void **)&RTL.init_async_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_async_info");
*((void **)&RTL.init_device_info) =
DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device_info");

RTL.LibraryHandler = std::move(DynLibrary);

// Successfully loaded
return true;
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 4 additions & 0 deletions openmp/libomptarget/test/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ if 'ROCR_VISIBLE_DEVICES' in os.environ:
if 'LIBOMPTARGET_DEBUG' in os.environ:
config.environment['LIBOMPTARGET_DEBUG'] = os.environ['LIBOMPTARGET_DEBUG']

# Allow running the tests with nextgen plugins when available
if 'LIBOMPTARGET_NEXTGEN_PLUGINS' in os.environ:
config.environment['LIBOMPTARGET_NEXTGEN_PLUGINS'] = os.environ['LIBOMPTARGET_NEXTGEN_PLUGINS']

if 'OMP_TARGET_OFFLOAD' in os.environ:
config.environment['OMP_TARGET_OFFLOAD'] = os.environ['OMP_TARGET_OFFLOAD']

Expand Down