r265668 - [OPENMP 4.0] Parsing/sema analysis for 'simdlen' clause in 'declare simd'

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 7 05:45:38 PDT 2016


Author: abataev
Date: Thu Apr  7 07:45:37 2016
New Revision: 265668

URL: http://llvm.org/viewvc/llvm-project?rev=265668&view=rev
Log:
[OPENMP 4.0] Parsing/sema analysis for 'simdlen' clause in 'declare simd'
construct.

OpenMP 4.0 defines '#pragma omp declare simd' construct that may have
associated 'simdlen' clause with constant positive expression as an
argument:
simdlen(<const_expr>)
Patch adds parsin and semantic analysis for simdlen clause.

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Parse/Parser.h
    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
    cfe/trunk/test/OpenMP/dump.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Apr  7 07:45:37 2016
@@ -2265,13 +2265,22 @@ def OMPDeclareSimdDecl : Attr {
   let SemaHandler = 0;
   let HasCustomParsing = 1;
   let Documentation = [OMPDeclareSimdDocs];
-  let Args = [EnumArgument<"BranchState", "BranchStateTy",
-                           ["", "inbranch", "notinbranch"],
-                           ["BS_Undefined", "BS_Inbranch", "BS_Notinbranch"]>];
+  let Args = [
+    EnumArgument<"BranchState", "BranchStateTy",
+                 [ "", "inbranch", "notinbranch" ],
+                 [ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
+    ExprArgument<"Simdlen">
+  ];
   let AdditionalMembers = [{
     void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
         const {
-      OS << ' ' << ConvertBranchStateTyToStr(getBranchState());
+      if (getBranchState() != BS_Undefined)
+        OS << ConvertBranchStateTyToStr(getBranchState()) << " ";
+      if (auto *E = getSimdlen()) {
+        OS << "simdlen(";
+        E->printPretty(OS, nullptr, Policy);
+        OS << ") ";
+      }
     }
   }];
 }

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu Apr  7 07:45:37 2016
@@ -2456,6 +2456,10 @@ private:
 
   //===--------------------------------------------------------------------===//
   // OpenMP: Directives and clauses.
+  /// Parse clauses for '#pragma omp declare simd'.
+  DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr,
+                                            CachedTokens &Toks,
+                                            SourceLocation Loc);
   /// \brief Parses declarative OpenMP directives.
   DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
       AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
@@ -2520,6 +2524,10 @@ private:
                                       OpenMPClauseKind Kind);
 
 public:
+  /// Parses simple expression in parens for single-expression clauses of OpenMP
+  /// constructs.
+  /// \param LLoc Returned location of left paren.
+  ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc);
   bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
                           bool AllowDestructorName,
                           bool AllowConstructorName,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Apr  7 07:45:37 2016
@@ -8107,7 +8107,7 @@ public:
   DeclGroupPtrTy
   ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
                                   OMPDeclareSimdDeclAttr::BranchStateTy BS,
-                                  SourceRange SR);
+                                  Expr *Simdlen, 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=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original)
+++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Thu Apr  7 07:45:37 2016
@@ -332,32 +332,134 @@ Parser::ParseOpenMPDeclareReductionDirec
 /// Parses clauses for 'declare simd' directive.
 ///    clause:
 ///      'inbranch' | 'notinbranch'
