[OPENMP 4.0] Support for 'uniform' clause in 'declare simd' directive.
authorAlexey Bataev <a.bataev@hotmail.com>
Tue, 12 Apr 2016 05:28:34 +0000 (05:28 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Tue, 12 Apr 2016 05:28:34 +0000 (05:28 +0000)
OpenMP 4.0 defines clause 'uniform' in 'declare simd' directive:
'uniform' '(' <argument-list> ')'
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.
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.

llvm-svn: 266041

15 files changed:
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/OpenMPKinds.h
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/OpenMPClause.cpp
clang/lib/Basic/OpenMPKinds.cpp
clang/lib/CodeGen/CGStmtOpenMP.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/OpenMP/declare_simd_ast_print.c
clang/test/OpenMP/declare_simd_ast_print.cpp
clang/test/OpenMP/declare_simd_messages.cpp

index 6d86727..46a5bfe 100644 (file)
@@ -2517,6 +2517,7 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
     break;
 #include "clang/Basic/OpenMPKinds.def"
   case OMPC_threadprivate:
+  case OMPC_uniform:
   case OMPC_unknown:
     break;
   }
index 4480873..5fcd2e9 100644 (file)
@@ -2276,7 +2276,7 @@ def OMPDeclareSimdDecl : Attr {
     EnumArgument<"BranchState", "BranchStateTy",
                  [ "", "inbranch", "notinbranch" ],
                  [ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
-    ExprArgument<"Simdlen">
+    ExprArgument<"Simdlen">, VariadicExprArgument<"Uniforms">
   ];
   let AdditionalMembers = [{
     void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
@@ -2288,6 +2288,16 @@ def OMPDeclareSimdDecl : Attr {
         E->printPretty(OS, nullptr, Policy);
         OS << ") ";
       }
+      if (uniforms_size() > 0) {
+        OS << "uniform";
+        StringRef Sep = "(";
+        for (auto *E : uniforms()) {
+          OS << Sep;
+          E->printPretty(OS, nullptr, Policy);
+          Sep = ", ";
+        }
+        OS << ") ";
+      }
     }
   }];
 }
index 7105c5d..76cf5c9 100644 (file)
@@ -8179,7 +8179,9 @@ def err_omp_schedule_nonmonotonic_ordered : Error<
 def err_omp_ordered_simd : Error<
   "'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">;
 def err_omp_variable_in_map_and_dsa : Error<
-  "%0 variable cannot be in a map clause in '#pragma omp %1' directive">; 
+  "%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">;
 } // end of OpenMP category
 
 let CategoryName = "Related Result Type Issue" in {
index 9a0bf5b..a6ec47b 100644 (file)
@@ -35,6 +35,7 @@ enum OpenMPClauseKind {
   OMPC_##Name,
 #include "clang/Basic/OpenMPKinds.def"
   OMPC_threadprivate,
+  OMPC_uniform,
   OMPC_unknown
 };
 
index 762fbc1..66406ba 100644 (file)
@@ -2528,6 +2528,25 @@ public:
   /// constructs.
   /// \param RLoc Returned location of right paren.
   ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc);
+
+  /// Data used for parsing list of variables in OpenMP clauses.
+  struct OpenMPVarListDataTy {
+    Expr *TailExpr = nullptr;
+    SourceLocation ColonLoc;
+    CXXScopeSpec ReductionIdScopeSpec;
+    DeclarationNameInfo ReductionId;
+    OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown;
+    OpenMPLinearClauseKind LinKind = OMPC_LINEAR_val;
+    OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
+    OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
+    bool IsMapTypeImplicit = false;
+    SourceLocation DepLinMapLoc;
+  };
+
+  /// Parses clauses with list.
+  bool ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind,
+                          SmallVectorImpl<Expr *> &Vars,
+                          OpenMPVarListDataTy &Data);
   bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
                           bool AllowDestructorName,
                           bool AllowConstructorName,
index f3c4ae5..54a3ed5 100644 (file)
@@ -8110,10 +8110,9 @@ public:
 
   /// \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, SourceRange SR);
+  DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(
+      DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS,
+      Expr *Simdlen, ArrayRef<Expr *> Uniforms, SourceRange SR);
 
   OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
                                          Expr *Expr,
