1 //===------ omptarget.cpp - Target independent OpenMP target RTL -- C++ -*-===//
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 // Implementation of the interface to be used by Clang during the codegen of a
10 // target region.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include <omptarget.h>
15 
16 #include "device.h"
17 #include "private.h"
18 #include "rtl.h"
19 
20 #include <cassert>
21 #include <vector>
22 
23 #ifdef OMPTARGET_DEBUG
24 int DebugLevel = 0;
25 #endif // OMPTARGET_DEBUG
26 
27 
28 
29 /* All begin addresses for partially mapped structs must be 8-aligned in order
30  * to ensure proper alignment of members. E.g.
31  *
32  * struct S {
33  *   int a;   // 4-aligned
34  *   int b;   // 4-aligned
35  *   int *p;  // 8-aligned
36  * } s1;
37  * ...
38  * #pragma omp target map(tofrom: s1.b, s1.p[0:N])
39  * {
40  *   s1.b = 5;
41  *   for (int i...) s1.p[i] = ...;
42  * }
43  *
44  * Here we are mapping s1 starting from member b, so BaseAddress=&s1=&s1.a and
45  * BeginAddress=&s1.b. Let's assume that the struct begins at address 0x100,
46  * then &s1.a=0x100, &s1.b=0x104, &s1.p=0x108. Each member obeys the alignment
47  * requirements for its type. Now, when we allocate memory on the device, in
48  * CUDA's case cuMemAlloc() returns an address which is at least 256-aligned.
49  * This means that the chunk of the struct on the device will start at a
50  * 256-aligned address, let's say 0x200. Then the address of b will be 0x200 and
51  * address of p will be a misaligned 0x204 (on the host there was no need to add
52  * padding between b and p, so p comes exactly 4 bytes after b). If the device
53  * kernel tries to access s1.p, a misaligned address error occurs (as reported
54  * by the CUDA plugin). By padding the begin address down to a multiple of 8 and
55  * extending the size of the allocated chuck accordingly, the chuck on the
56  * device will start at 0x200 with the padding (4 bytes), then &s1.b=0x204 and
57  * &s1.p=0x208, as they should be to satisfy the alignment requirements.
58  */
59 static const int64_t alignment = 8;
60 
61 /// Map global data and execute pending ctors
62 static int InitLibrary(DeviceTy& Device) {
63   /*
64    * Map global data
65    */
66   int32_t device_id = Device.DeviceID;
67   int rc = OFFLOAD_SUCCESS;
68 
69   Device.PendingGlobalsMtx.lock();
70   TrlTblMtx.lock();
71   for (HostEntriesBeginToTransTableTy::iterator
72       ii = HostEntriesBeginToTransTable.begin();
73       ii != HostEntriesBeginToTransTable.end(); ++ii) {
74     TranslationTable *TransTable = &ii->second;
75     if (TransTable->TargetsTable[device_id] != 0) {
76       // Library entries have already been processed
77       continue;
78     }
79 
80     // 1) get image.
81     assert(TransTable->TargetsImages.size() > (size_t)device_id &&
82            "Not expecting a device ID outside the table's bounds!");
83     __tgt_device_image *img = TransTable->TargetsImages[device_id];
84     if (!img) {
85       DP("No image loaded for device id %d.\n", device_id);
86       rc = OFFLOAD_FAIL;
87       break;
88     }
89     // 2) load image into the target table.
90     __tgt_target_table *TargetTable =
91         TransTable->TargetsTable[device_id] = Device.load_binary(img);
92     // Unable to get table for this image: invalidate image and fail.
93     if (!TargetTable) {
94       DP("Unable to generate entries table for device id %d.\n", device_id);
95       TransTable->TargetsImages[device_id] = 0;
96       rc = OFFLOAD_FAIL;
97       break;
98     }
99 
100     // Verify whether the two table sizes match.
101     size_t hsize =
102         TransTable->HostTable.EntriesEnd - TransTable->HostTable.EntriesBegin;
103     size_t tsize = TargetTable->EntriesEnd - TargetTable->EntriesBegin;
104 
105     // Invalid image for these host entries!
106     if (hsize != tsize) {
107       DP("Host and Target tables mismatch for device id %d [%zx != %zx].\n",
108          device_id, hsize, tsize);
109       TransTable->TargetsImages[device_id] = 0;
110       TransTable->TargetsTable[device_id] = 0;
111       rc = OFFLOAD_FAIL;
112       break;
113     }
114 
115     // process global data that needs to be mapped.
116     Device.DataMapMtx.lock();
117     __tgt_target_table *HostTable = &TransTable->HostTable;
118     for (__tgt_offload_entry *CurrDeviceEntry = TargetTable->EntriesBegin,
119                              *CurrHostEntry = HostTable->EntriesBegin,
120                              *EntryDeviceEnd = TargetTable->EntriesEnd;
121          CurrDeviceEntry != EntryDeviceEnd;
122          CurrDeviceEntry++, CurrHostEntry++) {
123       if (CurrDeviceEntry->size != 0) {
124         // has data.
125         assert(CurrDeviceEntry->size == CurrHostEntry->size &&
126                "data size mismatch");
127 
128         // Fortran may use multiple weak declarations for the same symbol,
129         // therefore we must allow for multiple weak symbols to be loaded from
130         // the fat binary. Treat these mappings as any other "regular" mapping.
131         // Add entry to map.
132         if (Device.getTgtPtrBegin(CurrHostEntry->addr, CurrHostEntry->size))
133           continue;
134         DP("Add mapping from host " DPxMOD " to device " DPxMOD " with size %zu"
135             "\n", DPxPTR(CurrHostEntry->addr), DPxPTR(CurrDeviceEntry->addr),
136             CurrDeviceEntry->size);
137         Device.HostDataToTargetMap.push_front(HostDataToTargetTy(
138             (uintptr_t)CurrHostEntry->addr /*HstPtrBase*/,
139             (uintptr_t)CurrHostEntry->addr /*HstPtrBegin*/,
140             (uintptr_t)CurrHostEntry->addr + CurrHostEntry->size /*HstPtrEnd*/,
141             (uintptr_t)CurrDeviceEntry->addr /*TgtPtrBegin*/,
142             INF_REF_CNT /*RefCount*/));
143       }
144     }
145     Device.DataMapMtx.unlock();
146   }
147   TrlTblMtx.unlock();
148 
149   if (rc != OFFLOAD_SUCCESS) {
150     Device.PendingGlobalsMtx.unlock();
151     return rc;
152   }
153 
154   /*
155    * Run ctors for static objects
156    */
157   if (!Device.PendingCtorsDtors.empty()) {
158     // Call all ctors for all libraries registered so far
159     for (auto &lib : Device.PendingCtorsDtors) {
160       if (!lib.second.PendingCtors.empty()) {
161         DP("Has pending ctors... call now\n");
162         for (auto &entry : lib.second.PendingCtors) {
163           void *ctor = entry;
164           int rc = target(device_id, ctor, 0, NULL, NULL, NULL,
165                           NULL, 1, 1, true /*team*/);
166           if (rc != OFFLOAD_SUCCESS) {
167             DP("Running ctor " DPxMOD " failed.\n", DPxPTR(ctor));
168             Device.PendingGlobalsMtx.unlock();
169             return OFFLOAD_FAIL;
170           }
171         }
172         // Clear the list to indicate that this device has been used
173         lib.second.PendingCtors.clear();
174         DP("Done with pending ctors for lib " DPxMOD "\n", DPxPTR(lib.first));
175       }
176     }
177   }
178   Device.HasPendingGlobals = false;
179   Device.PendingGlobalsMtx.unlock();
180 
181   return OFFLOAD_SUCCESS;
182 }
183 
184 // Check whether a device has been initialized, global ctors have been
185 // executed and global data has been mapped; do so if not already done.
186 int CheckDeviceAndCtors(int64_t device_id) {
187   // Is device ready?
188   if (!device_is_ready(device_id)) {
189     DP("Device %" PRId64 " is not ready.\n", device_id);
190     return OFFLOAD_FAIL;
191   }
192 
193   // Get device info.
194   DeviceTy &Device = Devices[device_id];
195 
196   // Check whether global data has been mapped for this device
197   Device.PendingGlobalsMtx.lock();
198   bool hasPendingGlobals = Device.HasPendingGlobals;
199   Device.PendingGlobalsMtx.unlock();
200   if (hasPendingGlobals && InitLibrary(Device) != OFFLOAD_SUCCESS) {
201     DP("Failed to init globals on device %" PRId64 "\n", device_id);
202     return OFFLOAD_FAIL;
203   }
204 
205   return OFFLOAD_SUCCESS;
206 }
207 
208 static int32_t member_of(int64_t type) {
209   return ((type & OMP_TGT_MAPTYPE_MEMBER_OF) >> 48) - 1;
210 }
211 
212 /// Internal function to do the mapping and transfer the data to the device
213 int target_data_begin(DeviceTy &Device, int32_t arg_num,
214     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
215   // process each input.
216   for (int32_t i = 0; i < arg_num; ++i) {
217     // Ignore private variables and arrays - there is no mapping for them.
218     if ((arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) ||
219         (arg_types[i] & OMP_TGT_MAPTYPE_PRIVATE))
220       continue;
221 
222     void *HstPtrBegin = args[i];
223     void *HstPtrBase = args_base[i];
224     int64_t data_size = arg_sizes[i];
225 
226     // Adjust for proper alignment if this is a combined entry (for structs).
227     // Look at the next argument - if that is MEMBER_OF this one, then this one
228     // is a combined entry.
229     int64_t padding = 0;
230     const int next_i = i+1;
231     if (member_of(arg_types[i]) < 0 && next_i < arg_num &&
232         member_of(arg_types[next_i]) == i) {
233       padding = (int64_t)HstPtrBegin % alignment;
234       if (padding) {
235         DP("Using a padding of %" PRId64 " bytes for begin address " DPxMOD
236             "\n", padding, DPxPTR(HstPtrBegin));
237         HstPtrBegin = (char *) HstPtrBegin - padding;
238         data_size += padding;
239       }
240     }
241 
242     // Address of pointer on the host and device, respectively.
243     void *Pointer_HstPtrBegin, *Pointer_TgtPtrBegin;
244     bool IsNew, Pointer_IsNew;
245     bool IsImplicit = arg_types[i] & OMP_TGT_MAPTYPE_IMPLICIT;
246     // UpdateRef is based on MEMBER_OF instead of TARGET_PARAM because if we
247     // have reached this point via __tgt_target_data_begin and not __tgt_target
248     // then no argument is marked as TARGET_PARAM ("omp target data map" is not
249     // associated with a target region, so there are no target parameters). This
250     // may be considered a hack, we could revise the scheme in the future.
251     bool UpdateRef = !(arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF);
252     if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ) {
253       DP("Has a pointer entry: \n");
254       // base is address of pointer.
255       Pointer_TgtPtrBegin = Device.getOrAllocTgtPtr(HstPtrBase, HstPtrBase,
256           sizeof(void *), Pointer_IsNew, IsImplicit, UpdateRef);
257       if (!Pointer_TgtPtrBegin) {
258         DP("Call to getOrAllocTgtPtr returned null pointer (device failure or "
259             "illegal mapping).\n");
260         return OFFLOAD_FAIL;
261       }
262       DP("There are %zu bytes allocated at target address " DPxMOD " - is%s new"
263           "\n", sizeof(void *), DPxPTR(Pointer_TgtPtrBegin),
264           (Pointer_IsNew ? "" : " not"));
265       Pointer_HstPtrBegin = HstPtrBase;
266       // modify current entry.
267       HstPtrBase = *(void **)HstPtrBase;
268       UpdateRef = true; // subsequently update ref count of pointee
269     }
270 
271     void *TgtPtrBegin = Device.getOrAllocTgtPtr(HstPtrBegin, HstPtrBase,
272         data_size, IsNew, IsImplicit, UpdateRef);
273     if (!TgtPtrBegin && data_size) {
274       // If data_size==0, then the argument could be a zero-length pointer to
275       // NULL, so getOrAlloc() returning NULL is not an error.
276       DP("Call to getOrAllocTgtPtr returned null pointer (device failure or "
277           "illegal mapping).\n");
278     }
279     DP("There are %" PRId64 " bytes allocated at target address " DPxMOD
280         " - is%s new\n", data_size, DPxPTR(TgtPtrBegin),
281         (IsNew ? "" : " not"));
282 
283     if (arg_types[i] & OMP_TGT_MAPTYPE_RETURN_PARAM) {
284       uintptr_t Delta = (uintptr_t)HstPtrBegin - (uintptr_t)HstPtrBase;
285       void *TgtPtrBase = (void *)((uintptr_t)TgtPtrBegin - Delta);
286       DP("Returning device pointer " DPxMOD "\n", DPxPTR(TgtPtrBase));
287       args_base[i] = TgtPtrBase;
288     }
289 
290     if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
291       bool copy = false;
292       if (IsNew || (arg_types[i] & OMP_TGT_MAPTYPE_ALWAYS)) {
293         copy = true;
294       } else if (arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) {
295         // Copy data only if the "parent" struct has RefCount==1.
296         int32_t parent_idx = member_of(arg_types[i]);
297         long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
298         assert(parent_rc > 0 && "parent struct not found");
299         if (parent_rc == 1) {
300           copy = true;
301         }
302       }
303 
304       if (copy) {
305         DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n",
306             data_size, DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBegin));
307         int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, data_size);
308         if (rt != OFFLOAD_SUCCESS) {
309           DP("Copying data to device failed.\n");
310           return OFFLOAD_FAIL;
311         }
312       }
313     }
314 
315     if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ) {
316       DP("Update pointer (" DPxMOD ") -> [" DPxMOD "]\n",
317           DPxPTR(Pointer_TgtPtrBegin), DPxPTR(TgtPtrBegin));
318       uint64_t Delta = (uint64_t)HstPtrBegin - (uint64_t)HstPtrBase;
319       void *TgtPtrBase = (void *)((uint64_t)TgtPtrBegin - Delta);
320       int rt = Device.data_submit(Pointer_TgtPtrBegin, &TgtPtrBase,
321           sizeof(void *));
322       if (rt != OFFLOAD_SUCCESS) {
323         DP("Copying data to device failed.\n");
324         return OFFLOAD_FAIL;
325       }
326       // create shadow pointers for this entry
327       Device.ShadowMtx.lock();
328       Device.ShadowPtrMap[Pointer_HstPtrBegin] = {HstPtrBase,
329           Pointer_TgtPtrBegin, TgtPtrBase};
330       Device.ShadowMtx.unlock();
331     }
332   }
333 
334   return OFFLOAD_SUCCESS;
335 }
336 
337 /// Internal function to undo the mapping and retrieve the data from the device.
338 int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
339     void **args, int64_t *arg_sizes, int64_t *arg_types) {
340   // process each input.
341   for (int32_t i = arg_num - 1; i >= 0; --i) {
342     // Ignore private variables and arrays - there is no mapping for them.
343     // Also, ignore the use_device_ptr directive, it has no effect here.
344     if ((arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) ||
345         (arg_types[i] & OMP_TGT_MAPTYPE_PRIVATE))
346       continue;
347 
348     void *HstPtrBegin = args[i];
349     int64_t data_size = arg_sizes[i];
350     // Adjust for proper alignment if this is a combined entry (for structs).
351     // Look at the next argument - if that is MEMBER_OF this one, then this one
352     // is a combined entry.
353     int64_t padding = 0;
354     const int next_i = i+1;
355     if (member_of(arg_types[i]) < 0 && next_i < arg_num &&
356         member_of(arg_types[next_i]) == i) {
357       padding = (int64_t)HstPtrBegin % alignment;
358       if (padding) {
359         DP("Using a padding of %" PRId64 " bytes for begin address " DPxMOD
360             "\n", padding, DPxPTR(HstPtrBegin));
361         HstPtrBegin = (char *) HstPtrBegin - padding;
362         data_size += padding;
363       }
364     }
365 
366     bool IsLast;
367     bool UpdateRef = !(arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) ||
368         (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ);
369     bool ForceDelete = arg_types[i] & OMP_TGT_MAPTYPE_DELETE;
370 
371     // If PTR_AND_OBJ, HstPtrBegin is address of pointee
372     void *TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, data_size, IsLast,
373         UpdateRef);
374     DP("There are %" PRId64 " bytes allocated at target address " DPxMOD
375         " - is%s last\n", data_size, DPxPTR(TgtPtrBegin),
376         (IsLast ? "" : " not"));
377 
378     bool DelEntry = IsLast || ForceDelete;
379 
380     if ((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
381         !(arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ)) {
382       DelEntry = false; // protect parent struct from being deallocated
383     }
384 
385     if ((arg_types[i] & OMP_TGT_MAPTYPE_FROM) || DelEntry) {
386       // Move data back to the host
387       if (arg_types[i] & OMP_TGT_MAPTYPE_FROM) {
388         bool Always = arg_types[i] & OMP_TGT_MAPTYPE_ALWAYS;
389         bool CopyMember = false;
390         if ((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
391             !(arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ)) {
392           // Copy data only if the "parent" struct has RefCount==1.
393           int32_t parent_idx = member_of(arg_types[i]);
394           long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
395           assert(parent_rc > 0 && "parent struct not found");
396           if (parent_rc == 1) {
397             CopyMember = true;
398           }
399         }
400 
401         if (DelEntry || Always || CopyMember) {
402           DP("Moving %" PRId64 " bytes (tgt:" DPxMOD ") -> (hst:" DPxMOD ")\n",
403               data_size, DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBegin));
404           int rt = Device.data_retrieve(HstPtrBegin, TgtPtrBegin, data_size);
405           if (rt != OFFLOAD_SUCCESS) {
406             DP("Copying data from device failed.\n");
407             return OFFLOAD_FAIL;
408           }
409         }
410       }
411 
412       // If we copied back to the host a struct/array containing pointers, we
413       // need to restore the original host pointer values from their shadow
414       // copies. If the struct is going to be deallocated, remove any remaining
415       // shadow pointer entries for this struct.
416       uintptr_t lb = (uintptr_t) HstPtrBegin;
417       uintptr_t ub = (uintptr_t) HstPtrBegin + data_size;
418       Device.ShadowMtx.lock();
419       for (ShadowPtrListTy::iterator it = Device.ShadowPtrMap.begin();
420            it != Device.ShadowPtrMap.end();) {
421         void **ShadowHstPtrAddr = (void**) it->first;
422 
423         // An STL map is sorted on its keys; use this property
424         // to quickly determine when to break out of the loop.
425         if ((uintptr_t) ShadowHstPtrAddr < lb) {
426           ++it;
427           continue;
428         }
429         if ((uintptr_t) ShadowHstPtrAddr >= ub)
430           break;
431 
432         // If we copied the struct to the host, we need to restore the pointer.
433         if (arg_types[i] & OMP_TGT_MAPTYPE_FROM) {
434           DP("Restoring original host pointer value " DPxMOD " for host "
435               "pointer " DPxMOD "\n", DPxPTR(it->second.HstPtrVal),
436               DPxPTR(ShadowHstPtrAddr));
437           *ShadowHstPtrAddr = it->second.HstPtrVal;
438         }
439         // If the struct is to be deallocated, remove the shadow entry.
440         if (DelEntry) {
441           DP("Removing shadow pointer " DPxMOD "\n", DPxPTR(ShadowHstPtrAddr));
442           it = Device.ShadowPtrMap.erase(it);
443         } else {
444           ++it;
445         }
446       }
447       Device.ShadowMtx.unlock();
448 
449       // Deallocate map
450       if (DelEntry) {
451         int rt = Device.deallocTgtPtr(HstPtrBegin, data_size, ForceDelete);
452         if (rt != OFFLOAD_SUCCESS) {
453           DP("Deallocating data from device failed.\n");
454           return OFFLOAD_FAIL;
455         }
456       }
457     }
458   }
459 
460   return OFFLOAD_SUCCESS;
461 }
462 
463 /// Internal function to pass data to/from the target.
464 int target_data_update(DeviceTy &Device, int32_t arg_num,
465     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
466   // process each input.
467   for (int32_t i = 0; i < arg_num; ++i) {
468     if ((arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) ||
469         (arg_types[i] & OMP_TGT_MAPTYPE_PRIVATE))
470       continue;
471 
472     void *HstPtrBegin = args[i];
473     int64_t MapSize = arg_sizes[i];
474     bool IsLast;
475     void *TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, MapSize, IsLast,
476         false);
477     if (!TgtPtrBegin) {
478       DP("hst data:" DPxMOD " not found, becomes a noop\n", DPxPTR(HstPtrBegin));
479       continue;
480     }
481 
482     if (arg_types[i] & OMP_TGT_MAPTYPE_FROM) {
483       DP("Moving %" PRId64 " bytes (tgt:" DPxMOD ") -> (hst:" DPxMOD ")\n",
484           arg_sizes[i], DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBegin));
485       int rt = Device.data_retrieve(HstPtrBegin, TgtPtrBegin, MapSize);
486       if (rt != OFFLOAD_SUCCESS) {
487         DP("Copying data from device failed.\n");
488         return OFFLOAD_FAIL;
489       }
490 
491       uintptr_t lb = (uintptr_t) HstPtrBegin;
492       uintptr_t ub = (uintptr_t) HstPtrBegin + MapSize;
493       Device.ShadowMtx.lock();
494       for (ShadowPtrListTy::iterator it = Device.ShadowPtrMap.begin();
495           it != Device.ShadowPtrMap.end(); ++it) {
496         void **ShadowHstPtrAddr = (void**) it->first;
497         if ((uintptr_t) ShadowHstPtrAddr < lb)
498           continue;
499         if ((uintptr_t) ShadowHstPtrAddr >= ub)
500           break;
501         DP("Restoring original host pointer value " DPxMOD " for host pointer "
502             DPxMOD "\n", DPxPTR(it->second.HstPtrVal),
503             DPxPTR(ShadowHstPtrAddr));
504         *ShadowHstPtrAddr = it->second.HstPtrVal;
505       }
506       Device.ShadowMtx.unlock();
507     }
508 
509     if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
510       DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n",
511           arg_sizes[i], DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBegin));
512       int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, MapSize);
513       if (rt != OFFLOAD_SUCCESS) {
514         DP("Copying data to device failed.\n");
515         return OFFLOAD_FAIL;
516       }
517       uintptr_t lb = (uintptr_t) HstPtrBegin;
518       uintptr_t ub = (uintptr_t) HstPtrBegin + MapSize;
519       Device.ShadowMtx.lock();
520       for (ShadowPtrListTy::iterator it = Device.ShadowPtrMap.begin();
521           it != Device.ShadowPtrMap.end(); ++it) {
522         void **ShadowHstPtrAddr = (void**) it->first;
523         if ((uintptr_t) ShadowHstPtrAddr < lb)
524           continue;
525         if ((uintptr_t) ShadowHstPtrAddr >= ub)
526           break;
527         DP("Restoring original target pointer value " DPxMOD " for target "
528             "pointer " DPxMOD "\n", DPxPTR(it->second.TgtPtrVal),
529             DPxPTR(it->second.TgtPtrAddr));
530         rt = Device.data_submit(it->second.TgtPtrAddr,
531             &it->second.TgtPtrVal, sizeof(void *));
532         if (rt != OFFLOAD_SUCCESS) {
533           DP("Copying data to device failed.\n");
534           Device.ShadowMtx.unlock();
535           return OFFLOAD_FAIL;
536         }
537       }
538       Device.ShadowMtx.unlock();
539     }
540   }
541   return OFFLOAD_SUCCESS;
542 }
543 
544 static const unsigned LambdaMapping = OMP_TGT_MAPTYPE_PTR_AND_OBJ |
545                                       OMP_TGT_MAPTYPE_LITERAL |
546                                       OMP_TGT_MAPTYPE_IMPLICIT;
547 static bool isLambdaMapping(int64_t Mapping) {
548   return (Mapping & LambdaMapping) == LambdaMapping;
549 }
550 
551 /// performs the same actions as data_begin in case arg_num is
552 /// non-zero and initiates run of the offloaded region on the target platform;
553 /// if arg_num is non-zero after the region execution is done it also
554 /// performs the same action as data_update and data_end above. This function
555 /// returns 0 if it was able to transfer the execution to a target and an
556 /// integer different from zero otherwise.
557 int target(int64_t device_id, void *host_ptr, int32_t arg_num,
558     void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types,
559     int32_t team_num, int32_t thread_limit, int IsTeamConstruct) {
560   DeviceTy &Device = Devices[device_id];
561 
562   // Find the table information in the map or look it up in the translation
563   // tables.
564   TableMap *TM = 0;
565   TblMapMtx.lock();
566   HostPtrToTableMapTy::iterator TableMapIt = HostPtrToTableMap.find(host_ptr);
567   if (TableMapIt == HostPtrToTableMap.end()) {
568     // We don't have a map. So search all the registered libraries.
569     TrlTblMtx.lock();
570     for (HostEntriesBeginToTransTableTy::iterator
571              ii = HostEntriesBeginToTransTable.begin(),
572              ie = HostEntriesBeginToTransTable.end();
573          !TM && ii != ie; ++ii) {
574       // get the translation table (which contains all the good info).
575       TranslationTable *TransTable = &ii->second;
576       // iterate over all the host table entries to see if we can locate the
577       // host_ptr.
578       __tgt_offload_entry *begin = TransTable->HostTable.EntriesBegin;
579       __tgt_offload_entry *end = TransTable->HostTable.EntriesEnd;
580       __tgt_offload_entry *cur = begin;
581       for (uint32_t i = 0; cur < end; ++cur, ++i) {
582         if (cur->addr != host_ptr)
583           continue;
584         // we got a match, now fill the HostPtrToTableMap so that we
585         // may avoid this search next time.
586         TM = &HostPtrToTableMap[host_ptr];
587         TM->Table = TransTable;
588         TM->Index = i;
589         break;
590       }
591     }
592     TrlTblMtx.unlock();
593   } else {
594     TM = &TableMapIt->second;
595   }
596   TblMapMtx.unlock();
597 
598   // No map for this host pointer found!
599   if (!TM) {
600     DP("Host ptr " DPxMOD " does not have a matching target pointer.\n",
601        DPxPTR(host_ptr));
602     return OFFLOAD_FAIL;
603   }
604 
605   // get target table.
606   TrlTblMtx.lock();
607   assert(TM->Table->TargetsTable.size() > (size_t)device_id &&
608          "Not expecting a device ID outside the table's bounds!");
609   __tgt_target_table *TargetTable = TM->Table->TargetsTable[device_id];
610   TrlTblMtx.unlock();
611   assert(TargetTable && "Global data has not been mapped\n");
612 
613   // Move data to device.
614   int rc = target_data_begin(Device, arg_num, args_base, args, arg_sizes,
615       arg_types);
616   if (rc != OFFLOAD_SUCCESS) {
617     DP("Call to target_data_begin failed, abort target.\n");
618     return OFFLOAD_FAIL;
619   }
620 
621   std::vector<void *> tgt_args;
622   std::vector<ptrdiff_t> tgt_offsets;
623 
624   // List of (first-)private arrays allocated for this target region
625   std::vector<void *> fpArrays;
626   std::vector<int> tgtArgsPositions(arg_num, -1);
627 
628   for (int32_t i = 0; i < arg_num; ++i) {
629     if (!(arg_types[i] & OMP_TGT_MAPTYPE_TARGET_PARAM)) {
630       // This is not a target parameter, do not push it into tgt_args.
631       // Check for lambda mapping.
632       if (isLambdaMapping(arg_types[i])) {
633         assert((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
634                "PTR_AND_OBJ must be also MEMBER_OF.");
635         unsigned idx = member_of(arg_types[i]);
636         int tgtIdx = tgtArgsPositions[idx];
637         assert(tgtIdx != -1 && "Base address must be translated already.");
638         // The parent lambda must be processed already and it must be the last
639         // in tgt_args and tgt_offsets arrays.
640         void *HstPtrVal = args[i];
641         void *HstPtrBegin = args_base[i];
642         void *HstPtrBase = args[idx];
643         bool IsLast; // unused.
644         void *TgtPtrBase =
645             (void *)((intptr_t)tgt_args[tgtIdx] + tgt_offsets[tgtIdx]);
646         DP("Parent lambda base " DPxMOD "\n", DPxPTR(TgtPtrBase));
647         uint64_t Delta = (uint64_t)HstPtrBegin - (uint64_t)HstPtrBase;
648         void *TgtPtrBegin = (void *)((uintptr_t)TgtPtrBase + Delta);
649         void *Pointer_TgtPtrBegin =
650             Device.getTgtPtrBegin(HstPtrVal, arg_sizes[i], IsLast, false);
651         if (!Pointer_TgtPtrBegin) {
652           DP("No lambda captured variable mapped (" DPxMOD ") - ignored\n",
653              DPxPTR(HstPtrVal));
654           continue;
655         }
656         DP("Update lambda reference (" DPxMOD ") -> [" DPxMOD "]\n",
657            DPxPTR(Pointer_TgtPtrBegin), DPxPTR(TgtPtrBegin));
658         int rt = Device.data_submit(TgtPtrBegin, &Pointer_TgtPtrBegin,
659                                     sizeof(void *));
660         if (rt != OFFLOAD_SUCCESS) {
661           DP("Copying data to device failed.\n");
662           return OFFLOAD_FAIL;
663         }
664       }
665       continue;
666     }
667     void *HstPtrBegin = args[i];
668     void *HstPtrBase = args_base[i];
669     void *TgtPtrBegin;
670     ptrdiff_t TgtBaseOffset;
671     bool IsLast; // unused.
672     if (arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) {
673       DP("Forwarding first-private value " DPxMOD " to the target construct\n",
674           DPxPTR(HstPtrBase));
675       TgtPtrBegin = HstPtrBase;
676       TgtBaseOffset = 0;
677     } else if (arg_types[i] & OMP_TGT_MAPTYPE_PRIVATE) {
678       // Allocate memory for (first-)private array
679       TgtPtrBegin = Device.RTL->data_alloc(Device.RTLDeviceID,
680           arg_sizes[i], HstPtrBegin);
681       if (!TgtPtrBegin) {
682         DP ("Data allocation for %sprivate array " DPxMOD " failed, "
683             "abort target.\n",
684             (arg_types[i] & OMP_TGT_MAPTYPE_TO ? "first-" : ""),
685             DPxPTR(HstPtrBegin));
686         return OFFLOAD_FAIL;
687       }
688       fpArrays.push_back(TgtPtrBegin);
689       TgtBaseOffset = (intptr_t)HstPtrBase - (intptr_t)HstPtrBegin;
690 #ifdef OMPTARGET_DEBUG
691       void *TgtPtrBase = (void *)((intptr_t)TgtPtrBegin + TgtBaseOffset);
692       DP("Allocated %" PRId64 " bytes of target memory at " DPxMOD " for "
693           "%sprivate array " DPxMOD " - pushing target argument " DPxMOD "\n",
694           arg_sizes[i], DPxPTR(TgtPtrBegin),
695           (arg_types[i] & OMP_TGT_MAPTYPE_TO ? "first-" : ""),
696           DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBase));
697 #endif
698       // If first-private, copy data from host
699       if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
700         int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, arg_sizes[i]);
701         if (rt != OFFLOAD_SUCCESS) {
702           DP ("Copying data to device failed, failed.\n");
703           return OFFLOAD_FAIL;
704         }
705       }
706     } else if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ) {
707       TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBase, sizeof(void *), IsLast,
708           false);
709       TgtBaseOffset = 0; // no offset for ptrs.
710       DP("Obtained target argument " DPxMOD " from host pointer " DPxMOD " to "
711          "object " DPxMOD "\n", DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBase),
712          DPxPTR(HstPtrBase));
713     } else {
714       TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, arg_sizes[i], IsLast,
715           false);
716       TgtBaseOffset = (intptr_t)HstPtrBase - (intptr_t)HstPtrBegin;
717 #ifdef OMPTARGET_DEBUG
718       void *TgtPtrBase = (void *)((intptr_t)TgtPtrBegin + TgtBaseOffset);
719       DP("Obtained target argument " DPxMOD " from host pointer " DPxMOD "\n",
720           DPxPTR(TgtPtrBase), DPxPTR(HstPtrBegin));
721 #endif
722     }
723     tgtArgsPositions[i] = tgt_args.size();
724     tgt_args.push_back(TgtPtrBegin);
725     tgt_offsets.push_back(TgtBaseOffset);
726   }
727 
728   assert(tgt_args.size() == tgt_offsets.size() &&
729       "Size mismatch in arguments and offsets");
730 
731   // Pop loop trip count
732   uint64_t ltc = 0;
733   TblMapMtx.lock();
734   auto I = Device.LoopTripCnt.find(__kmpc_global_thread_num(NULL));
735   if (I != Device.LoopTripCnt.end()) {
736     ltc = I->second;
737     Device.LoopTripCnt.erase(I);
738     DP("loop trip count is %lu.\n", ltc);
739   }
740   TblMapMtx.unlock();
741 
742   // Launch device execution.
743   DP("Launching target execution %s with pointer " DPxMOD " (index=%d).\n",
744       TargetTable->EntriesBegin[TM->Index].name,
745       DPxPTR(TargetTable->EntriesBegin[TM->Index].addr), TM->Index);
746   if (IsTeamConstruct) {
747     rc = Device.run_team_region(TargetTable->EntriesBegin[TM->Index].addr,
748         &tgt_args[0], &tgt_offsets[0], tgt_args.size(), team_num,
749         thread_limit, ltc);
750   } else {
751     rc = Device.run_region(TargetTable->EntriesBegin[TM->Index].addr,
752         &tgt_args[0], &tgt_offsets[0], tgt_args.size());
753   }
754   if (rc != OFFLOAD_SUCCESS) {
755     DP ("Executing target region abort target.\n");
756     return OFFLOAD_FAIL;
757   }
758 
759   // Deallocate (first-)private arrays
760   for (auto it : fpArrays) {
761     int rt = Device.RTL->data_delete(Device.RTLDeviceID, it);
762     if (rt != OFFLOAD_SUCCESS) {
763       DP("Deallocation of (first-)private arrays failed.\n");
764       return OFFLOAD_FAIL;
765     }
766   }
767 
768   // Move data from device.
769   int rt = target_data_end(Device, arg_num, args_base, args, arg_sizes,
770       arg_types);
771   if (rt != OFFLOAD_SUCCESS) {
772     DP("Call to target_data_end failed, abort targe.\n");
773     return OFFLOAD_FAIL;
774   }
775 
776   return OFFLOAD_SUCCESS;
777 }
778