[flang-commits] [flang] [flang][OpenMP] Fix declare target attribute for USE-associated module globals (PR #218339)
Urvi Rav via flang-commits
flang-commits at lists.llvm.org
Mon Aug 24 03:14:11 PDT 2026
https://github.com/ravurvi20 updated https://github.com/llvm/llvm-project/pull/218339
>From cd52b016bdad8560737bc1dbd31db7e7894d86df Mon Sep 17 00:00:00 2001
From: urvi-rav <urvi.rav at hpe.com>
Date: Mon, 24 Aug 2026 02:17:31 -0500
Subject: [PATCH] declare target for USE-associated module variables
---
flang/lib/Lower/ConvertVariable.cpp | 45 +++++++++++++++++++
.../declare-target-use-associated-global.f90 | 28 ++++++++++++
2 files changed, 73 insertions(+)
create mode 100644 flang/test/Lower/OpenMP/declare-target-use-associated-global.f90
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index a808905850922..5be119301a300 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -46,6 +46,7 @@
#include "flang/Semantics/tools.h"
#include "flang/Semantics/type.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -194,6 +195,49 @@ static void attachAccDeclareAttribute(fir::FirOpBuilder &builder,
builder.getContext(), clause)));
}
+/// Copy the `omp.declare_target` attribute onto an external global declaration
+/// created for a USE-associated module variable. The directive lives in the
+/// defining module, so the USE-ing unit must re-attach it here; otherwise the
+/// global is internalized on the device and loses its device-resident copy.
+static void
+attachDeclareTargetAttribute(fir::FirOpBuilder &builder, fir::GlobalOp global,
+ const Fortran::semantics::Symbol &sym) {
+ using Flag = Fortran::semantics::Symbol::Flag;
+ const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
+ if (!ultimate.test(Flag::OmpDeclareTarget))
+ return;
+ auto declareTargetOp =
+ llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(global.getOperation());
+ if (!declareTargetOp || declareTargetOp.isDeclareTarget())
+ return;
+
+ mlir::omp::DeclareTargetDeviceType deviceType =
+ mlir::omp::DeclareTargetDeviceType::any;
+ mlir::omp::DeclareTargetCaptureClause captureClause =
+ mlir::omp::DeclareTargetCaptureClause::to;
+ if (const auto *details =
+ ultimate.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
+ if (const std::optional<Fortran::common::OmpDeviceType> &dt =
+ details->ompDeclTargetDeviceType()) {
+ switch (*dt) {
+ case Fortran::common::OmpDeviceType::Host:
+ deviceType = mlir::omp::DeclareTargetDeviceType::host;
+ break;
+ case Fortran::common::OmpDeviceType::Nohost:
+ deviceType = mlir::omp::DeclareTargetDeviceType::nohost;
+ break;
+ case Fortran::common::OmpDeviceType::Any:
+ deviceType = mlir::omp::DeclareTargetDeviceType::any;
+ break;
+ }
+ }
+ if (details->ompDeclTarget().test(llvm::omp::Clause::OMPC_link))
+ captureClause = mlir::omp::DeclareTargetCaptureClause::link;
+ }
+ declareTargetOp.setDeclareTarget(deviceType, captureClause,
+ /*automap=*/false, /*implicit=*/false);
+}
+
/// Create the global op declaration without any initializer
static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
const Fortran::lower::pft::Variable &var,
@@ -225,6 +269,7 @@ static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
isConstant(ultimate), var.isTarget(), dataAttr,
/*setDefaultAlignment=*/!isBindC);
attachAccDeclareAttribute(builder, global, sym);
+ attachDeclareTargetAttribute(builder, global, sym);
Fortran::lower::declareExternalAccModuleDeclareActionRecipes(converter,
builder, sym);
return global;
diff --git a/flang/test/Lower/OpenMP/declare-target-use-associated-global.f90 b/flang/test/Lower/OpenMP/declare-target-use-associated-global.f90
new file mode 100644
index 0000000000000..88620f2efb450
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-target-use-associated-global.f90
@@ -0,0 +1,28 @@
+! A module variable marked `declare target` must keep that attribute when it is
+! USE-associated in a separately compiled file. The directive lives in the
+! module, so the USE-ing file must copy the attribute onto the external global
+! it declares. Without it the device pass internalizes the global and
+! `target update` reads stale data.
+
+! RUN: split-file %s %t
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -module-dir %t %t/mod.f90 -o /dev/null
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -fopenmp-is-target-device -module-dir %t %t/use.f90 -o - | FileCheck %s
+
+!--- mod.f90
+module dt_mod
+ implicit none
+ integer :: arr(100)
+ !$omp declare target enter(arr)
+end module
+
+!--- use.f90
+! Here the global is only an external declaration, but it still must carry the
+! declare target attribute.
+! CHECK: fir.global @_QMdt_modEarr {{.*}}omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (to)
+subroutine sub(i)
+ use dt_mod
+ implicit none
+ !$omp declare target
+ integer :: i
+ arr(i) = i
+end subroutine
More information about the flang-commits
mailing list