index 8843ded..cacfa53 100644 (file)
@@ -86,6 +86,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
   case OMPC_hint:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     break;
   }
 
@@ -146,6 +147,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
   case OMPC_hint:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     break;
   }
 
index 07a410f..0a36b95 100644 (file)
@@ -55,6 +55,7 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
   return llvm::StringSwitch<OpenMPClauseKind>(Str)
 #define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name)
 #include "clang/Basic/OpenMPKinds.def"
+      .Case("uniform", OMPC_uniform)
       .Default(OMPC_unknown);
 }
 
@@ -67,6 +68,8 @@ const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) {
   case OMPC_##Name:                                                            \
     return #Name;
 #include "clang/Basic/OpenMPKinds.def"
+  case OMPC_uniform:
+    return "uniform";
   case OMPC_threadprivate:
     return "threadprivate or thread local";
   }
@@ -158,6 +161,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
   case OMPC_nogroup:
   case OMPC_num_tasks:
   case OMPC_hint:
+  case OMPC_uniform:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -292,6 +296,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
   case OMPC_nogroup:
   case OMPC_num_tasks:
   case OMPC_hint:
+  case OMPC_uniform:
     break;
   }
   llvm_unreachable("Invalid OpenMP simple clause kind");
index e52e171..92c05ea 100644 (file)
@@ -2975,6 +2975,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
   case OMPC_hint:
   case OMPC_dist_schedule:
   case OMPC_defaultmap:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed in 'omp atomic'.");
   }
 }
index a874b8e..6112c90 100644 (file)
@@ -332,10 +332,12 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
 /// Parses clauses for 'declare simd' directive.
 ///    clause:
 ///      'inbranch' | 'notinbranch'
-///      'simdlen' '('<expr> ')'
+///      'simdlen' '(' <expr> ')'
+///      { 'uniform' '(' <argument_list> ')' }
 static bool parseDeclareSimdClauses(Parser &P,
                                     OMPDeclareSimdDeclAttr::BranchStateTy &BS,
-                                    ExprResult &SimdLen) {
+                                    ExprResult &SimdLen,
+                                    SmallVectorImpl<Expr *> &Uniforms) {
   SourceRange BSRange;
   const Token &Tok = P.getCurToken();
   bool IsError = false;
@@ -367,6 +369,13 @@ static bool parseDeclareSimdClauses(Parser &P,
       SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
       if (SimdLen.isInvalid())
         IsError = true;
+    } else if (ClauseName.equals("uniform")) {
+      Parser::OpenMPVarListDataTy Data;
+
+      P.ConsumeToken();
+      if (P.ParseOpenMPVarList(OMPD_declare_simd,
+                               getOpenMPClauseKind(ClauseName), Uniforms, Data))
+        IsError = true;
     } else
       // TODO: add parsing of other clauses.
       break;
@@ -446,7 +455,8 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
   OMPDeclareSimdDeclAttr::BranchStateTy BS =
       OMPDeclareSimdDeclAttr::BS_Undefined;
   ExprResult Simdlen;
-  bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen);
+  SmallVector<Expr *, 4> Uniforms;
+  bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms);
   // Need to check for extra tokens.
   if (Tok.isNot(tok::annot_pragma_openmp_end)) {
     Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
@@ -457,8 +467,8 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
   // Skip the last annot_pragma_openmp_end.
   SourceLocation EndLoc = ConsumeToken();
   if (!IsError)
-    return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, Simdlen.get(),
-                                                   SourceRange(Loc, EndLoc));
+    return Actions.ActOnOpenMPDeclareSimdDirective(
+        Ptr, BS, Simdlen.get(), Uniforms, SourceRange(Loc, EndLoc));
   return Ptr;
 }
 
@@ -526,8 +536,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
     //
     ConsumeToken();
     CachedTokens Toks;