-static void parseDeclareSimdClauses(Parser &P,
-                                    OMPDeclareSimdDeclAttr::BranchStateTy &BS) {
+///      'simdlen' '('<expr> ')'
+static bool parseDeclareSimdClauses(Parser &P,
+                                    OMPDeclareSimdDeclAttr::BranchStateTy &BS,
+                                    ExprResult &SimdLen) {
   SourceRange BSRange;
   const Token &Tok = P.getCurToken();
+  bool IsError = false;
   while (Tok.isNot(tok::annot_pragma_openmp_end)) {
     if (Tok.isNot(tok::identifier))
       break;
     OMPDeclareSimdDeclAttr::BranchStateTy Out;
-    StringRef TokName = Tok.getIdentifierInfo()->getName();
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+    StringRef ClauseName = II->getName();
     // Parse 'inranch|notinbranch' clauses.
-    if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(TokName, Out)) {
+    if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {
       if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {
         P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)
-            << TokName << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS)
-            << BSRange;
+            << ClauseName
+            << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;
+        IsError = true;
       }
       BS = Out;
       BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());
+      P.ConsumeToken();
+    } else if (ClauseName.equals("simdlen")) {
+      if (SimdLen.isUsable()) {
+        P.Diag(Tok, diag::err_omp_more_one_clause)
+            << getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;
+        IsError = true;
+      }
+      P.ConsumeToken();
+      SourceLocation RLoc;
+      SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
+      if (SimdLen.isInvalid())
+        IsError = true;
     } else
       // TODO: add parsing of other clauses.
       break;
-    P.ConsumeToken();
     // Skip ',' if any.
     if (Tok.is(tok::comma))
       P.ConsumeToken();
   }
+  return IsError;
+}
+
+namespace {
+/// RAII that recreates function context for correct parsing of clauses of
+/// 'declare simd' construct.
+/// OpenMP, 2.8.2 declare simd Construct
+/// The expressions appearing in the clauses of this directive are evaluated in
+/// the scope of the arguments of the function declaration or definition.
+class FNContextRAII final {
+  Parser &P;
+  Sema::CXXThisScopeRAII *ThisScope;
+  Parser::ParseScope *TempScope;
+  Parser::ParseScope *FnScope;
+  bool HasTemplateScope = false;
+  bool HasFunScope = false;
+  FNContextRAII() = delete;
+  FNContextRAII(const FNContextRAII &) = delete;
+  FNContextRAII &operator=(const FNContextRAII &) = delete;
+
+public:
+  FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) {
+    Decl *D = *Ptr.get().begin();
+    NamedDecl *ND = dyn_cast<NamedDecl>(D);
+    RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
+    Sema &Actions = P.getActions();
+
+    // Allow 'this' within late-parsed attributes.
+    ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, /*TypeQuals=*/0,
+                                           ND && ND->isCXXInstanceMember());
+
+    // If the Decl is templatized, add template parameters to scope.
+    HasTemplateScope = D->isTemplateDecl();
+    TempScope =
+        new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope);
+    if (HasTemplateScope)
+      Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D);
+
+    // If the Decl is on a function, add function parameters to the scope.
+    HasFunScope = D->isFunctionOrFunctionTemplate();
+    FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope,
+                                     HasFunScope);
+    if (HasFunScope)
+      Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);
+  }
+  ~FNContextRAII() {
+    if (HasFunScope) {
+      P.getActions().ActOnExitFunctionContext();
+      FnScope->Exit(); // Pop scope, and remove Decls from IdResolver
+    }
+    if (HasTemplateScope)
+      TempScope->Exit();
+    delete FnScope;
+    delete TempScope;
+    delete ThisScope;
+  }
+};
+} // namespace
+
+/// Parse clauses for '#pragma omp declare simd'.
+Parser::DeclGroupPtrTy
+Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
+                                   CachedTokens &Toks, SourceLocation Loc) {
+  PP.EnterToken(Tok);
+  PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
+  // Consume the previously pushed token.
+  ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+  FNContextRAII FnContext(*this, Ptr);
+  OMPDeclareSimdDeclAttr::BranchStateTy BS =
+      OMPDeclareSimdDeclAttr::BS_Undefined;
+  ExprResult Simdlen;
+  bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen);
+  // Need to check for extra tokens.
+  if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+    Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+        << getOpenMPDirectiveName(OMPD_declare_simd);
+    while (Tok.isNot(tok::annot_pragma_openmp_end))
+      ConsumeAnyToken();
+  }
+  // Skip the last annot_pragma_openmp_end.
+  SourceLocation EndLoc = ConsumeToken();
+  if (!IsError)
+    return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, Simdlen.get(),
+                                                   SourceRange(Loc, EndLoc));
+  return Ptr;
 }
 
 /// \brief Parsing of declarative OpenMP directives.
