[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