diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3305,24 +3305,14 @@ let Documentation = [OMPDeclareVariantDocs]; let Args = [ ExprArgument<"VariantFuncRef">, - ExprArgument<"Score">, - EnumArgument<"CtxSelectorSet", "CtxSelectorSetType", - [ "", "implementation" - ], - [ - "CtxSetUnknown", "CtxSetImplementation" - ]>, - EnumArgument<"CtxSelector", "CtxSelectorType", - [ "", "vendor" - ], - [ - "CtxUnknown", "CtxVendor" - ]>, + VariadicExprArgument<"Scores">, + VariadicUnsignedArgument<"CtxSelectorSets">, + VariadicUnsignedArgument<"CtxSelectors">, VariadicStringArgument<"ImplVendors"> ]; let AdditionalMembers = [{ - void printScore(raw_ostream & OS, const PrintingPolicy &Policy) const { - if (const Expr *E = getScore()) { + void printScore(raw_ostream & OS, const PrintingPolicy &Policy, unsigned I) const { + if (const Expr *E = *std::next(scores_begin(), I)) { OS << "score("; E->printPretty(OS, nullptr, Policy); OS << "):"; @@ -3330,8 +3320,6 @@ } void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy) const { - assert(getCtxSelectorSet() != CtxSetUnknown && - getCtxSelector() != CtxUnknown && "Unknown context selector."); if (const Expr *E = getVariantFuncRef()) { OS << "("; E->printPretty(OS, nullptr, Policy); @@ -3339,27 +3327,35 @@ } // TODO: add printing of real context selectors. OS << " match("; - switch (getCtxSelectorSet()) { - case CtxSetImplementation: - OS << "implementation={"; - switch (getCtxSelector()) { - case CtxVendor: - OS << "vendor("; - printScore(OS, Policy); - if (implVendors_size() > 0) { - OS << *implVendors(). begin(); - for (StringRef VendorName : llvm::drop_begin(implVendors(), 1)) - OS << ", " << VendorName; + for (unsigned I = 0, E = ctxSelectorSets_size(); I < E; ++I) { + auto CtxSet = static_cast( + *std::next(ctxSelectorSets_begin(), I)); + auto Ctx = static_cast( + *std::next(ctxSelectors_begin(), I)); + assert(CtxSet != OMPCtxSetUnknown && Ctx != OMPCtxUnknown && + "Unknown context selector."); + switch (CtxSet) { + case OMPCtxSet_implementation: + OS << "implementation={"; + switch (Ctx) { + case OMPCtx_vendor: + OS << "vendor("; + printScore(OS, Policy, I); + if (implVendors_size() > 0) { + OS << *implVendors(). begin(); + for (StringRef VendorName : llvm::drop_begin(implVendors(), 1)) + OS << ", " << VendorName; + } + OS << ")"; + break; + case OMPCtxUnknown: + llvm_unreachable("Unknown context selector."); } - OS << ")"; + OS << "}"; break; - case CtxUnknown: - llvm_unreachable("Unknown context selector."); + case OMPCtxSetUnknown: + llvm_unreachable("Unknown context selector set."); } - OS << "}"; - break; - case CtxSetUnknown: - llvm_unreachable("Unknown context selector set."); } OS << ")"; } diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -14,10 +14,48 @@ #ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H #define LLVM_CLANG_BASIC_OPENMPKINDS_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" namespace clang { +/// OpenMP context selector sets. +enum OpenMPContextSelectorSetKind { +#define OPENMP_CONTEXT_SELECTOR_SET(Name) OMPCtxSet_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPCtxSetUnknown, +}; + +/// OpenMP context selectors. +enum OpenMPContextSelectorKind { +#define OPENMP_CONTEXT_SELECTOR(Name) OMPCtx_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPCtxUnknown, +}; + +OpenMPContextSelectorSetKind getOpenMPContextSelectorSet(llvm::StringRef Str); +llvm::StringRef +getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind); +OpenMPContextSelectorKind getOpenMPContextSelector(llvm::StringRef Str); +llvm::StringRef getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind); + +/// Struct to store the context selectors info. +template > +struct OpenMPCtxSelectorData { + OpenMPContextSelectorSetKind CtxSet = OMPCtxSetUnknown; + OpenMPContextSelectorKind Ctx = OMPCtxUnknown; + VectorType Names; + explicit OpenMPCtxSelectorData() = default; + explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet, + OpenMPContextSelectorKind Ctx, + VectorType &&Names) + : CtxSet(CtxSet), Ctx(Ctx), Names(Names) {} + template + explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet, + OpenMPContextSelectorKind Ctx, const U &Names) + : CtxSet(CtxSet), Ctx(Ctx), Names(Names.begin(), Names.end()) {} +}; + /// OpenMP directives. enum OpenMPDirectiveKind { #define OPENMP_DIRECTIVE(Name) \ diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -212,6 +212,18 @@ #ifndef OPENMP_MATCH_KIND #define OPENMP_MATCH_KIND(Name) #endif +#ifndef OPENMP_CONTEXT_SELECTOR_SET +#define OPENMP_CONTEXT_SELECTOR_SET(Name) +#endif +#ifndef OPENMP_CONTEXT_SELECTOR +#define OPENMP_CONTEXT_SELECTOR(Name) +#endif + +// OpenMP context selector sets. +OPENMP_CONTEXT_SELECTOR_SET(implementation) + +// OpenMP context selectors. +OPENMP_CONTEXT_SELECTOR(vendor) // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) @@ -1076,6 +1088,8 @@ // TODO: add other context selectors. OPENMP_MATCH_KIND(implementation) +#undef OPENMP_CONTEXT_SELECTOR +#undef OPENMP_CONTEXT_SELECTOR_SET #undef OPENMP_MATCH_KIND #undef OPENMP_DECLARE_VARIANT_CLAUSE #undef OPENMP_DEVICE_TYPE_KIND diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2851,11 +2851,10 @@ SourceLocation Loc); /// Parses OpenMP context selectors and calls \p Callback for each /// successfully parsed context selector. - bool parseOpenMPContextSelectors( - SourceLocation Loc, - llvm::function_ref< - void(SourceRange, const Sema::OpenMPDeclareVariantCtsSelectorData &)> - Callback); + bool + parseOpenMPContextSelectors(SourceLocation Loc, + SmallVectorImpl &Data, + SmallVectorImpl &Scores); /// Parse clauses for '#pragma omp declare variant'. void ParseOMPDeclareVariantClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9307,21 +9307,9 @@ public: /// Struct to store the context selectors info for declare variant directive. - struct OpenMPDeclareVariantCtsSelectorData { - OMPDeclareVariantAttr::CtxSelectorSetType CtxSet = - OMPDeclareVariantAttr::CtxSetUnknown; - OMPDeclareVariantAttr::CtxSelectorType Ctx = - OMPDeclareVariantAttr::CtxUnknown; - MutableArrayRef ImplVendors; - ExprResult CtxScore; - explicit OpenMPDeclareVariantCtsSelectorData() = default; - explicit OpenMPDeclareVariantCtsSelectorData( - OMPDeclareVariantAttr::CtxSelectorSetType CtxSet, - OMPDeclareVariantAttr::CtxSelectorType Ctx, - MutableArrayRef ImplVendors, ExprResult CtxScore) - : CtxSet(CtxSet), Ctx(Ctx), ImplVendors(ImplVendors), - CtxScore(CtxScore) {} - }; + using OMPCtxStringType = SmallString<8>; + using OMPCtxSelectorData = + OpenMPCtxSelectorData>; /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( @@ -9799,9 +9787,10 @@ /// must be used instead of the original one, specified in \p DG. /// \param Data Set of context-specific data for the specified context /// selector. - void ActOnOpenMPDeclareVariantDirective( - FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data); + void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, + SourceRange SR, + ArrayRef Data, + ArrayRef Scores); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -19,6 +19,51 @@ using namespace clang; +OpenMPContextSelectorSetKind +clang::getOpenMPContextSelectorSet(llvm::StringRef Str) { + return llvm::StringSwitch(Str) +#define OPENMP_CONTEXT_SELECTOR_SET(Name) .Case(#Name, OMPCtxSet_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPCtxSetUnknown); +} + +llvm::StringRef +clang::getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind) { + assert(Kind <= OMPCtxSetUnknown); + switch (Kind) { + case OMPCtxSetUnknown: + return "unknown"; +#define OPENMP_CONTEXT_SELECTOR_SET(Name) \ + case OMPCtxSet_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + break; + } + llvm_unreachable("Invalid OpenMP context selector set kind"); +} + +OpenMPContextSelectorKind clang::getOpenMPContextSelector(llvm::StringRef Str) { + return llvm::StringSwitch(Str) +#define OPENMP_CONTEXT_SELECTOR(Name) .Case(#Name, OMPCtx_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPCtxUnknown); +} + +llvm::StringRef +clang::getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind) { + assert(Kind <= OMPCtxUnknown); + switch (Kind) { + case OMPCtxUnknown: + return "unknown"; +#define OPENMP_CONTEXT_SELECTOR(Name) \ + case OMPCtx_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + break; + } + llvm_unreachable("Invalid OpenMP context selector kind"); +} + OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) { return llvm::StringSwitch(Str) #define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11023,12 +11023,21 @@ return Address(Addr, Align); } +namespace { + using OMPContextSelectorData = OpenMPCtxSelectorData; + struct OMPContextSelectorDataAndScore { + OMPContextSelectorData Data; + llvm::APSInt Score; + }; + using CompleteOMPContextSelectorDataAndScore = + SmallVector; +} // anonymous namespace + /// Checks current context and returns true if it matches the context selector. -template -static bool checkContext(const OMPDeclareVariantAttr *A) { - assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown && - Ctx != OMPDeclareVariantAttr::CtxUnknown && +template +static bool checkContext(const OMPContextSelectorDataAndScore &Data) { + assert(Data.Data.CtxSet != OMPCtxSetUnknown && + Data.Data.Ctx != OMPCtxUnknown && "Unknown context selector or context selector set."); return false; } @@ -11036,17 +11045,91 @@ /// Checks for implementation={vendor()} context selector. /// \returns true iff ="llvm", false otherwise. template <> -bool checkContext( - const OMPDeclareVariantAttr *A) { - return llvm::all_of(A->implVendors(), +bool checkContext( + const OMPContextSelectorDataAndScore &Data) { + return Data.Data.Names.empty() || + llvm::all_of(Data.Data.Names, [](StringRef S) { return !S.compare_lower("llvm"); }); } -static bool greaterCtxScore(ASTContext &Ctx, const Expr *LHS, const Expr *RHS) { - llvm::APSInt LHSVal = LHS->EvaluateKnownConstInt(Ctx); - llvm::APSInt RHSVal = RHS->EvaluateKnownConstInt(Ctx); - return llvm::APSInt::compareValues(LHSVal, RHSVal) >= 0; +bool matchesContext(const CompleteOMPContextSelectorDataAndScore &ContextData) { + for (const OMPContextSelectorDataAndScore &DataScore : ContextData) { + switch (DataScore.Data.CtxSet) { + case OMPCtxSet_implementation: + switch (DataScore.Data.Ctx) { + case OMPCtx_vendor: + if (!checkContext(DataScore)) + return false; + break; + case OMPCtxUnknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMPCtxSetUnknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } + return true; +} + +static CompleteOMPContextSelectorDataAndScore +translateAttrToContextSelectorData(ASTContext &C, + const OMPDeclareVariantAttr *A) { + CompleteOMPContextSelectorDataAndScore Data; + for (unsigned I = 0, E = A->scores_size(); I < E; ++I) { + Data.emplace_back(); + auto CtxSet = static_cast( + *std::next(A->ctxSelectorSets_begin(), I)); + auto Ctx = static_cast( + *std::next(A->ctxSelectors_begin(), I)); + Data.back().Data.CtxSet = CtxSet; + Data.back().Data.Ctx = Ctx; + const Expr *Score = *std::next(A->scores_begin(), I); + Data.back().Score = Score->EvaluateKnownConstInt(C); + switch (CtxSet) { + case OMPCtxSet_implementation: + switch (Ctx) { + case OMPCtx_vendor: + Data.back().Data.Names = + llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); + break; + case OMPCtxUnknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMPCtxSetUnknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } + return Data; +} + +static bool greaterCtxScore(const CompleteOMPContextSelectorDataAndScore &LHS, + const CompleteOMPContextSelectorDataAndScore &RHS) { + // Score is calculated as sum of all scores + 1. + llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + for (const OMPContextSelectorDataAndScore &DataScore : LHS) { + if (DataScore.Score.getBitWidth() > LHSScore.getBitWidth()) { + LHSScore = + LHSScore.extend(DataScore.Score.getBitWidth()) + DataScore.Score; + } else if (DataScore.Score.getBitWidth() < LHSScore.getBitWidth()) { + LHSScore += DataScore.Score.extend(LHSScore.getBitWidth()); + } else { + LHSScore += DataScore.Score; + } + } + llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + for (const OMPContextSelectorDataAndScore &DataScore : RHS) { + if (DataScore.Score.getBitWidth() > RHSScore.getBitWidth()) { + RHSScore = + RHSScore.extend(DataScore.Score.getBitWidth()) + DataScore.Score; + } else if (DataScore.Score.getBitWidth() < RHSScore.getBitWidth()) { + RHSScore += DataScore.Score.extend(RHSScore.getBitWidth()); + } else { + RHSScore += DataScore.Score; + } + } + return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0; } /// Finds the variant function that matches current context with its context @@ -11056,33 +11139,19 @@ if (!FD->hasAttrs() || !FD->hasAttr()) return FD; // Iterate through all DeclareVariant attributes and check context selectors. - auto &&Comparer = [&Ctx](const OMPDeclareVariantAttr *LHS, - const OMPDeclareVariantAttr *RHS) { - return greaterCtxScore(Ctx, LHS->getScore(), RHS->getScore()); - }; const OMPDeclareVariantAttr *TopMostAttr = nullptr; + CompleteOMPContextSelectorDataAndScore TopMostData; for (const auto *A : FD->specific_attrs()) { - const OMPDeclareVariantAttr *SelectedAttr = nullptr; - switch (A->getCtxSelectorSet()) { - case OMPDeclareVariantAttr::CtxSetImplementation: - switch (A->getCtxSelector()) { - case OMPDeclareVariantAttr::CtxVendor: - if (checkContext(A)) - SelectedAttr = A; - break; - case OMPDeclareVariantAttr::CtxUnknown: - llvm_unreachable( - "Unknown context selector in implementation selector set."); - } - break; - case OMPDeclareVariantAttr::CtxSetUnknown: - llvm_unreachable("Unknown context selector set."); - } + CompleteOMPContextSelectorDataAndScore Data = + translateAttrToContextSelectorData(Ctx, A); + if (!matchesContext(Data)) + continue; // If the attribute matches the context, find the attribute with the highest // score. - if (SelectedAttr && (!TopMostAttr || !Comparer(TopMostAttr, SelectedAttr))) - TopMostAttr = SelectedAttr; + if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) { + TopMostAttr = A; + TopMostData.swap(Data); + } } if (!TopMostAttr) return FD; diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -797,7 +797,7 @@ /// Parse optional 'score' '(' ')' ':'. static ExprResult parseContextScore(Parser &P) { ExprResult ScoreExpr; - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef SelectorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); if (!SelectorName.equals("score")) @@ -817,11 +817,11 @@ /// Parse context selector for 'implementation' selector set: /// 'vendor' '(' [ 'score' '(' ')' ':' ] { ',' } /// ')' -static void parseImplementationSelector( - Parser &P, SourceLocation Loc, llvm::StringMap &UsedCtx, - llvm::function_ref - Callback) { +static void +parseImplementationSelector(Parser &P, SourceLocation Loc, + llvm::StringMap &UsedCtx, + SmallVectorImpl &Data, + SmallVectorImpl &Scores) { const Token &Tok = P.getCurToken(); // Parse inner context selector set name, if any. if (!Tok.is(tok::identifier)) { @@ -833,7 +833,7 @@ ; return; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); if (!Res.second) { @@ -844,19 +844,16 @@ P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) << CtxSelectorName; } - OMPDeclareVariantAttr::CtxSelectorType CSKind = - OMPDeclareVariantAttr::CtxUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName, - CSKind); + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); (void)P.ConsumeToken(); switch (CSKind) { - case OMPDeclareVariantAttr::CtxVendor: { + case OMPCtx_vendor: { // Parse '('. BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); (void)T.expectAndConsume(diag::err_expected_lparen_after, CtxSelectorName.data()); - const ExprResult Score = parseContextScore(P); - llvm::UniqueVector> Vendors; + ExprResult Score = parseContextScore(P); + llvm::UniqueVector Vendors; do { // Parse . StringRef VendorName; @@ -880,17 +877,12 @@ // Parse ')'. (void)T.consumeClose(); if (!Vendors.empty()) { - SmallVector ImplVendors(Vendors.size()); - llvm::copy(Vendors, ImplVendors.begin()); - Sema::OpenMPDeclareVariantCtsSelectorData Data( - OMPDeclareVariantAttr::CtxSetImplementation, CSKind, - llvm::makeMutableArrayRef(ImplVendors.begin(), ImplVendors.size()), - Score); - Callback(SourceRange(Loc, Tok.getLocation()), Data); + Data.emplace_back(OMPCtxSet_implementation, CSKind, Vendors); + Scores.push_back(Score); } break; } - case OMPDeclareVariantAttr::CtxUnknown: + case OMPCtxUnknown: P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) << "implementation"; // Skip until either '}', ')', or end of directive. @@ -906,10 +898,8 @@ /// '=' '{' '}' /// [ ',' '=' '{' '}' ] bool Parser::parseOpenMPContextSelectors( - SourceLocation Loc, - llvm::function_ref - Callback) { + SourceLocation Loc, SmallVectorImpl &Data, + SmallVectorImpl &Scores) { llvm::StringMap UsedCtxSets; do { // Parse inner context selector set name. @@ -918,7 +908,7 @@ << getOpenMPClauseName(OMPC_match); return true; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer); auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation()); if (!Res.second) { @@ -946,17 +936,15 @@ tok::annot_pragma_openmp_end); if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "=")) return true; - OMPDeclareVariantAttr::CtxSelectorSetType CSSKind = - OMPDeclareVariantAttr::CtxSetUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType( - CtxSelectorSetName, CSSKind); + OpenMPContextSelectorSetKind CSSKind = + getOpenMPContextSelectorSet(CtxSelectorSetName); llvm::StringMap UsedCtx; do { switch (CSSKind) { - case OMPDeclareVariantAttr::CtxSetImplementation: - parseImplementationSelector(*this, Loc, UsedCtx, Callback); + case OMPCtxSet_implementation: + parseImplementationSelector(*this, Loc, UsedCtx, Data, Scores); break; - case OMPDeclareVariantAttr::CtxSetUnknown: + case OMPCtxSetUnknown: // Skip until either '}', ')', or end of directive. while (!SkipUntil(tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -1036,15 +1024,9 @@ } // Parse inner context selectors. - if (!parseOpenMPContextSelectors( - Loc, [this, &DeclVarData]( - SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (DeclVarData.hasValue()) - Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData.getValue().first, DeclVarData.getValue().second, - SR, Data); - })) { + SmallVector Data; + SmallVector Scores; + if (!parseOpenMPContextSelectors(Loc, Data, Scores)) { // Parse ')'. (void)T.consumeClose(); // Need to check for extra tokens. @@ -1057,6 +1039,10 @@ // Skip last tokens. while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); + if (DeclVarData.hasValue()) + Actions.ActOnOpenMPDeclareVariantDirective( + DeclVarData.getValue().first, DeclVarData.getValue().second, + SourceRange(Loc, Tok.getLocation()), Data, Scores); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5190,30 +5190,62 @@ return std::make_pair(FD, cast(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective( - FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || - Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) +void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, + Expr *VariantRef, SourceRange SR, + ArrayRef Data, + ArrayRef Scores) { + if (Scores.empty()) return; - Expr *Score = nullptr; - if (Data.CtxScore.isUsable()) { - Score = Data.CtxScore.get(); - if (!Score->isTypeDependent() && !Score->isValueDependent() && - !Score->isInstantiationDependent() && - !Score->containsUnexpandedParameterPack()) { - llvm::APSInt Result; - ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result); - if (ICE.isInvalid()) - return; + SmallVector CtxScores; + SmallVector CtxSets; + SmallVector Ctxs; + SmallVector ImplVendors; + bool IsError = false; + for (unsigned I = 0, E = Scores.size(); I < E; ++I) { + OpenMPContextSelectorSetKind CtxSet = Data[I].CtxSet; + OpenMPContextSelectorKind Ctx = Data[I].Ctx; + if (CtxSet == OMPCtxSetUnknown || Ctx == OMPCtxUnknown) + return; + Expr *Score = nullptr; + if (Scores[I].isUsable()) { + Score = Scores[I].get(); + if (!Score->isTypeDependent() && !Score->isValueDependent() && + !Score->isInstantiationDependent() && + !Score->containsUnexpandedParameterPack()) { + Score = + PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score) + .get(); + if (Score) + Score = VerifyIntegerConstantExpression(Score).get(); + } + } else { + Score = ActOnIntegerConstant(SourceLocation(), 0).get(); } - } else { - Score = ActOnIntegerConstant(SourceLocation(), 0).get(); + switch (CtxSet) { + case OMPCtxSet_implementation: + switch (Ctx) { + case OMPCtx_vendor: + ImplVendors.append(Data[I].Names.begin(), Data[I].Names.end()); + break; + case OMPCtxUnknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMPCtxSetUnknown: + llvm_unreachable("Unexpected context selector set kind."); + } + IsError = IsError || !Score; + CtxSets.push_back(CtxSet); + Ctxs.push_back(Ctx); + CtxScores.push_back(Score); + } + if (!IsError) { + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, CtxScores.begin(), CtxScores.size(), + CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(), + ImplVendors.begin(), ImplVendors.size(), SR); + FD->addAttr(NewAttr); } - auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantRef, Score, Data.CtxSet, Data.Ctx, - Data.ImplVendors.begin(), Data.ImplVendors.size(), SR); - FD->addAttr(NewAttr); } void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -388,25 +388,41 @@ if (Expr *E = Attr.getVariantFuncRef()) VariantFuncRef = Subst(E); - ExprResult Score; - if (Expr *E = Attr.getScore()) - Score = Subst(E); - // Check function/variant ref. Optional> DeclVarData = S.checkOpenMPDeclareVariantFunction( S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange()); if (!DeclVarData) return; - // Instantiate the attribute. - Sema::OpenMPDeclareVariantCtsSelectorData Data( - Attr.getCtxSelectorSet(), Attr.getCtxSelector(), - llvm::makeMutableArrayRef(Attr.implVendors_begin(), - Attr.implVendors_size()), - Score); + SmallVector Scores; + SmallVector Data; + for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) { + ExprResult Score; + if (Expr *E = *std::next(Attr.scores_begin(), I)) + Score = Subst(E); + Scores.push_back(Score); + // Instantiate the attribute. + auto CtxSet = static_cast( + *std::next(Attr.ctxSelectorSets_begin(), I)); + auto Ctx = static_cast( + *std::next(Attr.ctxSelectors_begin(), I)); + switch (CtxSet) { + case OMPCtxSet_implementation: + switch (Ctx) { + case OMPCtx_vendor: + Data.emplace_back(CtxSet, Ctx, Attr.implVendors()); + break; + case OMPCtxUnknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMPCtxSetUnknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, DeclVarData.getValue().second, - Attr.getRange(), Data); + Attr.getRange(), Data, Scores); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(