[clang] 2e499ee - [OPENMP50]Add initial support for 'affinity' clause.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Tue May 19 05:43:51 PDT 2020


Author: Alexey Bataev
Date: 2020-05-19T08:19:09-04:00
New Revision: 2e499eee5884456f3dd068662ee1785f24bd88cc

URL: https://github.com/llvm/llvm-project/commit/2e499eee5884456f3dd068662ee1785f24bd88cc
DIFF: https://github.com/llvm/llvm-project/commit/2e499eee5884456f3dd068662ee1785f24bd88cc.diff

LOG: [OPENMP50]Add initial support for 'affinity' clause.

Summary:
Added parsing/sema/serialization support for affinity clause in task
directives.

Reviewers: jdoerfert

Subscribers: yaxunl, guansong, arphaman, llvm-commits, cfe-commits, caomhin

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D80148

Added: 
    clang/test/OpenMP/task_affinity_messages.cpp

Modified: 
    clang/include/clang/AST/OpenMPClause.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/OpenMPClause.cpp
    clang/lib/AST/StmtProfile.cpp
    clang/lib/Basic/OpenMPKinds.cpp
    clang/lib/CodeGen/CGStmtOpenMP.cpp
    clang/lib/Parse/ParseOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/lib/Sema/TreeTransform.h
    clang/lib/Serialization/ASTReader.cpp
    clang/lib/Serialization/ASTWriter.cpp
    clang/test/OpenMP/task_ast_print.cpp
    clang/tools/libclang/CIndex.cpp
    llvm/include/llvm/Frontend/OpenMP/OMPKinds.def

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 0b49209fb127..54e83f461980 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -7252,6 +7252,107 @@ class OMPUsesAllocatorsClause final
   }
 };
 
+/// This represents clause 'affinity' in the '#pragma omp task'-based
+/// directives.
+///
+/// \code
+/// #pragma omp task affinity(iterator(i = 0:n) : ([3][n])a, b[:n], c[i])
+/// \endcode
+/// In this example directive '#pragma omp task' has clause 'affinity' with the
+/// affinity modifer 'iterator(i = 0:n)' and locator items '([3][n])a', 'b[:n]'
+/// and 'c[i]'.
+class OMPAffinityClause final
+    : public OMPVarListClause<OMPAffinityClause>,
+      private llvm::TrailingObjects<OMPAffinityClause, Expr *> {
+  friend class OMPClauseReader;
+  friend OMPVarListClause;
+  friend TrailingObjects;
+
+  /// Location of ':' symbol.
+  SourceLocation ColonLoc;
+
+  /// Build clause.
+  ///
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param ColonLoc Location of ':'.
+  /// \param EndLoc Ending location of the clause.
+  /// \param N Number of locators asssociated with the clause.
+  OMPAffinityClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+                    SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N)
+      : OMPVarListClause<OMPAffinityClause>(llvm::omp::OMPC_affinity, StartLoc,
+                                            LParenLoc, EndLoc, N) {}
+
+  /// Build an empty clause.
+  /// \param N Number of locators asssociated with the clause.
+  ///
+  explicit OMPAffinityClause(unsigned N)
+      : OMPVarListClause<OMPAffinityClause>(llvm::omp::OMPC_affinity,
+                                            SourceLocation(), SourceLocation(),
+                                            SourceLocation(), N) {}
+
+  /// Sets the affinity modifier for the clause, if any.
+  void setModifier(Expr *E) {
+    getTrailingObjects<Expr *>()[varlist_size()] = E;
+  }
+
+  /// Sets the location of ':' symbol.
+  void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+
+public:
+  /// Creates clause with a modifier a list of locator items.
+  ///
+  /// \param C AST context.
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param ColonLoc Location of ':'.
+  /// \param EndLoc Ending location of the clause.
+  /// \param Locators List of locator items.
+  static OMPAffinityClause *Create(const ASTContext &C, SourceLocation StartLoc,
+                                   SourceLocation LParenLoc,
+                                   SourceLocation ColonLoc,
+                                   SourceLocation EndLoc, Expr *Modifier,
+                                   ArrayRef<Expr *> Locators);
+
+  /// Creates an empty clause with the place for \p N locator items.
+  ///
+  /// \param C AST context.
+  /// \param N The number of locator items.
+  static OMPAffinityClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+  /// Gets affinity modifier.
+  Expr *getModifier() { return getTrailingObjects<Expr *>()[varlist_size()]; }
+  Expr *getModifier() const {
+    return getTrailingObjects<Expr *>()[varlist_size()];
+  }
+
+  /// Gets the location of ':' symbol.
+  SourceLocation getColonLoc() const { return ColonLoc; }
+
+  // Iterators
+  child_range children() {
+    int Offset = getModifier() ? 1 : 0;
+    return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+                       reinterpret_cast<Stmt **>(varlist_end() + Offset));
+  }
+
+  const_child_range children() const {
+    auto Children = const_cast<OMPAffinityClause *>(this)->children();
+    return const_child_range(Children.begin(), Children.end());
+  }
+
+  child_range used_children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+  const_child_range used_children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == llvm::omp::OMPC_affinity;
+  }
+};
+
 /// This class implements a simple visitor for OMPClause
 /// subclasses.
 template<class ImplClass, template <typename> class Ptr, typename RetTy>

diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 015ec8d80e51..a264d1cf24b2 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3560,6 +3560,15 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUsesAllocatorsClause(
   return true;
 }
 
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPAffinityClause(
+    OMPAffinityClause *C) {
+  TRY_TO(TraverseStmt(C->getModifier()));
+  for (Expr *E : C->varlists())
+    TRY_TO(TraverseStmt(E));
+  return true;
+}
+
 // FIXME: look at the following tricky-seeming exprs to see if we
 // need to recurse on anything.  These are ones that have methods
 // returning decls or qualtypes or nestednamespecifier -- though I'm

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 831ea1f6163c..15a3d411237e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10799,6 +10799,12 @@ class Sema final {
                                             SourceLocation LParenLoc,
                                             SourceLocation EndLoc,
                                             ArrayRef<UsesAllocatorsData> Data);
+  /// Called on well-formed 'affinity' clause.
+  OMPClause *ActOnOpenMPAffinityClause(SourceLocation StartLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation ColonLoc,
+                                       SourceLocation EndLoc, Expr *Modifier,
+                                       ArrayRef<Expr *> Locators);
 
   /// The kind of conversion being performed.
   enum CheckedConversionKind {

diff  --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index d4d398f43c9d..14c4c78e5f39 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -151,6 +151,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     break;
   }
 
@@ -241,6 +242,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     break;
   }
 
@@ -1368,6 +1370,25 @@ OMPUsesAllocatorsClause::CreateEmpty(const ASTContext &C, unsigned N) {
   return new (Mem) OMPUsesAllocatorsClause(N);
 }
 
+OMPAffinityClause *
+OMPAffinityClause::Create(const ASTContext &C, SourceLocation StartLoc,
+                          SourceLocation LParenLoc, SourceLocation ColonLoc,
+                          SourceLocation EndLoc, Expr *Modifier,
+                          ArrayRef<Expr *> Locators) {
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Locators.size() + 1));
+  auto *Clause = new (Mem)
+      OMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, Locators.size());
+  Clause->setModifier(Modifier);
+  Clause->setVarRefs(Locators);
+  return Clause;
+}
+
+OMPAffinityClause *OMPAffinityClause::CreateEmpty(const ASTContext &C,
+                                                  unsigned N) {
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + 1));
+  return new (Mem) OMPAffinityClause(N);
+}
+
 //===----------------------------------------------------------------------===//
 //  OpenMP clauses printing methods
 //===----------------------------------------------------------------------===//
@@ -1969,6 +1990,21 @@ void OMPClausePrinter::VisitOMPUsesAllocatorsClause(
   OS << ")";
 }
 
