[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