Skip to content

Commit 12769aa

Browse files
abhinavgabaadurang
andauthored
[Offload] Introduce ATTACH map-type support for pointer attachment. (#149036)
This patch introduces libomptarget support for the ATTACH map-type, which can be used to implement OpenMP conditional compliant pointer attachment, based on whether the pointer/pointee is newly mapped on a given construct. For example, for the following: ```c int *p; #pragma omp target enter data map(p[1:10]) ``` The following maps can be emitted by clang: ``` (A) &p[0], &p[1], 10 * sizeof(p[1]), TO | FROM &p, &p[1], sizeof(p), ATTACH ``` Without this map-type, these two possible maps could be emitted by clang: ``` (B) &p[0], &p[1], 10 * sizeof(p[1]), TO | FROM (C) &p, &p[1], 10 * sizeof(p[1]), TO | FROM | PTR_AND_OBJ ```` (B) does not perform any pointer attachment, while (C) also maps the pointer p, which are both incorrect. In terms of implementation, maps with the ATTACH map-type are handled after all other maps have been processed, as it requires knowledge of which new allocations happened as part of the construct. As per OpenMP 5.0, an attachment should happen only when either the pointer or the pointee was newly mapped while handling the construct. Maps with ATTACH map-type-bit do not increase/decrease the ref-count. With OpenMP 6.1, `attach(always/never)` can be used to force/prevent attachment. For `attach(always)`, the compiler will insert the ALWAYS map-type, which would let libomptarget bypass the check about one of the pointer/pointee being new. With `attach(never)`, the ATTACH map will not be emitted at all. The size argument of the ATTACH map-type can specify values greater than `sizeof(void*)` which can be used to support pointer attachment on Fortran descriptors. Note that this also requires shadow-pointer tracking to also support them. That has not been implemented in this patch. This was worked upon in coordination with Ravi Narayanaswamy, who has since retired. Happy retirement, Ravi! --------- Co-authored-by: Alex Duran <[email protected]>
1 parent dff8dac commit 12769aa

File tree

6 files changed

+471
-37
lines changed

6 files changed

+471
-37
lines changed

offload/include/OpenMP/Mapping.h

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,12 +417,42 @@ struct MapperComponentsTy {
417417
typedef void (*MapperFuncPtrTy)(void *, void *, void *, int64_t, int64_t,
418418
void *);
419419

420+
/// Structure to store information about a single ATTACH map entry.
421+
struct AttachMapInfo {
422+
void *PointerBase;
423+
void *PointeeBegin;
424+
int64_t PointerSize;
425+
int64_t MapType;
426+
map_var_info_t Pointername;
427+
428+
AttachMapInfo(void *PointerBase, void *PointeeBegin, int64_t Size,
429+
int64_t Type, map_var_info_t Name)
430+
: PointerBase(PointerBase), PointeeBegin(PointeeBegin), PointerSize(Size),
431+
MapType(Type), Pointername(Name) {}
432+
};
433+
434+
/// Structure to track ATTACH entries and new allocations across recursive calls
435+
/// (for handling mappers) to targetDataBegin for a given construct.
436+
struct AttachInfoTy {
437+
/// ATTACH map entries for deferred processing.
438+
llvm::SmallVector<AttachMapInfo> AttachEntries;
439+
440+
/// Key: host pointer, Value: allocation size.
441+
llvm::DenseMap<void *, int64_t> NewAllocations;
442+
443+
AttachInfoTy() = default;
444+
445+
// Delete copy constructor and copy assignment operator to prevent copying
446+
AttachInfoTy(const AttachInfoTy &) = delete;
447+
AttachInfoTy &operator=(const AttachInfoTy &) = delete;
448+
};
449+
420450
// Function pointer type for targetData* functions (targetDataBegin,
421451
// targetDataEnd and targetDataUpdate).
422452
typedef int (*TargetDataFuncPtrTy)(ident_t *, DeviceTy &, int32_t, void **,
423453
void **, int64_t *, int64_t *,
424454
map_var_info_t *, void **, AsyncInfoTy &,
425-
bool);
455+
AttachInfoTy *, bool);
426456

427457
void dumpTargetPointerMappings(const ident_t *Loc, DeviceTy &Device,
428458
bool toStdOut = false);
@@ -431,20 +461,26 @@ int targetDataBegin(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
431461
void **ArgsBase, void **Args, int64_t *ArgSizes,
432462
int64_t *ArgTypes, map_var_info_t *ArgNames,
433463
void **ArgMappers, AsyncInfoTy &AsyncInfo,
464+
AttachInfoTy *AttachInfo = nullptr,
434465
bool FromMapper = false);
435466

436467
int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
437468
void **ArgBases, void **Args, int64_t *ArgSizes,
438469
int64_t *ArgTypes, map_var_info_t *ArgNames,
439470
void **ArgMappers, AsyncInfoTy &AsyncInfo,
440-
bool FromMapper = false);
471+
AttachInfoTy *AttachInfo = nullptr, bool FromMapper = false);
441472

442473
int targetDataUpdate(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
443474
void **ArgsBase, void **Args, int64_t *ArgSizes,
444475
int64_t *ArgTypes, map_var_info_t *ArgNames,
445476
void **ArgMappers, AsyncInfoTy &AsyncInfo,
477+
AttachInfoTy *AttachInfo = nullptr,
446478
bool FromMapper = false);
447479

480+
// Process deferred ATTACH map entries collected during targetDataBegin.
481+
int processAttachEntries(DeviceTy &Device, AttachInfoTy &AttachInfo,
482+
AsyncInfoTy &AsyncInfo);
483+
448484
struct MappingInfoTy {
449485
MappingInfoTy(DeviceTy &Device) : Device(Device) {}
450486

offload/include/device.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ struct DeviceTy {
9898
int32_t dataExchange(void *SrcPtr, DeviceTy &DstDev, void *DstPtr,
9999
int64_t Size, AsyncInfoTy &AsyncInfo);
100100

101+
// Insert a data fence between previous data operations and the following
102+
// operations if necessary for the device.
103+
int32_t dataFence(AsyncInfoTy &AsyncInfo);
104+
101105
/// Notify the plugin about a new mapping starting at the host address
102106
/// \p HstPtr and \p Size bytes.
103107
int32_t notifyDataMapped(void *HstPtr, int64_t Size);

offload/include/omptarget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ enum tgt_map_type {
7777
// the structured region
7878
// This is an OpenMP extension for the sake of OpenACC support.
7979
OMP_TGT_MAPTYPE_OMPX_HOLD = 0x2000,
80+
// Attach pointer and pointee, after processing all other maps.
81+
// Applicable to map-entering directives. Does not change ref-count.
82+
OMP_TGT_MAPTYPE_ATTACH = 0x4000,
8083
// descriptor for non-contiguous target-update
8184
OMP_TGT_MAPTYPE_NON_CONTIG = 0x100000000000,
8285
// member of struct, member given by [16 MSBs] - 1

offload/libomptarget/device.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ int32_t DeviceTy::dataExchange(void *SrcPtr, DeviceTy &DstDev, void *DstPtr,
191191
DstPtr, Size, AsyncInfo);
192192
}
193193

194+
int32_t DeviceTy::dataFence(AsyncInfoTy &AsyncInfo) {
195+
return RTL->data_fence(RTLDeviceID, AsyncInfo);
196+
}
197+
194198
int32_t DeviceTy::notifyDataMapped(void *HstPtr, int64_t Size) {
195199
DP("Notifying about new mapping: HstPtr=" DPxMOD ", Size=%" PRId64 "\n",
196200
DPxPTR(HstPtr), Size);

offload/libomptarget/interface.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <cstdint>
3131
#include <cstdio>
3232
#include <cstdlib>
33+
#include <memory>
3334

3435
#ifdef OMPT_SUPPORT
3536
using namespace llvm::omp::target::ompt;
@@ -165,12 +166,24 @@ targetData(ident_t *Loc, int64_t DeviceId, int32_t ArgNum, void **ArgsBase,
165166
OMPT_GET_RETURN_ADDRESS);)
166167

167168
int Rc = OFFLOAD_SUCCESS;
169+
170+
// Only allocate AttachInfo for targetDataBegin
171+
std::unique_ptr<AttachInfoTy> AttachInfo;
172+
if (TargetDataFunction == targetDataBegin)
173+
AttachInfo = std::make_unique<AttachInfoTy>();
174+
168175
Rc = TargetDataFunction(Loc, *DeviceOrErr, ArgNum, ArgsBase, Args, ArgSizes,
169176
ArgTypes, ArgNames, ArgMappers, AsyncInfo,
170-
false /*FromMapper=*/);
177+
AttachInfo.get(), /*FromMapper=*/false);
171178

172-
if (Rc == OFFLOAD_SUCCESS)
173-
Rc = AsyncInfo.synchronize();
179+
if (Rc == OFFLOAD_SUCCESS) {
180+
// Process deferred ATTACH entries BEFORE synchronization
181+
if (AttachInfo && !AttachInfo->AttachEntries.empty())
182+
Rc = processAttachEntries(*DeviceOrErr, *AttachInfo, AsyncInfo);
183+
184+
if (Rc == OFFLOAD_SUCCESS)
185+
Rc = AsyncInfo.synchronize();
186+
}
174187

175188
handleTargetOutcome(Rc == OFFLOAD_SUCCESS, Loc);
176189
}

0 commit comments

Comments
 (0)