mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 17:36:36 +00:00

Summary: The name `src` is confusing when combined with the plugins and the newly added `liboffload`.
312 lines
10 KiB
C++
312 lines
10 KiB
C++
//===-- InteropAPI.cpp - Implementation of OpenMP interoperability API ----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "OpenMP/InteropAPI.h"
|
|
#include "OpenMP/InternalTypes.h"
|
|
#include "OpenMP/omp.h"
|
|
|
|
#include "PluginManager.h"
|
|
#include "device.h"
|
|
#include "omptarget.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
extern "C" {
|
|
|
|
void __kmpc_omp_wait_deps(ident_t *loc_ref, int32_t gtid, int32_t ndeps,
|
|
kmp_depend_info_t *dep_list, int32_t ndeps_noalias,
|
|
kmp_depend_info_t *noalias_dep_list)
|
|
__attribute__((weak));
|
|
|
|
} // extern "C"
|
|
|
|
namespace {
|
|
omp_interop_rc_t getPropertyErrorType(omp_interop_property_t Property) {
|
|
switch (Property) {
|
|
case omp_ipr_fr_id:
|
|
return omp_irc_type_int;
|
|
case omp_ipr_fr_name:
|
|
return omp_irc_type_str;
|
|
case omp_ipr_vendor:
|
|
return omp_irc_type_int;
|
|
case omp_ipr_vendor_name:
|
|
return omp_irc_type_str;
|
|
case omp_ipr_device_num:
|
|
return omp_irc_type_int;
|
|
case omp_ipr_platform:
|
|
return omp_irc_type_int;
|
|
case omp_ipr_device:
|
|
return omp_irc_type_ptr;
|
|
case omp_ipr_device_context:
|
|
return omp_irc_type_ptr;
|
|
case omp_ipr_targetsync:
|
|
return omp_irc_type_ptr;
|
|
};
|
|
return omp_irc_no_value;
|
|
}
|
|
|
|
void getTypeMismatch(omp_interop_property_t Property, int *Err) {
|
|
if (Err)
|
|
*Err = getPropertyErrorType(Property);
|
|
}
|
|
|
|
const char *getVendorIdToStr(const omp_foreign_runtime_ids_t VendorId) {
|
|
switch (VendorId) {
|
|
case cuda:
|
|
return ("cuda");
|
|
case cuda_driver:
|
|
return ("cuda_driver");
|
|
case opencl:
|
|
return ("opencl");
|
|
case sycl:
|
|
return ("sycl");
|
|
case hip:
|
|
return ("hip");
|
|
case level_zero:
|
|
return ("level_zero");
|
|
}
|
|
return ("unknown");
|
|
}
|
|
|
|
template <typename PropertyTy>
|
|
PropertyTy getProperty(omp_interop_val_t &InteropVal,
|
|
omp_interop_property_t Property, int *Err);
|
|
|
|
template <>
|
|
intptr_t getProperty<intptr_t>(omp_interop_val_t &InteropVal,
|
|
omp_interop_property_t Property, int *Err) {
|
|
switch (Property) {
|
|
case omp_ipr_fr_id:
|
|
return InteropVal.backend_type_id;
|
|
case omp_ipr_vendor:
|
|
return InteropVal.vendor_id;
|
|
case omp_ipr_device_num:
|
|
return InteropVal.device_id;
|
|
default:;
|
|
}
|
|
getTypeMismatch(Property, Err);
|
|
return 0;
|
|
}
|
|
|
|
template <>
|
|
const char *getProperty<const char *>(omp_interop_val_t &InteropVal,
|
|
omp_interop_property_t Property,
|
|
int *Err) {
|
|
switch (Property) {
|
|
case omp_ipr_fr_id:
|
|
return InteropVal.interop_type == kmp_interop_type_tasksync
|
|
? "tasksync"
|
|
: "device+context";
|
|
case omp_ipr_vendor_name:
|
|
return getVendorIdToStr(InteropVal.vendor_id);
|
|
default:
|
|
getTypeMismatch(Property, Err);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void *getProperty<void *>(omp_interop_val_t &InteropVal,
|
|
omp_interop_property_t Property, int *Err) {
|
|
switch (Property) {
|
|
case omp_ipr_device:
|
|
if (InteropVal.device_info.Device)
|
|
return InteropVal.device_info.Device;
|
|
*Err = omp_irc_no_value;
|
|
return const_cast<char *>(InteropVal.err_str);
|
|
case omp_ipr_device_context:
|
|
return InteropVal.device_info.Context;
|
|
case omp_ipr_targetsync:
|
|
return InteropVal.async_info->Queue;
|
|
default:;
|
|
}
|
|
getTypeMismatch(Property, Err);
|
|
return nullptr;
|
|
}
|
|
|
|
bool getPropertyCheck(omp_interop_val_t **InteropPtr,
|
|
omp_interop_property_t Property, int *Err) {
|
|
if (Err)
|
|
*Err = omp_irc_success;
|
|
if (!InteropPtr) {
|
|
if (Err)
|
|
*Err = omp_irc_empty;
|
|
return false;
|
|
}
|
|
if (Property >= 0 || Property < omp_ipr_first) {
|
|
if (Err)
|
|
*Err = omp_irc_out_of_range;
|
|
return false;
|
|
}
|
|
if (Property == omp_ipr_targetsync &&
|
|
(*InteropPtr)->interop_type != kmp_interop_type_tasksync) {
|
|
if (Err)
|
|
*Err = omp_irc_other;
|
|
return false;
|
|
}
|
|
if ((Property == omp_ipr_device || Property == omp_ipr_device_context) &&
|
|
(*InteropPtr)->interop_type == kmp_interop_type_tasksync) {
|
|
if (Err)
|
|
*Err = omp_irc_other;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
#define __OMP_GET_INTEROP_TY(RETURN_TYPE, SUFFIX) \
|
|
RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
|
|
omp_interop_property_t property_id, \
|
|
int *err) { \
|
|
omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
|
|
assert((interop_val)->interop_type == kmp_interop_type_tasksync); \
|
|
if (!getPropertyCheck(&interop_val, property_id, err)) { \
|
|
return (RETURN_TYPE)(0); \
|
|
} \
|
|
return getProperty<RETURN_TYPE>(*interop_val, property_id, err); \
|
|
}
|
|
__OMP_GET_INTEROP_TY(intptr_t, int)
|
|
__OMP_GET_INTEROP_TY(void *, ptr)
|
|
__OMP_GET_INTEROP_TY(const char *, str)
|
|
#undef __OMP_GET_INTEROP_TY
|
|
|
|
#define __OMP_GET_INTEROP_TY3(RETURN_TYPE, SUFFIX) \
|
|
RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
|
|
omp_interop_property_t property_id) { \
|
|
int err; \
|
|
omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
|
|
if (!getPropertyCheck(&interop_val, property_id, &err)) { \
|
|
return (RETURN_TYPE)(0); \
|
|
} \
|
|
return nullptr; \
|
|
return getProperty<RETURN_TYPE>(*interop_val, property_id, &err); \
|
|
}
|
|
__OMP_GET_INTEROP_TY3(const char *, name)
|
|
__OMP_GET_INTEROP_TY3(const char *, type_desc)
|
|
__OMP_GET_INTEROP_TY3(const char *, rc_desc)
|
|
#undef __OMP_GET_INTEROP_TY3
|
|
|
|
static const char *copyErrorString(llvm::Error &&Err) {
|
|
// TODO: Use the error string while avoiding leaks.
|
|
std::string ErrMsg = llvm::toString(std::move(Err));
|
|
char *UsrMsg = reinterpret_cast<char *>(malloc(ErrMsg.size() + 1));
|
|
strcpy(UsrMsg, ErrMsg.c_str());
|
|
return UsrMsg;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void __tgt_interop_init(ident_t *LocRef, int32_t Gtid,
|
|
omp_interop_val_t *&InteropPtr,
|
|
kmp_interop_type_t InteropType, int32_t DeviceId,
|
|
int32_t Ndeps, kmp_depend_info_t *DepList,
|
|
int32_t HaveNowait) {
|
|
int32_t NdepsNoalias = 0;
|
|
kmp_depend_info_t *NoaliasDepList = NULL;
|
|
assert(InteropType != kmp_interop_type_unknown &&
|
|
"Cannot initialize with unknown interop_type!");
|
|
if (DeviceId == -1) {
|
|
DeviceId = omp_get_default_device();
|
|
}
|
|
|
|
if (InteropType == kmp_interop_type_tasksync) {
|
|
__kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
|
|
NoaliasDepList);
|
|
}
|
|
|
|
InteropPtr = new omp_interop_val_t(DeviceId, InteropType);
|
|
|
|
auto DeviceOrErr = PM->getDevice(DeviceId);
|
|
if (!DeviceOrErr) {
|
|
InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
|
|
return;
|
|
}
|
|
|
|
DeviceTy &Device = *DeviceOrErr;
|
|
if (!Device.RTL ||
|
|
Device.RTL->init_device_info(DeviceId, &(InteropPtr)->device_info,
|
|
&(InteropPtr)->err_str)) {
|
|
delete InteropPtr;
|
|
InteropPtr = omp_interop_none;
|
|
}
|
|
if (InteropType == kmp_interop_type_tasksync) {
|
|
if (!Device.RTL ||
|
|
Device.RTL->init_async_info(DeviceId, &(InteropPtr)->async_info)) {
|
|
delete InteropPtr;
|
|
InteropPtr = omp_interop_none;
|
|
}
|
|
}
|
|
}
|
|
|
|
void __tgt_interop_use(ident_t *LocRef, int32_t Gtid,
|
|
omp_interop_val_t *&InteropPtr, int32_t DeviceId,
|
|
int32_t Ndeps, kmp_depend_info_t *DepList,
|
|
int32_t HaveNowait) {
|
|
int32_t NdepsNoalias = 0;
|
|
kmp_depend_info_t *NoaliasDepList = NULL;
|
|
assert(InteropPtr && "Cannot use nullptr!");
|
|
omp_interop_val_t *InteropVal = InteropPtr;
|
|
if (DeviceId == -1) {
|
|
DeviceId = omp_get_default_device();
|
|
}
|
|
assert(InteropVal != omp_interop_none &&
|
|
"Cannot use uninitialized interop_ptr!");
|
|
assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
|
|
"Inconsistent device-id usage!");
|
|
|
|
auto DeviceOrErr = PM->getDevice(DeviceId);
|
|
if (!DeviceOrErr) {
|
|
InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
|
|
return;
|
|
}
|
|
|
|
if (InteropVal->interop_type == kmp_interop_type_tasksync) {
|
|
__kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
|
|
NoaliasDepList);
|
|
}
|
|
// TODO Flush the queue associated with the interop through the plugin
|
|
}
|
|
|
|
void __tgt_interop_destroy(ident_t *LocRef, int32_t Gtid,
|
|
omp_interop_val_t *&InteropPtr, int32_t DeviceId,
|
|
int32_t Ndeps, kmp_depend_info_t *DepList,
|
|
int32_t HaveNowait) {
|
|
int32_t NdepsNoalias = 0;
|
|
kmp_depend_info_t *NoaliasDepList = NULL;
|
|
assert(InteropPtr && "Cannot use nullptr!");
|
|
omp_interop_val_t *InteropVal = InteropPtr;
|
|
if (DeviceId == -1) {
|
|
DeviceId = omp_get_default_device();
|
|
}
|
|
|
|
if (InteropVal == omp_interop_none)
|
|
return;
|
|
|
|
assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
|
|
"Inconsistent device-id usage!");
|
|
auto DeviceOrErr = PM->getDevice(DeviceId);
|
|
if (!DeviceOrErr) {
|
|
InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
|
|
return;
|
|
}
|
|
|
|
if (InteropVal->interop_type == kmp_interop_type_tasksync) {
|
|
__kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
|
|
NoaliasDepList);
|
|
}
|
|
// TODO Flush the queue associated with the interop through the plugin
|
|
// TODO Signal out dependences
|
|
|
|
delete InteropPtr;
|
|
InteropPtr = omp_interop_none;
|
|
}
|
|
|
|
} // extern "C"
|