r232890 - [OPENMP] CodeGen of the 'linear' clause for the 'omp simd' directive.

Alexander Musman alexander.musman at gmail.com
Sat Mar 21 03:12:57 PDT 2015


Author: amusman
Date: Sat Mar 21 05:12:56 2015
New Revision: 232890

URL: http://llvm.org/viewvc/llvm-project?rev=232890&view=rev
Log:
[OPENMP] CodeGen of the 'linear' clause for the 'omp simd' directive.
The linear variable is privatized (similar to 'private') and its
value on current iteration is calculated, similar to the loop
counter variables.
Differential revision: http://reviews.llvm.org/D8375


Modified:
    cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/OpenMPClause.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/StmtOpenMP.h
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/OpenMP/simd_codegen.cpp
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Sat Mar 21 05:12:56 2015
@@ -2531,7 +2531,17 @@ bool RecursiveASTVisitor<Derived>::Visit
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
   TRY_TO(TraverseStmt(C->getStep()));
+  TRY_TO(TraverseStmt(C->getCalcStep()));
   TRY_TO(VisitOMPClauseList(C));
+  for (auto *E : C->inits()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->updates()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->finals()) {
+    TRY_TO(TraverseStmt(E));
+  }
   return true;
 }
 

Modified: cfe/trunk/include/clang/AST/OpenMPClause.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OpenMPClause.h?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OpenMPClause.h (original)
+++ cfe/trunk/include/clang/AST/OpenMPClause.h Sat Mar 21 05:12:56 2015
@@ -1356,7 +1356,10 @@ class OMPLinearClause : public OMPVarLis
   SourceLocation ColonLoc;
 
   /// \brief Sets the linear step for clause.
-  void setStep(Expr *Step) { *varlist_end() = Step; }
+  void setStep(Expr *Step) { *(getFinals().end()) = Step; }
+
+  /// \brief Sets the expression to calculate linear step for clause.
+  void setCalcStep(Expr *CalcStep) { *(getFinals().end() + 1) = CalcStep; }
 
   /// \brief Build 'linear' clause with given number of variables \a NumVars.
   ///
@@ -1383,6 +1386,46 @@ class OMPLinearClause : public OMPVarLis
                                           NumVars),
         ColonLoc(SourceLocation()) {}
 
+  /// \brief Gets the list of initial values for linear variables.
+  ///
+  /// There are NumVars expressions with initial values allocated after the
+  /// varlist, they are followed by NumVars update expressions (used to update
+  /// the linear variable's value on current iteration) and they are followed by
+  /// NumVars final expressions (used to calculate the linear variable's
+  /// value after the loop body). After these lists, there are 2 helper
+  /// expressions - linear step and a helper to calculate it before the
+  /// loop body (used when the linear step is not constant):
+  ///
+  /// { Vars[] /* in OMPVarListClause */; Inits[]; Updates[]; Finals[];
+  ///   Step; CalcStep; }
+  ///
+  MutableArrayRef<Expr *> getInits() {
+    return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+  }
+  ArrayRef<const Expr *> getInits() const {
+    return llvm::makeArrayRef(varlist_end(), varlist_size());
+  }
+
+  /// \brief Sets the list of update expressions for linear variables.
+  MutableArrayRef<Expr *> getUpdates() {
+    return MutableArrayRef<Expr *>(getInits().end(), varlist_size());
+  }
+  ArrayRef<const Expr *> getUpdates() const {
+    return llvm::makeArrayRef(getInits().end(), varlist_size());
+  }
+
+  /// \brief Sets the list of final update expressions for linear variables.
+  MutableArrayRef<Expr *> getFinals() {
+    return MutableArrayRef<Expr *>(getUpdates().end(), varlist_size());
+  }
+  ArrayRef<const Expr *> getFinals() const {
+    return llvm::makeArrayRef(getUpdates().end(), varlist_size());
+  }
+
+  /// \brief Sets the list of the initial values for linear variables.
+  /// \param IL List of expressions.
+  void setInits(ArrayRef<Expr *> IL);
+
 public:
   /// \brief Creates clause with a list of variables \a VL and a linear step
   /// \a Step.
@@ -1393,11 +1436,14 @@ public:
   /// \param ColonLoc Location of ':'.
   /// \param EndLoc Ending location of the clause.
   /// \param VL List of references to the variables.
