xref: /llvm-project/offload/src/OpenMP/API.cpp (revision caaf8099efa87a7ebca8920971b7d7f719808591)
1330d8983SJohannes Doerfert //===----------- api.cpp - Target independent OpenMP target RTL -----------===//
2330d8983SJohannes Doerfert //
3330d8983SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4330d8983SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5330d8983SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6330d8983SJohannes Doerfert //
7330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
8330d8983SJohannes Doerfert //
9330d8983SJohannes Doerfert // Implementation of OpenMP API interface functions.
10330d8983SJohannes Doerfert //
11330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
12330d8983SJohannes Doerfert 
13330d8983SJohannes Doerfert #include "PluginManager.h"
14330d8983SJohannes Doerfert #include "device.h"
15330d8983SJohannes Doerfert #include "omptarget.h"
16330d8983SJohannes Doerfert #include "rtl.h"
17330d8983SJohannes Doerfert 
18330d8983SJohannes Doerfert #include "OpenMP/InternalTypes.h"
19330d8983SJohannes Doerfert #include "OpenMP/Mapping.h"
20330d8983SJohannes Doerfert #include "OpenMP/OMPT/Interface.h"
21330d8983SJohannes Doerfert #include "OpenMP/omp.h"
22330d8983SJohannes Doerfert #include "Shared/Profile.h"
23330d8983SJohannes Doerfert 
24330d8983SJohannes Doerfert #include "llvm/ADT/SmallVector.h"
25330d8983SJohannes Doerfert 
26330d8983SJohannes Doerfert #include <climits>
27330d8983SJohannes Doerfert #include <cstdlib>
28330d8983SJohannes Doerfert #include <cstring>
29330d8983SJohannes Doerfert #include <mutex>
30330d8983SJohannes Doerfert 
31330d8983SJohannes Doerfert EXTERN void ompx_dump_mapping_tables() {
32330d8983SJohannes Doerfert   ident_t Loc = {0, 0, 0, 0, ";libomptarget;libomptarget;0;0;;"};
33330d8983SJohannes Doerfert   auto ExclusiveDevicesAccessor = PM->getExclusiveDevicesAccessor();
34330d8983SJohannes Doerfert   for (auto &Device : PM->devices(ExclusiveDevicesAccessor))
35330d8983SJohannes Doerfert     dumpTargetPointerMappings(&Loc, Device, true);
36330d8983SJohannes Doerfert }
37330d8983SJohannes Doerfert 
38330d8983SJohannes Doerfert #ifdef OMPT_SUPPORT
39330d8983SJohannes Doerfert using namespace llvm::omp::target::ompt;
40330d8983SJohannes Doerfert #endif
41330d8983SJohannes Doerfert 
42330d8983SJohannes Doerfert void *targetAllocExplicit(size_t Size, int DeviceNum, int Kind,
43330d8983SJohannes Doerfert                           const char *Name);
44330d8983SJohannes Doerfert void targetFreeExplicit(void *DevicePtr, int DeviceNum, int Kind,
45330d8983SJohannes Doerfert                         const char *Name);
46330d8983SJohannes Doerfert void *targetLockExplicit(void *HostPtr, size_t Size, int DeviceNum,
47330d8983SJohannes Doerfert                          const char *Name);
48330d8983SJohannes Doerfert void targetUnlockExplicit(void *HostPtr, int DeviceNum, const char *Name);
49330d8983SJohannes Doerfert 
50330d8983SJohannes Doerfert // Implemented in libomp, they are called from within __tgt_* functions.
51330d8983SJohannes Doerfert extern "C" {
52330d8983SJohannes Doerfert int __kmpc_get_target_offload(void) __attribute__((weak));
53330d8983SJohannes Doerfert kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, int32_t gtid, int32_t flags,
54330d8983SJohannes Doerfert                                   size_t sizeof_kmp_task_t,
55330d8983SJohannes Doerfert                                   size_t sizeof_shareds,
56330d8983SJohannes Doerfert                                   kmp_routine_entry_t task_entry)
57330d8983SJohannes Doerfert     __attribute__((weak));
58330d8983SJohannes Doerfert 
59330d8983SJohannes Doerfert kmp_task_t *
60330d8983SJohannes Doerfert __kmpc_omp_target_task_alloc(ident_t *loc_ref, int32_t gtid, int32_t flags,
61330d8983SJohannes Doerfert                              size_t sizeof_kmp_task_t, size_t sizeof_shareds,
62330d8983SJohannes Doerfert                              kmp_routine_entry_t task_entry, int64_t device_id)
63330d8983SJohannes Doerfert     __attribute__((weak));
64330d8983SJohannes Doerfert 
65330d8983SJohannes Doerfert int32_t __kmpc_omp_task_with_deps(ident_t *loc_ref, int32_t gtid,
66330d8983SJohannes Doerfert                                   kmp_task_t *new_task, int32_t ndeps,
67330d8983SJohannes Doerfert                                   kmp_depend_info_t *dep_list,
68330d8983SJohannes Doerfert                                   int32_t ndeps_noalias,
69330d8983SJohannes Doerfert                                   kmp_depend_info_t *noalias_dep_list)
70330d8983SJohannes Doerfert     __attribute__((weak));
71330d8983SJohannes Doerfert }
72330d8983SJohannes Doerfert 
73330d8983SJohannes Doerfert EXTERN int omp_get_num_devices(void) {
74330d8983SJohannes Doerfert   TIMESCOPE();
75330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
76330d8983SJohannes Doerfert   size_t NumDevices = PM->getNumDevices();
77330d8983SJohannes Doerfert 
78330d8983SJohannes Doerfert   DP("Call to omp_get_num_devices returning %zd\n", NumDevices);
79330d8983SJohannes Doerfert 
80330d8983SJohannes Doerfert   return NumDevices;
81330d8983SJohannes Doerfert }
82330d8983SJohannes Doerfert 
83330d8983SJohannes Doerfert EXTERN int omp_get_device_num(void) {
84330d8983SJohannes Doerfert   TIMESCOPE();
85330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
86330d8983SJohannes Doerfert   int HostDevice = omp_get_initial_device();
87330d8983SJohannes Doerfert 
88330d8983SJohannes Doerfert   DP("Call to omp_get_device_num returning %d\n", HostDevice);
89330d8983SJohannes Doerfert 
90330d8983SJohannes Doerfert   return HostDevice;
91330d8983SJohannes Doerfert }
92330d8983SJohannes Doerfert 
93330d8983SJohannes Doerfert EXTERN int omp_get_initial_device(void) {
94330d8983SJohannes Doerfert   TIMESCOPE();
95330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
96330d8983SJohannes Doerfert   int HostDevice = omp_get_num_devices();
97330d8983SJohannes Doerfert   DP("Call to omp_get_initial_device returning %d\n", HostDevice);
98330d8983SJohannes Doerfert   return HostDevice;
99330d8983SJohannes Doerfert }
100330d8983SJohannes Doerfert 
101330d8983SJohannes Doerfert EXTERN void *omp_target_alloc(size_t Size, int DeviceNum) {
102330d8983SJohannes Doerfert   TIMESCOPE_WITH_DETAILS("dst_dev=" + std::to_string(DeviceNum) +
103330d8983SJohannes Doerfert                          ";size=" + std::to_string(Size));
104330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
105330d8983SJohannes Doerfert   return targetAllocExplicit(Size, DeviceNum, TARGET_ALLOC_DEFAULT, __func__);
106330d8983SJohannes Doerfert }
107330d8983SJohannes Doerfert 
108330d8983SJohannes Doerfert EXTERN void *llvm_omp_target_alloc_device(size_t Size, int DeviceNum) {
109330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
110330d8983SJohannes Doerfert   return targetAllocExplicit(Size, DeviceNum, TARGET_ALLOC_DEVICE, __func__);
111330d8983SJohannes Doerfert }
112330d8983SJohannes Doerfert 
113330d8983SJohannes Doerfert EXTERN void *llvm_omp_target_alloc_host(size_t Size, int DeviceNum) {
114330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
115330d8983SJohannes Doerfert   return targetAllocExplicit(Size, DeviceNum, TARGET_ALLOC_HOST, __func__);
116330d8983SJohannes Doerfert }
117330d8983SJohannes Doerfert 
118330d8983SJohannes Doerfert EXTERN void *llvm_omp_target_alloc_shared(size_t Size, int DeviceNum) {
119330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
120330d8983SJohannes Doerfert   return targetAllocExplicit(Size, DeviceNum, TARGET_ALLOC_SHARED, __func__);
121330d8983SJohannes Doerfert }
122330d8983SJohannes Doerfert 
123330d8983SJohannes Doerfert EXTERN void omp_target_free(void *Ptr, int DeviceNum) {
124330d8983SJohannes Doerfert   TIMESCOPE();
125330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
126330d8983SJohannes Doerfert   return targetFreeExplicit(Ptr, DeviceNum, TARGET_ALLOC_DEFAULT, __func__);
127330d8983SJohannes Doerfert }
128330d8983SJohannes Doerfert 
129330d8983SJohannes Doerfert EXTERN void llvm_omp_target_free_device(void *Ptr, int DeviceNum) {
130330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
131330d8983SJohannes Doerfert   return targetFreeExplicit(Ptr, DeviceNum, TARGET_ALLOC_DEVICE, __func__);
132330d8983SJohannes Doerfert }
133330d8983SJohannes Doerfert 
134330d8983SJohannes Doerfert EXTERN void llvm_omp_target_free_host(void *Ptr, int DeviceNum) {
135330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
136330d8983SJohannes Doerfert   return targetFreeExplicit(Ptr, DeviceNum, TARGET_ALLOC_HOST, __func__);
137330d8983SJohannes Doerfert }
138330d8983SJohannes Doerfert 
139330d8983SJohannes Doerfert EXTERN void llvm_omp_target_free_shared(void *Ptre, int DeviceNum) {
140330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
141330d8983SJohannes Doerfert   return targetFreeExplicit(Ptre, DeviceNum, TARGET_ALLOC_SHARED, __func__);
142330d8983SJohannes Doerfert }
143330d8983SJohannes Doerfert 
144330d8983SJohannes Doerfert EXTERN void *llvm_omp_target_dynamic_shared_alloc() {
145330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
146330d8983SJohannes Doerfert   return nullptr;
147330d8983SJohannes Doerfert }
148330d8983SJohannes Doerfert 
149330d8983SJohannes Doerfert EXTERN void *llvm_omp_get_dynamic_shared() {
150330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
151330d8983SJohannes Doerfert   return nullptr;
152330d8983SJohannes Doerfert }
153330d8983SJohannes Doerfert 
154330d8983SJohannes Doerfert EXTERN [[nodiscard]] void *llvm_omp_target_lock_mem(void *Ptr, size_t Size,
155330d8983SJohannes Doerfert                                                     int DeviceNum) {
156330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
157330d8983SJohannes Doerfert   return targetLockExplicit(Ptr, Size, DeviceNum, __func__);
158330d8983SJohannes Doerfert }
159330d8983SJohannes Doerfert 
160330d8983SJohannes Doerfert EXTERN void llvm_omp_target_unlock_mem(void *Ptr, int DeviceNum) {
161330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
162330d8983SJohannes Doerfert   targetUnlockExplicit(Ptr, DeviceNum, __func__);
163330d8983SJohannes Doerfert }
164330d8983SJohannes Doerfert 
165330d8983SJohannes Doerfert EXTERN int omp_target_is_present(const void *Ptr, int DeviceNum) {
166330d8983SJohannes Doerfert   TIMESCOPE();
167330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
168330d8983SJohannes Doerfert   DP("Call to omp_target_is_present for device %d and address " DPxMOD "\n",
169330d8983SJohannes Doerfert      DeviceNum, DPxPTR(Ptr));
170330d8983SJohannes Doerfert 
171330d8983SJohannes Doerfert   if (!Ptr) {
172330d8983SJohannes Doerfert     DP("Call to omp_target_is_present with NULL ptr, returning false\n");
173330d8983SJohannes Doerfert     return false;
174330d8983SJohannes Doerfert   }
175330d8983SJohannes Doerfert 
176330d8983SJohannes Doerfert   if (DeviceNum == omp_get_initial_device()) {
177330d8983SJohannes Doerfert     DP("Call to omp_target_is_present on host, returning true\n");
178330d8983SJohannes Doerfert     return true;
179330d8983SJohannes Doerfert   }
180330d8983SJohannes Doerfert 
181330d8983SJohannes Doerfert   auto DeviceOrErr = PM->getDevice(DeviceNum);
182330d8983SJohannes Doerfert   if (!DeviceOrErr)
183330d8983SJohannes Doerfert     FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
184330d8983SJohannes Doerfert 
185330d8983SJohannes Doerfert   // omp_target_is_present tests whether a host pointer refers to storage that
186330d8983SJohannes Doerfert   // is mapped to a given device. However, due to the lack of the storage size,
187330d8983SJohannes Doerfert   // only check 1 byte. Cannot set size 0 which checks whether the pointer (zero
188330d8983SJohannes Doerfert   // lengh array) is mapped instead of the referred storage.
189330d8983SJohannes Doerfert   TargetPointerResultTy TPR =
190330d8983SJohannes Doerfert       DeviceOrErr->getMappingInfo().getTgtPtrBegin(const_cast<void *>(Ptr), 1,
191330d8983SJohannes Doerfert                                                    /*UpdateRefCount=*/false,
192330d8983SJohannes Doerfert                                                    /*UseHoldRefCount=*/false);
193330d8983SJohannes Doerfert   int Rc = TPR.isPresent();
194330d8983SJohannes Doerfert   DP("Call to omp_target_is_present returns %d\n", Rc);
195330d8983SJohannes Doerfert   return Rc;
196330d8983SJohannes Doerfert }
197330d8983SJohannes Doerfert 
198330d8983SJohannes Doerfert EXTERN int omp_target_memcpy(void *Dst, const void *Src, size_t Length,
199330d8983SJohannes Doerfert                              size_t DstOffset, size_t SrcOffset, int DstDevice,
200330d8983SJohannes Doerfert                              int SrcDevice) {
201330d8983SJohannes Doerfert   TIMESCOPE_WITH_DETAILS("dst_dev=" + std::to_string(DstDevice) +
202330d8983SJohannes Doerfert                          ";src_dev=" + std::to_string(SrcDevice) +
203330d8983SJohannes Doerfert                          ";size=" + std::to_string(Length));
204330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
205330d8983SJohannes Doerfert   DP("Call to omp_target_memcpy, dst device %d, src device %d, "
206330d8983SJohannes Doerfert      "dst addr " DPxMOD ", src addr " DPxMOD ", dst offset %zu, "
207330d8983SJohannes Doerfert      "src offset %zu, length %zu\n",
208330d8983SJohannes Doerfert      DstDevice, SrcDevice, DPxPTR(Dst), DPxPTR(Src), DstOffset, SrcOffset,
209330d8983SJohannes Doerfert      Length);
210330d8983SJohannes Doerfert 
211330d8983SJohannes Doerfert   if (!Dst || !Src || Length <= 0) {
212330d8983SJohannes Doerfert     if (Length == 0) {
213330d8983SJohannes Doerfert       DP("Call to omp_target_memcpy with zero length, nothing to do\n");
214330d8983SJohannes Doerfert       return OFFLOAD_SUCCESS;
215330d8983SJohannes Doerfert     }
216330d8983SJohannes Doerfert 
217330d8983SJohannes Doerfert     REPORT("Call to omp_target_memcpy with invalid arguments\n");
218330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
219330d8983SJohannes Doerfert   }
220330d8983SJohannes Doerfert 
221330d8983SJohannes Doerfert   int Rc = OFFLOAD_SUCCESS;
222330d8983SJohannes Doerfert   void *SrcAddr = (char *)const_cast<void *>(Src) + SrcOffset;
223330d8983SJohannes Doerfert   void *DstAddr = (char *)Dst + DstOffset;
224330d8983SJohannes Doerfert 
225330d8983SJohannes Doerfert   if (SrcDevice == omp_get_initial_device() &&
226330d8983SJohannes Doerfert       DstDevice == omp_get_initial_device()) {
227330d8983SJohannes Doerfert     DP("copy from host to host\n");
228330d8983SJohannes Doerfert     const void *P = memcpy(DstAddr, SrcAddr, Length);
229330d8983SJohannes Doerfert     if (P == NULL)
230330d8983SJohannes Doerfert       Rc = OFFLOAD_FAIL;
231330d8983SJohannes Doerfert   } else if (SrcDevice == omp_get_initial_device()) {
232330d8983SJohannes Doerfert     DP("copy from host to device\n");
233330d8983SJohannes Doerfert     auto DstDeviceOrErr = PM->getDevice(DstDevice);
234330d8983SJohannes Doerfert     if (!DstDeviceOrErr)
235330d8983SJohannes Doerfert       FATAL_MESSAGE(DstDevice, "%s",
236330d8983SJohannes Doerfert                     toString(DstDeviceOrErr.takeError()).c_str());
237330d8983SJohannes Doerfert     AsyncInfoTy AsyncInfo(*DstDeviceOrErr);
238330d8983SJohannes Doerfert     Rc = DstDeviceOrErr->submitData(DstAddr, SrcAddr, Length, AsyncInfo);
239330d8983SJohannes Doerfert   } else if (DstDevice == omp_get_initial_device()) {
240330d8983SJohannes Doerfert     DP("copy from device to host\n");
241330d8983SJohannes Doerfert     auto SrcDeviceOrErr = PM->getDevice(SrcDevice);
242330d8983SJohannes Doerfert     if (!SrcDeviceOrErr)
243330d8983SJohannes Doerfert       FATAL_MESSAGE(SrcDevice, "%s",
244330d8983SJohannes Doerfert                     toString(SrcDeviceOrErr.takeError()).c_str());
245330d8983SJohannes Doerfert     AsyncInfoTy AsyncInfo(*SrcDeviceOrErr);
246330d8983SJohannes Doerfert     Rc = SrcDeviceOrErr->retrieveData(DstAddr, SrcAddr, Length, AsyncInfo);
247330d8983SJohannes Doerfert   } else {
248330d8983SJohannes Doerfert     DP("copy from device to device\n");
249330d8983SJohannes Doerfert     auto SrcDeviceOrErr = PM->getDevice(SrcDevice);
250330d8983SJohannes Doerfert     if (!SrcDeviceOrErr)
251330d8983SJohannes Doerfert       FATAL_MESSAGE(SrcDevice, "%s",
252330d8983SJohannes Doerfert                     toString(SrcDeviceOrErr.takeError()).c_str());
253330d8983SJohannes Doerfert     AsyncInfoTy AsyncInfo(*SrcDeviceOrErr);
254330d8983SJohannes Doerfert     auto DstDeviceOrErr = PM->getDevice(DstDevice);
255330d8983SJohannes Doerfert     if (!DstDeviceOrErr)
256330d8983SJohannes Doerfert       FATAL_MESSAGE(DstDevice, "%s",
257330d8983SJohannes Doerfert                     toString(DstDeviceOrErr.takeError()).c_str());
258330d8983SJohannes Doerfert     // First try to use D2D memcpy which is more efficient. If fails, fall back
259330d8983SJohannes Doerfert     // to unefficient way.
260330d8983SJohannes Doerfert     if (SrcDeviceOrErr->isDataExchangable(*DstDeviceOrErr)) {
261330d8983SJohannes Doerfert       AsyncInfoTy AsyncInfo(*SrcDeviceOrErr);
262330d8983SJohannes Doerfert       Rc = SrcDeviceOrErr->dataExchange(SrcAddr, *DstDeviceOrErr, DstAddr,
263330d8983SJohannes Doerfert                                         Length, AsyncInfo);
264330d8983SJohannes Doerfert       if (Rc == OFFLOAD_SUCCESS)
265330d8983SJohannes Doerfert         return OFFLOAD_SUCCESS;
266330d8983SJohannes Doerfert     }
267330d8983SJohannes Doerfert 
268330d8983SJohannes Doerfert     void *Buffer = malloc(Length);
269330d8983SJohannes Doerfert     {
270330d8983SJohannes Doerfert       AsyncInfoTy AsyncInfo(*SrcDeviceOrErr);
271330d8983SJohannes Doerfert       Rc = SrcDeviceOrErr->retrieveData(Buffer, SrcAddr, Length, AsyncInfo);
272330d8983SJohannes Doerfert     }
273330d8983SJohannes Doerfert     if (Rc == OFFLOAD_SUCCESS) {
274330d8983SJohannes Doerfert       AsyncInfoTy AsyncInfo(*DstDeviceOrErr);
275330d8983SJohannes Doerfert       Rc = DstDeviceOrErr->submitData(DstAddr, Buffer, Length, AsyncInfo);
276330d8983SJohannes Doerfert     }
277330d8983SJohannes Doerfert     free(Buffer);
278330d8983SJohannes Doerfert   }
279330d8983SJohannes Doerfert 
280330d8983SJohannes Doerfert   DP("omp_target_memcpy returns %d\n", Rc);
281330d8983SJohannes Doerfert   return Rc;
282330d8983SJohannes Doerfert }
283330d8983SJohannes Doerfert 
284330d8983SJohannes Doerfert // The helper function that calls omp_target_memcpy or omp_target_memcpy_rect
285330d8983SJohannes Doerfert static int libomp_target_memcpy_async_task(int32_t Gtid, kmp_task_t *Task) {
286330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
287330d8983SJohannes Doerfert   if (Task == nullptr)
288330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
289330d8983SJohannes Doerfert 
290330d8983SJohannes Doerfert   TargetMemcpyArgsTy *Args = (TargetMemcpyArgsTy *)Task->shareds;
291330d8983SJohannes Doerfert 
292330d8983SJohannes Doerfert   if (Args == nullptr)
293330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
294330d8983SJohannes Doerfert 
295330d8983SJohannes Doerfert   // Call blocked version
296330d8983SJohannes Doerfert   int Rc = OFFLOAD_SUCCESS;
297330d8983SJohannes Doerfert   if (Args->IsRectMemcpy) {
298330d8983SJohannes Doerfert     Rc = omp_target_memcpy_rect(
299330d8983SJohannes Doerfert         Args->Dst, Args->Src, Args->ElementSize, Args->NumDims, Args->Volume,
300330d8983SJohannes Doerfert         Args->DstOffsets, Args->SrcOffsets, Args->DstDimensions,
301330d8983SJohannes Doerfert         Args->SrcDimensions, Args->DstDevice, Args->SrcDevice);
302330d8983SJohannes Doerfert 
303330d8983SJohannes Doerfert     DP("omp_target_memcpy_rect returns %d\n", Rc);
304330d8983SJohannes Doerfert   } else {
305330d8983SJohannes Doerfert     Rc = omp_target_memcpy(Args->Dst, Args->Src, Args->Length, Args->DstOffset,
306330d8983SJohannes Doerfert                            Args->SrcOffset, Args->DstDevice, Args->SrcDevice);
307330d8983SJohannes Doerfert 
308330d8983SJohannes Doerfert     DP("omp_target_memcpy returns %d\n", Rc);
309330d8983SJohannes Doerfert   }
310330d8983SJohannes Doerfert 
311330d8983SJohannes Doerfert   // Release the arguments object
312330d8983SJohannes Doerfert   delete Args;
313330d8983SJohannes Doerfert 
314330d8983SJohannes Doerfert   return Rc;
315330d8983SJohannes Doerfert }
316330d8983SJohannes Doerfert 
317330d8983SJohannes Doerfert static int libomp_target_memset_async_task(int32_t Gtid, kmp_task_t *Task) {
318330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
319330d8983SJohannes Doerfert   if (!Task)
320330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
321330d8983SJohannes Doerfert 
322330d8983SJohannes Doerfert   auto *Args = reinterpret_cast<TargetMemsetArgsTy *>(Task->shareds);
323330d8983SJohannes Doerfert   if (!Args)
324330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
325330d8983SJohannes Doerfert 
326330d8983SJohannes Doerfert   // call omp_target_memset()
327330d8983SJohannes Doerfert   omp_target_memset(Args->Ptr, Args->C, Args->N, Args->DeviceNum);
328330d8983SJohannes Doerfert 
329330d8983SJohannes Doerfert   delete Args;
330330d8983SJohannes Doerfert 
331330d8983SJohannes Doerfert   return OFFLOAD_SUCCESS;
332330d8983SJohannes Doerfert }
333330d8983SJohannes Doerfert 
334330d8983SJohannes Doerfert static inline void
335330d8983SJohannes Doerfert convertDepObjVector(llvm::SmallVector<kmp_depend_info_t> &Vec, int DepObjCount,
336330d8983SJohannes Doerfert                     omp_depend_t *DepObjList) {
337330d8983SJohannes Doerfert   for (int i = 0; i < DepObjCount; ++i) {
338330d8983SJohannes Doerfert     omp_depend_t DepObj = DepObjList[i];
339330d8983SJohannes Doerfert     Vec.push_back(*((kmp_depend_info_t *)DepObj));
340330d8983SJohannes Doerfert   }
341330d8983SJohannes Doerfert }
342330d8983SJohannes Doerfert 
343330d8983SJohannes Doerfert template <class T>
344330d8983SJohannes Doerfert static inline int
345330d8983SJohannes Doerfert libomp_helper_task_creation(T *Args, int (*Fn)(int32_t, kmp_task_t *),
346330d8983SJohannes Doerfert                             int DepObjCount, omp_depend_t *DepObjList) {
347330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
348330d8983SJohannes Doerfert   // Create global thread ID
349330d8983SJohannes Doerfert   int Gtid = __kmpc_global_thread_num(nullptr);
350330d8983SJohannes Doerfert 
351330d8983SJohannes Doerfert   // Setup the hidden helper flags
352330d8983SJohannes Doerfert   int32_t Flags = 0;
353330d8983SJohannes Doerfert   kmp_tasking_flags_t *InputFlags = (kmp_tasking_flags_t *)&Flags;
354330d8983SJohannes Doerfert   InputFlags->hidden_helper = 1;
355330d8983SJohannes Doerfert 
356330d8983SJohannes Doerfert   // Alloc the helper task
357330d8983SJohannes Doerfert   kmp_task_t *Task = __kmpc_omp_target_task_alloc(
358330d8983SJohannes Doerfert       nullptr, Gtid, Flags, sizeof(kmp_task_t), 0, Fn, -1);
359330d8983SJohannes Doerfert   if (!Task) {
360330d8983SJohannes Doerfert     delete Args;
361330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
362330d8983SJohannes Doerfert   }
363330d8983SJohannes Doerfert 
364330d8983SJohannes Doerfert   // Setup the arguments for the helper task
365330d8983SJohannes Doerfert   Task->shareds = Args;
366330d8983SJohannes Doerfert 
367330d8983SJohannes Doerfert   // Convert types of depend objects
368330d8983SJohannes Doerfert   llvm::SmallVector<kmp_depend_info_t> DepObjs;
369330d8983SJohannes Doerfert   convertDepObjVector(DepObjs, DepObjCount, DepObjList);
370330d8983SJohannes Doerfert 
371330d8983SJohannes Doerfert   // Launch the helper task
372330d8983SJohannes Doerfert   int Rc = __kmpc_omp_task_with_deps(nullptr, Gtid, Task, DepObjCount,
373330d8983SJohannes Doerfert                                      DepObjs.data(), 0, nullptr);
374330d8983SJohannes Doerfert 
375330d8983SJohannes Doerfert   return Rc;
376330d8983SJohannes Doerfert }
377330d8983SJohannes Doerfert 
378330d8983SJohannes Doerfert EXTERN void *omp_target_memset(void *Ptr, int ByteVal, size_t NumBytes,
379330d8983SJohannes Doerfert                                int DeviceNum) {
380330d8983SJohannes Doerfert   TIMESCOPE();
381330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
382330d8983SJohannes Doerfert   DP("Call to omp_target_memset, device %d, device pointer %p, size %zu\n",
383330d8983SJohannes Doerfert      DeviceNum, Ptr, NumBytes);
384330d8983SJohannes Doerfert 
385330d8983SJohannes Doerfert   // Behave as a no-op if N==0 or if Ptr is nullptr (as a useful implementation
386330d8983SJohannes Doerfert   // of unspecified behavior, see OpenMP spec).
387330d8983SJohannes Doerfert   if (!Ptr || NumBytes == 0) {
388330d8983SJohannes Doerfert     return Ptr;
389330d8983SJohannes Doerfert   }
390330d8983SJohannes Doerfert 
391330d8983SJohannes Doerfert   if (DeviceNum == omp_get_initial_device()) {
392330d8983SJohannes Doerfert     DP("filling memory on host via memset");
393330d8983SJohannes Doerfert     memset(Ptr, ByteVal, NumBytes); // ignore return value, memset() cannot fail
394330d8983SJohannes Doerfert   } else {
395330d8983SJohannes Doerfert     // TODO: replace the omp_target_memset() slow path with the fast path.
396330d8983SJohannes Doerfert     // That will require the ability to execute a kernel from within
397330d8983SJohannes Doerfert     // libomptarget.so (which we do not have at the moment).
398330d8983SJohannes Doerfert 
399330d8983SJohannes Doerfert     // This is a very slow path: create a filled array on the host and upload
400330d8983SJohannes Doerfert     // it to the GPU device.
401330d8983SJohannes Doerfert     int InitialDevice = omp_get_initial_device();
402330d8983SJohannes Doerfert     void *Shadow = omp_target_alloc(NumBytes, InitialDevice);
403330d8983SJohannes Doerfert     if (Shadow) {
404330d8983SJohannes Doerfert       (void)memset(Shadow, ByteVal, NumBytes);
405330d8983SJohannes Doerfert       (void)omp_target_memcpy(Ptr, Shadow, NumBytes, 0, 0, DeviceNum,
406330d8983SJohannes Doerfert                               InitialDevice);
407330d8983SJohannes Doerfert       (void)omp_target_free(Shadow, InitialDevice);
408330d8983SJohannes Doerfert     } else {
409330d8983SJohannes Doerfert       // If the omp_target_alloc has failed, let's just not do anything.
410330d8983SJohannes Doerfert       // omp_target_memset does not have any good way to fail, so we
411330d8983SJohannes Doerfert       // simply avoid a catastrophic failure of the process for now.
412330d8983SJohannes Doerfert       DP("omp_target_memset failed to fill memory due to error with "
413330d8983SJohannes Doerfert          "omp_target_alloc");
414330d8983SJohannes Doerfert     }
415330d8983SJohannes Doerfert   }
416330d8983SJohannes Doerfert 
417330d8983SJohannes Doerfert   DP("omp_target_memset returns %p\n", Ptr);
418330d8983SJohannes Doerfert   return Ptr;
419330d8983SJohannes Doerfert }
420330d8983SJohannes Doerfert 
421330d8983SJohannes Doerfert EXTERN void *omp_target_memset_async(void *Ptr, int ByteVal, size_t NumBytes,
422330d8983SJohannes Doerfert                                      int DeviceNum, int DepObjCount,
423330d8983SJohannes Doerfert                                      omp_depend_t *DepObjList) {
424330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
425330d8983SJohannes Doerfert   DP("Call to omp_target_memset_async, device %d, device pointer %p, size %zu",
426330d8983SJohannes Doerfert      DeviceNum, Ptr, NumBytes);
427330d8983SJohannes Doerfert 
428330d8983SJohannes Doerfert   // Behave as a no-op if N==0 or if Ptr is nullptr (as a useful implementation
429330d8983SJohannes Doerfert   // of unspecified behavior, see OpenMP spec).
430330d8983SJohannes Doerfert   if (!Ptr || NumBytes == 0)
431330d8983SJohannes Doerfert     return Ptr;
432330d8983SJohannes Doerfert 
433330d8983SJohannes Doerfert   // Create the task object to deal with the async invocation
434330d8983SJohannes Doerfert   auto *Args = new TargetMemsetArgsTy{Ptr, ByteVal, NumBytes, DeviceNum};
435330d8983SJohannes Doerfert 
436330d8983SJohannes Doerfert   // omp_target_memset_async() cannot fail via a return code, so ignore the
437330d8983SJohannes Doerfert   // return code of the helper function
438330d8983SJohannes Doerfert   (void)libomp_helper_task_creation(Args, &libomp_target_memset_async_task,
439330d8983SJohannes Doerfert                                     DepObjCount, DepObjList);
440330d8983SJohannes Doerfert 
441330d8983SJohannes Doerfert   return Ptr;
442330d8983SJohannes Doerfert }
443330d8983SJohannes Doerfert 
444330d8983SJohannes Doerfert EXTERN int omp_target_memcpy_async(void *Dst, const void *Src, size_t Length,
445330d8983SJohannes Doerfert                                    size_t DstOffset, size_t SrcOffset,
446330d8983SJohannes Doerfert                                    int DstDevice, int SrcDevice,
447330d8983SJohannes Doerfert                                    int DepObjCount, omp_depend_t *DepObjList) {
448330d8983SJohannes Doerfert   TIMESCOPE_WITH_DETAILS("dst_dev=" + std::to_string(DstDevice) +
449330d8983SJohannes Doerfert                          ";src_dev=" + std::to_string(SrcDevice) +
450330d8983SJohannes Doerfert                          ";size=" + std::to_string(Length));
451330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
452330d8983SJohannes Doerfert   DP("Call to omp_target_memcpy_async, dst device %d, src device %d, "
453330d8983SJohannes Doerfert      "dst addr " DPxMOD ", src addr " DPxMOD ", dst offset %zu, "
454330d8983SJohannes Doerfert      "src offset %zu, length %zu\n",
455330d8983SJohannes Doerfert      DstDevice, SrcDevice, DPxPTR(Dst), DPxPTR(Src), DstOffset, SrcOffset,
456330d8983SJohannes Doerfert      Length);
457330d8983SJohannes Doerfert 
458330d8983SJohannes Doerfert   // Check the source and dest address
459330d8983SJohannes Doerfert   if (Dst == nullptr || Src == nullptr)
460330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
461330d8983SJohannes Doerfert 
462330d8983SJohannes Doerfert   // Create task object
463330d8983SJohannes Doerfert   TargetMemcpyArgsTy *Args = new TargetMemcpyArgsTy(
464330d8983SJohannes Doerfert       Dst, Src, Length, DstOffset, SrcOffset, DstDevice, SrcDevice);
465330d8983SJohannes Doerfert 
466330d8983SJohannes Doerfert   // Create and launch helper task
467330d8983SJohannes Doerfert   int Rc = libomp_helper_task_creation(Args, &libomp_target_memcpy_async_task,
468330d8983SJohannes Doerfert                                        DepObjCount, DepObjList);
469330d8983SJohannes Doerfert 
470330d8983SJohannes Doerfert   DP("omp_target_memcpy_async returns %d\n", Rc);
471330d8983SJohannes Doerfert   return Rc;
472330d8983SJohannes Doerfert }
473330d8983SJohannes Doerfert 
474330d8983SJohannes Doerfert EXTERN int
475330d8983SJohannes Doerfert omp_target_memcpy_rect(void *Dst, const void *Src, size_t ElementSize,
476330d8983SJohannes Doerfert                        int NumDims, const size_t *Volume,
477330d8983SJohannes Doerfert                        const size_t *DstOffsets, const size_t *SrcOffsets,
478330d8983SJohannes Doerfert                        const size_t *DstDimensions, const size_t *SrcDimensions,
479330d8983SJohannes Doerfert                        int DstDevice, int SrcDevice) {
480330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
481330d8983SJohannes Doerfert   DP("Call to omp_target_memcpy_rect, dst device %d, src device %d, "
482330d8983SJohannes Doerfert      "dst addr " DPxMOD ", src addr " DPxMOD ", dst offsets " DPxMOD ", "
483330d8983SJohannes Doerfert      "src offsets " DPxMOD ", dst dims " DPxMOD ", src dims " DPxMOD ", "
484330d8983SJohannes Doerfert      "volume " DPxMOD ", element size %zu, num_dims %d\n",
485330d8983SJohannes Doerfert      DstDevice, SrcDevice, DPxPTR(Dst), DPxPTR(Src), DPxPTR(DstOffsets),
486330d8983SJohannes Doerfert      DPxPTR(SrcOffsets), DPxPTR(DstDimensions), DPxPTR(SrcDimensions),
487330d8983SJohannes Doerfert      DPxPTR(Volume), ElementSize, NumDims);
488330d8983SJohannes Doerfert 
489330d8983SJohannes Doerfert   if (!(Dst || Src)) {
490330d8983SJohannes Doerfert     DP("Call to omp_target_memcpy_rect returns max supported dimensions %d\n",
491330d8983SJohannes Doerfert        INT_MAX);
492330d8983SJohannes Doerfert     return INT_MAX;
493330d8983SJohannes Doerfert   }
494330d8983SJohannes Doerfert 
495330d8983SJohannes Doerfert   if (!Dst || !Src || ElementSize < 1 || NumDims < 1 || !Volume ||
496330d8983SJohannes Doerfert       !DstOffsets || !SrcOffsets || !DstDimensions || !SrcDimensions) {
497330d8983SJohannes Doerfert     REPORT("Call to omp_target_memcpy_rect with invalid arguments\n");
498330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
499330d8983SJohannes Doerfert   }
500330d8983SJohannes Doerfert 
501330d8983SJohannes Doerfert   int Rc;
502330d8983SJohannes Doerfert   if (NumDims == 1) {
503330d8983SJohannes Doerfert     Rc = omp_target_memcpy(Dst, Src, ElementSize * Volume[0],
504330d8983SJohannes Doerfert                            ElementSize * DstOffsets[0],
505330d8983SJohannes Doerfert                            ElementSize * SrcOffsets[0], DstDevice, SrcDevice);
506330d8983SJohannes Doerfert   } else {
507330d8983SJohannes Doerfert     size_t DstSliceSize = ElementSize;
508330d8983SJohannes Doerfert     size_t SrcSliceSize = ElementSize;
509330d8983SJohannes Doerfert     for (int I = 1; I < NumDims; ++I) {
510330d8983SJohannes Doerfert       DstSliceSize *= DstDimensions[I];
511330d8983SJohannes Doerfert       SrcSliceSize *= SrcDimensions[I];
512330d8983SJohannes Doerfert     }
513330d8983SJohannes Doerfert 
514330d8983SJohannes Doerfert     size_t DstOff = DstOffsets[0] * DstSliceSize;
515330d8983SJohannes Doerfert     size_t SrcOff = SrcOffsets[0] * SrcSliceSize;
516330d8983SJohannes Doerfert     for (size_t I = 0; I < Volume[0]; ++I) {
517330d8983SJohannes Doerfert       Rc = omp_target_memcpy_rect(
518330d8983SJohannes Doerfert           (char *)Dst + DstOff + DstSliceSize * I,
519330d8983SJohannes Doerfert           (char *)const_cast<void *>(Src) + SrcOff + SrcSliceSize * I,
520330d8983SJohannes Doerfert           ElementSize, NumDims - 1, Volume + 1, DstOffsets + 1, SrcOffsets + 1,
521330d8983SJohannes Doerfert           DstDimensions + 1, SrcDimensions + 1, DstDevice, SrcDevice);
522330d8983SJohannes Doerfert 
523330d8983SJohannes Doerfert       if (Rc) {
524330d8983SJohannes Doerfert         DP("Recursive call to omp_target_memcpy_rect returns unsuccessfully\n");
525330d8983SJohannes Doerfert         return Rc;
526330d8983SJohannes Doerfert       }
527330d8983SJohannes Doerfert     }
528330d8983SJohannes Doerfert   }
529330d8983SJohannes Doerfert 
530330d8983SJohannes Doerfert   DP("omp_target_memcpy_rect returns %d\n", Rc);
531330d8983SJohannes Doerfert   return Rc;
532330d8983SJohannes Doerfert }
533330d8983SJohannes Doerfert 
534330d8983SJohannes Doerfert EXTERN int omp_target_memcpy_rect_async(
535330d8983SJohannes Doerfert     void *Dst, const void *Src, size_t ElementSize, int NumDims,
536330d8983SJohannes Doerfert     const size_t *Volume, const size_t *DstOffsets, const size_t *SrcOffsets,
537330d8983SJohannes Doerfert     const size_t *DstDimensions, const size_t *SrcDimensions, int DstDevice,
538330d8983SJohannes Doerfert     int SrcDevice, int DepObjCount, omp_depend_t *DepObjList) {
539330d8983SJohannes Doerfert   TIMESCOPE_WITH_DETAILS("dst_dev=" + std::to_string(DstDevice) +
540330d8983SJohannes Doerfert                          ";src_dev=" + std::to_string(SrcDevice) +
541330d8983SJohannes Doerfert                          ";size=" + std::to_string(ElementSize) +
542330d8983SJohannes Doerfert                          ";num_dims=" + std::to_string(NumDims));
543330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
544330d8983SJohannes Doerfert   DP("Call to omp_target_memcpy_rect_async, dst device %d, src device %d, "
545330d8983SJohannes Doerfert      "dst addr " DPxMOD ", src addr " DPxMOD ", dst offsets " DPxMOD ", "
546330d8983SJohannes Doerfert      "src offsets " DPxMOD ", dst dims " DPxMOD ", src dims " DPxMOD ", "
547330d8983SJohannes Doerfert      "volume " DPxMOD ", element size %zu, num_dims %d\n",
548330d8983SJohannes Doerfert      DstDevice, SrcDevice, DPxPTR(Dst), DPxPTR(Src), DPxPTR(DstOffsets),
549330d8983SJohannes Doerfert      DPxPTR(SrcOffsets), DPxPTR(DstDimensions), DPxPTR(SrcDimensions),
550330d8983SJohannes Doerfert      DPxPTR(Volume), ElementSize, NumDims);
551330d8983SJohannes Doerfert 
552330d8983SJohannes Doerfert   // Need to check this first to not return OFFLOAD_FAIL instead
553330d8983SJohannes Doerfert   if (!Dst && !Src) {
554330d8983SJohannes Doerfert     DP("Call to omp_target_memcpy_rect returns max supported dimensions %d\n",
555330d8983SJohannes Doerfert        INT_MAX);
556330d8983SJohannes Doerfert     return INT_MAX;
557330d8983SJohannes Doerfert   }
558330d8983SJohannes Doerfert 
559330d8983SJohannes Doerfert   // Check the source and dest address
560330d8983SJohannes Doerfert   if (Dst == nullptr || Src == nullptr)
561330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
562330d8983SJohannes Doerfert 
563330d8983SJohannes Doerfert   // Create task object
564330d8983SJohannes Doerfert   TargetMemcpyArgsTy *Args = new TargetMemcpyArgsTy(
565330d8983SJohannes Doerfert       Dst, Src, ElementSize, NumDims, Volume, DstOffsets, SrcOffsets,
566330d8983SJohannes Doerfert       DstDimensions, SrcDimensions, DstDevice, SrcDevice);
567330d8983SJohannes Doerfert 
568330d8983SJohannes Doerfert   // Create and launch helper task
569330d8983SJohannes Doerfert   int Rc = libomp_helper_task_creation(Args, &libomp_target_memcpy_async_task,
570330d8983SJohannes Doerfert                                        DepObjCount, DepObjList);
571330d8983SJohannes Doerfert 
572330d8983SJohannes Doerfert   DP("omp_target_memcpy_rect_async returns %d\n", Rc);
573330d8983SJohannes Doerfert   return Rc;
574330d8983SJohannes Doerfert }
575330d8983SJohannes Doerfert 
576330d8983SJohannes Doerfert EXTERN int omp_target_associate_ptr(const void *HostPtr, const void *DevicePtr,
577330d8983SJohannes Doerfert                                     size_t Size, size_t DeviceOffset,
578330d8983SJohannes Doerfert                                     int DeviceNum) {
579330d8983SJohannes Doerfert   TIMESCOPE();
580330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
581330d8983SJohannes Doerfert   DP("Call to omp_target_associate_ptr with host_ptr " DPxMOD ", "
582330d8983SJohannes Doerfert      "device_ptr " DPxMOD ", size %zu, device_offset %zu, device_num %d\n",
583330d8983SJohannes Doerfert      DPxPTR(HostPtr), DPxPTR(DevicePtr), Size, DeviceOffset, DeviceNum);
584330d8983SJohannes Doerfert 
585330d8983SJohannes Doerfert   if (!HostPtr || !DevicePtr || Size <= 0) {
586330d8983SJohannes Doerfert     REPORT("Call to omp_target_associate_ptr with invalid arguments\n");
587330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
588330d8983SJohannes Doerfert   }
589330d8983SJohannes Doerfert 
590330d8983SJohannes Doerfert   if (DeviceNum == omp_get_initial_device()) {
591330d8983SJohannes Doerfert     REPORT("omp_target_associate_ptr: no association possible on the host\n");
592330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
593330d8983SJohannes Doerfert   }
594330d8983SJohannes Doerfert 
595330d8983SJohannes Doerfert   auto DeviceOrErr = PM->getDevice(DeviceNum);
596330d8983SJohannes Doerfert   if (!DeviceOrErr)
597330d8983SJohannes Doerfert     FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
598330d8983SJohannes Doerfert 
599330d8983SJohannes Doerfert   void *DeviceAddr = (void *)((uint64_t)DevicePtr + (uint64_t)DeviceOffset);
600*caaf8099SJan Patrick Lehr 
601*caaf8099SJan Patrick Lehr   OMPT_IF_BUILT(InterfaceRAII(
602*caaf8099SJan Patrick Lehr       RegionInterface.getCallbacks<ompt_target_data_associate>(), DeviceNum,
603*caaf8099SJan Patrick Lehr       const_cast<void *>(HostPtr), const_cast<void *>(DevicePtr), Size,
604*caaf8099SJan Patrick Lehr       __builtin_return_address(0)));
605*caaf8099SJan Patrick Lehr 
606330d8983SJohannes Doerfert   int Rc = DeviceOrErr->getMappingInfo().associatePtr(
607330d8983SJohannes Doerfert       const_cast<void *>(HostPtr), const_cast<void *>(DeviceAddr), Size);
608330d8983SJohannes Doerfert   DP("omp_target_associate_ptr returns %d\n", Rc);
609330d8983SJohannes Doerfert   return Rc;
610330d8983SJohannes Doerfert }
611330d8983SJohannes Doerfert 
612330d8983SJohannes Doerfert EXTERN int omp_target_disassociate_ptr(const void *HostPtr, int DeviceNum) {
613330d8983SJohannes Doerfert   TIMESCOPE();
614330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
615330d8983SJohannes Doerfert   DP("Call to omp_target_disassociate_ptr with host_ptr " DPxMOD ", "
616330d8983SJohannes Doerfert      "device_num %d\n",
617330d8983SJohannes Doerfert      DPxPTR(HostPtr), DeviceNum);
618330d8983SJohannes Doerfert 
619330d8983SJohannes Doerfert   if (!HostPtr) {
620330d8983SJohannes Doerfert     REPORT("Call to omp_target_associate_ptr with invalid host_ptr\n");
621330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
622330d8983SJohannes Doerfert   }
623330d8983SJohannes Doerfert 
624330d8983SJohannes Doerfert   if (DeviceNum == omp_get_initial_device()) {
625330d8983SJohannes Doerfert     REPORT(
626330d8983SJohannes Doerfert         "omp_target_disassociate_ptr: no association possible on the host\n");
627330d8983SJohannes Doerfert     return OFFLOAD_FAIL;
628330d8983SJohannes Doerfert   }
629330d8983SJohannes Doerfert 
630330d8983SJohannes Doerfert   auto DeviceOrErr = PM->getDevice(DeviceNum);
631330d8983SJohannes Doerfert   if (!DeviceOrErr)
632330d8983SJohannes Doerfert     FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
633330d8983SJohannes Doerfert 
634*caaf8099SJan Patrick Lehr   OMPT_IF_BUILT(InterfaceRAII(
635*caaf8099SJan Patrick Lehr       RegionInterface.getCallbacks<ompt_target_data_disassociate>(), DeviceNum,
636*caaf8099SJan Patrick Lehr       const_cast<void *>(HostPtr),
637*caaf8099SJan Patrick Lehr       /*DevicePtr=*/nullptr, /*Size=*/0, __builtin_return_address(0)));
638*caaf8099SJan Patrick Lehr 
639330d8983SJohannes Doerfert   int Rc = DeviceOrErr->getMappingInfo().disassociatePtr(
640330d8983SJohannes Doerfert       const_cast<void *>(HostPtr));
641330d8983SJohannes Doerfert   DP("omp_target_disassociate_ptr returns %d\n", Rc);
642330d8983SJohannes Doerfert   return Rc;
643330d8983SJohannes Doerfert }
644330d8983SJohannes Doerfert 
645330d8983SJohannes Doerfert EXTERN void *omp_get_mapped_ptr(const void *Ptr, int DeviceNum) {
646330d8983SJohannes Doerfert   TIMESCOPE();
647330d8983SJohannes Doerfert   OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
648330d8983SJohannes Doerfert   DP("Call to omp_get_mapped_ptr with ptr " DPxMOD ", device_num %d.\n",
649330d8983SJohannes Doerfert      DPxPTR(Ptr), DeviceNum);
650330d8983SJohannes Doerfert 
651330d8983SJohannes Doerfert   if (!Ptr) {
652330d8983SJohannes Doerfert     REPORT("Call to omp_get_mapped_ptr with nullptr.\n");
653330d8983SJohannes Doerfert     return nullptr;
654330d8983SJohannes Doerfert   }
655330d8983SJohannes Doerfert 
65681d20d86SJoseph Huber   int NumDevices = omp_get_initial_device();
657330d8983SJohannes Doerfert   if (DeviceNum == NumDevices) {
658330d8983SJohannes Doerfert     DP("Device %d is initial device, returning Ptr " DPxMOD ".\n",
659330d8983SJohannes Doerfert            DeviceNum, DPxPTR(Ptr));
660330d8983SJohannes Doerfert     return const_cast<void *>(Ptr);
661330d8983SJohannes Doerfert   }
662330d8983SJohannes Doerfert 
663330d8983SJohannes Doerfert   if (NumDevices <= DeviceNum) {
664330d8983SJohannes Doerfert     DP("DeviceNum %d is invalid, returning nullptr.\n", DeviceNum);
665330d8983SJohannes Doerfert     return nullptr;
666330d8983SJohannes Doerfert   }
667330d8983SJohannes Doerfert 
668330d8983SJohannes Doerfert   auto DeviceOrErr = PM->getDevice(DeviceNum);
669330d8983SJohannes Doerfert   if (!DeviceOrErr)
670330d8983SJohannes Doerfert     FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
671330d8983SJohannes Doerfert 
672330d8983SJohannes Doerfert   TargetPointerResultTy TPR =
673330d8983SJohannes Doerfert       DeviceOrErr->getMappingInfo().getTgtPtrBegin(const_cast<void *>(Ptr), 1,
674330d8983SJohannes Doerfert                                                    /*UpdateRefCount=*/false,
675330d8983SJohannes Doerfert                                                    /*UseHoldRefCount=*/false);
676330d8983SJohannes Doerfert   if (!TPR.isPresent()) {
677330d8983SJohannes Doerfert     DP("Ptr " DPxMOD "is not present on device %d, returning nullptr.\n",
678330d8983SJohannes Doerfert        DPxPTR(Ptr), DeviceNum);
679330d8983SJohannes Doerfert     return nullptr;
680330d8983SJohannes Doerfert   }
681330d8983SJohannes Doerfert 
682330d8983SJohannes Doerfert   DP("omp_get_mapped_ptr returns " DPxMOD ".\n", DPxPTR(TPR.TargetPointer));
683330d8983SJohannes Doerfert 
684330d8983SJohannes Doerfert   return TPR.TargetPointer;
685330d8983SJohannes Doerfert }
686