-    ConsumeAndStoreUntil(tok::annot_pragma_openmp_end, Toks,
-                         /*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
+    while(Tok.isNot(tok::annot_pragma_openmp_end)) {
+      Toks.push_back(Tok);
+      ConsumeAnyToken();
+    }
+    Toks.push_back(Tok);
+    ConsumeAnyToken();
 
     DeclGroupPtrTy Ptr;
     if (Tok.is(tok::annot_pragma_openmp))
@@ -1081,6 +1095,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
     SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
     break;
   case OMPC_threadprivate:
+  case OMPC_uniform:
     Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
                                                << getOpenMPDirectiveName(DKind);
     SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
@@ -1402,61 +1417,20 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
                               TemplateKWLoc, ReductionId);
 }
 
-/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
-/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
-///
-///    private-clause:
-///       'private' '(' list ')'
-///    firstprivate-clause:
-///       'firstprivate' '(' list ')'
-///    lastprivate-clause:
-///       'lastprivate' '(' list ')'
-///    shared-clause:
-///       'shared' '(' list ')'
-///    linear-clause:
-///       'linear' '(' linear-list [ ':' linear-step ] ')'
-///    aligned-clause:
-///       'aligned' '(' list [ ':' alignment ] ')'
-///    reduction-clause:
-///       'reduction' '(' reduction-identifier ':' list ')'
-///    copyprivate-clause:
-///       'copyprivate' '(' list ')'
-///    flush-clause:
-///       'flush' '(' list ')'
-///    depend-clause:
-///       'depend' '(' in | out | inout : list | source ')'
-///    map-clause:
-///       'map' '(' [ [ always , ]
-///          to | from | tofrom | alloc | release | delete ':' ] list ')';
-///
-/// For 'linear' clause linear-list may have the following forms:
-///  list
-///  modifier(list)
-/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
-OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
-                                            OpenMPClauseKind Kind) {
-  SourceLocation Loc = Tok.getLocation();
-  SourceLocation LOpen = ConsumeToken();
-  SourceLocation ColonLoc = SourceLocation();
-  // Optional scope specifier and unqualified id for reduction identifier.
-  CXXScopeSpec ReductionIdScopeSpec;
-  UnqualifiedId ReductionId;
+/// Parses clauses with list.
+bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
+                                OpenMPClauseKind Kind,
+                                SmallVectorImpl<Expr *> &Vars,
+                                OpenMPVarListDataTy &Data) {
+  UnqualifiedId UnqualifiedReductionId;
   bool InvalidReductionId = false;
-  OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown;
-  // OpenMP 4.1 [2.15.3.7, linear Clause]
-  //  If no modifier is specified it is assumed to be val.
-  OpenMPLinearClauseKind LinearModifier = OMPC_LINEAR_val;
-  OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
-  OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
-  bool MapTypeIsImplicit = false;
   bool MapTypeModifierSpecified = false;
-  SourceLocation DepLinMapLoc;
 
   // Parse '('.
   BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
   if (T.expectAndConsume(diag::err_expected_lparen_after,
                          getOpenMPClauseName(Kind)))
-    return nullptr;
+    return true;
 
   bool NeedRParenForLinear = false;
   BalancedDelimiterTracker LinearT(*this, tok::l_paren,
@@ -1465,47 +1439,45 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
   if (Kind == OMPC_reduction) {
     ColonProtectionRAIIObject ColonRAII(*this);
     if (getLangOpts().CPlusPlus)
-      ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec,
+      ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec,
                                      /*ObjectType=*/nullptr,
                                      /*EnteringContext=*/false);
-    InvalidReductionId =
-        ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
+    InvalidReductionId = ParseReductionId(*this, Data.ReductionIdScopeSpec,
+                                          UnqualifiedReductionId);
     if (InvalidReductionId) {
       SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
                 StopBeforeMatch);
     }
