[clang] [OpenACC] Implement loop 'gang' clause. (PR #112006)

via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 11 07:50:33 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

The 'gang' clause is used to specify parallel execution of loops, thus has some complicated rules depending on the 'loop's associated compute construct.  This patch implements all of those.

---

Patch is 75.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112006.diff


22 Files Affected:

- (modified) clang/include/clang/AST/OpenACCClause.h (+33-27) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+19) 
- (modified) clang/include/clang/Basic/OpenACCClauses.def (+1) 
- (modified) clang/include/clang/Basic/OpenACCKinds.h (+29) 
- (modified) clang/include/clang/Parse/Parser.h (+9-3) 
- (modified) clang/include/clang/Sema/SemaOpenACC.h (+73-7) 
- (modified) clang/lib/AST/OpenACCClause.cpp (+44-6) 
- (modified) clang/lib/AST/StmtProfile.cpp (+6) 
- (modified) clang/lib/AST/TextNodeDumper.cpp (+11) 
- (modified) clang/lib/Parse/ParseOpenACC.cpp (+35-15) 
- (modified) clang/lib/Sema/SemaOpenACC.cpp (+252-24) 
- (modified) clang/lib/Sema/TreeTransform.h (+23) 
- (modified) clang/lib/Serialization/ASTReader.cpp (+12-1) 
- (modified) clang/lib/Serialization/ASTWriter.cpp (+10-1) 
- (modified) clang/test/AST/ast-print-openacc-loop-construct.cpp (+82) 
- (modified) clang/test/ParserOpenACC/parse-clauses.c (+22-28) 
- (modified) clang/test/SemaOpenACC/compute-construct-device_type-clause.c (+1-2) 
- (modified) clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c (+4-11) 
- (modified) clang/test/SemaOpenACC/loop-construct-device_type-clause.c (-1) 
- (added) clang/test/SemaOpenACC/loop-construct-gang-ast.cpp (+330) 
- (added) clang/test/SemaOpenACC/loop-construct-gang-clause.cpp (+335) 
- (modified) clang/tools/libclang/CIndex.cpp (+5) 


``````````diff
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index b500acc768e55a..f3a09eb651458d 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -119,32 +119,6 @@ class OpenACCSeqClause : public OpenACCClause {
   }
 };
 
-// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
-// this provides a basic, do-nothing implementation. We still need to add this
-// type to the visitors/etc, as well as get it to take its proper arguments.
-class OpenACCGangClause : public OpenACCClause {
-protected:
-  OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc)
-      : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
-    llvm_unreachable("Not yet implemented");
-  }
-
-public:
-  static bool classof(const OpenACCClause *C) {
-    return C->getClauseKind() == OpenACCClauseKind::Gang;
-  }
-
-  static OpenACCGangClause *
-  Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
-
-  child_range children() {
-    return child_range(child_iterator(), child_iterator());
-  }
-  const_child_range children() const {
-    return const_child_range(const_child_iterator(), const_child_iterator());
-  }
-};
-
 // Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
 // this provides a basic, do-nothing implementation. We still need to add this
 // type to the visitors/etc, as well as get it to take its proper arguments.
@@ -177,7 +151,7 @@ class OpenACCVectorClause : public OpenACCClause {
 class OpenACCWorkerClause : public OpenACCClause {
 protected:
   OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc)
-      : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
+      : OpenACCClause(OpenACCClauseKind::Worker, BeginLoc, EndLoc) {
     llvm_unreachable("Not yet implemented");
   }
 
@@ -535,6 +509,38 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
   Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; };
 };
 