+void OMPClausePrinter::VisitOMPAffinityClause(OMPAffinityClause *Node) {
+  if (Node->varlist_empty())
+    return;
+  OS << "affinity";
+  char StartSym = '(';
+  if (Expr *Modifier = Node->getModifier()) {
+    OS << "(";
+    Modifier->printPretty(OS, nullptr, Policy);
+    OS << " :";
+    StartSym = ' ';
+  }
+  VisitOMPClauseList(Node, StartSym);
+  OS << ")";
+}
+
 void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
                                          VariantMatchInfo &VMI) const {
   for (const OMPTraitSet &Set : Sets) {

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 501c07b9b667..bd2eeb699e65 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -809,6 +809,12 @@ void OMPClauseProfiler::VisitOMPUsesAllocatorsClause(
       Profiler->VisitStmt(D.AllocatorTraits);
   }
 }
+void OMPClauseProfiler::VisitOMPAffinityClause(const OMPAffinityClause *C) {
+  if (const Expr *Modifier = C->getModifier())
+    Profiler->VisitStmt(Modifier);
+  for (const Expr *E : C->varlists())
+    Profiler->VisitStmt(E);
+}
 void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {}
 } // namespace
 

diff  --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 841d76ba27ed..8dddb66fa322 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -175,6 +175,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -422,6 +423,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");

diff  --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index ae3094430fdf..f91098d1d345 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4734,6 +4734,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Clause is not allowed in 'omp atomic'.");
   }
 }

diff  --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 19acfe1158fb..bd40e6b991a5 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2668,6 +2668,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
   case OMPC_nontemporal:
   case OMPC_inclusive:
   case OMPC_exclusive:
+  case OMPC_affinity:
     Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
     break;
   case OMPC_uses_allocators:
@@ -3275,7 +3276,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
                          getOpenMPClauseName(Kind).data()))
     return true;
 
-  bool DependWithIterator = false;
+  bool HasIterator = false;
   bool NeedRParenForLinear = false;
   BalancedDelimiterTracker LinearT(*this, tok::l_paren,
                                   tok::annot_pragma_openmp_end);
@@ -3321,7 +3322,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
         // iterators-definition ]
         // where iterator-specifier is [ iterator-type ] identifier =
         // range-specification
-        DependWithIterator = true;
+        HasIterator = true;
         EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
         ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
         Data.DepModOrTailExpr = IteratorRes.get();
@@ -3440,12 +3441,24 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
           ConsumeToken();
       }
     }
-  } else if (Kind == OMPC_allocate) {
+  } else if (Kind == OMPC_allocate ||
+             (Kind == OMPC_affinity && Tok.is(tok::identifier) &&
+              PP.getSpelling(Tok) == "iterator")) {
     // Handle optional allocator expression followed by colon delimiter.
     ColonProtectionRAIIObject ColonRAII(*this);
     TentativeParsingAction TPA(*this);
-    ExprResult Tail =
-        Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+    // OpenMP 5.0, 2.10.1, task Construct.
+    // where aff-modifier is one of the following:
+    // iterator(iterators-definition)
+    ExprResult Tail;
+    if (Kind == OMPC_allocate) {
+      Tail = ParseAssignmentExpression();
+    } else {
+      HasIterator = true;
+      EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+      Tail = ParseOpenMPIteratorsExpr();
+    }
+    Tail = Actions.CorrectDelayedTyposInExpr(Tail);
     Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),
                                        /*DiscardedValue=*/false);
     if (Tail.isUsable()) {
@@ -3454,8 +3467,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
         Data.ColonLoc = ConsumeToken();
         TPA.Commit();
       } else {
-        // colon not found, no allocator specified, parse only list of
-        // variables.
+        // Colon not found, parse only list of variables.
         TPA.Revert();
       }
     } else {
@@ -3524,7 +3536,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
   if (!T.consumeClose())
     Data.RLoc = T.getCloseLocation();
   // Exit from scope when the iterator is used in depend clause.
-  if (DependWithIterator)
+  if (HasIterator)
     ExitScope();
   return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
          (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId ||

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index e03b926bc581..b62fb26f8b49 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/StmtVisitor.h"
@@ -5414,6 +5415,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
       case OMPC_inclusive:
       case OMPC_exclusive:
       case OMPC_uses_allocators:
+      case OMPC_affinity:
         continue;
       case OMPC_allocator:
       case OMPC_flush:
@@ -11547,6 +11549,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -12301,6 +12304,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Unexpected OpenMP clause.");
   }
   return CaptureRegion;
@@ -12740,6 +12744,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -12966,6 +12971,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -13199,6 +13205,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
   case OMPC_inclusive:
   case OMPC_exclusive:
   case OMPC_uses_allocators:
+  case OMPC_affinity:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -13415,6 +13422,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
   case OMPC_exclusive:
     Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
     break;
+  case OMPC_affinity:
+    Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
+                                    DepModOrTailExpr, VarList);
+    break;
   case OMPC_if:
   case OMPC_depobj:
   case OMPC_final:
