[flang-commits] [flang] c2705cd - [flang][openmp] Support importing module declare target globals (#213930)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 2 02:51:34 PDT 2026


Author: Ville-Markus Yli-Suutala
Date: 2026-09-02T10:51:29+01:00
New Revision: c2705cdda1263926bc642f9abe3a3cb8b83071da

URL: https://github.com/llvm/llvm-project/commit/c2705cdda1263926bc642f9abe3a3cb8b83071da
DIFF: https://github.com/llvm/llvm-project/commit/c2705cdda1263926bc642f9abe3a3cb8b83071da.diff

LOG: [flang][openmp] Support importing module declare target globals (#213930)

Attach declare target attributes to declare target functions and
globals that have been imported from a module file.

Fixes https://github.com/llvm/llvm-project/issues/212333

Added: 
    flang/test/Lower/OpenMP/declare_target_module.f90

Modified: 
    flang/include/flang/Lower/OpenMP.h
    flang/include/flang/Semantics/semantics.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/OpenMP/OpenMP.cpp
    flang/test/Semantics/OpenMP/declare-target-modfile.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index a3f35498b9180..863a4ebc897d4 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -106,6 +106,12 @@ void materializeOpenMPDeclareMappers(
     Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
     const Fortran::semantics::Scope *scope = nullptr);
 
+// Mark declare target globals and functions that were imported from a
+// module file.
+void markOpenMPImportedDeclareTargets(
+    Fortran::lower::AbstractConverter &converter,
+    semantics::SemanticsContext &semaCtx);
+
 namespace omp {
 /// If \p base carries OpenMP DECLARE VARIANT entries, return the variant symbol
 /// that best matches the enclosing OpenMP context, or nullptr if none matches.

diff  --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index c41da2302e85b..b938749e756f6 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -377,6 +377,10 @@ class SemanticsContext {
   // Top-level ProgramTrees are owned by the SemanticsContext for persistence.
   ProgramTree &SaveProgramTree(ProgramTree &&);
 
+  const std::list<parser::Program> &GetModFileParseTrees() {
+    return modFileParseTrees_;
+  }
+
   // Label analysis classifies every labeled statement, and only some of those
   // classifications may be named by a statement that branches.  Lowering needs
   // the same distinction when it records the targets of a branch, so the

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index c6c230af7cf58..9392db1b0ecc5 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -626,6 +626,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             bridge.getLoweringOptions().getFPExceptionTraps());
       });
 
+    // Marking of OpenMP declare target functions and globals imported
+    // from a module file needs to happen after the primary
+    // translation pass has run, because that is where the ops that
+    // need marking are created.
+    createBuilderOutsideOfFuncOpAndDo([&]() {
+      Fortran::lower::markOpenMPImportedDeclareTargets(
+          *this, bridge.getSemanticsContext());
+    });
+
     finalizeOpenMPLowering(globalOmpRequiresSymbols);
   }
 

diff  --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index bb2c932fca790..76329bb5f08b4 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -18,6 +18,7 @@
 #include "Decomposer.h"
 #include "Utils.h"
 #include "flang/Common/idioms.h"
+#include "flang/Common/reference-wrapper.h"
 #include "flang/Evaluate/expression.h"
 #include "flang/Evaluate/fold.h"
 #include "flang/Evaluate/tools.h"