+class OpenACCGangClause final
+    : public OpenACCClauseWithExprs,
+      public llvm::TrailingObjects<OpenACCGangClause, Expr *, OpenACCGangKind> {
+protected:
+  OpenACCGangClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                    ArrayRef<OpenACCGangKind> GangKinds,
+                    ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
+
+  OpenACCGangKind getGangKind(unsigned I) const {
+    return getTrailingObjects<OpenACCGangKind>()[I];
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Gang;
+  }
+
+  size_t numTrailingObjects(OverloadToken<Expr *>) const {
+    return getNumExprs();
+  }
+
+  unsigned getNumExprs() const { return getExprs().size(); }
+  std::pair<OpenACCGangKind, const Expr *> getExpr(unsigned I) const {
+    return {getGangKind(I), getExprs()[I]};
+  }
+
+  static OpenACCGangClause *
+  Create(const ASTContext &Ctx, SourceLocation BeginLoc,
+         SourceLocation LParenLoc, ArrayRef<OpenACCGangKind> GangKinds,
+         ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
+};
+
 class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
   OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
                           Expr *IntExpr, SourceLocation EndLoc);
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 41cdd09e971651..3c62a017005e59 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12576,6 +12576,7 @@ def err_acc_duplicate_clause_disallowed
     : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' "
             "directive">;
 def note_acc_previous_clause_here : Note<"previous clause is here">;
+def note_acc_previous_expr_here : Note<"previous expression is here">;
 def err_acc_branch_in_out_compute_construct
     : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
             "OpenACC Compute Construct">;
@@ -12682,6 +12683,24 @@ def err_acc_insufficient_loops
 def err_acc_intervening_code
     : Error<"inner loops must be tightly nested inside a '%0' clause on "
             "a 'loop' construct">;
+def err_acc_gang_multiple_elt
+    : Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
+            "'num'|'dim'|'static'}0 argument">;
+def err_acc_gang_arg_invalid
+    : Error<"'%0' argument on 'gang' clause is not permitted on a%select{n "
+            "orphaned|||}1 'loop' construct %select{|associated with a "
+            "'parallel' compute construct|associated with a 'kernels' compute "
+            "construct|associated with a 'serial' compute construct}1">;
+def err_acc_gang_dim_value
+    : Error<"argument to 'gang' clause dimension must be %select{a constant "
+            "expression|1, 2, or 3: evaluated to %1}0">;
+def err_acc_gang_num_gangs_conflict
+    : Error<"'num' argument to 'gang' clause not allowed on a 'loop' construct "
+            "associated with a 'kernels' construct that has a 'num_gangs' "
+            "clause">;
+def err_acc_gang_inside_gang
+    : Error<"loop with a 'gang' clause may not exist in the region of a 'gang' "
+            "clause on a 'kernels' compute construct">;
 
 // AMDGCN builtins diagnostics
 def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def
index a380e5ae69c418..2a098de31eb618 100644
--- a/clang/include/clang/Basic/OpenACCClauses.def
+++ b/clang/include/clang/Basic/OpenACCClauses.def
@@ -42,6 +42,7 @@ VISIT_CLAUSE(DevicePtr)
 VISIT_CLAUSE(DeviceType)
 CLAUSE_ALIAS(DType, DeviceType, false)
 VISIT_CLAUSE(FirstPrivate)
+VISIT_CLAUSE(Gang)
 VISIT_CLAUSE(If)
 VISIT_CLAUSE(Independent)
 VISIT_CLAUSE(NoCreate)
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index c4dfe3bedc13a7..3f48ebca708a42 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -550,6 +550,35 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
                                      OpenACCReductionOperator Op) {
   return printOpenACCReductionOperator(Out, Op);
 }
