[flang] [llvm] [Flang] Add parser support for AUTOMAP modifier (PR #151020)

Akash Banerjee via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 28 11:52:56 PDT 2025


https://github.com/TIFitis updated https://github.com/llvm/llvm-project/pull/151020

>From 732b2db252285b37c83994577ac3e67b02524441 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Mon, 28 Jul 2025 19:05:25 +0100
Subject: [PATCH 1/2] [Flang] Add parser support for AUTOMAP modifier

Add parser support for the new AUTOMAP modifier for OpenMP Declare Target Enter clause introduced in OpenMP 6.0 section 7.9.7.
---
 flang/include/flang/Parser/dump-parse-tree.h  |  4 ++
 flang/include/flang/Parser/parse-tree.h       | 21 ++++++++++
 .../flang/Semantics/openmp-modifiers.h        |  1 +
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    | 10 +++--
 flang/lib/Lower/OpenMP/Clauses.cpp            | 15 ++++++-
 flang/lib/Parser/openmp-parsers.cpp           | 12 +++++-
 flang/lib/Parser/unparse.cpp                  |  6 +++
 flang/lib/Semantics/check-omp-structure.cpp   | 39 +++++++++++--------
 flang/lib/Semantics/openmp-modifiers.cpp      | 16 ++++++++
 flang/lib/Semantics/resolve-directives.cpp    |  3 +-
 flang/lib/Semantics/resolve-names.cpp         |  3 +-
 .../Parser/OpenMP/enter-automap-modifier.f90  | 16 ++++++++
 llvm/include/llvm/Frontend/OpenMP/ClauseT.h   |  5 ++-
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |  2 +-
 14 files changed, 126 insertions(+), 27 deletions(-)
 create mode 100644 flang/test/Parser/OpenMP/enter-automap-modifier.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 23e35d106c077..69acd31f3753f 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -581,6 +581,8 @@ class ParseTreeDumper {
   NODE(parser, OmpDependClause)
   NODE(OmpDependClause, TaskDep)
   NODE(OmpDependClause::TaskDep, Modifier)
+  NODE(parser, OmpAutomapModifier)
+  NODE_ENUM(OmpAutomapModifier, Value)
   NODE(parser, OmpDetachClause)
   NODE(parser, OmpDoacrossClause)
   NODE(parser, OmpDestroyClause)
@@ -588,6 +590,8 @@ class ParseTreeDumper {
   NODE(parser, OmpEndCriticalDirective)
   NODE(parser, OmpEndLoopDirective)
   NODE(parser, OmpEndSectionsDirective)
+  NODE(parser, OmpEnterClause)
+  NODE(OmpEnterClause, Modifier)
   NODE(parser, OmpFailClause)
   NODE(parser, OmpFromClause)
   NODE(OmpFromClause, Modifier)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 3a28f6f9731c3..c438ed63de798 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3769,6 +3769,16 @@ struct OmpAlwaysModifier {
   WRAPPER_CLASS_BOILERPLATE(OmpAlwaysModifier, Value);
 };
 
+// Ref: [6.0:289-290]
+//
+// automap-modifier ->
+//    automap                                       // since 6.0
+//
+struct OmpAutomapModifier {
+  ENUM_CLASS(Value, Automap);
+  WRAPPER_CLASS_BOILERPLATE(OmpAutomapModifier, Value);
+};
+
 // Ref: [5.2:252-254]
 //
 // chunk-modifier ->
@@ -4350,6 +4360,17 @@ struct OmpDeviceTypeClause {
   WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, DeviceTypeDescription);
 };
 
+// Ref: [5.2:158-159], [6.0:289-290]
+//
+// enter-clause ->
+//    ENTER(locator-list) |
+//    FROM(automap-modifier: locator-list) |         // since 6.0
+struct OmpEnterClause {
+  TUPLE_CLASS_BOILERPLATE(OmpEnterClause);
+  MODIFIER_BOILERPLATE(OmpAutomapModifier);
+  std::tuple<MODIFIERS(), OmpObjectList> t;
+};
+
 // OMP 5.2 15.8.3 extended-atomic, fail-clause ->
 //    FAIL(memory-order)
 struct OmpFailClause {
diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h
index a9fe911ef8807..e0eae984731c7 100644
--- a/flang/include/flang/Semantics/openmp-modifiers.h
+++ b/flang/include/flang/Semantics/openmp-modifiers.h
@@ -72,6 +72,7 @@ DECLARE_DESCRIPTOR(parser::OmpAlignModifier);
 DECLARE_DESCRIPTOR(parser::OmpAllocatorComplexModifier);
 DECLARE_DESCRIPTOR(parser::OmpAllocatorSimpleModifier);
 DECLARE_DESCRIPTOR(parser::OmpAlwaysModifier);
+DECLARE_DESCRIPTOR(parser::OmpAutomapModifier);
 DECLARE_DESCRIPTOR(parser::OmpChunkModifier);
 DECLARE_DESCRIPTOR(parser::OmpCloseModifier);
 DECLARE_DESCRIPTOR(parser::OmpContextSelector);
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 594f95ecdda63..8eabf4f499604 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1519,10 +1519,14 @@ bool ClauseProcessor::processTo(
 bool ClauseProcessor::processEnter(
     llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
   return findRepeatableClause<omp::clause::Enter>(
-      [&](const omp::clause::Enter &clause, const parser::CharBlock &) {
+      [&](const omp::clause::Enter &clause, const parser::CharBlock &source) {
+        mlir::Location currentLocation = converter.genLocation(source);
+        if (std::get<std::optional<omp::clause::Enter::Modifier>>(clause.t))
+          TODO(currentLocation, "Declare target enter AUTOMAP modifier");
         // Case: declare target enter(func, var1, var2)...
-        gatherFuncAndVarSyms(
-            clause.v, mlir::omp::DeclareTargetCaptureClause::enter, result);
+        gatherFuncAndVarSyms(std::get<ObjectList>(clause.t),
+                             mlir::omp::DeclareTargetCaptureClause::enter,
+                             result);
       });
 }
 
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 686fba0154f44..46fed427923da 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -772,8 +772,19 @@ Doacross make(const parser::OmpClause::Doacross &inp,
 
 Enter make(const parser::OmpClause::Enter &inp,
            semantics::SemanticsContext &semaCtx) {
-  // inp.v -> parser::OmpObjectList
-  return Enter{makeObjects(/*List=*/inp.v, semaCtx)};
+  // inp.v -> parser::OmpEnterClause
+  CLAUSET_ENUM_CONVERT(
+        convert, parser::OmpAutomapModifier::Value, Enter::Modifier,
+        // clang-format off
+        MS(Automap, Automap)
+        // clang-format on);
+  );
+  auto &mods = semantics::OmpGetModifiers(inp.v);
+  auto *mod = semantics::OmpGetUniqueModifier<parser::OmpAutomapModifier>(mods);
+  auto &objList = std::get<parser::OmpObjectList>(inp.v.t);
+
+  return Enter{{/*Modifier=*/maybeApplyToV(convert, mod),
+                /*List=*/makeObjects(objList, semaCtx)}};
 }
 
 Exclusive make(const parser::OmpClause::Exclusive &inp,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 1c626148a03ae..7fd51c63eb9d6 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -449,6 +449,9 @@ TYPE_PARSER(construct<OmpAllocatorSimpleModifier>(scalarIntExpr))
 TYPE_PARSER(construct<OmpAlwaysModifier>( //
     "ALWAYS" >> pure(OmpAlwaysModifier::Value::Always)))
 
+TYPE_PARSER(construct<OmpAutomapModifier>(
+    "AUTOMAP" >> pure(OmpAutomapModifier::Value::Automap)))
+
 TYPE_PARSER(construct<OmpChunkModifier>( //
     "SIMD" >> pure(OmpChunkModifier::Value::Simd)))
 
@@ -601,6 +604,13 @@ TYPE_PARSER(sourced(construct<OmpDependClause::TaskDep::Modifier>(sourced(
 TYPE_PARSER(
     sourced(construct<OmpDeviceClause::Modifier>(Parser<OmpDeviceModifier>{})))
 
+TYPE_PARSER(sourced(construct<OmpEnterClause::Modifier>(
+    Parser<OmpAutomapModifier>{})))
+
+TYPE_PARSER(construct<OmpEnterClause>(
+    maybe(nonemptyList(Parser<OmpEnterClause::Modifier>{}) / ":"),
+    Parser<OmpObjectList>{}))
+
 TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(
     sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||
         construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||
@@ -1023,7 +1033,7 @@ TYPE_PARSER( //
     "DYNAMIC_ALLOCATORS" >>
         construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
     "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
-                   parenthesized(Parser<OmpObjectList>{}))) ||
+                   parenthesized(Parser<OmpEnterClause>{}))) ||
     "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(
                        parenthesized(Parser<OmpObjectList>{}))) ||
     "FAIL" >> construct<OmpClause>(construct<OmpClause::Fail>(
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index fc15d46a8c727..3c14e154edc69 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2250,6 +2250,11 @@ class UnparseVisitor {
     Walk(std::get<OmpObjectList>(x.t));
     Walk(": ", std::get<std::optional<std::list<Modifier>>>(x.t));
   }
+  void Unparse(const OmpEnterClause &x) {
+    using Modifier = OmpEnterClause::Modifier;
+    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
+    Walk(std::get<OmpObjectList>(x.t));
+  }
   void Unparse(const OmpFromClause &x) {
     using Modifier = OmpFromClause::Modifier;
     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
@@ -2986,6 +2991,7 @@ class UnparseVisitor {
   WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
   WALK_NESTED_ENUM(OmpAdjustArgsClause::OmpAdjustOp, Value) // OMP adjustop
   WALK_NESTED_ENUM(OmpAtClause, ActionTime) // OMP at
+  WALK_NESTED_ENUM(OmpAutomapModifier, Value) // OMP automap-modifier
   WALK_NESTED_ENUM(OmpBindClause, Binding) // OMP bind
   WALK_NESTED_ENUM(OmpProcBindClause, AffinityPolicy) // OMP proc_bind
   WALK_NESTED_ENUM(OmpDefaultClause, DataSharingAttribute) // OMP default
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index d214d222e7c90..2472ff99f73d4 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1568,9 +1568,10 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &x) {
               },
               [&](const parser::OmpClause::Enter &enterClause) {
                 enterClauseFound = true;
-                CheckSymbolNames(dir.source, enterClause.v);
-                CheckVarIsNotPartOfAnotherVar(dir.source, enterClause.v);
-                CheckThreadprivateOrDeclareTargetVar(enterClause.v);
+                auto &objList{std::get<parser::OmpObjectList>(enterClause.v.t)};
+                CheckSymbolNames(dir.source, objList);
+                CheckVarIsNotPartOfAnotherVar(dir.source, objList);
+                CheckThreadprivateOrDeclareTargetVar(objList);
               },
               [&](const parser::OmpClause::DeviceType &deviceTypeClause) {
                 deviceTypeClauseFound = true;
@@ -2428,8 +2429,8 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
                                                         &objs,
                                                     std::string clause) {
             for (const auto &obj : objs.v) {
-              if (const parser::Name *
-                  objName{parser::Unwrap<parser::Name>(obj)}) {
+              if (const parser::Name *objName{
+                      parser::Unwrap<parser::Name>(obj)}) {
                 if (&objName->symbol->GetUltimate() == eventHandleSym) {
                   context_.Say(GetContext().clauseSource,
                       "A variable: `%s` that appears in a DETACH clause cannot appear on %s clause on the same construct"_err_en_US,
@@ -3000,7 +3001,8 @@ void OmpStructureChecker::CheckReductionModifier(
   if (modifier.v == ReductionModifier::Value::Task) {
     // "Task" is only allowed on worksharing or "parallel" directive.
     static llvm::omp::Directive worksharing[]{
-        llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_scope,
+        llvm::omp::Directive::OMPD_do,
+        llvm::omp::Directive::OMPD_scope,
         llvm::omp::Directive::OMPD_sections,
         // There are more worksharing directives, but they do not apply:
         // "for" is C++ only,
@@ -4028,7 +4030,11 @@ void OmpStructureChecker::Enter(const parser::OmpClause::HasDeviceAddr &x) {
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Enter &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_enter);
-  const parser::OmpObjectList &objList{x.v};
+  if (!OmpVerifyModifiers(
+          x.v, llvm::omp::OMPC_enter, GetContext().clauseSource, context_)) {
+    return;
+  }
+  const parser::OmpObjectList &objList{std::get<parser::OmpObjectList>(x.v.t)};
   SymbolSourceMap symbols;
   GetSymbolsInObjectList(objList, symbols);
   for (const auto &[symbol, source] : symbols) {
@@ -4488,17 +4494,18 @@ const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList(
     const parser::OmpClause &clause) {
 
   // Clauses with OmpObjectList as its data member
-  using MemberObjectListClauses = std::tuple<parser::OmpClause::Copyprivate,
-      parser::OmpClause::Copyin, parser::OmpClause::Enter,
-      parser::OmpClause::Firstprivate, parser::OmpClause::Link,
-      parser::OmpClause::Private, parser::OmpClause::Shared,
-      parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;
+  using MemberObjectListClauses =
+      std::tuple<parser::OmpClause::Copyprivate, parser::OmpClause::Copyin,
+          parser::OmpClause::Firstprivate, parser::OmpClause::Link,
+          parser::OmpClause::Private, parser::OmpClause::Shared,
+          parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;
 
   // Clauses with OmpObjectList in the tuple
-  using TupleObjectListClauses = std::tuple<parser::OmpClause::Aligned,
-      parser::OmpClause::Allocate, parser::OmpClause::From,
-      parser::OmpClause::Lastprivate, parser::OmpClause::Map,
-      parser::OmpClause::Reduction, parser::OmpClause::To>;
+  using TupleObjectListClauses =
+      std::tuple<parser::OmpClause::Aligned, parser::OmpClause::Allocate,
+          parser::OmpClause::From, parser::OmpClause::Lastprivate,
+          parser::OmpClause::Map, parser::OmpClause::Reduction,
+          parser::OmpClause::To, parser::OmpClause::Enter>;
 
   // TODO:: Generate the tuples using TableGen.
   // Handle other constructs with OmpObjectList such as OpenMPThreadprivate.
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index 336ce4beb24ba..af4000c4934ea 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -156,6 +156,22 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlwaysModifier>() {
   return desc;
 }
 
+template <>
+const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAutomapModifier>() {
+  static const OmpModifierDescriptor desc{
+      /*name=*/"automap-modifier",
+      /*props=*/
+      {
+          {60, {OmpProperty::Unique}},
+      },
+      /*clauses=*/
+      {
+          {60, {Clause::OMPC_enter}},
+      },
+  };
+  return desc;
+}
+
 template <>
 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpChunkModifier>() {
   static const OmpModifierDescriptor desc{
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 4c3e509b5a36d..cbd232a884af8 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2152,7 +2152,8 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPDeclareTargetConstruct &x) {
         ResolveOmpObjectList(linkClause->v, Symbol::Flag::OmpDeclareTarget);
       } else if (const auto *enterClause{
                      std::get_if<parser::OmpClause::Enter>(&clause.u)}) {
-        ResolveOmpObjectList(enterClause->v, Symbol::Flag::OmpDeclareTarget);
+        ResolveOmpObjectList(std::get<parser::OmpObjectList>(enterClause->v.t),
+            Symbol::Flag::OmpDeclareTarget);
       }
     }
   }
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index d08c669377cb2..2611470183e96 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1646,7 +1646,8 @@ class OmpVisitor : public virtual DeclarationVisitor {
           populateDeclareTargetNames(linkClause->v);
         } else if (const auto *enterClause{
                        std::get_if<parser::OmpClause::Enter>(&clause.u)}) {
-          populateDeclareTargetNames(enterClause->v);
+          populateDeclareTargetNames(
+              std::get<parser::OmpObjectList>(enterClause->v.t));
         }
       }
     }
diff --git a/flang/test/Parser/OpenMP/enter-automap-modifier.f90 b/flang/test/Parser/OpenMP/enter-automap-modifier.f90
new file mode 100644
index 0000000000000..1f361ca5c2f06
--- /dev/null
+++ b/flang/test/Parser/OpenMP/enter-automap-modifier.f90
@@ -0,0 +1,16 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck %s --check-prefix=UNPARSE
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck %s --check-prefix=PARSE-TREE
+
+program automap
+   integer :: x
+   !$omp declare target enter(automap: x)
+end program
+
+!UNPARSE: PROGRAM AUTOMAP
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP DECLARE TARGET  ENTER(AUTOMAP: x)
+!UNPARSE: END PROGRAM
+
+!PARSE-TREE: OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE-NEXT: | Modifier -> OmpAutomapModifier -> Value = Automap
+!PARSE-TREE-NEXT: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 7919f7a8b0c34..ce1cedc188fbf 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -578,8 +578,9 @@ struct DynamicAllocatorsT {
 template <typename T, typename I, typename E> //
 struct EnterT {
   using List = ObjectListT<I, E>;
-  using WrapperTrait = std::true_type;
-  List v;
+  ENUM(Modifier, Automap);
+  using TupleTrait = std::true_type;
+  std::tuple<OPT(Modifier), List> t;
 };
 
 // V5.2: [5.6.2] `exclusive` clause
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 1b94657dfae1e..f11eccc215bc2 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -179,7 +179,7 @@ def OMPC_DynamicAllocators : Clause<[Spelling<"dynamic_allocators">]> {
   let clangClass = "OMPDynamicAllocatorsClause";
 }
 def OMPC_Enter : Clause<[Spelling<"enter">]> {
-  let flangClass = "OmpObjectList";
+  let flangClass = "OmpEnterClause";
 }
 def OMPC_Exclusive : Clause<[Spelling<"exclusive">]> {
   let clangClass = "OMPExclusiveClause";

>From 7e76c064a8b32bc09a7718d0f63fef80811acaff Mon Sep 17 00:00:00 2001
From: Akash Banerjee <akash.banerjee at amd.com>
Date: Mon, 28 Jul 2025 19:52:48 +0100
Subject: [PATCH 2/2] Fix comment

Co-authored-by: Copilot <175728472+Copilot at users.noreply.github.com>
---
 flang/include/flang/Parser/parse-tree.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index c438ed63de798..a822cae393a3a 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4364,7 +4364,7 @@ struct OmpDeviceTypeClause {
 //
 // enter-clause ->
 //    ENTER(locator-list) |
-//    FROM(automap-modifier: locator-list) |         // since 6.0
+//    ENTER(automap-modifier: locator-list) |         // since 6.0
 struct OmpEnterClause {
   TUPLE_CLASS_BOILERPLATE(OmpEnterClause);
   MODIFIER_BOILERPLATE(OmpAutomapModifier);



More information about the llvm-commits mailing list