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 != OMP_CTX_SET_unknown && Ctx != OMP_CTX_unknown && + "Unknown context selector."); + switch (CtxSet) { + case OMP_CTX_SET_implementation: + OS << "implementation={"; + switch (Ctx) { + case OMP_CTX_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 OMP_CTX_unknown: + llvm_unreachable("Unknown context selector."); } - OS << ")"; + OS << "}"; break; - case CtxUnknown: - llvm_unreachable("Unknown context selector."); + case OMP_CTX_SET_unknown: + 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 @@ -18,6 +18,46 @@ namespace clang { +/// OpenMP context selector sets. +enum OpenMPContextSelectorSetKind { +#define OPENMP_CONTEXT_SELECTOR_SET(Name) OMP_CTX_SET_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMP_CTX_SET_unknown, +}; + +/// OpenMP context selectors. +enum OpenMPContextSelectorKind { +#define OPENMP_CONTEXT_SELECTOR(Name) OMP_CTX_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMP_CTX_unknown, +}; + +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 = OMP_CTX_SET_unknown; + OpenMPContextSelectorKind Ctx = OMP_CTX_unknown; + ScoreT Score; + VectorType Names; + explicit OpenMPCtxSelectorData() = default; + explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet, + OpenMPContextSelectorKind Ctx, + const ScoreT &Score, VectorType &&Names) + : CtxSet(CtxSet), Ctx(Ctx), Score(Score), Names(Names) {} + template + explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet, + OpenMPContextSelectorKind Ctx, + const ScoreT &Score, const U &Names) + : CtxSet(CtxSet), Ctx(Ctx), Score(Score), + 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,9 @@ 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); /// 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,10 @@ 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, + ExprResult>; /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( @@ -9799,9 +9788,9 @@ /// 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); 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,49 @@ using namespace clang; +OpenMPContextSelectorSetKind +clang::getOpenMPContextSelectorSet(llvm::StringRef Str) { + return llvm::StringSwitch(Str) +#define OPENMP_CONTEXT_SELECTOR_SET(Name) .Case(#Name, OMP_CTX_SET_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMP_CTX_SET_unknown); +} + +llvm::StringRef +clang::getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind) { + switch (Kind) { + case OMP_CTX_SET_unknown: + return "unknown"; +#define OPENMP_CONTEXT_SELECTOR_SET(Name) \ + case OMP_CTX_SET_##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, OMP_CTX_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMP_CTX_unknown); +} + +llvm::StringRef +clang::getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind) { + switch (Kind) { + case OMP_CTX_unknown: + return "unknown"; +#define OPENMP_CONTEXT_SELECTOR(Name) \ + case OMP_CTX_##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,16 @@ return Address(Addr, Align); } +namespace { +using OMPContextSelectorData = + OpenMPCtxSelectorData, llvm::APSInt>; +using CompleteOMPContextSelectorData = 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 OMPContextSelectorData &Data) { + assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown && "Unknown context selector or context selector set."); return false; } @@ -11036,17 +11040,88 @@ /// 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 OMPContextSelectorData &Data) { + return llvm::all_of(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 CompleteOMPContextSelectorData &ContextData) { + for (const OMPContextSelectorData &Data : ContextData) { + switch (Data.CtxSet) { + case OMP_CTX_SET_implementation: + switch (Data.Ctx) { + case OMP_CTX_vendor: + if (!checkContext(Data)) + return false; + break; + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_unknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } + return true; +} + +static CompleteOMPContextSelectorData +translateAttrToContextSelectorData(ASTContext &C, + const OMPDeclareVariantAttr *A) { + CompleteOMPContextSelectorData 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().CtxSet = CtxSet; + Data.back().Ctx = Ctx; + const Expr *Score = *std::next(A->scores_begin(), I); + Data.back().Score = Score->EvaluateKnownConstInt(C); + switch (CtxSet) { + case OMP_CTX_SET_implementation: + switch (Ctx) { + case OMP_CTX_vendor: + Data.back().Names = + llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_unknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } + return Data; +} + +static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS, + const CompleteOMPContextSelectorData &RHS) { + // Score is calculated as sum of all scores + 1. + llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + for (const OMPContextSelectorData &Data : LHS) { + if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) { + LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) { + LHSScore += Data.Score.extend(LHSScore.getBitWidth()); + } else { + LHSScore += Data.Score; + } + } + llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + for (const OMPContextSelectorData &Data : RHS) { + if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) { + RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) { + RHSScore += Data.Score.extend(RHSScore.getBitWidth()); + } else { + RHSScore += Data.Score; + } + } + return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0; } /// Finds the variant function that matches current context with its context @@ -11056,33 +11131,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; + CompleteOMPContextSelectorData 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."); - } + CompleteOMPContextSelectorData 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,10 @@ /// 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) { const Token &Tok = P.getCurToken(); // Parse inner context selector set name, if any. if (!Tok.is(tok::identifier)) { @@ -833,7 +832,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 +843,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 OMP_CTX_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; @@ -879,18 +875,11 @@ } while (Tok.is(tok::identifier)); // 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); - } + if (!Vendors.empty()) + Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors); break; } - case OMPDeclareVariantAttr::CtxUnknown: + case OMP_CTX_unknown: P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) << "implementation"; // Skip until either '}', ')', or end of directive. @@ -906,10 +895,7 @@ /// '=' '{' '}' /// [ ',' '=' '{' '}' ] bool Parser::parseOpenMPContextSelectors( - SourceLocation Loc, - llvm::function_ref - Callback) { + SourceLocation Loc, SmallVectorImpl &Data) { llvm::StringMap UsedCtxSets; do { // Parse inner context selector set name. @@ -918,7 +904,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 +932,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 OMP_CTX_SET_implementation: + parseImplementationSelector(*this, Loc, UsedCtx, Data); break; - case OMPDeclareVariantAttr::CtxSetUnknown: + case OMP_CTX_SET_unknown: // Skip until either '}', ')', or end of directive. while (!SkipUntil(tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -1036,15 +1020,8 @@ } // 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; + if (!parseOpenMPContextSelectors(Loc, Data)) { // Parse ')'. (void)T.consumeClose(); // Need to check for extra tokens. @@ -1057,6 +1034,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); // 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 @@ -5200,28 +5200,59 @@ void Sema::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || - Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) + ArrayRef Data) { + if (Data.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 (const OMPCtxSelectorData &D : Data) { + OpenMPContextSelectorSetKind CtxSet = D.CtxSet; + OpenMPContextSelectorKind Ctx = D.Ctx; + if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown) + return; + Expr *Score = nullptr; + if (D.Score.isUsable()) { + Score = D.Score.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 OMP_CTX_SET_implementation: + switch (Ctx) { + case OMP_CTX_vendor: + ImplVendors.append(D.Names.begin(), D.Names.end()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_unknown: + 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,22 +388,36 @@ 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 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); + // 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 OMP_CTX_SET_implementation: + switch (Ctx) { + case OMP_CTX_vendor: + Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_unknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, DeclVarData.getValue().second, Attr.getRange(), Data);