[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,