Skip to content

Commit 5af3fa8

Browse files
authored
[Offload][OpenMP] Support shadow-pointer tracking for Fortran descriptors. (#158370)
This change adds support for saving full contents of attached Fortran descriptors, and not just their pointee address, in the shadow-pointer table. With this, we now support: * comparing full contents of descriptors to check whether a previous shadow-pointer entry is stale; * restoring the full contents of descriptors And with that, we can now use ATTACH map-types (added in #149036) for mapping Fortran pointer/allocatable arrays, and array-sections on them. e.g.: ```f90 integer, allocatable :: x(:) !$omp target enter data map(to: x(:)) ``` as: ``` void* addr_of_pointee = allocated(x) ? &x(1) : nullptr; int64_t sizeof_pointee = allocated(x) ? sizeof(x(:)) : 0 addr_of_pointee, addr_of_pointee, sizeof_pointee, TO addr_of_descriptor, addr_of_pointee, size_of_descriptor, ATTACH ```
1 parent 3a695e1 commit 5af3fa8

File tree

2 files changed

+109
-38
lines changed

2 files changed

+109
-38
lines changed

offload/include/OpenMP/Mapping.h

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,46 @@ class MappingConfig {
4949
/// Information about shadow pointers.
5050
struct ShadowPtrInfoTy {
5151
void **HstPtrAddr = nullptr;
52-
void *HstPtrVal = nullptr;
5352
void **TgtPtrAddr = nullptr;
54-
void *TgtPtrVal = nullptr;
53+
int64_t PtrSize = sizeof(void *); // Size of the pointer/descriptor
54+
55+
// Store the complete contents for both host and target pointers/descriptors.
56+
// 96 bytes is chosen as the "Small" size to cover simple Fortran
57+
// 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 from
72+
// 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 than
77+
// VoidPtrSize), then that's that.
78+
if (PtrSize <= VoidPtrSize)
79+
return;
80+
81+
// For larger pointers, i.e. Fortran descriptors, the remaining contents of
82+
// 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;
5592

5693
bool operator==(const ShadowPtrInfoTy &Other) const {
5794
return HstPtrAddr == Other.HstPtrAddr;
@@ -243,9 +280,25 @@ struct HostDataToTargetTy {
243280
auto Pair = States->ShadowPtrInfos.insert(ShadowPtrInfo);
244281
if (Pair.second)
245282
return true;
283+
246284
// Check for a stale entry, if found, replace the old one.
247-
if ((*Pair.first).TgtPtrVal == ShadowPtrInfo.TgtPtrVal)
285+
286+
// For Fortran descriptors, we need to compare their full contents,
287+
// as the starting address may be the same while other fields have
288+
// 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 of
297+
// 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)
248300
return false;
301+
249302
States->ShadowPtrInfos.erase(ShadowPtrInfo);
250303
return addShadowPointer(ShadowPtrInfo);
251304
}

offload/libomptarget/omptarget.cpp

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ static int performPointerAttachment(DeviceTy &Device, AsyncInfoTy &AsyncInfo,
396396
assert(PtrTPR.getEntry() &&
397397
"Need a valid pointer entry to perform pointer-attachment");
398398

399-
int64_t VoidPtrSize = sizeof(void *);
399+
constexpr int64_t VoidPtrSize = sizeof(void *);
400400
assert(HstPtrSize >= VoidPtrSize && "PointerSize is too small");
401401

402402
uint64_t Delta = reinterpret_cast<uint64_t>(HstPteeBegin) -
@@ -411,23 +411,8 @@ static int performPointerAttachment(DeviceTy &Device, AsyncInfoTy &AsyncInfo,
411411
DPxPTR(TgtPteeBase), DPxPTR(TgtPteeBegin));
412412

413413
// Add shadow pointer tracking
414-
// TODO: Support shadow-tracking of larger than VoidPtrSize pointers,
415-
// to support restoration of Fortran descriptors. Currently, this check
416-
// would return false, even if the host Fortran descriptor had been
417-
// updated since its previous map, and we should have updated its
418-
// device counterpart. e.g.
419-
//
420-
// !$omp target enter data map(x(1:100)) ! (1)
421-
// p => x(10: 19)
422-
// !$omp target enter data map(p, p(:)) ! (2)
423-
// p => x(5: 9)
424-
// !$omp target enter data map(attach(always): p(:)) ! (3)
425-
//
426-
// While PtrAddr(&desc_p) and PteeBase(&p(1)) are same for (2) and (3), the
427-
// pointer attachment for (3) needs to update the bounds information
428-
// in the descriptor of p on device.
429414
if (!PtrTPR.getEntry()->addShadowPointer(
430-
ShadowPtrInfoTy{HstPtrAddr, HstPteeBase, TgtPtrAddr, TgtPteeBase})) {
415+
ShadowPtrInfoTy{HstPtrAddr, TgtPtrAddr, TgtPteeBase, HstPtrSize})) {
431416
DP("Pointer " DPxMOD " is already attached to " DPxMOD "\n",
432417
DPxPTR(TgtPtrAddr), DPxPTR(TgtPteeBase));
433418
return OFFLOAD_SUCCESS;
@@ -940,17 +925,29 @@ postProcessingTargetDataEnd(DeviceTy *Device,
940925
DelEntry = false;
941926
}
942927

943-
// If we copied back to the host a struct/array containing pointers,
944-
// we need to restore the original host pointer values from their
945-
// shadow copies. If the struct is going to be deallocated, remove any
946-
// remaining shadow pointer entries for this struct.
928+
// If we copied back to the host a struct/array containing pointers, or
929+
// Fortran descriptors (which are larger than a "void *"), we need to
930+
// restore the original host pointer/descriptor values from their shadow
931+
// copies. If the struct is going to be deallocated, remove any remaining
932+
// shadow pointer entries for this struct.
947933
const bool HasFrom = ArgType & OMP_TGT_MAPTYPE_FROM;
948934
if (HasFrom) {
949935
Entry->foreachShadowPointerInfo([&](const ShadowPtrInfoTy &ShadowPtr) {
950-
*ShadowPtr.HstPtrAddr = ShadowPtr.HstPtrVal;
951-
DP("Restoring original host pointer value " DPxMOD " for host "
952-
"pointer " DPxMOD "\n",
953-
DPxPTR(ShadowPtr.HstPtrVal), DPxPTR(ShadowPtr.HstPtrAddr));
936+
constexpr int64_t VoidPtrSize = sizeof(void *);
937+
if (ShadowPtr.PtrSize > VoidPtrSize) {
938+
DP("Restoring host descriptor " DPxMOD
939+
" to its original content (%" PRId64
940+
" bytes), containing pointee address " DPxMOD "\n",
941+
DPxPTR(ShadowPtr.HstPtrAddr), ShadowPtr.PtrSize,
942+
DPxPTR(ShadowPtr.HstPtrContent.data()));
943+
} else {
944+
DP("Restoring host pointer " DPxMOD " to its original value " DPxMOD
945+
"\n",
946+
DPxPTR(ShadowPtr.HstPtrAddr),
947+
DPxPTR(ShadowPtr.HstPtrContent.data()));
948+
}
949+
std::memcpy(ShadowPtr.HstPtrAddr, ShadowPtr.HstPtrContent.data(),
950+
ShadowPtr.PtrSize);
954951
return OFFLOAD_SUCCESS;
955952
});
956953
}
@@ -1163,12 +1160,22 @@ static int targetDataContiguous(ident_t *Loc, DeviceTy &Device, void *ArgsBase,
11631160
if (TPR.getEntry()) {
11641161
int Ret = TPR.getEntry()->foreachShadowPointerInfo(
11651162
[&](ShadowPtrInfoTy &ShadowPtr) {
1166-
DP("Restoring original target pointer value " DPxMOD " for target "
1167-
"pointer " DPxMOD "\n",
1168-
DPxPTR(ShadowPtr.TgtPtrVal), DPxPTR(ShadowPtr.TgtPtrAddr));
1163+
constexpr int64_t VoidPtrSize = sizeof(void *);
1164+
if (ShadowPtr.PtrSize > VoidPtrSize) {
1165+
DP("Restoring target descriptor " DPxMOD
1166+
" to its original content (%" PRId64
1167+
" bytes), containing pointee address " DPxMOD "\n",
1168+
DPxPTR(ShadowPtr.TgtPtrAddr), ShadowPtr.PtrSize,
1169+
DPxPTR(ShadowPtr.TgtPtrContent.data()));
1170+
} else {
1171+
DP("Restoring target pointer " DPxMOD
1172+
" to its original value " DPxMOD "\n",
1173+
DPxPTR(ShadowPtr.TgtPtrAddr),
1174+
DPxPTR(ShadowPtr.TgtPtrContent.data()));
1175+
}
11691176
Ret = Device.submitData(ShadowPtr.TgtPtrAddr,
1170-
(void *)&ShadowPtr.TgtPtrVal,
1171-
sizeof(void *), AsyncInfo);
1177+
ShadowPtr.TgtPtrContent.data(),
1178+
ShadowPtr.PtrSize, AsyncInfo);
11721179
if (Ret != OFFLOAD_SUCCESS) {
11731180
REPORT("Copying data to device failed.\n");
11741181
return OFFLOAD_FAIL;
@@ -1193,15 +1200,26 @@ static int targetDataContiguous(ident_t *Loc, DeviceTy &Device, void *ArgsBase,
11931200
}
11941201

11951202
// Wait for device-to-host memcopies for whole struct to complete,
1196-
// before restoring the correct host pointer.
1203+
// before restoring the correct host pointer/descriptor.
11971204
if (auto *Entry = TPR.getEntry()) {
11981205
AsyncInfo.addPostProcessingFunction([=]() -> int {
11991206
int Ret = Entry->foreachShadowPointerInfo(
12001207
[&](const ShadowPtrInfoTy &ShadowPtr) {
1201-
*ShadowPtr.HstPtrAddr = ShadowPtr.HstPtrVal;
1202-
DP("Restoring original host pointer value " DPxMOD
1203-
" for host pointer " DPxMOD "\n",
1204-
DPxPTR(ShadowPtr.HstPtrVal), DPxPTR(ShadowPtr.HstPtrAddr));
1208+
constexpr int64_t VoidPtrSize = sizeof(void *);
1209+
if (ShadowPtr.PtrSize > VoidPtrSize) {
1210+
DP("Restoring host descriptor " DPxMOD
1211+
" to its original content (%" PRId64
1212+
" bytes), containing pointee address " DPxMOD "\n",
1213+
DPxPTR(ShadowPtr.HstPtrAddr), ShadowPtr.PtrSize,
1214+
DPxPTR(ShadowPtr.HstPtrContent.data()));
1215+
} else {
1216+
DP("Restoring host pointer " DPxMOD
1217+
" to its original value " DPxMOD "\n",
1218+
DPxPTR(ShadowPtr.HstPtrAddr),
1219+
DPxPTR(ShadowPtr.HstPtrContent.data()));
1220+
}
1221+
std::memcpy(ShadowPtr.HstPtrAddr, ShadowPtr.HstPtrContent.data(),
1222+
ShadowPtr.PtrSize);
12051223
return OFFLOAD_SUCCESS;
12061224
});
12071225
Entry->unlock();

0 commit comments

Comments
 (0)