@@ -1498,7 +1499,7 @@ static void promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(
 /// 'declare target' directive and return the intended device type for them.
 static void getDeclareTargetInfo(
     lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
-    lower::pft::Evaluation &eval,
+    std::optional<common::reference_wrapper<lower::pft::Evaluation>> eval,
     const parser::OmpDeclareTargetDirective &construct,
     mlir::omp::DeclareTargetOperands &clauseOps,
     llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause) {
@@ -1512,8 +1513,10 @@ static void getDeclareTargetInfo(
     List<Clause> clauses = makeClauses(construct.v.Clauses(), semaCtx);
     if (clauses.empty()) {
       // Case: implicit capture of the enclosing function/subroutine.
+      assert(eval.has_value() &&
+             "expected eval to have value when clauses is empty");
       Fortran::lower::pft::FunctionLikeUnit *owningProc =
-          eval.getOwningProcedure();
+          eval->get().getOwningProcedure();
       bool owningProcNotMainProgram =
           owningProc && !owningProc->isMainProgram();
 
@@ -1854,6 +1857,36 @@ markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter,
                                    /*implicit=*/false);
 }
 
+// Take a declare target directive, and mark the globals and functions
+// named in its clauses.
+static void markDeclareTargetWithDirective(
+    lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+    std::optional<common::reference_wrapper<lower::pft::Evaluation>> eval,
+    const parser::OmpDeclareTargetDirective &declareTargetConstruct) {
+  mlir::omp::DeclareTargetOperands clauseOps;
+  llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
+  mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
+  getDeclareTargetInfo(converter, semaCtx, eval, declareTargetConstruct,
+                       clauseOps, symbolAndClause);
+
+  for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
+    mlir::Operation *op =
+        mod.lookupSymbol(converter.mangleName(symClause.symbol));
+
+    // Skip if no op is found. This happens during module declaration
+    // scope lowering for symbols that are deferred to be handled
+    // later in finalizeOpenMPLowering. This is also expected when
+    // handling a directive imported from a module file and the symbol
+    // is not used in the current translation unit, because no op is
+    // created for unused imports.
+    if (!op)
+      continue;
+
+    markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
+                      symClause.automap);
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Op body generation helper structures and functions
 //===----------------------------------------------------------------------===//
@@ -6797,25 +6830,8 @@ static void
 genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
        semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
        const parser::OmpDeclareTargetDirective &declareTargetConstruct) {
-  mlir::omp::DeclareTargetOperands clauseOps;
-  llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
-  mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
-  getDeclareTargetInfo(converter, semaCtx, eval, declareTargetConstruct,
-                       clauseOps, symbolAndClause);
-
-  for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
-    mlir::Operation *op =
-        mod.lookupSymbol(converter.mangleName(symClause.symbol));
-
-    // Some symbols are deferred until later in the module, these are handled
-    // upon finalization of the module for OpenMP inside of Bridge, so we simply
-    // skip for now.
-    if (!op)
-      continue;
-
-    markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
-                      symClause.automap);
-  }
+  markDeclareTargetWithDirective(converter, semaCtx, eval,
+                                 declareTargetConstruct);
 }
 
 static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -8116,3 +8132,37 @@ void Fortran::lower::materializeOpenMPDeclareMappers(
 // Walk scopes and materialize omp.declare_reduction ops for user-defined
 // operator reductions imported from modules (deleted: replaced by lazy,
 // clause-driven materialization).
+
+namespace {
+// Visitor used to mark declare target globals from imported modules.
+struct ModuleDeclareTargetVisitor {
+  Fortran::lower::AbstractConverter &converter;
+  semantics::SemanticsContext &semaCtx;
+
+  explicit ModuleDeclareTargetVisitor(
+      Fortran::lower::AbstractConverter &converter,
+      semantics::SemanticsContext &ctx)
+      : converter(converter), semaCtx(ctx) {}
+
+  template <typename T>
+  bool Pre(const T &) {
+    return true;
+  }
+  template <typename T>
+  void Post(const T &) {}
+
+  void Post(const parser::OmpDeclareTargetDirective &directive) {
+    markDeclareTargetWithDirective(converter, semaCtx, std::nullopt, directive);
+  }
+};
+} // namespace
+
+void Fortran::lower::markOpenMPImportedDeclareTargets(
+    Fortran::lower::AbstractConverter &converter,
+    semantics::SemanticsContext &semaCtx) {
+  const std::list<parser::Program> &modTrees = semaCtx.GetModFileParseTrees();
+  ModuleDeclareTargetVisitor visitor{converter, semaCtx};
+  for (auto &modTree : modTrees) {
+    parser::Walk(modTree, visitor);
+  }
+}

diff  --git a/flang/test/Lower/OpenMP/declare_target_module.f90 b/flang/test/Lower/OpenMP/declare_target_module.f90
new file mode 100644
index 0000000000000..8dbdb3d9469c4
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare_target_module.f90
@@ -0,0 +1,49 @@
+! RUN: rm -rf %t && split-file %s %t
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -module-dir %t %t/declare_target_module.f90 -o - > /dev/null
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -J %t %t/use_declare_target_module.f90 -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -fopenmp-is-target-device -J %t %t/use_declare_target_module.f90 -o - | FileCheck %s
+
+!--- declare_target_module.f90
+module declare_target_module
+  implicit none
+  integer, dimension(10) :: global_arr
+  !$omp declare target (global_arr)
+  real :: global_real
+  !$omp declare target link(global_real)
+  integer :: global_integer
+  !$omp declare target to(global_integer)
+  integer :: global_device_integer
+  !$omp declare target enter(global_device_integer) device_type(nohost)
+  contains
+  subroutine module_s()
+    !$omp declare target
+  end subroutine
+end module
+
+!--- use_declare_target_module.f90
+module use_declare_target_module
+use declare_target_module
+implicit none
+contains
+
+subroutine s()
+  !$omp declare target
+  global_arr(1) = 1
+  global_real = 1.0
+  global_integer = 1
+end subroutine
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_arr {alignment = 64 : i64, omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter)>} : !fir.array<10xi32>
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_real {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (link)>} : f32
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_integer {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter)>} : i32
+
+subroutine device_s()
+  !$omp declare target enter(device_s) device_type(nohost)
+  global_device_integer = 1
+end subroutine
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_device_integer {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter)>} : i32
+
+subroutine call_module_s()
+call module_s()
+end subroutine
+!CHECK-DAG: func.func private @_QMdeclare_target_modulePmodule_s() attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter)>}
+end module

diff  --git a/flang/test/Semantics/OpenMP/declare-target-modfile.f90 b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
index 710c849ca61b4..c2d119f9347b8 100644
--- a/flang/test/Semantics/OpenMP/declare-target-modfile.f90
+++ b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
@@ -25,6 +25,9 @@ subroutine h
   !$omp declare_target enter(h, a)
   continue
 end
+subroutine k
+  !$omp declare target
+end
 end module
 
 !Expect: m.mod
@@ -45,10 +48,13 @@ subroutine h
 !!$omp declare_target enter(g)
 !!$omp declare_target enter(f)
 !!$omp declare_target enter(h)
+!!$omp declare_target enter(k)
 !!$omp declare_target link(named_block)
 !contains
 !subroutine f()
 !end
 !subroutine h()
 !end
+!subroutine k()
+!end
 !end


        


More information about the flang-commits mailing list