[llvm-branch-commits] [flang] [flang][OpenMP] Store DECLARE_TARGET information in WithOmpDeclarative (PR #201103)

Krzysztof Parzyszek via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 2 05:34:02 PDT 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/201103

>From dc09abc584c63f344854abdab33084eb89c4a298 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 28 May 2026 12:29:06 -0500
Subject: [PATCH 1/2] [flang][OpenMP] Store DECLARE_TARGET information in
 WithOmpDeclarative

This will be used to emit DECLARE_TARGET directives into module files.

When a symbol apperars in DECLARE_TARGET (explicitly or explicitly), the
OmpDeclareTarget flag will be set on it. The set of accompanying clauses
will be stored in the associated details, in the WithOmpDeclarative mixin.
The mixin was added to ObjectEntityDetails, ProcEntityDetails, and
CommonBlockDetails.

The design goal was to be able to reconstruct the appropriate DECLARE_
TARGET directive for individual symbols for the purpose of emitting it
in a module file. Simply storing and then unparsing the AST node may
include symbols that should not be emitted.

Additionally, refactor the WithOmpDeclarative printing code for reuse in
symbol dumping for debugging, and for printing clause sets.
---
 .../FlangOmpReport/FlangOmpReportVisitor.cpp  |  3 +-
 flang/include/flang/Parser/dump-parse-tree.h  |  2 +-
 flang/include/flang/Parser/parse-tree.h       |  2 +-
 flang/include/flang/Semantics/symbol.h        | 26 ++++++-
 flang/include/flang/Support/Fortran.h         |  3 +
 flang/lib/Parser/unparse.cpp                  |  3 +-
 flang/lib/Semantics/mod-file.cpp              | 68 +++++++++++--------
 flang/lib/Semantics/resolve-directives.cpp    | 63 +++++++++++++++++
 flang/lib/Semantics/symbol.cpp                | 65 ++++++++++++------
 .../OpenMP/declare_target-device_type.f90     | 18 ++---
 flang/test/Parser/OpenMP/groupprivate.f90     |  2 +-
 .../Semantics/OpenMP/declare-target-flags.f90 | 36 ++++++++++
 .../OpenMP/declare-target-modfile.f90         | 41 +++++++++++
 .../OpenMP/dump-requires-details.f90          |  2 +-
 14 files changed, 265 insertions(+), 69 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/declare-target-flags.f90
 create mode 100644 flang/test/Semantics/OpenMP/declare-target-modfile.f90

diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp
index d9cb10a352708..c4ca3b22489d7 100644
--- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp
+++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp
@@ -137,8 +137,7 @@ void OpenMPCounterVisitor::Post(
 }
 void OpenMPCounterVisitor::Post(
     const OmpDeviceTypeClause::DeviceTypeDescription &c) {
-  clauseDetails +=
-      "type=" + std::string{OmpDeviceTypeClause::EnumToString(c)} + ";";
+  clauseDetails += "type=" + std::string{common::EnumToString(c)} + ";";
 }
 void OpenMPCounterVisitor::Post(
     const OmpDefaultmapClause::ImplicitBehavior &c) {
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index b4680e1cb656d..ff5c7a8ec01cf 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -66,6 +66,7 @@ class ParseTreeDumper {
   NODE_ENUM(common, CUDASubprogramAttrs)
   NODE_ENUM(common, ImportKind)
   NODE_ENUM(common, OmpDependenceKind)
+  NODE_ENUM(common, OmpDeviceType)
   NODE_ENUM(common, OmpMemoryOrderType)
   NODE_ENUM(common, OpenACCDeviceType)
   NODE(format, ControlEditDesc)
@@ -605,7 +606,6 @@ class ParseTreeDumper {
   NODE_ENUM(OmpDeviceModifier, Value)
   NODE(parser, OmpDeviceSafesyncClause)
   NODE(parser, OmpDeviceTypeClause)
-  NODE_ENUM(OmpDeviceTypeClause, DeviceTypeDescription)
   NODE(parser, OmpDimsModifier)
   NODE(parser, OmpDirectiveName)
   NODE(parser, OmpDirectiveSpecification)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 4efae0c9772b3..b8d622edf2b1a 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4591,7 +4591,7 @@ struct OmpDeviceSafesyncClause {
 // device-type-clause ->
 //    DEVICE_TYPE(ANY | HOST | NOHOST)              // since 5.0
 struct OmpDeviceTypeClause {
-  ENUM_CLASS(DeviceTypeDescription, Any, Host, Nohost)
+  using DeviceTypeDescription = common::OmpDeviceType;
   WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, DeviceTypeDescription);
 };
 
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index a7647665973d2..bb5a2dbbba409 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -66,6 +66,18 @@ class WithOmpDeclarative {
     ompAtomicDefaultMemOrder_ = flags;
   }
 
+  const OmpClauseSet &ompDeclTarget() const { return ompDeclTarget_; }
+  void set_ompDeclTarget(OmpClauseSet clauses) { ompDeclTarget_ = clauses; }
+
+  const std::optional<common::OmpDeviceType> &ompDeviceType() const {
+    return ompDeviceType_;
+  }
+  void set_ompDeclTarget(common::OmpDeviceType device) {
+    ompDeviceType_ = device;
+  }
+
+  void printClauseSet(llvm::raw_ostream &os, const OmpClauseSet &clauses,
+      parser::CharBlock name = parser::CharBlock{}) const;
   friend llvm::raw_ostream &operator<<(
       llvm::raw_ostream &, const WithOmpDeclarative &);
 
@@ -81,6 +93,12 @@ class WithOmpDeclarative {
   // The argument to ATOMIC_DEFAULT_MEM_ORDER. Only needed when the ADMO
   // clause is present in the ompRequires_ set.
   std::optional<common::OmpMemoryOrderType> ompAtomicDefaultMemOrder_;
+  // The set of clauses on DECLARE_TARGET directive that apply to this
+  // symbol.
+  OmpClauseSet ompDeclTarget_;
+  // The argument to DEVICE_TYPE clause. Only needed when the clause is
+  // present in the ompDeclTarget_ set.
+  std::optional<common::OmpDeviceType> ompDeviceType_;
 };
 
 // A module or submodule.
@@ -379,7 +397,7 @@ class AssocEntityDetails : public EntityDetails {
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
 
 // An entity known to be an object.
-class ObjectEntityDetails : public EntityDetails {
+class ObjectEntityDetails : public EntityDetails, public WithOmpDeclarative {
 public:
   explicit ObjectEntityDetails(EntityDetails &&);
   ObjectEntityDetails(const ObjectEntityDetails &) = default;
@@ -450,7 +468,9 @@ class WithPassArg {
 // A procedure pointer (other than one defined with POINTER and an
 // INTERFACE block), a dummy procedure (without an INTERFACE but with
 // EXTERNAL or use in a procedure reference), or external procedure.
-class ProcEntityDetails : public EntityDetails, public WithPassArg {
+class ProcEntityDetails : public EntityDetails,
+                          public WithPassArg,
+                          public WithOmpDeclarative {
 public:
   ProcEntityDetails() = default;
   explicit ProcEntityDetails(EntityDetails &&);
@@ -587,7 +607,7 @@ class NamelistDetails {
   SymbolVector objects_;
 };
 
-class CommonBlockDetails : public WithBindName {
+class CommonBlockDetails : public WithBindName, public WithOmpDeclarative {
 public:
   explicit CommonBlockDetails(SourceName location)
       : sourceLocation_{location} {}
diff --git a/flang/include/flang/Support/Fortran.h b/flang/include/flang/Support/Fortran.h
index 057b0c3da8c47..1118b2f8080a8 100644
--- a/flang/include/flang/Support/Fortran.h
+++ b/flang/include/flang/Support/Fortran.h
@@ -78,6 +78,9 @@ ENUM_CLASS(OmpDependenceKind, In, Out, Inout, Inoutset, Mutexinoutset, Depobj)
 // OpenMP memory-order types
 ENUM_CLASS(OmpMemoryOrderType, Acq_Rel, Acquire, Relaxed, Release, Seq_Cst)
 
+// OpenMP device-type
+ENUM_CLASS(OmpDeviceType, Any, Host, Nohost)
+
 // Fortran names may have up to 63 characters (See Fortran 2018 C601).
 static constexpr int maxNameLen{63};
 
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index fd9fcaa0405b2..58ecb365e138a 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2846,6 +2846,7 @@ class UnparseVisitor {
   WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA
   WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA
   WALK_NESTED_ENUM(common, OmpDependenceKind)
+  WALK_NESTED_ENUM(common, OmpDeviceType)
   WALK_NESTED_ENUM(common, OmpMemoryOrderType)
   WALK_NESTED_ENUM(IntentSpec, Intent) // R826
   WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
@@ -2873,8 +2874,6 @@ class UnparseVisitor {
   WALK_NESTED_ENUM(OmpThreadsetClause, ThreadsetPolicy) // OMP threadset
   WALK_NESTED_ENUM(OmpAccessGroup, Value)
   WALK_NESTED_ENUM(OmpDeviceModifier, Value) // OMP device modifier
-  WALK_NESTED_ENUM(
-      OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
   WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
   WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
   WALK_NESTED_ENUM(OmpFallbackModifier, Value) // OMP fallback-modifier
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 6e89ae92b882a..4f3d989d35235 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -364,39 +364,51 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
   }
 }
 
+static const WithOmpDeclarative *GetOmpDeclarative(const Symbol &symbol) {
+  return common::visit(
+      [&](auto &&details) -> const WithOmpDeclarative * {
+        using TypeD = llvm::remove_cvref_t<decltype(details)>;
+        if constexpr (std::is_base_of_v<WithOmpDeclarative, TypeD>) {
+          return &static_cast<const WithOmpDeclarative &>(details);
+        } else {
+          return nullptr;
+        }
+      },
+      symbol.details());
+}
+
+
 static void PutOpenMPRequirements(
     llvm::raw_ostream &os, const Symbol &symbol, SemanticsContext &semaCtx) {
   using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
-  using OmpMemoryOrderType = common::OmpMemoryOrderType;
   unsigned version{semaCtx.langOptions().OpenMPVersion};
 
-  const auto [reqs, order]{common::visit(
-      [&](auto &&details)
-          -> std::pair<const OmpClauseSet *, const OmpMemoryOrderType *> {
-        if constexpr (std::is_convertible_v<decltype(details),
-                          const WithOmpDeclarative &>) {
-          if (const auto &memOrder{details.ompAtomicDefaultMemOrder()}) {
-            return {&details.ompRequires(), &*memOrder};
-          }
-          return {&details.ompRequires(), nullptr};
-        } else {
-          return {nullptr, nullptr};
-        }
-      },
-      symbol.details())};
-
-  if (reqs->count()) {
-    os << "!$omp requires";
-    reqs->IterateOverMembers([&, order = order](llvm::omp::Clause f) {
-      os << ' '
-         << parser::ToLowerCaseLetters(
-                llvm::omp::getOpenMPClauseName(f, version));
-      if (f == llvm::omp::Clause::OMPC_atomic_default_mem_order) {
-        os << '(' << parser::ToLowerCaseLetters(EnumToString(DEREF(order)))
-           << ')';
+  if (const auto *decls{GetOmpDeclarative(symbol)}) {
+    if (const OmpClauseSet &reqs{decls->ompRequires()}; reqs.count()) {
+      os << "!$omp "
+         << parser::ToLowerCaseLetters(llvm::omp::getOpenMPDirectiveName(
+                llvm::omp::Directive::OMPD_requires, version));
+      decls->printClauseSet(os, reqs);
+      os << "\n";
+    }
+  }
+}
+
+static void PutOpenMPDeclarativeDirectives(llvm::raw_ostream &os,
+    const SymbolVector &symbols, SemanticsContext &semaCtx) {
+  using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
+  unsigned version{semaCtx.langOptions().OpenMPVersion};
+
+  for (const Symbol &symbol : symbols) {
+    if (const auto *decls{GetOmpDeclarative(symbol)}) {
+      if (const OmpClauseSet &dtgt{decls->ompDeclTarget()}; dtgt.count()) {
+        os << "!$omp "
+           << parser::ToLowerCaseLetters(llvm::omp::getOpenMPDirectiveName(
+                  llvm::omp::Directive::OMPD_declare_target, version)) << " ";
+        decls->printClauseSet(os, dtgt, symbol.name());
+        os << "\n";
       }
-    });
-    os << "\n";
+    }
   }
 }
 
@@ -438,6 +450,8 @@ void ModFileWriter::PutSymbols(
     PutUse(symbol);
   }
   PutOpenMPRequirements(decls_, DEREF(scope.symbol()), context_);
+  PutOpenMPDeclarativeDirectives(decls_, sorted, context_);
+
   for (const auto &set : scope.equivalenceSets()) {
     if (!set.empty() &&
         !set.front().symbol.test(Symbol::Flag::CompilerCreated)) {
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index b86bf64d18bd3..84d65d87c6a82 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2191,9 +2191,29 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) {
 bool OmpAttributeVisitor::Pre(const parser::OmpDeclareTargetDirective &x) {
   PushContext(x.source, llvm::omp::Directive::OMPD_declare_target);
 
+  using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
+  std::map<const Symbol *, WithOmpDeclarative> details;
+  std::optional<common::OmpDeviceType> device;
+
+  if (auto *devClause{
+          parser::omp::FindClause(x.v, llvm::omp::Clause::OMPC_device_type)}) {
+    device = parser::UnwrapRef<common::OmpDeviceType>(*devClause);
+  }
+
+  auto addClause{[&](const parser::OmpObject &object,
+                     llvm::omp::Clause clauseId) {
+    if (const Symbol *sym{omp::GetObjectSymbol(object)}) {
+      auto &clauseSet{const_cast<OmpClauseSet &>(details[sym].ompDeclTarget())};
+      clauseSet.set(clauseId);
+    }
+  }};
+
   for (const parser::OmpArgument &arg : x.v.Arguments().v) {
     if (auto *object{parser::omp::GetArgumentObject(arg)}) {
       ResolveOmpObject(*object, Symbol::Flag::OmpDeclareTarget);
+      // Always record this as "enter", even with older OpenMP versions
+      // (as opposed to "to").
+      addClause(*object, llvm::omp::Clause::OMPC_enter);
     }
   }
 
@@ -2201,9 +2221,52 @@ bool OmpAttributeVisitor::Pre(const parser::OmpDeclareTargetDirective &x) {
     if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
       for (const parser::OmpObject &object : objects->v) {
         ResolveOmpObject(object, Symbol::Flag::OmpDeclareTarget);
+        addClause(object, clause.Id());
       }
     }
   }
+
+  if (x.v.Arguments().v.empty() && x.v.Clauses().v.empty()) {
+    // "!$omp declare_target" alone applies to the associated procedure.
+    const Scope &scope{omp::GetScopingUnit(context_.FindScope(x.source))};
+    if (auto *proc{const_cast<Symbol *>(scope.symbol())}) {
+      proc->flags().set(Symbol::Flag::OmpDeclareTarget);
+      auto &clauseSet{
+          const_cast<OmpClauseSet &>(details[proc].ompDeclTarget())};
+      clauseSet.set(llvm::omp::Clause::OMPC_enter);
+    }
+  }
+
+  for (auto &pair : details) {
+    const Symbol *sym{&pair.first->GetUltimate()};
+    const WithOmpDeclarative &decl{pair.second};
+    common::visit(
+        [&](auto &d) {
+          using TypeD = llvm::remove_cvref_t<decltype(d)>;
+          if constexpr (std::is_base_of_v<WithOmpDeclarative, TypeD>) {
+            auto &clauseSet{const_cast<OmpClauseSet &>(d.ompDeclTarget())};
+            clauseSet |= decl.ompDeclTarget();
+            if (device) {
+              clauseSet.set(llvm::omp::Clause::OMPC_device_type);
+              auto &deviceType{
+                  const_cast<decltype(device) &>(d.ompDeviceType())};
+              deviceType = device;
+            }
+          } else if constexpr (std::is_same_v<GenericDetails, TypeD> ||
+              std::is_same_v<TypeParamDetails, TypeD> ||
+              std::is_same_v<MiscDetails, TypeD>) { // e.g. KindParamInquiry
+            // These cannot be specified on DECLARE_TARGET. The symbol will
+            // receive the OmpDeclareTarget flag (for a diagnostic message),
+            // but no details will be modified.
+          } else {
+            // Catch any unexpected cases.
+            assert((std::is_base_of_v<WithOmpDeclarative, TypeD>) &&
+                "Unexpected details type");
+          }
+        },
+        const_cast<Symbol *>(sym)->details());
+  }
+
   return true;
 }
 
diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 7712091a03210..b162a61d105ee 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -70,37 +70,55 @@ static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
   }
 }
 
-llvm::raw_ostream &operator<<(
-    llvm::raw_ostream &os, const WithOmpDeclarative &x) {
-  using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
-
+void WithOmpDeclarative::printClauseSet(llvm::raw_ostream &os,
+    const OmpClauseSet &clauses, parser::CharBlock name) const {
   auto toLower = [](std::string_view sv) {
     return parser::ToLowerCaseLetters(sv);
   };
   auto getLowerName = [&](llvm::omp::Clause c) {
-    return toLower(llvm::omp::getOpenMPClauseName(c, x.version_));
+    return toLower(llvm::omp::getOpenMPClauseName(c, version_));
   };
-  auto printClauses = [&](const OmpClauseSet &cs) {
-    size_t idx{0}, size{cs.count()};
-    cs.IterateOverMembers([&](llvm::omp::Clause c) {
-      os << getLowerName(c);
-      switch (c) {
-      case llvm::omp::Clause::OMPC_atomic_default_mem_order:
-        os << '(' << toLower(EnumToString(*x.ompAtomicDefaultMemOrder()))
-           << ')';
-        break;
-      default:
-        break;
-      }
-      if (++idx < size) {
-        os << ',';
+
+  size_t idx{0}, size{clauses.count()};
+  clauses.IterateOverMembers([&](llvm::omp::Clause c) {
+    os << getLowerName(c);
+    switch (c) {
+    case llvm::omp::Clause::OMPC_atomic_default_mem_order:
+      os << '(' << toLower(EnumToString(*ompAtomicDefaultMemOrder())) << ')';
+      break;
+    case llvm::omp::Clause::OMPC_device_type:
+      os << "(" << toLower(EnumToString(*ompDeviceType())) << ')';
+      break;
+    case llvm::omp::Clause::OMPC_enter:
+    case llvm::omp::Clause::OMPC_link:
+      if (!name.empty()) {
+        os << '(' << name.ToString() << ')';
       }
-    });
-  };
+      break;
+    case llvm::omp::Clause::OMPC_indirect:
+      os << "(true)";
+      break;
+    default:
+      break;
+    }
+    if (++idx < size) {
+      os << ' ';
+    }
+  });
+}
+
+llvm::raw_ostream &operator<<(
+    llvm::raw_ostream &os, const WithOmpDeclarative &x) {
+  using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
 
   if (const OmpClauseSet &reqs{x.ompRequires()}; reqs.count()) {
     os << " OmpRequirements:(";
-    printClauses(reqs);
+    x.printClauseSet(os, reqs);
+    os << ')';
+  }
+  if (const OmpClauseSet &dtgt{x.ompDeclTarget()}; dtgt.count()) {
+    os << " OmpDeclareTargetFlags:(";
+    x.printClauseSet(os, dtgt);
     os << ')';
   }
   return os;
@@ -545,6 +563,7 @@ llvm::raw_ostream &operator<<(
   if (x.cudaDataAttr()) {
     os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
   }
+  os << static_cast<const WithOmpDeclarative &>(x);
   return os;
 }
 
@@ -584,6 +603,7 @@ llvm::raw_ostream &operator<<(
   if (x.isCUDAKernel()) {
     os << " isCUDAKernel";
   }
+  os << static_cast<const WithOmpDeclarative &>(x);
   return os;
 }
 
@@ -679,6 +699,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
             for (const auto &object : x.objects()) {
               os << ' ' << object->name();
             }
+            os << static_cast<const WithOmpDeclarative &>(x);
           },
           [&](const TypeParamDetails &x) {
             DumpOptional(os, "type", x.type());
diff --git a/flang/test/Parser/OpenMP/declare_target-device_type.f90 b/flang/test/Parser/OpenMP/declare_target-device_type.f90
index 4b61fb6f16f33..9c2e63c12941c 100644
--- a/flang/test/Parser/OpenMP/declare_target-device_type.f90
+++ b/flang/test/Parser/OpenMP/declare_target-device_type.f90
@@ -7,7 +7,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | Flags = {}
@@ -17,7 +17,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | Flags = {}
@@ -27,7 +27,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | Flags = {}
@@ -37,7 +37,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | | bool = 'true'
@@ -48,7 +48,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | | bool = 'true'
@@ -59,7 +59,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | | bool = 'true'
@@ -70,7 +70,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
@@ -83,7 +83,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
@@ -96,7 +96,7 @@ subroutine openmp_declare_target
 
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
 !PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
 !PARSE-TREE: | OmpClause -> To -> OmpToClause
diff --git a/flang/test/Parser/OpenMP/groupprivate.f90 b/flang/test/Parser/OpenMP/groupprivate.f90
index ca4d974f6895c..120af619d3b9b 100644
--- a/flang/test/Parser/OpenMP/groupprivate.f90
+++ b/flang/test/Parser/OpenMP/groupprivate.f90
@@ -21,7 +21,7 @@ module m
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = groupprivate
 !PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'x'
 !PARSE-TREE: | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'y'
-!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
 !PARSE-TREE: | Flags = {}
 !PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpGroupprivateDirective -> OmpDirectiveSpecification
 !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = groupprivate
diff --git a/flang/test/Semantics/OpenMP/declare-target-flags.f90 b/flang/test/Semantics/OpenMP/declare-target-flags.f90
new file mode 100644
index 0000000000000..b17bc61d145f7
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-flags.f90
@@ -0,0 +1,36 @@
+!RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=60 %s | FileCheck %s
+
+module m
+integer :: x
+!$omp declare_target link(x) device_type(nohost)
+interface
+  real function g(v)
+    real :: v(10)
+    !$omp declare_target
+  end
+end interface
+contains
+subroutine f
+  !$omp declare_target(f)
+end
+subroutine h
+  integer, save :: a(10)
+  !$omp declare_target enter(h, a)
+  continue
+end
+end module
+
+!CHECK:  Module scope: m size=4 alignment=4 sourceRange=295 bytes
+!CHECK:    f, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
+!CHECK:    g, EXTERNAL, PUBLIC (Function, OmpDeclareTarget): Subprogram isInterface result:REAL(4) g (REAL(4) v) OmpDeclareTargetFlags:(enter)
+!CHECK:    h, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
+!CHECK:    x, PUBLIC (OmpDeclareTarget) size=4 offset=0: ObjectEntity type: INTEGER(4) OmpDeclareTargetFlags:(device_type(nohost) link)
+!CHECK:    Subprogram scope: g size=44 alignment=4 sourceRange=57 bytes
+!CHECK:      g size=4 offset=0: ObjectEntity funcResult type: REAL(4)
+!CHECK:      v size=40 offset=4: ObjectEntity dummy type: REAL(4) shape: 1_8:10_8
+!CHECK:    Subprogram scope: f size=0 alignment=1 sourceRange=40 bytes
+!CHECK:      f (Subroutine, OmpDeclareTarget): HostAssoc => f, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
+!CHECK:    Subprogram scope: h size=40 alignment=4 sourceRange=81 bytes
+!CHECK:      a, SAVE (OmpDeclareTarget) size=40 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:10_8 OmpDeclareTargetFlags:(enter)
+!CHECK:      h (Subroutine, OmpDeclareTarget): HostAssoc => h, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
+
diff --git a/flang/test/Semantics/OpenMP/declare-target-modfile.f90 b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
new file mode 100644
index 0000000000000..eb4c4c855f597
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-target-modfile.f90
@@ -0,0 +1,41 @@
+!RUN: %python %S/../test_modfile.py %s %flang_fc1 -fopenmp -fopenmp-version=60
+
+module m
+integer :: x
+!$omp declare_target link(x) device_type(nohost)
+interface
+  real function g(v)
+    real :: v(10)
+    !$omp declare_target
+  end
+end interface
+contains
+subroutine f
+  !$omp declare_target(f)
+end
+subroutine h
+  integer, save :: a(10)
+  !$omp declare_target enter(h, a)
+  continue
+end
+end module
+
+!Expect: m.mod
+!module m
+!integer(4)::x
+!interface
+!function g(v)
+!real(4)::v(1_8:10_8)
+!real(4)::g
+!end
+!end interface
+!!$omp declare_target device_type(nohost) link(x)
+!!$omp declare_target enter(g)
+!!$omp declare_target enter(f)
+!!$omp declare_target enter(h)
+!contains
+!subroutine f()
+!end
+!subroutine h()
+!end
+!end
diff --git a/flang/test/Semantics/OpenMP/dump-requires-details.f90 b/flang/test/Semantics/OpenMP/dump-requires-details.f90
index 9c844c092c5e6..dbca9df41c5fb 100644
--- a/flang/test/Semantics/OpenMP/dump-requires-details.f90
+++ b/flang/test/Semantics/OpenMP/dump-requires-details.f90
@@ -11,4 +11,4 @@ subroutine f01
 end
 end module
 
-!CHECK: fred: Module OmpRequirements:(atomic_default_mem_order(relaxed),unified_address,unified_shared_memory)
+!CHECK: fred: Module OmpRequirements:(atomic_default_mem_order(relaxed) unified_address unified_shared_memory)

>From 227e62e6d087f9c976aad91bedb77872100ab613 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 2 Jun 2026 07:33:48 -0500
Subject: [PATCH 2/2] format

---
 flang/lib/Semantics/mod-file.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 4f3d989d35235..e4dc5151abbc2 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -404,7 +404,8 @@ static void PutOpenMPDeclarativeDirectives(llvm::raw_ostream &os,
       if (const OmpClauseSet &dtgt{decls->ompDeclTarget()}; dtgt.count()) {
         os << "!$omp "
            << parser::ToLowerCaseLetters(llvm::omp::getOpenMPDirectiveName(
-                  llvm::omp::Directive::OMPD_declare_target, version)) << " ";
+                  llvm::omp::Directive::OMPD_declare_target, version))
+           << " ";
         decls->printClauseSet(os, dtgt, symbol.name());
         os << "\n";
       }



More information about the llvm-branch-commits mailing list