[flang] [llvm] [mlir] [Flang][OpenMP] Add lowering support for is_device_ptr clause (PR #169331)
Akash Banerjee via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 08:43:36 PST 2025
https://github.com/TIFitis updated https://github.com/llvm/llvm-project/pull/169331
>From f5d82d24949340fe444ca635ef53ba161d19d678 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Thu, 20 Nov 2025 13:18:00 +0000
Subject: [PATCH 1/4] [Flang][OpenMP] Add lowering support for is_device_ptr
clause
Add support for OpenMP is_device_ptr clause for target directives.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 42 +++++++----------
flang/lib/Lower/OpenMP/ClauseProcessor.h | 2 +-
flang/lib/Lower/OpenMP/OpenMP.cpp | 45 +++++++++++++++++--
flang/test/Lower/OpenMP/target.f90 | 30 +++++++++++++
.../mlir/Dialect/OpenMP/OpenMPEnums.td | 4 +-
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 5 +++
6 files changed, 95 insertions(+), 33 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 1c163e6de7e5a..8c15395c938c0 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -42,15 +42,6 @@ mlir::omp::ReductionModifier translateReductionModifier(ReductionModifier mod) {
return mlir::omp::ReductionModifier::defaultmod;
}
-/// Check for unsupported map operand types.
-static void checkMapType(mlir::Location location, mlir::Type type) {
- if (auto refType = mlir::dyn_cast<fir::ReferenceType>(type))
- type = refType.getElementType();
- if (auto boxType = mlir::dyn_cast_or_null<fir::BoxType>(type))
- if (!mlir::isa<fir::PointerType>(boxType.getElementType()))
- TODO(location, "OMPD_target_data MapOperand BoxType");
-}
-
static mlir::omp::ScheduleModifier
translateScheduleModifier(const omp::clause::Schedule::OrderingModifier &m) {
switch (m) {
@@ -209,18 +200,6 @@ getIfClauseOperand(lower::AbstractConverter &converter,
ifVal);
}
-static void addUseDeviceClause(
- lower::AbstractConverter &converter, const omp::ObjectList &objects,
- llvm::SmallVectorImpl<mlir::Value> &operands,
- llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) {
- genObjectList(objects, converter, operands);
- for (mlir::Value &operand : operands)
- checkMapType(operand.getLoc(), operand.getType());
-
- for (const omp::Object &object : objects)
- useDeviceSyms.push_back(object.sym());
-}
-
//===----------------------------------------------------------------------===//
// ClauseProcessor unique clauses
//===----------------------------------------------------------------------===//
@@ -1159,14 +1138,23 @@ bool ClauseProcessor::processInReduction(
}
bool ClauseProcessor::processIsDevicePtr(
- mlir::omp::IsDevicePtrClauseOps &result,
+ lower::StatementContext &stmtCtx, mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const {
- return findRepeatableClause<omp::clause::IsDevicePtr>(
- [&](const omp::clause::IsDevicePtr &devPtrClause,
- const parser::CharBlock &) {
- addUseDeviceClause(converter, devPtrClause.v, result.isDevicePtrVars,
- isDeviceSyms);
+ std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
+ bool clauseFound = findRepeatableClause<omp::clause::IsDevicePtr>(
+ [&](const omp::clause::IsDevicePtr &clause,
+ const parser::CharBlock &source) {
+ mlir::Location location = converter.genLocation(source);
+ mlir::omp::ClauseMapFlags mapTypeBits =
+ mlir::omp::ClauseMapFlags::is_device_ptr;
+ processMapObjects(stmtCtx, location, clause.v, mapTypeBits,
+ parentMemberIndices, result.isDevicePtrVars,
+ isDeviceSyms);
});
+
+ insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,
+ result.isDevicePtrVars, isDeviceSyms);
+ return clauseFound;
}
bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 6452e39b97551..4d2b684c51f60 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -130,7 +130,7 @@ class ClauseProcessor {
mlir::Location currentLocation, mlir::omp::InReductionClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const;
bool processIsDevicePtr(
- mlir::omp::IsDevicePtrClauseOps &result,
+ lower::StatementContext &stmtCtx, mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
bool processLinear(mlir::omp::LinearClauseOps &result) const;
bool
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 71067283d13f7..99cdc56bbbab3 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1673,7 +1673,7 @@ static void genTargetClauses(
hostEvalInfo->collectValues(clauseOps.hostEvalVars);
}
cp.processIf(llvm::omp::Directive::OMPD_target, clauseOps);
- cp.processIsDevicePtr(clauseOps, isDevicePtrSyms);
+ cp.processIsDevicePtr(stmtCtx, clauseOps, isDevicePtrSyms);
cp.processMap(loc, stmtCtx, clauseOps, llvm::omp::Directive::OMPD_unknown,
&mapSyms);
cp.processNowait(clauseOps);
@@ -2485,13 +2485,15 @@ static bool isDuplicateMappedSymbol(
const semantics::Symbol &sym,
const llvm::SetVector<const semantics::Symbol *> &privatizedSyms,
const llvm::SmallVectorImpl<const semantics::Symbol *> &hasDevSyms,
- const llvm::SmallVectorImpl<const semantics::Symbol *> &mappedSyms) {
+ const llvm::SmallVectorImpl<const semantics::Symbol *> &mappedSyms,
+ const llvm::SmallVectorImpl<const semantics::Symbol *> &isDevicePtrSyms) {
llvm::SmallVector<const semantics::Symbol *> concatSyms;
concatSyms.reserve(privatizedSyms.size() + hasDevSyms.size() +
- mappedSyms.size());
+ mappedSyms.size() + isDevicePtrSyms.size());
concatSyms.append(privatizedSyms.begin(), privatizedSyms.end());
concatSyms.append(hasDevSyms.begin(), hasDevSyms.end());
concatSyms.append(mappedSyms.begin(), mappedSyms.end());
+ concatSyms.append(isDevicePtrSyms.begin(), isDevicePtrSyms.end());
auto checkSymbol = [&](const semantics::Symbol &checkSym) {
return std::any_of(concatSyms.begin(), concatSyms.end(),
@@ -2531,6 +2533,41 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
loc, clauseOps, defaultMaps, hasDeviceAddrSyms,
isDevicePtrSyms, mapSyms);
+ if (!isDevicePtrSyms.empty()) {
+ // is_device_ptr maps get duplicated so the clause and synthesized
+ // has_device_addr entry each own a unique MapInfoOp user, keeping
+ // MapInfoFinalization happy while still wiring the symbol into
+ // has_device_addr when the user didn’t spell it explicitly.
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ auto insertionPt = builder.saveInsertionPoint();
+ auto alreadyPresent = [&](const semantics::Symbol *sym) {
+ return llvm::any_of(hasDeviceAddrSyms, [&](const semantics::Symbol *s) {
+ return s && sym && s->GetUltimate() == sym->GetUltimate();
+ });
+ };
+
+ for (auto [idx, sym] : llvm::enumerate(isDevicePtrSyms)) {
+ mlir::Value mapVal = clauseOps.isDevicePtrVars[idx];
+ if (!sym || !mapVal)
+ continue;
+ auto mapInfo = mapVal.getDefiningOp<mlir::omp::MapInfoOp>();
+ if (!mapInfo)
+ continue;
+
+ if (!alreadyPresent(sym)) {
+ clauseOps.hasDeviceAddrVars.push_back(mapVal);
+ hasDeviceAddrSyms.push_back(sym);
+ }
+
+ builder.setInsertionPointAfter(mapInfo);
+ auto clonedOp = builder.clone(*mapInfo.getOperation());
+ auto clonedMapInfo = mlir::dyn_cast<mlir::omp::MapInfoOp>(clonedOp);
+ assert(clonedMapInfo && "expected cloned map info op");
+ clauseOps.isDevicePtrVars[idx] = clonedMapInfo.getResult();
+ }
+ builder.restoreInsertionPoint(insertionPt);
+ }
+
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
/*shouldCollectPreDeterminedSymbols=*/
lower::omp::isLastItemInQueue(item, queue),
@@ -2570,7 +2607,7 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
return;
if (!isDuplicateMappedSymbol(sym, dsp.getAllSymbolsToPrivatize(),
- hasDeviceAddrSyms, mapSyms)) {
+ hasDeviceAddrSyms, mapSyms, isDevicePtrSyms)) {
if (const auto *details =
sym.template detailsIf<semantics::HostAssocDetails>())
converter.copySymbolBinding(details->symbol(), sym);
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 26bd62edf9d0c..1e62adc0f6f98 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -566,6 +566,36 @@ subroutine omp_target_device_addr
end subroutine omp_target_device_addr
+!===============================================================================
+! Target `is_device_ptr` clause
+!===============================================================================
+
+!CHECK-LABEL: func.func @_QPomp_target_is_device_ptr() {
+subroutine omp_target_is_device_ptr
+ use iso_c_binding, only: c_associated, c_ptr
+ implicit none
+ integer :: i
+ integer :: arr(4)
+ type(c_ptr) :: p
+
+ i = 0
+ arr = 0
+
+ !CHECK: %[[P_STORAGE:.*]] = omp.map.info {{.*}}{name = "p"}
+ !CHECK: %[[P_IS:.*]] = omp.map.info {{.*}}{name = "p"}
+ !CHECK: %[[ARR_MAP:.*]] = omp.map.info {{.*}}{name = "arr"}
+ !CHECK: omp.target is_device_ptr(%[[P_IS]] :
+ !CHECK-SAME: has_device_addr(%[[P_STORAGE]] ->
+ !CHECK-SAME: map_entries({{.*}}%[[ARR_MAP]] ->
+ !$omp target is_device_ptr(p)
+ if (c_associated(p)) i = i + 1
+ arr(1) = i
+ !$omp end target
+ !CHECK: omp.terminator
+ !CHECK: }
+end subroutine omp_target_is_device_ptr
+
+
!===============================================================================
! Target Data with unstructured code
!===============================================================================
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
index d9882cbcb5977..8a7680bf6385e 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
@@ -126,6 +126,7 @@ def ClauseMapFlagsAttachAuto : I32BitEnumAttrCaseBit<"attach_auto", 15>;
def ClauseMapFlagsRefPtr : I32BitEnumAttrCaseBit<"ref_ptr", 16>;
def ClauseMapFlagsRefPtee : I32BitEnumAttrCaseBit<"ref_ptee", 17>;
def ClauseMapFlagsRefPtrPtee : I32BitEnumAttrCaseBit<"ref_ptr_ptee", 18>;
+def ClauseMapFlagsIsDevicePtr : I32BitEnumAttrCaseBit<"is_device_ptr", 19>;
def ClauseMapFlags : OpenMP_BitEnumAttr<
"ClauseMapFlags",
@@ -149,7 +150,8 @@ def ClauseMapFlags : OpenMP_BitEnumAttr<
ClauseMapFlagsAttachAuto,
ClauseMapFlagsRefPtr,
ClauseMapFlagsRefPtee,
- ClauseMapFlagsRefPtrPtee
+ ClauseMapFlagsRefPtrPtee,
+ ClauseMapFlagsIsDevicePtr
]>;
def ClauseMapFlagsAttr : OpenMP_EnumAttr<ClauseMapFlags,
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 1b069c62a8be9..6ddc3d381b287 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -1817,6 +1817,9 @@ static ParseResult parseMapClause(OpAsmParser &parser,
if (mapTypeMod == "ref_ptr_ptee")
mapTypeBits |= ClauseMapFlags::ref_ptr_ptee;
+ if (mapTypeMod == "is_device_ptr")
+ mapTypeBits |= ClauseMapFlags::is_device_ptr;
+
return success();
};
@@ -1886,6 +1889,8 @@ static void printMapClause(OpAsmPrinter &p, Operation *op,
mapTypeStrs.push_back("ref_ptee");
if (mapTypeToBool(mapFlags, ClauseMapFlags::ref_ptr_ptee))
mapTypeStrs.push_back("ref_ptr_ptee");
+ if (mapTypeToBool(mapFlags, ClauseMapFlags::is_device_ptr))
+ mapTypeStrs.push_back("is_device_ptr");
if (mapFlags == ClauseMapFlags::none)
mapTypeStrs.push_back("none");
>From f9ee07c7f9ea9a8c447b84463b8159c4a8e3fbeb Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Mon, 1 Dec 2025 15:13:19 +0000
Subject: [PATCH 2/4] Address reviewer comments.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 16 +++++++---------
flang/test/Lower/OpenMP/target.f90 | 4 ++--
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 99cdc56bbbab3..e4a1a18ec0e4f 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2538,8 +2538,7 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
// has_device_addr entry each own a unique MapInfoOp user, keeping
// MapInfoFinalization happy while still wiring the symbol into
// has_device_addr when the user didn’t spell it explicitly.
- fir::FirOpBuilder &builder = converter.getFirOpBuilder();
- auto insertionPt = builder.saveInsertionPoint();
+ auto insertionPt = firOpBuilder.saveInsertionPoint();
auto alreadyPresent = [&](const semantics::Symbol *sym) {
return llvm::any_of(hasDeviceAddrSyms, [&](const semantics::Symbol *s) {
return s && sym && s->GetUltimate() == sym->GetUltimate();
@@ -2548,24 +2547,23 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
for (auto [idx, sym] : llvm::enumerate(isDevicePtrSyms)) {
mlir::Value mapVal = clauseOps.isDevicePtrVars[idx];
- if (!sym || !mapVal)
- continue;
+ assert(sym && "expected symbol for is_device_ptr");
+ assert(mapVal && "expected map value for is_device_ptr");
auto mapInfo = mapVal.getDefiningOp<mlir::omp::MapInfoOp>();
- if (!mapInfo)
- continue;
+ assert(mapInfo && "expected map info op");
if (!alreadyPresent(sym)) {
clauseOps.hasDeviceAddrVars.push_back(mapVal);
hasDeviceAddrSyms.push_back(sym);
}
- builder.setInsertionPointAfter(mapInfo);
- auto clonedOp = builder.clone(*mapInfo.getOperation());
+ firOpBuilder.setInsertionPointAfter(mapInfo);
+ auto clonedOp = firOpBuilder.clone(*mapInfo.getOperation());
auto clonedMapInfo = mlir::dyn_cast<mlir::omp::MapInfoOp>(clonedOp);
assert(clonedMapInfo && "expected cloned map info op");
clauseOps.isDevicePtrVars[idx] = clonedMapInfo.getResult();
}
- builder.restoreInsertionPoint(insertionPt);
+ firOpBuilder.restoreInsertionPoint(insertionPt);
}
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 1e62adc0f6f98..00be77ccfa32d 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -572,7 +572,7 @@ end subroutine omp_target_device_addr
!CHECK-LABEL: func.func @_QPomp_target_is_device_ptr() {
subroutine omp_target_is_device_ptr
- use iso_c_binding, only: c_associated, c_ptr
+ use iso_c_binding, only: c_ptr
implicit none
integer :: i
integer :: arr(4)
@@ -588,7 +588,7 @@ subroutine omp_target_is_device_ptr
!CHECK-SAME: has_device_addr(%[[P_STORAGE]] ->
!CHECK-SAME: map_entries({{.*}}%[[ARR_MAP]] ->
!$omp target is_device_ptr(p)
- if (c_associated(p)) i = i + 1
+ i = i + 1
arr(1) = i
!$omp end target
!CHECK: omp.terminator
>From f1ce4c7976228cde6cb262eb0db95120af0260a1 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <akash.banerjee at amd.com>
Date: Tue, 2 Dec 2025 14:46:34 +0000
Subject: [PATCH 3/4] [MLIR][OpenMP] Add OpenMPToLLVMIRTranslation support for
is_device_ptr (#169367)
This PR adds support for the OpenMP `is_device_ptr` clause in the MLIR
to LLVM IR translation for target regions. The `is_device_ptr` clause
allows device pointers (allocated via OpenMP runtime APIs) to be used
directly in target regions without implicit mapping.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 5 +-
.../OpenMP/map-types-and-sizes.f90 | 9 +++
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 25 +++++---
mlir/test/Target/LLVMIR/omptarget-llvm.mlir | 17 ++++++
mlir/test/Target/LLVMIR/openmp-todo.mlir | 11 ----
.../fortran/target-is-device-ptr.f90 | 60 +++++++++++++++++++
6 files changed, 108 insertions(+), 19 deletions(-)
create mode 100644 offload/test/offloading/fortran/target-is-device-ptr.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 8c15395c938c0..474d5725e4b82 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1145,8 +1145,11 @@ bool ClauseProcessor::processIsDevicePtr(
[&](const omp::clause::IsDevicePtr &clause,
const parser::CharBlock &source) {
mlir::Location location = converter.genLocation(source);
+ // Force a map so the descriptor is materialized on the device with the
+ // device address inside.
mlir::omp::ClauseMapFlags mapTypeBits =
- mlir::omp::ClauseMapFlags::is_device_ptr;
+ mlir::omp::ClauseMapFlags::is_device_ptr |
+ mlir::omp::ClauseMapFlags::to;
processMapObjects(stmtCtx, location, clause.v, mapTypeBits,
parentMemberIndices, result.isDevicePtrVars,
isDeviceSyms);
diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
index 44a049f5ac510..133b1664668d7 100644
--- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90
+++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
@@ -33,6 +33,15 @@ subroutine mapType_array
!$omp end target
end subroutine mapType_array
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 8]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 33]
+subroutine mapType_is_device_ptr
+ use iso_c_binding, only : c_ptr
+ type(c_ptr) :: p
+ !$omp target is_device_ptr(p)
+ !$omp end target
+end subroutine mapType_is_device_ptr
+
!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 0]
!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187]
subroutine mapType_ptr
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index f28454075f1d3..a1adbef23180f 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -332,10 +332,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
op.getInReductionSyms())
result = todo("in_reduction");
};
- auto checkIsDevicePtr = [&todo](auto op, LogicalResult &result) {
- if (!op.getIsDevicePtrVars().empty())
- result = todo("is_device_ptr");
- };
auto checkLinear = [&todo](auto op, LogicalResult &result) {
if (!op.getLinearVars().empty() || !op.getLinearStepVars().empty())
result = todo("linear");
@@ -444,7 +440,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
checkBare(op, result);
checkDevice(op, result);
checkInReduction(op, result);
- checkIsDevicePtr(op, result);
})
.Default([](Operation &) {
// Assume all clauses for an operation can be translated unless they are
@@ -3835,6 +3830,9 @@ convertClauseMapFlags(omp::ClauseMapFlags mlirFlags) {
auto mapTypeToBool = [&mlirFlags](omp::ClauseMapFlags flag) {
return (mlirFlags & flag) == flag;
};
+ const bool hasExplicitMap =
+ (mlirFlags & ~omp::ClauseMapFlags::is_device_ptr) !=
+ omp::ClauseMapFlags::none;
llvm::omp::OpenMPOffloadMappingFlags mapType =
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
@@ -3875,6 +3873,12 @@ convertClauseMapFlags(omp::ClauseMapFlags mlirFlags) {
if (mapTypeToBool(omp::ClauseMapFlags::attach))
mapType |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ATTACH;
+ if (mapTypeToBool(omp::ClauseMapFlags::is_device_ptr)) {
+ mapType |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
+ if (!hasExplicitMap)
+ mapType |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_LITERAL;
+ }
+
return mapType;
}
@@ -3996,6 +4000,9 @@ static void collectMapDataFromMapOperands(
llvm::Value *origValue = moduleTranslation.lookupValue(offloadPtr);
auto mapType = convertClauseMapFlags(mapOp.getMapType());
auto mapTypeAlways = llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
+ bool isDevicePtr =
+ (mapOp.getMapType() & omp::ClauseMapFlags::is_device_ptr) !=
+ omp::ClauseMapFlags::none;
mapData.OriginalValue.push_back(origValue);
mapData.BasePointers.push_back(origValue);
@@ -4022,14 +4029,18 @@ static void collectMapDataFromMapOperands(
mapData.Mappers.push_back(nullptr);
}
} else {
+ // For is_device_ptr we need the map type to propagate so the runtime
+ // can materialize the device-side copy of the pointer container.
mapData.Types.push_back(
- llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
+ isDevicePtr ? mapType
+ : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
mapData.Mappers.push_back(nullptr);
}
mapData.Names.push_back(LLVM::createMappingInformation(
mapOp.getLoc(), *moduleTranslation.getOpenMPBuilder()));
mapData.DevicePointers.push_back(
- llvm::OpenMPIRBuilder::DeviceInfoTy::Address);
+ isDevicePtr ? llvm::OpenMPIRBuilder::DeviceInfoTy::Pointer
+ : llvm::OpenMPIRBuilder::DeviceInfoTy::Address);
mapData.IsAMapping.push_back(false);
mapData.IsAMember.push_back(checkIsAMember(hasDevAddrOperands, mapOp));
}
diff --git a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
index e6ea3aaeec656..e289d5d013eaa 100644
--- a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
@@ -622,3 +622,20 @@ module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} {
// CHECK: br label %[[VAL_40]]
// CHECK: omp.done: ; preds = %[[VAL_68]], %[[VAL_63]], %[[VAL_32]]
// CHECK: ret void
+
+// -----
+
+module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} {
+ llvm.func @_QPomp_target_is_device_ptr(%arg0 : !llvm.ptr) {
+ %map = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.ptr)
+ map_clauses(is_device_ptr) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.target map_entries(%map -> %ptr_arg : !llvm.ptr) {
+ omp.terminator
+ }
+ llvm.return
+ }
+}
+
+// CHECK: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 8]
+// CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 288]
+// CHECK-LABEL: define void @_QPomp_target_is_device_ptr
diff --git a/mlir/test/Target/LLVMIR/openmp-todo.mlir b/mlir/test/Target/LLVMIR/openmp-todo.mlir
index af6d254cfd3c3..0704008aa7135 100644
--- a/mlir/test/Target/LLVMIR/openmp-todo.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-todo.mlir
@@ -238,17 +238,6 @@ llvm.func @target_in_reduction(%x : !llvm.ptr) {
// -----
-llvm.func @target_is_device_ptr(%x : !llvm.ptr) {
- // expected-error at below {{not yet implemented: Unhandled clause is_device_ptr in omp.target operation}}
- // expected-error at below {{LLVM Translation failed for operation: omp.target}}
- omp.target is_device_ptr(%x : !llvm.ptr) {
- omp.terminator
- }
- llvm.return
-}
-
-// -----
-
llvm.func @target_enter_data_depend(%x: !llvm.ptr) {
// expected-error at below {{not yet implemented: Unhandled clause depend in omp.target_enter_data operation}}
// expected-error at below {{LLVM Translation failed for operation: omp.target_enter_data}}
diff --git a/offload/test/offloading/fortran/target-is-device-ptr.f90 b/offload/test/offloading/fortran/target-is-device-ptr.f90
new file mode 100644
index 0000000000000..d6d8c02f50d6a
--- /dev/null
+++ b/offload/test/offloading/fortran/target-is-device-ptr.f90
@@ -0,0 +1,60 @@
+! Validate that a device pointer obtained via omp_get_mapped_ptr can be used
+! inside a TARGET region with the is_device_ptr clause.
+! REQUIRES: flang, amdgcn-amd-amdhsa
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+
+module mod
+ implicit none
+ integer, parameter :: n = 4
+contains
+ subroutine kernel(dptr)
+ use iso_c_binding, only : c_ptr, c_f_pointer
+ implicit none
+
+ type(c_ptr) :: dptr
+ integer, dimension(:), pointer :: b
+ integer :: i
+
+ b => null()
+
+ !$omp target is_device_ptr(dptr)
+ call c_f_pointer(dptr, b, [n])
+ do i = 1, n
+ b(i) = b(i) + 1
+ end do
+ !$omp end target
+ end subroutine kernel
+end module mod
+
+program is_device_ptr_target
+ use iso_c_binding, only : c_ptr, c_loc, c_f_pointer
+ use omp_lib, only: omp_get_default_device, omp_get_mapped_ptr
+ use mod, only: kernel, n
+ implicit none
+
+ integer, dimension(n), target :: a
+ integer :: dev
+ type(c_ptr) :: dptr
+
+ a = [2, 4, 6, 8]
+ print '("BEFORE:", I3)', a
+
+ dev = omp_get_default_device()
+
+ !$omp target data map(tofrom: a)
+ dptr = omp_get_mapped_ptr(c_loc(a), dev)
+ call kernel(dptr)
+ !$omp end target data
+
+ print '("AFTER: ", I3)', a
+
+ if (all(a == [3, 5, 7, 9])) then
+ print '("PASS")'
+ else
+ print '("FAIL ", I3)', a
+ end if
+
+end program is_device_ptr_target
+
+!CHECK: PASS
>From 9a96b989577187017e53aeebf4359eb72ce24a43 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Tue, 2 Dec 2025 14:57:58 +0000
Subject: [PATCH 4/4] Address reviewer comment.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index e4a1a18ec0e4f..987ef0ee45500 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2558,9 +2558,8 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
}
firOpBuilder.setInsertionPointAfter(mapInfo);
- auto clonedOp = firOpBuilder.clone(*mapInfo.getOperation());
- auto clonedMapInfo = mlir::dyn_cast<mlir::omp::MapInfoOp>(clonedOp);
- assert(clonedMapInfo && "expected cloned map info op");
+ mlir::Operation *clonedOp = firOpBuilder.clone(*mapInfo.getOperation());
+ auto clonedMapInfo = mlir::cast<mlir::omp::MapInfoOp>(clonedOp);
clauseOps.isDevicePtrVars[idx] = clonedMapInfo.getResult();
}
firOpBuilder.restoreInsertionPoint(insertionPt);
More information about the llvm-commits
mailing list