@@ -1086,6 +1086,7 @@ int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
10861086 HstPtrBegin, DataSize, UpdateRef, HasHoldModifier, !IsImplicit,
10871087 ForceDelete, /* FromDataEnd=*/ true );
10881088 void *TgtPtrBegin = TPR.TargetPointer ;
1089+
10891090 if (!TPR.isPresent () && !TPR.isHostPointer () &&
10901091 (DataSize || HasPresentModifier)) {
10911092 DP (" Mapping does not exist (%s)\n " ,
@@ -1125,6 +1126,11 @@ int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
11251126 if (!TPR.isPresent ())
11261127 continue ;
11271128
1129+ // Track force-deleted pointers so we can use this information if we
1130+ // encounter FROM entries for the same pointer later on.
1131+ if (ForceDelete && TPR.Flags .IsLast )
1132+ StateInfo->MarkedForDeletionPtrs .insert (HstPtrBegin);
1133+
11281134 // Move data back to the host
11291135 const bool HasAlways = ArgTypes[I] & OMP_TGT_MAPTYPE_ALWAYS;
11301136 const bool HasFrom = ArgTypes[I] & OMP_TGT_MAPTYPE_FROM;
@@ -1141,15 +1147,40 @@ int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
11411147 return true ;
11421148 };
11431149
1150+ // Lambda to check if this pointer was previously marked for deletion.
1151+ // Such a pointer would have had "IsLast" set to true when its DELETE entry
1152+ // was processed. So, the flag wouldn't be set for any FROM entries seen
1153+ // later on.
1154+ auto WasPreviouslyMarkedForDeletion = [&]() -> bool {
1155+ if (!StateInfo->MarkedForDeletionPtrs .contains (HstPtrBegin))
1156+ return false ;
1157+ DP (" Pointer HstPtr=" DPxMOD " was previously marked for deletion\n " ,
1158+ DPxPTR (HstPtrBegin));
1159+ return true ;
1160+ };
1161+
1162+ bool FromCopyBackAlreadyDone =
1163+ StateInfo->TransferredFromPtrs .contains (HstPtrBegin);
11441164 bool IsMapFromOnNonHostNonZeroData =
11451165 HasFrom && !TPR.Flags .IsHostPointer && DataSize != 0 ;
1146- bool IsLastOrHasAlways = TPR.Flags .IsLast || HasAlways;
1166+ bool IsLastOrHasAlwaysOrWasForceDeleted =
1167+ TPR.Flags .IsLast || HasAlways || WasPreviouslyMarkedForDeletion ();
1168+
1169+ if (!FromCopyBackAlreadyDone &&
1170+ ((IsMapFromOnNonHostNonZeroData &&
1171+ IsLastOrHasAlwaysOrWasForceDeleted) ||
1172+ // Even if are not looking at an entry with FROM map-type, if there
1173+ // were any previously deferred FROM transfers for this pointer, we
1174+ // should do them when the ref-count goes down to zero.
1175+ (TPR.Flags .IsLast && HasDeferredMapFrom ()))) {
1176+ // Track that we're doing a FROM transfer for this pointer
1177+ // NOTE: If we don't care about the case of multiple different maps with
1178+ // from, always, or multiple map(from)s seen after a map(delete), e.g.
1179+ // ... map(always, from: x) map(always, from: x)
1180+ // ... map(delete: x) map(from: x) map(from: x)
1181+ // Then we can forego tacking TransferredFromPtrs.
1182+ StateInfo->TransferredFromPtrs .insert (HstPtrBegin);
11471183
1148- if ((IsMapFromOnNonHostNonZeroData && IsLastOrHasAlways) ||
1149- // Even if are not looking at an entry with FROM map-type, if there were
1150- // any previously deferred FROM transfers for this pointer, we should
1151- // do them when the ref-count goes down to zero.
1152- (TPR.Flags .IsLast && HasDeferredMapFrom ())) {
11531184 DP (" Moving %" PRId64 " bytes (tgt:" DPxMOD " ) -> (hst:" DPxMOD " )\n " ,
11541185 DataSize, DPxPTR (TgtPtrBegin), DPxPTR (HstPtrBegin));
11551186 TIMESCOPE_WITH_DETAILS_AND_IDENT (
@@ -1179,8 +1210,8 @@ int targetDataEnd(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
11791210 OFFLOAD_SUCCESS)
11801211 return OFFLOAD_FAIL;
11811212 }
1182- } else if (IsMapFromOnNonHostNonZeroData && !IsLastOrHasAlways &&
1183- !IsMemberOf) {
1213+ } else if (!FromCopyBackAlreadyDone && IsMapFromOnNonHostNonZeroData &&
1214+ !IsLastOrHasAlwaysOrWasForceDeleted && ! IsMemberOf) {
11841215 // We can have cases like the following:
11851216 // map(alloc: p[0:1]) map(from: p[0:1])
11861217 //
0 commit comments