+  /// \param IL List of initial values for the variables.
   /// \param Step Linear step.
+  /// \param CalcStep Calculation of the linear step.
   static OMPLinearClause *Create(const ASTContext &C, SourceLocation StartLoc,
                                  SourceLocation LParenLoc,
                                  SourceLocation ColonLoc, SourceLocation EndLoc,
-                                 ArrayRef<Expr *> VL, Expr *Step);
+                                 ArrayRef<Expr *> VL, ArrayRef<Expr *> IL,
+                                 Expr *Step, Expr *CalcStep);
 
   /// \brief Creates an empty clause with the place for \a NumVars variables.
   ///
@@ -1412,13 +1458,61 @@ public:
   SourceLocation getColonLoc() const { return ColonLoc; }
 
   /// \brief Returns linear step.
-  Expr *getStep() { return *varlist_end(); }
+  Expr *getStep() { return *(getFinals().end()); }
   /// \brief Returns linear step.
-  const Expr *getStep() const { return *varlist_end(); }
+  const Expr *getStep() const { return *(getFinals().end()); }
+  /// \brief Returns expression to calculate linear step.
+  Expr *getCalcStep() { return *(getFinals().end() + 1); }
+  /// \brief Returns expression to calculate linear step.
+  const Expr *getCalcStep() const { return *(getFinals().end() + 1); }
+
+  /// \brief Sets the list of update expressions for linear variables.
+  /// \param UL List of expressions.
+  void setUpdates(ArrayRef<Expr *> UL);
+
+  /// \brief Sets the list of final update expressions for linear variables.
+  /// \param FL List of expressions.
+  void setFinals(ArrayRef<Expr *> FL);
+
+  typedef MutableArrayRef<Expr *>::iterator inits_iterator;
+  typedef ArrayRef<const Expr *>::iterator inits_const_iterator;
+  typedef llvm::iterator_range<inits_iterator> inits_range;
+  typedef llvm::iterator_range<inits_const_iterator> inits_const_range;
+
+  inits_range inits() {
+    return inits_range(getInits().begin(), getInits().end());
+  }
+  inits_const_range inits() const {
+    return inits_const_range(getInits().begin(), getInits().end());
+  }
+
+  typedef MutableArrayRef<Expr *>::iterator updates_iterator;
+  typedef ArrayRef<const Expr *>::iterator updates_const_iterator;
+  typedef llvm::iterator_range<updates_iterator> updates_range;
+  typedef llvm::iterator_range<updates_const_iterator> updates_const_range;
+
+  updates_range updates() {
+    return updates_range(getUpdates().begin(), getUpdates().end());
+  }
+  updates_const_range updates() const {
+    return updates_const_range(getUpdates().begin(), getUpdates().end());
+  }
+
+  typedef MutableArrayRef<Expr *>::iterator finals_iterator;
+  typedef ArrayRef<const Expr *>::iterator finals_const_iterator;
+  typedef llvm::iterator_range<finals_iterator> finals_range;
+  typedef llvm::iterator_range<finals_const_iterator> finals_const_range;
+
+  finals_range finals() {
+    return finals_range(getFinals().begin(), getFinals().end());
+  }
+  finals_const_range finals() const {
+    return finals_const_range(getFinals().begin(), getFinals().end());
+  }
 
   StmtRange children() {
     return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
-                     reinterpret_cast<Stmt **>(varlist_end() + 1));
+                     reinterpret_cast<Stmt **>(getFinals().end() + 2));
   }
 
   static bool classof(const OMPClause *T) {

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Sat Mar 21 05:12:56 2015
@@ -2561,7 +2561,17 @@ bool RecursiveASTVisitor<Derived>::Visit
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
   TRY_TO(TraverseStmt(C->getStep()));
+  TRY_TO(TraverseStmt(C->getCalcStep()));
   TRY_TO(VisitOMPClauseList(C));
+  for (auto *E : C->inits()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->updates()) {
+    TRY_TO(TraverseStmt(E));
+  }
+  for (auto *E : C->finals()) {
+    TRY_TO(TraverseStmt(E));
+  }
   return true;
 }
 