@@ -18785,3 +18796,42 @@ OMPClause *Sema::ActOnOpenMPUsesAllocatorClause(
   return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc,
                                          NewData);
 }
+
+OMPClause *Sema::ActOnOpenMPAffinityClause(
+    SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
+    SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) {
+  SmallVector<Expr *, 8> Vars;
+  for (Expr *RefExpr : Locators) {
+    assert(RefExpr && "NULL expr in OpenMP shared clause.");
+    if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) {
+      // It will be analyzed later.
+      Vars.push_back(RefExpr);
+      continue;
+    }
+
+    SourceLocation ELoc = RefExpr->getExprLoc();
+    Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts();
+
+    if (!SimpleExpr->isLValue()) {
+      Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+          << 1 << 0 << RefExpr->getSourceRange();
+      continue;
+    }
+
+    ExprResult Res;
+    {
+      Sema::TentativeAnalysisScope Trap(*this);
+      Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr);
+    }
+    if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+        !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+      Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+          << 1 << 0 << RefExpr->getSourceRange();
+      continue;
+    }
+    Vars.push_back(SimpleExpr);
+  }
+
+  return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
+                                   EndLoc, Modifier, Vars);
+}

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f8b84c292881..923792fde7fc 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2107,6 +2107,19 @@ class TreeTransform {
                                                     Data);
   }
 
+  /// Build a new OpenMP 'affinity' clause.
+  ///
+  /// By default, performs semantic analysis to build the new OpenMP clause.
+  /// Subclasses may override this routine to provide 
diff erent behavior.
+  OMPClause *RebuildOMPAffinityClause(SourceLocation StartLoc,
+                                      SourceLocation LParenLoc,
+                                      SourceLocation ColonLoc,
+                                      SourceLocation EndLoc, Expr *Modifier,
+                                      ArrayRef<Expr *> Locators) {
+    return getSema().ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc,
+                                               EndLoc, Modifier, Locators);
+  }
+
   /// Build a new OpenMP 'order' clause.
   ///
   /// By default, performs semantic analysis to build the new OpenMP clause.
@@ -9813,6 +9826,28 @@ OMPClause *TreeTransform<Derived>::TransformOMPUsesAllocatorsClause(
       Data, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
 }
 
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) {
+  SmallVector<Expr *, 4> Locators;
+  Locators.reserve(C->varlist_size());
+  ExprResult ModifierRes;
+  if (Expr *Modifier = C->getModifier()) {
+    ModifierRes = getDerived().TransformExpr(Modifier);
+    if (ModifierRes.isInvalid())
+      return nullptr;
+  }
+  for (Expr *E : C->varlists()) {
+    ExprResult Locator = getDerived().TransformExpr(E);
+    if (Locator.isInvalid())
+      continue;
+    Locators.push_back(Locator.get());
+  }
+  return getDerived().RebuildOMPAffinityClause(
+      C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(),
+      ModifierRes.get(), Locators);
+}
+
 template <typename Derived>
 OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
   return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(),

diff  --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 3f4164690c78..16bcb18f4e68 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11951,6 +11951,9 @@ OMPClause *OMPClauseReader::readClause() {
   case llvm::omp::OMPC_uses_allocators:
     C = OMPUsesAllocatorsClause::CreateEmpty(Context, Record.readInt());
     break;
+  case llvm::omp::OMPC_affinity:
+    C = OMPAffinityClause::CreateEmpty(Context, Record.readInt());
+    break;
 #define OMP_CLAUSE_NO_CLASS(Enum, Str)                                         \
   case llvm::omp::Enum:                                                        \
     break;
@@ -12794,6 +12797,18 @@ void OMPClauseReader::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) {
   C->setAllocatorsData(Data);
 }
 
