[clang] b35be6f - [Clang][Sema][OpenMP] Sema support for `atomic compare`

Shilei Tian via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 4 09:31:01 PST 2022


Author: Shilei Tian
Date: 2022-02-04T12:30:56-05:00
New Revision: b35be6fe98e30b2373e8fdf024ef8c13a32121d7

URL: https://github.com/llvm/llvm-project/commit/b35be6fe98e30b2373e8fdf024ef8c13a32121d7
DIFF: https://github.com/llvm/llvm-project/commit/b35be6fe98e30b2373e8fdf024ef8c13a32121d7.diff

LOG: [Clang][Sema][OpenMP] Sema support for `atomic compare`

This patch adds the Sema support for `atomic compare`.

Reviewed By: ABataev

Differential Revision: https://reviews.llvm.org/D116637

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/CodeGen/CGStmtOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/OpenMP/atomic_ast_print.cpp
    clang/test/OpenMP/atomic_messages.c
    clang/test/OpenMP/atomic_messages.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d5e653a7fa192..7f73b9b285e37 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10516,6 +10516,15 @@ def err_omp_atomic_capture_not_compound_statement : Error<
   " 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
index 39dd4c00765d2..596cef8ce60c1 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -6031,9 +6031,13 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
     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
index a4092f0d2b543..1fafd58ba3edd 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -10925,6 +10925,357 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
   }
   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 <tt>atomic compare</tt>.
+  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<CompoundStmt>(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<BinaryOperator>(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<BinaryOperator>(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<BinaryOperator>(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<ConditionalOperator>(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<BinaryOperator>(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<CompoundStmt>(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<IfStmt>(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<OMPClause *> Clauses,
@@ -11018,6 +11369,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
   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 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
     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
index 67ed8428031e2..9484917dde83b 100644
--- 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 <class T>
 T foo(T argc) {
+  T c = T();
   T b = T();
   T a = T();
 #pragma omp atomic
@@ -29,6 +38,14 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
     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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ T foo(T argc) {
 // 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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
     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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 @@ int main(int argc, char **argv) {
   // 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 at +1 {{in instantiation of function template specialization 'foo<int>' requested here}}
   return foo(a);
 }
 

diff  --git a/clang/test/OpenMP/atomic_messages.c b/clang/test/OpenMP/atomic_messages.c
index a1cfa3edf5747..6e0df178ca581 100644
--- 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 @@ void hint() {
 #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 at +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 at +2 {{expected compound statement}}
+#pragma omp atomic compare
+  {}
+// omp51-error at +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 at +2 {{expected exactly one expression statement}}
+#pragma omp atomic compare
+  {
+    x = d;
+    x = e;
+  }
+// omp51-error at +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 at +2 {{expected assignment statement}}
+#pragma omp atomic compare
+  { x += d; }
+// omp51-error at +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 at +2 {{expected assignment statement}}
+#pragma omp atomic compare
+  { bbar(); }
+// omp51-error at +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 at +2 {{expected conditional operator}}
+#pragma omp atomic compare
+  { x = d; }
+// omp51-error at +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 at +2 {{expect binary operator in conditional expression}}
+#pragma omp atomic compare
+  { x = ffoo() ? e : x; }
+// omp51-error at +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 at +2 {{expect '<', '>' or '==' as order operator}}
+#pragma omp atomic compare
+  { x = x >= e ? e : x; }
+// omp51-error at +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 at +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 at +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 at +2 {{expect result value to be at false expression}}
+#pragma omp atomic compare
+  { x = d > x ? e : d; }
+// omp51-error at +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 at +3 {{expect binary operator in conditional expression}}
+#pragma omp atomic compare
+  {
+    if (foo())
+      x = d;
+  }
+// omp51-error at +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 at +3 {{expect '<', '>' or '==' as order operator}}
+#pragma omp atomic compare
+  {
+    if (x >= d)
+      x = d;
+  }
+// omp51-error at +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 at +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 at +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 at +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 at +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 at +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
index 608847f87dadc..3e4ffa841ecd8 100644
--- 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 @@ T mixed() {
 // expected-note at +1 2 {{'capture' clause used here}}
 #pragma omp atomic capture read
   a = ++b;
+#ifdef OMP51
+// expected-error at +2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}}
+// expected-note at +1 2 {{'write' clause used here}}
+#pragma omp atomic write compare
+  a = b;
+// expected-error at +2 2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}}
+// expected-note at +1 2 {{'read' clause used here}}
+#pragma omp atomic read compare
+  a = b;
+#endif
   return T();
 }
 
@@ -935,18 +945,16 @@ int mixed() {
 // expected-note at +1 {{'write' clause used here}}
 #pragma omp atomic write capture
   a = b;
+#ifdef OMP51
+// expected-error at +2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}}
+// expected-note at +1 {{'write' clause used here}}
+#pragma omp atomic write compare
+  a = b;
+// expected-error at +2 {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause}}
+// expected-note at +1 {{'read' clause used here}}
+#pragma omp atomic read compare
+  a = b;
+#endif
   // expected-note at +1 {{in instantiation of function template specialization 'mixed<int>' requested here}}
   return mixed<int>();
 }
-
-#if _OPENMP >= 202011
-int compare() {
-  int a, b, c;
-// omp51-error at +1 {{atomic compare is not supported for now}}
-#pragma omp atomic compare
-  {
-    if (a == b)
-      a = c;
-  }
-}
-#endif


        


More information about the cfe-commits mailing list