@@ -382,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpen
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
   SourceLocation Loc = ConsumeToken();
-  SmallVector<Expr *, 5> Identifiers;
+  SmallVector<Expr *, 4> Identifiers;
   auto DKind = ParseOpenMPDirectiveKind(*this);
 
   switch (DKind) {
@@ -422,21 +524,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpen
     // { #pragma omp declare simd }
     // <function-declaration-or-definition>
     //
-
     ConsumeToken();
-    OMPDeclareSimdDeclAttr::BranchStateTy BS =
-        OMPDeclareSimdDeclAttr::BS_Undefined;
-    parseDeclareSimdClauses(*this, BS);
-
-    // Need to check for extra tokens.
-    if (Tok.isNot(tok::annot_pragma_openmp_end)) {
-      Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
-          << getOpenMPDirectiveName(OMPD_declare_simd);
-      while (Tok.isNot(tok::annot_pragma_openmp_end))
-        ConsumeAnyToken();
-    }
-    // Skip the last annot_pragma_openmp_end.
-    SourceLocation EndLoc = ConsumeToken();
+    CachedTokens Toks;
+    ConsumeAndStoreUntil(tok::annot_pragma_openmp_end, Toks,
+                         /*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
 
     DeclGroupPtrTy Ptr;
     if (Tok.is(tok::annot_pragma_openmp))
@@ -458,9 +549,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpen
       Diag(Loc, diag::err_omp_decl_in_declare_simd);
       return DeclGroupPtrTy();
     }
-
-    return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS,
-                                                   SourceRange(Loc, EndLoc));
+    return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
   }
   case OMPD_declare_target: {
     SourceLocation DTLoc = ConsumeAnyToken();
@@ -1000,6 +1089,28 @@ OMPClause *Parser::ParseOpenMPClause(Ope
   return ErrorFound ? nullptr : Clause;
 }
 
+/// Parses simple expression in parens for single-expression clauses of OpenMP
+/// constructs.
+/// \param RLoc Returned location of right paren.
+ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
+                                         SourceLocation &RLoc) {
+  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+  if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))
+    return ExprError();
+
+  SourceLocation ELoc = Tok.getLocation();
+  ExprResult LHS(ParseCastExpression(
+      /*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast));
+  ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+  Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
+
+  // Parse ')'.
+  T.consumeClose();
+
+  RLoc = T.getCloseLocation();
+  return Val;
+}
+
 /// \brief Parsing of OpenMP clauses with single expressions like 'final',
 /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
 /// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'.
@@ -1033,25 +1144,15 @@ OMPClause *Parser::ParseOpenMPClause(Ope
 ///
 OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
   SourceLocation Loc = ConsumeToken();
+  SourceLocation LLoc = Tok.getLocation();
+  SourceLocation RLoc;
 
-  BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
-  if (T.expectAndConsume(diag::err_expected_lparen_after,
-                         getOpenMPClauseName(Kind)))
-    return nullptr;
-
-  SourceLocation ELoc = Tok.getLocation();
-  ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
-  ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
-  Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
-
-  // Parse ')'.
-  T.consumeClose();
+  ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
 
   if (Val.isInvalid())
     return nullptr;
 
-  return Actions.ActOnOpenMPSingleExprClause(
-      Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
+  return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
 }
 
 /// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.

Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Thu Apr  7 07:45:37 2016
@@ -3193,7 +3193,7 @@ StmtResult Sema::ActOnOpenMPExecutableDi
 Sema::DeclGroupPtrTy
 Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
                                       OMPDeclareSimdDeclAttr::BranchStateTy BS,
-                                      SourceRange SR) {
+                                      Expr *Simdlen, SourceRange SR) {
   if (!DG || DG.get().isNull())
     return DeclGroupPtrTy();
 
@@ -3211,7 +3211,17 @@ Sema::ActOnOpenMPDeclareSimdDirective(De
     return DeclGroupPtrTy();
   }
 
-  auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SR);
+  // OpenMP [2.8.2, declare simd construct, Description]
+  // The parameter of the simdlen clause must be a constant positive integer
+  // expression.
+  ExprResult SL;
+  if (Simdlen) {
+    SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
+    if (SL.isInvalid())
+      return DG;
+  }
+  auto *NewAttr =
+      OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SL.get(), SR);
   ADecl->addAttr(NewAttr);
   return ConvertDeclToDeclGroup(ADecl);
 }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Apr  7 07:45:37 2016
@@ -235,6 +235,22 @@ instantiateDependentModeAttr(Sema &S,
                 Attr.getSpellingListIndex(), /*InInstantiation=*/true);
 }
 
