diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -2149,6 +2149,47 @@ } }; +/// This represents 'compare' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #pragma omp atomic compare +/// \endcode +/// In this example directive '#pragma omp atomic' has 'compare' clause. +class OMPCompareClause : public OMPClause { +public: + /// Build 'compare' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPCompareClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_compare, StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPCompareClause() + : OMPClause(llvm::omp::OMPC_compare, SourceLocation(), SourceLocation()) { + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_compare; + } +}; + /// This represents 'seq_cst' clause in the '#pragma omp atomic' /// directive. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3218,6 +3218,11 @@ return true; } +template +bool RecursiveASTVisitor::VisitOMPCompareClause(OMPCompareClause *) { + return true; +} + template bool RecursiveASTVisitor::VisitOMPSeqCstClause(OMPSeqCstClause *) { return true; diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -2794,16 +2794,34 @@ : OMPExecutableDirective(OMPAtomicDirectiveClass, llvm::omp::OMPD_atomic, SourceLocation(), SourceLocation()) {} + enum DataPositionTy : size_t { + POS_X = 0, + POS_V, + POS_D, + POS_E, + POS_UpdateExpr, + POS_CondExpr, + }; + /// Set 'x' part of the associated expression/statement. - void setX(Expr *X) { Data->getChildren()[0] = X; } + void setX(Expr *X) { Data->getChildren()[DataPositionTy::POS_X] = X; } + /// Set 'v' part of the associated expression/statement. + void setV(Expr *V) { Data->getChildren()[DataPositionTy::POS_V] = V; } + /// Set 'd' part of the associated expression/statement. + void setD(Expr *D) { Data->getChildren()[DataPositionTy::POS_D] = D; } + /// Set 'e' or 'expr' part of the associated expression/statement. + void setE(Expr *E) { Data->getChildren()[DataPositionTy::POS_E] = E; } /// Set helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. - void setUpdateExpr(Expr *UE) { Data->getChildren()[1] = UE; } - /// Set 'v' part of the associated expression/statement. - void setV(Expr *V) { Data->getChildren()[2] = V; } - /// Set 'expr' part of the associated expression/statement. - void setExpr(Expr *E) { Data->getChildren()[3] = E; } + void setUpdateExpr(Expr *UE) { + Data->getChildren()[DataPositionTy::POS_UpdateExpr] = UE; + } + /// Set the conditional expression part of the associated expression/statement + /// in atomic compare. + void setCondExpr(Expr *CE) { + Data->getChildren()[DataPositionTy::POS_CondExpr] = CE; + } public: /// Creates directive with a list of \a Clauses and 'x', 'v' and 'expr' @@ -2828,7 +2846,8 @@ static OMPAtomicDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V, - Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate); + Expr *E, Expr *D, Expr *Ex, Expr *UE, bool IsXLHSInRHSPart, + bool IsPostfixUpdate); /// Creates an empty directive with the place for \a NumClauses /// clauses. @@ -2840,16 +2859,52 @@ unsigned NumClauses, EmptyShell); /// Get 'x' part of the associated expression/statement. - Expr *getX() { return cast_or_null(Data->getChildren()[0]); } + Expr *getX() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_X]); + } const Expr *getX() const { - return cast_or_null(Data->getChildren()[0]); + return cast_or_null(Data->getChildren()[DataPositionTy::POS_X]); + } + /// Get 'd' part of the associated expression/statement. + Expr *getD() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_D]); + } + const Expr *getD() const { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_D]); + } + /// Get 'e' part of the associated expression/statement. + Expr *getE() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_E]); + } + const Expr *getE() const { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_E]); + } + /// Get 'v' part of the associated expression/statement. + Expr *getV() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_V]); + } + const Expr *getV() const { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_V]); } /// Get helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. - Expr *getUpdateExpr() { return cast_or_null(Data->getChildren()[1]); } + Expr *getUpdateExpr() { + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_UpdateExpr]); + } const Expr *getUpdateExpr() const { - return cast_or_null(Data->getChildren()[1]); + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_UpdateExpr]); + } + /// Get the conditional expression. + Expr *getCondExpr() { + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_CondExpr]); + } + const Expr *getCondExpr() const { + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_CondExpr]); } /// Return true if helper update expression has form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form @@ -2858,16 +2913,6 @@ /// Return true if 'v' expression must be updated to original value of /// 'x', false if 'v' must be updated to the new value of 'x'. bool isPostfixUpdate() const { return IsPostfixUpdate; } - /// Get 'v' part of the associated expression/statement. - Expr *getV() { return cast_or_null(Data->getChildren()[2]); } - const Expr *getV() const { - return cast_or_null(Data->getChildren()[2]); - } - /// Get 'expr' part of the associated expression/statement. - Expr *getExpr() { return cast_or_null(Data->getChildren()[3]); } - const Expr *getExpr() const { - return cast_or_null(Data->getChildren()[3]); - } static bool classof(const Stmt *T) { return T->getStmtClass() == OMPAtomicDirectiveClass; 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 @@ -10442,10 +10442,16 @@ " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}'," " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'" " where x is an lvalue expression with scalar type">; +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;}'," + " '{if (x == e) { x = d; } else { v = x; }}', or '{r = x == e; if (r) { x = d; }}', 'r = x == e; if (r) { x = d; } else { v = x; }}'" + " where x, r, v, e are lvalue expressions with scalar type, d is an expression with scalar type, and r must be of intergral 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 note_omp_atomic_compare: Note< + "%select{expected compound statement of size one|expected conditional update statement|expected assignment expression|expected conditional expression|expected binary operator|expected <, > or == for ordop|expected 'x' at false expression|expected 'x' in conditional expression|expected 'x ordop e'|expected lvalue scalar expression|expected scalar expression}0">; def err_omp_atomic_several_clauses : Error< - "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">; + "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">; def err_omp_several_mem_order_clauses : Error< "directive '#pragma omp %0' cannot contain more than one %select{'seq_cst', 'relaxed', |}1'acq_rel', 'acquire' or 'release' clause">; def err_omp_atomic_incompatible_mem_order_clause : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11056,6 +11056,9 @@ /// Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); + /// Called on well-formed 'compare' clause. + OMPClause *ActOnOpenMPCompareClause(SourceLocation StartLoc, + SourceLocation EndLoc); /// Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -126,6 +126,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -215,6 +216,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -1765,6 +1767,10 @@ OS << "capture"; } +void OMPClausePrinter::VisitOMPCompareClause(OMPCompareClause *) { + OS << "compare"; +} + void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) { OS << "seq_cst"; } diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -805,16 +805,20 @@ !IsStandalone); } -OMPAtomicDirective *OMPAtomicDirective::Create( - const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, - ArrayRef Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V, - Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate) { +OMPAtomicDirective * +OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef Clauses, + Stmt *AssociatedStmt, Expr *X, Expr *V, Expr *E, + Expr *D, Expr *UE, Expr *CE, bool IsXLHSInRHSPart, + bool IsPostfixUpdate) { auto *Dir = createDirective( - C, Clauses, AssociatedStmt, /*NumChildren=*/4, StartLoc, EndLoc); + C, Clauses, AssociatedStmt, /*NumChildren=*/6, StartLoc, EndLoc); Dir->setX(X); Dir->setV(V); - Dir->setExpr(E); + Dir->setE(E); + Dir->setD(D); Dir->setUpdateExpr(UE); + Dir->setCondExpr(CE); Dir->IsXLHSInRHSPart = IsXLHSInRHSPart; Dir->IsPostfixUpdate = IsPostfixUpdate; return Dir; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -546,6 +546,8 @@ void OMPClauseProfiler::VisitOMPCaptureClause(const OMPCaptureClause *) {} +void OMPClauseProfiler::VisitOMPCompareClause(const OMPCompareClause *) {} + void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} void OMPClauseProfiler::VisitOMPAcqRelClause(const OMPAcqRelClause *) {} diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -151,6 +151,7 @@ case OMPC_read: case OMPC_write: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -394,6 +395,7 @@ case OMPC_read: case OMPC_write: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: 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 @@ -5566,6 +5566,16 @@ return std::make_pair(true, RValue::get(Res)); } +static std::pair emitOMPAtomicCmpXchg(CodeGenFunction &CGF, + LValue X, RValue E, + RValue D, + llvm::AtomicOrdering AO) { + llvm::Value *Res = CGF.Builder.CreateAtomicCmpXchg( + X.getPointer(CGF), E.getScalarVal(), D.getScalarVal(), AO, AO); + llvm::Value *Old = CGF.Builder.CreateExtractValue(Res, 0); + return std::make_pair(true, RValue::get(Old)); +} + std::pair CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr( LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, llvm::AtomicOrdering AO, SourceLocation Loc, @@ -5762,11 +5772,39 @@ } } +static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF, + llvm::AtomicOrdering AO, const Expr *X, + const Expr *E, const Expr *D, + const Expr *CE, bool IsXLHSInRHSPart, + SourceLocation Loc) { + assert(X->isLValue() && "X of 'omp atomic compare' is not lvalue"); + assert(isa(CE->IgnoreImpCasts()) && + "Cond expr in 'atomic compare' must be a binary operator."); + + auto *CondBO = cast(CE->IgnoreImpCasts()); + + LValue XLValue = CGF.EmitLValue(X); + RValue ERValue = CGF.EmitAnyExpr(E); + + std::pair Res; + + if (CondBO->getOpcode() == BO_EQ) { + RValue DRValue = CGF.EmitAnyExpr(D); + Res = emitOMPAtomicCmpXchg(CGF, XLValue, ERValue, DRValue, AO); + } else + Res = emitOMPAtomicRMW(CGF, XLValue, ERValue, CondBO->getOpcode(), AO, + /* IsXLHSInRHSPart */ false); + // Cannot emit atomic operation. + // TODO: Do we really want to emit a non-atomic operation here? + if (!Res.first) { + } +} + static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, llvm::AtomicOrdering AO, bool IsPostfixUpdate, const Expr *X, const Expr *V, const Expr *E, - const Expr *UE, bool IsXLHSInRHSPart, - SourceLocation Loc) { + const Expr *D, const Expr *UE, const Expr *CE, + bool IsXLHSInRHSPart, SourceLocation Loc) { switch (Kind) { case OMPC_read: emitOMPAtomicReadExpr(CGF, AO, X, V, Loc); @@ -5782,6 +5820,9 @@ emitOMPAtomicCaptureExpr(CGF, AO, IsPostfixUpdate, V, X, E, UE, IsXLHSInRHSPart, Loc); break; + case OMPC_compare: + emitOMPAtomicCompareExpr(CGF, AO, X, E, D, CE, IsXLHSInRHSPart, Loc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -5919,8 +5960,8 @@ LexicalScope Scope(*this, S.getSourceRange()); EmitStopPoint(S.getAssociatedStmt()); emitOMPAtomicExpr(*this, Kind, AO, S.isPostfixUpdate(), S.getX(), S.getV(), - S.getExpr(), S.getUpdateExpr(), S.isXLHSInRHSPart(), - S.getBeginLoc()); + S.getE(), S.getD(), S.getUpdateExpr(), S.getCondExpr(), + S.isXLHSInRHSPart(), S.getBeginLoc()); } static void emitCommonOMPTargetDirective(CodeGenFunction &CGF, diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2883,6 +2883,7 @@ case OMPC_read: case OMPC_write: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: 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 @@ -6274,6 +6274,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -10514,8 +10515,335 @@ bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0, unsigned NoteId = 0); }; + +/// Get the node id of the fixed point of corresponding statement +llvm::FoldingSetNodeID getNodeId(ASTContext &Context, const Expr *S) { + llvm::FoldingSetNodeID Id; + S->IgnoreParenImpCasts()->Profile(Id, Context, true); + return Id; +} + +/// Check if two statemenmts are the same fixed point statements +bool checkIfTwoExprsAreSame(ASTContext &Context, const Expr *LHS, + const Expr *RHS) { + return getNodeId(Context, LHS) == getNodeId(Context, RHS); +} + +// OpenMP 5.1 [2.19.7 atomic Construct] +// cond-update-stmt, a conditional update statement that has one of the +// following forms: +// if (expr ordop x) { x = expr; } +// if (x ordop expr) { x = expr; } +// if (x == e) { x = d; } +bool checkIfCondUpdateStmt(ASTContext &Context, IfStmt *IS, Expr *&X, Expr *&E, + Expr *&D, Expr *&C) { + auto *Cond = dyn_cast(IS->getCond()); + auto *Then = dyn_cast(IS->getThen()); + + if (!Cond || !Then) + return false; + + // The if-stmt cannot have else statement + if (IS->getElse()) + return false; + + // Only ==, <, > are supported + if (Cond->getOpcode() != BO_EQ && Cond->getOpcode() != BO_LT && + Cond->getOpcode() != BO_GT) + return false; + + X = Then->getLHS(); + C = Cond; + + llvm::FoldingSetNodeID XId = getNodeId(Context, X); + llvm::FoldingSetNodeID LHSId = getNodeId(Context, Cond->getLHS()); + llvm::FoldingSetNodeID RHSId = getNodeId(Context, Cond->getRHS()); + + if (Cond->getOpcode() == BO_EQ) { + // if (x == e) { x = d; } + D = Then->getRHS(); + if (LHSId == XId) + E = Cond->getRHS(); + else if (RHSId == XId) + E = Cond->getLHS(); + else + return false; + } else { + // if (expr ordop x) { x = expr; } + // if (x ordop expr) { x = expr; } + E = Then->getRHS(); + + llvm::FoldingSetNodeID EId = getNodeId(Context, E); + if (LHSId == EId) { + if (RHSId != XId) + return false; + } else if (RHSId == EId) { + if (LHSId != XId) + return false; + } else + return false; + } + + return true; +} + +/// Helper class for checking expression in 'omp atomic compare' construct. +class OpenMPAtomicCompareChecker { +protected: + Sema &SemaRef; + ASTContext &Context; + /// 'x' lvalue part of the source atomic expression. + Expr *X = nullptr; + /// Depending on different cases, it can be: + /// 'e' rvalue part of the source atomic expression. + /// 'expr' rvalue part of the source atomic expression. + Expr *E = nullptr; + /// 'd' rvalue part of the source atomic expression. + Expr *D = nullptr; + /// 'cond' rvalue part of the source atomic expression, which is in one of the + /// following forms: + /// expr ordop x + /// x ordop expr + /// x == e + /// Note that when 'x' is on RHS, a corresponding LHS version is generated for + /// easier codegen. + Expr *C = nullptr; + +public: + /// All kinds of errors that can occur in `atomic compare` + enum class ErrorTy { + /// Not only one statement in compound statement + NotOneSubstatement = 0, + /// Not a cond-update statement (ref. spec 5.1) + NotCondUpdateStatement, + /// Not an assignment statement + NotAssignmentStatement, + /// Not a conditional statement + NotCondStatement, + /// Not a binary operator + NotBinaryOperator, + /// Not required ordop (ordop must be <, >, or ==) + NotRequiredOrderOp, + /// 'x' is not at false expression + NotAtFalseExpr, + /// 'x' is not in conditional expression + NotInCondExpr, + /// Not required expression 'x ordop e' or 'e ordop x' + NotAOrdopEExpr, + /// Not a lvalue scalar type expression + NotLValueScalarExpr, + /// Not a scalar type expression + NotScalarExpr, + /// No error + NoError + }; + + /// Error descriptor type which will be returned to Sema + struct ErrorDescTy { + ErrorTy ErrorNo = ErrorTy::NoError; + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + }; + + OpenMPAtomicCompareChecker(Sema &S) + : SemaRef(S), Context(S.getASTContext()) {} + + /// Note: If `checkStatement` returns false, it is undefined behavior to call + /// the following getters. + /// Return the 'x' lvalue part of the source atomic expression. + Expr *getX() const { return X; } + /// Return the 'e' or 'expr' rvalue part of the source atomic expression. + Expr *getE() const { return E; } + /// Return the 'd' rvalue part of the source atomic expression. + Expr *getD() const { return D; } + /// Return the 'cond' rvalue part of the source atomic expression. + Expr *getCondExpr() const { return C; } + + /// Check given statement if it conforms with requiremenet of `atomic + /// compare`, and set `x`, `e`, `d`, `expr` and conditional expr accordingly. + /// if (expr ordop x) { x = expr; } + /// if (x ordop expr) { x = expr; } + /// if (x == e) { x = d; } + /// x = expr ordop x ? expr : x; + /// x = expr ordop x ? expr : x; + /// x = x == e ? d : x; + bool checkStatement(Stmt *S); + + /// Return the error descriptor that will guide the error message emission. + /// Note: it is undefined behavior to call it if `checkStatement` returns + /// true. + ErrorDescTy getErrorDesc() const { return ErrorDesc; } + +protected: + /// Error descriptor + ErrorDescTy ErrorDesc; + /// Check if all results conform with spec in terms of lvalue/rvalue and + /// scalar type. + bool checkResult(); + /// Update {expr ordop x} to {x ordop expr} for easier codegen if needed. + void updateCondExpr(); +}; } // namespace +void OpenMPAtomicCompareChecker::updateCondExpr() { + // We don't apply any correctness check in this function. + auto *Cond = cast(C); + + if (Cond->getOpcode() == BO_EQ) + return; + + if (checkIfTwoExprsAreSame(Context, X, Cond->getLHS())) + return; + + BinaryOperatorKind Op = Cond->getOpcode() == BO_LT ? BO_GT : BO_LT; + ExprResult Result = + SemaRef.CreateBuiltinBinOp(Cond->getOperatorLoc(), Op, X, E); + assert(!Result.isInvalid()); + + C = Result.get(); +} + +bool OpenMPAtomicCompareChecker::checkStatement(Stmt *S) { + auto *CS = dyn_cast(S); + if (CS) { + if (CS->size() != 1) { + ErrorDesc.ErrorNo = ErrorTy::NotOneSubstatement; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = CS->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = CS->getBeginLoc(); + return false; + } + S = CS->body_front(); + } + + // 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; } + if (auto *IS = dyn_cast(S)) { + if (!checkIfCondUpdateStmt(Context, IS, X, E, D, C)) { + ErrorDesc.ErrorNo = ErrorTy::NotCondUpdateStatement; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = IS->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = IS->getBeginLoc(); + return false; + } + + updateCondExpr(); + + return checkResult(); + } + + // 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; + auto *BO = dyn_cast(S); + if (!BO || BO->getOpcode() != BO_Assign) { + ErrorDesc.ErrorNo = ErrorTy::NotAssignmentStatement; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = S->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = S->getBeginLoc(); + return false; + } + + X = BO->getLHS(); + + auto *CO = dyn_cast(BO->getRHS()); + if (!CO) { + ErrorDesc.ErrorNo = ErrorTy::NotCondStatement; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = BO->getRHS()->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = BO->getRHS()->getBeginLoc(); + return false; + } + + if (!checkIfTwoExprsAreSame(Context, X, CO->getFalseExpr())) { + ErrorDesc.ErrorNo = ErrorTy::NotAtFalseExpr; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = + CO->getFalseExpr()->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = CO->getFalseExpr()->getExprLoc(); + return false; + } + + auto *Cond = dyn_cast(CO->getCond()); + if (!Cond) { + ErrorDesc.ErrorNo = ErrorTy::NotBinaryOperator; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = + CO->getCond()->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = CO->getCond()->getBeginLoc(); + return false; + } + + // Only ==, <, > are supported + if (Cond->getOpcode() != BO_LT && Cond->getOpcode() != BO_GT && + Cond->getOpcode() != BO_EQ) { + ErrorDesc.ErrorNo = ErrorTy::NotRequiredOrderOp; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = Cond->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = Cond->getOperatorLoc(); + return false; + } + + if (Cond->getOpcode() == BO_EQ) { + if (checkIfTwoExprsAreSame(Context, X, Cond->getLHS())) + E = Cond->getRHS(); + else if (checkIfTwoExprsAreSame(Context, X, Cond->getRHS())) + E = Cond->getLHS(); + else { + ErrorDesc.ErrorNo = ErrorTy::NotInCondExpr; + ErrorDesc.NoteRange = ErrorDesc.ErrorRange = Cond->getSourceRange(); + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = Cond->getExprLoc(); + return false; + } + D = CO->getTrueExpr(); + } else { + E = CO->getTrueExpr(); + if (!((checkIfTwoExprsAreSame(Context, X, Cond->getLHS()) && + checkIfTwoExprsAreSame(Context, E, Cond->getRHS())) || + (checkIfTwoExprsAreSame(Context, X, Cond->getRHS()) && + checkIfTwoExprsAreSame(Context, E, Cond->getLHS())))) { + ErrorDesc.ErrorNo = ErrorTy::NotAOrdopEExpr; + ErrorDesc.ErrorRange = Cond->getSourceRange(); + ErrorDesc.NoteRange = X->getSourceRange(); + ErrorDesc.ErrorLoc = Cond->getExprLoc(); + ErrorDesc.NoteLoc = X->getExprLoc(); + return false; + } + } + + C = Cond; + + updateCondExpr(); + + return checkResult(); +} + +bool OpenMPAtomicCompareChecker::checkResult() { + // 'x' and 'e' cannot be nullptr + assert(X && E && "X and E cannot be nullptr"); + + // 'x' and 'e' have to be scalar type. 'x' has to be lvalue, but no such this + // requirement for 'e' and 'd'. + if (!X->isLValue() || !X->getType()->isScalarType()) { + ErrorDesc.ErrorNo = ErrorTy::NotLValueScalarExpr; + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = X->getExprLoc(); + ErrorDesc.ErrorRange = ErrorDesc.NoteRange = X->getSourceRange(); + return false; + } + + if (!E->getType()->isScalarType()) { + ErrorDesc.ErrorNo = ErrorTy::NotScalarExpr; + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = E->getExprLoc(); + ErrorDesc.ErrorRange = ErrorDesc.NoteRange = E->getSourceRange(); + return false; + } + + if (D && !D->getType()->isScalarType()) { + ErrorDesc.ErrorNo = ErrorTy::NotScalarExpr; + ErrorDesc.NoteLoc = ErrorDesc.ErrorLoc = D->getExprLoc(); + ErrorDesc.ErrorRange = ErrorDesc.NoteRange = D->getSourceRange(); + return false; + } + + return true; +} + bool OpenMPAtomicUpdateChecker::checkBinaryOperation( BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) { ExprAnalysisErrorCode ErrorFound = NoError; @@ -10695,24 +11023,30 @@ OpenMPClauseKind MemOrderKind = OMPC_unknown; SourceLocation MemOrderLoc; for (const OMPClause *C : Clauses) { - if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || - C->getClauseKind() == OMPC_update || - C->getClauseKind() == OMPC_capture) { - if (AtomicKind != OMPC_unknown) { + switch (C->getClauseKind()) { + default: + llvm_unreachable("unknow clause for atomic directive"); + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_compare: + if (AtomicKind == OMPC_unknown) { + AtomicKind = C->getClauseKind(); + AtomicKindLoc = C->getBeginLoc(); + break; + } else { Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses) << SourceRange(C->getBeginLoc(), C->getEndLoc()); Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause) << getOpenMPClauseName(AtomicKind); - } else { - AtomicKind = C->getClauseKind(); - AtomicKindLoc = C->getBeginLoc(); + return StmtError(); } - } - if (C->getClauseKind() == OMPC_seq_cst || - C->getClauseKind() == OMPC_acq_rel || - C->getClauseKind() == OMPC_acquire || - C->getClauseKind() == OMPC_release || - C->getClauseKind() == OMPC_relaxed) { + case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: if (MemOrderKind != OMPC_unknown) { Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses) << getOpenMPDirectiveName(OMPD_atomic) << 0 @@ -10723,8 +11057,10 @@ MemOrderKind = C->getClauseKind(); MemOrderLoc = C->getBeginLoc(); } + break; } } + // 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. @@ -10752,10 +11088,18 @@ if (auto *EWC = dyn_cast(Body)) Body = EWC->getSubExpr(); + // Stands for 'x' in the spec Expr *X = nullptr; + // Stands for 'v' in the spec Expr *V = nullptr; + // Stands for 'd' in the spec + Expr *D = nullptr; + // Stands for 'e' or 'expr' in the spec Expr *E = nullptr; + // Stands for update-stmt in the spec Expr *UE = nullptr; + // Stands for conditional statement in the spec + Expr *CE = nullptr; bool IsXLHSInRHSPart = false; bool IsPostfixUpdate = false; // OpenMP [2.12.6, atomic Construct] @@ -10837,8 +11181,8 @@ if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement) << ErrorRange; - Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound - << NoteRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) + << ErrorFound << NoteRange; return StmtError(); } if (CurContext->isDependentContext()) @@ -10899,8 +11243,8 @@ if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement) << ErrorRange; - Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound - << NoteRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) + << ErrorFound << NoteRange; return StmtError(); } if (CurContext->isDependentContext()) @@ -10916,9 +11260,10 @@ // x = expr binop x; OpenMPAtomicUpdateChecker Checker(*this); if (Checker.checkStatement( - Body, (AtomicKind == OMPC_update) - ? diag::err_omp_atomic_update_not_expression_statement - : diag::err_omp_atomic_not_expression_statement, + Body, + (AtomicKind == OMPC_update) + ? diag::err_omp_atomic_update_not_expression_statement + : diag::err_omp_atomic_not_expression_statement, diag::note_omp_atomic_update)) return StmtError(); if (!CurContext->isDependentContext()) { @@ -11132,21 +11477,37 @@ SourceRange(Body->getBeginLoc(), Body->getBeginLoc()); ErrorFound = NotACompoundStatement; } - if (ErrorFound != NoError) { - Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement) - << ErrorRange; - Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; - return StmtError(); - } - if (CurContext->isDependentContext()) - UE = V = E = X = nullptr; } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; + return StmtError(); + } + if (CurContext->isDependentContext()) + UE = V = E = X = nullptr; + } else if (AtomicKind == OMPC_compare) { + // TODO: error handling + OpenMPAtomicCompareChecker Checker(*this); + if (!Checker.checkStatement(Body)) { + OpenMPAtomicCompareChecker::ErrorDescTy Err = Checker.getErrorDesc(); + Diag(Err.ErrorLoc, diag::err_omp_atomic_compare) << Err.ErrorRange; + Diag(Err.NoteLoc, diag::note_omp_atomic_compare) + << static_cast(Err.ErrorNo) << Err.NoteRange; + return StmtError(); + } + X = Checker.getX(); + E = Checker.getE(); + D = Checker.getD(); + CE = Checker.getCondExpr(); + if (CurContext->isDependentContext()) + X = E = D = CE = nullptr; } setFunctionHasBranchProtectedScope(); return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, - X, V, E, UE, IsXLHSInRHSPart, + X, V, E, D, UE, CE, IsXLHSInRHSPart, IsPostfixUpdate); } @@ -13215,6 +13576,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -14019,6 +14381,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -14475,6 +14838,7 @@ case OMPC_read: case OMPC_write: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -14768,6 +15132,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: @@ -14954,6 +15319,9 @@ case OMPC_capture: Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc); break; + case OMPC_compare: + Res = ActOnOpenMPCompareClause(StartLoc, EndLoc); + break; case OMPC_seq_cst: Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); break; @@ -15099,6 +15467,11 @@ return new (Context) OMPCaptureClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPCompareClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPCompareClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPSeqCstClause(StartLoc, EndLoc); @@ -15567,6 +15940,7 @@ case OMPC_write: case OMPC_update: case OMPC_capture: + case OMPC_compare: case OMPC_seq_cst: case OMPC_acq_rel: case OMPC_acquire: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9381,6 +9381,13 @@ return C; } +template +OMPClause * +TreeTransform::TransformOMPCompareClause(OMPCompareClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + template OMPClause * TreeTransform::TransformOMPSeqCstClause(OMPSeqCstClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11779,6 +11779,9 @@ case llvm::omp::OMPC_capture: C = new (Context) OMPCaptureClause(); break; + case llvm::omp::OMPC_compare: + C = new (Context) OMPCompareClause(); + break; case llvm::omp::OMPC_seq_cst: C = new (Context) OMPSeqCstClause(); break; @@ -12131,6 +12134,8 @@ void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {} +void OMPClauseReader::VisitOMPCompareClause(OMPCompareClause *) {} + void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {} void OMPClauseReader::VisitOMPAcqRelClause(OMPAcqRelClause *) {} diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6135,6 +6135,8 @@ void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {} +void OMPClauseWriter::VisitOMPCompareClause(OMPCompareClause *) {} + void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {} void OMPClauseWriter::VisitOMPAcqRelClause(OMPAcqRelClause *) {} diff --git a/clang/test/OpenMP/atomic_compare_codegen.cpp b/clang/test/OpenMP/atomic_compare_codegen.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/atomic_compare_codegen.cpp @@ -0,0 +1,985 @@ + +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s + +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp-simd -fopenmp-version=51 -x c -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// SIMD-ONLY0-NOT: {{__kmpc|__tgt}} +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +_Bool bv, bx; +char cv, cx; +unsigned char ucv, ucx; +short sv, sx; +unsigned short usv, usx; +int iv, ix; +unsigned int uiv, uix; +long lv, lx; +unsigned long ulv, ulx; +long long llv, llx; +unsigned long long ullv, ullx; +float fv, fx; +double dv, dx; +long double ldv, ldx; +_Complex int civ, cix; +_Complex float cfv, cfx; +_Complex double cdv, cdx; + +typedef int int4 __attribute__((__vector_size__(16))); +int4 int4x; + +struct BitFields { + int : 32; + int a : 31; +} bfx; + +struct BitFields_packed { + int : 32; + int a : 31; +} __attribute__ ((__packed__)) bfx_packed; + +struct BitFields2 { + int : 31; + int a : 1; +} bfx2; + +struct BitFields2_packed { + int : 31; + int a : 1; +} __attribute__ ((__packed__)) bfx2_packed; + +struct BitFields3 { + int : 11; + int a : 14; +} bfx3; + +struct BitFields3_packed { + int : 11; + int a : 14; +} __attribute__ ((__packed__)) bfx3_packed; + +struct BitFields4 { + short : 16; + int a: 1; + long b : 7; +} bfx4; + +struct BitFields4_packed { + short : 16; + int a: 1; + long b : 7; +} __attribute__ ((__packed__)) bfx4_packed; + +typedef float float2 __attribute__((ext_vector_type(2))); +float2 float2x; + +// Register "0" is currently an invalid register for global register variables. +// Use "esp" instead of "0". +// register int rix __asm__("0"); +register int rix __asm__("esp"); + +int main() { +// CHECK: [[PREV:%.+]] = atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: store i8 [[PREV]], i8* @{{.+}}, +#pragma omp atomic compare + bv = bx++; +// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: add nsw i32 %{{.+}}, 1 +// CHECK: store i8 %{{.+}}, i8* @{{.+}}, +#pragma omp atomic compare + cv = ++cx; +// CHECK: [[PREV:%.+]] = atomicrmw sub i8* @{{.+}}, i8 1 monotonic, align 1 +// CHECK: store i8 [[PREV]], i8* @{{.+}}, +#pragma omp atomic compare + ucv = ucx--; +// CHECK: atomicrmw sub i16* @{{.+}}, i16 1 monotonic, align 2 +// CHECK: sub nsw i32 %{{.+}}, 1 +// CHECK: store i16 %{{.+}}, i16* @{{.+}}, +#pragma omp atomic compare + sv = --sx; +// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i32 +// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32 +// CHECK: [[ADD:%.+]] = add nsw i32 [[CONV]], [[EXPR]] +// CHECK: [[DESIRED_CALC:%.+]] = trunc i32 [[ADD]] to i16 +// CHECK: store i16 [[DESIRED_CALC]], i16* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i16 [[DESIRED_CALC]], i16* @{{.+}}, +#pragma omp atomic compare + sv = usx += usv; +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[DESIRED_CALC:%.+]] = mul nsw i32 [[EXPECTED]], [[EXPR]] +// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +#pragma omp atomic compare + uiv = ix *= iv; +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, +// CHECK: [[PREV:%.+]] = atomicrmw sub i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: store i32 [[PREV]], i32* @{{.+}}, +#pragma omp atomic compare + {iv = uix; uix -= uiv;} +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[DESIRED_CALC:%.+]] = shl i32 [[EXPECTED]], [[EXPR]] +// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +#pragma omp atomic compare + {ix <<= iv; uiv = ix;} +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[DESIRED_CALC:%.+]] = lshr i32 [[EXPECTED]], [[EXPR]] +// CHECK: store i32 [[DESIRED_CALC]], i32* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[DESIRED_CALC]], i32* @{{.+}}, +#pragma omp atomic compare + iv = uix >>= uiv; +// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[DESIRED:%.+]] = sdiv i64 [[EXPECTED]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i64 [[EXPECTED]], i64* @{{.+}}, +#pragma omp atomic compare + {ulv = lx; lx /= lv;} +// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[DESIRED:%.+]] = and i64 [[OLD]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +#pragma omp atomic compare + {ulx &= ulv; lv = ulx;} +// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw xor i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[DESIRED:%.+]] = xor i64 [[OLD]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +#pragma omp atomic compare + ullv = llx ^= llv; +// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[OLD:%.+]] = atomicrmw or i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[DESIRED:%.+]] = or i64 [[OLD]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +#pragma omp atomic compare + llv = ullx |= ullv; +// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I:%.+]] = bitcast float* [[TEMP:%.+]] to i32* +// CHECK: [[OLD:%.+]] = bitcast i32 [[EXPECTED]] to float +// CHECK: [[ADD:%.+]] = fadd float [[OLD]], [[EXPR]] +// CHECK: store float [[ADD]], float* [[TEMP]], +// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP_I]], +// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: [[OLD_X:%.+]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[CAST:%.+]] = fpext float [[ADD]] to double +// CHECK: store double [[CAST]], double* @{{.+}}, +#pragma omp atomic compare + dv = fx = fx + fv; +// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I:%.+]] = bitcast double* [[TEMP:%.+]] to i64* +// CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double +// CHECK: [[SUB:%.+]] = fsub double [[EXPR]], [[OLD]] +// CHECK: store double [[SUB]], double* [[TEMP]], +// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP_I]], +// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[CAST:%.+]] = fptrunc double [[OLD]] to float +// CHECK: store float [[CAST]], float* @{{.+}}, +#pragma omp atomic compare + {fv = dx; dx = dv - dx;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i128 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* +// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST]] +// CHECK: [[BITCAST1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* +// CHECK: store i128 [[EXPECTED]], i128* [[BITCAST1]] +// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP1]] +// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[OLD]], [[EXPR]] +// CHECK: store x86_fp80 [[MUL]], x86_fp80* [[TEMP]] +// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST]] +// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: [[OLD_X:%.+]] = extractvalue { i128, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[CAST:%.+]] = fptrunc x86_fp80 [[MUL]] to double +// CHECK: store double [[CAST]], double* @{{.+}}, +#pragma omp atomic compare + {ldx = ldx * ldv; dv = ldx;} +// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0) +// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1) +// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[LD_RE:%.+]] = load i32, i32* [[LD_RE_ADDR]] +// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[LD_IM:%.+]] = load i32, i32* [[LD_IM_ADDR]] +// +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 [[NEW_RE:%.+]], i32* [[X_RE_ADDR]] +// CHECK: store i32 [[NEW_IM:%.+]], i32* [[X_IM_ADDR]] +// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* +// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0) +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[RE_CAST:%.+]] = sitofp i32 [[NEW_RE]] to float +// CHECK: [[IM_CAST:%.+]] = sitofp i32 [[NEW_IM]] to float +// CHECK: store float [[RE_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0), +// CHECK: store float [[IM_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1), +#pragma omp atomic compare + cfv = cix = civ / cix; +// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0) +// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1) +// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ float, float }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE_OLD:%.+]] = load float, float* [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM_OLD:%.+]] = load float, float* [[X_IM_ADDR]] +// +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store float [[NEW_RE:%.+]], float* [[X_RE_ADDR]] +// CHECK: store float [[NEW_IM:%.+]], float* [[X_IM_ADDR]] +// CHECK: [[EXPECTED:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR]] to i8* +// CHECK: [[DESIRED:%.+]] = bitcast { float, float }* [[DESIRED_ADDR]] to i8* +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ float, float }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0) +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[RE_CAST:%.+]] = fptosi float [[X_RE_OLD]] to i32 +// CHECK: [[IM_CAST:%.+]] = fptosi float [[X_IM_OLD]] to i32 +// CHECK: store i32 [[RE_CAST]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), +// CHECK: store i32 [[IM_CAST]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +#pragma omp atomic compare + {civ = cfx; cfx = cfv + cfx;} +// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0) +// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1) +// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 16, i8* bitcast ({ double, double }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 5) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load double, double* [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load double, double* [[X_IM_ADDR]] +// +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store double [[NEW_RE:%.+]], double* [[X_RE_ADDR]] +// CHECK: store double [[NEW_IM:%.+]], double* [[X_IM_ADDR]] +// CHECK: [[EXPECTED:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR]] to i8* +// CHECK: [[DESIRED:%.+]] = bitcast { double, double }* [[DESIRED_ADDR]] to i8* +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 16, i8* bitcast ({ double, double }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 5, i32 5) +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[RE_CAST:%.+]] = fptrunc double [[NEW_RE]] to float +// CHECK: [[IM_CAST:%.+]] = fptrunc double [[NEW_IM]] to float +// CHECK: store float [[RE_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0), +// CHECK: store float [[IM_CAST]], float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1), +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare seq_cst + {cdx = cdx - cdv; cfv = cdx;} +// CHECK: [[BV:%.+]] = load i8, i8* @{{.+}} +// CHECK: [[BOOL:%.+]] = trunc i8 [[BV]] to i1 +// CHECK: [[EXPR:%.+]] = zext i1 [[BOOL]] to i64 +// CHECK: [[OLD:%.+]] = atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic, align 8 +// CHECK: [[DESIRED:%.+]] = and i64 [[OLD]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* @{{.+}}, +#pragma omp atomic compare + ulv = ulx = ulx & bv; +// CHECK: [[CV:%.+]] = load i8, i8* @{{.+}}, align 1 +// CHECK: [[EXPR:%.+]] = sext i8 [[CV]] to i32 +// CHECK: [[X:%.+]] = load atomic i8, i8* [[BX_ADDR:@.+]] monotonic, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[OLD_BOOL:%.+]] = trunc i8 [[EXPECTED]] to i1 +// CHECK: [[X_RVAL:%.+]] = zext i1 [[OLD_BOOL]] to i32 +// CHECK: [[AND:%.+]] = and i32 [[EXPR]], [[X_RVAL]] +// CHECK: [[CAST:%.+]] = icmp ne i32 [[AND]], 0 +// CHECK: [[NEW:%.+]] = zext i1 [[CAST]] to i8 +// CHECK: store i8 [[NEW]], i8* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i8* [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: [[OLD:%.+]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[OLD_I8:%.+]] = zext i1 [[OLD_BOOL]] to i8 +// CHECK: store i8 [[OLD_I8]], i8* @{{.+}}, +#pragma omp atomic compare + {bv = bx; bx = cv & bx;} +// CHECK: [[UCV:%.+]] = load i8, i8* @{{.+}}, +// CHECK: [[EXPR:%.+]] = zext i8 [[UCV]] to i32 +// CHECK: [[X:%.+]] = load atomic i8, i8* [[CX_ADDR:@.+]] seq_cst, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[X_RVAL:%.+]] = sext i8 [[EXPECTED]] to i32 +// CHECK: [[ASHR:%.+]] = ashr i32 [[X_RVAL]], [[EXPR]] +// CHECK: [[NEW:%.+]] = trunc i32 [[ASHR]] to i8 +// CHECK: store i8 [[NEW]], i8* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i8* [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst, align 1 +// CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i8 [[NEW]], i8* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare, seq_cst + {cx = cx >> ucv; cv = cx;} +// CHECK: [[SV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[EXPR:%.+]] = sext i16 [[SV]] to i32 +// CHECK: [[X:%.+]] = load atomic i64, i64* [[ULX_ADDR:@.+]] monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[X_RVAL:%.+]] = trunc i64 [[EXPECTED]] to i32 +// CHECK: [[SHL:%.+]] = shl i32 [[EXPR]], [[X_RVAL]] +// CHECK: [[NEW:%.+]] = sext i32 [[SHL]] to i64 +// CHECK: store i64 [[NEW]], i64* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i64* [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i64 [[NEW]], i64* @{{.+}}, +#pragma omp atomic compare + ulv = ulx = sv << ulx; +// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}}, +// CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i64 +// CHECK: [[X:%.+]] = load atomic i64, i64* [[LX_ADDR:@.+]] monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[DESIRED:%.+]] = srem i64 [[EXPECTED]], [[EXPR]] +// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i64* [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i64 [[EXPECTED]], i64* @{{.+}}, +#pragma omp atomic compare + {lv = lx; lx = lx % usv;} +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} +// CHECK: [[OLD:%.+]] = atomicrmw or i32* @{{.+}}, i32 [[EXPR]] seq_cst, align 4 +// CHECK: [[DESIRED:%.+]] = or i32 [[EXPR]], [[OLD]] +// CHECK: store i32 [[DESIRED]], i32* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic seq_cst, compare + {uix = iv | uix; uiv = uix;} +// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}} +// CHECK: [[OLD:%.+]] = atomicrmw and i32* @{{.+}}, i32 [[EXPR]] monotonic, align 4 +// CHECK: [[DESIRED:%.+]] = and i32 [[OLD]], [[EXPR]] +// CHECK: store i32 [[DESIRED]], i32* @{{.+}}, +#pragma omp atomic compare + iv = ix = ix & uiv; +// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[OLD_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[OLD_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]] +// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]] +// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* +// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0) +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[OLD_RE]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), +// CHECK: store i32 [[OLD_IM]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +#pragma omp atomic compare + {civ = cix; cix = lv + cix;} +// CHECK: [[ULV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[EXPR:%.+]] = uitofp i64 [[ULV]] to float +// CHECK: [[X:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I:%.+]] = bitcast float* [[TEMP:%.+]] to i32* +// CHECK: [[OLD:%.+]] = bitcast i32 [[EXPECTED]] to float +// CHECK: [[MUL:%.+]] = fmul float [[OLD]], [[EXPR]] +// CHECK: store float [[MUL]], float* [[TEMP]], +// CHECK: [[DESIRED:%.+]] = load i32, i32* [[TEMP_I]], +// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic, align 4 +// CHECK: [[OLD_X:%.+]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store float [[MUL]], float* @{{.+}}, +#pragma omp atomic compare + {fx = fx * ulv; fv = fx;} +// CHECK: [[LLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[EXPR:%.+]] = sitofp i64 [[LLV]] to double +// CHECK: [[X:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I:%.+]] = bitcast double* [[TEMP:%.+]] to i64* +// CHECK: [[OLD:%.+]] = bitcast i64 [[EXPECTED]] to double +// CHECK: [[DIV:%.+]] = fdiv double [[OLD]], [[EXPR]] +// CHECK: store double [[DIV]], double* [[TEMP]], +// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP_I]], +// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic, align 8 +// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store double [[DIV]], double* @{{.+}}, +#pragma omp atomic compare + dv = dx /= llv; +// CHECK: [[ULLV:%.+]] = load i64, i64* @{{.+}}, +// CHECK: [[EXPR:%.+]] = uitofp i64 [[ULLV]] to x86_fp80 +// CHECK: [[X:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic, align 16 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i128 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I1:%.+]] = bitcast x86_fp80* [[TEMP1:%.+]] to i128* +// CHECK: store i128 [[EXPECTED]], i128* [[TEMP_I1]], +// CHECK: [[TEMP_I:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128* +// CHECK: store i128 [[EXPECTED]], i128* [[TEMP_I]], +// CHECK: [[OLD:%.+]] = load x86_fp80, x86_fp80* [[TEMP]], +// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[OLD]], [[EXPR]] +// CHECK: store x86_fp80 [[SUB]], x86_fp80* [[TEMP1]] +// CHECK: [[DESIRED:%.+]] = load i128, i128* [[TEMP_I1]] +// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic, align 16 +// CHECK: [[OLD_X:%.+]] = extractvalue { i128, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store x86_fp80 [[OLD]], x86_fp80* @{{.+}}, +#pragma omp atomic compare + {ldv = ldx; ldx -= ullv;} +// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}}, +// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 0 +// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]] +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1 +// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]] +// +// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0 +// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1 +// CHECK: store i32 [[NEW_RE:%.+]], i32* [[X_RE_ADDR]] +// CHECK: store i32 [[NEW_IM:%.+]], i32* [[X_IM_ADDR]] +// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8* +// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8* +// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0) +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[NEW_RE]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0), +// CHECK: store i32 [[NEW_IM]], i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1), +#pragma omp atomic compare + {cix = fv / cix; civ = cix;} +// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, +// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic, align 2 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[CONV:%.+]] = sext i16 [[EXPECTED]] to i32 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to double +// CHECK: [[ADD:%.+]] = fadd double [[X_RVAL]], [[EXPR]] +// CHECK: [[NEW:%.+]] = fptosi double [[ADD]] to i16 +// CHECK: store i16 [[NEW]], i16* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic, align 2 +// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i16 [[NEW]], i16* @{{.+}}, +#pragma omp atomic compare + sv = sx = sx + dv; +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}, +// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[BOOL_EXPECTED:%.+]] = trunc i8 [[EXPECTED]] to i1 +// CHECK: [[CONV:%.+]] = zext i1 [[BOOL_EXPECTED]] to i32 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to x86_fp80 +// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[EXPR]], [[X_RVAL]] +// CHECK: [[BOOL_DESIRED:%.+]] = fcmp une x86_fp80 [[MUL]], 0xK00000000000000000000 +// CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 +// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[EXPECTED_I8:%.+]] = zext i1 [[BOOL_EXPECTED]] to i8 +// CHECK: store i8 [[EXPECTED_I8]], i8* @{{.+}}, +#pragma omp atomic compare + {bv = bx; bx = ldv * bx;} +// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR:@.+]], i32 0, i32 0), +// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR]], i32 0, i32 1), +// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[EXPECTED:%.+]] = phi i8 [ [[XI8]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] +// CHECK: [[BOOL_EXPECTED:%.+]] = trunc i8 [[EXPECTED]] to i1 +// CHECK: [[X_RVAL:%.+]] = zext i1 [[BOOL_EXPECTED]] to i32 +// CHECK: [[SUB_RE:%.+]] = sub i32 [[EXPR_RE:%.+]], [[X_RVAL]] +// CHECK: [[SUB_IM:%.+]] = sub i32 [[EXPR_IM:%.+]], 0 +// CHECK: icmp ne i32 [[SUB_RE]], 0 +// CHECK: icmp ne i32 [[SUB_IM]], 0 +// CHECK: [[BOOL_DESIRED:%.+]] = or i1 +// CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 +// CHECK: store i8 [[DESIRED]], i8* [[TEMP:%.+]], +// CHECK: [[DESIRED:%.+]] = load i8, i8* [[TEMP]], +// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic, align 1 +// CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[DESIRED_I8:%.+]] = zext i1 [[BOOL_DESIRED]] to i8 +// CHECK: store i8 [[DESIRED_I8]], i8* @{{.+}}, +#pragma omp atomic compare + {bx = civ - bx; bv = bx;} +// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}} +// CHECK: load i8, i8* +// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32 +// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* [[DEST:@.+]] to i128*) monotonic, align 16 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_I128:%.+]] = phi i128 [ [[I128VAL]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: [[TEMP_I:%.+]] = bitcast <4 x i32>* [[TEMP:%.+]] to i128* +// CHECK: store i128 [[OLD_I128]], i128* [[TEMP_I]], +// CHECK: [[LD:%.+]] = bitcast i128 [[OLD_I128]] to <4 x i32> +// CHECK: store <4 x i32> [[LD]], <4 x i32>* [[TEMP1:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[TEMP1]] +// CHECK: [[ITEM:%.+]] = extractelement <4 x i32> [[VEC_VAL]], i16 [[IDX]] +// CHECK: [[OR:%.+]] = or i32 [[ITEM]], [[VEC_ITEM_VAL]] +// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[TEMP]] +// CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <4 x i32> [[VEC_VAL]], i32 [[OR]], i16 [[IDX]] +// CHECK: store <4 x i32> [[NEW_VEC_VAL]], <4 x i32>* [[TEMP]] +// CHECK: [[NEW_I128:%.+]] = load i128, i128* [[TEMP_I]], +// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (<4 x i32>* [[DEST]] to i128*), i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic, align 16 +// CHECK: [[FAILED_OLD_VAL:%.+]] = extractvalue { i128, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[OR]], i32* @{{.+}}, +#pragma omp atomic compare + {int4x[sv] |= bv; iv = int4x[sv];} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*) monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 +// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 +// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 +// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 +// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 +// CHECK: [[BF_SET:%.+]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i32 [[BF_SET]], i32* [[TEMP1]], +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[CONV]], i32* @{{.+}}, +#pragma omp atomic compare + iv = bfx.a = bfx.a - ldv; +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[BITCAST:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8* +// CHECK: call void @__atomic_load(i64 4, i8* getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD:%.+]] = load i32, i32* [[LDTEMP]], +// CHECK: store i32 [[OLD]], i32* [[TEMP1:%.+]], +// CHECK: [[OLD:%.+]] = load i32, i32* [[LDTEMP]], +// CHECK: store i32 [[OLD]], i32* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1 +// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 +// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[MUL]] to i32 +// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647 +// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648 +// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] +// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* [[LDTEMP]] to i8* +// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* [[TEMP1]] to i8* +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 4, i8* getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* [[BITCAST_TEMP_OLD_BF_ADDR]], i8* [[BITCAST_TEMP_NEW_BF_ADDR]], i32 0, i32 0) +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[A_ASHR]], i32* @{{.+}}, +#pragma omp atomic compare + {iv = bfx_packed.a; bfx_packed.a *= ldv;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_LD]], 31 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 +// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32 +// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_AND:%.+]] = and i32 [[CONV]], 1 +// CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 31 +// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], 2147483647 +// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[CONV]], i32* @{{.+}}, +#pragma omp atomic compare + {bfx2.a -= ldv; iv = bfx2.a;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3) monotonic, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: [[BITCAST_NEW:%.+]] = bitcast i32* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST_NEW]], +// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], +// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 7 +// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i32 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80 +// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[EXPR]], [[X_RVAL]] +// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 +// CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i8 +// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST_NEW]], +// CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 1 +// CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 7 +// CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 127 +// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i8 %{{.+}}, i8* [[BITCAST_NEW]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST_NEW]] +// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +#pragma omp atomic compare + iv = bfx2_packed.a = ldv / bfx2_packed.a; +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0) monotonic, align 4 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP1:%.+]], +// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]], +// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 7 +// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 18 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80 +// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32 +// CHECK: [[BF_LD:%.+]] = load i32, i32* [[TEMP1]], +// CHECK: [[BF_AND:%.+]] = and i32 [[NEW_VAL]], 16383 +// CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 11 +// CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -33552385 +// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i32 %{{.+}}, i32* [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic, align 4 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[A_ASHR]], i32* @{{.+}}, +#pragma omp atomic compare + {iv = bfx3.a; bfx3.a /= ldv;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[LDTEMP:%.+]] = bitcast i32* %{{.+}} to i24* +// CHECK: [[BITCAST:%.+]] = bitcast i24* [[LDTEMP]] to i8* +// CHECK: call void @__atomic_load(i64 3, i8* getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* [[BITCAST]], i32 0) +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD:%.+]] = load i24, i24* [[LDTEMP]], +// CHECK: store i24 [[OLD]], i24* [[BITCAST2:%.+]], +// CHECK: [[OLD:%.+]] = load i24, i24* [[LDTEMP]], +// CHECK: store i24 [[OLD]], i24* [[BITCAST1:%.+]], +// CHECK: [[A_LD:%.+]] = load i24, i24* [[BITCAST1]], +// CHECK: [[A_SHL:%.+]] = shl i24 [[A_LD]], 7 +// CHECK: [[A_ASHR:%.+]] = ashr i24 [[A_SHL]], 10 +// CHECK: [[CAST:%.+]] = sext i24 [[A_ASHR]] to i32 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80 +// CHECK: [[ADD:%.+]] = fadd x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i32 +// CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i24 +// CHECK: [[BF_LD:%.+]] = load i24, i24* [[BITCAST2]], +// CHECK: [[BF_AND:%.+]] = and i24 [[TRUNC]], 16383 +// CHECK: [[BF_VALUE:%.+]] = shl i24 [[BF_AND]], 3 +// CHECK: [[BF_CLEAR:%.+]] = and i24 [[BF_LD]], -131065 +// CHECK: or i24 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i24 %{{.+}}, i24* [[BITCAST2]] +// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i24* [[LDTEMP]] to i8* +// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i24* [[BITCAST2]] to i8* +// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 3, i8* getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* [[BITCAST_TEMP_OLD_BF_ADDR]], i8* [[BITCAST_TEMP_NEW_BF_ADDR]], i32 0, i32 0) +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +#pragma omp atomic compare + {bfx3_packed.a += ldv; iv = bfx3_packed.a;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 47 +// CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 63 +// CHECK: [[A_CAST:%.+]] = trunc i64 [[A_ASHR:%.+]] to i32 +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST:%.+]] to x86_fp80 +// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]] +// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[MUL]] to i32 +// CHECK: [[ZEXT:%.+]] = zext i32 [[NEW_VAL]] to i64 +// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_AND:%.+]] = and i64 [[ZEXT]], 1 +// CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 16 +// CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -65537 +// CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i64 %{{.+}}, i64* [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic, align 8 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +#pragma omp atomic relaxed compare + iv = bfx4.a = bfx4.a * ldv; +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: [[BITCAST1:%.+]] = bitcast i32* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], +// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], +// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: [[A_SHL:%.+]] = shl i8 [[A_LD]], 7 +// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_SHL:%.+]], 7 +// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR:%.+]] to i32 +// CHECK: [[CONV:%.+]] = sitofp i32 [[CAST]] to x86_fp80 +// CHECK: [[SUB: %.+]] = fsub x86_fp80 [[CONV]], [[EXPR]] +// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB:%.+]] to i32 +// CHECK: [[NEW_VAL:%.+]] = trunc i32 [[CONV]] to i8 +// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_VALUE:%.+]] = and i8 [[NEW_VAL]], 1 +// CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], -2 +// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic, align 1 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store i32 [[CAST]], i32* @{{.+}}, +#pragma omp atomic compare relaxed + {iv = bfx4_packed.a; bfx4_packed.a -= ldv;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP1:%.+]], +// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]], +// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]], +// CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 40 +// CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 57 +// CHECK: [[CONV:%.+]] = sitofp i64 [[A_ASHR]] to x86_fp80 +// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[CONV]], [[EXPR]] +// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[DIV]] to i64 +// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP1]], +// CHECK: [[BF_AND:%.+]] = and i64 [[CONV]], 127 +// CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND:%.+]], 17 +// CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -16646145 +// CHECK: [[VAL:%.+]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i64 [[VAL]], i64* [[TEMP1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[TEMP1]] +// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] release monotonic, align 8 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[NEW_VAL:%.+]] = trunc i64 [[CONV]] to i32 +// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare release + {bfx4.b /= ldv; iv = bfx4.b;} +// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}} +// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) acquire, align 1 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: [[BITCAST1:%.+]] = bitcast i64* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST1]], +// CHECK: [[BITCAST:%.+]] = bitcast i64* %{{.+}} to i8* +// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]], +// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]], +// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 1 +// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i64 +// CHECK: [[CONV:%.+]] = sitofp i64 [[CAST]] to x86_fp80 +// CHECK: [[ADD:%.+]] = fadd x86_fp80 [[CONV]], [[EXPR]] +// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i64 +// CHECK: [[TRUNC:%.+]] = trunc i64 [[NEW_VAL]] to i8 +// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST1]], +// CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 127 +// CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 1 +// CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], 1 +// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]] +// CHECK: store i8 %{{.+}}, i8* [[BITCAST1]] +// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[BITCAST1]] +// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] acquire acquire, align 1 +// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: [[NEW_VAL_I32:%.+]] = trunc i64 [[NEW_VAL]] to i32 +// CHECK: store i32 [[NEW_VAL_I32]], i32* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare acquire + iv = bfx4_packed.b += ldv; +// CHECK: load i64, i64* +// CHECK: [[EXPR:%.+]] = uitofp i64 %{{.+}} to float +// CHECK: [[I64VAL:%.+]] = load atomic i64, i64* bitcast (<2 x float>* [[DEST:@.+]] to i64*) acquire, align 8 +// CHECK: br label %[[CONT:.+]] +// CHECK: [[CONT]] +// CHECK: [[OLD_I64:%.+]] = phi i64 [ [[I64VAL]], %{{.+}} ], [ [[FAILED_I64_OLD_VAL:%.+]], %[[CONT]] ] +// CHECK: [[BITCAST:%.+]] = bitcast <2 x float>* [[LDTEMP1:%.+]] to i64* +// CHECK: store i64 [[OLD_I64]], i64* [[BITCAST]], +// CHECK: [[OLD_VEC_VAL:%.+]] = bitcast i64 [[OLD_I64]] to <2 x float> +// CHECK: store <2 x float> [[OLD_VEC_VAL]], <2 x float>* [[LDTEMP:%.+]], +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]] +// CHECK: [[X:%.+]] = extractelement <2 x float> [[VEC_VAL]], i64 0 +// CHECK: [[VEC_ITEM_VAL:%.+]] = fsub float [[EXPR]], [[X]] +// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP1]], +// CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <2 x float> [[VEC_VAL]], float [[VEC_ITEM_VAL]], i64 0 +// CHECK: store <2 x float> [[NEW_VEC_VAL]], <2 x float>* [[LDTEMP1]] +// CHECK: [[NEW_I64:%.+]] = load i64, i64* [[BITCAST]] +// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (<2 x float>* [[DEST]] to i64*), i64 [[OLD_I64]], i64 [[NEW_I64]] acq_rel acquire, align 8 +// CHECK: [[FAILED_I64_OLD_VAL:%.+]] = extractvalue { i64, i1 } [[RES]], 0 +// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1 +// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]] +// CHECK: [[EXIT]] +// CHECK: store float [[X]], float* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare acq_rel + {fv = float2x.x; float2x.x = ulv - float2x.x;} +// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}}, +// CHECK: [[OLD_VAL:%.+]] = call i32 @llvm.read_register.i32([[REG:metadata ![0-9]+]]) +// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[OLD_VAL]] to double +// CHECK: [[DIV:%.+]] = fdiv double [[EXPR]], [[X_RVAL]] +// CHECK: [[NEW_VAL:%.+]] = fptosi double [[DIV]] to i32 +// CHECK: call void @llvm.write_register.i32([[REG]], i32 [[NEW_VAL]]) +// CHECK: store i32 [[NEW_VAL]], i32* @{{.+}}, +// CHECK: call{{.*}} @__kmpc_flush( +#pragma omp atomic compare seq_cst + {rix = dv / rix; iv = rix;} +// CHECK: [[OLD_VAL:%.+]] = atomicrmw xchg i32* @{{.+}}, i32 5 monotonic, align 4 +// CHECK: call void @llvm.write_register.i32([[REG]], i32 [[OLD_VAL]]) +#pragma omp atomic compare + {rix = ix; ix = 5;} + return 0; +} +#endif diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2271,6 +2271,8 @@ void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {} +void OMPClauseEnqueue::VisitOMPCompareClause(const OMPCompareClause *) {} + void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {} diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -160,6 +160,7 @@ def OMPC_Write : Clause<"write"> { let clangClass = "OMPWriteClause"; } def OMPC_Update : Clause<"update"> { let clangClass = "OMPUpdateClause"; } def OMPC_Capture : Clause<"capture"> { let clangClass = "OMPCaptureClause"; } +def OMPC_Compare : Clause<"compare"> { let clangClass = "OMPCompareClause"; } def OMPC_SeqCst : Clause<"seq_cst"> { let clangClass = "OMPSeqCstClause"; } def OMPC_AcqRel : Clause<"acq_rel"> { let clangClass = "OMPAcqRelClause"; } def OMPC_Acquire : Clause<"acquire"> { let clangClass = "OMPAcquireClause"; } @@ -500,6 +501,7 @@ VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; let allowedOnceClauses = [ VersionedClause,