[OPENMP] Codegen for 'atomic update' construct.
Adds atomic update codegen for the following forms of expressions:
x binop= expr;
x++;
++x;
x--;
--x;
x = x binop expr;
x = expr binop x;
If x and expr are integer and binop is associative or x is a LHS in a RHS of the assignment expression, and atomics are allowed for type of x on the target platform atomicrmw instruction is emitted.
Otherwise compare-and-swap sequence is emitted:
bb:
...
atomic load <x>
cont:
<expected> = phi [ <x>, label %bb ], [ <new_failed>, %cont ]
<desired> = <expected> binop <expr>
<res> = cmpxchg atomic &<x>, desired, expected
<new_failed> = <res>.field1;
br <res>field2, label %exit, label %cont
exit:
...
Differential Revision: http://reviews.llvm.org/D8536
llvm-svn: 233513
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index e027e55..54dc886 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3282,21 +3282,24 @@
Sema &SemaRef;
/// \brief A location for note diagnostics (when error is found).
SourceLocation NoteLoc;
- /// \brief Atomic operation supposed to be performed on source expression.
- BinaryOperatorKind OpKind;
/// \brief 'x' lvalue part of the source atomic expression.
Expr *X;
- /// \brief 'x' rvalue part of the source atomic expression, used in the right
- /// hand side of the expression. We need this to properly generate RHS part of
- /// the source expression (x = x'rval' binop expr or x = expr binop x'rval').
- Expr *XRVal;
/// \brief 'expr' rvalue part of the source atomic expression.
Expr *E;
+ /// \brief Helper expression of the form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ Expr *UpdateExpr;
+ /// \brief Is 'x' a LHS in a RHS part of full update expression. It is
+ /// important for non-associative operations.
+ bool IsXLHSInRHSPart;
+ BinaryOperatorKind Op;
+ SourceLocation OpLoc;
public:
OpenMPAtomicUpdateChecker(Sema &SemaRef)
- : SemaRef(SemaRef), OpKind(BO_PtrMemD), X(nullptr), XRVal(nullptr),
- E(nullptr) {}
+ : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr),
+ IsXLHSInRHSPart(false), Op(BO_PtrMemD) {}
/// \brief Check specified statement that it is suitable for 'atomic update'
/// constructs and extract 'x', 'expr' and Operation from the original
/// expression.
@@ -3306,13 +3309,16 @@
bool checkStatement(Stmt *S, unsigned DiagId, unsigned NoteId);
/// \brief Return the 'x' lvalue part of the source atomic expression.
Expr *getX() const { return X; }
- /// \brief Return the 'x' rvalue part of the source atomic expression, used in
- /// the RHS part of the source expression.
- Expr *getXRVal() const { return XRVal; }
/// \brief Return the 'expr' rvalue part of the source atomic expression.
Expr *getExpr() const { return E; }
- /// \brief Return required atomic operation.
- BinaryOperatorKind getOpKind() const {return OpKind;}
+ /// \brief Return the update expression used in calculation of the updated
+ /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ Expr *getUpdateExpr() const { return UpdateExpr; }
+ /// \brief Return true if 'x' is LHS in RHS part of full update expression,
+ /// false otherwise.
+ bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
+
private:
bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId,
unsigned NoteId);
@@ -3334,7 +3340,8 @@
if (AtomicInnerBinOp->isMultiplicativeOp() ||
AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() ||
AtomicInnerBinOp->isBitwiseOp()) {
- OpKind = AtomicInnerBinOp->getOpcode();
+ Op = AtomicInnerBinOp->getOpcode();
+ OpLoc = AtomicInnerBinOp->getOperatorLoc();
auto *LHS = AtomicInnerBinOp->getLHS();
auto *RHS = AtomicInnerBinOp->getRHS();
llvm::FoldingSetNodeID XId, LHSId, RHSId;
@@ -3346,10 +3353,10 @@
/*Canonical=*/true);
if (XId == LHSId) {
E = RHS;
- XRVal = LHS;
+ IsXLHSInRHSPart = true;
} else if (XId == RHSId) {
E = LHS;
- XRVal = RHS;
+ IsXLHSInRHSPart = false;
} else {
ErrorLoc = AtomicInnerBinOp->getExprLoc();
ErrorRange = AtomicInnerBinOp->getSourceRange();
@@ -3381,7 +3388,7 @@
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
} else if (SemaRef.CurContext->isDependentContext())
- E = X = XRVal = nullptr;
+ E = X = UpdateExpr = nullptr;
return false;
}
@@ -3405,26 +3412,26 @@
if (auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Compound Assignment Operation
- OpKind = BinaryOperator::getOpForCompoundAssignment(
+ Op = BinaryOperator::getOpForCompoundAssignment(
AtomicCompAssignOp->getOpcode());
- X = AtomicCompAssignOp->getLHS();
- XRVal = SemaRef.PerformImplicitConversion(
- X, AtomicCompAssignOp->getComputationLHSType(),
- Sema::AA_Casting, /*AllowExplicit=*/true).get();
+ OpLoc = AtomicCompAssignOp->getOperatorLoc();
E = AtomicCompAssignOp->getRHS();
+ X = AtomicCompAssignOp->getLHS();
+ IsXLHSInRHSPart = true;
} else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Binary Operation
- return checkBinaryOperation(AtomicBinOp, DiagId, NoteId);
+ if(checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
+ return true;
} else if (auto *AtomicUnaryOp =
- // Check for Binary Operation
dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) {
// Check for Unary Operation
if (AtomicUnaryOp->isIncrementDecrementOp()) {
- OpKind = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
- XRVal = X = AtomicUnaryOp->getSubExpr();
- E = SemaRef.ActOnIntegerConstant(AtomicUnaryOp->getOperatorLoc(), 1)
- .get();
+ Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
+ OpLoc = AtomicUnaryOp->getOperatorLoc();
+ X = AtomicUnaryOp->getSubExpr();
+ E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get();
+ IsXLHSInRHSPart = true;
} else {
ErrorFound = NotAnUnaryIncDecExpression;
ErrorLoc = AtomicUnaryOp->getExprLoc();
@@ -3452,7 +3459,26 @@
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
} else if (SemaRef.CurContext->isDependentContext())
- E = X = XRVal = nullptr;
+ E = X = UpdateExpr = nullptr;
+ if (E && X) {
+ // Build an update expression of form 'OpaqueValueExpr(x) binop
+ // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop
+ // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression.
+ auto *OVEX = new (SemaRef.getASTContext())
+ OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue);
+ auto *OVEExpr = new (SemaRef.getASTContext())
+ OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue);
+ auto Update =
+ SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr,
+ IsXLHSInRHSPart ? OVEExpr : OVEX);
+ if (Update.isInvalid())
+ return true;
+ Update = SemaRef.PerformImplicitConversion(Update.get(), X->getType(),
+ Sema::AA_Casting);
+ if (Update.isInvalid())
+ return true;
+ UpdateExpr = Update.get();
+ }
return false;
}
@@ -3490,11 +3516,11 @@
if (auto *EWC = dyn_cast<ExprWithCleanups>(Body))
Body = EWC->getSubExpr();
- BinaryOperatorKind OpKind = BO_PtrMemD;
Expr *X = nullptr;
- Expr *XRVal = nullptr;
Expr *V = nullptr;
Expr *E = nullptr;
+ Expr *UE = nullptr;
+ bool IsXLHSInRHSPart = false;
// OpenMP [2.12.6, atomic Construct]
// In the next expressions:
// * x and v (as applicable) are both l-value expressions with scalar type.
@@ -3652,8 +3678,8 @@
if (!CurContext->isDependentContext()) {
E = Checker.getExpr();
X = Checker.getX();
- XRVal = Checker.getXRVal();
- OpKind = Checker.getOpKind();
+ UE = Checker.getUpdateExpr();
+ IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
}
} else if (AtomicKind == OMPC_capture) {
if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) {
@@ -3670,7 +3696,7 @@
getCurFunction()->setHasBranchProtectedScope();
return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
- OpKind, X, XRVal, V, E);
+ X, V, E, UE, IsXLHSInRHSPart);
}
StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,