1 //===-------- interface.cpp - Target independent OpenMP target RTL --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.txt for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Implementation of the interface to be used by Clang during the codegen of a
11 // target region.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include <omptarget.h>
16 
17 #include "device.h"
18 #include "private.h"
19 #include "rtl.h"
20 
21 #include <cassert>
22 #include <cstdlib>
23 #include <mutex>
24 
25 // Store target policy (disabled, mandatory, default)
26 kmp_target_offload_kind_t TargetOffloadPolicy = tgt_default;
27 std::mutex TargetOffloadMtx;
28 
29 ////////////////////////////////////////////////////////////////////////////////
30 /// manage the success or failure of a target constuct
31 
32 static void HandleDefaultTargetOffload() {
33   TargetOffloadMtx.lock();
34   if (TargetOffloadPolicy == tgt_default) {
35     if (omp_get_num_devices() > 0) {
36       DP("Default TARGET OFFLOAD policy is now mandatory "
37          "(devicew were found)\n");
38       TargetOffloadPolicy = tgt_mandatory;
39     } else {
40       DP("Default TARGET OFFLOAD policy is now disabled "
41          "(devices were not found)\n");
42       TargetOffloadPolicy = tgt_disabled;
43     }
44   }
45   TargetOffloadMtx.unlock();
46 }
47 
48 static int IsOffloadDisabled() {
49   if (TargetOffloadPolicy == tgt_default) HandleDefaultTargetOffload();
50   return TargetOffloadPolicy == tgt_disabled;
51 }
52 
53 static void HandleTargetOutcome(bool success) {
54   switch (TargetOffloadPolicy) {
55     case tgt_disabled:
56       if (success) {
57         FATAL_MESSAGE0(1, "expected no offloading while offloading is disabled");
58       }
59       break;
60     case tgt_default:
61         FATAL_MESSAGE0(1, "default offloading policy must switched to "
62             "mandatory or disabled");
63       break;
64     case tgt_mandatory:
65       if (!success) {
66         FATAL_MESSAGE0(1, "failure of target construct while offloading is mandatory");
67       }
68       break;
69   }
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// adds a target shared library to the target execution image
74 EXTERN void __tgt_register_lib(__tgt_bin_desc *desc) {
75   RTLs.RegisterLib(desc);
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 /// unloads a target shared library
80 EXTERN void __tgt_unregister_lib(__tgt_bin_desc *desc) {
81   RTLs.UnregisterLib(desc);
82 }
83 
84 /// creates host-to-target data mapping, stores it in the
85 /// libomptarget.so internal structure (an entry in a stack of data maps)
86 /// and passes the data to the device.
87 EXTERN void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
88     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
89   if (IsOffloadDisabled()) return;
90 
91   DP("Entering data begin region for device %" PRId64 " with %d mappings\n",
92       device_id, arg_num);
93 
94   // No devices available?
95   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
96     device_id = omp_get_default_device();
97     DP("Use default device id %" PRId64 "\n", device_id);
98   }
99 
100   if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
101     DP("Failed to get device %" PRId64 " ready\n", device_id);
102     HandleTargetOutcome(false);
103     return;
104   }
105 
106   DeviceTy& Device = Devices[device_id];
107 
108 #ifdef OMPTARGET_DEBUG
109   for (int i=0; i<arg_num; ++i) {
110     DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
111         ", Type=0x%" PRIx64 "\n", i, DPxPTR(args_base[i]), DPxPTR(args[i]),
112         arg_sizes[i], arg_types[i]);
113   }
114 #endif
115 
116   int rc = target_data_begin(Device, arg_num, args_base,
117       args, arg_sizes, arg_types);
118   HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
119 }
120 
121 EXTERN void __tgt_target_data_begin_nowait(int64_t device_id, int32_t arg_num,
122     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types,
123     int32_t depNum, void *depList, int32_t noAliasDepNum,
124     void *noAliasDepList) {
125   if (depNum + noAliasDepNum > 0)
126     __kmpc_omp_taskwait(NULL, 0);
127 
128   __tgt_target_data_begin(device_id, arg_num, args_base, args, arg_sizes,
129                           arg_types);
130 }
131 
132 /// passes data from the target, releases target memory and destroys
133 /// the host-target mapping (top entry from the stack of data maps)
134 /// created by the last __tgt_target_data_begin.
135 EXTERN void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
136     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
137   if (IsOffloadDisabled()) return;
138   DP("Entering data end region with %d mappings\n", arg_num);
139 
140   // No devices available?
141   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
142     device_id = omp_get_default_device();
143   }
144 
145   RTLsMtx.lock();
146   size_t Devices_size = Devices.size();
147   RTLsMtx.unlock();
148   if (Devices_size <= (size_t)device_id) {
149     DP("Device ID  %" PRId64 " does not have a matching RTL.\n", device_id);
150     HandleTargetOutcome(false);
151     return;
152   }
153 
154   DeviceTy &Device = Devices[device_id];
155   if (!Device.IsInit) {
156     DP("Uninit device: ignore");
157     HandleTargetOutcome(false);
158     return;
159   }
160 
161 #ifdef OMPTARGET_DEBUG
162   for (int i=0; i<arg_num; ++i) {
163     DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
164         ", Type=0x%" PRIx64 "\n", i, DPxPTR(args_base[i]), DPxPTR(args[i]),
165         arg_sizes[i], arg_types[i]);
166   }
167 #endif
168 
169   int rc = target_data_end(Device, arg_num, args_base,
170       args, arg_sizes, arg_types);
171   HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
172 }
173 
174 EXTERN void __tgt_target_data_end_nowait(int64_t device_id, int32_t arg_num,
175     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types,
176     int32_t depNum, void *depList, int32_t noAliasDepNum,
177     void *noAliasDepList) {
178   if (depNum + noAliasDepNum > 0)
179     __kmpc_omp_taskwait(NULL, 0);
180 
181   __tgt_target_data_end(device_id, arg_num, args_base, args, arg_sizes,
182                         arg_types);
183 }
184 
185 EXTERN void __tgt_target_data_update(int64_t device_id, int32_t arg_num,
186     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
187   if (IsOffloadDisabled()) return;
188   DP("Entering data update with %d mappings\n", arg_num);
189 
190   // No devices available?
191   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
192     device_id = omp_get_default_device();
193   }
194 
195   if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
196     DP("Failed to get device %" PRId64 " ready\n", device_id);
197     HandleTargetOutcome(false);
198     return;
199   }
200 
201   DeviceTy& Device = Devices[device_id];
202   int rc = target_data_update(Device, arg_num, args_base,
203       args, arg_sizes, arg_types);
204   HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
205 }
206 
207 EXTERN void __tgt_target_data_update_nowait(
208     int64_t device_id, int32_t arg_num, void **args_base, void **args,
209     int64_t *arg_sizes, int64_t *arg_types, int32_t depNum, void *depList,
210     int32_t noAliasDepNum, void *noAliasDepList) {
211   if (depNum + noAliasDepNum > 0)
212     __kmpc_omp_taskwait(NULL, 0);
213 
214   __tgt_target_data_update(device_id, arg_num, args_base, args, arg_sizes,
215                            arg_types);
216 }
217 
218 EXTERN int __tgt_target(int64_t device_id, void *host_ptr, int32_t arg_num,
219     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
220   if (IsOffloadDisabled()) return OFFLOAD_FAIL;
221   DP("Entering target region with entry point " DPxMOD " and device Id %"
222       PRId64 "\n", DPxPTR(host_ptr), device_id);
223 
224   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
225     device_id = omp_get_default_device();
226   }
227 
228   if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
229     DP("Failed to get device %" PRId64 " ready\n", device_id);
230     HandleTargetOutcome(false);
231     return OFFLOAD_FAIL;
232   }
233 
234 #ifdef OMPTARGET_DEBUG
235   for (int i=0; i<arg_num; ++i) {
236     DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
237         ", Type=0x%" PRIx64 "\n", i, DPxPTR(args_base[i]), DPxPTR(args[i]),
238         arg_sizes[i], arg_types[i]);
239   }
240 #endif
241 
242   int rc = target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
243       arg_types, 0, 0, false /*team*/);
244   HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
245   return rc;
246 }
247 
248 EXTERN int __tgt_target_nowait(int64_t device_id, void *host_ptr,
249     int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes,
250     int64_t *arg_types, int32_t depNum, void *depList, int32_t noAliasDepNum,
251     void *noAliasDepList) {
252   if (depNum + noAliasDepNum > 0)
253     __kmpc_omp_taskwait(NULL, 0);
254 
255   return __tgt_target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
256                       arg_types);
257 }
258 
259 EXTERN int __tgt_target_teams(int64_t device_id, void *host_ptr,
260     int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes,
261     int64_t *arg_types, int32_t team_num, int32_t thread_limit) {
262   if (IsOffloadDisabled()) return OFFLOAD_FAIL;
263   DP("Entering target region with entry point " DPxMOD " and device Id %"
264       PRId64 "\n", DPxPTR(host_ptr), device_id);
265 
266   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
267     device_id = omp_get_default_device();
268   }
269 
270   if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
271     DP("Failed to get device %" PRId64 " ready\n", device_id);
272     HandleTargetOutcome(false);
273     return OFFLOAD_FAIL;
274   }
275 
276 #ifdef OMPTARGET_DEBUG
277   for (int i=0; i<arg_num; ++i) {
278     DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
279         ", Type=0x%" PRIx64 "\n", i, DPxPTR(args_base[i]), DPxPTR(args[i]),
280         arg_sizes[i], arg_types[i]);
281   }
282 #endif
283 
284   int rc = target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
285       arg_types, team_num, thread_limit, true /*team*/);
286   HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
287 
288   return rc;
289 }
290 
291 EXTERN int __tgt_target_teams_nowait(int64_t device_id, void *host_ptr,
292     int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes,
293     int64_t *arg_types, int32_t team_num, int32_t thread_limit, int32_t depNum,
294     void *depList, int32_t noAliasDepNum, void *noAliasDepList) {
295   if (depNum + noAliasDepNum > 0)
296     __kmpc_omp_taskwait(NULL, 0);
297 
298   return __tgt_target_teams(device_id, host_ptr, arg_num, args_base, args,
299                             arg_sizes, arg_types, team_num, thread_limit);
300 }
301 
302 
303 // The trip count mechanism will be revised - this scheme is not thread-safe.
304 EXTERN void __kmpc_push_target_tripcount(int64_t device_id,
305     uint64_t loop_tripcount) {
306   if (device_id == OFFLOAD_DEVICE_DEFAULT) {
307     device_id = omp_get_default_device();
308   }
309 
310   if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
311     DP("Failed to get device %" PRId64 " ready\n", device_id);
312     HandleTargetOutcome(false);
313     return;
314   }
315 
316   DP("__kmpc_push_target_tripcount(%" PRId64 ", %" PRIu64 ")\n", device_id,
317       loop_tripcount);
318   Devices[device_id].loopTripCnt = loop_tripcount;
319 }
320