-    if (Tok.is(tok::colon)) {
-      ColonLoc = ConsumeToken();
-    } else {
+    if (Tok.is(tok::colon))
+      Data.ColonLoc = ConsumeToken();
+    else
       Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
-    }
+    if (!InvalidReductionId)
+      Data.ReductionId =
+          Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);
   } else if (Kind == OMPC_depend) {
   // Handle dependency type for depend clause.
     ColonProtectionRAIIObject ColonRAII(*this);
-    DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
-        Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
-    DepLinMapLoc = Tok.getLocation();
+    Data.DepKind =
+        static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
+            Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
+    Data.DepLinMapLoc = Tok.getLocation();
 
-    if (DepKind == OMPC_DEPEND_unknown) {
+    if (Data.DepKind == OMPC_DEPEND_unknown) {
       SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
                 StopBeforeMatch);
     } else {
       ConsumeToken();
       // Special processing for depend(source) clause.
-      if (DKind == OMPD_ordered && DepKind == OMPC_DEPEND_source) {
+      if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) {
         // Parse ')'.
         T.consumeClose();
-        return Actions.ActOnOpenMPVarListClause(
-            Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen,
-            /*ColonLoc=*/SourceLocation(), Tok.getLocation(),
-            ReductionIdScopeSpec, DeclarationNameInfo(), DepKind,
-            LinearModifier, MapTypeModifier, MapType, MapTypeIsImplicit,
-            DepLinMapLoc);
+        return false;
       }
     }
-    if (Tok.is(tok::colon)) {
-      ColonLoc = ConsumeToken();
-    else {
+    if (Tok.is(tok::colon))
+      Data.ColonLoc = ConsumeToken();
+    else {
       Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
                                       : diag::warn_pragma_expected_colon)
           << "dependency type";
@@ -1513,9 +1485,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
   } else if (Kind == OMPC_linear) {
     // Try to parse modifier if any.
     if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
-      LinearModifier = static_cast<OpenMPLinearClauseKind>(
+      Data.LinKind = static_cast<OpenMPLinearClauseKind>(
           getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
-      DepLinMapLoc = ConsumeToken();
+      Data.DepLinMapLoc = ConsumeToken();
       LinearT.consumeOpen();
       NeedRParenForLinear = true;
     }
@@ -1525,79 +1497,76 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
 
     /// The map clause modifier token can be either a identifier or the C++
     /// delete keyword.
-    auto IsMapClauseModifierToken = [](const Token &Tok) {
+    auto &&IsMapClauseModifierToken = [](const Token &Tok) -> bool {
       return Tok.isOneOf(tok::identifier, tok::kw_delete);
     };
 
     // The first identifier may be a list item, a map-type or a
     // map-type-modifier. The map modifier can also be delete which has the same
     // spelling of the C++ delete keyword.
-    MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
-        Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
-    DepLinMapLoc = Tok.getLocation();
+    Data.MapType =
+        IsMapClauseModifierToken(Tok)
+            ? static_cast<OpenMPMapClauseKind>(
+                  getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
+            : OMPC_MAP_unknown;
+    Data.DepLinMapLoc = Tok.getLocation();
     bool ColonExpected = false;
 
     if (IsMapClauseModifierToken(Tok)) {
       if (PP.LookAhead(0).is(tok::colon)) {
-        MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
-            Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
-        if (MapType == OMPC_MAP_unknown) {
+        if (Data.MapType == OMPC_MAP_unknown)
           Diag(Tok, diag::err_omp_unknown_map_type);
-        } else if (MapType == OMPC_MAP_always) {
+        else if (Data.MapType == OMPC_MAP_always)
           Diag(Tok, diag::err_omp_map_type_missing);
-        }
         ConsumeToken();
       } else if (PP.LookAhead(0).is(tok::comma)) {
         if (IsMapClauseModifierToken(PP.LookAhead(1)) &&
             PP.LookAhead(2).is(tok::colon)) {
-          MapTypeModifier =
-              static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
-                  Kind,
-                  IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
-          if (MapTypeModifier != OMPC_MAP_always) {
+          Data.MapTypeModifier = Data.MapType;
+          if (Data.MapTypeModifier != OMPC_MAP_always) {
             Diag(Tok, diag::err_omp_unknown_map_type_modifier);
-            MapTypeModifier = OMPC_MAP_unknown;
-          } else {
+            Data.MapTypeModifier = OMPC_MAP_unknown;
+          } else
             MapTypeModifierSpecified = true;
-          }
 
           ConsumeToken();
           ConsumeToken();
 
-          MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
-              Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
-          if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) {
+          Data.MapType =
+              IsMapClauseModifierToken(Tok)
+                  ? static_cast<OpenMPMapClauseKind>(
+                        getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
+                  : OMPC_MAP_unknown;
+          if (Data.MapType == OMPC_MAP_unknown ||
+              Data.MapType == OMPC_MAP_always)
             Diag(Tok, diag::err_omp_unknown_map_type);
-          }
           ConsumeToken();
         } else {
-          MapType = OMPC_MAP_tofrom;
-          MapTypeIsImplicit = true;
+          Data.MapType = OMPC_MAP_tofrom;
+          Data.IsMapTypeImplicit = true;
         }
       } else {
-        MapType = OMPC_MAP_tofrom;
-        MapTypeIsImplicit = true;
+        Data.MapType = OMPC_MAP_tofrom;
+        Data.IsMapTypeImplicit = true;
       }
     } else {
-      MapType = OMPC_MAP_tofrom;
-      MapTypeIsImplicit = true;
+      Data.MapType = OMPC_MAP_tofrom;
+      Data.IsMapTypeImplicit = true;
     }
 
-    if (Tok.is(tok::colon)) {
-      ColonLoc = ConsumeToken();
-    } else if (ColonExpected) {
+    if (Tok.is(tok::colon))
+      Data.ColonLoc = ConsumeToken();
+    else if (ColonExpected)
       Diag(Tok, diag::warn_pragma_expected_colon) << "map type";
-    }
   }
 
-  SmallVector<Expr *, 5> Vars;
   bool IsComma =
-      ((Kind != OMPC_reduction) && (Kind != OMPC_depend) &&
-       (Kind != OMPC_map)) ||
-      ((Kind == OMPC_reduction) && !InvalidReductionId) ||
-      ((Kind == OMPC_map) && (MapType != OMPC_MAP_unknown) &&
-       (!MapTypeModifierSpecified || MapTypeModifier == OMPC_MAP_always)) ||
-      ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown);
+      (Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
+      (Kind == OMPC_reduction && !InvalidReductionId) ||
+      (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown &&
+       (!MapTypeModifierSpecified ||
+        Data.MapTypeModifier == OMPC_MAP_always)) ||
+      (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown);
   const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
   while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
                      Tok.isNot(tok::annot_pragma_openmp_end))) {
@@ -1605,9 +1574,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
     // Parse variable
     ExprResult VarExpr =
         Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
-    if (VarExpr.isUsable()) {
+    if (VarExpr.isUsable())
       Vars.push_back(VarExpr.get());
-    else {
+    else {
       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
                 StopBeforeMatch);
     }
@@ -1629,15 +1598,14 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
     LinearT.consumeClose();
 
   // Parse ':' linear-step (or ':' alignment).
-  Expr *TailExpr = nullptr;
   const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
   if (MustHaveTail) {
-    ColonLoc = Tok.getLocation();
+    Data.ColonLoc = Tok.getLocation();
     SourceLocation ELoc = ConsumeToken();
     ExprResult Tail = ParseAssignmentExpression();
     Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc);
     if (Tail.isUsable())
-      TailExpr = Tail.get();
+      Data.TailExpr = Tail.get();
     else
       SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
                 StopBeforeMatch);
@@ -1645,18 +1613,59 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
 
   // Parse ')'.
   T.consumeClose();
-  if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) ||
+  if ((Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown &&
+       Vars.empty()) ||
       (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
-      (MustHaveTail && !TailExpr) || InvalidReductionId) {
+      (MustHaveTail && !Data.TailExpr) || InvalidReductionId)
+    return true;
+  return false;
+}
+
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
+/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
+///
+///    private-clause:
+///       'private' '(' list ')'
+///    firstprivate-clause:
+///       'firstprivate' '(' list ')'
+///    lastprivate-clause:
+///       'lastprivate' '(' list ')'
+///    shared-clause:
+///       'shared' '(' list ')'
+///    linear-clause:
+///       'linear' '(' linear-list [ ':' linear-step ] ')'
+///    aligned-clause:
+///       'aligned' '(' list [ ':' alignment ] ')'
+///    reduction-clause:
+///       'reduction' '(' reduction-identifier ':' list ')'
+///    copyprivate-clause:
+///       'copyprivate' '(' list ')'
+///    flush-clause:
+///       'flush' '(' list ')'
+///    depend-clause:
+///       'depend' '(' in | out | inout : list | source ')'
+///    map-clause:
+///       'map' '(' [ [ always , ]
+///          to | from | tofrom | alloc | release | delete ':' ] list ')';
+///
+/// For 'linear' clause linear-list may have the following forms:
+///  list
+///  modifier(list)
+/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
+OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
+                                            OpenMPClauseKind Kind) {
+  SourceLocation Loc = Tok.getLocation();
+  SourceLocation LOpen = ConsumeToken();
+  SmallVector<Expr *, 4> Vars;
+  OpenMPVarListDataTy Data;
+
+  if (ParseOpenMPVarList(DKind, Kind, Vars, Data))
     return nullptr;
-  }
 
   return Actions.ActOnOpenMPVarListClause(
-      Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
-      ReductionIdScopeSpec,
-      ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
-                            : DeclarationNameInfo(),
-      DepKind, LinearModifier, MapTypeModifier, MapType, MapTypeIsImplicit,
-      DepLinMapLoc);
+      Kind, Vars, Data.TailExpr, Loc, LOpen, Data.ColonLoc, Tok.getLocation(),
+      Data.ReductionIdScopeSpec, Data.ReductionId, Data.DepKind, Data.LinKind,
+      Data.MapTypeModifier, Data.MapType, Data.IsMapTypeImplicit,
+      Data.DepLinMapLoc);
 }
 
