628 lines · c
1//===-- OpenMP/Mapping.h - OpenMP/OpenACC pointer mapping -------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Declarations for managing host-to-device pointer mappings.10//11//===----------------------------------------------------------------------===//12 13#ifndef OMPTARGET_OPENMP_MAPPING_H14#define OMPTARGET_OPENMP_MAPPING_H15 16#include "ExclusiveAccess.h"17#include "Shared/EnvironmentVar.h"18#include "omptarget.h"19 20#include <cstdint>21#include <mutex>22#include <string>23 24#include "llvm/ADT/SmallSet.h"25 26struct DeviceTy;27class AsyncInfoTy;28 29using map_var_info_t = void *;30 31class MappingConfig {32 33 MappingConfig() {34 BoolEnvar ForceAtomic = BoolEnvar("LIBOMPTARGET_MAP_FORCE_ATOMIC", true);35 UseEventsForAtomicTransfers = ForceAtomic;36 }37 38public:39 static const MappingConfig &get() {40 static MappingConfig MP;41 return MP;42 };43 44 /// Flag to indicate if we use events to ensure the atomicity of45 /// map clauses or not. Can be modified with an environment variable.46 bool UseEventsForAtomicTransfers = true;47};48 49/// Information about shadow pointers.50struct ShadowPtrInfoTy {51 void **HstPtrAddr = nullptr;52 void **TgtPtrAddr = nullptr;53 int64_t PtrSize = sizeof(void *); // Size of the pointer/descriptor54 55 // Store the complete contents for both host and target pointers/descriptors.56 // 96 bytes is chosen as the "Small" size to cover simple Fortran57 // descriptors of up to 3 dimensions.58 llvm::SmallVector<char, 96> HstPtrContent;59 llvm::SmallVector<char, 96> TgtPtrContent;60 61 ShadowPtrInfoTy(void **HstPtrAddr, void **TgtPtrAddr, void *TgtPteeBase,62 int64_t PtrSize)63 : HstPtrAddr(HstPtrAddr), TgtPtrAddr(TgtPtrAddr), PtrSize(PtrSize),64 HstPtrContent(PtrSize), TgtPtrContent(PtrSize) {65 constexpr int64_t VoidPtrSize = sizeof(void *);66 assert(HstPtrAddr != nullptr && "HstPtrAddr is nullptr");67 assert(TgtPtrAddr != nullptr && "TgtPtrAddr is nullptr");68 assert(PtrSize >= VoidPtrSize && "PtrSize is less than sizeof(void *)");69 70 void *HstPteeBase = *HstPtrAddr;71 // The first VoidPtrSize bytes for HstPtrContent/TgtPtrContent are from72 // HstPteeBase/TgtPteeBase.73 std::memcpy(HstPtrContent.data(), &HstPteeBase, VoidPtrSize);74 std::memcpy(TgtPtrContent.data(), &TgtPteeBase, VoidPtrSize);75 76 // If we are not dealing with Fortran descriptors (pointers larger than77 // VoidPtrSize), then that's that.78 if (PtrSize <= VoidPtrSize)79 return;80 81 // For larger pointers, i.e. Fortran descriptors, the remaining contents of82 // the descriptor come from the host descriptor, i.e. HstPtrAddr.83 std::memcpy(HstPtrContent.data() + VoidPtrSize,84 reinterpret_cast<char *>(HstPtrAddr) + VoidPtrSize,85 PtrSize - VoidPtrSize);86 std::memcpy(TgtPtrContent.data() + VoidPtrSize,87 reinterpret_cast<char *>(HstPtrAddr) + VoidPtrSize,88 PtrSize - VoidPtrSize);89 }90 91 ShadowPtrInfoTy() = delete;92 93 bool operator==(const ShadowPtrInfoTy &Other) const {94 return HstPtrAddr == Other.HstPtrAddr;95 }96};97 98inline bool operator<(const ShadowPtrInfoTy &lhs, const ShadowPtrInfoTy &rhs) {99 return lhs.HstPtrAddr < rhs.HstPtrAddr;100}101 102/// Map between host data and target data.103struct HostDataToTargetTy {104 const uintptr_t HstPtrBase; // host info.105 const uintptr_t HstPtrBegin;106 const uintptr_t HstPtrEnd; // non-inclusive.107 const map_var_info_t HstPtrName; // Optional source name of mapped variable.108 109 const uintptr_t TgtAllocBegin; // allocated target memory110 const uintptr_t TgtPtrBegin; // mapped target memory = TgtAllocBegin + padding111 112private:113 static const uint64_t INFRefCount = ~(uint64_t)0;114 static std::string refCountToStr(uint64_t RefCount) {115 return RefCount == INFRefCount ? "INF" : std::to_string(RefCount);116 }117 118 struct StatesTy {119 StatesTy(uint64_t DRC, uint64_t HRC)120 : DynRefCount(DRC), HoldRefCount(HRC) {}121 /// The dynamic reference count is the standard reference count as of OpenMP122 /// 4.5. The hold reference count is an OpenMP extension for the sake of123 /// OpenACC support.124 ///125 /// The 'ompx_hold' map type modifier is permitted only on "omp target" and126 /// "omp target data", and "delete" is permitted only on "omp target exit127 /// data" and associated runtime library routines. As a result, we really128 /// need to implement "reset" functionality only for the dynamic reference129 /// counter. Likewise, only the dynamic reference count can be infinite130 /// because, for example, omp_target_associate_ptr and "omp declare target131 /// link" operate only on it. Nevertheless, it's actually easier to follow132 /// the code (and requires less assertions for special cases) when we just133 /// implement these features generally across both reference counters here.134 /// Thus, it's the users of this class that impose those restrictions.135 ///136 uint64_t DynRefCount;137 uint64_t HoldRefCount;138 139 /// A map of shadow pointers associated with this entry, the keys are host140 /// pointer addresses to identify stale entries.141 llvm::SmallSet<ShadowPtrInfoTy, 2> ShadowPtrInfos;142 143 /// Pointer to the event corresponding to the data update of this map.144 /// Note: At present this event is created when the first data transfer from145 /// host to device is issued, and only being used for H2D. It is not used146 /// for data transfer in another direction (device to host). It is still147 /// unclear whether we need it for D2H. If in the future we need similar148 /// mechanism for D2H, and if the event cannot be shared between them, Event149 /// should be written as <tt>void *Event[2]</tt>.150 void *Event = nullptr;151 152 /// Number of threads currently holding a reference to the entry at a153 /// targetDataEnd. This is used to ensure that only the last thread that154 /// references this entry will actually delete it.155 int32_t DataEndThreadCount = 0;156 };157 // When HostDataToTargetTy is used by std::set, std::set::iterator is const158 // use unique_ptr to make States mutable.159 const std::unique_ptr<StatesTy> States;160 161public:162 HostDataToTargetTy(uintptr_t BP, uintptr_t B, uintptr_t E,163 uintptr_t TgtAllocBegin, uintptr_t TgtPtrBegin,164 bool UseHoldRefCount, map_var_info_t Name = nullptr,165 bool IsINF = false)166 : HstPtrBase(BP), HstPtrBegin(B), HstPtrEnd(E), HstPtrName(Name),167 TgtAllocBegin(TgtAllocBegin), TgtPtrBegin(TgtPtrBegin),168 States(std::make_unique<StatesTy>(UseHoldRefCount ? 0169 : IsINF ? INFRefCount170 : 1,171 !UseHoldRefCount ? 0172 : IsINF ? INFRefCount173 : 1)) {}174 175 /// Get the total reference count. This is smarter than just getDynRefCount()176 /// + getHoldRefCount() because it handles the case where at least one is177 /// infinity and the other is non-zero.178 uint64_t getTotalRefCount() const {179 if (States->DynRefCount == INFRefCount ||180 States->HoldRefCount == INFRefCount)181 return INFRefCount;182 return States->DynRefCount + States->HoldRefCount;183 }184 185 /// Get the dynamic reference count.186 uint64_t getDynRefCount() const { return States->DynRefCount; }187 188 /// Get the hold reference count.189 uint64_t getHoldRefCount() const { return States->HoldRefCount; }190 191 /// Get the event bound to this data map.192 void *getEvent() const { return States->Event; }193 194 /// Add a new event, if necessary.195 /// Returns OFFLOAD_FAIL if something went wrong, OFFLOAD_SUCCESS otherwise.196 int addEventIfNecessary(DeviceTy &Device, AsyncInfoTy &AsyncInfo) const;197 198 /// Functions that manages the number of threads referencing the entry in a199 /// targetDataEnd.200 void incDataEndThreadCount() { ++States->DataEndThreadCount; }201 202 [[nodiscard]] int32_t decDataEndThreadCount() {203 return --States->DataEndThreadCount;204 }205 206 [[nodiscard]] int32_t getDataEndThreadCount() const {207 return States->DataEndThreadCount;208 }209 210 /// Set the event bound to this data map.211 void setEvent(void *Event) const { States->Event = Event; }212 213 /// Reset the specified reference count unless it's infinity. Reset to 1214 /// (even if currently 0) so it can be followed by a decrement.215 void resetRefCount(bool UseHoldRefCount) const {216 uint64_t &ThisRefCount =217 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;218 if (ThisRefCount != INFRefCount)219 ThisRefCount = 1;220 }221 222 /// Increment the specified reference count unless it's infinity.223 void incRefCount(bool UseHoldRefCount) const {224 uint64_t &ThisRefCount =225 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;226 if (ThisRefCount != INFRefCount) {227 ++ThisRefCount;228 assert(ThisRefCount < INFRefCount && "refcount overflow");229 }230 }231 232 /// Decrement the specified reference count unless it's infinity or zero, and233 /// return the total reference count.234 uint64_t decRefCount(bool UseHoldRefCount) const {235 uint64_t &ThisRefCount =236 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;237 uint64_t OtherRefCount =238 UseHoldRefCount ? States->DynRefCount : States->HoldRefCount;239 (void)OtherRefCount;240 if (ThisRefCount != INFRefCount) {241 if (ThisRefCount > 0)242 --ThisRefCount;243 else244 assert(OtherRefCount >= 0 && "total refcount underflow");245 }246 return getTotalRefCount();247 }248 249 /// Is the dynamic (and thus the total) reference count infinite?250 bool isDynRefCountInf() const { return States->DynRefCount == INFRefCount; }251 252 /// Convert the dynamic reference count to a debug string.253 std::string dynRefCountToStr() const {254 return refCountToStr(States->DynRefCount);255 }256 257 /// Convert the hold reference count to a debug string.258 std::string holdRefCountToStr() const {259 return refCountToStr(States->HoldRefCount);260 }261 262 /// Should one decrement of the specified reference count (after resetting it263 /// if \c AfterReset) remove this mapping?264 bool decShouldRemove(bool UseHoldRefCount, bool AfterReset = false) const {265 uint64_t ThisRefCount =266 UseHoldRefCount ? States->HoldRefCount : States->DynRefCount;267 uint64_t OtherRefCount =268 UseHoldRefCount ? States->DynRefCount : States->HoldRefCount;269 if (OtherRefCount > 0)270 return false;271 if (AfterReset)272 return ThisRefCount != INFRefCount;273 return ThisRefCount == 1;274 }275 276 /// Add the shadow pointer info \p ShadowPtrInfo to this entry but only if the277 /// the target ptr value was not already present in the existing set of shadow278 /// pointers. Return true if something was added.279 bool addShadowPointer(const ShadowPtrInfoTy &ShadowPtrInfo) const {280 auto Pair = States->ShadowPtrInfos.insert(ShadowPtrInfo);281 if (Pair.second)282 return true;283 284 // Check for a stale entry, if found, replace the old one.285 286 // For Fortran descriptors, we need to compare their full contents,287 // as the starting address may be the same while other fields have288 // been updated. e.g.289 //290 // !$omp target enter data map(x(1:100)) ! (1)291 // p => x(10: 19)292 // !$omp target enter data map(p, p(:)) ! (2)293 // p => x(5: 9)294 // !$omp target enter data map(attach(always): p(:)) ! (3)295 //296 // While &desc_p and &p(1) (TgtPtrAddr and first "sizeof(void*)" bytes of297 // TgtPtrContent) are same for (2) and (3), the pointer attachment for (3)298 // needs to update the bounds information in the descriptor of p on device.299 if ((*Pair.first).TgtPtrContent == ShadowPtrInfo.TgtPtrContent)300 return false;301 302 States->ShadowPtrInfos.erase(ShadowPtrInfo);303 return addShadowPointer(ShadowPtrInfo);304 }305 306 /// Apply \p CB to all shadow pointers of this entry. Returns OFFLOAD_FAIL if307 /// \p CB returned OFFLOAD_FAIL for any of them, otherwise this returns308 /// OFFLOAD_SUCCESS. The entry is locked for this operation.309 template <typename CBTy> int foreachShadowPointerInfo(CBTy CB) const {310 for (auto &It : States->ShadowPtrInfos)311 if (CB(const_cast<ShadowPtrInfoTy &>(It)) == OFFLOAD_FAIL)312 return OFFLOAD_FAIL;313 return OFFLOAD_SUCCESS;314 }315 316 /// Lock this entry for exclusive access. Ensure to get exclusive access to317 /// HDTTMap first!318 void lock() const { Mtx.lock(); }319 320 /// Unlock this entry to allow other threads inspecting it.321 void unlock() const { Mtx.unlock(); }322 323private:324 // Mutex that needs to be held before the entry is inspected or modified. The325 // HDTTMap mutex needs to be held before trying to lock any HDTT Entry.326 mutable std::mutex Mtx;327};328 329/// Wrapper around the HostDataToTargetTy to be used in the HDTT map. In330/// addition to the HDTT pointer we store the key value explicitly. This331/// allows the set to inspect (sort/search/...) this entry without an additional332/// load of HDTT. HDTT is a pointer to allow the modification of the set without333/// invalidating HDTT entries which can now be inspected at the same time.334struct HostDataToTargetMapKeyTy {335 uintptr_t KeyValue;336 337 HostDataToTargetMapKeyTy(void *Key) : KeyValue(uintptr_t(Key)) {}338 HostDataToTargetMapKeyTy(uintptr_t Key) : KeyValue(Key) {}339 HostDataToTargetMapKeyTy(HostDataToTargetTy *HDTT)340 : KeyValue(HDTT->HstPtrBegin), HDTT(HDTT) {}341 HostDataToTargetTy *HDTT;342};343inline bool operator<(const HostDataToTargetMapKeyTy &LHS,344 const uintptr_t &RHS) {345 return LHS.KeyValue < RHS;346}347inline bool operator<(const uintptr_t &LHS,348 const HostDataToTargetMapKeyTy &RHS) {349 return LHS < RHS.KeyValue;350}351inline bool operator<(const HostDataToTargetMapKeyTy &LHS,352 const HostDataToTargetMapKeyTy &RHS) {353 return LHS.KeyValue < RHS.KeyValue;354}355 356/// This struct will be returned by \p DeviceTy::getTargetPointer which provides357/// more data than just a target pointer. A TargetPointerResultTy that has a non358/// null Entry owns the entry. As long as the TargetPointerResultTy (TPR) exists359/// the entry is locked. To give up ownership without destroying the TPR use the360/// reset() function.361struct TargetPointerResultTy {362 struct FlagTy {363 /// If the map table entry is just created364 unsigned IsNewEntry : 1;365 /// If the pointer is actually a host pointer (when unified memory enabled)366 unsigned IsHostPointer : 1;367 /// If the pointer is present in the mapping table.368 unsigned IsPresent : 1;369 /// Flag indicating that this was the last user of the entry and the ref370 /// count is now 0.371 unsigned IsLast : 1;372 /// If the pointer is contained.373 unsigned IsContained : 1;374 } Flags = {0, 0, 0, 0, 0};375 376 TargetPointerResultTy(const TargetPointerResultTy &) = delete;377 TargetPointerResultTy &operator=(const TargetPointerResultTy &TPR) = delete;378 TargetPointerResultTy() {}379 380 TargetPointerResultTy(FlagTy Flags, HostDataToTargetTy *Entry,381 void *TargetPointer)382 : Flags(Flags), TargetPointer(TargetPointer), Entry(Entry) {383 if (Entry)384 Entry->lock();385 }386 387 TargetPointerResultTy(TargetPointerResultTy &&TPR)388 : Flags(TPR.Flags), TargetPointer(TPR.TargetPointer), Entry(TPR.Entry) {389 TPR.Entry = nullptr;390 }391 392 TargetPointerResultTy &operator=(TargetPointerResultTy &&TPR) {393 if (&TPR != this) {394 std::swap(Flags, TPR.Flags);395 std::swap(Entry, TPR.Entry);396 std::swap(TargetPointer, TPR.TargetPointer);397 }398 return *this;399 }400 401 ~TargetPointerResultTy() {402 if (Entry)403 Entry->unlock();404 }405 406 bool isPresent() const { return Flags.IsPresent; }407 408 bool isHostPointer() const { return Flags.IsHostPointer; }409 410 bool isContained() const { return Flags.IsContained; }411 412 /// The corresponding target pointer413 void *TargetPointer = nullptr;414 415 HostDataToTargetTy *getEntry() const { return Entry; }416 void setEntry(HostDataToTargetTy *HDTTT,417 HostDataToTargetTy *OwnedTPR = nullptr) {418 if (Entry)419 Entry->unlock();420 Entry = HDTTT;421 if (Entry && Entry != OwnedTPR)422 Entry->lock();423 }424 425 void reset() { *this = TargetPointerResultTy(); }426 427private:428 /// The corresponding map table entry which is stable.429 HostDataToTargetTy *Entry = nullptr;430};431 432struct LookupResult {433 struct {434 unsigned IsContained : 1;435 unsigned ExtendsBefore : 1;436 unsigned ExtendsAfter : 1;437 } Flags;438 439 LookupResult() : Flags({0, 0, 0}), TPR() {}440 441 TargetPointerResultTy TPR;442};443 444// This structure stores information of a mapped memory region.445struct MapComponentInfoTy {446 void *Base;447 void *Begin;448 int64_t Size;449 int64_t Type;450 void *Name;451 MapComponentInfoTy() = default;452 MapComponentInfoTy(void *Base, void *Begin, int64_t Size, int64_t Type,453 void *Name)454 : Base(Base), Begin(Begin), Size(Size), Type(Type), Name(Name) {}455};456 457// This structure stores all components of a user-defined mapper. The number of458// components are dynamically decided, so we utilize C++ STL vector459// implementation here.460struct MapperComponentsTy {461 llvm::SmallVector<MapComponentInfoTy> Components;462 int32_t size() { return Components.size(); }463};464 465// The mapper function pointer type. It follows the signature below:466// void .omp_mapper.<type_name>.<mapper_id>.(void *rt_mapper_handle,467// void *base, void *begin,468// size_t size, int64_t type,469// void * name);470typedef void (*MapperFuncPtrTy)(void *, void *, void *, int64_t, int64_t,471 void *);472 473/// Structure to store information about a single ATTACH map entry.474struct AttachMapInfo {475 void *PointerBase;476 void *PointeeBegin;477 int64_t PointerSize;478 int64_t MapType;479 map_var_info_t Pointername;480 481 AttachMapInfo(void *PointerBase, void *PointeeBegin, int64_t Size,482 int64_t Type, map_var_info_t Name)483 : PointerBase(PointerBase), PointeeBegin(PointeeBegin), PointerSize(Size),484 MapType(Type), Pointername(Name) {}485};486 487/// Structure to track ATTACH entries and new allocations across recursive calls488/// (for handling mappers) to targetDataBegin for a given construct.489struct AttachInfoTy {490 /// ATTACH map entries for deferred processing.491 llvm::SmallVector<AttachMapInfo> AttachEntries;492 493 /// Key: host pointer, Value: allocation size.494 llvm::DenseMap<void *, int64_t> NewAllocations;495 496 AttachInfoTy() = default;497 498 // Delete copy constructor and copy assignment operator to prevent copying499 AttachInfoTy(const AttachInfoTy &) = delete;500 AttachInfoTy &operator=(const AttachInfoTy &) = delete;501};502 503// Function pointer type for targetData* functions (targetDataBegin,504// targetDataEnd and targetDataUpdate).505typedef int (*TargetDataFuncPtrTy)(ident_t *, DeviceTy &, int32_t, void **,506 void **, int64_t *, int64_t *,507 map_var_info_t *, void **, AsyncInfoTy &,508 AttachInfoTy *, bool);509 510void dumpTargetPointerMappings(const ident_t *Loc, DeviceTy &Device,511 bool toStdOut = false);512 513int targetDataBegin(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,514 void **ArgsBase, void **Args, int64_t *ArgSizes,515 int64_t *ArgTypes, map_var_info_t *ArgNames,516 void **ArgMappers, AsyncInfoTy &AsyncInfo,517 AttachInfoTy *AttachInfo = nullptr,518 bool FromMapper = false);519 520int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,521 void **ArgBases, void **Args, int64_t *ArgSizes,522 int64_t *ArgTypes, map_var_info_t *ArgNames,523 void **ArgMappers, AsyncInfoTy &AsyncInfo,524 AttachInfoTy *AttachInfo = nullptr, bool FromMapper = false);525 526int targetDataUpdate(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,527 void **ArgsBase, void **Args, int64_t *ArgSizes,528 int64_t *ArgTypes, map_var_info_t *ArgNames,529 void **ArgMappers, AsyncInfoTy &AsyncInfo,530 AttachInfoTy *AttachInfo = nullptr,531 bool FromMapper = false);532 533// Process deferred ATTACH map entries collected during targetDataBegin.534int processAttachEntries(DeviceTy &Device, AttachInfoTy &AttachInfo,535 AsyncInfoTy &AsyncInfo);536 537struct MappingInfoTy {538 MappingInfoTy(DeviceTy &Device) : Device(Device) {}539 540 /// Host data to device map type with a wrapper key indirection that allows541 /// concurrent modification of the entries without invalidating the underlying542 /// entries.543 using HostDataToTargetListTy =544 std::set<HostDataToTargetMapKeyTy, std::less<>>;545 546 /// The HDTTMap is a protected object that can only be accessed by one thread547 /// at a time.548 ProtectedObj<HostDataToTargetListTy> HostDataToTargetMap;549 550 /// The type used to access the HDTT map.551 using HDTTMapAccessorTy = decltype(HostDataToTargetMap)::AccessorTy;552 553 /// Lookup the mapping of \p HstPtrBegin in \p HDTTMap. The accessor ensures554 /// exclusive access to the HDTT map.555 LookupResult lookupMapping(HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin,556 int64_t Size,557 HostDataToTargetTy *OwnedTPR = nullptr);558 559 /// Get the target pointer based on host pointer begin and base. If the560 /// mapping already exists, the target pointer will be returned directly. In561 /// addition, if required, the memory region pointed by \p HstPtrBegin of size562 /// \p Size will also be transferred to the device. If the mapping doesn't563 /// exist, and if unified shared memory is not enabled, a new mapping will be564 /// created and the data will also be transferred accordingly. nullptr will be565 /// returned because of any of following reasons:566 /// - Data allocation failed;567 /// - The user tried to do an illegal mapping;568 /// - Data transfer issue fails.569 TargetPointerResultTy getTargetPointer(570 HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin, void *HstPtrBase,571 int64_t TgtPadding, int64_t Size, map_var_info_t HstPtrName,572 bool HasFlagTo, bool HasFlagAlways, bool IsImplicit, bool UpdateRefCount,573 bool HasCloseModifier, bool HasPresentModifier, bool HasHoldModifier,574 AsyncInfoTy &AsyncInfo, HostDataToTargetTy *OwnedTPR = nullptr,575 bool ReleaseHDTTMap = true);576 577 /// Return the target pointer for \p HstPtrBegin in \p HDTTMap. The accessor578 /// ensures exclusive access to the HDTT map.579 void *getTgtPtrBegin(HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin,580 int64_t Size);581 582 /// Return the target pointer begin (where the data will be moved).583 /// Used by targetDataBegin, targetDataEnd, targetDataUpdate and target.584 /// - \p UpdateRefCount and \p UseHoldRefCount controls which and if the entry585 /// reference counters will be decremented.586 /// - \p MustContain enforces that the query must not extend beyond an already587 /// mapped entry to be valid.588 /// - \p ForceDelete deletes the entry regardless of its reference counting589 /// (unless it is infinite).590 /// - \p FromDataEnd tracks the number of threads referencing the entry at591 /// targetDataEnd for delayed deletion purpose.592 [[nodiscard]] TargetPointerResultTy593 getTgtPtrBegin(void *HstPtrBegin, int64_t Size, bool UpdateRefCount,594 bool UseHoldRefCount, bool MustContain = false,595 bool ForceDelete = false, bool FromDataEnd = false);596 597 /// Remove the \p Entry from the data map. Expect the entry's total reference598 /// count to be zero and the caller thread to be the last one using it. \p599 /// HDTTMap ensure the caller holds exclusive access and can modify the map.600 /// Return \c OFFLOAD_SUCCESS if the map entry existed, and return \c601 /// OFFLOAD_FAIL if not. It is the caller's responsibility to skip calling602 /// this function if the map entry is not expected to exist because \p603 /// HstPtrBegin uses shared memory.604 [[nodiscard]] int eraseMapEntry(HDTTMapAccessorTy &HDTTMap,605 HostDataToTargetTy *Entry, int64_t Size);606 607 /// Deallocate the \p Entry from the device memory and delete it. Return \c608 /// OFFLOAD_SUCCESS if the deallocation operations executed successfully, and609 /// return \c OFFLOAD_FAIL otherwise.610 [[nodiscard]] int deallocTgtPtrAndEntry(HostDataToTargetTy *Entry,611 int64_t Size);612 613 int associatePtr(void *HstPtrBegin, void *TgtPtrBegin, int64_t Size);614 int disassociatePtr(void *HstPtrBegin);615 616 /// Print information about the transfer from \p HstPtr to \p TgtPtr (or vice617 /// versa if \p H2D is false). If there is an existing mapping, or if \p Entry618 /// is set, the associated metadata will be printed as well.619 void printCopyInfo(void *TgtPtr, void *HstPtr, int64_t Size, bool H2D,620 HostDataToTargetTy *Entry,621 MappingInfoTy::HDTTMapAccessorTy *HDTTMapPtr);622 623private:624 DeviceTy &Device;625};626 627#endif // OMPTARGET_OPENMP_MAPPING_H628