r266056 - [OPENMP 4.0] Support for 'linear' clause in 'declare simd' directive.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 12 04:02:12 PDT 2016


Author: abataev
Date: Tue Apr 12 06:02:11 2016
New Revision: 266056

URL: http://llvm.org/viewvc/llvm-project?rev=266056&view=rev
Log:
[OPENMP 4.0] Support for 'linear' clause in 'declare simd' directive.

The linear clause declares one or more list items to be private to a SIMD lane and to have a linear relationship with respect to the iteration space of a loop.
'linear' '(' <linear-list> [ ':' <linear-step> ] ')'
When a linear-step expression is specified in a linear clause it must be
either a constant integer expression or an integer-typed parameter that is specified in a uniform clause on the directive.
The special this pointer can be used as if was one of the arguments to the function in any of the linear, aligned, or uniform clauses.

Modified:
    cfe/trunk/include/clang/AST/Attr.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseOpenMP.cpp
    cfe/trunk/lib/Sema/SemaOpenMP.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/OpenMP/declare_simd_ast_print.c
    cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp
    cfe/trunk/test/OpenMP/declare_simd_messages.cpp

Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Tue Apr 12 06:02:11 2016
@@ -20,6 +20,7 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/OpenMPKinds.h"
 #include "clang/Basic/Sanitizers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/VersionTuple.h"

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Apr 12 06:02:11 2016
@@ -2277,7 +2277,9 @@ def OMPDeclareSimdDecl : Attr {
                  [ "", "inbranch", "notinbranch" ],
                  [ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
     ExprArgument<"Simdlen">, VariadicExprArgument<"Uniforms">,
-    VariadicExprArgument<"Aligneds">, VariadicExprArgument<"Alignments">
+    VariadicExprArgument<"Aligneds">, VariadicExprArgument<"Alignments">,
+    VariadicExprArgument<"Linears">, VariadicUnsignedArgument<"Modifiers">,
+    VariadicExprArgument<"Steps">
   ];
   let AdditionalMembers = [{
     void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
@@ -2300,7 +2302,7 @@ def OMPDeclareSimdDecl : Attr {
         OS << ") ";
       }
       alignments_iterator NI = alignments_begin();
-      for (auto E : aligneds()) {
+      for (auto *E : aligneds()) {
         OS << "aligned(";
         E->printPretty(OS, nullptr, Policy);
         if (*NI) {
@@ -2310,6 +2312,23 @@ def OMPDeclareSimdDecl : Attr {
         OS << ") ";
         ++NI;
       }
+      steps_iterator I = steps_begin();
+      modifiers_iterator MI = modifiers_begin();
+      for (auto *E : linears()) {
+        OS << "linear(";
+        if (*MI != OMPC_LINEAR_unknown)
+          OS << getOpenMPSimpleClauseTypeName(OMPC_linear, *MI) << "(";
+        E->printPretty(OS, nullptr, Policy);
+        if (*MI != OMPC_LINEAR_unknown)
+          OS << ")";
+        if (*I) {
+          OS << ": ";
+          (*I)->printPretty(OS, nullptr, Policy);
+        }
+        OS << ") ";
+        ++I;
+        ++MI;
+      }
     }
   }];
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 12 06:02:11 2016
@@ -8182,6 +8182,10 @@ def err_omp_variable_in_map_and_dsa : Er
   "%0 variable cannot be in a map clause in '#pragma omp %1' directive">;
 def err_omp_param_or_this_in_clause : Error<
   "expected reference to one of the parameters of function %0%select{| or 'this'}1">;
+def err_omp_expected_uniform_param : Error<
+  "expected a reference to a parameter specified in a 'uniform' clause">;
+def err_omp_expected_int_param : Error<
+  "expected a reference to an integer-typed parameter">;
 } // end of OpenMP category
 
 let CategoryName = "Related Result Type Issue" in {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Apr 12 06:02:11 2016
@@ -8108,12 +8108,21 @@ public:
       SourceLocation EndLoc,
       llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA);
 
+  /// Checks correctness of linear modifiers.
+  bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
+                                 SourceLocation LinLoc);
+  /// Checks that the specified declaration matches requirements for the linear
+  /// decls.
+  bool CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc,
+                             OpenMPLinearClauseKind LinKind, QualType Type);
+
   /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of
   /// the associated method/function.
   DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(
       DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS,
       Expr *Simdlen, ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
-      ArrayRef<Expr *> Alignments, SourceRange SR);
+      ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
+      ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR);
 
   OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                          Expr *Expr,

Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Tue Apr 12 06:02:11 2016
@@ -391,12 +391,12 @@ public:
 ///      'simdlen' '(' <expr> ')'
 ///      { 'uniform' '(' <argument_list> ')' }
 ///      { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' }
