[flang-commits] [flang] [flang][OpenMP] Fix use_device_addr handling for COMMON blocks in target data (PR #217105)
Sairudra More via flang-commits
flang-commits at lists.llvm.org
Wed Aug 19 01:08:15 PDT 2026
https://github.com/Saieiei updated https://github.com/llvm/llvm-project/pull/217105
>From e20b22e3751d15b0782c459dd259966e5e75d633 Mon Sep 17 00:00:00 2001
From: Sairudra More <sairudra60 at gmail.com>
Date: Tue, 18 Aug 2026 10:54:38 -0500
Subject: [PATCH 1/2] Fix use_device_addr for COMMON blocks in target data
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 25 ++-
flang/lib/Lower/OpenMP/OpenMP.cpp | 31 ++-
flang/lib/Semantics/resolve-directives.cpp | 26 ++-
...rget-data-use-device-addr-common-block.f90 | 197 ++++++++++++++++++
.../OpenMP/use-device-addr-common-block.f90 | 102 +++++++++
5 files changed, 375 insertions(+), 6 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
create mode 100644 flang/test/Semantics/OpenMP/use-device-addr-common-block.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 5a554def351ea..70cc1b621ca14 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -2204,6 +2204,15 @@ bool ClauseProcessor::processEnter(
bool ClauseProcessor::processUseDeviceAddr(
lower::StatementContext &stmtCtx, mlir::omp::UseDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<Object> &useDeviceObjects) const {
+ llvm::SmallPtrSet<const semantics::Symbol *, 4> mappedCommonBlocks;
+ findRepeatableClause<omp::clause::Map>(
+ [&](const omp::clause::Map &clause, const parser::CharBlock &) {
+ for (const Object &object : std::get<ObjectList>(clause.t)) {
+ if (object.sym()->has<semantics::CommonBlockDetails>())
+ mappedCommonBlocks.insert(&object.sym()->GetUltimate());
+ }
+ });
+
std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
bool clauseFound = findRepeatableClause<omp::clause::UseDeviceAddr>(
[&](const omp::clause::UseDeviceAddr &clause,
@@ -2211,7 +2220,21 @@ bool ClauseProcessor::processUseDeviceAddr(
mlir::Location location = converter.genLocation(source);
mlir::omp::ClauseMapFlags mapTypeBits =
mlir::omp::ClauseMapFlags::return_param;
- processMapObjects(stmtCtx, location, clause.v, mapTypeBits,
+ ObjectList objects;
+ // Keep the aggregate only when it pairs with a whole-COMMON map on
+ // this directive; otherwise preserve named-COMMON member equivalence.
+ for (const Object &object : clause.v) {
+ auto *details =
+ object.sym()->detailsIf<semantics::CommonBlockDetails>();
+ if (!details ||
+ mappedCommonBlocks.contains(&object.sym()->GetUltimate())) {
+ objects.push_back(object);
+ continue;
+ }
+ for (const auto &member : details->objects())
+ objects.push_back(Object{&*member, std::nullopt});
+ }
+ processMapObjects(stmtCtx, location, objects, mapTypeBits,
parentMemberIndices, result.useDeviceAddrVars,
useDeviceObjects);
});
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index ae1eb897c9348..c3c1317aa6ef7 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -133,11 +133,13 @@ struct ObjectEntryBlockArgs {
ObjectEntryBlockArgsEntry taskReduction;
ObjectEntryBlockArgsEntry useDeviceAddr;
ObjectEntryBlockArgsEntry useDevicePtr;
+ std::size_t sourceUseDeviceAddrCount{0};
bool isValid() const {
return hasDeviceAddr.isValid() && inReduction.isValid() && map.isValid() &&
priv.isValid() && reduction.isValid() && taskReduction.isValid() &&
- useDeviceAddr.isValid() && useDevicePtr.isValid();
+ useDeviceAddr.isValid() && useDevicePtr.isValid() &&
+ sourceUseDeviceAddrCount <= useDeviceAddr.objects.size();
}
llvm::SmallVector<const semantics::Symbol *> getSyms() const {
@@ -2252,6 +2254,12 @@ static void createBodyOfOp(mlir::Operation &op, const OpWithBodyGenInfo &info,
marker->erase();
}
+static void genIntermediateCommonBlockAccessors(
+ Fortran::lower::AbstractConverter &converter,
+ const mlir::Location ¤tLocation,
+ llvm::ArrayRef<mlir::BlockArgument> mapBlockArgs,
+ llvm::ArrayRef<const Fortran::semantics::Symbol *> mapSyms);
+
static void genBodyOfTargetDataOp(
lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
@@ -2262,6 +2270,15 @@ static void genBodyOfTargetDataOp(
genEntryBlock(firOpBuilder, args.asEntryBlockArgs(), dataOp.getRegion());
bindEntryBlockArgs(converter, dataOp, args);
+ auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*dataOp);
+ llvm::SmallVector<const semantics::Symbol *> sourceUseDeviceAddrSyms{
+ args.useDeviceAddr.getSyms()};
+ genIntermediateCommonBlockAccessors(
+ converter, currentLocation,
+ argIface.getUseDeviceAddrBlockArgs().take_front(
+ args.sourceUseDeviceAddrCount),
+ llvm::ArrayRef(sourceUseDeviceAddrSyms)
+ .take_front(args.sourceUseDeviceAddrCount));
// Insert dummy instruction to remember the insertion position. The
// marker will be deleted by clean up passes since there are no uses.
@@ -2299,7 +2316,7 @@ static void genBodyOfTargetDataOp(
// When the scope changes, the bindings to the intermediate accessors should
// be dropped in place of the original symbol bindings.
//
-// This is for utilisation with TargetOp.
+// This is for utilisation with TargetOp and TargetDataOp.
static void genIntermediateCommonBlockAccessors(
Fortran::lower::AbstractConverter &converter,
const mlir::Location ¤tLocation,
@@ -2749,12 +2766,15 @@ static void genTargetDataClauses(
lower::StatementContext &stmtCtx, const List<Clause> &clauses,
mlir::Location loc, mlir::omp::TargetDataOperands &clauseOps,
llvm::SmallVectorImpl<Object> &useDeviceAddrObjects,
- llvm::SmallVectorImpl<Object> &useDevicePtrObjects) {
+ llvm::SmallVectorImpl<Object> &useDevicePtrObjects,
+ std::size_t &sourceUseDeviceAddrCount) {
ClauseProcessor cp(converter, semaCtx, clauses);
cp.processDevice(stmtCtx, clauseOps);
cp.processIf(llvm::omp::Directive::OMPD_target_data, clauseOps);
cp.processMap(loc, stmtCtx, clauseOps);
cp.processUseDeviceAddr(stmtCtx, clauseOps, useDeviceAddrObjects);
+ // Record the source UDA prefix before non-C_PTR UDP operands are promoted.
+ sourceUseDeviceAddrCount = useDeviceAddrObjects.size();
cp.processUseDevicePtr(stmtCtx, clauseOps, useDevicePtrObjects);
// This function implements the deprecated functionality of use_device_ptr
@@ -4091,8 +4111,10 @@ static mlir::omp::TargetDataOp genTargetDataOp(
const ConstructQueue &queue, ConstructQueue::const_iterator item) {
mlir::omp::TargetDataOperands clauseOps;
llvm::SmallVector<Object> useDeviceAddrObjects, useDevicePtrObjects;
+ std::size_t sourceUseDeviceAddrCount;
genTargetDataClauses(converter, semaCtx, stmtCtx, item->clauses, loc,
- clauseOps, useDeviceAddrObjects, useDevicePtrObjects);
+ clauseOps, useDeviceAddrObjects, useDevicePtrObjects,
+ sourceUseDeviceAddrCount);
auto targetDataOp = mlir::omp::TargetDataOp::create(
converter.getFirOpBuilder(), loc, clauseOps);
@@ -4107,6 +4129,7 @@ static mlir::omp::TargetDataOp genTargetDataOp(
args.useDeviceAddr.vars = useDeviceAddrBaseValues;
args.useDevicePtr.objects = useDevicePtrObjects;
args.useDevicePtr.vars = useDevicePtrBaseValues;
+ args.sourceUseDeviceAddrCount = sourceUseDeviceAddrCount;
genBodyOfTargetDataOp(converter, symTable, semaCtx, eval, targetDataOp, args,
loc, queue, item);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 15bb84d7e486f..73dedc79b8528 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -61,6 +61,7 @@ template <typename T> class DirectiveAttributeVisitor {
Scope &scope;
Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC
std::map<const Symbol *, Symbol::Flag> objectWithDSA;
+ std::map<const Symbol *, Symbol::Flag> commonBlockClauseFlags;
std::map<parser::OmpVariableCategory::Value,
parser::OmpDefaultmapClause::ImplicitBehavior>
defaultMap;
@@ -3194,7 +3195,30 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
Symbol *originalCB{ResolveOmpCommonBlockName(&cbName)};
if (auto *symbol{cbResolved ? name.symbol : originalCB}) {
if (!dataCopyingAttributeFlags.test(ompFlag)) {
- CheckMultipleAppearances(name, *symbol, Symbol::Flag::OmpCommonBlock);
+ auto isMapFlag{[](Symbol::Flag flag) {
+ return flag == Symbol::Flag::OmpMapTo ||
+ flag == Symbol::Flag::OmpMapFrom ||
+ flag == Symbol::Flag::OmpMapToFrom ||
+ flag == Symbol::Flag::OmpMapStorage ||
+ flag == Symbol::Flag::OmpMapDelete;
+ }};
+ const Symbol *commonBlock{&symbol->GetUltimate()};
+ auto [it, inserted]{GetContext().commonBlockClauseFlags.try_emplace(
+ commonBlock, ompFlag)};
+ bool mapUseDeviceAddrPair{
+ GetContext().directive == llvm::omp::Directive::OMPD_target_data &&
+ !inserted &&
+ ((isMapFlag(it->second) &&
+ ompFlag == Symbol::Flag::OmpUseDeviceAddr) ||
+ (it->second == Symbol::Flag::OmpUseDeviceAddr &&
+ isMapFlag(ompFlag)))};
+ if (mapUseDeviceAddrPair) {
+ // Mark the one permitted overlap as consumed so a third appearance is
+ // still diagnosed.
+ it->second = Symbol::Flag::OmpCommonBlock;
+ } else {
+ CheckMultipleAppearances(name, *symbol, Symbol::Flag::OmpCommonBlock);
+ }
}
// 2.15.3 When a named common block appears in a list, it has the
// same meaning as if every explicit member of the common block
diff --git a/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90 b/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
new file mode 100644
index 0000000000000..fa3689e386a68
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
@@ -0,0 +1,197 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=50 %s -o /dev/null
+
+! CHECK-LABEL: func.func @_QPstandalone_common
+! CHECK: %[[STANDALONE_X_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "x"}
+! CHECK: %[[STANDALONE_Y_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "y"}
+! CHECK: omp.target_data use_device_addr(%[[STANDALONE_X_MAP]] -> %[[STANDALONE_X_ARG:.*]], %[[STANDALONE_Y_MAP]] -> %[[STANDALONE_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[STANDALONE_X:.*]]:2 = hlfir.declare %[[STANDALONE_X_ARG]]
+! CHECK: %[[STANDALONE_Y:.*]]:2 = hlfir.declare %[[STANDALONE_Y_ARG]]
+! CHECK: %[[STANDALONE_LOAD:.*]] = fir.load %[[STANDALONE_Y]]#0
+! CHECK: %[[STANDALONE_SUM:.*]] = arith.addi %[[STANDALONE_LOAD]]
+! CHECK: hlfir.assign %[[STANDALONE_SUM]] to %[[STANDALONE_X]]#0
+subroutine standalone_common
+ integer :: x, y
+ common /standalone/ x, y
+ !$omp target data use_device_addr(/standalone/)
+ x = y + 1
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPall_cptr_common
+! CHECK-NOT: use_device_ptr
+! CHECK: %[[CPTR_P_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "p"}
+! CHECK: %[[CPTR_Q_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "q"}
+! CHECK: omp.target_data use_device_addr(%[[CPTR_P_MAP]] -> %[[CPTR_P_ARG:.*]], %[[CPTR_Q_MAP]] -> %[[CPTR_Q_ARG:.*]] : {{.*}}) {
+! CHECK-NOT: use_device_ptr
+! CHECK: %[[CPTR_P:.*]]:2 = hlfir.declare %[[CPTR_P_ARG]]
+! CHECK: %[[CPTR_Q:.*]]:2 = hlfir.declare %[[CPTR_Q_ARG]]
+! CHECK: hlfir.assign %[[CPTR_Q]]#0 to %[[CPTR_P]]#0
+subroutine all_cptr_common
+ use iso_c_binding, only : c_ptr
+ type(c_ptr) :: p, q
+ common /all_cptr/ p, q
+ !$omp target data use_device_addr(/all_cptr/)
+ p = q
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmixed_common
+! CHECK-NOT: use_device_ptr
+! CHECK: %[[MIXED_P_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "p"}
+! CHECK: %[[MIXED_X_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "x"}
+! CHECK: omp.target_data use_device_addr(%[[MIXED_P_MAP]] -> %[[MIXED_P_ARG:.*]], %[[MIXED_X_MAP]] -> %[[MIXED_X_ARG:.*]] : {{.*}}) {
+! CHECK-NOT: use_device_ptr
+! CHECK: %[[MIXED_P:.*]]:2 = hlfir.declare %[[MIXED_P_ARG]]
+! CHECK: %[[MIXED_X:.*]]:2 = hlfir.declare %[[MIXED_X_ARG]]
+! CHECK: %[[MIXED_LOAD:.*]] = fir.load %[[MIXED_X]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[MIXED_X]]#0
+subroutine mixed_common
+ use iso_c_binding, only : c_ptr
+ type(c_ptr) :: p
+ integer :: x
+ common /mixed/ p, x
+ !$omp target data use_device_addr(/mixed/)
+ x = x + 1
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmapped_common
+! CHECK: %[[MAPPED_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} {name = "mapped"}
+! CHECK: %[[MAPPED_UDA:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "mapped"}
+! CHECK: omp.target_data map_entries(%[[MAPPED_MAP]] : {{.*}}) use_device_addr(%[[MAPPED_UDA]] -> %[[MAPPED_ARG:.*]] : {{.*}}) {
+! CHECK: %[[MAPPED_X_COORD:.*]] = fir.coordinate_of %[[MAPPED_ARG]], %{{.*}}
+! CHECK: %[[MAPPED_X_REF:.*]] = fir.convert %[[MAPPED_X_COORD]]
+! CHECK: %[[MAPPED_X:.*]]:2 = hlfir.declare %[[MAPPED_X_REF]] storage(%[[MAPPED_ARG]][0])
+! CHECK: %[[MAPPED_Y_COORD:.*]] = fir.coordinate_of %[[MAPPED_ARG]], %{{.*}}
+! CHECK: %[[MAPPED_Y_REF:.*]] = fir.convert %[[MAPPED_Y_COORD]]
+! CHECK: %[[MAPPED_Y:.*]]:2 = hlfir.declare %[[MAPPED_Y_REF]] storage(%[[MAPPED_ARG]][4])
+! CHECK: %[[MAPPED_LOAD:.*]] = fir.load %[[MAPPED_Y]]#0
+! CHECK: %[[MAPPED_SUM:.*]] = arith.addi %[[MAPPED_LOAD]]
+! CHECK: hlfir.assign %[[MAPPED_SUM]] to %[[MAPPED_X]]#0
+subroutine mapped_common
+ integer :: x, y
+ common /mapped/ x, y
+ !$omp target data map(tofrom: /mapped/) use_device_addr(/mapped/)
+ x = y + 1
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPexplicit_map_common
+! CHECK: %[[EXPLICIT_X_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} {name = "x"}
+! CHECK: %[[EXPLICIT_Y_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} {name = "y"}
+! CHECK: %[[EXPLICIT_X_UDA:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "x"}
+! CHECK: %[[EXPLICIT_Y_UDA:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "y"}
+! CHECK: omp.target_data map_entries(%[[EXPLICIT_X_MAP]], %[[EXPLICIT_Y_MAP]] : {{.*}}) use_device_addr(%[[EXPLICIT_X_UDA]] -> %[[EXPLICIT_X_ARG:.*]], %[[EXPLICIT_Y_UDA]] -> %[[EXPLICIT_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[EXPLICIT_X:.*]]:2 = hlfir.declare %[[EXPLICIT_X_ARG]]
+! CHECK: %[[EXPLICIT_Y:.*]]:2 = hlfir.declare %[[EXPLICIT_Y_ARG]]
+! CHECK: %[[EXPLICIT_LOAD:.*]] = fir.load %[[EXPLICIT_Y]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[EXPLICIT_X]]#0
+subroutine explicit_map_common
+ integer :: x, y
+ common /explicit_map/ x, y
+ !$omp target data map(tofrom: x, y) use_device_addr(/explicit_map/)
+ x = y + 1
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPouter_map_common
+! CHECK: %[[OUTER_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} {name = "outer_map"}
+! CHECK: omp.target_data map_entries(%[[OUTER_MAP]] : {{.*}}) {
+! CHECK: %[[OUTER_X_UDA:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "x"}
+! CHECK: %[[OUTER_Y_UDA:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "y"}
+! CHECK: omp.target_data use_device_addr(%[[OUTER_X_UDA]] -> %[[OUTER_X_ARG:.*]], %[[OUTER_Y_UDA]] -> %[[OUTER_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[OUTER_X:.*]]:2 = hlfir.declare %[[OUTER_X_ARG]]
+! CHECK: %[[OUTER_Y:.*]]:2 = hlfir.declare %[[OUTER_Y_ARG]]
+! CHECK: %[[OUTER_LOAD:.*]] = fir.load %[[OUTER_Y]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[OUTER_X]]#0
+subroutine outer_map_common
+ integer :: x, y
+ common /outer_map/ x, y
+ !$omp target data map(tofrom: /outer_map/)
+ !$omp target data use_device_addr(/outer_map/)
+ x = y + 1
+ !$omp end target data
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPreordered_common
+! CHECK: %[[SECOND_R_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "r"}
+! CHECK: %[[SECOND_S_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "s"}
+! CHECK: %[[PTR_CHILD:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = ""}
+! CHECK: %[[PTR_MAP:.*]] = omp.map.info {{.*}} members(%[[PTR_CHILD]] {{.*}}) {{.*}} {name = "ptr"}
+! CHECK: %[[PTR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} {name = "ptr"}
+! CHECK: %[[FIRST_A_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "a"}
+! CHECK: %[[FIRST_B_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "b"}
+! CHECK: omp.target_data map_entries(%[[PTR_ATTACH]] : {{.*}}) use_device_addr(%[[SECOND_R_MAP]] -> %[[SECOND_R_ARG:.*]], %[[SECOND_S_MAP]] -> %[[SECOND_S_ARG:.*]], %[[PTR_MAP]] -> %[[PTR_ARG:.*]], %[[FIRST_A_MAP]] -> %[[FIRST_A_ARG:.*]], %[[FIRST_B_MAP]] -> %[[FIRST_B_ARG:.*]], %[[PTR_CHILD]] -> %[[PTR_CHILD_ARG:.*]] : {{.*}}) {
+! CHECK: %[[SECOND_R:.*]]:2 = hlfir.declare %[[SECOND_R_ARG]]
+! CHECK: %[[SECOND_S:.*]]:2 = hlfir.declare %[[SECOND_S_ARG]]
+! CHECK: %[[PTR:.*]]:2 = hlfir.declare %[[PTR_ARG]]
+! CHECK: %[[FIRST_A:.*]]:2 = hlfir.declare %[[FIRST_A_ARG]]
+! CHECK: %[[FIRST_B:.*]]:2 = hlfir.declare %[[FIRST_B_ARG]]
+! CHECK: %[[SECOND_LOAD:.*]] = fir.load %[[SECOND_S]]#0
+! CHECK: %[[FIRST_LOAD:.*]] = fir.load %[[FIRST_A]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[SECOND_R]]#0
+! CHECK: %[[FIRST_B_LOAD:.*]] = fir.load %[[FIRST_B]]#0
+! CHECK: %[[PTR_LOAD:.*]] = fir.load %[[PTR]]#0
+subroutine reordered_common(ptr)
+ integer, pointer :: ptr
+ integer :: a, b
+ real :: r, s
+ common /first/ a, b
+ common /second/ r, s
+ !$omp target data use_device_addr(/second/, ptr, /first/)
+ r = s + real(a)
+ ptr = b
+ !$omp end target data
+end subroutine
+
+! CHECK-LABEL: func.func @_QPnested_common
+! CHECK: %[[HOST_X:.*]]:2 = hlfir.declare {{.*}} storage({{.*}}[0])
+! CHECK: %[[HOST_Y:.*]]:2 = hlfir.declare {{.*}} storage({{.*}}[4])
+! CHECK: omp.target_data use_device_addr({{.*}} -> %[[OUTER_X_ARG:.*]], {{.*}} -> %[[OUTER_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[NESTED_OUTER_X:.*]]:2 = hlfir.declare %[[OUTER_X_ARG]]
+! CHECK: %[[NESTED_OUTER_Y:.*]]:2 = hlfir.declare %[[OUTER_Y_ARG]]
+! CHECK: %[[OUTER_INITIAL_LOAD:.*]] = fir.load %[[NESTED_OUTER_Y]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[NESTED_OUTER_X]]#0
+! CHECK: omp.target_data use_device_addr({{.*}} -> %[[INNER_X_ARG:.*]], {{.*}} -> %[[INNER_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[NESTED_INNER_X:.*]]:2 = hlfir.declare %[[INNER_X_ARG]]
+! CHECK: %[[NESTED_INNER_Y:.*]]:2 = hlfir.declare %[[INNER_Y_ARG]]
+! CHECK: %[[INNER_LOAD:.*]] = fir.load %[[NESTED_INNER_X]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[NESTED_INNER_Y]]#0
+! CHECK: %[[OUTER_RESTORED_LOAD:.*]] = fir.load %[[NESTED_OUTER_Y]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[NESTED_OUTER_X]]#0
+! CHECK: %[[HOST_RESTORED_LOAD:.*]] = fir.load %[[HOST_X]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[HOST_Y]]#0
+subroutine nested_common
+ integer :: x, y
+ common /nested/ x, y
+ !$omp target data use_device_addr(/nested/)
+ x = y + 1
+ !$omp target data use_device_addr(/nested/)
+ y = x + 2
+ !$omp end target data
+ x = y + 3
+ !$omp end target data
+ y = x + 4
+end subroutine
+
+! CHECK-LABEL: func.func @_QPunstructured_common
+! CHECK: omp.target_data use_device_addr({{.*}} -> %[[UNSTRUCTURED_X_ARG:.*]], {{.*}} -> %[[UNSTRUCTURED_Y_ARG:.*]] : {{.*}}) {
+! CHECK: %[[UNSTRUCTURED_X:.*]]:2 = hlfir.declare %[[UNSTRUCTURED_X_ARG]]
+! CHECK: %[[UNSTRUCTURED_Y:.*]]:2 = hlfir.declare %[[UNSTRUCTURED_Y_ARG]]
+! CHECK: %[[UNSTRUCTURED_Y_LOAD:.*]] = fir.load %[[UNSTRUCTURED_Y]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[UNSTRUCTURED_X]]#0
+! CHECK: cf.br ^[[DEST:.*]]
+! CHECK: ^[[DEST]]:
+! CHECK: %[[UNSTRUCTURED_X_LOAD:.*]] = fir.load %[[UNSTRUCTURED_X]]#0
+! CHECK: hlfir.assign %{{.*}} to %[[UNSTRUCTURED_Y]]#0
+subroutine unstructured_common
+ integer :: x, y
+ common /unstructured/ x, y
+ !$omp target data use_device_addr(/unstructured/)
+ x = y + 1
+ goto 10
+10 y = x + 2
+ !$omp end target data
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/use-device-addr-common-block.f90 b/flang/test/Semantics/OpenMP/use-device-addr-common-block.f90
new file mode 100644
index 0000000000000..cd5e52e3e4c9d
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/use-device-addr-common-block.f90
@@ -0,0 +1,102 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=50 -Wno-openmp-usage
+
+subroutine valid_map_use_device_addr
+ integer :: x, y
+ common /valid/ x, y
+
+ !$omp target data map(tofrom: /valid/) use_device_addr(/valid/)
+ !$omp end target data
+
+ !$omp target data use_device_addr(/valid/) map(from: /valid/)
+ !$omp end target data
+
+ !$omp target data map(alloc: /valid/) use_device_addr(/valid/)
+ !$omp end target data
+end subroutine
+
+subroutine duplicate_and_exclusive_clauses
+ integer :: x, y
+ common /duplicates/ x, y
+
+ !ERROR: List item 'duplicates' present at multiple USE_DEVICE_ADDR clauses
+ !ERROR: 'duplicates' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_addr(/duplicates/) use_device_addr(/duplicates/)
+ !$omp end target data
+
+ !ERROR: 'duplicates' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_ptr(/duplicates/) use_device_ptr(/duplicates/)
+ !$omp end target data
+
+ !ERROR: 'duplicates' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_ptr(/duplicates/) use_device_addr(/duplicates/)
+ !$omp end target data
+
+ !ERROR: 'duplicates' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_addr(/duplicates/) use_device_ptr(/duplicates/)
+ !$omp end target data
+end subroutine
+
+subroutine third_appearance
+ integer :: x, y
+ common /third/ x, y
+
+ !ERROR: 'third' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data map(tofrom: /third/) use_device_addr(/third/) map(from: /third/)
+ !$omp end target data
+
+ !ERROR: List item 'third' present at multiple USE_DEVICE_ADDR clauses
+ !ERROR: 'third' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data map(tofrom: /third/) use_device_addr(/third/) use_device_addr(/third/)
+ !$omp end target data
+
+ !ERROR: 'third' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_addr(/third/) map(tofrom: /third/) map(from: /third/)
+ !$omp end target data
+
+ !ERROR: List item 'third' present at multiple USE_DEVICE_ADDR clauses
+ !ERROR: 'third' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_addr(/third/) map(tofrom: /third/) use_device_addr(/third/)
+ !$omp end target data
+end subroutine
+
+subroutine map_use_device_ptr_non_cptr
+ integer :: x, y
+ common /non_cptr/ x, y
+
+ !ERROR: 'non_cptr' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data map(tofrom: /non_cptr/) use_device_ptr(/non_cptr/)
+ !$omp end target data
+
+ !ERROR: 'non_cptr' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_ptr(/non_cptr/) map(tofrom: /non_cptr/)
+ !$omp end target data
+end subroutine
+
+subroutine map_use_device_ptr_cptr
+ use iso_c_binding, only : c_ptr
+ type(c_ptr) :: p, q
+ common /all_cptr/ p, q
+
+ !ERROR: 'all_cptr' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data map(tofrom: /all_cptr/) use_device_ptr(/all_cptr/)
+ !$omp end target data
+
+ !ERROR: 'all_cptr' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_ptr(/all_cptr/) map(tofrom: /all_cptr/)
+ !$omp end target data
+end subroutine
+
+subroutine map_use_device_ptr_mixed
+ use iso_c_binding, only : c_ptr
+ type(c_ptr) :: p
+ integer :: x
+ common /mixed/ p, x
+
+ !ERROR: 'mixed' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data map(tofrom: /mixed/) use_device_ptr(/mixed/)
+ !$omp end target data
+
+ !ERROR: 'mixed' appears in more than one data-sharing clause on the same OpenMP directive
+ !$omp target data use_device_ptr(/mixed/) map(tofrom: /mixed/)
+ !$omp end target data
+end subroutine
>From 8f705886d1e127ccfcd123d6424870030ff0b57c Mon Sep 17 00:00:00 2001
From: Sairudra More <sairudra60 at gmail.com>
Date: Wed, 19 Aug 2026 03:00:18 -0500
Subject: [PATCH 2/2] [flang][OpenMP] Use OpenMP 5.1 for COMMON UDA test
---
.../Lower/OpenMP/target-data-use-device-addr-common-block.f90 | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90 b/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
index fa3689e386a68..cf85e77126258 100644
--- a/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
+++ b/flang/test/Lower/OpenMP/target-data-use-device-addr-common-block.f90
@@ -1,5 +1,5 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=50 %s -o /dev/null
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=51 %s -o /dev/null
! CHECK-LABEL: func.func @_QPstandalone_common
! CHECK: %[[STANDALONE_X_MAP:.*]] = omp.map.info {{.*}} map_clauses(return_param) {{.*}} {name = "x"}
More information about the flang-commits
mailing list