Modified: cfe/trunk/include/clang/AST/StmtOpenMP.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtOpenMP.h?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtOpenMP.h (original)
+++ cfe/trunk/include/clang/AST/StmtOpenMP.h Sat Mar 21 05:12:56 2015
@@ -95,6 +95,7 @@ public:
   /// This iterator visits only those declarations that meet some run-time
   /// criteria.
   template <class FilterPredicate> class filtered_clause_iterator {
+  protected:
     ArrayRef<OMPClause *>::const_iterator Current;
     ArrayRef<OMPClause *>::const_iterator End;
     FilterPredicate Pred;
@@ -126,6 +127,27 @@ public:
 
     bool operator!() { return Current == End; }
     operator bool() { return Current != End; }
+    bool empty() const { return Current == End; }
+  };
+
+  /// \brief A filter to iterate over 'linear' clauses using a C++ range
+  /// for loop.
+  struct linear_filter : public filtered_clause_iterator<
+                             std::function<bool(const OMPClause *)> > {
+    linear_filter(ArrayRef<OMPClause *> Arr)
+        : filtered_clause_iterator(Arr, [](const OMPClause *C)->bool {
+            return C->getClauseKind() == OMPC_linear;
+          }) {}
+    const OMPLinearClause *operator*() const {
+      return cast<OMPLinearClause>(*Current);
+    }
+    const OMPLinearClause *operator->() const {
+      return cast<OMPLinearClause>(*Current);
+    }
+    friend linear_filter begin(const linear_filter &range) { return range; }
+    friend linear_filter end(const linear_filter &range) {
+      return linear_filter(ArrayRef<OMPClause *>(range.End, range.End));
+    }
   };
 
   /// \brief Gets a single clause of the specified kind \a K associated with the
@@ -410,6 +432,8 @@ public:
     Expr *IterationVarRef;
     /// \brief Loop last iteration number.
     Expr *LastIteration;
+    /// \brief Loop number of iterations.
+    Expr *NumIterations;
     /// \brief Calculation of last iteration.
     Expr *CalcLastIteration;
     /// \brief Loop pre-condition.
@@ -447,8 +471,9 @@ public:
     /// worksharing ones).
     bool builtAll() {
       return IterationVarRef != nullptr && LastIteration != nullptr &&
-             PreCond != nullptr && Cond != nullptr &&
-             SeparatedCond != nullptr && Init != nullptr && Inc != nullptr;
+             NumIterations != nullptr && PreCond != nullptr &&
+             Cond != nullptr && SeparatedCond != nullptr && Init != nullptr &&
+             Inc != nullptr;
     }
 
     /// \brief Initialize all the fields to null.

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Sat Mar 21 05:12:56 2015
@@ -1291,27 +1291,56 @@ OMPSharedClause *OMPSharedClause::Create
   return new (Mem) OMPSharedClause(N);
 }
 
-OMPLinearClause *OMPLinearClause::Create(const ASTContext &C,
-                                         SourceLocation StartLoc,
-                                         SourceLocation LParenLoc,
-                                         SourceLocation ColonLoc,
-                                         SourceLocation EndLoc,
-                                         ArrayRef<Expr *> VL, Expr *Step) {
+void OMPLinearClause::setInits(ArrayRef<Expr *> IL) {
+  assert(IL.size() == varlist_size() &&
+         "Number of inits is not the same as the preallocated buffer");
+  std::copy(IL.begin(), IL.end(), varlist_end());
+}
+
+void OMPLinearClause::setUpdates(ArrayRef<Expr *> UL) {
+  assert(UL.size() == varlist_size() &&
+         "Number of updates is not the same as the preallocated buffer");
+  std::copy(UL.begin(), UL.end(), getInits().end());
+}
+
+void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) {
+  assert(FL.size() == varlist_size() &&
+         "Number of final updates is not the same as the preallocated buffer");
+  std::copy(FL.begin(), FL.end(), getUpdates().end());
+}
+
+OMPLinearClause *
+OMPLinearClause::Create(const ASTContext &C, SourceLocation StartLoc,
+                        SourceLocation LParenLoc, SourceLocation ColonLoc,
+                        SourceLocation EndLoc, ArrayRef<Expr *> VL,
+                        ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep) {
+  // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
+  // (Step and CalcStep).
   void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
                                                   llvm::alignOf<Expr *>()) +
-                         sizeof(Expr *) * (VL.size() + 1));
+                         (4 * VL.size() + 2) * sizeof(Expr *));
   OMPLinearClause *Clause = new (Mem)
       OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
   Clause->setVarRefs(VL);