-static bool parseDeclareSimdClauses(Parser &P,
-                                    OMPDeclareSimdDeclAttr::BranchStateTy &BS,
-                                    ExprResult &SimdLen,
-                                    SmallVectorImpl<Expr *> &Uniforms,
-                                    SmallVectorImpl<Expr *> &Aligneds,
-                                    SmallVectorImpl<Expr *> &Alignments) {
+///      { 'linear '(' <argument_list> [ ':' <step> ] ')' }
+static bool parseDeclareSimdClauses(
+    Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen,
+    SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds,
+    SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears,
+    SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) {
   SourceRange BSRange;
   const Token &Tok = P.getCurToken();
   bool IsError = false;
@@ -430,12 +430,14 @@ static bool parseDeclareSimdClauses(Pars
         IsError = true;
     } else {
       OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName);
-      if (CKind == OMPC_uniform || CKind == OMPC_aligned) {
+      if (CKind == OMPC_uniform || CKind == OMPC_aligned ||
+          CKind == OMPC_linear) {
         Parser::OpenMPVarListDataTy Data;
         auto *Vars = &Uniforms;
-        if (CKind == OMPC_aligned) {
+        if (CKind == OMPC_aligned)
           Vars = &Aligneds;
-        }
+        else if (CKind == OMPC_linear)
+          Vars = &Linears;
 
         P.ConsumeToken();
         if (P.ParseOpenMPVarList(OMPD_declare_simd,
@@ -443,6 +445,14 @@ static bool parseDeclareSimdClauses(Pars
           IsError = true;
         if (CKind == OMPC_aligned)
           Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr);
+        else if (CKind == OMPC_linear) {
+          if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind,
+                                                       Data.DepLinMapLoc))
+            Data.LinKind = OMPC_LINEAR_val;
+          LinModifiers.append(Linears.size() - LinModifiers.size(),
+                              Data.LinKind);
+          Steps.append(Linears.size() - Steps.size(), Data.TailExpr);
+        }
       } else
         // TODO: add parsing of other clauses.
         break;
@@ -470,8 +480,12 @@ Parser::ParseOMPDeclareSimdClauses(Parse
   SmallVector<Expr *, 4> Uniforms;
   SmallVector<Expr *, 4> Aligneds;
   SmallVector<Expr *, 4> Alignments;
-  bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,
-                                         Alignments);
+  SmallVector<Expr *, 4> Linears;
+  SmallVector<unsigned, 4> LinModifiers;
+  SmallVector<Expr *, 4> Steps;
+  bool IsError =
+      parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,
+                              Alignments, Linears, LinModifiers, Steps);
   // Need to check for extra tokens.
   if (Tok.isNot(tok::annot_pragma_openmp_end)) {
     Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
@@ -483,8 +497,8 @@ Parser::ParseOMPDeclareSimdClauses(Parse
   SourceLocation EndLoc = ConsumeToken();
   if (!IsError) {
     return Actions.ActOnOpenMPDeclareSimdDirective(
-        Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments,
-        SourceRange(Loc, EndLoc));
+        Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,
+        LinModifiers, Steps, SourceRange(Loc, EndLoc));
   }
   return Ptr;
 }

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Tue Apr 12 06:02:11 2016
@@ -3193,8 +3193,11 @@ StmtResult Sema::ActOnOpenMPExecutableDi
 Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
     DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
     ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
-    ArrayRef<Expr *> Alignments, SourceRange SR) {
+    ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
+    ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) {
   assert(Aligneds.size() == Alignments.size());
+  assert(Linears.size() == LinModifiers.size());
+  assert(Linears.size() == Steps.size());
   if (!DG || DG.get().isNull())
     return DeclGroupPtrTy();
 
@@ -3224,16 +3227,22 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDe
   // The uniform clause declares one or more arguments to have an invariant
   // value for all concurrent invocations of the function in the execution of a
   // single SIMD loop.
+  llvm::DenseMap<Decl *, Expr *> UniformedArgs;
+  Expr *UniformedLinearThis = nullptr;
   for (auto *E : Uniforms) {
     E = E->IgnoreParenImpCasts();
     if (auto *DRE = dyn_cast<DeclRefExpr>(E))
       if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
         if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
             FD->getParamDecl(PVD->getFunctionScopeIndex())
-                    ->getCanonicalDecl() == PVD->getCanonicalDecl())
+                    ->getCanonicalDecl() == PVD->getCanonicalDecl()) {
+          UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E));
           continue;
