diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 2808a37d0b314676e7b50f38ce488b51058a97dd..dfc3a47f9f460962b96bc71ec2728d245f6f6ede 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -2190,14 +2190,18 @@ enum CXCursorKind { /** \brief OpenMP flush directive. */ CXCursor_OMPFlushDirective = 246, - + /** \brief OpenMP ordered directive. */ CXCursor_OMPOrderedDirective = 247, + /** \brief OpenMP atomic directive. + */ + CXCursor_OMPAtomicDirective = 248, + /** \brief Windows Structured Exception Handling's leave statement. */ - CXCursor_SEHLeaveStmt = 248, + CXCursor_SEHLeaveStmt = 249, CXCursor_LastStmt = CXCursor_SEHLeaveStmt, diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 89ddfe4a54c2bf653385fdc4944f7552d531ac95..28fb848bdd4f1000e5f90cc38869e85635f025a5 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2329,6 +2329,9 @@ DEF_TRAVERSE_STMT(OMPFlushDirective, DEF_TRAVERSE_STMT(OMPOrderedDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPAtomicDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index c50a68ad4c6b866635c4dbacc3e603c456ee0295..e3f68196cea584d33a04babcb4c6aeb60e0016ad 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2351,6 +2351,9 @@ DEF_TRAVERSE_STMT(OMPFlushDirective, DEF_TRAVERSE_STMT(OMPOrderedDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPAtomicDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index 17bd0ee138cd0575e6368672419262121b7b4ddf..381fbd3f0d0254097bf45b81f3d7252408aff721 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -1075,6 +1075,62 @@ public: } }; +/// \brief This represents '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic capture +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'capture'. +/// +class OMPAtomicDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPAtomicDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPAtomicDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPAtomicDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPAtomicDirectiveClass; + } +}; + } // end namespace clang #endif diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index baf83cf0f9b99766f3a593884714a0a6c7203981..7e6b196359bf0eaa044449364f5b25371ae57ac9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7127,6 +7127,8 @@ def err_omp_prohibited_region : Error< "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?}2">; def err_omp_prohibited_region_simd : Error< "OpenMP constructs may not be nested inside a simd region">; +def err_omp_prohibited_region_atomic : Error< + "OpenMP constructs may not be nested inside an atomic region">; def err_omp_prohibited_region_critical_same_name : Error< "cannot nest 'critical' regions having the same name %0">; def note_omp_previous_critical_region : Note< diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index e89147f87388e4cc6f3be1afbdfc61fda73de62c..4d19ea77bd676c5341521865ccd5762d862d54a2 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -45,6 +45,9 @@ #ifndef OPENMP_TASK_CLAUSE # define OPENMP_TASK_CLAUSE(Name) #endif +#ifndef OPENMP_ATOMIC_CLAUSE +# define OPENMP_ATOMIC_CLAUSE(Name) +#endif #ifndef OPENMP_DEFAULT_KIND # define OPENMP_DEFAULT_KIND(Name) #endif @@ -71,6 +74,7 @@ OPENMP_DIRECTIVE(barrier) OPENMP_DIRECTIVE(taskwait) OPENMP_DIRECTIVE(flush) OPENMP_DIRECTIVE(ordered) +OPENMP_DIRECTIVE(atomic) OPENMP_DIRECTIVE_EXT(parallel_for, "parallel for") OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections") @@ -206,6 +210,7 @@ OPENMP_TASK_CLAUSE(mergeable) #undef OPENMP_PARALLEL_FOR_CLAUSE #undef OPENMP_PARALLEL_SECTIONS_CLAUSE #undef OPENMP_TASK_CLAUSE +#undef OPENMP_ATOMIC_CLAUSE #undef OPENMP_SIMD_CLAUSE #undef OPENMP_FOR_CLAUSE diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index ce6a6d68a324d8a545ff313f7430aecede4b1cc8..1dc7e2fa63bba55ab0ec9a7db94592cf6657df86 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -194,3 +194,4 @@ def OMPBarrierDirective : DStmt<OMPExecutableDirective>; def OMPTaskwaitDirective : DStmt<OMPExecutableDirective>; def OMPFlushDirective : DStmt<OMPExecutableDirective>; def OMPOrderedDirective : DStmt<OMPExecutableDirective>; +def OMPAtomicDirective : DStmt<OMPExecutableDirective>; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e11023606d182eeabbfaf6a9da06d289e17b5e29..34515506b595ffddf09c093670fec8cab9db14af 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7395,10 +7395,15 @@ public: StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp master' after parsing of the + /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 440e2cd599db711f541fd7af2aeefc07cd8e8dba..7541f24ce5a1c46009a42778eda1356673dc7798 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1356,6 +1356,7 @@ namespace clang { STMT_OMP_TASKWAIT_DIRECTIVE, STMT_OMP_FLUSH_DIRECTIVE, STMT_OMP_ORDERED_DIRECTIVE, + STMT_OMP_ATOMIC_DIRECTIVE, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 2eba8753f6df43badc14923392a13c2e448002c6..91fdcd6587d28a4c219ccd91c976290f792897ac 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1698,3 +1698,29 @@ OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C, return new (Mem) OMPOrderedDirective(); } +OMPAtomicDirective *OMPAtomicDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPAtomicDirective *Dir = + new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + return new (Mem) OMPAtomicDirective(NumClauses); +} + diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index e8fbdf4539031423c95b231aa18034ee5b053150..959c45acc6a840d8036709e47b2b8e058d17f282 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -891,6 +891,11 @@ void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) { PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) { + Indent() << "#pragma omp atomic "; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 0e308861fca46f02a590f9fd05efc35d6f21ad2f..c2bfa46531d141e79b3b2d496d1be1cbaa4a6f61 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -435,6 +435,10 @@ void StmtProfiler::VisitOMPOrderedDirective(const OMPOrderedDirective *S) { VisitOMPExecutableDirective(S); } +void StmtProfiler::VisitOMPAtomicDirective(const OMPAtomicDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 2f37f2fe66c3621293c8d9e8315546aeacf3aa40..92145d6012957e2c146ad560596a5d35cf791c0d 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -260,6 +260,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, case OMPD_flush: return CKind == OMPC_flush; break; + case OMPD_atomic: + switch (CKind) { +#define OPENMP_ATOMIC_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index d34a69ec3de5aa7e27251309550f57516bf02055..fdeaaf6bb8882fef0d5c052c79da81153a281ea7 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -224,6 +224,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::OMPOrderedDirectiveClass: EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S)); break; + case Stmt::OMPAtomicDirectiveClass: + EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S)); + break; } } diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 8fdec176ed53e56a7c28d9917b0d4fc72a4417d7..339be3a5a9924824ff9e5da672a7422e137e6704 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -132,3 +132,7 @@ void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &) { llvm_unreachable("CodeGen for 'omp ordered' is not supported yet."); } +void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &) { + llvm_unreachable("CodeGen for 'omp atomic' is not supported yet."); +} + diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f2ecc4a796a497b349fd9369a32f86b2363a9927..335a8910e82b29ba8af31666a5b363aa13e98b25 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1937,6 +1937,7 @@ public: void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S); void EmitOMPFlushDirective(const OMPFlushDirective &S); void EmitOMPOrderedDirective(const OMPOrderedDirective &S); + void EmitOMPAtomicDirective(const OMPAtomicDirective &S); //===--------------------------------------------------------------------===// // LValue Expression Emission diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 9afe26cee15f739f6d7aa628928ef83a54ddfeca..f5ccb7c14e4cb2c4ea3a81de651b01b263418733 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -96,6 +96,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_critical: case OMPD_parallel_for: case OMPD_parallel_sections: + case OMPD_atomic: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; @@ -114,7 +115,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | /// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | -/// 'barrier' | 'taskwait' | 'flush' | 'ordered' {clause} +/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' {clause} /// annot_pragma_openmp_end /// StmtResult @@ -179,7 +180,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { case OMPD_parallel_for: case OMPD_parallel_sections: case OMPD_task: - case OMPD_ordered: { + case OMPD_ordered: + case OMPD_atomic: { ConsumeToken(); // Parse directive name of the 'critical' directive if any. if (DKind == OMPD_critical) { diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 23ed63192b6988593b48dd6dd14c9e3cc67cb21d..c7c7654250166d6d849549dd3c82bb7966060f0c 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1114,6 +1114,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_atomic: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_threadprivate: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: @@ -1145,6 +1153,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel | taskwait | * | // | parallel | flush | * | // | parallel | ordered | + | + // | parallel | atomic | * | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | @@ -1162,6 +1171,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for | taskwait | * | // | for | flush | * | // | for | ordered | * (if construct is ordered) | + // | for | atomic | * | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | @@ -1179,6 +1189,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | master | taskwait | * | // | master | flush | * | // | master | ordered | + | + // | master | atomic | * | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | @@ -1195,6 +1206,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | critical | barrier | + | // | critical | taskwait | * | // | critical | ordered | + | + // | critical | atomic | * | // +------------------+-----------------+------------------------------------+ // | simd | parallel | | // | simd | for | | @@ -1212,6 +1224,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | taskwait | | // | simd | flush | | // | simd | ordered | | + // | simd | atomic | | // +------------------+-----------------+------------------------------------+ // | sections | parallel | * | // | sections | for | + | @@ -1229,6 +1242,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | sections | taskwait | * | // | sections | flush | * | // | sections | ordered | + | + // | sections | atomic | * | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | @@ -1246,6 +1260,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | section | taskwait | * | // | section | flush | * | // | section | ordered | + | + // | section | atomic | * | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | @@ -1263,6 +1278,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | single | taskwait | * | // | single | flush | * | // | single | ordered | + | + // | single | atomic | * | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | @@ -1280,6 +1296,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for | taskwait | * | // | parallel for | flush | * | // | parallel for | ordered | * (if construct is ordered) | + // | parallel for | atomic | * | // +------------------+-----------------+------------------------------------+ // | parallel sections| parallel | * | // | parallel sections| for | + | @@ -1297,6 +1314,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel sections| taskwait | * | // | parallel sections| flush | * | // | parallel sections| ordered | + | + // | parallel sections| atomic | * | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | @@ -1314,6 +1332,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | task | taskwait | * | // | task | flush | * | // | task | ordered | + | + // | task | atomic | * | // +------------------+-----------------+------------------------------------+ // | ordered | parallel | * | // | ordered | for | + | @@ -1331,6 +1350,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | ordered | taskwait | * | // | ordered | flush | * | // | ordered | ordered | + | + // | ordered | atomic | * | // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); @@ -1347,6 +1367,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); return true; } + if (ParentRegion == OMPD_atomic) { + // OpenMP [2.16, Nesting of Regions] + // OpenMP constructs may not be nested inside an atomic region. + SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_atomic); + return true; + } if (CurrentRegion == OMPD_section) { // OpenMP [2.7.2, sections Construct, Restrictions] // Orphaned section directives are prohibited. That is, the section @@ -1368,7 +1394,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, if (CurrentRegion == OMPD_master) { // OpenMP [2.16, Nesting of Regions] // A master region may not be closely nested inside a worksharing, - // atomic (TODO), or explicit task region. + // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task; } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { @@ -1403,7 +1429,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, } else if (CurrentRegion == OMPD_barrier) { // OpenMP [2.16, Nesting of Regions] // A barrier region may not be closely nested inside a worksharing, - // explicit task, critical, ordered, atomic(TODO), or master region. + // explicit task, critical, ordered, atomic, or master region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || ParentRegion == OMPD_master || @@ -1414,7 +1440,6 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // A worksharing region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. - // TODO NestingProhibited = (isOpenMPWorksharingDirective(ParentRegion) && !isOpenMPSimdDirective(ParentRegion)) || @@ -1424,7 +1449,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] // An ordered region may not be closely nested inside a critical, - // atomic(TODO), or explicit task region. + // atomic, or explicit task region. // An ordered region must be closely nested inside a loop region (or // parallel loop region) with an ordered clause. NestingProhibited = ParentRegion == OMPD_critical || @@ -1558,6 +1583,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, "No clauses are allowed for 'omp ordered' directive"); Res = ActOnOpenMPOrderedDirective(AStmt, StartLoc, EndLoc); break; + case OMPD_atomic: + Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; case OMPD_threadprivate: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: @@ -2345,6 +2374,23 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt, return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt); } +StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + // 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. + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 22a01bb636dc45af107820a83f200e76f6894c4f..42bd1b0da0f795a8c829958b668ab4eb0c7ae45e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6644,6 +6644,17 @@ TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) { return Res; } +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPAtomicDirective(OMPAtomicDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 3d6a9a70fc06eadf2d3c963cd99e7738b3cd7005..6c60745aa09d5b03429d4a03a02499298e1254d4 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -2036,6 +2036,13 @@ void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) { VisitOMPExecutableDirective(D); } +void ASTStmtReader::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; + VisitOMPExecutableDirective(D); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -2595,6 +2602,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OMPOrderedDirective::CreateEmpty(Context, Empty); break; + case STMT_OMP_ATOMIC_DIRECTIVE: + S = OMPAtomicDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(Context, Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 486f89d67702edf26bd365758062fa874e8b83f2..70d834dedf05f3869dc4cbf2b71fad2feaf096cf 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1905,6 +1905,13 @@ void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) { Code = serialization::STMT_OMP_TASK_DIRECTIVE; } +void ASTStmtWriter::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE; +} + void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index eac8dd0af61792ea0e3046420541d288c0384177..f4636ef18aaed187860d05abccc9b83034ddefa5 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -747,6 +747,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPTaskwaitDirectiveClass: case Stmt::OMPFlushDirectiveClass: case Stmt::OMPOrderedDirectiveClass: + case Stmt::OMPAtomicDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: diff --git a/test/OpenMP/atomic_ast_print.cpp b/test/OpenMP/atomic_ast_print.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47c723469aab038c1be1bd1f4a4abfe4882281c8 --- /dev/null +++ b/test/OpenMP/atomic_ast_print.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +template <class T> +T foo(T arg) { + T a; +#pragma omp atomic + a++; + return T(); +} + +// CHECK: int a; +// CHECK-NEXT: #pragma omp atomic +// CHECK-NEXT: a++; +// CHECK: T a; +// CHECK-NEXT: #pragma omp atomic +// CHECK-NEXT: a++; + +int main(int argc, char **argv) { + int a; +// CHECK: int a; +#pragma omp atomic + a++; + // CHECK-NEXT: #pragma omp atomic + // CHECK-NEXT: a++; + return foo(a); +} + +#endif diff --git a/test/OpenMP/atomic_messages.cpp b/test/OpenMP/atomic_messages.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6eef8f227df3bbdc52934b51aee4e47dd244293e --- /dev/null +++ b/test/OpenMP/atomic_messages.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 %s + +int foo() { + 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 + { + foo(); + L2: + foo(); + } + + return 0; +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 8e9a7bd93306f25725ed47cc13027b088fb00c92..c124b1ab0de67e96f57ff9b846ac7bad4f489afd 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1872,6 +1872,7 @@ public: void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D); void VisitOMPFlushDirective(const OMPFlushDirective *D); void VisitOMPOrderedDirective(const OMPOrderedDirective *D); + void VisitOMPAtomicDirective(const OMPAtomicDirective *D); private: void AddDeclarationNameInfo(const Stmt *S); @@ -2378,6 +2379,10 @@ void EnqueueVisitor::VisitOMPOrderedDirective(const OMPOrderedDirective *D) { VisitOMPExecutableDirective(D); } +void EnqueueVisitor::VisitOMPAtomicDirective(const OMPAtomicDirective *D) { + VisitOMPExecutableDirective(D); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); } @@ -4082,6 +4087,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OMPFlushDirective"); case CXCursor_OMPOrderedDirective: return cxstring::createRef("OMPOrderedDirective"); + case CXCursor_OMPAtomicDirective: + return cxstring::createRef("OMPAtomicDirective"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 796c25c0ec6508665286585a8aac42063f69c9c0..a20cc4ad3d005f7781cfe56fd8541fa22b4d593c 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -565,6 +565,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OMPOrderedDirectiveClass: K = CXCursor_OMPOrderedDirective; break; + case Stmt::OMPAtomicDirectiveClass: + K = CXCursor_OMPAtomicDirective; + break; } CXCursor C = { K, 0, { Parent, S, TU } };