index 3705cf2..43a774e 100644 (file)
@@ -3190,10 +3190,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
   return Res;
 }
 
-Sema::DeclGroupPtrTy
-Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
-                                      OMPDeclareSimdDeclAttr::BranchStateTy BS,
-                                      Expr *Simdlen, SourceRange SR) {
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
+    DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
+    ArrayRef<Expr *> Uniforms, SourceRange SR) {
   if (!DG || DG.get().isNull())
     return DeclGroupPtrTy();
 
@@ -3205,9 +3204,9 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
   if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
     ADecl = FTD->getTemplatedDecl();
 
-  if (!isa<FunctionDecl>(ADecl)) {
-    Diag(ADecl->getLocation(), diag::err_omp_function_expected)
-        << ADecl->getDeclContext()->isFileContext();
+  auto *FD = dyn_cast<FunctionDecl>(ADecl);
+  if (!FD) {
+    Diag(ADecl->getLocation(), diag::err_omp_function_expected);
     return DeclGroupPtrTy();
   }
 
@@ -3215,13 +3214,30 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
   // The parameter of the simdlen clause must be a constant positive integer
   // expression.
   ExprResult SL;
-  if (Simdlen) {
+  if (Simdlen)
     SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
-    if (SL.isInvalid())
-      return DG;
+  // OpenMP [2.8.2, declare simd construct, Description]
+  // 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.
+  // 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.
+  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())
+          continue;
+    if (isa<CXXThisExpr>(E))
+      continue;
+    Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+        << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
   }
-  auto *NewAttr =
-      OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SL.get(), SR);
+  auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
+      Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
+      Uniforms.size(), SR);
   ADecl->addAttr(NewAttr);
   return ConvertDeclToDeclGroup(ADecl);
 }