+  Clause->setInits(IL);
+  // Fill update and final expressions with zeroes, they are provided later,
+  // after the directive construction.
+  std::fill(Clause->getInits().end(), Clause->getInits().end() + VL.size(),
+            nullptr);
+  std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(),
+            nullptr);
   Clause->setStep(Step);
+  Clause->setCalcStep(CalcStep);
   return Clause;
 }
 
 OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
                                               unsigned NumVars) {
+  // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
+  // (Step and CalcStep).
   void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
                                                   llvm::alignOf<Expr *>()) +
-                         sizeof(Expr *) * (NumVars + 1));
+                         (4 * NumVars + 2) * sizeof(Expr *));
   return new (Mem) OMPLinearClause(NumVars);
 }
 

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Sat Mar 21 05:12:56 2015
@@ -359,7 +359,17 @@ void OMPClauseProfiler::VisitOMPReductio
 }
 void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
   VisitOMPClauseList(C);
+  for (auto *E : C->inits()) {
+    Profiler->VisitStmt(E);
+  }
+  for (auto *E : C->updates()) {
+    Profiler->VisitStmt(E);
+  }
+  for (auto *E : C->finals()) {
+    Profiler->VisitStmt(E);
+  }
   Profiler->VisitStmt(C->getStep());
+  Profiler->VisitStmt(C->getCalcStep());
 }
 void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) {
   VisitOMPClauseList(C);

Modified: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp Sat Mar 21 05:12:56 2015
@@ -266,6 +266,13 @@ void CodeGenFunction::EmitOMPLoopBody(co
   for (auto I : S.updates()) {
     EmitIgnoredExpr(I);
   }
+  // Update the linear variables.
+  for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+    for (auto U : C->updates()) {
+      EmitIgnoredExpr(U);
+    }
+  }
+
   // On a continue in the body, jump to the end.
   auto Continue = getJumpDestInCurrentScope("omp.body.continue");
   BreakContinueStack.push_back(BreakContinue(JumpDest(), Continue));
@@ -336,6 +343,12 @@ void CodeGenFunction::EmitOMPSimdFinal(c
     }
     ++IC;
   }
+  // Emit the final values of the linear variables.
+  for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+    for (auto F : C->finals()) {
+      EmitIgnoredExpr(F);
+    }
+  }
 }
 
 static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM,
@@ -381,6 +394,25 @@ static void EmitPrivateLoopCounters(Code
   }
 }
 
+static void
+EmitPrivateLinearVars(CodeGenFunction &CGF, const OMPExecutableDirective &D,
+                      CodeGenFunction::OMPPrivateScope &PrivateScope) {
+  for (auto Clause : OMPExecutableDirective::linear_filter(D.clauses())) {
+    for (auto *E : Clause->varlists()) {
+      auto VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+      bool IsRegistered = PrivateScope.addPrivate(VD, [&]()->llvm::Value * {
+        // Emit var without initialization.
+        auto VarEmission = CGF.EmitAutoVarAlloca(*VD);
+        CGF.EmitAutoVarCleanups(VarEmission);
+        return VarEmission.getAllocatedAddress();
+      });
+      assert(IsRegistered && "linear var already registered as private");
+      // Silence the warning about unused variable.
+      (void)IsRegistered;
+    }
+  }
+}
+
 void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
   // Pragma 'simd' code depends on presence of 'lastprivate'.
   // If present, we have to separate last iteration of the loop:
@@ -428,6 +460,14 @@ void CodeGenFunction::EmitOMPSimdDirecti
 
   InlinedOpenMPRegionScopeRAII Region(*this, S);
 
+  // Emit inits for the linear variables.
+  for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+    for (auto Init : C->inits()) {
+      auto *D = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
+      EmitVarDecl(*D);
+    }
+  }
+
   // Emit the loop iteration variable.
   const Expr *IVExpr = S.getIterationVariable();
   const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
@@ -443,6 +483,17 @@ void CodeGenFunction::EmitOMPSimdDirecti
     EmitIgnoredExpr(S.getCalcLastIteration());
   }
 