-    if (isa<CXXThisExpr>(E))
+        }
+    if (isa<CXXThisExpr>(E)) {
+      UniformedLinearThis = E;
       continue;
+    }
     Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
         << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
   }
@@ -3303,10 +3312,126 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDe
       Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned);
     NewAligns.push_back(Align.get());
   }
+  // OpenMP [2.8.2, declare simd construct, Description]
+  // The linear clause declares one or more list items to be private to a SIMD
+  // lane and to have a linear relationship with respect to the iteration space
+  // of a loop.
+  // The special this pointer can be used as if was one of the arguments to the
+  // function in any of the linear, aligned, or uniform clauses.
+  // When a linear-step expression is specified in a linear clause it must be
+  // either a constant integer expression or an integer-typed parameter that is
+  // specified in a uniform clause on the directive.
+  llvm::DenseMap<Decl *, Expr *> LinearArgs;
+  const bool IsUniformedThis = UniformedLinearThis != nullptr;
+  auto MI = LinModifiers.begin();
+  for (auto *E : Linears) {
+    auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI);
+    ++MI;
+    E = E->IgnoreParenImpCasts();
+    if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+      if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+        auto *CanonPVD = PVD->getCanonicalDecl();
+        if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+            FD->getParamDecl(PVD->getFunctionScopeIndex())
+                    ->getCanonicalDecl() == CanonPVD) {
+          // OpenMP  [2.15.3.7, linear Clause, Restrictions]
+          // A list-item cannot appear in more than one linear clause.
+          if (LinearArgs.count(CanonPVD) > 0) {
+            Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+                << getOpenMPClauseName(OMPC_linear)
+                << getOpenMPClauseName(OMPC_linear) << E->getSourceRange();
+            Diag(LinearArgs[CanonPVD]->getExprLoc(),
+                 diag::note_omp_explicit_dsa)
+                << getOpenMPClauseName(OMPC_linear);
+            continue;
+          }
+          // Each argument can appear in at most one uniform or linear clause.
+          if (UniformedArgs.count(CanonPVD) > 0) {
+            Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+                << getOpenMPClauseName(OMPC_linear)
+                << getOpenMPClauseName(OMPC_uniform) << E->getSourceRange();
+            Diag(UniformedArgs[CanonPVD]->getExprLoc(),
+                 diag::note_omp_explicit_dsa)
+                << getOpenMPClauseName(OMPC_uniform);
+            continue;
+          }
+          LinearArgs[CanonPVD] = E;
+          if (E->isValueDependent() || E->isTypeDependent() ||
+              E->isInstantiationDependent() ||
+              E->containsUnexpandedParameterPack())
+            continue;
+          (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
+                                      PVD->getOriginalType());
+          continue;
+        }
+      }
+    if (isa<CXXThisExpr>(E)) {
+      if (UniformedLinearThis) {
+        Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+            << getOpenMPClauseName(OMPC_linear)
+            << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear)
+            << E->getSourceRange();
+        Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa)
+            << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform
+                                                   : OMPC_linear);
+        continue;
+      }
+      UniformedLinearThis = E;
+      if (E->isValueDependent() || E->isTypeDependent() ||
+          E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
+        continue;
+      (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
+                                  E->getType());
+      continue;
+    }
+    Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+        << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
+  }
+  Expr *Step = nullptr;
+  Expr *NewStep = nullptr;
+  SmallVector<Expr *, 4> NewSteps;
+  for (auto *E : Steps) {
+    // Skip the same step expression, it was checked already.
+    if (Step == E || !E) {
+      NewSteps.push_back(E ? NewStep : nullptr);
+      continue;
+    }
+    Step = E;
+    if (auto *DRE = dyn_cast<DeclRefExpr>(Step))
+      if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+        auto *CanonPVD = PVD->getCanonicalDecl();
+        if (UniformedArgs.count(CanonPVD) == 0) {
+          Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param)
+              << Step->getSourceRange();
+        } else if (E->isValueDependent() || E->isTypeDependent() ||
+                   E->isInstantiationDependent() ||
+                   E->containsUnexpandedParameterPack() ||
+                   CanonPVD->getType()->hasIntegerRepresentation())
+          NewSteps.push_back(Step);
+        else {
+          Diag(Step->getExprLoc(), diag::err_omp_expected_int_param)
+              << Step->getSourceRange();
+        }
+        continue;
+      }
+    NewStep = Step;
+    if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+        !Step->isInstantiationDependent() &&
+        !Step->containsUnexpandedParameterPack()) {
+      NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step)
+                    .get();
+      if (NewStep)
+        NewStep = VerifyIntegerConstantExpression(NewStep).get();
+    }
+    NewSteps.push_back(NewStep);
+  }
   auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
       Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
       Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(),
