xref: /llvm-project/offload/src/OpenMP/InteropAPI.cpp (revision fa9e90f5d23312587b3a17920941334e0d1a58a1)
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