+
+enum class OpenACCGangKind : uint8_t {
+  /// num:
+  Num,
+  /// dim:
+  Dim,
+  /// static:
+  Static
+};
+
+template <typename StreamTy>
+inline StreamTy &printOpenACCGangKind(StreamTy &Out, OpenACCGangKind GK) {
+  switch (GK) {
+  case OpenACCGangKind::Num:
+    return Out << "num";
+  case OpenACCGangKind::Dim:
+    return Out << "dim";
+  case OpenACCGangKind::Static:
+    return Out << "static";
+  }
+}
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
+                                             OpenACCGangKind Op) {
+  return printOpenACCGangKind(Out, Op);
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
+                                     OpenACCGangKind Op) {
+  return printOpenACCGangKind(Out, Op);
+}
 } // namespace clang
 
 #endif // LLVM_CLANG_BASIC_OPENACCKINDS_H
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index dbcb545058a026..045ee754a242b3 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3797,9 +3797,15 @@ class Parser : public CodeCompletionHandler {
   bool ParseOpenACCSizeExprList(OpenACCClauseKind CK,
                                 llvm::SmallVectorImpl<Expr *> &SizeExprs);
   /// Parses a 'gang-arg-list', used for the 'gang' clause.
-  bool ParseOpenACCGangArgList(SourceLocation GangLoc);
-  /// Parses a 'gang-arg', used for the 'gang' clause.
-  bool ParseOpenACCGangArg(SourceLocation GangLoc);
+  bool ParseOpenACCGangArgList(SourceLocation GangLoc,
+                               llvm::SmallVectorImpl<OpenACCGangKind> &GKs,
+                               llvm::SmallVectorImpl<Expr *> &IntExprs);
+
+  using OpenACCGangArgRes = std::pair<OpenACCGangKind, ExprResult>;
+  /// Parses a 'gang-arg', used for the 'gang' clause. Returns a pair of the
+  /// ExprResult (which contains the validity of the expression), plus the gang
+  /// kind for the current argument.
+  OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc);
   /// Parses a 'condition' expr, ensuring it results in a
   ExprResult ParseOpenACCConditionExpr();
 
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 97386d2378b758..59a9648d5f9380 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -38,9 +38,20 @@ class SemaOpenACC : public SemaBase {
   /// haven't had their 'parent' compute construct set yet. Entires will only be
   /// made to this list in the case where we know the loop isn't an orphan.
   llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
-  /// Whether we are inside of a compute construct, and should add loops to the
-  /// above collection.
-  bool InsideComputeConstruct = false;
+
+  struct ComputeConstructInfo {
+    /// Which type of compute construct we are inside of, which we can use to
+    /// determine whether we should add loops to the above collection.  We can
+    /// also use it to diagnose loop construct clauses.
+    OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
+    // If we have an active compute construct, stores the list of clauses we've
+    // prepared for it, so that we can diagnose limitations on child constructs.
+    ArrayRef<OpenACCClause *> Clauses;
+  } ActiveComputeConstructInfo;
+
+  bool isInComputeConstruct() const {
+    return ActiveComputeConstructInfo.Kind != OpenACCDirectiveKind::Invalid;
+  }
 
   /// Certain clauses care about the same things that aren't specific to the
   /// individual clause, but can be shared by a few, so store them here. All
@@ -99,6 +110,15 @@ class SemaOpenACC : public SemaBase {
   } TileInfo;
 
 public:
+  ComputeConstructInfo &getActiveComputeConstructInfo() {
+    return ActiveComputeConstructInfo;
+  }
+
+  /// If there is a current 'active' loop construct with a 'gang' clause on a
+  /// 'kernel' construct, this will have the source location for it. This
+  /// permits us to implement the restriction of no further 'gang' clauses.
+  SourceLocation LoopGangClauseOnKernelLoc;
+
   // Redeclaration of the version in OpenACCClause.h.
   using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
 
@@ -149,9 +169,14 @@ class SemaOpenACC : public SemaBase {
       Expr *LoopCount;
     };
 
+    struct GangDetails {
+      SmallVector<OpenACCGangKind> GangKinds;
+      SmallVector<Expr *> IntExprs;
+    };
+
     std::variant<std::monostate, DefaultDetails, ConditionDetails,
                  IntExprDetails, VarListDetails, WaitDetails, DeviceTypeDetails,
-                 ReductionDetails, CollapseDetails>
+                 ReductionDetails, CollapseDetails, GangDetails>
         Details = std::monostate{};
 
   public:
@@ -245,9 +270,18 @@ class SemaOpenACC : public SemaBase {
               ClauseKind == OpenACCClauseKind::NumWorkers ||
               ClauseKind == OpenACCClauseKind::Async ||
               ClauseKind == OpenACCClauseKind::Tile ||
+              ClauseKind == OpenACCClauseKind::Gang ||
               ClauseKind == OpenACCClauseKind::VectorLength) &&
              "Parsed clause kind does not have a int exprs");
 
+      if (ClauseKind == OpenACCClauseKind::Gang) {
+        // There might not be any gang int exprs, as this is an optional
+        // argument.
+        if (std::holds_alternative<std::monostate>(Details))
+          return {};
+        return std::get<GangDetails>(Details).IntExprs;
+      }
+
       return std::get<IntExprDetails>(Details).IntExprs;
     }
 