-      const_cast<Expr **>(NewAligns.data()), NewAligns.size(), SR);
+      const_cast<Expr **>(NewAligns.data()), NewAligns.size(),
+      const_cast<Expr **>(Linears.data()), Linears.size(),
+      const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
+      NewSteps.data(), NewSteps.size(), SR);
   ADecl->addAttr(NewAttr);
   return ConvertDeclToDeclGroup(ADecl);
 }
@@ -8653,6 +8778,65 @@ OMPClause *Sema::ActOnOpenMPReductionCla
       buildPostUpdate(*this, ExprPostUpdates));
 }
 
+bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
+                                     SourceLocation LinLoc) {
+  if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
+      LinKind == OMPC_LINEAR_unknown) {
+    Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+    return true;
+  }
+  return false;
+}
+
+bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc,
+                                 OpenMPLinearClauseKind LinKind,
+                                 QualType Type) {
+  auto *VD = dyn_cast_or_null<VarDecl>(D);
+  // A variable must not have an incomplete type or a reference type.
+  if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
+    return true;
+  if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
+      !Type->isReferenceType()) {
+    Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
+        << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
+    return true;
+  }
+  Type = Type.getNonReferenceType();
+
+  // A list item must not be const-qualified.
+  if (Type.isConstant(Context)) {
+    Diag(ELoc, diag::err_omp_const_variable)
+        << getOpenMPClauseName(OMPC_linear);
+    if (D) {
+      bool IsDecl =
+          !VD ||
+          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+      Diag(D->getLocation(),
+           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+          << D;
+    }
+    return true;
+  }
+
+  // A list item must be of integral or pointer type.
+  Type = Type.getUnqualifiedType().getCanonicalType();
+  const auto *Ty = Type.getTypePtrOrNull();
+  if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+              !Ty->isPointerType())) {
+    Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
+    if (D) {
+      bool IsDecl =
+          !VD ||
+          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+      Diag(D->getLocation(),
+           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+          << D;
+    }
+    return true;
+  }
+  return false;
+}
+
 OMPClause *Sema::ActOnOpenMPLinearClause(
     ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc,
     SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind,
@@ -8662,11 +8846,8 @@ OMPClause *Sema::ActOnOpenMPLinearClause
   SmallVector<Expr *, 8> Inits;
   SmallVector<Decl *, 4> ExprCaptures;
   SmallVector<Expr *, 4> ExprPostUpdates;
-  if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
-      LinKind == OMPC_LINEAR_unknown) {
-    Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+  if (CheckOpenMPLinearModifier(LinKind, LinLoc))
     LinKind = OMPC_LINEAR_val;
-  }
   for (auto &RefExpr : VarList) {
     assert(RefExpr && "NULL expr in OpenMP linear clause.");
     SourceLocation ELoc;
@@ -8699,45 +8880,9 @@ OMPClause *Sema::ActOnOpenMPLinearClause
       continue;
     }
 
