Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2380,6 +2380,12 @@ } template +bool +DataRecursiveASTVisitor::VisitOMPProcBindClause(OMPProcBindClause *C) { + return true; +} + +template template void DataRecursiveASTVisitor::VisitOMPClauseList(T *Node) { for (auto *I : Node->varlists()) Index: include/clang/AST/OpenMPClause.h =================================================================== --- include/clang/AST/OpenMPClause.h +++ include/clang/AST/OpenMPClause.h @@ -375,6 +375,76 @@ StmtRange children() { return StmtRange(); } }; +/// \brief This represents 'proc_bind' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel proc_bind(master) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'proc_bind' +/// clause with kind 'master'. +/// +class OMPProcBindClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'proc_bind' clause. + OpenMPProcBindClauseKind Kind; + /// \brief Start location of the kind in source code. + SourceLocation KindKwLoc; + + /// \brief Set kind of the clause. + /// + /// \param K Kind of clause. + /// + void setProcBindKind(OpenMPProcBindClauseKind K) { Kind = K; } + + /// \brief Set clause kind location. + /// + /// \param KLoc Kind location. + /// + void setProcBindKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } + +public: + /// \brief Build 'proc_bind' clause with argument \a A ('master', 'close' or + /// 'spread'). + /// + /// \param A Argument of the clause ('master', 'close' or 'spread'). + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPProcBindClause(OpenMPProcBindClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_proc_bind, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(A), KindKwLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + OMPProcBindClause() + : OMPClause(OMPC_proc_bind, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Kind(OMPC_PROC_BIND_unknown), + KindKwLoc(SourceLocation()) {} + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns kind of the clause. + OpenMPProcBindClauseKind getProcBindKind() const { return Kind; } + + /// \brief Returns location of clause kind. + SourceLocation getProcBindKindKwLoc() const { return KindKwLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_proc_bind; + } + + StmtRange children() { return StmtRange(); } +}; + /// \brief This represents clause 'private' in the '#pragma omp ...' directives. /// /// \code Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2417,6 +2417,11 @@ } template +bool RecursiveASTVisitor::VisitOMPProcBindClause(OMPProcBindClause *C) { + return true; +} + +template template void RecursiveASTVisitor::VisitOMPClauseList(T *Node) { for (auto *I : Node->varlists()) Index: include/clang/Basic/OpenMPKinds.h =================================================================== --- include/clang/Basic/OpenMPKinds.h +++ include/clang/Basic/OpenMPKinds.h @@ -47,6 +47,14 @@ NUM_OPENMP_DEFAULT_KINDS }; +/// \brief OpenMP attributes for 'proc_bind' clause. +enum OpenMPProcBindClauseKind { +#define OPENMP_PROC_BIND_KIND(Name) \ + OMPC_PROC_BIND_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_PROC_BIND_unknown +}; + OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); Index: include/clang/Basic/OpenMPKinds.def =================================================================== --- include/clang/Basic/OpenMPKinds.def +++ include/clang/Basic/OpenMPKinds.def @@ -27,6 +27,9 @@ #ifndef OPENMP_DEFAULT_KIND # define OPENMP_DEFAULT_KIND(Name) #endif +#ifndef OPENMP_PROC_BIND_KIND +# define OPENMP_PROC_BIND_KIND(Name) +#endif // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) @@ -44,11 +47,13 @@ OPENMP_CLAUSE(shared, OMPSharedClause) OPENMP_CLAUSE(linear, OMPLinearClause) OPENMP_CLAUSE(copyin, OMPCopyinClause) +OPENMP_CLAUSE(proc_bind, OMPProcBindClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) OPENMP_PARALLEL_CLAUSE(num_threads) OPENMP_PARALLEL_CLAUSE(default) +OPENMP_PARALLEL_CLAUSE(proc_bind) OPENMP_PARALLEL_CLAUSE(private) OPENMP_PARALLEL_CLAUSE(firstprivate) OPENMP_PARALLEL_CLAUSE(shared) @@ -63,6 +68,12 @@ OPENMP_DEFAULT_KIND(none) OPENMP_DEFAULT_KIND(shared) +// Static attributes for 'proc_bind' clause. +OPENMP_PROC_BIND_KIND(master) +OPENMP_PROC_BIND_KIND(close) +OPENMP_PROC_BIND_KIND(spread) + +#undef OPENMP_PROC_BIND_KIND #undef OPENMP_DEFAULT_KIND #undef OPENMP_DIRECTIVE #undef OPENMP_CLAUSE Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7289,6 +7289,12 @@ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'proc_bind' clause. + OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef Vars, Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -625,6 +625,12 @@ << ")"; } +void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) { + OS << "proc_bind(" + << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getProcBindKind()) + << ")"; +} + template void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { for (typename T::varlist_iterator I = Node->varlist_begin(), Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -281,6 +281,8 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } +void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { } + template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { for (auto *I : Node->varlists()) Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -75,6 +75,12 @@ .Case(#Name, OMPC_DEFAULT_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEFAULT_unknown); + case OMPC_proc_bind: + return llvm::StringSwitch(Str) +#define OPENMP_PROC_BIND_KIND(Name) \ + .Case(#Name, OMPC_PROC_BIND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_PROC_BIND_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -103,6 +109,15 @@ #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'default' clause type"); + case OMPC_proc_bind: + switch (Type) { + case OMPC_PROC_BIND_unknown: + return "unknown"; +#define OPENMP_PROC_BIND_KIND(Name) \ + case OMPC_PROC_BIND_##Name : return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'proc_bind' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -288,9 +288,12 @@ Clause = ParseOpenMPSingleExprClause(CKind); break; case OMPC_default: + case OMPC_proc_bind: // OpenMP [2.14.3.1, Restrictions] // Only a single default clause may be specified on a parallel, task or // teams directive. + // OpenMP [2.5, parallel Construct, Restrictions] + // At most one proc_bind clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); @@ -355,11 +358,14 @@ T.getCloseLocation()); } -/// \brief Parsing of simple OpenMP clauses like 'default'. +/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: /// 'default' '(' 'none' | 'shared' ') /// +/// proc_bind-clause: +/// 'proc_bind' '(' 'master' | 'close' | 'spread' ') +/// OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); SourceLocation LOpen = ConsumeToken(); @@ -369,9 +375,9 @@ getOpenMPClauseName(Kind))) return 0; - unsigned Type = Tok.isAnnotation() ? - unsigned(OMPC_DEFAULT_unknown) : - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + unsigned Type = + getOpenMPSimpleClauseType(Kind, + Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); SourceLocation TypeLoc = Tok.getLocation(); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -772,6 +772,7 @@ Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_default: + case OMPC_proc_bind: case OMPC_private: case OMPC_firstprivate: case OMPC_shared: @@ -925,6 +926,11 @@ ActOnOpenMPDefaultClause(static_cast(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; + case OMPC_proc_bind: + Res = + ActOnOpenMPProcBindClause(static_cast(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_num_threads: case OMPC_safelen: @@ -987,6 +993,37 @@ EndLoc); } +OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_PROC_BIND_unknown) { + std::string Values; + std::string Sep(", "); + for (unsigned i = 0; i < OMPC_PROC_BIND_unknown; ++i) { + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i); + Values += "'"; + switch (i) { + case OMPC_PROC_BIND_unknown - 2: + Values += " or "; + break; + case OMPC_PROC_BIND_unknown - 1: + break; + default: + Values += Sep; + break; + } + } + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_proc_bind); + return 0; + } + return new (Context) OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef VarList, Expr *TailExpr, @@ -1016,6 +1053,7 @@ case OMPC_num_threads: case OMPC_safelen: case OMPC_default: + case OMPC_proc_bind: case OMPC_threadprivate: case OMPC_unknown: case NUM_OPENMP_CLAUSES: Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1346,6 +1346,19 @@ StartLoc, LParenLoc, EndLoc); } + /// \brief Build a new OpenMP 'proc_bind' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPProcBindClause(Kind, KindKwLoc, + StartLoc, LParenLoc, EndLoc); + } + /// \brief Build a new OpenMP 'private' clause. /// /// By default, performs semantic analysis to build the new statement. @@ -6397,6 +6410,16 @@ template OMPClause * +TreeTransform::TransformOMPProcBindClause(OMPProcBindClause *C) { + return getDerived().RebuildOMPProcBindClause(C->getProcBindKind(), + C->getProcBindKindKwLoc(), + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + +template +OMPClause * TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1683,6 +1683,9 @@ case OMPC_default: C = new (Context) OMPDefaultClause(); break; + case OMPC_proc_bind: + C = new (Context) OMPProcBindClause(); + break; case OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); break; @@ -1728,6 +1731,13 @@ C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx)); } +void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { + C->setProcBindKind( + static_cast(Record[Idx++])); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setProcBindKindKwLoc(Reader->ReadSourceLocation(Record, Idx)); +} + void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1695,6 +1695,12 @@ Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record); } +void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { + Record.push_back(C->getProcBindKind()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Writer->Writer.AddSourceLocation(C->getProcBindKindKwLoc(), Record); +} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); Index: test/OpenMP/parallel_ast_print.cpp =================================================================== --- test/OpenMP/parallel_ast_print.cpp +++ test/OpenMP/parallel_ast_print.cpp @@ -35,9 +35,9 @@ S s; #pragma omp parallel a=2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S::TS) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S::TS) proc_bind(master) foo(); -#pragma omp parallel if (C) num_threads(s) +#pragma omp parallel if (C) num_threads(s) proc_bind(close) foo(); return 0; } @@ -48,9 +48,9 @@ // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S::TS) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S::TS) proc_bind(master) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) // CHECK-NEXT: foo() // CHECK: template long tmain(long argc, long *argv) { // CHECK-NEXT: long b = argc, c, d, e, f, g; @@ -58,9 +58,9 @@ // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S::TS) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S::TS) proc_bind(master) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) // CHECK-NEXT: foo() // CHECK: template T tmain(T argc, T *argv) { // CHECK-NEXT: T b = argc, c, d, e, f, g; @@ -68,9 +68,9 @@ // CHECK-NEXT: S s; // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: a = 2; -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S::TS) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S::TS) proc_bind(master) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) // CHECK-NEXT: foo() enum Enum { }; @@ -86,8 +86,8 @@ // CHECK-NEXT: #pragma omp parallel a=2; // CHECK-NEXT: a = 2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) proc_bind(spread) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) proc_bind(spread) foo(); // CHECK-NEXT: foo(); return tmain(b, &b) + tmain(x, &x); Index: test/OpenMP/parallel_proc_bind_messages.cpp =================================================================== --- test/OpenMP/parallel_proc_bind_messages.cpp +++ test/OpenMP/parallel_proc_bind_messages.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp parallel proc_bind // expected-error {{expected '(' after 'proc_bind'}} + #pragma omp parallel proc_bind ( // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel proc_bind () // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} + #pragma omp parallel proc_bind (master // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel proc_bind (close), proc_bind(spread) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'proc_bind' clause}} + #pragma omp parallel proc_bind (x) // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} + foo(); + + #pragma omp parallel proc_bind(master) + ++argc; + + #pragma omp parallel proc_bind(close) + #pragma omp parallel proc_bind(spread) + ++argc; + return 0; +} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -1937,6 +1937,8 @@ void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { } +void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) { } + template void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { for (const auto *I : Node->varlists())