@@ -6386,6 +6402,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_dist_schedule:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -6671,6 +6688,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
   case OMPC_dist_schedule:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -6821,6 +6839,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
   case OMPC_num_tasks:
   case OMPC_hint:
   case OMPC_unknown:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -7004,6 +7023,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
   case OMPC_dist_schedule:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
@@ -7149,6 +7169,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
   case OMPC_dist_schedule:
   case OMPC_defaultmap:
   case OMPC_unknown:
+  case OMPC_uniform:
     llvm_unreachable("Clause is not allowed.");
   }
   return Res;
index c60a17a..168bf6f 100644 (file)
@@ -240,15 +240,42 @@ static void instantiateOMPDeclareSimdDeclAttr(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
   ExprResult Simdlen;
-  if (auto *E = Attr.getSimdlen()) {
+  if (auto *E = Attr.getSimdlen())
     Simdlen = S.SubstExpr(E, TemplateArgs);
-    if (Simdlen.isInvalid())
-      return;
+  // 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;
+
+  auto &&Subst = [&](Expr *E) -> ExprResult {
+    if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+      if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+        Sema::ContextRAII SavedContext(S, FD);
+        LocalInstantiationScope Local(S);
+        if (FD->getNumParams() > PVD->getFunctionScopeIndex())
+          Local.InstantiatedLocal(
+              PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
+        return S.SubstExpr(E, TemplateArgs);
+      }
+    Sema::CXXThisScopeRAII ThisScope(S, ThisContext, /*TypeQuals=*/0,
+                                     FD->isCXXInstanceMember());
+    return S.SubstExpr(E, TemplateArgs);
+  };
+
+  if (Attr.uniforms_size() > 0) {
+    for(auto *E : Attr.uniforms()) {
+      ExprResult Inst = Subst(E);
+      if (Inst.isInvalid())
+        continue;
+      Uniforms.push_back(Inst.get());
+    }
   }
 
   (void)S.ActOnOpenMPDeclareSimdDirective(S.ConvertDeclToDeclGroup(New),
                                           Attr.getBranchState(), Simdlen.get(),
-                                          Attr.getRange());
+                                          Uniforms, Attr.getRange());
 }
 
 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