-    // A variable must not have an incomplete type or a reference type.
-    if (RequireCompleteType(ELoc, Type,
-                            diag::err_omp_linear_incomplete_type))
+    if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type))
       continue;
-    if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
-        !Type->isReferenceType()) {
-      Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
-          << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
-      continue;
-    }
-    Type = Type.getNonReferenceType();
-
-    // A list item must not be const-qualified.
-    if (Type.isConstant(Context)) {
-      Diag(ELoc, diag::err_omp_const_variable)
-          << getOpenMPClauseName(OMPC_linear);
-      bool IsDecl =
-          !VD ||
-          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
-      Diag(D->getLocation(),
-           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-          << D;
-      continue;
-    }
-
-    // A list item must be of integral or pointer type.
-    Type = Type.getUnqualifiedType().getCanonicalType();
-    const auto *Ty = Type.getTypePtrOrNull();
-    if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
-                !Ty->isPointerType())) {
-      Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
-      bool IsDecl =
-          !VD ||
-          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
-      Diag(D->getLocation(),
-           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-          << D;
-      continue;
-    }
+    Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType();
 
     // Build private copy of original var.
     auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(),

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Apr 12 06:02:11 2016
@@ -239,15 +239,13 @@ instantiateDependentModeAttr(Sema &S,
 static void instantiateOMPDeclareSimdDeclAttr(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
-  ExprResult Simdlen;
-  if (auto *E = Attr.getSimdlen())
-    Simdlen = S.SubstExpr(E, TemplateArgs);
   // Allow 'this' in clauses with varlists.
   if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
     New = FTD->getTemplatedDecl();
   auto *FD = cast<FunctionDecl>(New);
   auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
-  SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments;
+  SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
+  SmallVector<unsigned, 4> LinModifiers;
 
   auto &&Subst = [&](Expr *E) -> ExprResult {
     if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
@@ -264,6 +262,10 @@ static void instantiateOMPDeclareSimdDec
     return S.SubstExpr(E, TemplateArgs);
   };
 
+  ExprResult Simdlen;
+  if (auto *E = Attr.getSimdlen())
+    Simdlen = Subst(E);
+
   if (Attr.uniforms_size() > 0) {
     for(auto *E : Attr.uniforms()) {
       ExprResult Inst = Subst(E);
@@ -285,9 +287,24 @@ static void instantiateOMPDeclareSimdDec
     Alignments.push_back(Inst.get());
     ++AI;
   }
+
+  auto SI = Attr.steps_begin();
+  for (auto *E : Attr.linears()) {
+    ExprResult Inst = Subst(E);
+    if (Inst.isInvalid())
+      continue;
+    Linears.push_back(Inst.get());
+    Inst = ExprEmpty();
+    if (*SI)
+      Inst = S.SubstExpr(*SI, TemplateArgs);
+    Steps.push_back(Inst.get());
+    ++SI;
+  }
+  LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end());
   (void)S.ActOnOpenMPDeclareSimdDirective(
       S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(),
-      Uniforms, Aligneds, Alignments, Attr.getRange());
+      Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps,
+      Attr.getRange());
 }
 
 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,

Modified: cfe/trunk/test/OpenMP/declare_simd_ast_print.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_simd_ast_print.c?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_ast_print.c (original)
+++ cfe/trunk/test/OpenMP/declare_simd_ast_print.c Tue Apr 12 06:02:11 2016
@@ -7,15 +7,15 @@
 #define HEADER
 
 #pragma omp declare simd aligned(b : 64)
-#pragma omp declare simd simdlen(32) aligned(d, s1)
-#pragma omp declare simd inbranch, uniform(d)
-#pragma omp declare simd notinbranch simdlen(2), uniform(s1, s2)
-void add_1(float *d, float *s1, float *s2, double b[]) __attribute__((cold));
+#pragma omp declare simd simdlen(32) aligned(d, b)
+#pragma omp declare simd inbranch, uniform(d) linear(val(s1, s2) : 32)
+#pragma omp declare simd notinbranch simdlen(2), uniform(s1, s2) linear(d: s1)
+void add_1(float *d, int s1, float *s2, double b[]) __attribute__((cold));
 
-// CHECK: #pragma omp declare simd notinbranch simdlen(2) uniform(s1, s2)
-// CHECK-NEXT: #pragma omp declare simd inbranch uniform(d)
-// CHECK-NEXT: #pragma omp declare simd simdlen(32) aligned(d) aligned(s1)
+// CHECK: #pragma omp declare simd notinbranch simdlen(2) uniform(s1, s2) linear(val(d): s1)
+// CHECK-NEXT: #pragma omp declare simd inbranch uniform(d) linear(val(s1): 32) linear(val(s2): 32)
+// CHECK-NEXT: #pragma omp declare simd simdlen(32) aligned(d) aligned(b)
 // CHECK-NEXT: #pragma omp declare simd aligned(b: 64)
-// CHECK-NEXT: void add_1(float *d, float *s1, float *s2, double b[]) __attribute__((cold))
+// CHECK-NEXT: void add_1(float *d, int s1, float *s2, double b[]) __attribute__((cold))
 
 #endif

Modified: cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp (original)
+++ cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp Tue Apr 12 06:02:11 2016
@@ -6,14 +6,14 @@
 #ifndef HEADER
 #define HEADER
 
-#pragma omp declare simd
+#pragma omp declare simd linear(d: 8)
 #pragma omp declare simd inbranch simdlen(32)
 #pragma omp declare simd notinbranch
 void add_1(float *d) __attribute__((cold));
 
 // CHECK: #pragma omp declare simd notinbranch
 // CHECK-NEXT: #pragma omp declare simd inbranch simdlen(32)
-// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd linear(val(d): 8)
 // CHECK-NEXT: void add_1(float *d) __attribute__((cold));
 //
 
@@ -48,28 +48,28 @@ void h(int *hp, int *hp2, int *hq, int *
 }
 
 class VV {
-  // CHECK: #pragma omp declare simd uniform(this, a)
+  // CHECK: #pragma omp declare simd uniform(this, a) linear(val(b): a)
   // CHECK-NEXT: int add(int a, int b) __attribute__((cold))    {
   // CHECK-NEXT: return a + b;
   // CHECK-NEXT: }
-  #pragma omp declare simd uniform(this, a)
+  #pragma omp declare simd uniform(this, a) linear(val(b): a)
   int add(int a, int b) __attribute__((cold)) { return a + b; }
 
-  // CHECK: #pragma omp declare simd aligned(b: 4) aligned(a)
+  // CHECK: #pragma omp declare simd aligned(b: 4) aligned(a) linear(ref(b): 4) linear(val(this)) linear(val(a))
   // CHECK-NEXT: float taddpf(float *a, float *&b)     {
   // CHECK-NEXT: return *a + *b;
   // CHECK-NEXT: }
-  #pragma omp declare simd aligned (b: 4) aligned(a)
+  #pragma omp declare simd aligned (b: 4) aligned(a) linear(ref(b): 4) linear(this, a)
   float taddpf(float *a, float *&b) { return *a + *b; }
 
 // CHECK: #pragma omp declare simd aligned(b: 8)
-// CHECK-NEXT: #pragma omp declare simd
-// CHECK-NEXT: int tadd(int (&b)[]) {
+// CHECK-NEXT: #pragma omp declare simd linear(uval(c): 8)
+// CHECK-NEXT: int tadd(int (&b)[], int &c) {
 // CHECK-NEXT: return this->x[b[0]] + b[0];
 // CHECK-NEXT: }
-  #pragma omp declare simd
+  #pragma omp declare simd linear(uval(c): 8)
   #pragma omp declare simd aligned(b : 8)
-  int tadd(int (&b)[]) { return x[b[0]] + b[0]; }
+  int tadd(int (&b)[], int &c) { return x[b[0]] + b[0]; }
 
 private:
   int x[10];
@@ -78,7 +78,7 @@ private:
 // CHECK: template <int X = 16, typename T = float> class TVV {
 // CHECK: #pragma omp declare simd
 // CHECK-NEXT: int tadd(int a, int b);
-// CHECK: #pragma omp declare simd aligned(a: 16 * 2) aligned(b)
+// CHECK: #pragma omp declare simd aligned(a: 16 * 2) aligned(b) linear(ref(b): 16)
 // CHECK-NEXT: float taddpf(float *a, float *&b) {
 // CHECK-NEXT: return *a + *b;
 // CHECK-NEXT: }
@@ -100,7 +100,7 @@ public:
 // CHECK-NEXT: return a + b;
 // CHECK-NEXT: }
 
-  #pragma omp declare simd aligned(a : X * 2) aligned(b)
+  #pragma omp declare simd aligned(a : X * 2) aligned(b) linear(ref(b): X)
   float taddpf(float *a, T *&b) { return *a + *b; }
 
 // CHECK: #pragma omp declare simd aligned(a: X * 2) aligned(b)
@@ -123,13 +123,13 @@ private:
 };
 // CHECK: };
 
-// CHECK: #pragma omp declare simd simdlen(64) aligned(b: 64 * 2)
-// CHECK: template <int N = 64> void foo(int (&b)[64])
-// CHECK: #pragma omp declare simd simdlen(N) aligned(b: N * 2)
-// CHECK: template <int N> void foo(int (&b)[N])
-#pragma omp declare simd simdlen(N) aligned(b : N * 2)
+// CHECK: #pragma omp declare simd simdlen(64) aligned(b: 64 * 2) linear(uval(c): 64)
+// CHECK: template <int N = 64> void foo(int (&b)[64], float *&c)
+// CHECK: #pragma omp declare simd simdlen(N) aligned(b: N * 2) linear(uval(c): N)
+// CHECK: template <int N> void foo(int (&b)[N], float *&c)
+#pragma omp declare simd simdlen(N) aligned(b : N * 2) linear(uval(c): N)
 template <int N>
-void foo(int (&b)[N]);
+void foo(int (&b)[N], float *&c);
 
 // CHECK: TVV<16, float> t16;
 TVV<16, float> t16;
@@ -140,7 +140,7 @@ void f() {
   float r = t16.taddpf(&a, p);
   int res = t16.tadd(b);
   int c[64];
-  foo(c);
+  foo(c, p);
 }
 
 #endif

Modified: cfe/trunk/test/OpenMP/declare_simd_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_simd_messages.cpp?rev=266056&r1=266055&r2=266056&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/declare_simd_messages.cpp Tue Apr 12 06:02:11 2016
@@ -144,6 +144,57 @@ void test() {
 #pragma omp declare simd aligned(b: -1)
 // expected-warning at +1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
 #pragma omp declare simd aligned(b: 3)
+// expected-error at +1 {{expected '(' after 'linear'}}
+#pragma omp declare simd linear
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expected ')'}}
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd linear(
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd linear()
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expected ')'}}
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd linear(a:
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd linear(a:)
+// expected-warning at +2 {{extra tokens at the end of '#pragma omp declare simd' are ignored}}
+// expected-error at +1 {{expected '(' after 'linear'}}
+#pragma omp declare simd linear :)
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expected ')'}}
+// expected-error at +1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd linear(this
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expected ')'}}
+// expected-error at +1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd linear(this,b
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd linear(, b)
+// expected-note at +4 {{defined as linear}}
+// expected-error at +3 {{linear variable cannot be linear}}
+// expected-error at +2 {{expected expression}}
+// expected-error at +1 {{expected ',' or ')' in 'linear' clause}}
+#pragma omp declare simd linear(b) linear(b ; 64)
+// expected-note at +2 {{defined as linear}}
+// expected-error at +1 {{linear variable cannot be linear}}
+#pragma omp declare simd linear(b) linear(b: 64)
+#pragma omp declare simd linear(b: -1)
+#pragma omp declare simd linear(b: 3)
+// expected-error at +1 {{expected a reference to a parameter specified in a 'uniform' clause}}
+#pragma omp declare simd linear(b: a)
+// expected-note at +2 {{defined as uniform}}
+// expected-error at +1 {{linear variable cannot be uniform}}
+#pragma omp declare simd uniform(a), linear(a: 4)
+// expected-note at +2 {{defined as uniform}}
+// expected-error at +1 {{linear variable cannot be uniform}}
+#pragma omp declare simd linear(a: 4) uniform(a)
+// expected-error at +1 {{variable of non-reference type 'int *' can be used only with 'val' modifier, but used with 'uval'}}
+#pragma omp declare simd linear(uval(b))
+// expected-error at +1 {{variable of non-reference type 'int *' can be used only with 'val' modifier, but used with 'ref'}}
+#pragma omp declare simd linear(ref(b))
+// expected-error at +1 {{expected one of 'ref', val' or 'uval' modifiers}}
+#pragma omp declare simd linear(uref(b))
 void bar(int a, int *b);
 
 template <class T>
@@ -152,11 +203,14 @@ struct St {
 #pragma init_seg(compiler)
 #pragma omp declare simd
 #pragma init_seg(compiler)
+// expected-note at +7 {{defined as uniform}}
+// expected-error at +6 {{expected a reference to a parameter specified in a 'uniform' clause}}
+// expected-error at +5 {{linear variable cannot be uniform}}
 // expected-note at +4 {{defined as aligned}}
 // expected-error at +3 {{argument to 'aligned' clause must be a strictly positive integer value}}
 // expected-error at +2 {{'this' cannot appear in more than one aligned clause}}
 // expected-error at +1 {{use of undeclared identifier 't'}}
-#pragma omp declare simd uniform(this, t) aligned(this: 4) aligned(this: -4)
+#pragma omp declare simd uniform(this, t) aligned(this: 4) aligned(this: -4) linear(this: hp)
   void h(T *hp) {
 // expected-error at +1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
 #pragma omp declare simd




More information about the cfe-commits mailing list