diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -7252,6 +7252,107 @@ } }; +/// 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, + private llvm::TrailingObjects { + 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(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(llvm::omp::OMPC_affinity, + SourceLocation(), SourceLocation(), + SourceLocation(), N) {} + + /// Sets the affinity modifier for the clause, if any. + void setModifier(Expr *E) { + getTrailingObjects()[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 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()[varlist_size()]; } + Expr *getModifier() const { + return getTrailingObjects()[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(varlist_begin()), + reinterpret_cast(varlist_end() + Offset)); + } + + const_child_range children() const { + auto Children = const_cast(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 Ptr, typename RetTy> diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3560,6 +3560,15 @@ return true; } +template +bool RecursiveASTVisitor::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 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10799,6 +10799,12 @@ SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef Data); + /// Called on well-formed 'affinity' clause. + OMPClause *ActOnOpenMPAffinityClause(SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, + ArrayRef Locators); /// The kind of conversion being performed. enum CheckedConversionKind { diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -151,6 +151,7 @@ case OMPC_inclusive: case OMPC_exclusive: case OMPC_uses_allocators: + case OMPC_affinity: break; } @@ -241,6 +242,7 @@ case OMPC_inclusive: case OMPC_exclusive: case OMPC_uses_allocators: + case OMPC_affinity: break; } @@ -1368,6 +1370,25 @@ return new (Mem) OMPUsesAllocatorsClause(N); } +OMPAffinityClause * +OMPAffinityClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, + ArrayRef Locators) { + void *Mem = C.Allocate(totalSizeToAlloc(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(N + 1)); + return new (Mem) OMPAffinityClause(N); +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -1969,6 +1990,21 @@ 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 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -809,6 +809,12 @@ 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 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -175,6 +175,7 @@ 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 @@ 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 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4734,6 +4734,7 @@ 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 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2668,6 +2668,7 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ 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 --- 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 @@ case OMPC_inclusive: case OMPC_exclusive: case OMPC_uses_allocators: + case OMPC_affinity: continue; case OMPC_allocator: case OMPC_flush: @@ -11547,6 +11549,7 @@ 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 @@ case OMPC_inclusive: case OMPC_exclusive: case OMPC_uses_allocators: + case OMPC_affinity: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -12740,6 +12744,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc, NewData); } + +OMPClause *Sema::ActOnOpenMPAffinityClause( + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, ArrayRef Locators) { + SmallVector Vars; + for (Expr *RefExpr : Locators) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa(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(SimpleExpr) && + !isa(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 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2107,6 +2107,19 @@ 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 different behavior. + OMPClause *RebuildOMPAffinityClause(SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, + ArrayRef 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. @@ -9814,6 +9827,28 @@ } template +OMPClause * +TreeTransform::TransformOMPAffinityClause(OMPAffinityClause *C) { + SmallVector 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 OMPClause *TreeTransform::TransformOMPOrderClause(OMPOrderClause *C) { return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(), diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11951,6 +11951,9 @@ 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 @@ 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 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()); C->setLParenLoc(Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6704,6 +6704,15 @@ } } +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 --- /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 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -34,7 +34,7 @@ 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 @@ }; // 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 { S8() {} @@ -101,7 +101,7 @@ 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::TS > 0) priority(argc) +#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S::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 @@ // 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::TS > 0) priority(argc) +// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::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 @@ // 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::TS > 0) priority(argc) +// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::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 @@ // 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::TS > 0) priority(argc) +// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::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 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2508,6 +2508,11 @@ 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 --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -197,6 +197,7 @@ __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, 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)