+  // Emit the linear steps for the linear clauses.
+  // If a step is not constant, it is pre-calculated before the loop.
+  for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+    if (auto CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
+      if (auto SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
+        EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
+        // Emit calculation of the linear step.
+        EmitIgnoredExpr(CS);
+      }
+  }
+
   if (SeparateIter) {
     // Emit: if (LastIteration > 0) - begin.
     RegionCounter Cnt = getPGORegionCounter(&S);
@@ -455,6 +506,7 @@ void CodeGenFunction::EmitOMPSimdDirecti
     {
       OMPPrivateScope LoopScope(*this);
       EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+      EmitPrivateLinearVars(*this, S, LoopScope);
       EmitOMPPrivateClause(S, LoopScope);
       (void)LoopScope.Privatize();
       EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
@@ -473,6 +525,7 @@ void CodeGenFunction::EmitOMPSimdDirecti
     {
       OMPPrivateScope LoopScope(*this);
       EmitPrivateLoopCounters(*this, LoopScope, S.counters());
+      EmitPrivateLinearVars(*this, S, LoopScope);
       EmitOMPPrivateClause(S, LoopScope);
       (void)LoopScope.Privatize();
       EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Sat Mar 21 05:12:56 2015
@@ -622,6 +622,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDi
   PopExpressionEvaluationContext();
 }
 
+static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
+                                     Expr *NumIterations, Sema &SemaRef,
+                                     Scope *S);
+
 namespace {
 
 class VarDeclFilterCCC : public CorrectionCandidateCallback {
@@ -2915,6 +2919,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKin
   // Save results
   Built.IterationVarRef = IV.get();
   Built.LastIteration = LastIteration.get();
+  Built.NumIterations = NumIterations.get();
   Built.CalcLastIteration = CalcLastIteration.get();
   Built.PreCond = PreCond.get();
   Built.Cond = Cond.get();
@@ -2958,6 +2963,16 @@ StmtResult Sema::ActOnOpenMPSimdDirectiv
   assert((CurContext->isDependentContext() || B.builtAll()) &&
          "omp simd loop exprs were not built");
 
+  if (!CurContext->isDependentContext()) {
+    // Finalize the clauses that need pre-built expressions for CodeGen.
+    for (auto C : Clauses) {
+      if (auto LC = dyn_cast<OMPLinearClause>(C))
+        if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+                                     B.NumIterations, *this, CurScope))
+          return StmtError();
+    }
+  }
+
   getCurFunction()->setHasBranchProtectedScope();
   return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
                                   Clauses, AStmt, B);
@@ -5231,11 +5246,13 @@ OMPClause *Sema::ActOnOpenMPLinearClause
                                          SourceLocation ColonLoc,
                                          SourceLocation EndLoc) {
   SmallVector<Expr *, 8> Vars;
+  SmallVector<Expr *, 8> Inits;
   for (auto &RefExpr : VarList) {
     assert(RefExpr && "NULL expr in OpenMP linear clause.");
     if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
       // It will be analyzed later.
       Vars.push_back(RefExpr);
+      Inits.push_back(nullptr);
       continue;
     }
 
@@ -5277,6 +5294,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause
     if (QType->isDependentType() || QType->isInstantiationDependentType()) {
       // It will be analyzed later.
       Vars.push_back(DE);
+      Inits.push_back(nullptr);
       continue;
     }
 
@@ -5322,14 +5340,27 @@ OMPClause *Sema::ActOnOpenMPLinearClause
       continue;
     }
 
+    // Build var to save initial value.
+    VarDecl *Init = BuildVarDecl(*this, ELoc, DE->getType(), ".linear.start");
+    AddInitializerToDecl(Init, DefaultLvalueConversion(DE).get(),
+                         /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+    CurContext->addDecl(Init);
+    Init->setIsUsed();
+    auto InitRef = DeclRefExpr::Create(
+        Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+        /*TemplateKWLoc*/ SourceLocation(), Init,
+        /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(),
+        /*VK*/ VK_LValue);
     DSAStack->addDSA(VD, DE, OMPC_linear);
     Vars.push_back(DE);
+    Inits.push_back(InitRef);
   }
 
   if (Vars.empty())
     return nullptr;
 
   Expr *StepExpr = Step;
