1 //===---------------interop.cpp - Implementation of interop directive -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "interop.h"
10 #include "private.h"
11
12 namespace {
getPropertyErrorType(omp_interop_property_t Property)13 omp_interop_rc_t getPropertyErrorType(omp_interop_property_t Property) {
14 switch (Property) {
15 case omp_ipr_fr_id:
16 return omp_irc_type_int;
17 case omp_ipr_fr_name:
18 return omp_irc_type_str;
19 case omp_ipr_vendor:
20 return omp_irc_type_int;
21 case omp_ipr_vendor_name:
22 return omp_irc_type_str;
23 case omp_ipr_device_num:
24 return omp_irc_type_int;
25 case omp_ipr_platform:
26 return omp_irc_type_int;
27 case omp_ipr_device:
28 return omp_irc_type_ptr;
29 case omp_ipr_device_context:
30 return omp_irc_type_ptr;
31 case omp_ipr_targetsync:
32 return omp_irc_type_ptr;
33 };
34 return omp_irc_no_value;
35 }
36
getTypeMismatch(omp_interop_property_t Property,int * Err)37 void getTypeMismatch(omp_interop_property_t Property, int *Err) {
38 if (Err)
39 *Err = getPropertyErrorType(Property);
40 }
41
getVendorIdToStr(const omp_foreign_runtime_ids_t VendorId)42 const char *getVendorIdToStr(const omp_foreign_runtime_ids_t VendorId) {
43 switch (VendorId) {
44 case cuda:
45 return ("cuda");
46 case cuda_driver:
47 return ("cuda_driver");
48 case opencl:
49 return ("opencl");
50 case sycl:
51 return ("sycl");
52 case hip:
53 return ("hip");
54 case level_zero:
55 return ("level_zero");
56 }
57 return ("unknown");
58 }
59
60 template <typename PropertyTy>
61 PropertyTy getProperty(omp_interop_val_t &InteropVal,
62 omp_interop_property_t Property, int *Err);
63
64 template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)65 intptr_t getProperty<intptr_t>(omp_interop_val_t &InteropVal,
66 omp_interop_property_t Property, int *Err) {
67 switch (Property) {
68 case omp_ipr_fr_id:
69 return InteropVal.backend_type_id;
70 case omp_ipr_vendor:
71 return InteropVal.vendor_id;
72 case omp_ipr_device_num:
73 return InteropVal.device_id;
74 default:;
75 }
76 getTypeMismatch(Property, Err);
77 return 0;
78 }
79
80 template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)81 const char *getProperty<const char *>(omp_interop_val_t &InteropVal,
82 omp_interop_property_t Property,
83 int *Err) {
84 switch (Property) {
85 case omp_ipr_fr_id:
86 return InteropVal.interop_type == kmp_interop_type_tasksync
87 ? "tasksync"
88 : "device+context";
89 case omp_ipr_vendor_name:
90 return getVendorIdToStr(InteropVal.vendor_id);
91 default:
92 getTypeMismatch(Property, Err);
93 return nullptr;
94 }
95 }
96
97 template <>
getProperty(omp_interop_val_t & InteropVal,omp_interop_property_t Property,int * Err)98 void *getProperty<void *>(omp_interop_val_t &InteropVal,
99 omp_interop_property_t Property, int *Err) {
100 switch (Property) {
101 case omp_ipr_device:
102 if (InteropVal.device_info.Device)
103 return InteropVal.device_info.Device;
104 *Err = omp_irc_no_value;
105 return const_cast<char *>(InteropVal.err_str);
106 case omp_ipr_device_context:
107 return InteropVal.device_info.Context;
108 case omp_ipr_targetsync:
109 return InteropVal.async_info->Queue;
110 default:;
111 }
112 getTypeMismatch(Property, Err);
113 return nullptr;
114 }
115
getPropertyCheck(omp_interop_val_t ** InteropPtr,omp_interop_property_t Property,int * Err)116 bool getPropertyCheck(omp_interop_val_t **InteropPtr,
117 omp_interop_property_t Property, int *Err) {
118 if (Err)
119 *Err = omp_irc_success;
120 if (!InteropPtr) {
121 if (Err)
122 *Err = omp_irc_empty;
123 return false;
124 }
125 if (Property >= 0 || Property < omp_ipr_first) {
126 if (Err)
127 *Err = omp_irc_out_of_range;
128 return false;
129 }
130 if (Property == omp_ipr_targetsync &&
131 (*InteropPtr)->interop_type != kmp_interop_type_tasksync) {
132 if (Err)
133 *Err = omp_irc_other;
134 return false;
135 }
136 if ((Property == omp_ipr_device || Property == omp_ipr_device_context) &&
137 (*InteropPtr)->interop_type == kmp_interop_type_tasksync) {
138 if (Err)
139 *Err = omp_irc_other;
140 return false;
141 }
142 return true;
143 }
144
145 } // namespace
146
147 #define __OMP_GET_INTEROP_TY(RETURN_TYPE, SUFFIX) \
148 RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
149 omp_interop_property_t property_id, \
150 int *err) { \
151 omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
152 assert((interop_val)->interop_type == kmp_interop_type_tasksync); \
153 if (!getPropertyCheck(&interop_val, property_id, err)) { \
154 return (RETURN_TYPE)(0); \
155 } \
156 return getProperty<RETURN_TYPE>(*interop_val, property_id, err); \
157 }
158 __OMP_GET_INTEROP_TY(intptr_t, int)
159 __OMP_GET_INTEROP_TY(void *, ptr)
160 __OMP_GET_INTEROP_TY(const char *, str)
161 #undef __OMP_GET_INTEROP_TY
162
163 #define __OMP_GET_INTEROP_TY3(RETURN_TYPE, SUFFIX) \
164 RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \
165 omp_interop_property_t property_id) { \
166 int err; \
167 omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \
168 if (!getPropertyCheck(&interop_val, property_id, &err)) { \
169 return (RETURN_TYPE)(0); \
170 } \
171 return nullptr; \
172 return getProperty<RETURN_TYPE>(*interop_val, property_id, &err); \
173 }
174 __OMP_GET_INTEROP_TY3(const char *, name)
175 __OMP_GET_INTEROP_TY3(const char *, type_desc)
176 __OMP_GET_INTEROP_TY3(const char *, rc_desc)
177 #undef __OMP_GET_INTEROP_TY3
178
179 typedef int64_t kmp_int64;
180
181 #ifdef __cplusplus
182 extern "C" {
183 #endif
__tgt_interop_init(ident_t * LocRef,kmp_int32 Gtid,omp_interop_val_t * & InteropPtr,kmp_interop_type_t InteropType,kmp_int32 DeviceId,kmp_int64 Ndeps,kmp_depend_info_t * DepList,kmp_int32 HaveNowait)184 void __tgt_interop_init(ident_t *LocRef, kmp_int32 Gtid,
185 omp_interop_val_t *&InteropPtr,
186 kmp_interop_type_t InteropType, kmp_int32 DeviceId,
187 kmp_int64 Ndeps, kmp_depend_info_t *DepList,
188 kmp_int32 HaveNowait) {
189 kmp_int32 NdepsNoalias = 0;
190 kmp_depend_info_t *NoaliasDepList = NULL;
191 assert(InteropType != kmp_interop_type_unknown &&
192 "Cannot initialize with unknown interop_type!");
193 if (DeviceId == -1) {
194 DeviceId = omp_get_default_device();
195 }
196
197 if (InteropType == kmp_interop_type_tasksync) {
198 __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
199 NoaliasDepList);
200 }
201
202 InteropPtr = new omp_interop_val_t(DeviceId, InteropType);
203 if (!deviceIsReady(DeviceId)) {
204 InteropPtr->err_str = "Device not ready!";
205 return;
206 }
207
208 DeviceTy &Device = *PM->Devices[DeviceId];
209 if (!Device.RTL || !Device.RTL->init_device_info ||
210 Device.RTL->init_device_info(DeviceId, &(InteropPtr)->device_info,
211 &(InteropPtr)->err_str)) {
212 delete InteropPtr;
213 InteropPtr = omp_interop_none;
214 }
215 if (InteropType == kmp_interop_type_tasksync) {
216 if (!Device.RTL || !Device.RTL->init_async_info ||
217 Device.RTL->init_async_info(DeviceId, &(InteropPtr)->async_info)) {
218 delete InteropPtr;
219 InteropPtr = omp_interop_none;
220 }
221 }
222 }
223
__tgt_interop_use(ident_t * LocRef,kmp_int32 Gtid,omp_interop_val_t * & InteropPtr,kmp_int32 DeviceId,kmp_int32 Ndeps,kmp_depend_info_t * DepList,kmp_int32 HaveNowait)224 void __tgt_interop_use(ident_t *LocRef, kmp_int32 Gtid,
225 omp_interop_val_t *&InteropPtr, kmp_int32 DeviceId,
226 kmp_int32 Ndeps, kmp_depend_info_t *DepList,
227 kmp_int32 HaveNowait) {
228 kmp_int32 NdepsNoalias = 0;
229 kmp_depend_info_t *NoaliasDepList = NULL;
230 assert(InteropPtr && "Cannot use nullptr!");
231 omp_interop_val_t *InteropVal = InteropPtr;
232 if (DeviceId == -1) {
233 DeviceId = omp_get_default_device();
234 }
235 assert(InteropVal != omp_interop_none &&
236 "Cannot use uninitialized interop_ptr!");
237 assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
238 "Inconsistent device-id usage!");
239
240 if (!deviceIsReady(DeviceId)) {
241 InteropPtr->err_str = "Device not ready!";
242 return;
243 }
244
245 if (InteropVal->interop_type == kmp_interop_type_tasksync) {
246 __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
247 NoaliasDepList);
248 }
249 // TODO Flush the queue associated with the interop through the plugin
250 }
251
__tgt_interop_destroy(ident_t * LocRef,kmp_int32 Gtid,omp_interop_val_t * & InteropPtr,kmp_int32 DeviceId,kmp_int32 Ndeps,kmp_depend_info_t * DepList,kmp_int32 HaveNowait)252 void __tgt_interop_destroy(ident_t *LocRef, kmp_int32 Gtid,
253 omp_interop_val_t *&InteropPtr, kmp_int32 DeviceId,
254 kmp_int32 Ndeps, kmp_depend_info_t *DepList,
255 kmp_int32 HaveNowait) {
256 kmp_int32 NdepsNoalias = 0;
257 kmp_depend_info_t *NoaliasDepList = NULL;
258 assert(InteropPtr && "Cannot use nullptr!");
259 omp_interop_val_t *InteropVal = InteropPtr;
260 if (DeviceId == -1) {
261 DeviceId = omp_get_default_device();
262 }
263
264 if (InteropVal == omp_interop_none)
265 return;
266
267 assert((DeviceId == -1 || InteropVal->device_id == DeviceId) &&
268 "Inconsistent device-id usage!");
269 if (!deviceIsReady(DeviceId)) {
270 InteropPtr->err_str = "Device not ready!";
271 return;
272 }
273
274 if (InteropVal->interop_type == kmp_interop_type_tasksync) {
275 __kmpc_omp_wait_deps(LocRef, Gtid, Ndeps, DepList, NdepsNoalias,
276 NoaliasDepList);
277 }
278 // TODO Flush the queue associated with the interop through the plugin
279 // TODO Signal out dependences
280
281 delete InteropPtr;
282 InteropPtr = omp_interop_none;
283 }
284 #ifdef __cplusplus
285 } // extern "C"
286 #endif
287