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 @@ -24,6 +24,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PrettyStackTrace.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" @@ -6015,7 +6016,7 @@ llvm::AtomicOrdering AO, bool IsPostfixUpdate, const Expr *X, const Expr *V, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, - SourceLocation Loc) { + bool IsCompareCapture, SourceLocation Loc) { switch (Kind) { case OMPC_read: emitOMPAtomicReadExpr(CGF, AO, X, V, Loc); @@ -6032,10 +6033,13 @@ IsXLHSInRHSPart, Loc); break; 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); + if (!IsCompareCapture) { + // 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: @@ -6148,18 +6152,23 @@ AO = llvm::AtomicOrdering::Monotonic; MemOrderingSpecified = true; } + llvm::SmallSet KindsEncountered; OpenMPClauseKind Kind = OMPC_unknown; for (const OMPClause *C : S.clauses()) { // Find first clause (skip seq_cst|acq_rel|aqcuire|release|relaxed clause, // if it is first). - if (C->getClauseKind() != OMPC_seq_cst && - C->getClauseKind() != OMPC_acq_rel && - C->getClauseKind() != OMPC_acquire && - C->getClauseKind() != OMPC_release && - C->getClauseKind() != OMPC_relaxed && C->getClauseKind() != OMPC_hint) { - Kind = C->getClauseKind(); - break; - } + OpenMPClauseKind K = C->getClauseKind(); + if (K == OMPC_seq_cst || K == OMPC_acq_rel || K == OMPC_acquire || + K == OMPC_release || K == OMPC_relaxed || K == OMPC_hint) + continue; + Kind = K; + KindsEncountered.insert(K); + } + bool IsCompareCapture = false; + if (KindsEncountered.contains(OMPC_compare) && + KindsEncountered.contains(OMPC_capture)) { + IsCompareCapture = true; + Kind = OMPC_compare; } if (!MemOrderingSpecified) { llvm::AtomicOrdering DefaultOrder = @@ -6183,7 +6192,7 @@ EmitStopPoint(S.getAssociatedStmt()); emitOMPAtomicExpr(*this, Kind, AO, S.isPostfixUpdate(), S.getX(), S.getV(), S.getExpr(), S.getUpdateExpr(), S.isXLHSInRHSPart(), - S.getBeginLoc()); + IsCompareCapture, S.getBeginLoc()); } static void emitCommonOMPTargetDirective(CodeGenFunction &CGF, 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 @@ -35,6 +35,7 @@ #include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" @@ -11315,14 +11316,18 @@ SourceLocation AtomicKindLoc; OpenMPClauseKind MemOrderKind = OMPC_unknown; SourceLocation MemOrderLoc; + bool MutexClauseEncountered = false; + llvm::SmallSet EncounteredAtomicKinds; for (const OMPClause *C : Clauses) { switch (C->getClauseKind()) { case OMPC_read: case OMPC_write: case OMPC_update: + MutexClauseEncountered = true; + LLVM_FALLTHROUGH; case OMPC_capture: case OMPC_compare: { - if (AtomicKind != OMPC_unknown) { + if (AtomicKind != OMPC_unknown && MutexClauseEncountered) { Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses) << SourceRange(C->getBeginLoc(), C->getEndLoc()); Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause) @@ -11330,6 +11335,7 @@ } else { AtomicKind = C->getClauseKind(); AtomicKindLoc = C->getBeginLoc(); + EncounteredAtomicKinds.insert(C->getClauseKind()); } break; } @@ -11357,6 +11363,12 @@ llvm_unreachable("unknown clause is encountered"); } } + bool IsCompareCapture = false; + if (EncounteredAtomicKinds.contains(OMPC_compare) && + EncounteredAtomicKinds.contains(OMPC_capture)) { + IsCompareCapture = true; + AtomicKind = OMPC_compare; + } // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions // If atomic-clause is read then memory-order-clause must not be acq_rel or // release. @@ -11775,17 +11787,26 @@ if (CurContext->isDependentContext()) UE = V = E = X = nullptr; } else if (AtomicKind == OMPC_compare) { - 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(); + if (IsCompareCapture) { + // TODO: For now we emit an error here and in emitOMPAtomicExpr we ignore + // code gen. + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "atomic compare capture is not supported for now"); + Diag(AtomicKindLoc, DiagID); + } else { + 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. } - // 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_messages.cpp b/clang/test/OpenMP/atomic_messages.cpp --- a/clang/test/OpenMP/atomic_messages.cpp +++ b/clang/test/OpenMP/atomic_messages.cpp @@ -958,3 +958,16 @@ // expected-note@+1 {{in instantiation of function template specialization 'mixed' requested here}} return mixed(); } + +#ifdef OMP51 +int compare_capture() { + int a, b, c, x; +// omp51-error@+1 {{atomic compare capture is not supported for now}} +#pragma omp atomic compare capture + { + x = a; + if (a == b) + a = c; + } +} +#endif