From f98b00c33e83cb507c21107e8c56961a4b043509 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 23 Jul 2014 02:27:21 +0000 Subject: [PATCH] [OPENMP] Initial parsing and sema analysis for 'read' clause in 'atomic' directive. llvm-svn: 213717 --- clang/include/clang/AST/DataRecursiveASTVisitor.h | 5 +++ clang/include/clang/AST/OpenMPClause.h | 28 ++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 5 +++ clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/include/clang/Basic/OpenMPKinds.def | 4 ++ clang/include/clang/Sema/Sema.h | 3 ++ clang/lib/AST/StmtPrinter.cpp | 2 + clang/lib/AST/StmtProfile.cpp | 2 + clang/lib/Basic/OpenMPKinds.cpp | 2 + clang/lib/Parse/ParseOpenMP.cpp | 6 ++- clang/lib/Sema/SemaOpenMP.cpp | 46 +++++++++++++++++++++-- clang/lib/Sema/TreeTransform.h | 6 +++ clang/lib/Serialization/ASTReaderStmt.cpp | 5 +++ clang/lib/Serialization/ASTWriterStmt.cpp | 2 + clang/test/OpenMP/atomic_ast_print.cpp | 10 +++++ clang/test/OpenMP/atomic_messages.cpp | 37 +++++++++++++++--- clang/tools/libclang/CIndex.cpp | 2 + 17 files changed, 158 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/AST/DataRecursiveASTVisitor.h b/clang/include/clang/AST/DataRecursiveASTVisitor.h index 28fb848..579d24c 100644 --- a/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -2421,6 +2421,11 @@ RecursiveASTVisitor::VisitOMPMergeableClause(OMPMergeableClause *) { } template +bool RecursiveASTVisitor::VisitOMPReadClause(OMPReadClause *) { + return true; +} + +template template bool RecursiveASTVisitor::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 3345959..08b1379 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -770,6 +770,34 @@ public: StmtRange children() { return StmtRange(); } }; +/// \brief This represents 'read' clause in the '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic read +/// \endcode +/// In this example directive '#pragma omp atomic' has 'read' clause. +/// +class OMPReadClause : public OMPClause { +public: + /// \brief Build 'read' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_read, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + OMPReadClause() : OMPClause(OMPC_read, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_read; + } + + StmtRange children() { return StmtRange(); } +}; + /// \brief This represents clause 'private' in the '#pragma omp ...' directives. /// /// \code diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index e3f6819..cef019b 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2443,6 +2443,11 @@ RecursiveASTVisitor::VisitOMPMergeableClause(OMPMergeableClause *) { } template +bool RecursiveASTVisitor::VisitOMPReadClause(OMPReadClause *) { + return true; +} + +template template bool RecursiveASTVisitor::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7e6b196..8e5fe27 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7146,6 +7146,9 @@ def err_omp_parallel_sections_substmt_not_section : Error< "statement in 'omp parallel sections' directive must be enclosed into a section region">; def err_omp_parallel_reduction_in_task_firstprivate : Error< "argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">; +def err_omp_atomic_read_not_expression_statement : Error< + "the statement for 'atomic read' must be an expression statement of form 'v = x;'," + " where v and x are both l-value expressions with scalar type">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 4d19ea7..9fe3fe9 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -101,6 +101,7 @@ OPENMP_CLAUSE(nowait, OMPNowaitClause) OPENMP_CLAUSE(untied, OMPUntiedClause) OPENMP_CLAUSE(mergeable, OMPMergeableClause) OPENMP_CLAUSE(flush, OMPFlushClause) +OPENMP_CLAUSE(read, OMPReadClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -198,6 +199,9 @@ OPENMP_TASK_CLAUSE(shared) OPENMP_TASK_CLAUSE(untied) OPENMP_TASK_CLAUSE(mergeable) +// TODO More clauses allowed for OpenMP directive 'atomic'. +OPENMP_ATOMIC_CLAUSE(read) + #undef OPENMP_SCHEDULE_KIND #undef OPENMP_PROC_BIND_KIND #undef OPENMP_DEFAULT_KIND diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3451550..b08c278 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7482,6 +7482,9 @@ public: /// \brief Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'read' clause. + OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc); OMPClause * ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef Vars, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 959c45a..2a704c3 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -665,6 +665,8 @@ void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) { OS << "mergeable"; } +void OMPClausePrinter::VisitOMPReadClause(OMPReadClause *) { OS << "read"; } + template void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { for (typename T::varlist_iterator I = Node->varlist_begin(), diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c2bfa465..4cf7077 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -310,6 +310,8 @@ void OMPClauseProfiler::VisitOMPUntiedClause(const OMPUntiedClause *) {} void OMPClauseProfiler::VisitOMPMergeableClause(const OMPMergeableClause *) {} +void OMPClauseProfiler::VisitOMPReadClause(const OMPReadClause *) {} + template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { for (auto *I : Node->varlists()) diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 92145d6..78cfa18 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -108,6 +108,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_untied: case OMPC_mergeable: case OMPC_flush: + case OMPC_read: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -167,6 +168,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_untied: case OMPC_mergeable: case OMPC_flush: + case OMPC_read: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index f5ccb7c..9ba18b4 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -342,7 +342,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// | linear-clause | aligned-clause | collapse-clause | /// lastprivate-clause | reduction-clause | proc_bind-clause | /// schedule-clause | copyin-clause | copyprivate-clause | untied-clause | -/// mergeable-clause | flush-clause +/// mergeable-clause | flush-clause | read-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -405,6 +405,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: + case OMPC_read: // OpenMP [2.7.1, Restrictions, p. 9] // Only one ordered clause can appear on a loop directive. // OpenMP [2.7.1, Restrictions, C/C++, p. 4] @@ -527,6 +528,9 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { /// mergeable-clause: /// 'mergeable' /// +/// read-clause: +/// 'read' +/// OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); ConsumeAnyToken(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c7c7654..7ec0d2b 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -92,15 +92,16 @@ private: Scope *CurScope; SourceLocation ConstructLoc; bool OrderedRegion; + SourceLocation AtomicClauseLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc), OrderedRegion(false) {} + ConstructLoc(Loc), OrderedRegion(false), AtomicClauseLoc() {} SharingMapTy() : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc(), OrderedRegion(false) {} + ConstructLoc(), OrderedRegion(false), AtomicClauseLoc() {} }; typedef SmallVector StackTy; @@ -207,6 +208,22 @@ public: return false; } + /// \brief Checks if the 'atomic' construct has explicitly specified 'read', + /// 'update', 'write' or 'capture' clause. + bool hasAtomicClause() const { + return Stack.back().AtomicClauseLoc.isValid(); + } + /// \brief Gets location of explicitly specified clause for 'atomic' + /// construct. + SourceLocation getAtomicClauseLoc() const { + return Stack.back().AtomicClauseLoc; + } + /// \brief Sets location of explicitly specified clause for 'atomic' + /// directive. + void setAtomicClauseLoc(SourceLocation Loc) { + Stack.back().AtomicClauseLoc = Loc; + } + Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } @@ -2379,12 +2396,22 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { assert(AStmt && isa(AStmt) && "Captured statement expected"); + auto CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. // TODO further analysis of associated statements and clauses. + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_read) { + if (!isa(CS->getCapturedStmt())) { + Diag(CS->getCapturedStmt()->getLocStart(), + diag::err_omp_atomic_read_not_expression_statement); + return StmtError(); + } + } + } getCurFunction()->setHasBranchProtectedScope(); @@ -2430,6 +2457,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2633,6 +2661,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2748,6 +2777,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2827,6 +2857,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_mergeable: Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc); break; + case OMPC_read: + Res = ActOnOpenMPReadClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -2873,6 +2906,12 @@ OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc, return new (Context) OMPMergeableClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + DSAStack->setAtomicClauseLoc(StartLoc); + return new (Context) OMPReadClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef VarList, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, @@ -2926,6 +2965,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_read: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -4226,5 +4266,3 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef VarList, return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } - -#undef DSAStack diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 42bd1b0..fff0e57 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6762,6 +6762,12 @@ TreeTransform::TransformOMPMergeableClause(OMPMergeableClause *C) { } template +OMPClause *TreeTransform::TransformOMPReadClause(OMPReadClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template OMPClause * TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector Vars; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 6c60745a..ae87017 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1715,6 +1715,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_mergeable: C = new (Context) OMPMergeableClause(); break; + case OMPC_read: + C = new (Context) OMPReadClause(); + break; case OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); break; @@ -1809,6 +1812,8 @@ void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {} void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *) {} +void OMPClauseReader::VisitOMPReadClause(OMPReadClause *) {} + void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 70d834d..d42f9d6 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1735,6 +1735,8 @@ void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {} void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *) {} +void OMPClauseWriter::VisitOMPReadClause(OMPReadClause *) {} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); diff --git a/clang/test/OpenMP/atomic_ast_print.cpp b/clang/test/OpenMP/atomic_ast_print.cpp index 47c7234..957d4ae 100644 --- a/clang/test/OpenMP/atomic_ast_print.cpp +++ b/clang/test/OpenMP/atomic_ast_print.cpp @@ -11,23 +11,33 @@ T foo(T arg) { T a; #pragma omp atomic a++; +#pragma omp atomic read + a = arg; return T(); } // CHECK: int a; // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; +// CHECK-NEXT: #pragma omp atomic read +// CHECK-NEXT: a = arg; // CHECK: T a; // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; +// CHECK-NEXT: #pragma omp atomic read +// CHECK-NEXT: a = arg; int main(int argc, char **argv) { int a; // CHECK: int a; #pragma omp atomic a++; +#pragma omp atomic read + a = argc; // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; + // CHECK-NEXT: #pragma omp atomic read + // CHECK-NEXT: a = argc; return foo(a); } diff --git a/clang/test/OpenMP/atomic_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp index 6eef8f2..7b35e42 100644 --- a/clang/test/OpenMP/atomic_messages.cpp +++ b/clang/test/OpenMP/atomic_messages.cpp @@ -1,20 +1,47 @@ // RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 %s int foo() { - L1: - foo(); - #pragma omp atomic +L1: + foo(); +#pragma omp atomic { foo(); goto L1; // expected-error {{use of undeclared label 'L1'}} } goto L2; // expected-error {{use of undeclared label 'L2'}} - #pragma omp atomic +#pragma omp atomic { foo(); - L2: + L2: foo(); } return 0; } + +template +T read() { + T a, b = 0; +// Test for atomic read +#pragma omp atomic read +// expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}} + ; +// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}} +#pragma omp atomic read read + a = b; + + return T(); +} + +int read() { + int a, b = 0; +// Test for atomic read +#pragma omp atomic read +// expected-error@+1 {{the statement for 'atomic read' must be an expression statement of form 'v = x;', where v and x are both l-value expressions with scalar type}} + ; +// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'read' clause}} +#pragma omp atomic read read + a = b; + + return read(); +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index c124b1a..099302f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1981,6 +1981,8 @@ void OMPClauseEnqueue::VisitOMPUntiedClause(const OMPUntiedClause *) {} void OMPClauseEnqueue::VisitOMPMergeableClause(const OMPMergeableClause *) {} +void OMPClauseEnqueue::VisitOMPReadClause(const OMPReadClause *) {} + template void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { for (const auto *I : Node->varlists()) -- 2.7.4