+void OMPClauseReader::VisitOMPAffinityClause(OMPAffinityClause *C) {
+  C->setLParenLoc(Record.readSourceLocation());
+  C->setModifier(Record.readSubExpr());
+  C->setColonLoc(Record.readSourceLocation());
+  unsigned NumOfLocators = C->varlist_size();
+  SmallVector<Expr *, 4> Locators;
+  Locators.reserve(NumOfLocators);
+  for (unsigned I = 0; I != NumOfLocators; ++I)
+    Locators.push_back(Record.readSubExpr());
+  C->setVarRefs(Locators);
+}
+
 void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) {
   C->setKind(Record.readEnum<OpenMPOrderClauseKind>());
   C->setLParenLoc(Record.readSourceLocation());

diff  --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index bd7cbfc2a50e..1e3adb588da2 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -6704,6 +6704,15 @@ void OMPClauseWriter::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) {
   }
 }
 
+void OMPClauseWriter::VisitOMPAffinityClause(OMPAffinityClause *C) {
+  Record.push_back(C->varlist_size());
+  Record.AddSourceLocation(C->getLParenLoc());
+  Record.AddStmt(C->getModifier());
+  Record.AddSourceLocation(C->getColonLoc());
+  for (Expr *E : C->varlists())
+    Record.AddStmt(E);
+}
+
 void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) {
   writeUInt32(TI->Sets.size());
   for (const auto &Set : TI->Sets) {

diff  --git a/clang/test/OpenMP/task_affinity_messages.cpp b/clang/test/OpenMP/task_affinity_messages.cpp
new file mode 100644
index 000000000000..34ec8d2e1e14
--- /dev/null
+++ b/clang/test/OpenMP/task_affinity_messages.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -verify -fopenmp-version=50 -fopenmp -ferror-limit 100 -o - -std=c++11 %s
+
+// RUN: %clang_cc1 -verify -fopenmp-version=50 -fopenmp-simd -ferror-limit 100 -o - -std=c++11 %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+  return argc;
+}
+
+struct S1; // expected-note {{declared here}}
+
+class vector {
+  public:
+    int operator[](int index) { return 0; }
+};
+
+int main(int argc, char **argv, char *env[]) {
+  vector vec;
+  typedef float V __attribute__((vector_size(16)));
+  V a;
+  auto arr = x; // expected-error {{use of undeclared identifier 'x'}}
+
+  #pragma omp task affinity(arr[0])
+  #pragma omp task affinity // expected-error {{expected '(' after 'affinity'}}
+  #pragma omp task affinity ( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+  #pragma omp task affinity () // expected-error {{expected expression}}
+  #pragma omp task affinity (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
+  #pragma omp task affinity (foobool(argc)), affinity (in, argc) // expected-error {{expected addressable lvalue expression, array element, array section or array shaping expression}} expected-error {{use of undeclared identifier 'in'}}
+  #pragma omp task affinity (S1) // expected-error {{'S1' does not refer to a value}}
+  #pragma omp task affinity(argv[1][1] = '2')
+  #pragma omp task affinity (vec[1]) // expected-error {{expected addressable lvalue expression, array element, array section or array shaping expression}}
+  #pragma omp task affinity (in: argv[0]) // expected-error {{use of undeclared identifier 'in'}}
+  #pragma omp task affinity (main)
+  #pragma omp task affinity(a[0]) // expected-error {{expected addressable lvalue expression, array element, array section or array shaping expression}}
+  #pragma omp task affinity (vec[1:2]) // expected-error {{ value is not an array or pointer}}
+  #pragma omp task affinity (argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argv[:] // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argv[argc: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argv[argc:argc] // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task affinity (argv[0:-1]) // expected-error {{section length is evaluated to a negative value -1}}
+  #pragma omp task affinity (argv[-1:0])
+  #pragma omp task affinity (argv[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
+  #pragma omp task affinity (argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
+  #pragma omp task affinity(a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
+  #pragma omp task affinity(argv[argv[:2]:1]) // expected-error {{OpenMP array section is not allowed here}}
+  #pragma omp task affinity(argv[0:][:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
+  #pragma omp task affinity(env[0:][:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is an array of unknown bound}}
+  #pragma omp task affinity(argv[ : argc][1 : argc - 1])
+  #pragma omp task affinity(arr[0])
+  #pragma omp task affinity(([ // expected-error {{expected variable name or 'this' in lambda capture list}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task affinity(([] // expected-error {{expected body of lambda expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task affinity(([]) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2 {{expected expression}}
+  #pragma omp task affinity(([])a // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+  #pragma omp task affinity(([])a) // expected-error {{expected expression}}
+  #pragma omp task affinity(([a])a) // expected-error {{expected expression with a pointer to a complete type as a base of an array shaping operation}}
+  #pragma omp task affinity(([a])argc) // expected-error {{expected expression with a pointer to a complete type as a base of an array shaping operation}}
+  #pragma omp task affinity(([-1][0])argv) // expected-error {{array shaping dimension is evaluated to a non-positive value -1}} expected-error {{array shaping dimension is evaluated to a non-positive value 0}}
+  #pragma omp task affinity(iterator // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected '(' after 'iterator'}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator():argc)
+  #pragma omp task affinity(iterator(argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown type name 'argc'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator(unsigned argc: // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected '=' in iterator specifier}} expected-error 2 {{expected expression}} expected-error {{expected ',' or ')' after iterator specifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator(unsigned argc = // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2 {{expected expression}} expected-error {{expected ',' or ')' after iterator specifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator(vector argc = 0:2):argc) // expected-error {{expected integral or pointer type as the iterator-type, not 'vector'}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator(vector *argc = nullptr:nullptr+2:0):argc) // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}} expected-error {{iterator step expression 0 evaluates to 0}} expected-error {{expected expression}}
+  #pragma omp task affinity(iterator(vector *argc = 0:vector():argc):argc) // expected-error {{converting 'vector' to incompatible type 'vector *'}} expected-error {{expected expression}}
+  foo();
+#pragma omp task affinity(iterator(i = 0:10, i = 0:10) : argv[i]) // expected-error {{redefinition of 'i'}} expected-note {{previous definition is here}}
+  i = 0; // expected-error {{use of undeclared identifier 'i'}}
+
+  return 0;
+}

diff  --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp
index cc569a6aab84..b58dd02b9891 100644
--- a/clang/test/OpenMP/task_ast_print.cpp
+++ b/clang/test/OpenMP/task_ast_print.cpp
@@ -34,7 +34,7 @@ class S7 : public T {
     omp_depend_t x;
     omp_event_handle_t evt;
 #pragma omp taskgroup allocate(b) task_reduction(+:b)
-#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) detach(evt) depend(iterator(i=0:10:1, T *k = &a:&b), in: c[i], d[(int)(k-&a)])
+#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) detach(evt) depend(iterator(i=0:10:1, T *k = &a:&b), in: c[i], d[(int)(k-&a)]) affinity(iterator(i=0:10:1, T *k = &a:&b): c[i], d[(int)(k-&a)])
     for (int k = 0; k < a.a; ++k)
       ++this->a.a;
   }
@@ -47,9 +47,9 @@ class S7 : public T {
 };
 
 // CHECK: #pragma omp taskgroup allocate(this->b) task_reduction(+: this->b)
-// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10:1, T * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)]){{$}}
+// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10:1, T * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)]) affinity(iterator(int i = 0:10:1, T * k = &this->a:&this->b) : this->c[i],this->d[(int)(k - &this->a)]){{$}}
 // CHECK: #pragma omp task private(this->a) private(this->a)
-// CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10:1, S1 * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)])
+// CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt) depend(iterator(int i = 0:10:1, S1 * k = &this->a:&this->b), in : this->c[i],this->d[(int)(k - &this->a)]) affinity(iterator(int i = 0:10:1, S1 * k = &this->a:&this->b) : this->c[i],this->d[(int)(k - &this->a)])
 
 class S8 : public S7<S1> {
   S8() {}
@@ -101,7 +101,7 @@ T tmain(T argc, T *argv) {
   omp_event_handle_t evt;
 #pragma omp task untied depend(in : argc, argv[b:argc], arr[:], ([argc][sizeof(T)])argv) if (task : argc > 0) depend(depobj: x) detach(evt)
   a = 2;
-#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) priority(argc)
+#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) priority(argc) affinity(argc, argv[b:argc], arr[:], ([argc][sizeof(T)])argv)
   foo();
 #pragma omp taskgroup task_reduction(-: argc)
 #pragma omp task if (C) mergeable priority(C) in_reduction(-: argc)
@@ -118,7 +118,7 @@ T tmain(T argc, T *argv) {
 // CHECK-NEXT: omp_event_handle_t evt;
 // CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(T)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
 // CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) priority(argc)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) priority(argc) affinity(argc,argv[b:argc],arr[:],([argc][sizeof(T)])argv)
 // CHECK-NEXT: foo()
 // CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
 // CHECK-NEXT: #pragma omp task if(C) mergeable priority(C) in_reduction(-: argc)
@@ -132,7 +132,7 @@ T tmain(T argc, T *argv) {
 // CHECK-NEXT: omp_event_handle_t evt;
 // CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(int)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
 // CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) priority(argc)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) priority(argc) affinity(argc,argv[b:argc],arr[:],([argc][sizeof(int)])argv)
 // CHECK-NEXT: foo()
 // CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
 // CHECK-NEXT: #pragma omp task if(5) mergeable priority(5) in_reduction(-: argc)
@@ -146,7 +146,7 @@ T tmain(T argc, T *argv) {
 // CHECK-NEXT: omp_event_handle_t evt;
 // CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:],([argc][sizeof(long)])argv) if(task: argc > 0) depend(depobj : x) detach(evt)
 // CHECK-NEXT: a = 2;
-// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) priority(argc)
+// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) priority(argc) affinity(argc,argv[b:argc],arr[:],([argc][sizeof(long)])argv)
 // CHECK-NEXT: foo()
 // CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
 // CHECK-NEXT: #pragma omp task if(1) mergeable priority(1) in_reduction(-: argc)

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 589d38fa615a..79a970c229dd 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2508,6 +2508,11 @@ void OMPClauseEnqueue::VisitOMPUsesAllocatorsClause(
     Visitor->AddStmt(D.AllocatorTraits);
   }
 }
+void OMPClauseEnqueue::VisitOMPAffinityClause(const OMPAffinityClause *C) {
+  Visitor->AddStmt(C->getModifier());
+  for (const Expr *E : C->varlists())
+    Visitor->AddStmt(E);
+}
 } // namespace
 
 void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
index 8677b38a9afb..e16e7c6ad1f9 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
@@ -197,6 +197,7 @@ __OMP_CLAUSE(detach, OMPDetachClause)
 __OMP_CLAUSE(inclusive, OMPInclusiveClause)
 __OMP_CLAUSE(exclusive, OMPExclusiveClause)
 __OMP_CLAUSE(uses_allocators, OMPUsesAllocatorsClause)
+__OMP_CLAUSE(affinity, OMPAffinityClause)
 
 __OMP_CLAUSE_NO_CLASS(uniform)
 __OMP_CLAUSE_NO_CLASS(device_type)
@@ -865,6 +866,7 @@ __OMP_DIRECTIVE_CLAUSE(task, 1, ~0, priority)
 __OMP_DIRECTIVE_CLAUSE(task, 1, ~0, in_reduction)
 __OMP_DIRECTIVE_CLAUSE(task, 1, ~0, allocate)
 __OMP_DIRECTIVE_CLAUSE(task, 50, ~0, detach)
+__OMP_DIRECTIVE_CLAUSE(task, 50, ~0, affinity)
 
 __OMP_DIRECTIVE_CLAUSE(atomic, 1, ~0, read)
 __OMP_DIRECTIVE_CLAUSE(atomic, 1, ~0, write)


        


More information about the cfe-commits mailing list