@@ -259,6 +293,16 @@ class SemaOpenACC : public SemaBase {
       return std::get<ReductionDetails>(Details).Op;
     }
 
+    ArrayRef<OpenACCGangKind> getGangKinds() const {
+      assert(ClauseKind == OpenACCClauseKind::Gang &&
+             "Parsed clause kind does not have gang kind");
+      // The args on gang are optional, so this might not actually hold
+      // anything.
+      if (std::holds_alternative<std::monostate>(Details))
+        return {};
+      return std::get<GangDetails>(Details).GangKinds;
+    }
+
     ArrayRef<Expr *> getVarList() {
       assert((ClauseKind == OpenACCClauseKind::Private ||
               ClauseKind == OpenACCClauseKind::NoCreate ||
@@ -371,6 +415,25 @@ class SemaOpenACC : public SemaBase {
       Details = IntExprDetails{std::move(IntExprs)};
     }
 
+    void setGangDetails(ArrayRef<OpenACCGangKind> GKs,
+                        ArrayRef<Expr *> IntExprs) {
+      assert(ClauseKind == OpenACCClauseKind::Gang &&
+             "Parsed Clause kind does not have gang details");
+      assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?");
+
+      Details = GangDetails{{GKs.begin(), GKs.end()},
+                            {IntExprs.begin(), IntExprs.end()}};
+    }
+
+    void setGangDetails(llvm::SmallVector<OpenACCGangKind> &&GKs,
+                        llvm::SmallVector<Expr *> &&IntExprs) {
+      assert(ClauseKind == OpenACCClauseKind::Gang &&
+             "Parsed Clause kind does not have gang details");
+      assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?");
+
+      Details = GangDetails{std::move(GKs), std::move(IntExprs)};
+    }
+
     void setVarListDetails(ArrayRef<Expr *> VarList, bool IsReadOnly,
                            bool IsZero) {
       assert((ClauseKind == OpenACCClauseKind::Private ||
@@ -545,10 +608,12 @@ class SemaOpenACC : public SemaBase {
                                    SourceLocation RBLoc);
   /// Checks the loop depth value for a collapse clause.
   ExprResult CheckCollapseLoopCount(Expr *LoopCount);
-  /// Checks a single size expr for a tile clause. 'gang' could possibly call
-  /// this, but has slightly stricter rules as to valid values.
+  /// Checks a single size expr for a tile clause.
   ExprResult CheckTileSizeExpr(Expr *SizeExpr);
 
+  // Check a single expression on a gang clause.
+  ExprResult CheckGangExpr(OpenACCGangKind GK, Expr *E);
+
   ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
   ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
 
@@ -595,8 +660,9 @@ class SemaOpenACC : public SemaBase {
   /// Loop needing its parent construct.
   class AssociatedStmtRAII {
     SemaOpenACC &SemaRef;
-    bool WasInsideComputeConstruct;
+    ComputeConstructInfo OldActiveComputeConstructInfo;
     OpenACCDirectiveKind DirKind;
+    SourceLocation OldLoopGangClauseOnKernelLoc;
     llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
     LoopInConstructRAII LoopRAII;
 
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 0b34ed6189593e..6fb8fe0b8cfeef 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -26,7 +26,7 @@ bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) {
   return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) ||
          OpenACCTileClause::classof(C) ||
          OpenACCClauseWithSingleIntExpr::classof(C) ||
-         OpenACCClauseWithVarList::classof(C);
+         OpenACCGangClause::classof(C) || OpenACCClauseWithVarList::classof(C);
 }
 bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) {
   return OpenACCPrivateClause::classof(C) ||
@@ -125,6 +125,21 @@ OpenACCNumWorkersClause::OpenACCNumWorkersClause(SourceLocation BeginLoc,
          "Condition expression type not scalar/dependent");
 }
 
+OpenACCGangClause::OpenACCGangClause(SourceLocation BeginLoc,
+                                     SourceLocation LParenLoc,
+                                     ArrayRef<OpenACCGangKind> GangKinds,
+                                     ArrayRef<Expr *> IntExprs,
+                                     SourceLocation EndLoc)
+    : OpenACCClauseWithExprs(OpenACCClauseKind::Gang, BeginLoc, LParenLoc,
+                             EndLoc) {
+  assert(GangKinds.size() == IntExprs.size() && "Mismatch exprs/kind?");
+  std::uninitialized_copy(IntExprs.begin(), IntExprs.end(),
+                          getTrailingObjects<Expr *>());
+  setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size()));
+  std::uninitialized_copy(GangKinds.begin(), GangKinds.end(),
+                          getTrailingObjects<OpenACCGangKind>());
+}
+
 OpenACCNumWorkersClause *
 OpenACCNumWorkersClause::Create(const ASTContext &C, SourceLocation BeginLoc,
                                 SourceLocation LParenLoc, Expr *IntExpr,
@@ -376,11 +391,16 @@ OpenACCSeqClause *OpenACCSeqClause::Create(const ASTContext &C,
   return new (Mem) OpenACCSeqClause(BeginLoc, EndLoc);
 }
 
-OpenACCGangClause *OpenACCGangClause::Create(const ASTContext &C,
-                                             SourceLocation BeginLoc,
-                                             SourceLocation EndLoc) {
-  void *Mem = C.Allocate(sizeof(OpenACCGangClause));
-  return new (Mem) OpenACCGangClause(BeginLoc, EndLoc);
+OpenACCGangClause *
+OpenACCGangClause::Create(const ASTContext &C, SourceLocation BeginLoc,
+                          SourceLocation LParenLoc,
+                          ArrayRef<OpenACCGangKind> GangKinds,
+                          ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) {
+  void *Mem =
+      C.Allocate(OpenACCGangClause::totalSizeToAlloc<Expr *, OpenACCGangKind>(
+          IntExprs.size(), GangKinds.size()));
+  return new (Mem)
+      OpenACCGangClause(BeginLoc, LParenLoc, GangKinds, IntExprs, EndLoc);
 }
 
 OpenACCWorkerClause *OpenACCWorkerClause::Create(const ASTContext &C,
@@ -600,3 +620,21 @@ void OpenACCClausePrinter::VisitCollapseClause(const OpenACCCollapseClause &C) {
   printExpr(C.getLoopCount());
   OS << ")";
 }
+
+void OpenACCClausePrinter::VisitGangClause(const OpenACCGangClause &C) {
+  OS << "gang";
+
+  if (C.getNumExprs() > 0) {
+    OS << "(";
+    bool first = true;
+    for (unsigned I = 0; I < C.getNumExprs(); ++I) {
+      if (!first)
+        OS << ", ";
+      first = false;
+
+      OS << C.getExpr(I).first << ": ";
+      printExpr(C.getExpr(I).second);
+    }
+    OS << ")";
+  }
+}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 4d177fd6c5968c..6161b1403ed35d 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2646,6 +2646,12 @@ void OpenACCClauseProfiler::VisitIndependentClause(
 
 void OpenACCClauseProfiler::VisitSeqClause(const OpenACCSeqClause &Clause) {}
 
+void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) {
+  for (unsigned I = 0; I < Clause.getNumExprs(); ++I) {
+    Profiler.VisitStmt(Clause.getExpr(I).second);
+  }
+}
+
 void OpenACCClauseProfiler::VisitReductionClause(
     const OpenACCReductionClause &Clause) {
   for (auto *E : Clause.getVarList())
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 15b23d60c3ffab..ac8c196777f9b8 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -425,6 +425,17 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
       // but print 'clause' here so it is clear what is happening from the dump.
       OS << " clause";
       break;
+    case OpenACCClauseKind::Gang: {
+      OS << " clause";
+      // print the list of all GangKinds, so that there is some sort of
+      // relationship to the expressions listed afterwards.
+      auto *GC = cast<OpenACCGangClause>(C);
+
+      for (unsigned I = 0; I < GC->getNumExprs(); ++I) {
+        OS << " " << GC->getExpr(I).first;
+      }
+      break;
+    }
     case OpenACCClauseKind::Collapse:
       OS << " clause";
       if (cast<OpenACCCollapseClause>(C)->hasForce())
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index b27e50b147f4a8..635039b724e6a0 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -797,23 +797,26 @@ bool Parser::ParseOpenACCSizeExprList(
 /// [num:]int-expr
 /// dim:int-expr
 /// static:size-expr
-bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
+Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceL...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/112006


More information about the cfe-commits mailing list