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