diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10516,6 +10516,15 @@ " where x is an lvalue expression with scalar type">; def note_omp_atomic_capture: Note< "%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">; +def err_omp_atomic_compare : Error< + "the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}'," + " '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}'," + " 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type," + " and 'ordop' is one of '<' or '>'.">; +def note_omp_atomic_compare: Note< + "%select{expected compound statement|expected exactly one expression statement|expected assignment statement|expected conditional operator|expect result value to be at false expression|" + "expect binary operator in conditional expression|expect '<', '>' or '==' as order operator|expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'|" + "expect lvalue for result value|expect scalar value|expect integer value}0">; def err_omp_atomic_several_clauses : Error< "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">; def err_omp_several_mem_order_clauses : Error< 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 @@ -6031,9 +6031,13 @@ emitOMPAtomicCaptureExpr(CGF, AO, IsPostfixUpdate, V, X, E, UE, IsXLHSInRHSPart, Loc); break; - case OMPC_compare: - // Do nothing here as we already emit an error. + case OMPC_compare: { + // Emit an error here. + unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID( + DiagnosticsEngine::Error, "'atomic compare' is not supported for now"); + CGF.CGM.getDiags().Report(DiagID); break; + } case OMPC_if: case OMPC_final: case OMPC_num_threads: 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 @@ -10925,6 +10925,357 @@ } return ErrorFound != NoError; } + +/// Get the node id of the fixed point of an expression \a S. +llvm::FoldingSetNodeID getNodeId(ASTContext &Context, const Expr *S) { + llvm::FoldingSetNodeID Id; + S->IgnoreParenImpCasts()->Profile(Id, Context, true); + return Id; +} + +/// Check if two expressions are same. +bool checkIfTwoExprsAreSame(ASTContext &Context, const Expr *LHS, + const Expr *RHS) { + return getNodeId(Context, LHS) == getNodeId(Context, RHS); +} + +class OpenMPAtomicCompareChecker { +public: + /// All kinds of errors that can occur in `atomic compare` + enum ErrorTy { + /// Empty compound statement. + NoStmt = 0, + /// More than one statement in a compound statement. + MoreThanOneStmt, + /// Not an assignment binary operator. + NotAnAssignment, + /// Not a conditional operator. + NotCondOp, + /// Wrong false expr. According to the spec, 'x' should be at the false + /// expression of a conditional expression. + WrongFalseExpr, + /// The condition of a conditional expression is not a binary operator. + NotABinaryOp, + /// Invalid binary operator (not <, >, or ==). + InvalidBinaryOp, + /// Invalid comparison (not x == e, e == x, x ordop expr, or expr ordop x). + InvalidComparison, + /// X is not a lvalue. + XNotLValue, + /// Not a scalar. + NotScalar, + /// Not an integer. + NotInteger, + /// No error. + NoError, + }; + + struct ErrorInfoTy { + ErrorTy Error; + SourceLocation ErrorLoc; + SourceRange ErrorRange; + SourceLocation NoteLoc; + SourceRange NoteRange; + }; + + OpenMPAtomicCompareChecker(Sema &S) : ContextRef(S.getASTContext()) {} + + /// Check if statement \a S is valid for atomic compare. + bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo); + + Expr *getX() const { return X; } + Expr *getE() const { return E; } + Expr *getD() const { return D; } + Expr *getCond() const { return C; } + bool isXBinopExpr() const { return IsXBinopExpr; } + +private: + /// Reference to ASTContext + ASTContext &ContextRef; + /// 'x' lvalue part of the source atomic expression. + Expr *X = nullptr; + /// 'expr' or 'e' rvalue part of the source atomic expression. + Expr *E = nullptr; + /// 'd' rvalue part of the source atomic expression. + Expr *D = nullptr; + /// 'cond' part of the source atomic expression. It is in one of the following + /// forms: + /// expr ordop x + /// x ordop expr + /// x == e + /// e == x + Expr *C = nullptr; + /// True if the cond expr is in the form of 'x ordop expr'. + bool IsXBinopExpr = true; + /// The atomic compare operator. + OMPAtomicCompareOp Op; + + /// Check if it is a valid conditional update statement (cond-update-stmt). + bool checkCondUpdateStmt(IfStmt *S, ErrorInfoTy &ErrorInfo); + + /// Check if it is a valid conditional expression statement (cond-expr-stmt). + bool checkCondExprStmt(Stmt *S, ErrorInfoTy &ErrorInfo); + + /// Check if all captured values have right type. + bool checkType(ErrorInfoTy &ErrorInfo) const; +}; + +bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S, + ErrorInfoTy &ErrorInfo) { + auto *Then = S->getThen(); + if (auto *CS = dyn_cast(Then)) { + if (CS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + if (CS->size() > 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange(); + return false; + } + Then = CS->body_front(); + } + + auto *BO = dyn_cast(Then); + if (!BO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange(); + return false; + } + if (BO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = BO->getExprLoc(); + ErrorInfo.NoteLoc = BO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + + X = BO->getLHS(); + + auto *Cond = dyn_cast(S->getCond()); + if (!Cond) { + ErrorInfo.Error = ErrorTy::NotABinaryOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange(); + return false; + } + if (Cond->getOpcode() != BO_EQ && Cond->getOpcode() != BO_LT && + Cond->getOpcode() != BO_GT) { + ErrorInfo.Error = ErrorTy::InvalidBinaryOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + + if (Cond->getOpcode() == BO_EQ) { + C = Cond; + D = BO->getRHS(); + if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) { + E = Cond->getRHS(); + } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) { + E = Cond->getLHS(); + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + } else { + E = BO->getRHS(); + if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS()) && + checkIfTwoExprsAreSame(ContextRef, E, Cond->getRHS())) { + C = Cond; + } else if (checkIfTwoExprsAreSame(ContextRef, E, Cond->getLHS()) && + checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) { + C = Cond; + IsXBinopExpr = false; + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + } + + return true; +} + +bool OpenMPAtomicCompareChecker::checkCondExprStmt(Stmt *S, + ErrorInfoTy &ErrorInfo) { + auto *BO = dyn_cast(S); + if (!BO) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange(); + return false; + } + if (BO->getOpcode() != BO_Assign) { + ErrorInfo.Error = ErrorTy::NotAnAssignment; + ErrorInfo.ErrorLoc = BO->getExprLoc(); + ErrorInfo.NoteLoc = BO->getOperatorLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange(); + return false; + } + + X = BO->getLHS(); + + auto *CO = dyn_cast(BO->getRHS()->IgnoreParenImpCasts()); + if (!CO) { + ErrorInfo.Error = ErrorTy::NotCondOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getRHS()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getRHS()->getSourceRange(); + return false; + } + + if (!checkIfTwoExprsAreSame(ContextRef, X, CO->getFalseExpr())) { + ErrorInfo.Error = ErrorTy::WrongFalseExpr; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getFalseExpr()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = + CO->getFalseExpr()->getSourceRange(); + return false; + } + + auto *Cond = dyn_cast(CO->getCond()); + if (!Cond) { + ErrorInfo.Error = ErrorTy::NotABinaryOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = + CO->getCond()->getSourceRange(); + return false; + } + + if (Cond->getOpcode() != BO_EQ && Cond->getOpcode() != BO_LT && + Cond->getOpcode() != BO_GT) { + ErrorInfo.Error = ErrorTy::InvalidBinaryOp; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + + if (Cond->getOpcode() == BO_EQ) { + C = Cond; + D = CO->getTrueExpr(); + if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) { + E = Cond->getRHS(); + } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) { + E = Cond->getLHS(); + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + } else { + E = CO->getTrueExpr(); + if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS()) && + checkIfTwoExprsAreSame(ContextRef, E, Cond->getRHS())) { + C = Cond; + } else if (checkIfTwoExprsAreSame(ContextRef, E, Cond->getLHS()) && + checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) { + C = Cond; + IsXBinopExpr = false; + } else { + ErrorInfo.Error = ErrorTy::InvalidComparison; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange(); + return false; + } + } + + return true; +} + +bool OpenMPAtomicCompareChecker::checkType(ErrorInfoTy &ErrorInfo) const { + // 'x' and 'e' cannot be nullptr + assert(X && E && "X and E cannot be nullptr"); + + auto CheckValue = [&ErrorInfo](const Expr *E, OMPAtomicCompareOp Op, + bool ShouldBeLValue) { + if (ShouldBeLValue && !E->isLValue()) { + ErrorInfo.Error = ErrorTy::XNotLValue; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + + if (!E->isInstantiationDependent()) { + QualType QTy = E->getType(); + if (!QTy->isScalarType()) { + ErrorInfo.Error = ErrorTy::NotScalar; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + + if (Op != OMPAtomicCompareOp::EQ && !QTy->isIntegerType()) { + ErrorInfo.Error = ErrorTy::NotInteger; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + } + + return true; + }; + + if (!CheckValue(X, Op, true)) + return false; + + if (!CheckValue(E, Op, false)) + return false; + + if (D && !CheckValue(D, Op, false)) + return false; + + return true; +} + +bool OpenMPAtomicCompareChecker::checkStmt( + Stmt *S, OpenMPAtomicCompareChecker::ErrorInfoTy &ErrorInfo) { + auto *CS = dyn_cast(S); + if (CS) { + if (CS->body_empty()) { + ErrorInfo.Error = ErrorTy::NoStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + + if (CS->size() != 1) { + ErrorInfo.Error = ErrorTy::MoreThanOneStmt; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange(); + return false; + } + S = CS->body_front(); + } + + auto Res = false; + + if (auto *IS = dyn_cast(S)) { + // Check if the statement is in one of the following forms + // (cond-update-stmt): + // if (expr ordop x) { x = expr; } + // if (x ordop expr) { x = expr; } + // if (x == e) { x = d; } + Res = checkCondUpdateStmt(IS, ErrorInfo); + } else { + // Check if the statement is in one of the following forms (cond-expr-stmt): + // x = expr ordop x ? expr : x; + // x = x ordop expr ? expr : x; + // x = x == e ? d : x; + Res = checkCondExprStmt(S, ErrorInfo); + } + + if (!Res) + return false; + + return checkType(ErrorInfo); +} } // namespace StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, @@ -11018,6 +11369,8 @@ Expr *V = nullptr; Expr *E = nullptr; Expr *UE = nullptr; + Expr *D = nullptr; + Expr *CE = nullptr; bool IsXLHSInRHSPart = false; bool IsPostfixUpdate = false; // OpenMP [2.12.6, atomic Construct] @@ -11405,11 +11758,17 @@ if (CurContext->isDependentContext()) UE = V = E = X = nullptr; } else if (AtomicKind == OMPC_compare) { - // TODO: For now we emit an error here and in emitOMPAtomicExpr we ignore - // code gen. - unsigned DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, "atomic compare is not supported for now"); - Diag(AtomicKindLoc, DiagID); + OpenMPAtomicCompareChecker::ErrorInfoTy ErrorInfo; + OpenMPAtomicCompareChecker Checker(*this); + if (!Checker.checkStmt(Body, ErrorInfo)) { + Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_compare) + << ErrorInfo.ErrorRange; + Diag(ErrorInfo.NoteLoc, diag::note_omp_atomic_compare) + << ErrorInfo.Error << ErrorInfo.NoteRange; + return StmtError(); + } + // TODO: We don't set X, D, E, etc. here because in code gen we will emit + // error directly. } setFunctionHasBranchProtectedScope(); diff --git a/clang/test/OpenMP/atomic_ast_print.cpp b/clang/test/OpenMP/atomic_ast_print.cpp --- a/clang/test/OpenMP/atomic_ast_print.cpp +++ b/clang/test/OpenMP/atomic_ast_print.cpp @@ -5,6 +5,14 @@ // RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s // RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s + +// RUN: %clang_cc1 -DOMP51 -verify -fopenmp -fopenmp-version=51 -ast-print %s | FileCheck --check-prefixes=CHECK,CHECK-51 %s +// RUN: %clang_cc1 -DOMP51 -fopenmp -fopenmp-version=51 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -DOMP51 -fopenmp -fopenmp-version=51 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck --check-prefixes=CHECK,CHECK-51 %s + +// RUN: %clang_cc1 -DOMP51 -verify -fopenmp-simd -fopenmp-version=51 -ast-print %s | FileCheck --check-prefixes=CHECK,CHECK-51 %s +// RUN: %clang_cc1 -DOMP51 -fopenmp-simd -fopenmp-version=51 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -DOMP51 -fopenmp-simd -fopenmp-version=51 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck --check-prefixes=CHECK,CHECK-51 %s // expected-no-diagnostics #ifndef HEADER @@ -12,6 +20,7 @@ template T foo(T argc) { + T c = T(); T b = T(); T a = T(); #pragma omp atomic @@ -29,6 +38,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare + { a = a > b ? b : a; } +#pragma omp atomic compare + { a = a < b ? b : a; } +#pragma omp atomic compare + { a = a == b ? c : a; } +#endif #pragma omp atomic seq_cst a++; #pragma omp atomic read seq_cst @@ -44,6 +61,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare seq_cst + { a = a > b ? b : a; } +#pragma omp atomic seq_cst compare + { a = a < b ? b : a; } +#pragma omp atomic compare seq_cst + { a = a == b ? c : a; } +#endif #pragma omp atomic a++; #pragma omp atomic read @@ -59,6 +84,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare acq_rel + { a = a > b ? b : a; } +#pragma omp atomic acq_rel compare + { a = a < b ? b : a; } +#pragma omp atomic compare acq_rel + { a = a == b ? c : a; } +#endif #pragma omp atomic a++; #pragma omp atomic read acquire @@ -74,6 +107,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare acquire + { a = a > b ? b : a; } +#pragma omp atomic acquire compare + { a = a < b ? b : a; } +#pragma omp atomic compare acquire + { a = a == b ? c : a; } +#endif #pragma omp atomic release a++; #pragma omp atomic read @@ -89,6 +130,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare release + { a = a > b ? b : a; } +#pragma omp atomic release compare + { a = a < b ? b : a; } +#pragma omp atomic compare release + { a = a == b ? c : a; } +#endif #pragma omp atomic relaxed a++; #pragma omp atomic read @@ -104,6 +153,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare relaxed + { a = a > b ? b : a; } +#pragma omp atomic relaxed compare + { a = a < b ? b : a; } +#pragma omp atomic compare relaxed + { a = a == b ? c : a; } +#endif #pragma omp atomic hint(6) a++; #pragma omp atomic read hint(6) @@ -119,6 +176,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare hint(6) + { a = a > b ? b : a; } +#pragma omp atomic hint(6) compare + { a = a < b ? b : a; } +#pragma omp atomic compare hint(6) + { a = a == b ? c : a; } +#endif return T(); } @@ -138,6 +203,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic seq_cst // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read seq_cst @@ -153,6 +230,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare seq_cst +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic seq_cst compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare seq_cst +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -168,6 +257,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acq_rel +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic acq_rel compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acq_rel +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read acquire @@ -183,6 +284,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acquire +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic acquire compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acquire +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic release // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -198,6 +311,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare release +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic release compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare release +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic relaxed // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -213,6 +338,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare relaxed +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic relaxed compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare relaxed +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic hint(6) // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read hint(6) @@ -228,6 +365,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare hint(6) +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic hint(6) compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare hint(6) +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK: int a = int(); // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; @@ -244,6 +393,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic seq_cst // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read seq_cst @@ -259,6 +420,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare seq_cst +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic seq_cst compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare seq_cst +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -274,6 +447,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acq_rel +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic acq_rel compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acq_rel +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read acquire @@ -289,6 +474,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acquire +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic acquire compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare acquire +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic release // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -304,6 +501,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare release +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic release compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare release +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic relaxed // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -319,6 +528,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare relaxed +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic relaxed compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare relaxed +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic hint(6) // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read hint(6) @@ -334,8 +555,21 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare hint(6) +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a > b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic hint(6) compare +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a < b ? b : a; +// CHECK-51-NEXT: } +// CHECK-51-NEXT: #pragma omp atomic compare hint(6) +// CHECK-51-NEXT: { +// CHECK-51-NEXT: a = a == b ? c : a; +// CHECK-51-NEXT: } int main(int argc, char **argv) { + int c = 0; int b = 0; int a = 0; // CHECK: int a = 0; @@ -354,6 +588,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare + { a = a > b ? b : a; } +#pragma omp atomic compare + { a = a < b ? b : a; } +#pragma omp atomic compare + { a = a == b ? c : a; } +#endif #pragma omp atomic seq_cst a++; #pragma omp atomic read seq_cst @@ -369,6 +611,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare seq_cst + { a = a > b ? b : a; } +#pragma omp atomic seq_cst compare + { a = a < b ? b : a; } +#pragma omp atomic compare seq_cst + { a = a == b ? c : a; } +#endif #pragma omp atomic a++; #pragma omp atomic read @@ -384,6 +634,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare acq_rel + { a = a > b ? b : a; } +#pragma omp atomic acq_rel compare + { a = a < b ? b : a; } +#pragma omp atomic compare acq_rel + { a = a == b ? c : a; } +#endif #pragma omp atomic a++; #pragma omp atomic read acquire @@ -399,6 +657,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare acquire + { a = a > b ? b : a; } +#pragma omp atomic acquire compare + { a = a < b ? b : a; } +#pragma omp atomic compare acquire + { a = a == b ? c : a; } +#endif #pragma omp atomic release a++; #pragma omp atomic read @@ -414,6 +680,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare release + { a = a > b ? b : a; } +#pragma omp atomic release compare + { a = a < b ? b : a; } +#pragma omp atomic compare release + { a = a == b ? c : a; } +#endif #pragma omp atomic relaxed a++; #pragma omp atomic read @@ -429,6 +703,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare relaxed + { a = a > b ? b : a; } +#pragma omp atomic relaxed compare + { a = a < b ? b : a; } +#pragma omp atomic compare relaxed + { a = a == b ? c : a; } +#endif #pragma omp atomic hint(6) a++; #pragma omp atomic read hint(6) @@ -444,6 +726,14 @@ a = b; b++; } +#ifdef OMP51 +#pragma omp atomic compare hint(6) + { a = a > b ? b : a; } +#pragma omp atomic hint(6) compare + { a = a < b ? b : a; } +#pragma omp atomic compare hint(6) + { a = a == b ? c : a; } +#endif // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -459,6 +749,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic seq_cst // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read seq_cst @@ -474,6 +776,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare seq_cst + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic seq_cst compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare seq_cst + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -489,6 +803,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare acq_rel + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic acq_rel compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare acq_rel + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read acquire @@ -504,6 +830,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare acquire + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic acquire compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare acquire + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic release // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -519,6 +857,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare release + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic release compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare release + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic relaxed // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read @@ -534,6 +884,18 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare relaxed + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic relaxed compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare relaxed + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } // CHECK-NEXT: #pragma omp atomic hint(6) // CHECK-NEXT: a++; // CHECK-NEXT: #pragma omp atomic read hint(6) @@ -549,6 +911,19 @@ // CHECK-NEXT: a = b; // CHECK-NEXT: b++; // CHECK-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare hint(6) + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a > b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic hint(6) compare + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a < b ? b : a; + // CHECK-51-NEXT: } + // CHECK-51-NEXT: #pragma omp atomic compare hint(6) + // CHECK-51-NEXT: { + // CHECK-51-NEXT: a = a == b ? c : a; + // CHECK-51-NEXT: } + // expect-note@+1 {{in instantiation of function template specialization 'foo' requested here}} return foo(a); } diff --git a/clang/test/OpenMP/atomic_messages.c b/clang/test/OpenMP/atomic_messages.c --- a/clang/test/OpenMP/atomic_messages.c +++ b/clang/test/OpenMP/atomic_messages.c @@ -1,8 +1,10 @@ // RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -ferror-limit 100 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -fopenmp-version=51 -ferror-limit 100 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 100 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -ferror-limit 100 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -fopenmp-version=51 -ferror-limit 100 %s -Wuninitialized void xxx(int argc) { int x; // expected-note {{initialize the variable 'x' to silence this warning}} @@ -394,3 +396,92 @@ #pragma omp atomic hint(1) hint(1) // omp45-error 2 {{unexpected OpenMP clause 'hint' in directive '#pragma omp atomic'}} expected-error {{directive '#pragma omp atomic' cannot contain more than one 'hint' clause}} a += 1; } + +#ifdef OMP51 +extern void bbar(); +extern int ffoo(); + +void compare() { + int x = 0; + int d = 0; + int e = 0; +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected compound statement}} +#pragma omp atomic compare + {} +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected exactly one expression statement}} +#pragma omp atomic compare + { + x = d; + x = e; + } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare + { x += d; } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected assignment statement}} +#pragma omp atomic compare + { bbar(); } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected conditional operator}} +#pragma omp atomic compare + { x = d; } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect binary operator in conditional expression}} +#pragma omp atomic compare + { x = ffoo() ? e : x; } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect '<', '>' or '==' as order operator}} +#pragma omp atomic compare + { x = x >= e ? e : x; } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'}} +#pragma omp atomic compare + { x = d > e ? e : x; } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expect result value to be at false expression}} +#pragma omp atomic compare + { x = d > x ? e : d; } +// omp51-error@+4 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+3 {{expect binary operator in conditional expression}} +#pragma omp atomic compare + { + if (foo()) + x = d; + } +// omp51-error@+4 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+3 {{expect '<', '>' or '==' as order operator}} +#pragma omp atomic compare + { + if (x >= d) + x = d; + } +// omp51-error@+4 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+3 {{expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'}} +#pragma omp atomic compare + { + if (e > d) + x = d; + } +// omp51-error@+3 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+2 {{expected exactly one expression statement}} +#pragma omp atomic compare + { + if (x > d) + x = e; + d = e; + } + float fx = 0.0f; + float fd = 0.0f; + float fe = 0.0f; +// omp51-error@+5 {{the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}', '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type, and 'ordop' is one of '<' or '>'.}} +// omp51-note@+4 {{expect integer value}} +#pragma omp atomic compare + { + if (fx > fe) + fx = fe; + } +} +#endif diff --git a/clang/test/OpenMP/atomic_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp --- a/clang/test/OpenMP/atomic_messages.cpp +++ b/clang/test/OpenMP/atomic_messages.cpp @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -ferror-limit 150 %s -Wuninitialized -// RUN: %clang_cc1 -verify=expected,omp50,omp51 -fopenmp -fopenmp-version=51 -ferror-limit 150 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp -fopenmp-version=51 -ferror-limit 150 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -ferror-limit 150 %s -Wuninitialized // RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -ferror-limit 150 %s -Wuninitialized -// RUN: %clang_cc1 -verify=expected,omp50,omp51 -fopenmp-simd -fopenmp-version=51 -ferror-limit 150 %s -Wuninitialized +// RUN: %clang_cc1 -DOMP51 -verify=expected,omp50,omp51 -fopenmp-simd -fopenmp-version=51 -ferror-limit 150 %s -Wuninitialized int foo() { L1: @@ -914,6 +914,16 @@ // expected-note@+1 2 {{'capture' clause used here}} #pragma omp atomic capture read a = ++b; +#ifdef OMP51 +// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}} +// expected-note@+1 2 {{'write' clause used here}} +#pragma omp atomic write compare + a = b; +// expected-error@+2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}} +// expected-note@+1 2 {{'read' clause used here}} +#pragma omp atomic read compare + a = b; +#endif return T(); } @@ -935,18 +945,16 @@ // expected-note@+1 {{'write' clause used here}} #pragma omp atomic write capture a = b; +#ifdef OMP51 +// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}} +// expected-note@+1 {{'write' clause used here}} +#pragma omp atomic write compare + a = b; +// expected-error@+2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}} +// expected-note@+1 {{'read' clause used here}} +#pragma omp atomic read compare + a = b; +#endif // expected-note@+1 {{in instantiation of function template specialization 'mixed' requested here}} return mixed(); } - -#if _OPENMP >= 202011 -int compare() { - int a, b, c; -// omp51-error@+1 {{atomic compare is not supported for now}} -#pragma omp atomic compare - { - if (a == b) - a = c; - } -} -#endif