index 49dd102..fe6bffc 100644 (file)
@@ -8,12 +8,12 @@
 
 #pragma omp declare simd
 #pragma omp declare simd simdlen(32)
-#pragma omp declare simd inbranch
-#pragma omp declare simd notinbranch simdlen(2)
+#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) __attribute__((cold));
 
-// CHECK: #pragma omp declare simd notinbranch simdlen(2)
-// CHECK-NEXT: #pragma omp declare simd inbranch
+// 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)
 // CHECK-NEXT: #pragma omp declare simd
 // CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
index 5adbb95..e38ebe9 100644 (file)
@@ -48,11 +48,11 @@ void h(int *hp, int *hp2, int *hq, int *lin)
 }
 
 class VV {
-  // CHECK: #pragma omp declare simd
+  // CHECK: #pragma omp declare simd uniform(this, a)
   // CHECK-NEXT: int add(int a, int b) __attribute__((cold))    {
   // CHECK-NEXT: return a + b;
   // CHECK-NEXT: }
-  #pragma omp declare simd
+  #pragma omp declare simd uniform(this, a)
   int add(int a, int b) __attribute__((cold)) { return a + b; }
 
   // CHECK: #pragma omp declare simd
@@ -109,10 +109,10 @@ public:
 // CHECK-NEXT: }
 
   #pragma omp declare simd
-  #pragma omp declare simd
+  #pragma omp declare simd uniform(this, b)
   int tadd(int b) { return x[b] + b; }
 
-// CHECK: #pragma omp declare simd
+// CHECK: #pragma omp declare simd uniform(this, b)
 // CHECK-NEXT: #pragma omp declare simd
 // CHECK-NEXT: int tadd(int b) {
 // CHECK-NEXT: return this->x[b] + b;
index b222388..70737ad 100644 (file)
@@ -75,8 +75,10 @@ void h(int *hp, int *hp2, int *hq, int *lin) {
 #pragma omp declare simd simdlen() simdlen)
 void foo();
 
+// expected-error@+3 2 {{expected reference to one of the parameters of function 'foo'}}
+// expected-error@+2 {{invalid use of 'this' outside of a non-static member function}}
 // expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
-#pragma omp declare simd simdlen(N)
+#pragma omp declare simd simdlen(N) uniform(this, var)
 template<int N>
 void foo() {}
 
@@ -85,12 +87,34 @@ void test() {
   foo<-3>();
 }
 
+// expected-error@+1 {{expected '(' after 'uniform'}}
+#pragma omp declare simd uniform
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd uniform(
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd uniform()
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd uniform(this
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd uniform(this,a
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd uniform(,a)
+void bar(int a);
+
 template <class T>
 struct St {
 // expected-error@+2 {{function declaration is expected after 'declare simd' directive}}
 #pragma init_seg(compiler)
 #pragma omp declare simd
 #pragma init_seg(compiler)
+// expected-error@+1 {{use of undeclared identifier 't'}}
+#pragma omp declare simd uniform(this, t)
   void h(T *hp) {
 // expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
 #pragma omp declare simd