+  Expr *CalcStepExpr = nullptr;
   if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
       !Step->isInstantiationDependent() &&
       !Step->containsUnexpandedParameterPack()) {
@@ -5339,17 +5370,85 @@ OMPClause *Sema::ActOnOpenMPLinearClause
       return nullptr;
     StepExpr = Val.get();
 
+    // Build var to save the step value.
+    VarDecl *SaveVar =
+        BuildVarDecl(*this, StepLoc, StepExpr->getType(), ".linear.step");
+    CurContext->addDecl(SaveVar);
+    SaveVar->setIsUsed();
+    ExprResult SaveRef =
+        BuildDeclRefExpr(SaveVar, StepExpr->getType(), VK_LValue, StepLoc);
+    ExprResult CalcStep =
+        BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr);
+
     // Warn about zero linear step (it would be probably better specified as
     // making corresponding variables 'const').
     llvm::APSInt Result;
-    if (StepExpr->isIntegerConstantExpr(Result, Context) &&
-        !Result.isNegative() && !Result.isStrictlyPositive())
+    bool IsConstant = StepExpr->isIntegerConstantExpr(Result, Context);
+    if (IsConstant && !Result.isNegative() && !Result.isStrictlyPositive())
       Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
                                                      << (Vars.size() > 1);
+    if (!IsConstant && CalcStep.isUsable()) {
+      // Calculate the step beforehand instead of doing this on each iteration.
+      // (This is not used if the number of iterations may be kfold-ed).
+      CalcStepExpr = CalcStep.get();
+    }
   }
 
   return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc,
-                                 Vars, StepExpr);
+                                 Vars, Inits, StepExpr, CalcStepExpr);
+}
+
+static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
+                                     Expr *NumIterations, Sema &SemaRef,
+                                     Scope *S) {
+  // Walk the vars and build update/final expressions for the CodeGen.
+  SmallVector<Expr *, 8> Updates;
+  SmallVector<Expr *, 8> Finals;
+  Expr *Step = Clause.getStep();
+  Expr *CalcStep = Clause.getCalcStep();
+  // OpenMP [2.14.3.7, linear clause]
+  // If linear-step is not specified it is assumed to be 1.
+  if (Step == nullptr)
+    Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get();
+  else if (CalcStep)
+    Step = cast<BinaryOperator>(CalcStep)->getLHS();
+  bool HasErrors = false;
+  auto CurInit = Clause.inits().begin();
+  for (auto &RefExpr : Clause.varlists()) {
+    Expr *InitExpr = *CurInit;
+
+    // Build privatized reference to the current linear var.
+    auto DE = cast<DeclRefExpr>(RefExpr);
+    auto PrivateRef = DeclRefExpr::Create(
+        SemaRef.Context, /*QualifierLoc*/ DE->getQualifierLoc(),
+        /*TemplateKWLoc*/ SourceLocation(), DE->getDecl(),
+        /* RefersToEnclosingVariableOrCapture */ true, DE->getLocStart(),
+        DE->getType(), /*VK*/ VK_LValue);
+
+    // Build update: Var = InitExpr + IV * Step
+    ExprResult Update =
+        BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef,
+                           InitExpr, IV, Step, /* Subtract */ false);
+    Update = SemaRef.ActOnFinishFullExpr(Update.get());
+
+    // Build final: Var = InitExpr + NumIterations * Step
+    ExprResult Final =
+        BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), RefExpr, InitExpr,
+                           NumIterations, Step, /* Subtract */ false);
+    Final = SemaRef.ActOnFinishFullExpr(Final.get());
+    if (!Update.isUsable() || !Final.isUsable()) {
+      Updates.push_back(nullptr);
+      Finals.push_back(nullptr);
+      HasErrors = true;
+    } else {
+      Updates.push_back(Update.get());
+      Finals.push_back(Final.get());
+    }
+    ++CurInit;
+  }
+  Clause.setUpdates(Updates);
+  Clause.setFinals(Finals);
+  return HasErrors;
 }
 
 OMPClause *Sema::ActOnOpenMPAlignedClause(

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Sat Mar 21 05:12:56 2015
@@ -1928,7 +1928,20 @@ void OMPClauseReader::VisitOMPLinearClau
   for (unsigned i = 0; i != NumVars; ++i)
     Vars.push_back(Reader->Reader.ReadSubExpr());
   C->setVarRefs(Vars);
+  Vars.clear();
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setInits(Vars);
+  Vars.clear();
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setUpdates(Vars);
+  Vars.clear();
+  for (unsigned i = 0; i != NumVars; ++i)
+    Vars.push_back(Reader->Reader.ReadSubExpr());
+  C->setFinals(Vars);
   C->setStep(Reader->Reader.ReadSubExpr());
+  C->setCalcStep(Reader->Reader.ReadSubExpr());
 }
 
 void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Sat Mar 21 05:12:56 2015
