From e48a5fc56d7dbd6e24e7fd326c3e50630b648da7 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 12 Apr 2016 05:28:34 +0000 Subject: [PATCH] [OPENMP 4.0] Support for 'uniform' clause in 'declare simd' directive. OpenMP 4.0 defines clause 'uniform' in 'declare simd' directive: 'uniform' '(' ')' 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 --- clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/Basic/Attr.td | 12 +- .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/include/clang/Basic/OpenMPKinds.h | 1 + clang/include/clang/Parse/Parser.h | 19 + clang/include/clang/Sema/Sema.h | 7 +- clang/lib/AST/OpenMPClause.cpp | 2 + clang/lib/Basic/OpenMPKinds.cpp | 5 + clang/lib/CodeGen/CGStmtOpenMP.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 457 +++++++++--------- clang/lib/Sema/SemaOpenMP.cpp | 45 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 35 +- clang/test/OpenMP/declare_simd_ast_print.c | 8 +- clang/test/OpenMP/declare_simd_ast_print.cpp | 8 +- clang/test/OpenMP/declare_simd_messages.cpp | 26 +- 15 files changed, 376 insertions(+), 255 deletions(-) diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 6d867270e050..46a5bfef96cb 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2517,6 +2517,7 @@ bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { break; #include "clang/Basic/OpenMPKinds.def" case OMPC_threadprivate: + case OMPC_uniform: case OMPC_unknown: break; } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 44808734a0bd..5fcd2e9458e2 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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 << ") "; + } } }]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7105c5d10927..76cf5c947ce7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 { diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 9a0bf5b60bbd..a6ec47bc5f69 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -35,6 +35,7 @@ enum OpenMPClauseKind { OMPC_##Name, #include "clang/Basic/OpenMPKinds.def" OMPC_threadprivate, + OMPC_uniform, OMPC_unknown }; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 762fbc1d5d6e..66406ba36ef7 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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 &Vars, + OpenMPVarListDataTy &Data); bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f3c4ae5caf45..54a3ed56d6f5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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 Uniforms, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 8843ded050b6..cacfa53d8c97 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -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; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 07a410f052c4..0a36b957fab5 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -55,6 +55,7 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { return llvm::StringSwitch(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"); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e52e1719c7e2..92c05eabdb6f 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -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'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index a874b8e8ebfa..6112c90cacda 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -332,10 +332,12 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { /// Parses clauses for 'declare simd' directive. /// clause: /// 'inbranch' | 'notinbranch' -/// 'simdlen' '(' ')' +/// 'simdlen' '(' ')' +/// { 'uniform' '(' ')' } static bool parseDeclareSimdClauses(Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, - ExprResult &SimdLen) { + ExprResult &SimdLen, + SmallVectorImpl &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 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,6 +1417,210 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, TemplateKWLoc, ReductionId); } +/// Parses clauses with list. +bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind, + SmallVectorImpl &Vars, + OpenMPVarListDataTy &Data) { + UnqualifiedId UnqualifiedReductionId; + bool InvalidReductionId = false; + bool MapTypeModifierSpecified = false; + + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return true; + + bool NeedRParenForLinear = false; + BalancedDelimiterTracker LinearT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + // Handle reduction-identifier for reduction clause. + if (Kind == OMPC_reduction) { + ColonProtectionRAIIObject ColonRAII(*this); + if (getLangOpts().CPlusPlus) + ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false); + 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)) + 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); + Data.DepKind = + static_cast(getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); + Data.DepLinMapLoc = Tok.getLocation(); + + 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 && Data.DepKind == OMPC_DEPEND_source) { + // Parse ')'. + T.consumeClose(); + return false; + } + } + 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"; + } + } else if (Kind == OMPC_linear) { + // Try to parse modifier if any. + if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { + Data.LinKind = static_cast( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); + Data.DepLinMapLoc = ConsumeToken(); + LinearT.consumeOpen(); + NeedRParenForLinear = true; + } + } else if (Kind == OMPC_map) { + // Handle map type for map clause. + ColonProtectionRAIIObject ColonRAII(*this); + + /// The map clause modifier token can be either a identifier or the C++ + /// delete keyword. + 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. + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast( + 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)) { + if (Data.MapType == OMPC_MAP_unknown) + Diag(Tok, diag::err_omp_unknown_map_type); + 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)) { + Data.MapTypeModifier = Data.MapType; + if (Data.MapTypeModifier != OMPC_MAP_always) { + Diag(Tok, diag::err_omp_unknown_map_type_modifier); + Data.MapTypeModifier = OMPC_MAP_unknown; + } else + MapTypeModifierSpecified = true; + + ConsumeToken(); + ConsumeToken(); + + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast( + 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 { + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; + } + } else { + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; + } + } else { + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; + } + + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else if (ColonExpected) + Diag(Tok, diag::warn_pragma_expected_colon) << "map type"; + } + + bool IsComma = + (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))) { + ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); + // Parse variable + ExprResult VarExpr = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (VarExpr.isUsable()) + Vars.push_back(VarExpr.get()); + else { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + // Skip ',' if any + IsComma = Tok.is(tok::comma); + if (IsComma) + ConsumeToken(); + else if (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end) && + (!MayHaveTail || Tok.isNot(tok::colon))) + Diag(Tok, diag::err_omp_expected_punc) + << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush) + : getOpenMPClauseName(Kind)) + << (Kind == OMPC_flush); + } + + // Parse ')' for linear clause with modifier. + if (NeedRParenForLinear) + LinearT.consumeClose(); + + // Parse ':' linear-step (or ':' alignment). + const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); + if (MustHaveTail) { + Data.ColonLoc = Tok.getLocation(); + SourceLocation ELoc = ConsumeToken(); + ExprResult Tail = ParseAssignmentExpression(); + Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc); + if (Tail.isUsable()) + Data.TailExpr = Tail.get(); + else + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + + // Parse ')'. + T.consumeClose(); + if ((Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && + Vars.empty()) || + (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || + (MustHaveTail && !Data.TailExpr) || InvalidReductionId) + return true; + return false; +} + /// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'. /// @@ -1437,226 +1656,16 @@ 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; - 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; + SmallVector Vars; + OpenMPVarListDataTy Data; - // Parse '('. - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) + if (ParseOpenMPVarList(DKind, Kind, Vars, Data)) return nullptr; - bool NeedRParenForLinear = false; - BalancedDelimiterTracker LinearT(*this, tok::l_paren, - tok::annot_pragma_openmp_end); - // Handle reduction-identifier for reduction clause. - if (Kind == OMPC_reduction) { - ColonProtectionRAIIObject ColonRAII(*this); - if (getLangOpts().CPlusPlus) - ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, - /*ObjectType=*/nullptr, - /*EnteringContext=*/false); - InvalidReductionId = - ParseReductionId(*this, ReductionIdScopeSpec, ReductionId); - if (InvalidReductionId) { - SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); - } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { - Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; - } - } else if (Kind == OMPC_depend) { - // Handle dependency type for depend clause. - ColonProtectionRAIIObject ColonRAII(*this); - DepKind = static_cast(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); - - if (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) { - // 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); - } - } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { - Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren - : diag::warn_pragma_expected_colon) - << "dependency type"; - } - } 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( - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); - DepLinMapLoc = ConsumeToken(); - LinearT.consumeOpen(); - NeedRParenForLinear = true; - } - } else if (Kind == OMPC_map) { - // Handle map type for map clause. - ColonProtectionRAIIObject ColonRAII(*this); - - /// The map clause modifier token can be either a identifier or the C++ - /// delete keyword. - auto IsMapClauseModifierToken = [](const Token &Tok) { - 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(getOpenMPSimpleClauseType( - Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); - bool ColonExpected = false; - - if (IsMapClauseModifierToken(Tok)) { - if (PP.LookAhead(0).is(tok::colon)) { - MapType = static_cast(getOpenMPSimpleClauseType( - Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown) { - Diag(Tok, diag::err_omp_unknown_map_type); - } else if (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(getOpenMPSimpleClauseType( - Kind, - IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : "")); - if (MapTypeModifier != OMPC_MAP_always) { - Diag(Tok, diag::err_omp_unknown_map_type_modifier); - MapTypeModifier = OMPC_MAP_unknown; - } else { - MapTypeModifierSpecified = true; - } - - ConsumeToken(); - ConsumeToken(); - - MapType = static_cast(getOpenMPSimpleClauseType( - Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) { - Diag(Tok, diag::err_omp_unknown_map_type); - } - ConsumeToken(); - } else { - MapType = OMPC_MAP_tofrom; - MapTypeIsImplicit = true; - } - } else { - MapType = OMPC_MAP_tofrom; - MapTypeIsImplicit = true; - } - } else { - MapType = OMPC_MAP_tofrom; - MapTypeIsImplicit = true; - } - - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else if (ColonExpected) { - Diag(Tok, diag::warn_pragma_expected_colon) << "map type"; - } - } - - SmallVector 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); - 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))) { - ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); - // Parse variable - ExprResult VarExpr = - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (VarExpr.isUsable()) { - Vars.push_back(VarExpr.get()); - } else { - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); - } - // Skip ',' if any - IsComma = Tok.is(tok::comma); - if (IsComma) - ConsumeToken(); - else if (Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end) && - (!MayHaveTail || Tok.isNot(tok::colon))) - Diag(Tok, diag::err_omp_expected_punc) - << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush) - : getOpenMPClauseName(Kind)) - << (Kind == OMPC_flush); - } - - // Parse ')' for linear clause with modifier. - if (NeedRParenForLinear) - LinearT.consumeClose(); - - // Parse ':' linear-step (or ':' alignment). - Expr *TailExpr = nullptr; - const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); - if (MustHaveTail) { - ColonLoc = Tok.getLocation(); - SourceLocation ELoc = ConsumeToken(); - ExprResult Tail = ParseAssignmentExpression(); - Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc); - if (Tail.isUsable()) - TailExpr = Tail.get(); - else - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); - } - - // Parse ')'. - T.consumeClose(); - if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) || - (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || - (MustHaveTail && !TailExpr) || InvalidReductionId) { - 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); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 3705cf211ea7..43a774eec665 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -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 Uniforms, SourceRange SR) { if (!DG || DG.get().isNull()) return DeclGroupPtrTy(); @@ -3205,9 +3204,9 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG, if (auto *FTD = dyn_cast(ADecl)) ADecl = FTD->getTemplatedDecl(); - if (!isa(ADecl)) { - Diag(ADecl->getLocation(), diag::err_omp_function_expected) - << ADecl->getDeclContext()->isFileContext(); + auto *FD = dyn_cast(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(E)) + if (auto *PVD = dyn_cast(DRE->getDecl())) + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == PVD->getCanonicalDecl()) + continue; + if (isa(E)) + continue; + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa(ADecl) ? 1 : 0); } - auto *NewAttr = - OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SL.get(), SR); + auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit( + Context, BS, SL.get(), const_cast(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; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c60a17abc6f6..168bf6f451d8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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(New)) + New = FTD->getTemplatedDecl(); + auto *FD = cast(New); + auto *ThisContext = dyn_cast_or_null(FD->getDeclContext()); + SmallVector Uniforms; + + auto &&Subst = [&](Expr *E) -> ExprResult { + if (auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) + if (auto *PVD = dyn_cast(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, diff --git a/clang/test/OpenMP/declare_simd_ast_print.c b/clang/test/OpenMP/declare_simd_ast_print.c index 49dd1022ed0f..fe6bffcf89ad 100644 --- a/clang/test/OpenMP/declare_simd_ast_print.c +++ b/clang/test/OpenMP/declare_simd_ast_print.c @@ -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)) diff --git a/clang/test/OpenMP/declare_simd_ast_print.cpp b/clang/test/OpenMP/declare_simd_ast_print.cpp index 5adbb95e982f..e38ebe9613ce 100644 --- a/clang/test/OpenMP/declare_simd_ast_print.cpp +++ b/clang/test/OpenMP/declare_simd_ast_print.cpp @@ -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; diff --git a/clang/test/OpenMP/declare_simd_messages.cpp b/clang/test/OpenMP/declare_simd_messages.cpp index b222388a7a31..70737ad2685a 100644 --- a/clang/test/OpenMP/declare_simd_messages.cpp +++ b/clang/test/OpenMP/declare_simd_messages.cpp @@ -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 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 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