Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / openmp / libomptarget / include / device.h
blobcd76d88618be4ee6aab6d61e23a4f9353504a8cd
1 //===----------- device.h - Target independent OpenMP target RTL ----------===//
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 // Declarations for managing devices that are handled by RTL plugins.
11 //===----------------------------------------------------------------------===//
13 #ifndef _OMPTARGET_DEVICE_H
14 #define _OMPTARGET_DEVICE_H
16 #include <cassert>
17 #include <cstddef>
18 #include <cstdint>
19 #include <cstring>
20 #include <list>
21 #include <map>
22 #include <memory>
23 #include <mutex>
24 #include <set>
25 #include <thread>
27 #include "ExclusiveAccess.h"
28 #include "omptarget.h"
29 #include "rtl.h"
30 #include "llvm/ADT/SmallSet.h"
31 #include "llvm/ADT/SmallVector.h"
33 // Forward declarations.
34 struct RTLInfoTy;
35 struct __tgt_bin_desc;
36 struct __tgt_target_table;
38 using map_var_info_t = void *;
40 // enum for OMP_TARGET_OFFLOAD; keep in sync with kmp.h definition
41 enum kmp_target_offload_kind {
42 tgt_disabled = 0,
43 tgt_default = 1,
44 tgt_mandatory = 2
46 typedef enum kmp_target_offload_kind kmp_target_offload_kind_t;
48 /// Information about shadow pointers.
49 struct ShadowPtrInfoTy {
50 void **HstPtrAddr = nullptr;
51 void *HstPtrVal = nullptr;
52 void **TgtPtrAddr = nullptr;
53 void *TgtPtrVal = nullptr;
55 bool operator==(const ShadowPtrInfoTy &Other) const {
56 return HstPtrAddr == Other.HstPtrAddr;
60 inline bool operator<(const ShadowPtrInfoTy &lhs, const ShadowPtrInfoTy &rhs) {
61 return lhs.HstPtrAddr < rhs.HstPtrAddr;
64 /// Map between host data and target data.
65 struct HostDataToTargetTy {
66 const uintptr_t HstPtrBase; // host info.
67 const uintptr_t HstPtrBegin;
68 const uintptr_t HstPtrEnd; // non-inclusive.
69 const map_var_info_t HstPtrName; // Optional source name of mapped variable.
71 const uintptr_t TgtAllocBegin; // allocated target memory
72 const uintptr_t TgtPtrBegin; // mapped target memory = TgtAllocBegin + padding
74 private:
75 static const uint64_t INFRefCount = ~(uint64_t)0;
76 static std::string refCountToStr(uint64_t RefCount) {
77 return RefCount == INFRefCount ? "INF" : std::to_string(RefCount);
80 struct StatesTy {
81 StatesTy(uint64_t DRC, uint64_t HRC)
82 : DynRefCount(DRC), HoldRefCount(HRC) {}
83 /// The dynamic reference count is the standard reference count as of OpenMP
84 /// 4.5. The hold reference count is an OpenMP extension for the sake of
85 /// OpenACC support.
86 ///
87 /// The 'ompx_hold' map type modifier is permitted only on "omp target" and
88 /// "omp target data", and "delete" is permitted only on "omp target exit
89 /// data" and associated runtime library routines. As a result, we really
90 /// need to implement "reset" functionality only for the dynamic reference
91 /// counter. Likewise, only the dynamic reference count can be infinite
92 /// because, for example, omp_target_associate_ptr and "omp declare target
93 /// link" operate only on it. Nevertheless, it's actually easier to follow
94 /// the code (and requires less assertions for special cases) when we just
95 /// implement these features generally across both reference counters here.
96 /// Thus, it's the users of this class that impose those restrictions.
97 ///
98 uint64_t DynRefCount;
99 uint64_t HoldRefCount;
101 /// A map of shadow pointers associated with this entry, the keys are host
102 /// pointer addresses to identify stale entries.
103 llvm::SmallSet<ShadowPtrInfoTy, 2> ShadowPtrInfos;
105 /// Pointer to the event corresponding to the data update of this map.
106 /// Note: At present this event is created when the first data transfer from
107 /// host to device is issued, and only being used for H2D. It is not used
108 /// for data transfer in another direction (device to host). It is still
109 /// unclear whether we need it for D2H. If in the future we need similar
110 /// mechanism for D2H, and if the event cannot be shared between them, Event
111 /// should be written as <tt>void *Event[2]</tt>.
112 void *Event = nullptr;
114 /// Number of threads currently holding a reference to the entry at a
115 /// targetDataEnd. This is used to ensure that only the last thread that
116 /// references this entry will actually delete it.
117 int32_t DataEndThreadCount = 0;
119 // When HostDataToTargetTy is used by std::set, std::set::iterator is const
120 // use unique_ptr to make States mutable.
121 const std::unique_ptr<StatesTy> States;
123 public:
124 HostDataToTargetTy(uintptr_t BP, uintptr_t B, uintptr_t E,
125 uintptr_t TgtAllocBegin, uintptr_t TgtPtrBegin,
126 bool UseHoldRefCount, map_var_info_t Name = nullptr,
127 bool IsINF = false)
128 : HstPtrBase(BP), HstPtrBegin(B), HstPtrEnd(E), HstPtrName(Name),
129 TgtAllocBegin(TgtAllocBegin), TgtPtrBegin(TgtPtrBegin),
130 States(std::make_unique<StatesTy>(UseHoldRefCount ? 0
131 : IsINF ? INFRefCount
132 : 1,
133 !UseHoldRefCount ? 0
134 : IsINF ? INFRefCount
135 : 1)) {}
137 /// Get the total reference count. This is smarter than just getDynRefCount()
138 /// + getHoldRefCount() because it handles the case where at least one is
139 /// infinity and the other is non-zero.
140 uint64_t getTotalRefCount() const {
141 if (States->DynRefCount == INFRefCount ||
142 States->HoldRefCount == INFRefCount)
143 return INFRefCount;
144 return States->DynRefCount + States->HoldRefCount;
147 /// Get the dynamic reference count.
148 uint64_t getDynRefCount() const { return States->DynRefCount; }
150 /// Get the hold reference count.
151 uint64_t getHoldRefCount() const { return States->HoldRefCount; }
153 /// Get the event bound to this data map.
154 void *getEvent() const { return States->Event; }
156 /// Add a new event, if necessary.
157 /// Returns OFFLOAD_FAIL if something went wrong, OFFLOAD_SUCCESS otherwise.
158 int addEventIfNecessary(DeviceTy &Device, AsyncInfoTy &AsyncInfo) const;
160 /// Functions that manages the number of threads referencing the entry in a
161 /// targetDataEnd.
162 void incDataEndThreadCount() { ++States->DataEndThreadCount; }
164 [[nodiscard]] int32_t decDataEndThreadCount() {
165 return --States->DataEndThreadCount;
168 [[nodiscard]] int32_t getDataEndThreadCount() const {
169 return States->DataEndThreadCount;
172 /// Set the event bound to this data map.
173 void setEvent(void *Event) const { States->Event = Event; }
175 /// Reset the specified reference count unless it's infinity. Reset to 1
176 /// (even if currently 0) so it can be followed by a decrement.
177 void resetRefCount(bool UseHoldRefCount) const {
178 uint64_t &ThisRefCount =
179 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;
180 if (ThisRefCount != INFRefCount)
181 ThisRefCount = 1;
184 /// Increment the specified reference count unless it's infinity.
185 void incRefCount(bool UseHoldRefCount) const {
186 uint64_t &ThisRefCount =
187 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;
188 if (ThisRefCount != INFRefCount) {
189 ++ThisRefCount;
190 assert(ThisRefCount < INFRefCount && "refcount overflow");
194 /// Decrement the specified reference count unless it's infinity or zero, and
195 /// return the total reference count.
196 uint64_t decRefCount(bool UseHoldRefCount) const {
197 uint64_t &ThisRefCount =
198 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;
199 uint64_t OtherRefCount =
200 UseHoldRefCount ? States->DynRefCount : States->HoldRefCount;
201 (void)OtherRefCount;
202 if (ThisRefCount != INFRefCount) {
203 if (ThisRefCount > 0)
204 --ThisRefCount;
205 else
206 assert(OtherRefCount >= 0 && "total refcount underflow");
208 return getTotalRefCount();
211 /// Is the dynamic (and thus the total) reference count infinite?
212 bool isDynRefCountInf() const { return States->DynRefCount == INFRefCount; }
214 /// Convert the dynamic reference count to a debug string.
215 std::string dynRefCountToStr() const {
216 return refCountToStr(States->DynRefCount);
219 /// Convert the hold reference count to a debug string.
220 std::string holdRefCountToStr() const {
221 return refCountToStr(States->HoldRefCount);
224 /// Should one decrement of the specified reference count (after resetting it
225 /// if \c AfterReset) remove this mapping?
226 bool decShouldRemove(bool UseHoldRefCount, bool AfterReset = false) const {
227 uint64_t ThisRefCount =
228 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;
229 uint64_t OtherRefCount =
230 UseHoldRefCount ? States->DynRefCount : States->HoldRefCount;
231 if (OtherRefCount > 0)
232 return false;
233 if (AfterReset)
234 return ThisRefCount != INFRefCount;
235 return ThisRefCount == 1;
238 /// Add the shadow pointer info \p ShadowPtrInfo to this entry but only if the
239 /// the target ptr value was not already present in the existing set of shadow
240 /// pointers. Return true if something was added.
241 bool addShadowPointer(const ShadowPtrInfoTy &ShadowPtrInfo) const {
242 auto Pair = States->ShadowPtrInfos.insert(ShadowPtrInfo);
243 if (Pair.second)
244 return true;
245 // Check for a stale entry, if found, replace the old one.
246 if ((*Pair.first).TgtPtrVal == ShadowPtrInfo.TgtPtrVal)
247 return false;
248 States->ShadowPtrInfos.erase(ShadowPtrInfo);
249 return addShadowPointer(ShadowPtrInfo);
252 /// Apply \p CB to all shadow pointers of this entry. Returns OFFLOAD_FAIL if
253 /// \p CB returned OFFLOAD_FAIL for any of them, otherwise this returns
254 /// OFFLOAD_SUCCESS. The entry is locked for this operation.
255 template <typename CBTy> int foreachShadowPointerInfo(CBTy CB) const {
256 for (auto &It : States->ShadowPtrInfos)
257 if (CB(const_cast<ShadowPtrInfoTy &>(It)) == OFFLOAD_FAIL)
258 return OFFLOAD_FAIL;
259 return OFFLOAD_SUCCESS;
262 /// Lock this entry for exclusive access. Ensure to get exclusive access to
263 /// HDTTMap first!
264 void lock() const { Mtx.lock(); }
266 /// Unlock this entry to allow other threads inspecting it.
267 void unlock() const { Mtx.unlock(); }
269 private:
270 // Mutex that needs to be held before the entry is inspected or modified. The
271 // HDTTMap mutex needs to be held before trying to lock any HDTT Entry.
272 mutable std::mutex Mtx;
275 /// Wrapper around the HostDataToTargetTy to be used in the HDTT map. In
276 /// addition to the HDTT pointer we store the key value explicitly. This
277 /// allows the set to inspect (sort/search/...) this entry without an additional
278 /// load of HDTT. HDTT is a pointer to allow the modification of the set without
279 /// invalidating HDTT entries which can now be inspected at the same time.
280 struct HostDataToTargetMapKeyTy {
281 uintptr_t KeyValue;
283 HostDataToTargetMapKeyTy(void *Key) : KeyValue(uintptr_t(Key)) {}
284 HostDataToTargetMapKeyTy(uintptr_t Key) : KeyValue(Key) {}
285 HostDataToTargetMapKeyTy(HostDataToTargetTy *HDTT)
286 : KeyValue(HDTT->HstPtrBegin), HDTT(HDTT) {}
287 HostDataToTargetTy *HDTT;
289 inline bool operator<(const HostDataToTargetMapKeyTy &LHS,
290 const uintptr_t &RHS) {
291 return LHS.KeyValue < RHS;
293 inline bool operator<(const uintptr_t &LHS,
294 const HostDataToTargetMapKeyTy &RHS) {
295 return LHS < RHS.KeyValue;
297 inline bool operator<(const HostDataToTargetMapKeyTy &LHS,
298 const HostDataToTargetMapKeyTy &RHS) {
299 return LHS.KeyValue < RHS.KeyValue;
302 /// This struct will be returned by \p DeviceTy::getTargetPointer which provides
303 /// more data than just a target pointer. A TargetPointerResultTy that has a non
304 /// null Entry owns the entry. As long as the TargetPointerResultTy (TPR) exists
305 /// the entry is locked. To give up ownership without destroying the TPR use the
306 /// reset() function.
307 struct TargetPointerResultTy {
308 struct FlagTy {
309 /// If the map table entry is just created
310 unsigned IsNewEntry : 1;
311 /// If the pointer is actually a host pointer (when unified memory enabled)
312 unsigned IsHostPointer : 1;
313 /// If the pointer is present in the mapping table.
314 unsigned IsPresent : 1;
315 /// Flag indicating that this was the last user of the entry and the ref
316 /// count is now 0.
317 unsigned IsLast : 1;
318 /// If the pointer is contained.
319 unsigned IsContained : 1;
320 } Flags = {0, 0, 0, 0, 0};
322 TargetPointerResultTy(const TargetPointerResultTy &) = delete;
323 TargetPointerResultTy &operator=(const TargetPointerResultTy &TPR) = delete;
324 TargetPointerResultTy() {}
326 TargetPointerResultTy(FlagTy Flags, HostDataToTargetTy *Entry,
327 void *TargetPointer)
328 : Flags(Flags), TargetPointer(TargetPointer), Entry(Entry) {
329 if (Entry)
330 Entry->lock();
333 TargetPointerResultTy(TargetPointerResultTy &&TPR)
334 : Flags(TPR.Flags), TargetPointer(TPR.TargetPointer), Entry(TPR.Entry) {
335 TPR.Entry = nullptr;
338 TargetPointerResultTy &operator=(TargetPointerResultTy &&TPR) {
339 if (&TPR != this) {
340 std::swap(Flags, TPR.Flags);
341 std::swap(Entry, TPR.Entry);
342 std::swap(TargetPointer, TPR.TargetPointer);
344 return *this;
347 ~TargetPointerResultTy() {
348 if (Entry)
349 Entry->unlock();
352 bool isPresent() const { return Flags.IsPresent; }
354 bool isHostPointer() const { return Flags.IsHostPointer; }
356 bool isContained() const { return Flags.IsContained; }
358 /// The corresponding target pointer
359 void *TargetPointer = nullptr;
361 HostDataToTargetTy *getEntry() const { return Entry; }
362 void setEntry(HostDataToTargetTy *HDTTT,
363 HostDataToTargetTy *OwnedTPR = nullptr) {
364 if (Entry)
365 Entry->unlock();
366 Entry = HDTTT;
367 if (Entry && Entry != OwnedTPR)
368 Entry->lock();
371 void reset() { *this = TargetPointerResultTy(); }
373 private:
374 /// The corresponding map table entry which is stable.
375 HostDataToTargetTy *Entry = nullptr;
378 struct LookupResult {
379 struct {
380 unsigned IsContained : 1;
381 unsigned ExtendsBefore : 1;
382 unsigned ExtendsAfter : 1;
383 } Flags;
385 LookupResult() : Flags({0, 0, 0}), TPR() {}
387 TargetPointerResultTy TPR;
391 struct PendingCtorDtorListsTy {
392 std::list<void *> PendingCtors;
393 std::list<void *> PendingDtors;
395 typedef std::map<__tgt_bin_desc *, PendingCtorDtorListsTy>
396 PendingCtorsDtorsPerLibrary;
398 struct DeviceTy {
399 int32_t DeviceID;
400 RTLInfoTy *RTL;
401 int32_t RTLDeviceID;
403 bool IsInit;
404 std::once_flag InitFlag;
405 bool HasPendingGlobals;
407 /// Host data to device map type with a wrapper key indirection that allows
408 /// concurrent modification of the entries without invalidating the underlying
409 /// entries.
410 using HostDataToTargetListTy =
411 std::set<HostDataToTargetMapKeyTy, std::less<>>;
413 /// The HDTTMap is a protected object that can only be accessed by one thread
414 /// at a time.
415 ProtectedObj<HostDataToTargetListTy> HostDataToTargetMap;
417 /// The type used to access the HDTT map.
418 using HDTTMapAccessorTy = decltype(HostDataToTargetMap)::AccessorTy;
420 PendingCtorsDtorsPerLibrary PendingCtorsDtors;
422 std::mutex PendingGlobalsMtx;
424 DeviceTy(RTLInfoTy *RTL);
425 // DeviceTy is not copyable
426 DeviceTy(const DeviceTy &D) = delete;
427 DeviceTy &operator=(const DeviceTy &D) = delete;
429 ~DeviceTy();
431 // Return true if data can be copied to DstDevice directly
432 bool isDataExchangable(const DeviceTy &DstDevice);
434 /// Lookup the mapping of \p HstPtrBegin in \p HDTTMap. The accessor ensures
435 /// exclusive access to the HDTT map.
436 LookupResult lookupMapping(HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin,
437 int64_t Size,
438 HostDataToTargetTy *OwnedTPR = nullptr);
440 /// Get the target pointer based on host pointer begin and base. If the
441 /// mapping already exists, the target pointer will be returned directly. In
442 /// addition, if required, the memory region pointed by \p HstPtrBegin of size
443 /// \p Size will also be transferred to the device. If the mapping doesn't
444 /// exist, and if unified shared memory is not enabled, a new mapping will be
445 /// created and the data will also be transferred accordingly. nullptr will be
446 /// returned because of any of following reasons:
447 /// - Data allocation failed;
448 /// - The user tried to do an illegal mapping;
449 /// - Data transfer issue fails.
450 TargetPointerResultTy getTargetPointer(
451 HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin, void *HstPtrBase,
452 int64_t TgtPadding, int64_t Size, map_var_info_t HstPtrName,
453 bool HasFlagTo, bool HasFlagAlways, bool IsImplicit, bool UpdateRefCount,
454 bool HasCloseModifier, bool HasPresentModifier, bool HasHoldModifier,
455 AsyncInfoTy &AsyncInfo, HostDataToTargetTy *OwnedTPR = nullptr,
456 bool ReleaseHDTTMap = true);
458 /// Return the target pointer for \p HstPtrBegin in \p HDTTMap. The accessor
459 /// ensures exclusive access to the HDTT map.
460 void *getTgtPtrBegin(HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin,
461 int64_t Size);
463 /// Return the target pointer begin (where the data will be moved).
464 /// Used by targetDataBegin, targetDataEnd, targetDataUpdate and target.
465 /// - \p UpdateRefCount and \p UseHoldRefCount controls which and if the entry
466 /// reference counters will be decremented.
467 /// - \p MustContain enforces that the query must not extend beyond an already
468 /// mapped entry to be valid.
469 /// - \p ForceDelete deletes the entry regardless of its reference counting
470 /// (unless it is infinite).
471 /// - \p FromDataEnd tracks the number of threads referencing the entry at
472 /// targetDataEnd for delayed deletion purpose.
473 [[nodiscard]] TargetPointerResultTy
474 getTgtPtrBegin(void *HstPtrBegin, int64_t Size, bool UpdateRefCount,
475 bool UseHoldRefCount, bool MustContain = false,
476 bool ForceDelete = false, bool FromDataEnd = false);
478 /// Remove the \p Entry from the data map. Expect the entry's total reference
479 /// count to be zero and the caller thread to be the last one using it. \p
480 /// HDTTMap ensure the caller holds exclusive access and can modify the map.
481 /// Return \c OFFLOAD_SUCCESS if the map entry existed, and return \c
482 /// OFFLOAD_FAIL if not. It is the caller's responsibility to skip calling
483 /// this function if the map entry is not expected to exist because \p
484 /// HstPtrBegin uses shared memory.
485 [[nodiscard]] int eraseMapEntry(HDTTMapAccessorTy &HDTTMap,
486 HostDataToTargetTy *Entry, int64_t Size);
488 /// Deallocate the \p Entry from the device memory and delete it. Return \c
489 /// OFFLOAD_SUCCESS if the deallocation operations executed successfully, and
490 /// return \c OFFLOAD_FAIL otherwise.
491 [[nodiscard]] int deallocTgtPtrAndEntry(HostDataToTargetTy *Entry,
492 int64_t Size);
494 int associatePtr(void *HstPtrBegin, void *TgtPtrBegin, int64_t Size);
495 int disassociatePtr(void *HstPtrBegin);
497 // calls to RTL
498 int32_t initOnce();
499 __tgt_target_table *loadBinary(void *Img);
501 // device memory allocation/deallocation routines
502 /// Allocates \p Size bytes on the device, host or shared memory space
503 /// (depending on \p Kind) and returns the address/nullptr when
504 /// succeeds/fails. \p HstPtr is an address of the host data which the
505 /// allocated target data will be associated with. If it is unknown, the
506 /// default value of \p HstPtr is nullptr. Note: this function doesn't do
507 /// pointer association. Actually, all the __tgt_rtl_data_alloc
508 /// implementations ignore \p HstPtr. \p Kind dictates what allocator should
509 /// be used (host, shared, device).
510 void *allocData(int64_t Size, void *HstPtr = nullptr,
511 int32_t Kind = TARGET_ALLOC_DEFAULT);
512 /// Deallocates memory which \p TgtPtrBegin points at and returns
513 /// OFFLOAD_SUCCESS/OFFLOAD_FAIL when succeeds/fails. p Kind dictates what
514 /// allocator should be used (host, shared, device).
515 int32_t deleteData(void *TgtPtrBegin, int32_t Kind = TARGET_ALLOC_DEFAULT);
517 // Data transfer. When AsyncInfo is nullptr, the transfer will be
518 // synchronous.
519 // Copy data from host to device
520 int32_t submitData(void *TgtPtrBegin, void *HstPtrBegin, int64_t Size,
521 AsyncInfoTy &AsyncInfo,
522 HostDataToTargetTy *Entry = nullptr);
523 // Copy data from device back to host
524 int32_t retrieveData(void *HstPtrBegin, void *TgtPtrBegin, int64_t Size,
525 AsyncInfoTy &AsyncInfo,
526 HostDataToTargetTy *Entry = nullptr);
527 // Copy data from current device to destination device directly
528 int32_t dataExchange(void *SrcPtr, DeviceTy &DstDev, void *DstPtr,
529 int64_t Size, AsyncInfoTy &AsyncInfo);
531 /// Notify the plugin about a new mapping starting at the host address
532 /// \p HstPtr and \p Size bytes.
533 int32_t notifyDataMapped(void *HstPtr, int64_t Size);
535 /// Notify the plugin about an existing mapping being unmapped starting at
536 /// the host address \p HstPtr.
537 int32_t notifyDataUnmapped(void *HstPtr);
539 // Launch the kernel identified by \p TgtEntryPtr with the given arguments.
540 int32_t launchKernel(void *TgtEntryPtr, void **TgtVarsPtr,
541 ptrdiff_t *TgtOffsets, const KernelArgsTy &KernelArgs,
542 AsyncInfoTy &AsyncInfo);
544 /// Synchronize device/queue/event based on \p AsyncInfo and return
545 /// OFFLOAD_SUCCESS/OFFLOAD_FAIL when succeeds/fails.
546 int32_t synchronize(AsyncInfoTy &AsyncInfo);
548 /// Query for device/queue/event based completion on \p AsyncInfo in a
549 /// non-blocking manner and return OFFLOAD_SUCCESS/OFFLOAD_FAIL when
550 /// succeeds/fails. Must be called multiple times until AsyncInfo is
551 /// completed and AsyncInfo.isDone() returns true.
552 int32_t queryAsync(AsyncInfoTy &AsyncInfo);
554 /// Calls the corresponding print in the \p RTLDEVID
555 /// device RTL to obtain the information of the specific device.
556 bool printDeviceInfo(int32_t RTLDevID);
558 /// Event related interfaces.
559 /// {
560 /// Create an event.
561 int32_t createEvent(void **Event);
563 /// Record the event based on status in AsyncInfo->Queue at the moment the
564 /// function is called.
565 int32_t recordEvent(void *Event, AsyncInfoTy &AsyncInfo);
567 /// Wait for an event. This function can be blocking or non-blocking,
568 /// depending on the implmentation. It is expected to set a dependence on the
569 /// event such that corresponding operations shall only start once the event
570 /// is fulfilled.
571 int32_t waitEvent(void *Event, AsyncInfoTy &AsyncInfo);
573 /// Synchronize the event. It is expected to block the thread.
574 int32_t syncEvent(void *Event);
576 /// Destroy the event.
577 int32_t destroyEvent(void *Event);
578 /// }
580 private:
581 // Call to RTL
582 void init(); // To be called only via DeviceTy::initOnce()
584 /// Deinitialize the device (and plugin).
585 void deinit();
588 extern bool deviceIsReady(int DeviceNum);
590 /// Struct for the data required to handle plugins
591 struct PluginManager {
592 PluginManager(bool UseEventsForAtomicTransfers)
593 : UseEventsForAtomicTransfers(UseEventsForAtomicTransfers) {}
595 /// RTLs identified on the host
596 RTLsTy RTLs;
598 /// Executable images and information extracted from the input images passed
599 /// to the runtime.
600 std::list<std::pair<__tgt_device_image, __tgt_image_info>> Images;
602 /// Devices associated with RTLs
603 llvm::SmallVector<std::unique_ptr<DeviceTy>> Devices;
604 std::mutex RTLsMtx; ///< For RTLs and Devices
606 /// Translation table retreived from the binary
607 HostEntriesBeginToTransTableTy HostEntriesBeginToTransTable;
608 std::mutex TrlTblMtx; ///< For Translation Table
609 /// Host offload entries in order of image registration
610 llvm::SmallVector<__tgt_offload_entry *> HostEntriesBeginRegistrationOrder;
612 /// Map from ptrs on the host to an entry in the Translation Table
613 HostPtrToTableMapTy HostPtrToTableMap;
614 std::mutex TblMapMtx; ///< For HostPtrToTableMap
616 // Store target policy (disabled, mandatory, default)
617 kmp_target_offload_kind_t TargetOffloadPolicy = tgt_default;
618 std::mutex TargetOffloadMtx; ///< For TargetOffloadPolicy
620 /// Flag to indicate if we use events to ensure the atomicity of
621 /// map clauses or not. Can be modified with an environment variable.
622 const bool UseEventsForAtomicTransfers;
624 // Work around for plugins that call dlopen on shared libraries that call
625 // tgt_register_lib during their initialisation. Stash the pointers in a
626 // vector until the plugins are all initialised and then register them.
627 bool maybeDelayRegisterLib(__tgt_bin_desc *Desc) {
628 if (!RTLsLoaded) {
629 // Only reachable from libomptarget constructor
630 DelayedBinDesc.push_back(Desc);
631 return true;
632 } else {
633 return false;
637 void registerDelayedLibraries() {
638 // Only called by libomptarget constructor
639 RTLsLoaded = true;
640 for (auto *Desc : DelayedBinDesc)
641 __tgt_register_lib(Desc);
642 DelayedBinDesc.clear();
645 private:
646 bool RTLsLoaded = false;
647 llvm::SmallVector<__tgt_bin_desc *> DelayedBinDesc;
650 extern PluginManager *PM;
652 #endif