+/// Instantiation of 'declare simd' attribute and its arguments.
+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);
+    if (Simdlen.isInvalid())
+      return;
+  }
+
+  (void)S.ActOnOpenMPDeclareSimdDirective(S.ConvertDeclToDeclGroup(New),
+                                          Attr.getBranchState(), Simdlen.get(),
+                                          Attr.getRange());
+}
+
 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
                             const Decl *Tmpl, Decl *New,
                             LateInstantiatedAttrVec *LateAttrs,
@@ -278,6 +294,11 @@ void Sema::InstantiateAttrs(const MultiL
       continue;
     }
 
+    if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) {
+      instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New);
+      continue;
+    }
+
     // Existing DLL attribute on the instantiation takes precedence.
     if (TmplAttr->getKind() == attr::DLLExport ||
         TmplAttr->getKind() == attr::DLLImport) {

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=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_ast_print.c (original)
+++ cfe/trunk/test/OpenMP/declare_simd_ast_print.c Thu Apr  7 07:45:37 2016
@@ -7,14 +7,14 @@
 #define HEADER
 
 #pragma omp declare simd
-#pragma omp declare simd
+#pragma omp declare simd simdlen(32)
 #pragma omp declare simd inbranch
-#pragma omp declare simd notinbranch
+#pragma omp declare simd notinbranch simdlen(2)
 void add_1(float *d, float *s1, float *s2) __attribute__((cold));
 
-// CHECK: #pragma omp declare simd notinbranch
+// CHECK: #pragma omp declare simd notinbranch simdlen(2)
 // CHECK-NEXT: #pragma omp declare simd inbranch
-// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd simdlen(32)
 // CHECK-NEXT: #pragma omp declare simd
 // CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
 

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=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp (original)
+++ cfe/trunk/test/OpenMP/declare_simd_ast_print.cpp Thu Apr  7 07:45:37 2016
@@ -7,12 +7,12 @@
 #define HEADER
 
 #pragma omp declare simd
-#pragma omp declare simd inbranch
+#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
+// CHECK-NEXT: #pragma omp declare simd inbranch simdlen(32)
 // CHECK-NEXT: #pragma omp declare simd
 // CHECK-NEXT: void add_1(float *d) __attribute__((cold));
 //
@@ -92,10 +92,10 @@ template <int X>
 class TVV {
 public:
 // CHECK: template <int X> class TVV {
-  #pragma omp declare simd
+  #pragma omp declare simd simdlen(X)
   int tadd(int a, int b) { return a + b; }
 
-// CHECK: #pragma omp declare simd
+// CHECK: #pragma omp declare simd simdlen(X)
 // CHECK-NEXT: int tadd(int a, int b) {
 // CHECK-NEXT: return a + b;
 // CHECK-NEXT: }
@@ -123,6 +123,14 @@ private:
 };
 // CHECK: };
 
+// CHECK: #pragma omp declare simd simdlen(64)
+// CHECK: template <int N = 64> void foo(int (&)[64])
+// CHECK: #pragma omp declare simd simdlen(N)
+// CHECK: template <int N> void foo(int (&)[N])
+#pragma omp declare simd simdlen(N)
+template <int N>
+void foo(int (&)[N]);
+
 // CHECK: TVV<16> t16;
 TVV<16> t16;
 
@@ -130,6 +138,8 @@ void f() {
   float a = 1.0f, b = 2.0f;
   float r = t16.taddpf(&a, &b);
   int res = t16.tadd(b);
+  int c[64];
+  foo(c);
 }
 
 #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=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/declare_simd_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/declare_simd_messages.cpp Thu Apr  7 07:45:37 2016
@@ -32,9 +32,12 @@ int main();
 
 // expected-error at +1 {{single declaration is expected after 'declare simd' directive}}
 #pragma omp declare simd
+// expected-note at +1 {{declared here}}
 int b, c;
 
-#pragma omp declare simd
+// expected-error at +1 {{'C' does not refer to a value}}
+#pragma omp declare simd simdlen(C)
+// expected-note at +1 {{declared here}}
 template <class C>
 void h(C *hp, C *hp2, C *hq, C *lin) {
   b = 0;
@@ -50,8 +53,38 @@ void h(int *hp, int *hp2, int *hq, int *
 #pragma omp declare simd notinbranch notinbranch
 #pragma omp declare simd inbranch inbranch notinbranch // expected-error {{unexpected 'notinbranch' clause, 'inbranch' is specified already}}
 #pragma omp declare simd notinbranch notinbranch inbranch // expected-error {{unexpected 'inbranch' clause, 'notinbranch' is specified already}}
+// expected-note at +2 {{read of non-const variable 'b' is not allowed in a constant expression}}
+// expected-error at +1 {{expression is not an integral constant expression}}
+#pragma omp declare simd simdlen(b)
+// expected-error at +1 {{directive '#pragma omp declare simd' cannot contain more than one 'simdlen' clause}}
+#pragma omp declare simd simdlen(32) simdlen(c)
+// expected-error at +1 {{expected '(' after 'simdlen'}}
+#pragma omp declare simd simdlen
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expected ')'}}
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd simdlen(
+// expected-error at +2 {{expected '(' after 'simdlen'}}
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd simdlen(), simdlen
+// expected-error at +1 2 {{expected expression}}
+#pragma omp declare simd simdlen(), simdlen()
+// expected-warning at +3 {{extra tokens at the end of '#pragma omp declare simd' are ignored}}
+// expected-error at +2 {{expected '(' after 'simdlen'}}
+// expected-error at +1 {{expected expression}}
+#pragma omp declare simd simdlen() simdlen)
 void foo();
 
+// expected-error at +1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
+#pragma omp declare simd simdlen(N)
+template<int N>
+void foo() {}
+
+void test() {
+  // expected-note at +1 {{in instantiation of function template specialization 'foo<-3>' requested here}}
+  foo<-3>();
+}
+
 template <class T>
 struct St {
 // expected-error at +2 {{function declaration is expected after 'declare simd' directive}}

Modified: cfe/trunk/test/OpenMP/dump.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/dump.cpp?rev=265668&r1=265667&r2=265668&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/dump.cpp (original)
+++ cfe/trunk/test/OpenMP/dump.cpp Thu Apr  7 07:45:37 2016
@@ -64,5 +64,5 @@ void foo();
 
 // CHECK:      `-FunctionDecl {{.+}} <line:63:1, col:10> col:6 foo 'void (void)'
 // CHECK-NEXT:   |-OMPDeclareSimdDeclAttr {{.+}} <line:62:9, col:34> Implicit BS_Inbranch
-// CHECK-NEXT:   `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
+// CHECK:        `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
 




More information about the cfe-commits mailing list