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 { 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 37 void getTypeMismatch(omp_interop_property_t Property, int *Err) { 38 if (Err) 39 *Err = getPropertyErrorType(Property); 40 } 41 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 <> 65 intptr_t getProperty<intptr_t>(omp_interop_val_t &interop_val, 66 omp_interop_property_t property, int *err) { 67 switch (property) { 68 case omp_ipr_fr_id: 69 return interop_val.backend_type_id; 70 case omp_ipr_vendor: 71 return interop_val.vendor_id; 72 case omp_ipr_device_num: 73 return interop_val.device_id; 74 default:; 75 } 76 getTypeMismatch(property, err); 77 return 0; 78 } 79 80 template <> 81 const char *getProperty<const char *>(omp_interop_val_t &interop_val, 82 omp_interop_property_t property, 83 int *err) { 84 switch (property) { 85 case omp_ipr_fr_id: 86 return interop_val.interop_type == kmp_interop_type_tasksync 87 ? "tasksync" 88 : "device+context"; 89 case omp_ipr_vendor_name: 90 return getVendorIdToStr(interop_val.vendor_id); 91 default: 92 getTypeMismatch(property, err); 93 return nullptr; 94 } 95 } 96 97 template <> 98 void *getProperty<void *>(omp_interop_val_t &interop_val, 99 omp_interop_property_t property, int *err) { 100 switch (property) { 101 case omp_ipr_device: 102 if (interop_val.device_info.Device) 103 return interop_val.device_info.Device; 104 *err = omp_irc_no_value; 105 return const_cast<char *>(interop_val.err_str); 106 case omp_ipr_device_context: 107 return interop_val.device_info.Context; 108 case omp_ipr_targetsync: 109 return interop_val.async_info->Queue; 110 default:; 111 } 112 getTypeMismatch(property, err); 113 return nullptr; 114 } 115 116 bool getPropertyCheck(omp_interop_val_t **interop_ptr, 117 omp_interop_property_t property, int *err) { 118 if (err) 119 *err = omp_irc_success; 120 if (!interop_ptr) { 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 (*interop_ptr)->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 (*interop_ptr)->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 184 void __tgt_interop_init(ident_t *loc_ref, kmp_int32 gtid, 185 omp_interop_val_t *&interop_ptr, 186 kmp_interop_type_t interop_type, kmp_int32 device_id, 187 kmp_int64 ndeps, kmp_depend_info_t *dep_list, 188 kmp_int32 have_nowait) { 189 kmp_int32 ndeps_noalias = 0; 190 kmp_depend_info_t *noalias_dep_list = NULL; 191 assert(interop_type != kmp_interop_type_unknown && 192 "Cannot initialize with unknown interop_type!"); 193 if (device_id == -1) { 194 device_id = omp_get_default_device(); 195 } 196 197 if (interop_type == kmp_interop_type_tasksync) { 198 __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, 199 noalias_dep_list); 200 } 201 202 interop_ptr = new omp_interop_val_t(device_id, interop_type); 203 if (!device_is_ready(device_id)) { 204 interop_ptr->err_str = "Device not ready!"; 205 return; 206 } 207 208 DeviceTy &Device = *PM->Devices[device_id]; 209 if (!Device.RTL || !Device.RTL->init_device_info || 210 Device.RTL->init_device_info(device_id, &(interop_ptr)->device_info, 211 &(interop_ptr)->err_str)) { 212 delete interop_ptr; 213 interop_ptr = omp_interop_none; 214 } 215 if (interop_type == kmp_interop_type_tasksync) { 216 if (!Device.RTL || !Device.RTL->init_async_info || 217 Device.RTL->init_async_info(device_id, &(interop_ptr)->async_info)) { 218 delete interop_ptr; 219 interop_ptr = omp_interop_none; 220 } 221 } 222 } 223 224 void __tgt_interop_use(ident_t *loc_ref, kmp_int32 gtid, 225 omp_interop_val_t *&interop_ptr, kmp_int32 device_id, 226 kmp_int32 ndeps, kmp_depend_info_t *dep_list, 227 kmp_int32 have_nowait) { 228 kmp_int32 ndeps_noalias = 0; 229 kmp_depend_info_t *noalias_dep_list = NULL; 230 assert(interop_ptr && "Cannot use nullptr!"); 231 omp_interop_val_t *interop_val = interop_ptr; 232 if (device_id == -1) { 233 device_id = omp_get_default_device(); 234 } 235 assert(interop_val != omp_interop_none && 236 "Cannot use uninitialized interop_ptr!"); 237 assert((device_id == -1 || interop_val->device_id == device_id) && 238 "Inconsistent device-id usage!"); 239 240 if (!device_is_ready(device_id)) { 241 interop_ptr->err_str = "Device not ready!"; 242 return; 243 } 244 245 if (interop_val->interop_type == kmp_interop_type_tasksync) { 246 __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, 247 noalias_dep_list); 248 } 249 // TODO Flush the queue associated with the interop through the plugin 250 } 251 252 void __tgt_interop_destroy(ident_t *loc_ref, kmp_int32 gtid, 253 omp_interop_val_t *&interop_ptr, kmp_int32 device_id, 254 kmp_int32 ndeps, kmp_depend_info_t *dep_list, 255 kmp_int32 have_nowait) { 256 kmp_int32 ndeps_noalias = 0; 257 kmp_depend_info_t *noalias_dep_list = NULL; 258 assert(interop_ptr && "Cannot use nullptr!"); 259 omp_interop_val_t *interop_val = interop_ptr; 260 if (device_id == -1) { 261 device_id = omp_get_default_device(); 262 } 263 264 if (interop_val == omp_interop_none) 265 return; 266 267 assert((device_id == -1 || interop_val->device_id == device_id) && 268 "Inconsistent device-id usage!"); 269 if (!device_is_ready(device_id)) { 270 interop_ptr->err_str = "Device not ready!"; 271 return; 272 } 273 274 if (interop_val->interop_type == kmp_interop_type_tasksync) { 275 __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, 276 noalias_dep_list); 277 } 278 // TODO Flush the queue associated with the interop through the plugin 279 // TODO Signal out dependences 280 281 delete interop_ptr; 282 interop_ptr = omp_interop_none; 283 } 284 #ifdef __cplusplus 285 } // extern "C" 286 #endif 287