[flang-commits] [flang] [flang][openmp] Support importing module declare target globals (PR #213930)
Ville-Markus Yli-Suutala via flang-commits
flang-commits at lists.llvm.org
Wed Aug 26 04:16:51 PDT 2026
https://github.com/VeeEM updated https://github.com/llvm/llvm-project/pull/213930
>From bd9c1852a8f4cd2c11cfd4c607f57371d6c422e9 Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Mon, 3 Aug 2026 18:59:50 +0300
Subject: [PATCH 1/5] [flang][openmp] Write to clause symbols to modfile
Fix bug where the list of variables would be ignored when writing the to
clause of a declare target directive to a modfile.
to clauses are written into a modfile as enter clauses.
---
flang/lib/Semantics/symbol.cpp | 9 +++++++--
flang/test/Semantics/OpenMP/declare-target-modfile.f90 | 4 ++++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index b802930326a6f..b3acd59b4a299 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -78,8 +78,13 @@ void WithOmpDeclarative::printClauseSet(llvm::raw_ostream &os,
size_t idx{0}, size{clauses.count()};
for (llvm::omp::Clause c : clauses) {
- os << toLower(llvm::omp::getOpenMPClauseName(c, version_));
- switch (c) {
+ llvm::omp::Clause clause = c;
+ // Write to as enter when writing a mod file
+ if (clause == llvm::omp::Clause::OMPC_to && !name.empty()) {
+ clause = llvm::omp::Clause::OMPC_enter;
+ }
+ os << toLower(llvm::omp::getOpenMPClauseName(clause, version_));
+ switch (clause) {
case llvm::omp::Clause::OMPC_atomic_default_mem_order:
os << '(' << toLower(EnumToString(*ompAtomicDefaultMemOrder())) << ')';
break;
diff --git a/flang/test/Semantics/OpenMP/declare-target-modfile.f90 b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
index 9a2f9a3026947..710c849ca61b4 100644
--- a/flang/test/Semantics/OpenMP/declare-target-modfile.f90
+++ b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
@@ -3,6 +3,8 @@
module m
integer :: x
!$omp declare_target link(x) device_type(nohost)
+integer :: y
+!$omp declare target to(y)
real :: w(10), u(10)
common /named_block/ w, u
!$omp declare_target link(/named_block/)
@@ -28,6 +30,7 @@ subroutine h
!Expect: m.mod
!module m
!integer(4)::x
+!integer(4)::y
!real(4)::w(1_8:10_8)
!real(4)::u(1_8:10_8)
!interface
@@ -38,6 +41,7 @@ subroutine h
!end interface
!common/named_block/w,u
!!$omp declare_target device_type(nohost) link(x)
+!!$omp declare_target enter(y)
!!$omp declare_target enter(g)
!!$omp declare_target enter(f)
!!$omp declare_target enter(h)
>From 04671dd6fc7dc299574c5099a9bd267c09a3e1c3 Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Sat, 8 Aug 2026 20:21:24 +0300
Subject: [PATCH 2/5] [flang][openmp] Support importing module declare target
globals
Attach device type and capture clause attributes to declare target
globals that have been imported from a module file.
Fixes https://github.com/llvm/llvm-project/issues/212333
---
flang/include/flang/Lower/OpenMP.h | 5 +++
flang/lib/Lower/OpenMP/OpenMP.cpp | 57 ++++++++++++++++++++++++------
2 files changed, 52 insertions(+), 10 deletions(-)
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index a3f35498b9180..47f27ceece165 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -106,6 +106,11 @@ void materializeOpenMPDeclareMappers(
Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
const Fortran::semantics::Scope *scope = nullptr);
+// Attach declare target attributes to declare target global variables
+// imported from a module file.
+void attachOpenMPDeclareTargetAttributes(lower::AbstractConverter &converter,
+ const lower::pft::Variable &var);
+
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/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 7503d33c8df38..6232e6e0468fa 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -7830,8 +7830,12 @@ void Fortran::lower::genOpenMPSymbolProperties(
if (sym.test(semantics::Symbol::Flag::OmpThreadprivate))
lower::genThreadprivateOp(converter, var);
- if (sym.test(semantics::Symbol::Flag::OmpDeclareTarget))
- lower::genDeclareTargetIntGlobal(converter, var);
+ if (sym.test(semantics::Symbol::Flag::OmpDeclareTarget)) {
+ if (var.isGlobal())
+ lower::attachOpenMPDeclareTargetAttributes(converter, var);
+ else
+ lower::genDeclareTargetIntGlobal(converter, var);
+ }
}
void Fortran::lower::genGroupprivateOp(lower::AbstractConverter &converter,
@@ -7931,14 +7935,12 @@ void Fortran::lower::genThreadprivateOp(lower::AbstractConverter &converter,
// generation.
void Fortran::lower::genDeclareTargetIntGlobal(
lower::AbstractConverter &converter, const lower::pft::Variable &var) {
- if (!var.isGlobal()) {
- // A non-global variable which can be in a declare target directive must
- // be a variable in the main program, and it has the implicit SAVE
- // attribute. We create a GlobalOp for it to simplify the translation to
- // LLVM IR.
- globalInitialization(converter, converter.getFirOpBuilder(),
- var.getSymbol(), var, converter.getCurrentLocation());
- }
+ // A non-global variable which can be in a declare target directive must
+ // be a variable in the main program, and it has the implicit SAVE
+ // attribute. We create a GlobalOp for it to simplify the translation to
+ // LLVM IR.
+ globalInitialization(converter, converter.getFirOpBuilder(), var.getSymbol(),
+ var, converter.getCurrentLocation());
}
bool Fortran::lower::isOpenMPTargetConstruct(
@@ -8093,3 +8095,38 @@ 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).
+
+void Fortran::lower::attachOpenMPDeclareTargetAttributes(
+ lower::AbstractConverter &converter, const lower::pft::Variable &var) {
+ auto module = converter.getModuleOp();
+
+ mlir::Operation *globalOp =
+ module.lookupSymbol(converter.mangleName(var.getSymbol()));
+
+ auto ultimateSymbol = var.getSymbol().GetUltimate();
+
+ if (globalOp && ultimateSymbol.IsFromModFile()) {
+ auto declareTargetOp =
+ llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(globalOp);
+ Fortran::common::visit(
+ [&](const auto &details) {
+ if constexpr (std::is_base_of_v<semantics::WithOmpDeclarative,
+ std::decay_t<decltype(details)>>) {
+ mlir::omp::DeclareTargetDeviceType deviceType =
+ toMLIRDeclareTargetDeviceType(
+ details.ompDeclTargetDeviceType().value_or(
+ Fortran::common::OmpDeviceType::Any));
+
+ mlir::omp::DeclareTargetCaptureClause clause;
+ if (details.ompDeclTarget().test(llvm::omp::Clause::OMPC_link))
+ clause = mlir::omp::DeclareTargetCaptureClause::link;
+ else
+ clause = mlir::omp::DeclareTargetCaptureClause::enter;
+
+ declareTargetOp.setDeclareTarget(deviceType, clause,
+ /*automap=*/false);
+ }
+ },
+ ultimateSymbol.details());
+ }
+}
>From 140cf54d09bd18bd62be9311df12dacaa09cb4f8 Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Mon, 10 Aug 2026 16:11:34 +0300
Subject: [PATCH 3/5] fixup! [flang][openmp] Support importing module declare
target globals
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 3 +-
.../Lower/OpenMP/declare_target_module.f90 | 37 +++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Lower/OpenMP/declare_target_module.f90
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 6232e6e0468fa..daa4e6ecb14a2 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -8098,6 +8098,7 @@ void Fortran::lower::materializeOpenMPDeclareMappers(
void Fortran::lower::attachOpenMPDeclareTargetAttributes(
lower::AbstractConverter &converter, const lower::pft::Variable &var) {
+ assert(var.isGlobal());
auto module = converter.getModuleOp();
mlir::Operation *globalOp =
@@ -8107,7 +8108,7 @@ void Fortran::lower::attachOpenMPDeclareTargetAttributes(
if (globalOp && ultimateSymbol.IsFromModFile()) {
auto declareTargetOp =
- llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(globalOp);
+ llvm::cast<mlir::omp::DeclareTargetInterface>(globalOp);
Fortran::common::visit(
[&](const auto &details) {
if constexpr (std::is_base_of_v<semantics::WithOmpDeclarative,
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..226b70e9f5137
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare_target_module.f90
@@ -0,0 +1,37 @@
+! 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
+
+!--- 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)
+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), automap = false>} : !fir.array<10xi32>
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_real {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (link), automap = false>} : f32
+!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_integer {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter), automap = false>} : 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), automap = false>} : i32
+end module
>From 31b2c15c2c6eb3126a4e8da3d275879c4ba7fbf0 Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Mon, 24 Aug 2026 23:15:57 +0300
Subject: [PATCH 4/5] fixup! [flang][openmp] Support importing module declare
target globals
---
flang/include/flang/Lower/OpenMP.h | 7 +-
flang/include/flang/Semantics/semantics.h | 4 +
flang/lib/Lower/Bridge.cpp | 5 +
flang/lib/Lower/OpenMP/OpenMP.cpp | 102 ++++++++++--------
.../Lower/OpenMP/declare_target_module.f90 | 19 +++-
5 files changed, 86 insertions(+), 51 deletions(-)
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index 47f27ceece165..0ad4d05f63792 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -106,10 +106,9 @@ void materializeOpenMPDeclareMappers(
Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
const Fortran::semantics::Scope *scope = nullptr);
-// Attach declare target attributes to declare target global variables
-// imported from a module file.
-void attachOpenMPDeclareTargetAttributes(lower::AbstractConverter &converter,
- const lower::pft::Variable &var);
+void markOpenMPImportedDeclareTargets(
+ Fortran::lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx);
namespace omp {
/// If \p base carries OpenMP DECLARE VARIANT entries, return the variant symbol
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index c41da2302e85b..1b9f314ab4c08 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 &&);
+ 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 3d71a4dbf9b1b..a7aa7ebb1b79a 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -626,6 +626,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
bridge.getLoweringOptions().getFPExceptionTraps());
});
+ 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 daa4e6ecb14a2..64b85404aa648 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"
@@ -1496,7 +1497,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) {
@@ -1510,8 +1511,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();
@@ -7830,12 +7833,8 @@ void Fortran::lower::genOpenMPSymbolProperties(
if (sym.test(semantics::Symbol::Flag::OmpThreadprivate))
lower::genThreadprivateOp(converter, var);
- if (sym.test(semantics::Symbol::Flag::OmpDeclareTarget)) {
- if (var.isGlobal())
- lower::attachOpenMPDeclareTargetAttributes(converter, var);
- else
- lower::genDeclareTargetIntGlobal(converter, var);
- }
+ if (sym.test(semantics::Symbol::Flag::OmpDeclareTarget))
+ lower::genDeclareTargetIntGlobal(converter, var);
}
void Fortran::lower::genGroupprivateOp(lower::AbstractConverter &converter,
@@ -7935,12 +7934,14 @@ void Fortran::lower::genThreadprivateOp(lower::AbstractConverter &converter,
// generation.
void Fortran::lower::genDeclareTargetIntGlobal(
lower::AbstractConverter &converter, const lower::pft::Variable &var) {
- // A non-global variable which can be in a declare target directive must
- // be a variable in the main program, and it has the implicit SAVE
- // attribute. We create a GlobalOp for it to simplify the translation to
- // LLVM IR.
- globalInitialization(converter, converter.getFirOpBuilder(), var.getSymbol(),
- var, converter.getCurrentLocation());
+ if (!var.isGlobal()) {
+ // A non-global variable which can be in a declare target directive must
+ // be a variable in the main program, and it has the implicit SAVE
+ // attribute. We create a GlobalOp for it to simplify the translation to
+ // LLVM IR.
+ globalInitialization(converter, converter.getFirOpBuilder(),
+ var.getSymbol(), var, converter.getCurrentLocation());
+ }
}
bool Fortran::lower::isOpenMPTargetConstruct(
@@ -8096,38 +8097,53 @@ void Fortran::lower::materializeOpenMPDeclareMappers(
// operator reductions imported from modules (deleted: replaced by lazy,
// clause-driven materialization).
-void Fortran::lower::attachOpenMPDeclareTargetAttributes(
- lower::AbstractConverter &converter, const lower::pft::Variable &var) {
- assert(var.isGlobal());
- auto module = converter.getModuleOp();
+// Visitor used to mark declare target globals from imported modules.
+struct ModuleDeclareTargetVisitor {
+ Fortran::lower::AbstractConverter &converter;
+ semantics::SemanticsContext &semaCtx;
- mlir::Operation *globalOp =
- module.lookupSymbol(converter.mangleName(var.getSymbol()));
+ explicit ModuleDeclareTargetVisitor(
+ Fortran::lower::AbstractConverter &converter,
+ semantics::SemanticsContext &ctx)
+ : converter(converter), semaCtx(ctx) {}
- auto ultimateSymbol = var.getSymbol().GetUltimate();
+ template <typename T>
+ bool Pre(const T &) {
+ return true;
+ }
+ template <typename T>
+ void Post(const T &) {}
- if (globalOp && ultimateSymbol.IsFromModFile()) {
- auto declareTargetOp =
- llvm::cast<mlir::omp::DeclareTargetInterface>(globalOp);
- Fortran::common::visit(
- [&](const auto &details) {
- if constexpr (std::is_base_of_v<semantics::WithOmpDeclarative,
- std::decay_t<decltype(details)>>) {
- mlir::omp::DeclareTargetDeviceType deviceType =
- toMLIRDeclareTargetDeviceType(
- details.ompDeclTargetDeviceType().value_or(
- Fortran::common::OmpDeviceType::Any));
-
- mlir::omp::DeclareTargetCaptureClause clause;
- if (details.ompDeclTarget().test(llvm::omp::Clause::OMPC_link))
- clause = mlir::omp::DeclareTargetCaptureClause::link;
- else
- clause = mlir::omp::DeclareTargetCaptureClause::enter;
+ void Post(const parser::OmpDeclareTargetDirective &directive) {
+ mlir::omp::DeclareTargetOperands clauseOps;
+ llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
+ mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
- declareTargetOp.setDeclareTarget(deviceType, clause,
- /*automap=*/false);
- }
- },
- ultimateSymbol.details());
+ getDeclareTargetInfo(converter, semaCtx, std::nullopt, directive, clauseOps,
+ symbolAndClause);
+
+ for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
+ mlir::Operation *op =
+ mod.lookupSymbol(converter.mangleName(symClause.symbol));
+
+ // op not found, so nothing to mark. This happens for variables
+ // and functions that are not actually used in the current
+ // translation unit.
+ if (!op)
+ continue;
+
+ markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
+ symClause.automap);
+ }
+ }
+};
+
+void Fortran::lower::markOpenMPImportedDeclareTargets(
+ Fortran::lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx) {
+ 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
index 226b70e9f5137..3a9ec591140ea 100644
--- a/flang/test/Lower/OpenMP/declare_target_module.f90
+++ b/flang/test/Lower/OpenMP/declare_target_module.f90
@@ -13,6 +13,10 @@ module declare_target_module
!$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
@@ -20,18 +24,25 @@ 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), automap = false>} : !fir.array<10xi32>
-!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_real {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (link), automap = false>} : f32
-!CHECK-DAG: fir.global @_QMdeclare_target_moduleEglobal_integer {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter), automap = false>} : i32
+!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), automap = false>} : i32
+!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
>From 327777026780e51d7dc19417f4c358a510aaa27f Mon Sep 17 00:00:00 2001
From: Ville-Markus Yli-Suutala <ville-markus.yli-suutala at helsinki.fi>
Date: Wed, 26 Aug 2026 14:16:24 +0300
Subject: [PATCH 5/5] fixup! [flang][openmp] Support importing module declare
target globals
---
flang/include/flang/Lower/OpenMP.h | 2 +
flang/include/flang/Semantics/semantics.h | 2 +-
flang/lib/Lower/OpenMP/OpenMP.cpp | 77 +++++++++++------------
3 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index 0ad4d05f63792..863a4ebc897d4 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -106,6 +106,8 @@ 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);
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 1b9f314ab4c08..b938749e756f6 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -377,7 +377,7 @@ class SemanticsContext {
// Top-level ProgramTrees are owned by the SemanticsContext for persistence.
ProgramTree &SaveProgramTree(ProgramTree &&);
- std::list<parser::Program> &GetModFileParseTrees() {
+ const std::list<parser::Program> &GetModFileParseTrees() {
return modFileParseTrees_;
}
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 64b85404aa648..fad071c561d41 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1855,6 +1855,31 @@ 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));
+
+ // Do nothing if op is not found.
+ if (!op)
+ continue;
+
+ markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
+ symClause.automap);
+ }
+}
+
//===----------------------------------------------------------------------===//
// Op body generation helper structures and functions
//===----------------------------------------------------------------------===//
@@ -6777,25 +6802,12 @@ 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);
- }
+ // Some symbols are deferred until later. These are skipped in
+ // markDeclareTargetWithDirective at this stage and handled later in
+ // finalizeOpenMPLowering.
+ markDeclareTargetWithDirective(converter, semaCtx, eval,
+ declareTargetConstruct);
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -8097,6 +8109,7 @@ void Fortran::lower::materializeOpenMPDeclareMappers(
// 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;
@@ -8115,33 +8128,19 @@ struct ModuleDeclareTargetVisitor {
void Post(const T &) {}
void Post(const parser::OmpDeclareTargetDirective &directive) {
- mlir::omp::DeclareTargetOperands clauseOps;
- llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
- mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
-
- getDeclareTargetInfo(converter, semaCtx, std::nullopt, directive, clauseOps,
- symbolAndClause);
-
- for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
- mlir::Operation *op =
- mod.lookupSymbol(converter.mangleName(symClause.symbol));
-
- // op not found, so nothing to mark. This happens for variables
- // and functions that are not actually used in the current
- // translation unit.
- if (!op)
- continue;
-
- markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
- symClause.automap);
- }
+ // The directive might mention symbols that are not used in the
+ // current translation unit. Such symbols are ignored in
+ // markDeclareTargetWithDirective, as there exists no Operation
+ // that needs marking.
+ markDeclareTargetWithDirective(converter, semaCtx, std::nullopt, directive);
}
};
+} // namespace
void Fortran::lower::markOpenMPImportedDeclareTargets(
Fortran::lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx) {
- std::list<parser::Program> &modTrees = semaCtx.GetModFileParseTrees();
+ const std::list<parser::Program> &modTrees = semaCtx.GetModFileParseTrees();
ModuleDeclareTargetVisitor visitor{converter, semaCtx};
for (auto &modTree : modTrees) {
parser::Walk(modTree, visitor);
More information about the flang-commits
mailing list