1330d8983SJohannes Doerfert //===-- InteropAPI.cpp - Implementation of OpenMP interoperability API ----===//
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 #include "OpenMP/InteropAPI.h"
10330d8983SJohannes Doerfert #include "OpenMP/InternalTypes.h"
11330d8983SJohannes Doerfert #include "OpenMP/omp.h"
12330d8983SJohannes Doerfert
13330d8983SJohannes Doerfert #include "PluginManager.h"
14330d8983SJohannes Doerfert #include "device.h"
15330d8983SJohannes Doerfert #include "omptarget.h"
16330d8983SJohannes Doerfert #include "llvm/Support/Error.h"
17330d8983SJohannes Doerfert #include <cstdlib>
18330d8983SJohannes Doerfert #include <cstring>
19330d8983SJohannes Doerfert
20330d8983SJohannes Doerfert extern "C" {
21330d8983SJohannes Doerfert
22330d8983SJohannes Doerfert void __kmpc_omp_wait_deps(ident_t *loc_ref, int32_t gtid, int32_t ndeps,
23330d8983SJohannes Doerfert kmp_depend_info_t *dep_list, int32_t ndeps_noalias,
24330d8983SJohannes Doerfert kmp_depend_info_t *noalias_dep_list)
25330d8983SJohannes Doerfert __attribute__((weak));
26330d8983SJohannes Doerfert
27330d8983SJohannes Doerfert } // extern "C"
28330d8983SJohannes Doerfert
29330d8983SJohannes Doerfert namespace {
getPropertyErrorType(omp_interop_property_t Property)30330d8983SJohannes Doerfert omp_interop_rc_t getPropertyErrorType(omp_interop_property_t Property) {
31330d8983SJohannes Doerfert switch (Property) {
32330d8983SJohannes Doerfert case omp_ipr_fr_id:
33330d8983SJohannes Doerfert return omp_irc_type_int;
34330d8983SJohannes Doerfert case omp_ipr_fr_name:
35330d8983SJohannes Doerfert return omp_irc_type_str;
36330d8983SJohannes Doerfert case omp_ipr_vendor:
37330d8983SJohannes Doerfert return omp_irc_type_int;
38330d8983SJohannes Doerfert case omp_ipr_vendor_name:
39330d8983SJohannes Doerfert return omp_irc_type_str;
40330d8983SJohannes Doerfert case omp_ipr_device_num:
41330d8983SJohannes Doerfert return omp_irc_type_int;
42330d8983SJohannes Doerfert case omp_ipr_platform:
43330d8983SJohannes Doerfert return omp_irc_type_int;
44330d8983SJohannes Doerfert case omp_ipr_device:
45330d8983SJohannes Doerfert return omp_irc_type_ptr;
46330d8983SJohannes Doerfert case omp_ipr_device_context:
47330d8983SJohannes Doerfert return omp_irc_type_ptr;
48330d8983SJohannes Doerfert case omp_ipr_targetsync:
49330d8983SJohannes Doerfert return omp_irc_type_ptr;
50330d8983SJohannes Doerfert };
51330d8983SJohannes Doerfert return omp_irc_no_value;
52330d8983SJohannes Doerfert }
53330d8983SJohannes Doerfert
getTypeMismatch(omp_interop_property_t Property,int * Err)54330d8983SJohannes Doerfert void getTypeMismatch(omp_interop_property_t Property, int *Err) {
55330d8983SJohannes Doerfert if (Err)
56330d8983SJohannes Doerfert *Err = getPropertyErrorType(Property);
57330d8983SJohannes Doerfert }
58330d8983SJohannes Doerfert
getVendorIdToStr(const omp_foreign_runtime_ids_t VendorId)59330d8983SJohannes Doerfert const char *getVendorIdToStr(const omp_foreign_runtime_ids_t VendorId) {
60330d8983SJohannes Doerfert switch (VendorId) {
61330d8983SJohannes Doerfert case cuda:
62330d8983SJohannes Doerfert return ("cuda");
63330d8983SJohannes Doerfert case cuda_driver:
64330d8983SJohannes Doerfert return ("cuda_driver");
65330d8983SJohannes Doerfert case opencl:
66330d8983SJohannes Doerfert return ("opencl");
67330d8983SJohannes Doerfert case sycl:
68330d8983SJohannes Doerfert return ("sycl");
69330d8983SJohannes Doerfert case hip:
70330d8983SJohannes Doerfert return ("hip");
71330d8983SJohannes Doerfert case level_zero:
72330d8983SJohannes Doerfert return ("level_zero");
73330d8983SJohannes Doerfert }
74330d8983SJohannes Doerfert return ("unknown");
75330d8983SJohannes Doerfert }
76330d8983SJohannes Doerfert
77330d8983SJohannes Doerfert template <typename PropertyTy>
78330d8983SJohannes Doerfert PropertyTy getProperty(omp_interop_val_t &InteropVal,
79330d8983SJohannes Doerfert omp_interop_property_t Property, int *Err);
80330d8983SJohannes Doerfert
81330d8983SJohannes Doerfert template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)82330d8983SJohannes Doerfert intptr_t getProperty<intptr_t>(omp_interop_val_t &InteropVal,
83330d8983SJohannes Doerfert omp_interop_property_t Property, int *Err) {
84330d8983SJohannes Doerfert switch (Property) {
85330d8983SJohannes Doerfert case omp_ipr_fr_id:
86330d8983SJohannes Doerfert return InteropVal.backend_type_id;
87330d8983SJohannes Doerfert case omp_ipr_vendor:
88330d8983SJohannes Doerfert return InteropVal.vendor_id;
89330d8983SJohannes Doerfert case omp_ipr_device_num:
90330d8983SJohannes Doerfert return InteropVal.device_id;
91330d8983SJohannes Doerfert default:;
92330d8983SJohannes Doerfert }
93330d8983SJohannes Doerfert getTypeMismatch(Property, Err);
94330d8983SJohannes Doerfert return 0;
95330d8983SJohannes Doerfert }
96330d8983SJohannes Doerfert
97330d8983SJohannes Doerfert template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)98330d8983SJohannes Doerfert const char *getProperty<const char *>(omp_interop_val_t &InteropVal,
99330d8983SJohannes Doerfert omp_interop_property_t Property,
100330d8983SJohannes Doerfert int *Err) {
101330d8983SJohannes Doerfert switch (Property) {
102330d8983SJohannes Doerfert case omp_ipr_fr_id:
103330d8983SJohannes Doerfert return InteropVal.interop_type == kmp_interop_type_tasksync
104330d8983SJohannes Doerfert ? "tasksync"
105330d8983SJohannes Doerfert : "device+context";
106330d8983SJohannes Doerfert case omp_ipr_vendor_name:
107330d8983SJohannes Doerfert return getVendorIdToStr(InteropVal.vendor_id);
108330d8983SJohannes Doerfert default:
109330d8983SJohannes Doerfert getTypeMismatch(Property, Err);
110330d8983SJohannes Doerfert return nullptr;
111330d8983SJohannes Doerfert }
112330d8983SJohannes Doerfert }
113330d8983SJohannes Doerfert
114330d8983SJohannes Doerfert template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)115330d8983SJohannes Doerfert void *getProperty<void *>(omp_interop_val_t &InteropVal,
116330d8983SJohannes Doerfert omp_interop_property_t Property, int *Err) {
117330d8983SJohannes Doerfert switch (Property) {
118330d8983SJohannes Doerfert case omp_ipr_device:
119330d8983SJohannes Doerfert if (InteropVal.device_info.Device)
120330d8983SJohannes Doerfert return InteropVal.device_info.Device;
121330d8983SJohannes Doerfert *Err = omp_irc_no_value;
122330d8983SJohannes Doerfert return const_cast<char *>(InteropVal.err_str);
123330d8983SJohannes Doerfert case omp_ipr_device_context:
124330d8983SJohannes Doerfert return InteropVal.device_info.Context;
125330d8983SJohannes Doerfert case omp_ipr_targetsync:
126330d8983SJohannes Doerfert return InteropVal.async_info->Queue;
127330d8983SJohannes Doerfert default:;
128330d8983SJohannes Doerfert }
129330d8983SJohannes Doerfert getTypeMismatch(Property, Err);
130330d8983SJohannes Doerfert return nullptr;
131330d8983SJohannes Doerfert }
132330d8983SJohannes Doerfert
getPropertyCheck(omp_interop_val_t ** InteropPtr,omp_interop_property_t Property,int * Err)133330d8983SJohannes Doerfert bool getPropertyCheck(omp_interop_val_t **InteropPtr,
134330d8983SJohannes Doerfert omp_interop_property_t Property, int *Err) {
135330d8983SJohannes Doerfert if (Err)
136330d8983SJohannes Doerfert *Err = omp_irc_success;
137330d8983SJohannes Doerfert if (!InteropPtr) {
138330d8983SJohannes Doerfert if (Err)
139330d8983SJohannes Doerfert *Err = omp_irc_empty;
140330d8983SJohannes Doerfert return false;
141330d8983SJohannes Doerfert }
142330d8983SJohannes Doerfert if (Property >= 0 || Property < omp_ipr_first) {
143330d8983SJohannes Doerfert if (Err)
144330d8983SJohannes Doerfert *Err = omp_irc_out_of_range;
145330d8983SJohannes Doerfert return false;
146330d8983SJohannes Doerfert }
147330d8983SJohannes Doerfert if (Property == omp_ipr_targetsync &&
148330d8983SJohannes Doerfert (*InteropPtr)->interop_type != kmp_interop_type_tasksync) {
149330d8983SJohannes Doerfert if (Err)
150330d8983SJohannes Doerfert *Err = omp_irc_other;
151330d8983SJohannes Doerfert return false;
152330d8983SJohannes Doerfert }
153330d8983SJohannes Doerfert if ((Property == omp_ipr_device || Property == omp_ipr_device_context) &&
154330d8983SJohannes Doerfert (*InteropPtr)->interop_type == kmp_interop_type_tasksync) {
155330d8983SJohannes Doerfert if (Err)
156330d8983SJohannes Doerfert *Err = omp_irc_other;
157330d8983SJohannes Doerfert return false;
158330d8983SJohannes Doerfert }
159330d8983SJohannes Doerfert return true;
160330d8983SJohannes Doerfert }
161330d8983SJohannes Doerfert
162330d8983SJohannes Doerfert } // namespace
163330d8983SJohannes Doerfert
164330d8983SJohannes Doerfert #define __OMP_GET_INTEROP_TY(RETURN_TYPE, SUFFIX) \
165330d8983SJohannes Doerfert RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
166330d8983SJohannes Doerfert omp_interop_property_t property_id, \
167330d8983SJohannes Doerfert int *err) { \
168330d8983SJohannes Doerfert omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
169330d8983SJohannes Doerfert assert((interop_val)->interop_type == kmp_interop_type_tasksync); \
170330d8983SJohannes Doerfert if (!getPropertyCheck(&interop_val, property_id, err)) { \
171330d8983SJohannes Doerfert return (RETURN_TYPE)(0); \
172330d8983SJohannes Doerfert } \
173330d8983SJohannes Doerfert return getProperty<RETURN_TYPE>(*interop_val, property_id, err); \
174330d8983SJohannes Doerfert }
__OMP_GET_INTEROP_TY(intptr_t,int)175330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY(intptr_t, int)
176330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY(void *, ptr)
177330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY(const char *, str)
178330d8983SJohannes Doerfert #undef __OMP_GET_INTEROP_TY
179330d8983SJohannes Doerfert
180330d8983SJohannes Doerfert #define __OMP_GET_INTEROP_TY3(RETURN_TYPE, SUFFIX) \
181330d8983SJohannes Doerfert RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
182330d8983SJohannes Doerfert omp_interop_property_t property_id) { \
183330d8983SJohannes Doerfert int err; \
184330d8983SJohannes Doerfert omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
185330d8983SJohannes Doerfert if (!getPropertyCheck(&interop_val, property_id, &err)) { \
186330d8983SJohannes Doerfert return (RETURN_TYPE)(0); \
187330d8983SJohannes Doerfert } \
188330d8983SJohannes Doerfert return nullptr; \
189330d8983SJohannes Doerfert return getProperty<RETURN_TYPE>(*interop_val, property_id, &err); \
190330d8983SJohannes Doerfert }
191330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY3(const char *, name)
192330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY3(const char *, type_desc)
193330d8983SJohannes Doerfert __OMP_GET_INTEROP_TY3(const char *, rc_desc)
194330d8983SJohannes Doerfert #undef __OMP_GET_INTEROP_TY3
195330d8983SJohannes Doerfert
196330d8983SJohannes Doerfert static const char *copyErrorString(llvm::Error &&Err) {
197330d8983SJohannes Doerfert // TODO: Use the error string while avoiding leaks.
198330d8983SJohannes Doerfert std::string ErrMsg = llvm::toString(std::move(Err));
199330d8983SJohannes Doerfert char *UsrMsg = reinterpret_cast<char *>(malloc(ErrMsg.size() + 1));
200330d8983SJohannes Doerfert strcpy(UsrMsg, ErrMsg.c_str());
201330d8983SJohannes Doerfert return UsrMsg;
202330d8983SJohannes Doerfert }
203330d8983SJohannes Doerfert
204330d8983SJohannes Doerfert extern "C" {
205330d8983SJohannes Doerfert
__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)206330d8983SJohannes Doerfert void __tgt_interop_init(ident_t *LocRef, int32_t Gtid,
207330d8983SJohannes Doerfert omp_interop_val_t *&InteropPtr,
208330d8983SJohannes Doerfert kmp_interop_type_t InteropType, int32_t DeviceId,
209330d8983SJohannes Doerfert int32_t Ndeps, kmp_depend_info_t *DepList,
210330d8983SJohannes Doerfert int32_t HaveNowait) {
211330d8983SJohannes Doerfert int32_t NdepsNoalias = 0;
212330d8983SJohannes Doerfert kmp_depend_info_t *NoaliasDepList = NULL;
213330d8983SJohannes Doerfert assert(InteropType != kmp_interop_type_unknown &&
214330d8983SJohannes Doerfert "Cannot initialize with unknown interop_type!");
215330d8983SJohannes Doerfert if (DeviceId == -1) {
216330d8983SJohannes Doerfert DeviceId = omp_get_default_device();
217330d8983SJohannes Doerfert }
218330d8983SJohannes Doerfert
219330d8983SJohannes Doerfert if (InteropType == kmp_interop_type_tasksync) {
220330d8983SJohannes Doerfert __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
221330d8983SJohannes Doerfert NoaliasDepList);
222330d8983SJohannes Doerfert }
223330d8983SJohannes Doerfert
224330d8983SJohannes Doerfert InteropPtr = new omp_interop_val_t(DeviceId, InteropType);
225330d8983SJohannes Doerfert
226330d8983SJohannes Doerfert auto DeviceOrErr = PM->getDevice(DeviceId);
227330d8983SJohannes Doerfert if (!DeviceOrErr) {
228330d8983SJohannes Doerfert InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
229330d8983SJohannes Doerfert return;
230330d8983SJohannes Doerfert }
231330d8983SJohannes Doerfert
232330d8983SJohannes Doerfert DeviceTy &Device = *DeviceOrErr;
233*fa9e90f5SJoseph Huber if (!Device.RTL ||
234330d8983SJohannes Doerfert Device.RTL->init_device_info(DeviceId, &(InteropPtr)->device_info,
235330d8983SJohannes Doerfert &(InteropPtr)->err_str)) {
236330d8983SJohannes Doerfert delete InteropPtr;
237330d8983SJohannes Doerfert InteropPtr = omp_interop_none;
238330d8983SJohannes Doerfert }
239330d8983SJohannes Doerfert if (InteropType == kmp_interop_type_tasksync) {
240*fa9e90f5SJoseph Huber if (!Device.RTL ||
241330d8983SJohannes Doerfert Device.RTL->init_async_info(DeviceId, &(InteropPtr)->async_info)) {
242330d8983SJohannes Doerfert delete InteropPtr;
243330d8983SJohannes Doerfert InteropPtr = omp_interop_none;
244330d8983SJohannes Doerfert }
245330d8983SJohannes Doerfert }
246330d8983SJohannes Doerfert }
247330d8983SJohannes Doerfert
__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)248330d8983SJohannes Doerfert void __tgt_interop_use(ident_t *LocRef, int32_t Gtid,
249330d8983SJohannes Doerfert omp_interop_val_t *&InteropPtr, int32_t DeviceId,
250330d8983SJohannes Doerfert int32_t Ndeps, kmp_depend_info_t *DepList,
251330d8983SJohannes Doerfert int32_t HaveNowait) {
252330d8983SJohannes Doerfert int32_t NdepsNoalias = 0;
253330d8983SJohannes Doerfert kmp_depend_info_t *NoaliasDepList = NULL;
254330d8983SJohannes Doerfert assert(InteropPtr && "Cannot use nullptr!");
255330d8983SJohannes Doerfert omp_interop_val_t *InteropVal = InteropPtr;
256330d8983SJohannes Doerfert if (DeviceId == -1) {
257330d8983SJohannes Doerfert DeviceId = omp_get_default_device();
258330d8983SJohannes Doerfert }
259330d8983SJohannes Doerfert assert(InteropVal != omp_interop_none &&
260330d8983SJohannes Doerfert "Cannot use uninitialized interop_ptr!");
261330d8983SJohannes Doerfert assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
262330d8983SJohannes Doerfert "Inconsistent device-id usage!");
263330d8983SJohannes Doerfert
264330d8983SJohannes Doerfert auto DeviceOrErr = PM->getDevice(DeviceId);
265330d8983SJohannes Doerfert if (!DeviceOrErr) {
266330d8983SJohannes Doerfert InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
267330d8983SJohannes Doerfert return;
268330d8983SJohannes Doerfert }
269330d8983SJohannes Doerfert
270330d8983SJohannes Doerfert if (InteropVal->interop_type == kmp_interop_type_tasksync) {
271330d8983SJohannes Doerfert __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
272330d8983SJohannes Doerfert NoaliasDepList);
273330d8983SJohannes Doerfert }
274330d8983SJohannes Doerfert // TODO Flush the queue associated with the interop through the plugin
275330d8983SJohannes Doerfert }
276330d8983SJohannes Doerfert
__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)277330d8983SJohannes Doerfert void __tgt_interop_destroy(ident_t *LocRef, int32_t Gtid,
278330d8983SJohannes Doerfert omp_interop_val_t *&InteropPtr, int32_t DeviceId,
279330d8983SJohannes Doerfert int32_t Ndeps, kmp_depend_info_t *DepList,
280330d8983SJohannes Doerfert int32_t HaveNowait) {
281330d8983SJohannes Doerfert int32_t NdepsNoalias = 0;
282330d8983SJohannes Doerfert kmp_depend_info_t *NoaliasDepList = NULL;
283330d8983SJohannes Doerfert assert(InteropPtr && "Cannot use nullptr!");
284330d8983SJohannes Doerfert omp_interop_val_t *InteropVal = InteropPtr;
285330d8983SJohannes Doerfert if (DeviceId == -1) {
286330d8983SJohannes Doerfert DeviceId = omp_get_default_device();
287330d8983SJohannes Doerfert }
288330d8983SJohannes Doerfert
289330d8983SJohannes Doerfert if (InteropVal == omp_interop_none)
290330d8983SJohannes Doerfert return;
291330d8983SJohannes Doerfert
292330d8983SJohannes Doerfert assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
293330d8983SJohannes Doerfert "Inconsistent device-id usage!");
294330d8983SJohannes Doerfert auto DeviceOrErr = PM->getDevice(DeviceId);
295330d8983SJohannes Doerfert if (!DeviceOrErr) {
296330d8983SJohannes Doerfert InteropPtr->err_str = copyErrorString(DeviceOrErr.takeError());
297330d8983SJohannes Doerfert return;
298330d8983SJohannes Doerfert }
299330d8983SJohannes Doerfert
300330d8983SJohannes Doerfert if (InteropVal->interop_type == kmp_interop_type_tasksync) {
301330d8983SJohannes Doerfert __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
302330d8983SJohannes Doerfert NoaliasDepList);
303330d8983SJohannes Doerfert }
304330d8983SJohannes Doerfert // TODO Flush the queue associated with the interop through the plugin
305330d8983SJohannes Doerfert // TODO Signal out dependences
306330d8983SJohannes Doerfert
307330d8983SJohannes Doerfert delete InteropPtr;
308330d8983SJohannes Doerfert InteropPtr = omp_interop_none;
309330d8983SJohannes Doerfert }
310330d8983SJohannes Doerfert
311330d8983SJohannes Doerfert } // extern "C"
312