@@ -1820,9 +1820,20 @@ void OMPClauseWriter::VisitOMPLinearClau
   Record.push_back(C->varlist_size());
   Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
   Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
-  for (auto *VE : C->varlists())
+  for (auto *VE : C->varlists()) {
     Writer->Writer.AddStmt(VE);
+  }
+  for (auto *VE : C->inits()) {
+    Writer->Writer.AddStmt(VE);
+  }
+  for (auto *VE : C->updates()) {
+    Writer->Writer.AddStmt(VE);
+  }
+  for (auto *VE : C->finals()) {
+    Writer->Writer.AddStmt(VE);
+  }
   Writer->Writer.AddStmt(C->getStep());
+  Writer->Writer.AddStmt(C->getCalcStep());
 }
 
 void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {

Modified: cfe/trunk/test/OpenMP/simd_codegen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_codegen.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_codegen.cpp (original)
+++ cfe/trunk/test/OpenMP/simd_codegen.cpp Sat Mar 21 05:12:56 2015
@@ -7,6 +7,9 @@
 #ifndef HEADER
 #define HEADER
 
+long long get_val() { return 0; }
+double *g_ptr;
+
 // CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
 void simple(float *a, float *b, float *c, float *d) {
   #pragma omp simd
@@ -33,7 +36,13 @@ void simple(float *a, float *b, float *c
   }
 // CHECK: [[SIMPLE_LOOP1_END]]
 
-  #pragma omp simd
+  long long k = get_val();
+
+  #pragma omp simd linear(k : 3)
+// CHECK: [[K0:%.+]] = call {{.*}}i64 @{{.*}}get_val
+// CHECK-NEXT: store i64 [[K0]], i64* [[K_VAR:%[^,]+]]
+// CHECK: [[K0LOAD:%.+]] = load i64, i64* [[K_VAR]]
+// CHECK-NEXT: store i64 [[K0LOAD]], i64* [[LIN0:%[^,]+]]
 // CHECK: store i32 0, i32* [[OMP_IV2:%[^,]+]]
 
 // CHECK: [[IV2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID:[0-9]+]]
@@ -47,17 +56,45 @@ void simple(float *a, float *b, float *c
 // CHECK-NEXT: [[IV2_1:%.+]] = mul nsw i32 [[IV2_0]], 1
 // CHECK-NEXT: [[LC_I_1:%.+]] = sub nsw i32 10, [[IV2_1]]
 // CHECK-NEXT: store i32 [[LC_I_1]], i32* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
-    a[i]++;
+//
+// CHECK-NEXT: [[LIN0_1:%.+]] = load i64, i64* [[LIN0]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+// CHECK-NEXT: [[IV2_2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
+// CHECK-NEXT: [[LIN_MUL1:%.+]] = mul nsw i32 [[IV2_2]], 3
+// CHECK-NEXT: [[LIN_EXT1:%.+]] = sext i32 [[LIN_MUL1]] to i64
+// CHECK-NEXT: [[LIN_ADD1:%.+]] = add nsw i64 [[LIN0_1]], [[LIN_EXT1]]
+// Update of the privatized version of linear variable!
+// CHECK-NEXT: store i64 [[LIN_ADD1]], i64* [[K_PRIVATIZED:%[^,]+]]
+    a[k]++;
+    k = k + 3;
 // CHECK: [[IV2_2:%.+]] = load i32, i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
 // CHECK-NEXT: [[ADD2_2:%.+]] = add nsw i32 [[IV2_2]], 1
 // CHECK-NEXT: store i32 [[ADD2_2]], i32* [[OMP_IV2]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP2_ID]]
 // br label {{.+}}, !llvm.loop ![[SIMPLE_LOOP2_ID]]
   }
 // CHECK: [[SIMPLE_LOOP2_END]]
+//
+// Update linear vars after loop, as the loop was operating on a private version.
+// CHECK: [[LIN0_2:%.+]] = load i64, i64* [[LIN0]]
+// CHECK-NEXT: [[LIN_ADD2:%.+]] = add nsw i64 [[LIN0_2]], 27
+// CHECK-NEXT: store i64 [[LIN_ADD2]], i64* [[K_VAR]]
+//
+
+  int lin = 12;
+  #pragma omp simd linear(lin : get_val()), linear(g_ptr)
+
+// Init linear private var.
+// CHECK: store i32 12, i32* [[LIN_VAR:%[^,]+]]
+// CHECK: [[LIN_LOAD:%.+]] = load i32, i32* [[LIN_VAR]]
+// CHECK-NEXT: store i32 [[LIN_LOAD]], i32* [[LIN_START:%[^,]+]]
+// CHECK: [[GLIN_LOAD:%.+]] = load double*, double** [[GLIN_VAR:@[^,]+]]
+// CHECK-NEXT: store double* [[GLIN_LOAD]], double** [[GLIN_START:%[^,]+]]
 
-  #pragma omp simd
 // CHECK: store i64 0, i64* [[OMP_IV3:%[^,]+]]
 
+// Remember linear step.
+// CHECK: [[CALL_VAL:%.+]] = invoke
+// CHECK: store i64 [[CALL_VAL]], i64* [[LIN_STEP:%[^,]+]]
+
 // CHECK: [[IV3:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID:[0-9]+]]
 // CHECK-NEXT: [[CMP3:%.+]] = icmp ult i64 [[IV3]], 4
 // CHECK-NEXT: br i1 [[CMP3]], label %[[SIMPLE_LOOP3_BODY:.+]], label %[[SIMPLE_LOOP3_END:[^,]+]]
@@ -68,12 +105,34 @@ void simple(float *a, float *b, float *c
 // CHECK-NEXT: [[LC_IT_1:%.+]] = mul i64 [[IV3_0]], 400
 // CHECK-NEXT: [[LC_IT_2:%.+]] = sub i64 2000, [[LC_IT_1]]
 // CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
-    a[it]++;
+//
+// Linear start and step are used to calculate current value of the linear variable.
+// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NOT: store i32 {{.+}}, i32* [[LIN_VAR]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: [[IV3_1:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK-NEXT: [[MUL:%.+]] = mul i64 [[IV3_1]], 1
+// CHECK-NEXT: [[GEP:%.+]] = getelementptr{{.*}}[[GLINSTART]]{{.*}}[[MUL]]
+// CHECK-NEXT: store double* [[GEP]], double** [[G_PTR_CUR:%[^,]+]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+    *g_ptr++ = 0.0;
+// CHECK: [[GEP_VAL:%.+]] = load double{{.*}}[[G_PTR_CUR]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+// CHECK: store double{{.*}}[[GEP_VAL]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
+    a[it + lin]++;
+// CHECK: [[FLT_INC:%.+]] = fadd float
+// CHECK-NEXT: store float [[FLT_INC]],{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
 // CHECK: [[IV3_2:%.+]] = load i64, i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
 // CHECK-NEXT: [[ADD3_2:%.+]] = add i64 [[IV3_2]], 1
 // CHECK-NEXT: store i64 [[ADD3_2]], i64* [[OMP_IV3]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP3_ID]]
   }
 // CHECK: [[SIMPLE_LOOP3_END]]
+//
+// Linear start and step are used to calculate final value of the linear variables.
+// CHECK: [[LINSTART:.+]] = load i32, i32* [[LIN_START]]
+// CHECK: [[LINSTEP:.+]] = load i64, i64* [[LIN_STEP]]
+// CHECK: store i32 {{.+}}, i32* [[LIN_VAR]],
+// CHECK: [[GLINSTART:.+]] = load double*, double** [[GLIN_START]]
+// CHECK: store double* {{.*}}[[GLIN_VAR]]
 
   #pragma omp simd
 // CHECK: store i32 0, i32* [[OMP_IV4:%[^,]+]]

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=232890&r1=232889&r2=232890&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Sat Mar 21 05:12:56 2015
@@ -2031,7 +2031,17 @@ void OMPClauseEnqueue::VisitOMPReduction
 }
 void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
   VisitOMPClauseList(C);
+  for (const auto *E : C->inits()) {
+    Visitor->AddStmt(E);
+  }
+  for (const auto *E : C->updates()) {
+    Visitor->AddStmt(E);
+  }
+  for (const auto *E : C->finals()) {
+    Visitor->AddStmt(E);
+  }
   Visitor->AddStmt(C->getStep());
+  Visitor->AddStmt(C->getCalcStep());
 }
 void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) {
   VisitOMPClauseList(C);





More information about the cfe-commits mailing list