diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -17,6 +17,7 @@ #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/Type.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/AttributeCommonInfo.h" diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -31,6 +31,7 @@ #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/Frontend/OpenMP/OMPContext.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" @@ -6658,6 +6659,53 @@ #include "clang/Basic/OpenMPKinds.def" }; +/// Helper data structure representing the traits in a match clause of an +/// `declare variant` or `metadirective`. The outer level is an ordered +/// collection of selector sets, each with an associated kind and an ordered +/// collection of selectors. A selector has a kind, an optional score/condition, +/// and an ordered collection of properties. +struct OMPTraitInfo { + struct OMPTraitProperty { + llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid; + }; + struct OMPTraitSelector { + Expr *ScoreOrCondition = nullptr; + llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid; + llvm::SmallVector Properties; + }; + struct OMPTraitSet { + llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid; + llvm::SmallVector Selectors; + }; + + /// The outermost level of selector sets. + llvm::SmallVector Sets; + + bool anyScoreOrCondition( + llvm::function_ref Cond) { + return llvm::any_of(Sets, [Cond](OMPTraitInfo::OMPTraitSet &Set) { + return llvm::any_of( + Set.Selectors, [Cond](OMPTraitInfo::OMPTraitSelector &Selector) { + return Cond(Selector.ScoreOrCondition, + /* IsScore */ Selector.Kind != + llvm::omp::TraitSelector::user_condition); + }); + }); + } + + /// Create a variant match info object from this trait info object. While the + /// former is a flat representation the actual main difference is that the + /// latter uses clang::Expr to store the score/condition while the former is + /// independent of clang. Thus, expressions and conditions are evaluated in + /// this method. + void getAsVariantMatchInfo(ASTContext &ASTCtx, + llvm::omp::VariantMatchInfo &VMI) const; + + /// Print a human readable representation into \p OS. + void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; +}; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI); + } // namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H 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 @@ -180,6 +180,27 @@ class NamedArgument : Argument; + +// An argument of a OMPDeclareVariantAttribute that represents the `match` +// clause of the declare variant by keeping the information (incl. nesting) in +// an OMPTraitInfo object. +// +// With some exceptions, the `match()` clause looks roughly +// as follows: +// context-selector := list +// selector-set := ={list} +// selector := ([score():] list) +// trait := +// +// The structure of an OMPTraitInfo object is a tree as defined below: +// +// OMPTraitInfo := {list} +// OMPTraitSet := {Kind, list} +// OMPTraitSelector := {Kind, Expr, list} +// OMPTraitProperty := {Kind} +// +class OMPTraitInfoArgument : Argument; + class TypeArgument : Argument; class UnsignedArgument : Argument; class VariadicUnsignedArgument : Argument; @@ -3342,20 +3363,10 @@ let Documentation = [OMPDeclareVariantDocs]; let Args = [ ExprArgument<"VariantFuncRef">, - VariadicExprArgument<"Scores">, - VariadicUnsignedArgument<"CtxSelectorSets">, - VariadicUnsignedArgument<"CtxSelectors">, - VariadicStringArgument<"ImplVendors">, - VariadicStringArgument<"DeviceKinds"> + OMPTraitInfoArgument<"TraitInfos">, ]; let AdditionalMembers = [{ - 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 << "):"; - } - } + ~OMPDeclareVariantAttr() { delete traitInfos; } void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy) const { if (const Expr *E = getVariantFuncRef()) { @@ -3363,66 +3374,8 @@ E->printPretty(OS, nullptr, Policy); OS << ")"; } - // TODO: add printing of real context selectors. OS << " match("; - int Used[OMP_CTX_SET_unknown] = {0}; - for (unsigned I = 0, E = ctxSelectorSets_size(); I < E; ++I) { - auto CtxSet = static_cast( - *std::next(ctxSelectorSets_begin(), I)); - if (Used[CtxSet]) - continue; - if (I > 0) - OS << ","; - switch (CtxSet) { - case OMP_CTX_SET_implementation: - OS << "implementation={"; - break; - case OMP_CTX_SET_device: - OS << "device={"; - break; - case OMP_CTX_SET_unknown: - llvm_unreachable("Unknown context selector set."); - } - Used[CtxSet] = 1; - for (unsigned K = I, EK = ctxSelectors_size(); K < EK; ++K) { - auto CtxSetK = static_cast( - *std::next(ctxSelectorSets_begin(), K)); - if (CtxSet != CtxSetK) - continue; - if (K != I) - OS << ","; - auto Ctx = static_cast( - *std::next(ctxSelectors_begin(), K)); - switch (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - OS << "vendor("; - printScore(OS, Policy, K); - if (implVendors_size() > 0) { - OS << *implVendors(). begin(); - for (StringRef VendorName : llvm::drop_begin(implVendors(), 1)) - OS << ", " << VendorName; - } - OS << ")"; - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - OS << "kind("; - if (deviceKinds_size() > 0) { - OS << *deviceKinds().begin(); - for (StringRef KindName : llvm::drop_begin(deviceKinds(), 1)) - OS << ", " << KindName; - } - OS << ")"; - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector."); - } - } - OS << "}"; - } + traitInfos->print(OS, Policy); OS << ")"; } }]; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1258,30 +1258,68 @@ "expected declarator on 'omp declare mapper' directive">; def err_omp_declare_variant_wrong_clause : Error< "expected '%0' clause on 'omp declare variant' directive">; -def err_omp_declare_variant_no_ctx_selector : Error< - "expected context selector in '%0' clause on 'omp declare variant' directive">; -def err_omp_declare_variant_equal_expected : Error< - "expected '=' after '%0' context selector set name on 'omp declare variant' directive">; -def warn_omp_declare_variant_cs_name_expected : Warning< - "unknown context selector in '%0' context selector set of 'omp declare variant' directive, ignored">, - InGroup; -def err_omp_declare_variant_item_expected : Error< - "expected %0 in '%1' context selector of '%2' selector set of 'omp declare variant' directive">; -def err_omp_declare_variant_ctx_set_mutiple_use : Error< - "context selector set '%0' is used already in the same 'omp declare variant' directive">; -def note_omp_declare_variant_ctx_set_used_here : Note< - "previously context selector set '%0' used here">; -def err_omp_expected_comma_brace : Error<"expected '}' or ',' after '%0'">; -def err_omp_declare_variant_ctx_mutiple_use : Error< - "context trait selector '%0' is used already in the same '%1' context selector set of 'omp declare variant' directive">; -def note_omp_declare_variant_ctx_used_here : Note< - "previously context trait selector '%0' used here">; -def warn_omp_more_one_device_type_clause : Warning< - "more than one 'device_type' clause is specified">, - InGroup; -def err_omp_wrong_device_kind_trait : Error< - "unknown '%0' device kind trait in the 'device' context selector set, expected" - " one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'">; +def warn_omp_declare_variant_string_literal_or_identifier + : Warning<"expected identifier or string literal describing a context " + "%select{set|selector|property}0; " + "%select{set|selector|property}0 skipped">, + InGroup; +def note_omp_declare_variant_ctx_options + : Note<"context %select{set|selector|property}0 options are: %1">; +def warn_omp_declare_variant_expected + : Warning<"expected '%0' after the %1; '%0' assumed">, + InGroup; +def warn_omp_declare_variant_ctx_not_a_property + : Warning<"'%0' is not a valid context property for the context selector " + "'%1' and the context set '%2'; property ignored">, + InGroup; +def note_omp_declare_variant_ctx_is_a + : Note<"'%0' is a context %select{set|selector|property}1 not a context " + "%select{set|selector|property}2">; +def note_omp_declare_variant_ctx_try : Note<"try 'match(%0={%1%2})'">; +def warn_omp_declare_variant_ctx_not_a_selector + : Warning<"'%0' is not a valid context selector for the context set '%1'; " + "selector ignored">, + InGroup; +def warn_omp_declare_variant_ctx_not_a_set + : Warning<"'%0' is not a valid context set in a `declare variant`; set " + "ignored">, + InGroup; +def warn_omp_declare_variant_ctx_mutiple_use + : Warning<"the context %select{set|selector|property}0 '%1' was used " + "already in the same 'omp declare variant' directive; " + "%select{set|selector|property}0 ignored">, + InGroup; +def note_omp_declare_variant_ctx_used_here + : Note<"the previous context %select{set|selector|property}0 '%1' used " + "here">; +def note_omp_declare_variant_ctx_continue_here + : Note<"the ignored %select{set|selector|property}0 spans until here">; +def warn_omp_ctx_incompatible_selector_for_set + : Warning<"the context selector '%0' is not valid for the context set " + "'%1'; selector ignored">, + InGroup; +def note_omp_ctx_compatible_set_for_selector + : Note<"the context selector '%0' can be nested in the context set '%1'; " + "try 'match(%1={%0%select{|(property)}2})'">; +def warn_omp_ctx_selector_without_properties + : Warning<"the context selector '%0' in context set '%1' requires a " + "context property defined in parentheses; selector ignored">, + InGroup; +def warn_omp_ctx_incompatible_property_for_selector + : Warning<"the context property '%0' is not valid for the context selector " + "'%1' and the context set '%2'; property ignored">, + InGroup; +def note_omp_ctx_compatible_set_and_selector_for_property + : Note<"the context property '%0' can be nested in the context selector " + "'%1' which is nested in the context set '%2'; try " + "'match(%2={%1(%0)})'">; +def warn_omp_ctx_incompatible_score_for_property + : Warning<"the context selector '%0' in the context set '%1' cannot have a " + "score ('%2'); score ignored">, + InGroup; +def warn_omp_more_one_device_type_clause + : Warning<"more than one 'device_type' clause is specified">, + InGroup; // Pragma loop support. def err_pragma_loop_missing_argument : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9910,6 +9910,12 @@ InGroup; def err_omp_declare_variant_incompat_attributes : Error< "'#pragma omp declare variant' is not compatible with any target-specific attributes">; +def warn_omp_declare_variant_score_not_constant + : Warning<"score expressions in the OpenMP context selector need to be " + "constant; %0 is not and will be ignored">; +def err_omp_declare_variant_user_condition_not_constant + : Error<"the user condition in the OpenMP context selector needs to be " + "constant; %0 is not">; def warn_omp_declare_variant_after_used : Warning< "'#pragma omp declare variant' cannot be applied for function after first " "usage; the original function might be used">, InGroup; 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 @@ -19,45 +19,6 @@ 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. using OpenMPDirectiveKind = llvm::omp::Directive; 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 @@ -203,12 +203,6 @@ #ifndef OPENMP_DECLARE_VARIANT_CLAUSE #define OPENMP_DECLARE_VARIANT_CLAUSE(Name) #endif -#ifndef OPENMP_CONTEXT_SELECTOR_SET -#define OPENMP_CONTEXT_SELECTOR_SET(Name) -#endif -#ifndef OPENMP_CONTEXT_SELECTOR -#define OPENMP_CONTEXT_SELECTOR(Name) -#endif #ifndef OPENMP_LASTPRIVATE_KIND #define OPENMP_LASTPRIVATE_KIND(Name) #endif @@ -219,14 +213,6 @@ #define OPENMP_FLUSH_CLAUSE(Name) #endif -// OpenMP context selector sets. -OPENMP_CONTEXT_SELECTOR_SET(implementation) -OPENMP_CONTEXT_SELECTOR_SET(device) - -// OpenMP context selectors. -OPENMP_CONTEXT_SELECTOR(vendor) -OPENMP_CONTEXT_SELECTOR(kind) - // OpenMP clauses. OPENMP_CLAUSE(allocator, OMPAllocatorClause) OPENMP_CLAUSE(if, OMPIfClause) @@ -1102,8 +1088,6 @@ #undef OPENMP_FLUSH_CLAUSE #undef OPENMP_ORDER_KIND #undef OPENMP_LASTPRIVATE_KIND -#undef OPENMP_CONTEXT_SELECTOR -#undef OPENMP_CONTEXT_SELECTOR_SET #undef OPENMP_DECLARE_VARIANT_CLAUSE #undef OPENMP_DEVICE_TYPE_KIND #undef OPENMP_ALLOCATE_CLAUSE 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 @@ -1701,6 +1701,8 @@ unsigned &NumLineToksConsumed, bool IsUnevaluated); + ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); + private: ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); @@ -1793,8 +1795,6 @@ SourceLocation LParenLoc, SourceLocation RParenLoc); - ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); - ExprResult ParseGenericSelectionExpression(); ExprResult ParseObjCBoolLiteral(); @@ -2920,11 +2920,39 @@ DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc); - /// Parses OpenMP context selectors and calls \p Callback for each - /// successfully parsed context selector. - bool - parseOpenMPContextSelectors(SourceLocation Loc, - SmallVectorImpl &Data); + + /// Parse a property kind into \p TIProperty for the selector set \p Set and + /// selector \p Selector. + void parseOMPTraitPropertyKind(OMPTraitInfo::OMPTraitProperty &TIProperty, + llvm::omp::TraitSet Set, + llvm::omp::TraitSelector Selector, + llvm::StringMap &Seen); + + /// Parse a selector kind into \p TISelector for the selector set \p Set. + void parseOMPTraitSelectorKind(OMPTraitInfo::OMPTraitSelector &TISelector, + llvm::omp::TraitSet Set, + llvm::StringMap &Seen); + + /// Parse a selector set kind into \p TISet. + void parseOMPTraitSetKind(OMPTraitInfo::OMPTraitSet &TISet, + llvm::StringMap &Seen); + + /// Parses an OpenMP context property. + void parseOMPContextProperty(OMPTraitInfo::OMPTraitSelector &TISelector, + llvm::omp::TraitSet Set, + llvm::StringMap &Seen); + + /// Parses an OpenMP context selector. + void parseOMPContextSelector(OMPTraitInfo::OMPTraitSelector &TISelector, + llvm::omp::TraitSet Set, + llvm::StringMap &SeenSelectors); + + /// Parses an OpenMP context selector set. + void parseOMPContextSelectorSet(OMPTraitInfo::OMPTraitSet &TISet, + llvm::StringMap &SeenSets); + + /// Parses OpenMP context selectors. + bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); /// 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 @@ -9716,9 +9716,6 @@ public: /// Struct to store the context selectors info for declare variant directive. - using OMPCtxStringType = SmallString<8>; - using OMPCtxSelectorData = - OpenMPCtxSelectorData, ExprResult>; /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( @@ -10190,10 +10187,12 @@ /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. + /// \param TI The trait info object representing the match clause. /// \returns None, if the function/variant function are not compatible with /// the pragma, pair of original function/variant ref expression otherwise. - Optional> checkOpenMPDeclareVariantFunction( - DeclGroupPtrTy DG, Expr *VariantRef, SourceRange SR); + Optional> + checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef, + OMPTraitInfo &TI, SourceRange SR); /// Called on well-formed '\#pragma omp declare variant' after parsing of /// the associated method/function. @@ -10201,11 +10200,9 @@ /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. - /// \param Data Set of context-specific data for the specified context - /// selector. + /// \param TI The context traits associated with the function variant. void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, - SourceRange SR, - ArrayRef Data); + OMPTraitInfo *TI, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -22,6 +22,7 @@ #include "llvm/ADT/APSInt.h" namespace clang { +struct OMPTraitInfo; /// An object for streaming information from a record. class ASTRecordReader @@ -258,6 +259,9 @@ return Reader->ReadCXXTemporary(*F, Record, Idx); } + /// Read an OMPTraitInfo object, advancing Idx. + OMPTraitInfo *readOMPTraitInfo(); + /// Read an OpenMP clause, advancing Idx. OMPClause *readOMPClause(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -266,6 +266,9 @@ void AddCXXDefinitionData(const CXXRecordDecl *D); + /// Write an OMPTraitInfo object. + void writeOMPTraitInfo(OMPTraitInfo *TI); + void writeOMPClause(OMPClause *C); /// Emit a string. diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1722,3 +1722,107 @@ OS << "order(" << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind()) << ")"; } + +void OMPTraitInfo::getAsVariantMatchInfo( + ASTContext &ASTCtx, llvm::omp::VariantMatchInfo &VMI) const { + for (const OMPTraitSet &Set : Sets) { + for (const OMPTraitSelector &Selector : Set.Selectors) { + + // User conditions are special as we evaluate the condition here. + if (Selector.Kind == llvm::omp::TraitSelector::user_condition) { + assert(Selector.ScoreOrCondition && + "Ill-formed user condition, expected condition expression!"); + assert(Selector.Properties.size() == 1 && + Selector.Properties.front().Kind == + llvm::omp::TraitProperty::user_condition_unknown && + "Ill-formed user condition, expected unknown trait property!"); + + llvm::APInt CondVal = + Selector.ScoreOrCondition->EvaluateKnownConstInt(ASTCtx); + VMI.addTrait(CondVal.isNullValue() + ? llvm::omp::TraitProperty::user_condition_false + : llvm::omp::TraitProperty::user_condition_true); + continue; + } + + llvm::APInt Score; + llvm::APInt *ScorePtr = nullptr; + if (Selector.ScoreOrCondition) { + Score = Selector.ScoreOrCondition->EvaluateKnownConstInt(ASTCtx); + ScorePtr = &Score; + } + for (const OMPTraitProperty &Property : Selector.Properties) + VMI.addTrait(Set.Kind, Property.Kind, ScorePtr); + + if (Set.Kind != llvm::omp::TraitSet::construct) + continue; + + // TODO: This might not hold once we implement SIMD properly. + assert(Selector.Properties.size() == 1 && + Selector.Properties.front().Kind == + llvm::omp::getOpenMPContextTraitPropertyForSelector( + Selector.Kind) && + "Ill-formed construct selector!"); + + VMI.ConstructTraits.push_back(Selector.Properties.front().Kind); + } + } +} + +void OMPTraitInfo::print(llvm::raw_ostream &OS, + const PrintingPolicy &Policy) const { + bool FirstSet = true; + for (const OMPTraitInfo::OMPTraitSet &Set : Sets) { + if (!FirstSet) + OS << ", "; + FirstSet = false; + OS << llvm::omp::getOpenMPContextTraitSetName(Set.Kind) << "={"; + + bool FirstSelector = true; + for (const OMPTraitInfo::OMPTraitSelector &Selector : Set.Selectors) { + if (!FirstSelector) + OS << ", "; + FirstSelector = false; + OS << llvm::omp::getOpenMPContextTraitSelectorName(Selector.Kind); + + bool AllowsTraitScore = false; + bool RequiresProperty = false; + llvm::omp::isValidTraitSelectorForTraitSet( + Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty); + + if (!RequiresProperty) + continue; + + OS << "("; + if (Selector.Kind == llvm::omp::TraitSelector::user_condition) { + Selector.ScoreOrCondition->printPretty(OS, nullptr, Policy); + } else { + + if (Selector.ScoreOrCondition) { + OS << "score("; + Selector.ScoreOrCondition->printPretty(OS, nullptr, Policy); + OS << "): "; + } + + bool FirstProperty = true; + for (const OMPTraitInfo::OMPTraitProperty &Property : + Selector.Properties) { + if (!FirstProperty) + OS << ", "; + FirstProperty = false; + OS << llvm::omp::getOpenMPContextTraitPropertyName(Property.Kind); + } + } + OS << ")"; + } + OS << "}"; + } +} + +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const OMPTraitInfo &TI) { + LangOptions LO; + PrintingPolicy Policy(LO); + TI.print(OS, Policy); + return OS; +} 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 @@ -20,49 +20,6 @@ using namespace clang; using namespace llvm::omp; -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"); -} - OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { // 'flush' clause cannot be specified explicitly, because this is an implicit // clause for 'flush' directive. If the 'flush' clause is explicitly specified 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 @@ -11065,257 +11065,34 @@ 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 OMPContextSelectorData &Data, - Arguments... Params) { - assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown && - "Unknown context selector or context selector set."); - return false; -} - -/// Checks for implementation={vendor()} context selector. -/// \returns true iff ="llvm", false otherwise. -template <> -bool checkContext( - const OMPContextSelectorData &Data) { - return llvm::all_of(Data.Names, - [](StringRef S) { return !S.compare_lower("llvm"); }); -} - -/// Checks for device={kind()} context selector. -/// \returns true if ="host" and compilation is for host. -/// true if ="nohost" and compilation is for device. -/// true if ="cpu" and compilation is for Arm, X86 or PPC CPU. -/// true if ="gpu" and compilation is for NVPTX or AMDGCN. -/// false otherwise. -template <> -bool checkContext( - const OMPContextSelectorData &Data, CodeGenModule &CGM) { - for (StringRef Name : Data.Names) { - if (!Name.compare_lower("host")) { - if (CGM.getLangOpts().OpenMPIsDevice) - return false; - continue; - } - if (!Name.compare_lower("nohost")) { - if (!CGM.getLangOpts().OpenMPIsDevice) - return false; - continue; - } - switch (CGM.getTriple().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::aarch64_32: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (Name.compare_lower("cpu")) - return false; - break; - case llvm::Triple::amdgcn: - case llvm::Triple::nvptx: - case llvm::Triple::nvptx64: - if (Name.compare_lower("gpu")) - return false; - break; - case llvm::Triple::UnknownArch: - case llvm::Triple::arc: - case llvm::Triple::avr: - case llvm::Triple::bpfel: - case llvm::Triple::bpfeb: - case llvm::Triple::hexagon: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::msp430: - case llvm::Triple::r600: - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::sparcel: - case llvm::Triple::systemz: - case llvm::Triple::tce: - case llvm::Triple::tcele: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::xcore: - case llvm::Triple::le32: - case llvm::Triple::le64: - case llvm::Triple::amdil: - case llvm::Triple::amdil64: - case llvm::Triple::hsail: - case llvm::Triple::hsail64: - case llvm::Triple::spir: - case llvm::Triple::spir64: - case llvm::Triple::kalimba: - case llvm::Triple::shave: - case llvm::Triple::lanai: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - case llvm::Triple::renderscript32: - case llvm::Triple::renderscript64: - case llvm::Triple::ve: - return false; - } - } - return true; -} - -static bool matchesContext(CodeGenModule &CGM, - const CompleteOMPContextSelectorData &ContextData) { - for (const OMPContextSelectorData &Data : ContextData) { - switch (Data.Ctx) { - case OMP_CTX_vendor: - assert(Data.CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - if (!checkContext(Data)) - return false; - break; - case OMP_CTX_kind: - assert(Data.CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - if (!checkContext(Data, - CGM)) - return false; - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector 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 (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - Data.back().Names = - llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - Data.back().Names = - llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end()); - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector kind."); - } - } - return Data; -} - -static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS, - const CompleteOMPContextSelectorData &RHS) { - llvm::SmallDenseMap, llvm::StringSet<>, 4> RHSData; - for (const OMPContextSelectorData &D : RHS) { - auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx)); - Pair.getSecond().insert(D.Names.begin(), D.Names.end()); - } - bool AllSetsAreEqual = true; - for (const OMPContextSelectorData &D : LHS) { - auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx)); - if (It == RHSData.end()) - return false; - if (D.Names.size() > It->getSecond().size()) - return false; - if (llvm::set_union(It->getSecond(), D.Names)) - return false; - AllSetsAreEqual = - AllSetsAreEqual && (D.Names.size() == It->getSecond().size()); - } - - return LHS.size() != RHS.size() || !AllSetsAreEqual; -} - -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); - bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS); - if (RHSIsSubsetOfLHS) { - LHSScore = llvm::APSInt::get(0); - } else { - 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); - if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) { - RHSScore = llvm::APSInt::get(0); - } else { - 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 /// selector. static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, const FunctionDecl *FD) { if (!FD->hasAttrs() || !FD->hasAttr()) return FD; - // Iterate through all DeclareVariant attributes and check context selectors. - const OMPDeclareVariantAttr *TopMostAttr = nullptr; - CompleteOMPContextSelectorData TopMostData; + + SmallVector VariantExprs; + SmallVector VMIs; for (const auto *A : FD->specific_attrs()) { - CompleteOMPContextSelectorData Data = - translateAttrToContextSelectorData(CGM.getContext(), A); - if (!matchesContext(CGM, Data)) + const OMPTraitInfo *TI = A->getTraitInfos(); + if (!TI) continue; - // If the attribute matches the context, find the attribute with the highest - // score. - if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) { - TopMostAttr = A; - TopMostData.swap(Data); - } + VMIs.push_back(VariantMatchInfo()); + TI->getAsVariantMatchInfo(CGM.getContext(), VMIs.back()); + VariantExprs.push_back(A->getVariantFuncRef()); } - if (!TopMostAttr) + + OMPContext Ctx(CGM.getLangOpts().OpenMPIsDevice, CGM.getTriple()); + // FIXME: Keep the context in the OMPIRBuilder so we can add constructs as we + // build them. + + int BestMatchIdx = getBestVariantMatchForContext(VMIs, Ctx); + if (BestMatchIdx < 0) return FD; + return cast( - cast(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts()) + cast(VariantExprs[BestMatchIdx]->IgnoreParenImpCasts()) ->getDecl()); } 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 @@ -19,6 +19,7 @@ #include "clang/Sema/Scope.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/UniqueVector.h" +#include "llvm/Frontend/OpenMP/OMPContext.h" using namespace clang; using namespace llvm::omp; @@ -810,10 +811,225 @@ LinModifiers, Steps, SourceRange(Loc, EndLoc)); } +namespace { +/// Constant used in the diagnostics to distinguish the levels in an OpenMP +/// contexts: selector-set={selector(trait, ...), ...}, .... +enum OMPContextLvl { + CONTEXT_SELECTOR_SET_LVL = 0, + CONTEXT_SELECTOR_LVL = 1, + CONTEXT_TRAIT_LVL = 2, +}; + +static StringRef stringLiteralParser(Parser &P) { + ExprResult Res = P.ParseStringLiteralExpression(true); + return Res.isUsable() ? Res.getAs()->getString() : ""; +} + +static StringRef getNameFromIdOrString(Parser &P, Token &Tok, + OMPContextLvl Lvl) { + if (Tok.is(tok::identifier)) { + llvm::SmallString<16> Buffer; + StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer); + (void)P.ConsumeToken(); + return Name; + } + + if (tok::isStringLiteral(Tok.getKind())) + return stringLiteralParser(P); + + P.Diag(Tok.getLocation(), + diag::warn_omp_declare_variant_string_literal_or_identifier) + << Lvl; + return ""; +} + +static bool checkForDuplicates(Parser &P, StringRef Name, + SourceLocation NameLoc, + llvm::StringMap &Seen, + OMPContextLvl Lvl) { + auto Res = Seen.try_emplace(Name, NameLoc); + if (Res.second) + return false; + + // Each trait-set-selector-name, trait-selector-name and trait-name can + // only be specified once. + P.Diag(NameLoc, diag::warn_omp_declare_variant_ctx_mutiple_use) + << Lvl << Name; + P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) + << Lvl << Name; + return true; +} +} // namespace + +void Parser::parseOMPTraitPropertyKind( + OMPTraitInfo::OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, + llvm::omp::TraitSelector Selector, llvm::StringMap &Seen) { + TIProperty.Kind = TraitProperty::invalid; + + SourceLocation NameLoc = Tok.getLocation(); + StringRef Name = + getNameFromIdOrString(*this, Tok, CONTEXT_TRAIT_LVL); + if (Name.empty()) { + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) + << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector); + return; + } + + TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Name); + if (TIProperty.Kind != TraitProperty::invalid) { + if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_TRAIT_LVL)) + TIProperty.Kind = TraitProperty::invalid; + return; + } + + // It follows diagnosis and helping notes. + // FIXME: We should move the diagnosis string generation into libFrontend. + Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_property) + << Name << getOpenMPContextTraitSelectorName(Selector) + << getOpenMPContextTraitSetName(Set); + + TraitSet SetForName = getOpenMPContextTraitSetKind(Name); + if (SetForName != TraitSet::invalid) { + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_TRAIT_LVL; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << Name << "" + << "()"; + return; + } + TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name); + if (SelectorForName != TraitSelector::invalid) { + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_SELECTOR_LVL << CONTEXT_TRAIT_LVL; + bool AllowsTraitScore = false; + bool RequiresProperty = false; + isValidTraitSelectorForTraitSet( + SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName), + AllowsTraitScore, RequiresProperty); + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForSelector(SelectorForName)) + << Name << (RequiresProperty ? "()" : ""); + return; + } + for (const auto &PotentialSet : + {TraitSet::construct, TraitSet::user, TraitSet::implementation, + TraitSet::device}) { + TraitProperty PropertyForName = + getOpenMPContextTraitPropertyKind(PotentialSet, Name); + if (PropertyForName == TraitProperty::invalid) + continue; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForProperty(PropertyForName)) + << getOpenMPContextTraitSelectorName( + getOpenMPContextTraitSelectorForProperty(PropertyForName)) + << ("(" + Name + ")").str(); + return; + } + Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) + << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector); +} + +void Parser::parseOMPContextProperty(OMPTraitInfo::OMPTraitSelector &TISelector, + llvm::omp::TraitSet Set, + llvm::StringMap &Seen) { + assert(TISelector.Kind != TraitSelector::user_condition && + "User conditions are special properties not handled here!"); + + SourceLocation PropertyLoc = Tok.getLocation(); + OMPTraitInfo::OMPTraitProperty TIProperty; + parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen); + + // If we have an invalid property here we already issued a warning. + if (TIProperty.Kind == TraitProperty::invalid) { + if (PropertyLoc != Tok.getLocation()) + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) + << CONTEXT_TRAIT_LVL; + return; + } + + if (isValidTraitPropertyForTraitSetAndSelector(TIProperty.Kind, + TISelector.Kind, Set)) { + // If we make it here the property, selector, set, score, condition, ... are + // all valid (or have been corrected). Thus we can record the property. + TISelector.Properties.push_back(TIProperty); + return; + } + + Diag(PropertyLoc, diag::warn_omp_ctx_incompatible_property_for_selector) + << getOpenMPContextTraitPropertyName(TIProperty.Kind) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set); + Diag(PropertyLoc, diag::note_omp_ctx_compatible_set_and_selector_for_property) + << getOpenMPContextTraitPropertyName(TIProperty.Kind) + << getOpenMPContextTraitSelectorName( + getOpenMPContextTraitSelectorForProperty(TIProperty.Kind)) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForProperty(TIProperty.Kind)); + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) + << CONTEXT_TRAIT_LVL; +} + +void Parser::parseOMPTraitSelectorKind( + OMPTraitInfo::OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, + llvm::StringMap &Seen) { + TISelector.Kind = TraitSelector::invalid; + + SourceLocation NameLoc = Tok.getLocation(); + StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_LVL + ); + if (Name.empty()) { + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) + << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set); + return; + } + + TISelector.Kind = getOpenMPContextTraitSelectorKind(Name); + if (TISelector.Kind != TraitSelector::invalid) { + if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_SELECTOR_LVL)) + TISelector.Kind = TraitSelector::invalid; + return; + } + + // It follows diagnosis and helping notes. + Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_selector) + << Name << getOpenMPContextTraitSetName(Set); + + TraitSet SetForName = getOpenMPContextTraitSetKind(Name); + if (SetForName != TraitSet::invalid) { + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_SELECTOR_LVL; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << Name << "" + << ""; + return; + } + for (const auto &PotentialSet : + {TraitSet::construct, TraitSet::user, TraitSet::implementation, + TraitSet::device}) { + TraitProperty PropertyForName = + getOpenMPContextTraitPropertyKind(PotentialSet, Name); + if (PropertyForName == TraitProperty::invalid) + continue; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_LVL; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForProperty(PropertyForName)) + << getOpenMPContextTraitSelectorName( + getOpenMPContextTraitSelectorForProperty(PropertyForName)) + << ("(" + Name + ")").str(); + return; + } + Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) + << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set); +} + /// Parse optional 'score' '(' ')' ':'. static ExprResult parseContextScore(Parser &P) { ExprResult ScoreExpr; - Sema::OMPCtxStringType Buffer; + llvm::SmallString<16> Buffer; StringRef SelectorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); if (!SelectorName.equals("score")) @@ -825,246 +1041,266 @@ if (P.getCurToken().is(tok::colon)) (void)P.ConsumeAnyToken(); else - P.Diag(P.getCurToken(), diag::warn_pragma_expected_colon) - << "context selector score clause"; + P.Diag(P.getCurToken(), diag::warn_omp_declare_variant_expected) + << "':'" + << "score expression"; return ScoreExpr; } -/// Parse context selector for 'implementation' selector set: -/// 'vendor' '(' [ 'score' '(' ')' ':' ] { ',' } -/// ')' -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)) { - P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) - << "implementation"; - // Skip until either '}', ')', or end of directive. - while (!P.SkipUntil(tok::r_brace, tok::r_paren, - tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; - return; - } - Sema::OMPCtxStringType Buffer; - StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); - auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); - if (!Res.second) { - // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. - // Each trait-selector-name can only be specified once. - P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) - << CtxSelectorName << "implementation"; - P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) - << CtxSelectorName; - } - OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); - (void)P.ConsumeToken(); - switch (CSKind) { - 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()); - ExprResult Score = parseContextScore(P); - llvm::UniqueVector Vendors; - do { - // Parse . - StringRef VendorName; - if (Tok.is(tok::identifier)) { - Buffer.clear(); - VendorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); - (void)P.ConsumeToken(); - if (!VendorName.empty()) - Vendors.insert(VendorName); - } else { - P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected) - << "vendor identifier" - << "vendor" - << "implementation"; +/// Parses an OpenMP context selector. +/// +/// ['('[] [, ]* ')'] +void Parser::parseOMPContextSelector( + OMPTraitInfo::OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, + llvm::StringMap &SeenSelectors) { + unsigned short OuterPC = ParenCount; + + // If anything went wrong we issue an error or warning and then skip the rest + // of the selector. However, commas are ambiguous so we look for the nesting + // of parentheses here as well. + auto FinishSelector = [OuterPC, this]() -> void { + bool Done = false; + while (!Done) { + while (!SkipUntil({tok::r_brace, tok::r_paren, tok::comma, + tok::annot_pragma_openmp_end}, + StopBeforeMatch)) + ; + if (Tok.is(tok::r_paren) && OuterPC > ParenCount) + (void)ConsumeParen(); + if (OuterPC <= ParenCount) { + Done = true; + break; } - if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) { - P.Diag(Tok, diag::err_expected_punc) - << (VendorName.empty() ? "vendor name" : VendorName); + if (!Tok.is(tok::comma) && !Tok.is(tok::r_paren)) { + Done = true; + break; } - } while (Tok.is(tok::identifier)); - // Parse ')'. - (void)T.consumeClose(); - if (!Vendors.empty()) - Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors); - break; + (void)ConsumeAnyToken(); + } + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) + << CONTEXT_SELECTOR_LVL; + }; + + SourceLocation SelectorLoc = Tok.getLocation(); + parseOMPTraitSelectorKind(TISelector, Set, SeenSelectors); + if (TISelector.Kind == TraitSelector::invalid) + return FinishSelector(); + + bool AllowsTraitScore = false; + bool RequiresProperty = false; + if (!isValidTraitSelectorForTraitSet(TISelector.Kind, Set, AllowsTraitScore, + RequiresProperty)) { + Diag(SelectorLoc, diag::warn_omp_ctx_incompatible_selector_for_set) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set); + Diag(SelectorLoc, diag::note_omp_ctx_compatible_set_for_selector) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForSelector(TISelector.Kind)) + << RequiresProperty; + return FinishSelector(); + } + + if (!RequiresProperty) { + TISelector.Properties.push_back( + {getOpenMPContextTraitPropertyForSelector(TISelector.Kind)}); + return; } - case OMP_CTX_kind: - case OMP_CTX_unknown: - P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) - << "implementation"; - // Skip until either '}', ')', or end of directive. - while (!P.SkipUntil(tok::r_brace, tok::r_paren, - tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; + + if (!Tok.is(tok::l_paren)) { + Diag(SelectorLoc, diag::warn_omp_ctx_selector_without_properties) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set); + return FinishSelector(); + } + + if (TISelector.Kind == TraitSelector::user_condition) { + SourceLocation RLoc; + ExprResult Condition = ParseOpenMPParensExpr("user condition", RLoc); + if (!Condition.isUsable()) + return FinishSelector(); + TISelector.ScoreOrCondition = Condition.get(); + TISelector.Properties.push_back({TraitProperty::user_condition_unknown}); return; } + + BalancedDelimiterTracker BDT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + // Parse '('. + (void)BDT.consumeOpen(); + + ExprResult Score = parseContextScore(*this); + + if (!AllowsTraitScore && Score.isUsable()) { + Diag(Score.get()->getBeginLoc(), + diag::warn_omp_ctx_incompatible_score_for_property) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set) << Score.get(); + Score = ExprResult(); + } + + if (Score.isUsable()) + TISelector.ScoreOrCondition = Score.get(); + + llvm::StringMap SeenProperties; + do { + parseOMPContextProperty(TISelector, Set, SeenProperties); + } while (TryConsumeToken(tok::comma)); + + // Parse ')'. + BDT.consumeClose(); } -/// Parse context selector for 'device' selector set: -/// 'kind' '(' { ',' } ')' -static void -parseDeviceSelector(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)) { - P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) - << "device"; - // Skip until either '}', ')', or end of directive. - while (!P.SkipUntil(tok::r_brace, tok::r_paren, - tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; +void Parser::parseOMPTraitSetKind(OMPTraitInfo::OMPTraitSet &TISet, + llvm::StringMap &Seen) { + TISet.Kind = TraitSet::invalid; + + SourceLocation NameLoc = Tok.getLocation(); + StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_SET_LVL + ); + if (Name.empty()) { + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) + << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets(); return; } - Sema::OMPCtxStringType Buffer; - StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); - auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); - if (!Res.second) { - // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. - // Each trait-selector-name can only be specified once. - P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) - << CtxSelectorName << "device"; - P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) - << CtxSelectorName; - } - OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); - (void)P.ConsumeToken(); - switch (CSKind) { - case OMP_CTX_kind: { - // Parse '('. - BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); - (void)T.expectAndConsume(diag::err_expected_lparen_after, - CtxSelectorName.data()); - llvm::UniqueVector Kinds; - do { - // Parse . - StringRef KindName; - if (Tok.is(tok::identifier)) { - Buffer.clear(); - KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); - SourceLocation SLoc = P.getCurToken().getLocation(); - (void)P.ConsumeToken(); - if (llvm::StringSwitch(KindName) - .Case("host", false) - .Case("nohost", false) - .Case("cpu", false) - .Case("gpu", false) - .Case("fpga", false) - .Default(true)) { - P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName; - } else { - Kinds.insert(KindName); - } - } else { - P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected) - << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'" - << "kind" - << "device"; + + TISet.Kind = getOpenMPContextTraitSetKind(Name); + if (TISet.Kind != TraitSet::invalid) { + if (checkForDuplicates(*this, Name, NameLoc, Seen, + CONTEXT_SELECTOR_SET_LVL)) + TISet.Kind = TraitSet::invalid; + return; + } + + // It follows diagnosis and helping notes. + Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_set) << Name; + + TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name); + if (SelectorForName != TraitSelector::invalid) { + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_SELECTOR_LVL << CONTEXT_SELECTOR_SET_LVL; + bool AllowsTraitScore = false; + bool RequiresProperty = false; + isValidTraitSelectorForTraitSet( + SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName), + AllowsTraitScore, RequiresProperty); + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForSelector(SelectorForName)) + << Name << (RequiresProperty ? "()" : ""); + return; + } + for (const auto &PotentialSet : + {TraitSet::construct, TraitSet::user, TraitSet::implementation, + TraitSet::device}) { + TraitProperty PropertyForName = + getOpenMPContextTraitPropertyKind(PotentialSet, Name); + if (PropertyForName == TraitProperty::invalid) + continue; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) + << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_SET_LVL; + Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) + << getOpenMPContextTraitSetName( + getOpenMPContextTraitSetForProperty(PropertyForName)) + << getOpenMPContextTraitSelectorName( + getOpenMPContextTraitSelectorForProperty(PropertyForName)) + << ("(" + Name + ")").str(); + return; + } + Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) + << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets(); +} + +/// Parses an OpenMP context selector set. +/// +/// '=' '{' [, ]* '}' +void Parser::parseOMPContextSelectorSet( + OMPTraitInfo::OMPTraitSet &TISet, + llvm::StringMap &SeenSets) { + auto OuterBC = BraceCount; + + // If anything went wrong we issue an error or warning and then skip the rest + // of the set. However, commas are ambiguous so we look for the nesting + // of braces here as well. + auto FinishSelectorSet = [this, OuterBC]() -> void { + bool Done = false; + while (!Done) { + while (!SkipUntil({tok::comma, tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end}, + StopBeforeMatch)) + ; + if (Tok.is(tok::r_brace) && OuterBC > BraceCount) + (void)ConsumeBrace(); + if (OuterBC <= BraceCount) { + Done = true; + break; } - if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) { - P.Diag(Tok, diag::err_expected_punc) - << (KindName.empty() ? "kind of device" : KindName); + if (!Tok.is(tok::comma) && !Tok.is(tok::r_brace)) { + Done = true; + break; } - } while (Tok.is(tok::identifier)); - // Parse ')'. - (void)T.consumeClose(); - if (!Kinds.empty()) - Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds); - break; + (void)ConsumeAnyToken(); + } + Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) + << CONTEXT_SELECTOR_SET_LVL; + }; + + parseOMPTraitSetKind(TISet, SeenSets); + if (TISet.Kind == TraitSet::invalid) + return FinishSelectorSet(); + + // Parse '='. + if (!TryConsumeToken(tok::equal)) + Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) + << "=" + << ("context set name \"" + getOpenMPContextTraitSetName(TISet.Kind) + + "\"") + .str(); + + // Parse '{'. + if (Tok.is(tok::l_brace)) { + (void)ConsumeBrace(); + } else { + Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) + << "{" + << ("'=' that follows the context set name \"" + + getOpenMPContextTraitSetName(TISet.Kind) + "\"") + .str(); } - case OMP_CTX_vendor: - case OMP_CTX_unknown: - P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) - << "device"; - // Skip until either '}', ')', or end of directive. - while (!P.SkipUntil(tok::r_brace, tok::r_paren, - tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; - return; + + llvm::StringMap SeenSelectors; + do { + OMPTraitInfo::OMPTraitSelector TISelector; + parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors); + if (TISelector.Kind != TraitSelector::invalid && + !TISelector.Properties.empty()) + TISet.Selectors.push_back(TISelector); + } while (TryConsumeToken(tok::comma)); + + // Parse '}'. + if (Tok.is(tok::r_brace)) { + (void)ConsumeBrace(); + } else { + Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) + << "}" + << ("context selectors for the context set \"" + + getOpenMPContextTraitSetName(TISet.Kind) + "\"") + .str(); } } -/// Parses clauses for 'declare variant' directive. -/// clause: -/// '=' '{' '}' -/// [ ',' '=' '{' '}' ] -bool Parser::parseOpenMPContextSelectors( - SourceLocation Loc, SmallVectorImpl &Data) { - llvm::StringMap UsedCtxSets; +/// Parse OpenMP context selectors: +/// +/// [, ]* +bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) { + llvm::StringMap SeenSets; do { - // Parse inner context selector set name. - if (!Tok.is(tok::identifier)) { - Diag(Tok.getLocation(), diag::err_omp_declare_variant_no_ctx_selector) - << getOpenMPClauseName(OMPC_match); - return true; - } - Sema::OMPCtxStringType Buffer; - StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer); - auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation()); - if (!Res.second) { - // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. - // Each trait-set-selector-name can only be specified once. - Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_set_mutiple_use) - << CtxSelectorSetName; - Diag(Res.first->getValue(), - diag::note_omp_declare_variant_ctx_set_used_here) - << CtxSelectorSetName; - } - // Parse '='. - (void)ConsumeToken(); - if (Tok.isNot(tok::equal)) { - Diag(Tok.getLocation(), diag::err_omp_declare_variant_equal_expected) - << CtxSelectorSetName; - return true; - } - (void)ConsumeToken(); - // TBD: add parsing of known context selectors. - // Unknown selector - just ignore it completely. - { - // Parse '{'. - BalancedDelimiterTracker TBr(*this, tok::l_brace, - tok::annot_pragma_openmp_end); - if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "=")) - return true; - OpenMPContextSelectorSetKind CSSKind = - getOpenMPContextSelectorSet(CtxSelectorSetName); - llvm::StringMap UsedCtx; - do { - switch (CSSKind) { - case OMP_CTX_SET_implementation: - parseImplementationSelector(*this, Loc, UsedCtx, Data); - break; - case OMP_CTX_SET_device: - parseDeviceSelector(*this, Loc, UsedCtx, Data); - break; - 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)) - ; - break; - } - const Token PrevTok = Tok; - if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace)) - Diag(Tok, diag::err_omp_expected_comma_brace) - << (PrevTok.isAnnotation() ? "context selector trait" - : PP.getSpelling(PrevTok)); - } while (Tok.is(tok::identifier)); - // Parse '}'. - (void)TBr.consumeClose(); - } - // Consume ',' - if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) - (void)ExpectAndConsume(tok::comma); - } while (Tok.isAnyIdentifier()); + OMPTraitInfo::OMPTraitSet TISet; + parseOMPContextSelectorSet(TISet, SeenSets); + if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty()) + TI.Sets.push_back(TISet); + } while (TryConsumeToken(tok::comma)); + return false; } @@ -1102,9 +1338,6 @@ (void)ConsumeAnnotationToken(); return; } - Optional> DeclVarData = - Actions.checkOpenMPDeclareVariantFunction( - Ptr, AssociatedFunction.get(), SourceRange(Loc, Tok.getLocation())); // Parse 'match'. OpenMPClauseKind CKind = Tok.isAnnotation() @@ -1132,24 +1365,27 @@ } // Parse inner context selectors. - SmallVector Data; - if (!parseOpenMPContextSelectors(Loc, Data)) { - // Parse ')'. - (void)T.consumeClose(); - // Need to check for extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_declare_variant); - } - } + OMPTraitInfo *TI = new OMPTraitInfo(); + parseOMPContextSelectors(Loc, *TI); + + // Parse ')' + (void)T.consumeClose(); + + Optional> DeclVarData = + Actions.checkOpenMPDeclareVariantFunction( + Ptr, AssociatedFunction.get(), *TI, + SourceRange(Loc, Tok.getLocation())); // Skip last tokens. while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); - if (DeclVarData.hasValue()) + if (DeclVarData.hasValue() && !TI->Sets.empty()) Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData.getValue().first, DeclVarData.getValue().second, - SourceRange(Loc, Tok.getLocation()), Data); + DeclVarData.getValue().first, DeclVarData.getValue().second, TI, + SourceRange(Loc, Tok.getLocation())); + else + delete TI; + // 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 @@ -5369,7 +5369,8 @@ Optional> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, - Expr *VariantRef, SourceRange SR) { + Expr *VariantRef, OMPTraitInfo &TI, + SourceRange SR) { if (!DG || DG.get().isNull()) return None; @@ -5422,12 +5423,41 @@ return None; } + auto ShouldDelayChecks = [](Expr *&E, bool) { + return E && (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || + E->isInstantiationDependent()); + }; // Do not check templates, wait until instantiation. - if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || - VariantRef->containsUnexpandedParameterPack() || - VariantRef->isInstantiationDependent() || FD->isDependentContext()) + if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) || + TI.anyScoreOrCondition(ShouldDelayChecks)) return std::make_pair(FD, VariantRef); + // Deal with non-constant score and user condition expressions. + auto HandleNonConstantScoresAndConditions = [this](Expr *&E, + bool IsScore) -> bool { + llvm::APSInt Result; + if (!E || E->isIntegerConstantExpr(Result, Context)) + return false; + + if (IsScore) { + // We warn on non-constant scores and pretend they were not present. + Diag(E->getExprLoc(), diag::warn_omp_declare_variant_score_not_constant) + << E; + E = nullptr; + } else { + // We could replace a non-constant user condition with "false" but we + // will soon need to handle these anyway for the dynamic version of + // OpenMP context selectors. + Diag(E->getExprLoc(), + diag::err_omp_declare_variant_user_condition_not_constant) + << E; + } + return true; + }; + if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) + return None; + // Convert VariantRef expression to the type of the original function to // resolve possible conflicts. ExprResult VariantRefCast; @@ -5600,75 +5630,13 @@ return std::make_pair(FD, cast(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective( - FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - ArrayRef Data) { - if (Data.empty()) - return; - SmallVector CtxScores; - SmallVector CtxSets; - SmallVector Ctxs; - SmallVector ImplVendors, DeviceKinds; - 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 { - // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors. - // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and - // 2^(l+2), respectively, where l is the number of traits in the construct - // set. - // TODO: implement correct logic for isa and arch traits. - // TODO: take the construct context set into account when it is - // implemented. - int L = 0; // Currently set the number of traits in construct set to 0, - // since the construct trait set in not supported yet. - if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind) - Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get(); - else - Score = ActOnIntegerConstant(SourceLocation(), 0).get(); - } - switch (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - ImplVendors.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - DeviceKinds.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector 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(), DeviceKinds.begin(), - DeviceKinds.size(), SR); - FD->addAttr(NewAttr); - } +void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, + Expr *VariantRef, + OMPTraitInfo *TI, + SourceRange SR) { + auto *NewAttr = + OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, TI, SR); + FD->addAttr(NewAttr); } void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, @@ -10481,7 +10449,6 @@ CS->getCapturedDecl()->setNothrow(); } - OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. 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 @@ -393,50 +393,43 @@ VariantFuncRef = Subst(E); } + // Copy the template version of the OMPTraitInfo and run substitute on all + // score and condition expressiosn. + OMPTraitInfo *TI = new OMPTraitInfo(); + *TI = *Attr.getTraitInfos(); + + // Try to substitute template parameters in score and condition expressions. + auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) { + if (E) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult ER = Subst(E); + if (ER.isUsable()) + E = ER.get(); + else + return true; + } + return false; + }; + if (TI->anyScoreOrCondition(SubstScoreOrConditionExpr)) { + delete TI; + return; + } + // Check function/variant ref. Optional> DeclVarData = - S.checkOpenMPDeclareVariantFunction( - S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange()); - if (!DeclVarData) + S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), + VariantFuncRef.get(), *TI, + Attr.getRange()); + + if (!DeclVarData) { + delete TI; return; - 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_kind: - case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); - } - break; - case OMP_CTX_SET_device: - switch (Ctx) { - case OMP_CTX_kind: - Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds()); - break; - case OMP_CTX_vendor: - 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); + DeclVarData.getValue().second, TI, + Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12612,3 +12612,22 @@ C->setLParenLoc(Record.readSourceLocation()); C->setKindKwLoc(Record.readSourceLocation()); } + +OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { + OMPTraitInfo *TI = new OMPTraitInfo(); + TI->Sets.resize(readUInt32()); + for (auto &Set : TI->Sets) { + Set.Kind = readEnum(); + Set.Selectors.resize(readUInt32()); + for (auto &Selector : Set.Selectors) { + Selector.Kind = readEnum(); + Selector.ScoreOrCondition = nullptr; + if (readBool()) + Selector.ScoreOrCondition = readExprRef(); + Selector.Properties.resize(readUInt32()); + for (auto &Property : Selector.Properties) + Property.Kind = readEnum(); + } + } + return TI; +} diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2756,6 +2756,8 @@ return Reader.readVersionTuple(); } + OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } + template T *GetLocalDeclAs(uint32_t LocalID) { return Reader.GetLocalDeclAs(LocalID); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6578,3 +6578,19 @@ Record.AddSourceLocation(C->getKindKwLoc()); } +void ASTRecordWriter::writeOMPTraitInfo(OMPTraitInfo *TI) { + writeUInt32(TI->Sets.size()); + for (const auto &Set : TI->Sets) { + writeEnum(Set.Kind); + writeUInt32(Set.Selectors.size()); + for (const auto &Selector : Set.Selectors) { + writeEnum(Selector.Kind); + writeBool(Selector.ScoreOrCondition); + if (Selector.ScoreOrCondition) + writeExprRef(Selector.ScoreOrCondition); + writeUInt32(Selector.Properties.size()); + for (const auto &Property : Selector.Properties) + writeEnum(Property.Kind); + } + } +} diff --git a/clang/test/OpenMP/declare_variant_ast_print.c b/clang/test/OpenMP/declare_variant_ast_print.c --- a/clang/test/OpenMP/declare_variant_ast_print.c +++ b/clang/test/OpenMP/declare_variant_ast_print.c @@ -8,7 +8,7 @@ #pragma omp declare variant(foo) match(xxx={}, yyy={ccc}) #pragma omp declare variant(foo) match(xxx={vvv}) -#pragma omp declare variant(foo) match(implementation={vendor(llvm)}, device={kind(fpga)}) +#pragma omp declare variant(foo) match(implementation={vendor(score(0):llvm)}, device={kind(fpga)}) #pragma omp declare variant(foo) match(implementation={vendor(llvm), xxx}) #pragma omp declare variant(foo) match(implementation={vendor(unknown)}, device={kind(gpu)}) #pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm, xxx, ibm)}, device={kind(cpu, nohost)}) @@ -19,8 +19,8 @@ // CHECK: int foo(); // CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind(nohost)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(device={kind(host)}) -// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):ibm, xxx)},device={kind(cpu, nohost)}) -// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):unknown)},device={kind(gpu)}) -// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):llvm)}) -// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0):llvm)},device={kind(fpga)}) +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm)}, device={kind(cpu, nohost)}) +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(unknown)}, device={kind(gpu)}) +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(llvm)}) +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(0): llvm)}, device={kind(fpga)}) // CHECK-NEXT: int bar(); diff --git a/clang/test/OpenMP/declare_variant_ast_print.cpp b/clang/test/OpenMP/declare_variant_ast_print.cpp --- a/clang/test/OpenMP/declare_variant_ast_print.cpp +++ b/clang/test/OpenMP/declare_variant_ast_print.cpp @@ -17,36 +17,40 @@ // CHECK-NEXT: return int(); // CHECK-NEXT: } -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(5):ibm)},device={kind(fpga)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):unknown)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):llvm)},device={kind(cpu)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(5): ibm)}, device={kind(fpga)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0): llvm)}, device={kind(cpu)}) // CHECK-NEXT: int bar(); #pragma omp declare variant(foofoo ) match(xxx = {}) #pragma omp declare variant(foofoo ) match(xxx = {vvv}) -#pragma omp declare variant(foofoo ) match(implementation={vendor(llvm), xxx}, device={kind(cpu)}) -#pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm)}, device={kind(fpga)}) +#pragma omp declare variant(foofoo ) match(implementation = {vendor(score(0): "llvm"), xxx}, device = {kind(cpu)}) +#pragma omp declare variant(foofoo ) match(implementation = {vendor("unknown")}) +#pragma omp declare variant(foofoo ) match(implementation = {vendor(score(5): ibm)}, device = {kind(fpga)}) int bar(); -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(C + 5):ibm, xxx)},device={kind(cpu, host)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):unknown)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):llvm)},device={kind(cpu)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(C + 5): ibm)}, device={kind(cpu, host)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(llvm)}, device={kind(cpu)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(user={condition(false)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(user={condition(true)}) // CHECK-NEXT: template T barbar(); #pragma omp declare variant(foofoo ) match(xxx = {}) #pragma omp declare variant(foofoo ) match(xxx = {vvv}) -#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) -#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) -#pragma omp declare variant(foofoo ) match(user = {condition()}) -#pragma omp declare variant(foofoo ) match(user = {condition()}) -#pragma omp declare variant(foofoo ) match(implementation={vendor(llvm)},device={kind(cpu)}) +#pragma omp declare variant(foofoo ) match(user = {score(1 * 1 + 1) : condition(100 > 10 + 2)}) +#pragma omp declare variant(foofoo ) match(user = {score(0) : condition(0)}) +#pragma omp declare variant(foofoo ) match(user = {condition(true)}) +#pragma omp declare variant(foofoo ) match(user = {condition(false)}) +#pragma omp declare variant(foofoo ) match(implementation = {vendor(llvm)}, device = {kind(cpu)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm, xxx, ibm)},device={kind(cpu,host)}) template T barbar(); -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(3 + 5):ibm, xxx)},device={kind(cpu, host)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):unknown)}) -// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(score(0):llvm)},device={kind(cpu)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(3 + 5): ibm)}, device={kind(cpu, host)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(llvm)}, device={kind(cpu)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(user={condition(false)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(user={condition(true)}) // CHECK-NEXT: template<> int barbar(); // CHECK-NEXT: int baz() { @@ -66,19 +70,19 @@ void h_ref(C *hp, C *hp2, C *hq, C *lin) { } -// CHECK: #pragma omp declare variant(h_ref) match(implementation={vendor(score(0):unknown)},device={kind(nohost)}) -// CHECK-NEXT: #pragma omp declare variant(h_ref) match(implementation={vendor(score(0):llvm)},device={kind(gpu)}) +// CHECK: #pragma omp declare variant(h_ref) match(implementation={vendor(unknown)}, device={kind(nohost)}) +// CHECK-NEXT: #pragma omp declare variant(h_ref) match(implementation={vendor(llvm)}, device={kind(gpu)}) // CHECK-NEXT: template void h(C *hp, C *hp2, C *hq, C *lin) { // CHECK-NEXT: } #pragma omp declare variant(h_ref ) match(xxx = {}) -#pragma omp declare variant(h_ref ) match(implementation={vendor(llvm)}, device={kind(gpu)}) -#pragma omp declare variant(h_ref ) match(implementation={vendor(unknown)},device={kind(nohost)}) +#pragma omp declare variant(h_ref ) match(implementation = {vendor(llvm)}, device = {kind(gpu)}) +#pragma omp declare variant(h_ref ) match(implementation = {vendor(unknown)}, device = {kind(nohost)}) template void h(C *hp, C *hp2, C *hq, C *lin) { } -// CHECK: #pragma omp declare variant(h_ref) match(implementation={vendor(score(0):unknown)},device={kind(nohost)}) -// CHECK-NEXT: #pragma omp declare variant(h_ref) match(implementation={vendor(score(0):llvm)},device={kind(gpu)}) +// CHECK: #pragma omp declare variant(h_ref) match(implementation={vendor(unknown)}, device={kind(nohost)}) +// CHECK-NEXT: #pragma omp declare variant(h_ref) match(implementation={vendor(llvm)}, device={kind(gpu)}) // CHECK-NEXT: template<> void h(float *hp, float *hp2, float *hq, float *lin) { // CHECK-NEXT: } @@ -86,7 +90,7 @@ // CHECK-NEXT: h((float *)hp, (float *)hp2, (float *)hq, (float *)lin); // CHECK-NEXT: } #pragma omp declare variant(h_ref ) match(xxx = {}) -#pragma omp declare variant(h_ref ) match(implementation={vendor(ibm)},device={kind(cpu,gpu)}) +#pragma omp declare variant(h_ref ) match(implementation = {vendor(ibm)}, device = {kind(cpu, gpu)}) #pragma omp declare variant(h_ref ) match(implementation={vendor(unknown)}) template <> void h(double *hp, double *hp2, double *hq, double *lin) { @@ -97,36 +101,36 @@ int fn(); // CHECK: int fn(int); int fn(int); -// CHECK: #pragma omp declare variant(fn) match(implementation={vendor(score(0):unknown)},device={kind(cpu, gpu)}) -// CHECK-NEXT: #pragma omp declare variant(fn) match(implementation={vendor(score(0):llvm)}) +// CHECK: #pragma omp declare variant(fn) match(implementation={vendor(unknown)}, device={kind(cpu, gpu)}) +// CHECK-NEXT: #pragma omp declare variant(fn) match(implementation={vendor(llvm)}) // CHECK-NEXT: int overload(); #pragma omp declare variant(fn) match(xxx = {}) #pragma omp declare variant(fn) match(implementation={vendor(llvm)}) -#pragma omp declare variant(fn) match(implementation={vendor(unknown)},device={kind(cpu,gpu)}) +#pragma omp declare variant(fn) match(implementation = {vendor(unknown)}, device = {kind(cpu, gpu)}) int overload(void); // CHECK: int fn_deduced_variant() { // CHECK-NEXT: return 0; // CHECK-NEXT: } auto fn_deduced_variant() { return 0; } -// CHECK: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):unknown)},device={kind(gpu, nohost)}) -// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(score(0):llvm)},device={kind(cpu, host)}) +// CHECK: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(unknown)}, device={kind(gpu, nohost)}) +// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(llvm)}, device={kind(cpu, host)}) // CHECK-NEXT: int fn_deduced(); #pragma omp declare variant(fn_deduced_variant) match(xxx = {}) -#pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(llvm)},device={kind(cpu,host)}) -#pragma omp declare variant(fn_deduced_variant) match(implementation={vendor(unknown)},device={kind(gpu,nohost)}) +#pragma omp declare variant(fn_deduced_variant) match(implementation = {vendor(llvm)}, device = {kind(cpu, host)}) +#pragma omp declare variant(fn_deduced_variant) match(implementation = {vendor(unknown)}, device = {kind(gpu, nohost)}) int fn_deduced(); // CHECK: int fn_deduced_variant1(); int fn_deduced_variant1(); -// CHECK: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)}) -// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(score(0):ibm)},device={kind(gpu, nohost)}) +// CHECK: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(unknown)}, device={kind(cpu, host)}) +// CHECK-NEXT: #pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(ibm)}, device={kind(gpu, nohost)}) // CHECK-NEXT: int fn_deduced1() { // CHECK-NEXT: return 0; // CHECK-NEXT: } #pragma omp declare variant(fn_deduced_variant1) match(xxx = {}) -#pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(ibm)},device={kind(gpu,nohost)}) -#pragma omp declare variant(fn_deduced_variant1) match(implementation={vendor(unknown)},device={kind(cpu,host)}) +#pragma omp declare variant(fn_deduced_variant1) match(implementation = {vendor(ibm)}, device = {kind(gpu, nohost)}) +#pragma omp declare variant(fn_deduced_variant1) match(implementation = {vendor(unknown)}, device = {kind(cpu, host)}) auto fn_deduced1() { return 0; } // CHECK: struct SpecialFuncs { @@ -140,11 +144,11 @@ // CHECK-NEXT: } // CHECK-NEXT: void bar(int) { // CHECK-NEXT: } -// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(nohost)}) -// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::bar) match(implementation={vendor(score(0):ibm)},device={kind(cpu)}) +// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(unknown)}, device={kind(nohost)}) +// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::bar) match(implementation={vendor(ibm)}, device={kind(cpu)}) // CHECK-NEXT: void foo1() { // CHECK-NEXT: } -// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)}) +// CHECK-NEXT: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(unknown)}, device={kind(cpu, host)}) // CHECK-NEXT: void xxx(); // CHECK-NEXT: } s; struct SpecialFuncs { @@ -157,14 +161,14 @@ void bar(int) {} #pragma omp declare variant(SpecialFuncs::baz) match(xxx = {}) #pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) -#pragma omp declare variant(SpecialFuncs::bar) match(implementation={vendor(ibm)},device={kind(cpu)}) -#pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(unknown)},device={kind(nohost)}) +#pragma omp declare variant(SpecialFuncs::bar) match(implementation = {vendor(ibm)}, device = {kind(cpu)}) +#pragma omp declare variant(SpecialFuncs::baz) match(implementation = {vendor(unknown)}, device = {kind(nohost)}) void foo1() {} -#pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(unknown)},device={kind(cpu, host)}) +#pragma omp declare variant(SpecialFuncs::baz) match(implementation = {vendor(unknown)}, device = {kind(cpu, host)}) void xxx(); } s; -// CHECK: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(score(0):unknown)},device={kind(cpu, host)}) +// CHECK: #pragma omp declare variant(SpecialFuncs::baz) match(implementation={vendor(unknown)}, device={kind(cpu, host)}) // CHECK-NEXT: void SpecialFuncs::xxx() { // CHECK-NEXT: } void SpecialFuncs::xxx() {} @@ -172,12 +176,12 @@ // CHECK: static void static_f_variant() { // CHECK-NEXT: } static void static_f_variant() {} -// CHECK: #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):unknown)}) -// CHECK-NEXT: #pragma omp declare variant(static_f_variant) match(implementation={vendor(score(0):llvm)},device={kind(fpga)}) +// CHECK: #pragma omp declare variant(static_f_variant) match(implementation={vendor(unknown)}) +// CHECK-NEXT: #pragma omp declare variant(static_f_variant) match(implementation={vendor(llvm)}, device={kind(fpga)}) // CHECK-NEXT: static void static_f() { // CHECK-NEXT: } #pragma omp declare variant(static_f_variant) match(xxx = {}) -#pragma omp declare variant(static_f_variant) match(implementation={vendor(llvm)},device={kind(fpga)}) +#pragma omp declare variant(static_f_variant) match(implementation = {vendor(llvm)}, device = {kind(fpga)}) #pragma omp declare variant(static_f_variant) match(implementation={vendor(unknown)}) static void static_f() {} @@ -192,19 +196,19 @@ // CHECK: int fn_linkage_variant(); // CHECK: extern "C" { -// CHECK: #pragma omp declare variant(fn_linkage_variant) match(implementation={vendor(score(0):xxx)},device={kind(cpu, host)}) +// CHECK: #pragma omp declare variant(fn_linkage_variant) match(implementation={vendor(ti)}, device={kind(cpu, host)}) // CHECK: int fn_linkage(); // CHECK: } int fn_linkage_variant(); extern "C" { -#pragma omp declare variant(fn_linkage_variant) match(implementation = {vendor(xxx)},device={kind(cpu,host)}) +#pragma omp declare variant(fn_linkage_variant) match(implementation = {vendor(ti)}, device = {kind(cpu, host)}) int fn_linkage(); } // CHECK: extern "C" int fn_linkage_variant1() -// CHECK: #pragma omp declare variant(fn_linkage_variant1) match(implementation={vendor(score(0):xxx)},device={kind(cpu, host)}) +// CHECK: #pragma omp declare variant(fn_linkage_variant1) match(implementation={vendor(gnu)}, device={kind(cpu, host)}) // CHECK: int fn_linkage1(); extern "C" int fn_linkage_variant1(); -#pragma omp declare variant(fn_linkage_variant1) match(implementation = {vendor(xxx)},device={kind(cpu,host)}) +#pragma omp declare variant(fn_linkage_variant1) match(implementation = {vendor(gnu)}, device = {kind(cpu, host)}) int fn_linkage1(); diff --git a/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp b/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp --- a/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp @@ -71,18 +71,18 @@ #pragma omp declare target #ifdef HOST -#define CORRECT host -#define SUBSET host, cpu +#define SUBSET host +#define CORRECT host, cpu #define WRONG host, nohost #endif // HOST #ifdef CPU -#define CORRECT cpu -#define SUBSET host, cpu +#define SUBSET cpu +#define CORRECT cpu, any #define WRONG cpu, gpu #endif // CPU #ifdef NOHOST -#define CORRECT nohost -#define SUBSET nohost, cpu +#define SUBSET nohost +#define CORRECT nohost, cpu #define WRONG nohost, host #endif // NOHOST diff --git a/clang/test/OpenMP/declare_variant_messages.c b/clang/test/OpenMP/declare_variant_messages.c --- a/clang/test/OpenMP/declare_variant_messages.c +++ b/clang/test/OpenMP/declare_variant_messages.c @@ -2,95 +2,102 @@ // RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp-simd -x c -std=c99 -fms-extensions -Wno-pragma-pack %s -// expected-error@+1 {{expected an OpenMP directive}} -#pragma omp declare + +#pragma omp declare // expected-error {{expected an OpenMP directive}} int foo(void); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} -#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} #pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} #pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) match // expected-error {{expected '(' after 'match'}} -#pragma omp declare variant(foo) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foo) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foo) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} -#pragma omp declare variant(foo) match(xxx=) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foo) match(xxx=yyy) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foo) match(xxx={) // expected-error {{expected '}' or ',' after ')'}} expected-error {{expected '}'}} expected-note {{to match this '{'}} -#pragma omp declare variant(foo) match(xxx={}) -#pragma omp declare variant(foo) match(xxx={vvv, vvv}) -#pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}} -#pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} -#pragma omp declare variant(foo) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foo) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} -#pragma omp declare variant(foo) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} -#pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} -#pragma omp declare variant(foo) match(implementation={vendor(score(foo()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integer constant expression}} -#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} -#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foo) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foo) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} -#pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foo) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foo) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}}} +#pragma omp declare variant(foo) match( // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match() // expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx=) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx=yyy) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected ')'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(xxx={) // expected-error {{expected ')'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx={vvv, vvv}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(implementation={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(implementation={vendor}) // expected-warning {{the context selector 'vendor' in context set 'implementation' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(implementation={vendor()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} +#pragma omp declare variant(foo) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(implementation={vendor(score(foo()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{score expressions in the OpenMP context selector need to be constant; foo() is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-warning {{the context selector 'vendor' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'vendor' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{the context selector 'kind' is not valid for the context set 'implementation'; selector ignored}} expected-note {{the context selector 'kind' can be nested in the context set 'device'; try 'match(device={kind(property)})'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(device={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'device'; selector ignored}} expected-note {{context selector options are: 'kind' 'isa' 'arch'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(device={kind}) // expected-warning {{the context selector 'kind' in context set 'device' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(device={kind(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(device={kind()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} +#pragma omp declare variant(foo) match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foo) match(device={kind(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(device={kind(score(foo()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('foo()'); score ignored}} expected-warning {{'ibm' is not a valid context property for the context selector 'kind' and the context set 'device'; property ignored}} expected-note {{try 'match(implementation={vendor(ibm)})'}} expected-note {{the ignored property spans until here}} +#pragma omp declare variant(foo) match(device={kind(score(5): host), kind(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'kind' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'kind' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foo) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'vendor' is not valid for the context set 'device'; selector ignored}} expected-note {{the context selector 'vendor' can be nested in the context set 'implementation'; try 'match(implementation={vendor(property)})'}} expected-note {{the ignored selector spans until here}} int bar(void); -// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} -#pragma omp declare variant(foo) match(xxx={}) -int a; -// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} -#pragma omp declare variant(foo) match(xxx={}) -#pragma omp threadprivate(a) +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo()) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo() is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score() :llvm)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} +#pragma omp declare variant(foo) match(user = {condition(foo)}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo is not}} +#pragma omp declare variant(foo) match(user = {condition(foo())}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo() is not}} +#pragma omp declare variant(foo) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +int score_and_cond_non_const(); + +#pragma omp declare variant(foo) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +int a; // expected-error {{'#pragma omp declare variant' can only be applied to functions}} + +#pragma omp declare variant(foo) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp threadprivate(a) // expected-error {{'#pragma omp declare variant' can only be applied to functions}} int var; #pragma omp threadprivate(var) -// expected-error@+2 {{expected an OpenMP directive}} expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(foo) match(xxx={}) -#pragma omp declare -// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(foo) match(xxx={}) -#pragma omp declare variant(foo) match(xxx={}) +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare // expected-error {{expected an OpenMP directive}} + + + +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{function declaration is expected after 'declare variant' directive}} #pragma options align=packed int main(); -// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(foo) match(xxx={}) -#pragma omp declare variant(foo) match(xxx={}) + + +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{function declaration is expected after 'declare variant' directive}} #pragma init_seg(compiler) int main(); -// expected-error@+1 {{single declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(foo) match(xxx={}) + +#pragma omp declare variant(foo) match(xxx={}) // expected-error {{single declaration is expected after 'declare variant' directive}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int b, c; int no_proto(); -#pragma omp declare variant(no_proto) match(xxx={}) +#pragma omp declare variant(no_proto) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int no_proto_too(); int proto1(int); -// expected-note@+2 {{previous declaration is here}} -#pragma omp declare variant(proto1) match(xxx={}) -int diff_proto(); -// expected-error@+1 {{conflicting types for 'diff_proto'}} -int diff_proto(double); -#pragma omp declare variant(no_proto) match(xxx={}) +#pragma omp declare variant(proto1) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +int diff_proto(); // expected-note {{previous declaration is here}} + +int diff_proto(double); // expected-error {{conflicting types for 'diff_proto'}} + +#pragma omp declare variant(no_proto) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int diff_proto1(double); int after_use_variant(void); @@ -99,37 +106,37 @@ return after_use(); } -// expected-warning@+1 {{'#pragma omp declare variant' cannot be applied for function after first usage; the original function might be used}} -#pragma omp declare variant(after_use_variant) match(xxx={}) + +#pragma omp declare variant(after_use_variant) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-warning {{'#pragma omp declare variant' cannot be applied for function after first usage; the original function might be used}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int after_use(void); -#pragma omp declare variant(after_use_variant) match(xxx={}) +#pragma omp declare variant(after_use_variant) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int defined(void) { return 0; } int defined1(void) { return 0; } -// expected-warning@+1 {{#pragma omp declare variant' cannot be applied to the function that was defined already; the original function might be used}} -#pragma omp declare variant(after_use_variant) match(xxx={}) + +#pragma omp declare variant(after_use_variant) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-warning {{'#pragma omp declare variant' cannot be applied to the function that was defined already; the original function might be used}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int defined1(void); int diff_cc_variant(void); -// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'int (void) __attribute__((vectorcall))'}} -#pragma omp declare variant(diff_cc_variant) match(xxx={}) + +#pragma omp declare variant(diff_cc_variant) match(xxx={}) // expected-error {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'int (void) __attribute__((vectorcall))'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} __vectorcall int diff_cc(void); int diff_ret_variant(void); -// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'void (void)'}} -#pragma omp declare variant(diff_ret_variant) match(xxx={}) + +#pragma omp declare variant(diff_ret_variant) match(xxx={}) // expected-error {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'void (void)'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} void diff_ret(void); void marked(void); void not_marked(void); -// expected-note@+1 {{marked as 'declare variant' here}} -#pragma omp declare variant(not_marked) match(implementation={vendor(unknown)}, device={kind(cpu)}) + +#pragma omp declare variant(not_marked) match(implementation={vendor(unknown)}, device={kind(cpu)}) // expected-note {{marked as 'declare variant' here}} void marked_variant(void); -// expected-warning@+1 {{variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'}} -#pragma omp declare variant(marked_variant) match(xxx={}) + +#pragma omp declare variant(marked_variant) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-warning {{variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} void marked(void); -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant + +#pragma omp declare variant // expected-error {{function declaration is expected after 'declare variant' directive}} + +#pragma omp declare variant // expected-error {{function declaration is expected after 'declare variant' directive}} diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp --- a/clang/test/OpenMP/declare_variant_messages.cpp +++ b/clang/test/OpenMP/declare_variant_messages.cpp @@ -2,137 +2,180 @@ // RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp-simd -x c++ -std=c++14 -fms-extensions -Wno-pragma-pack -fexceptions -fcxx-exceptions %s -// expected-error@+1 {{expected an OpenMP directive}} -#pragma omp declare + +#pragma omp declare // expected-error {{expected an OpenMP directive}} int foo(); template -T foofoo(); // expected-note 2 {{declared here}} - -#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} -#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} -#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} -#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} -#pragma omp declare variant(foofoo ) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = yyy) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = yyy }) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}' or ',' after ')'}} expected-error {{expected '}'}} expected-note {{to match this '{'}} -#pragma omp declare variant(foofoo ) match(xxx = {}) -#pragma omp declare variant(foofoo ) match(xxx = {vvv, vvv}) -#pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}} -#pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} -#pragma omp declare variant(foofoo ) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foofoo ) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foofoo ) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foofoo ) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(2 gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(foofoo ()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} +T foofoo(); + +#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} +#pragma omp declare variant(foofoo ) match( // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match() // expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foofoo ) match(implementation) // expected-warning {{expected '=' after the context set name "implementation"; '=' assumed}} expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation =) // expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = yyy) // expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{'yyy' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = yyy }) // expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{'yyy' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv, vvv}) // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv} implementation) // expected-error {{expected ')'}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv}) implementation // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={vendor}) // expected-warning {{the context selector 'vendor' in context set 'implementation' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{score expressions in the OpenMP context selector need to be constant; foofoo() is not and will be ignored}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-warning {{the context selector 'vendor' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'vendor' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{the context selector 'kind' is not valid for the context set 'implementation'; selector ignored}} expected-note {{the context selector 'kind' can be nested in the context set 'device'; try 'match(device={kind(property)})'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'device'; selector ignored}} expected-note {{context selector options are: 'kind' 'isa' 'arch'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind}) // expected-warning {{the context selector 'kind' in context set 'device' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} +#pragma omp declare variant(foofoo ) match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foofoo ) match(device={kind(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind(score(2 gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('2'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind(score(foofoo ()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('foofoo()'); score ignored}} expected-warning {{'ibm' is not a valid context property for the context selector 'kind' and the context set 'device'; property ignored}} expected-note {{try 'match(implementation={vendor(ibm)})'}} expected-note {{the ignored property spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(score(5): host), kind(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'kind' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'kind' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(score(5): nohost), vendor(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('5'); score ignored}} expected-warning {{the context selector 'vendor' is not valid for the context set 'device'; selector ignored}} expected-note {{the context selector 'vendor' can be nested in the context set 'implementation'; try 'match(implementation={vendor(property)})'}} expected-note {{the ignored selector spans until here}} int bar(); -#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} -#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} -#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} -#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} -#pragma omp declare variant(foofoo ) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}' or ',' after ')'}} expected-error {{expected '}'}} expected-note {{to match this '{'}} -#pragma omp declare variant(foofoo ) match(xxx = {}) -#pragma omp declare variant(foofoo ) match(xxx = {vvv, vvv}) -#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) -#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) -#pragma omp declare variant(foofoo ) match(user = {condition()}) -#pragma omp declare variant(foofoo ) match(user = {condition()}) -#pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}} -#pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foofoo ) match(device={xxx}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} -#pragma omp declare variant(foofoo ) match(device={kind}) // expected-error {{expected '(' after 'kind'}} expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-error {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(device={kind(}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} expected-error 2 {{expected ')'}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(device={kind()}) // expected-error {{expected 'host', 'nohost', 'cpu', 'gpu', or 'fpga' in 'kind' context selector of 'device' selector set of 'omp declare variant' directive}} -#pragma omp declare variant(foofoo ) match(device={kind(score cpu)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score( ibm)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(C gpu)}) // expected-error 2 {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(foofoo ()) ibm)}) // expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(C+5): host), kind(llvm)}) // expected-error {{context trait selector 'kind' is used already in the same 'device' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'kind' used here}} expected-error {{expected ')' or ',' after 'score'}} expected-note {{to match this '('}} expected-error {{expected ')'}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} expected-error {{unknown 'llvm' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} -#pragma omp declare variant(foofoo ) match(device={kind(score(C+5): nohost), vendor(llvm)}) // expected-warning {{unknown context selector in 'device' context selector set of 'omp declare variant' directive, ignored}} expected-error {{expected ')' or ',' after 'score'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{unknown 'score' device kind trait in the 'device' context selector set, expected one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'}} +#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} +#pragma omp declare variant(foofoo ) match( // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match() // expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foofoo ) match(implementation) // expected-warning {{expected '=' after the context set name "implementation"; '=' assumed}} expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation =) // expected-warning {{expected '{' after the '=' that follows the context set name "implementation"; '{' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{expected '}' after the context selectors for the context set "implementation"; '}' assumed}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv, vvv}) // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) // expected-warning {{'score' is not a valid context selector for the context set 'user'; selector ignored}} expected-note {{context selector options are: 'condition'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) // expected-warning {{'score' is not a valid context selector for the context set 'user'; selector ignored}} expected-note {{context selector options are: 'condition'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv} implementation) // expected-error {{expected ')'}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv}) xxx // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm), vendor(llvm)}) // expected-warning {{the context selector 'vendor' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'vendor' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), kind(cpu)}) // expected-warning {{the context selector 'kind' is not valid for the context set 'implementation'; selector ignored}} expected-note {{the context selector 'kind' can be nested in the context set 'device'; try 'match(device={kind(property)})'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'device'; selector ignored}} expected-note {{context selector options are: 'kind' 'isa' 'arch'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind}) // expected-warning {{the context selector 'kind' in context set 'device' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind()}) // expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} +#pragma omp declare variant(foofoo ) match(device={kind(score cpu)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} +#pragma omp declare variant(foofoo ) match(device={kind(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind(score(C gpu)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('C'); score ignored}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'host' 'nohost' 'cpu' 'gpu' 'fpga' 'any'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(device={kind(score(foofoo ()) ibm)}) // expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('foofoo()'); score ignored}} expected-warning {{'ibm' is not a valid context property for the context selector 'kind' and the context set 'device'; property ignored}} expected-note {{try 'match(implementation={vendor(ibm)})'}} expected-note {{the ignored property spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(score(C+5): host), kind(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('C + 5'); score ignored}} expected-warning {{the context selector 'kind' was used already in the same 'omp declare variant' directive; selector ignored}} expected-note {{the previous context selector 'kind' used here}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(device={kind(score(C+5): nohost), vendor(llvm)}) // expected-warning {{the context selector 'kind' in the context set 'device' cannot have a score ('C + 5'); score ignored}} expected-warning {{the context selector 'vendor' is not valid for the context set 'device'; selector ignored}} expected-note {{the context selector 'vendor' can be nested in the context set 'implementation'; try 'match(implementation={vendor(property)})'}} expected-note {{the ignored selector spans until here}} template T barbar(); -// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} -#pragma omp declare variant(barbar ) match(xxx = {}) -int a; -// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} -#pragma omp declare variant(barbar ) match(xxx = {}) -#pragma omp threadprivate(a) +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo()) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo() is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score() :llvm)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} +#pragma omp declare variant(foo) match(user = {condition(foo)}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo is not}} +#pragma omp declare variant(foo) match(user = {condition(foo())}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo() is not}} +#pragma omp declare variant(foo) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +int score_and_cond_non_const(); + +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo) :llvm)}) +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo()) :llvm)}) +#pragma omp declare variant(foo) match(implementation = {vendor(score() :llvm)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} +#pragma omp declare variant(foo) match(user = {condition(foo)}) +#pragma omp declare variant(foo) match(user = {condition(foo())}) +#pragma omp declare variant(foo) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +template +int score_and_cond_non_const_no_inst(); + +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score(foo()) :llvm)}) // expected-warning {{score expressions in the OpenMP context selector need to be constant; foo() is not and will be ignored}} +#pragma omp declare variant(foo) match(implementation = {vendor(score() :llvm)}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} +#pragma omp declare variant(foo) match(user = {condition(foo)}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo is not}} +#pragma omp declare variant(foo) match(user = {condition(foo())}) // expected-error {{the user condition in the OpenMP context selector needs to be constant; foo() is not}} +#pragma omp declare variant(foo) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} +template +int score_and_cond_non_const_inst(); + +constexpr int constexpr_fn(int i) { return 7 * i; } +#pragma omp declare variant(foo) match(implementation = {vendor(score(constexpr_fn(3)) : llvm)}) +#pragma omp declare variant(foo) match(user = {condition(constexpr_fn(1))}) +int score_and_cond_const(); + +#pragma omp declare variant(foo) match(implementation = {vendor(score(constexpr_fn(3)) : llvm)}) +#pragma omp declare variant(foo) match(implementation = {vendor(score(constexpr_fn(C)) : llvm)}) +#pragma omp declare variant(foo) match(user = {condition(constexpr_fn(1))}) +#pragma omp declare variant(foo) match(user = {condition(constexpr_fn(C))}) +template +int score_and_cond_const_inst(); + +void score_and_cond_inst() { + score_and_cond_non_const(); + score_and_cond_non_const_inst<8>(); // expected-note {{in instantiation of function template specialization 'score_and_cond_non_const_inst<8>' requested here}} + score_and_cond_const_inst<9>(); +} + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +int a; // expected-error {{'#pragma omp declare variant' can only be applied to functions}} + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp threadprivate(a) // expected-error {{'#pragma omp declare variant' can only be applied to functions}} int var; #pragma omp threadprivate(var) -// expected-error@+2 {{expected an OpenMP directive}} expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(barbar ) match(xxx = {}) -#pragma omp declare -// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(barbar ) match(xxx = {}) -#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare // expected-error {{expected an OpenMP directive}} + + + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) // expected-error {{function declaration is expected after 'declare variant' directive}} #pragma options align = packed int main(); -// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(barbar ) match(xxx = {}) -#pragma omp declare variant(barbar ) match(xxx = {}) + + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-error {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) // expected-error {{function declaration is expected after 'declare variant' directive}} #pragma init_seg(compiler) int main(); -// expected-error@+1 {{single declaration is expected after 'declare variant' directive}} -#pragma omp declare variant(barbar ) match(xxx = {}) + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-error {{single declaration is expected after 'declare variant' directive}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int b, c; -// expected-error@+1 {{'C' does not refer to a value}} -#pragma omp declare variant(C) match(xxx = {}) -// expected-note@+1 {{declared here}} -template + +#pragma omp declare variant(C) match(implementation = {}) // expected-error {{'C' does not refer to a value}} + +template // expected-note {{declared here}} void h(C *hp, C *hp2, C *hq, C *lin) { b = 0; } -// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'void (int *, int *, int *, int *)'}} -#pragma omp declare variant(barbar ) match(xxx = {}) + +#pragma omp declare variant(barbar ) match(implementation = {}) // expected-error {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'void (int *, int *, int *, int *)'}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} template <> void h(int *hp, int *hp2, int *hq, int *lin); @@ -142,113 +185,113 @@ return after_use(); } -// expected-warning@+1 {{'#pragma omp declare variant' cannot be applied for function after first usage; the original function might be used}} -#pragma omp declare variant(after_use_variant) match(xxx = {}) + +#pragma omp declare variant(after_use_variant) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{'#pragma omp declare variant' cannot be applied for function after first usage; the original function might be used}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int after_use(void); int fn(); int fn(int); -#pragma omp declare variant(fn) match(xxx = {}) +#pragma omp declare variant(fn) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int overload(void); int fn1(); int fn1(int); -// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'int (float)'}} -#pragma omp declare variant(fn1) match(xxx = {}) + +#pragma omp declare variant(fn1) match(implementation = {}) // expected-error {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'int (float)'}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int overload1(float); int fn_constexpr_variant(); -// expected-error@+2 {{'#pragma omp declare variant' does not support constexpr functions}} -#pragma omp declare variant(fn_constexpr_variant) match(xxx = {}) -constexpr int fn_constexpr(); + +#pragma omp declare variant(fn_constexpr_variant) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +constexpr int fn_constexpr(); // expected-error {{'#pragma omp declare variant' does not support constexpr functions}} constexpr int fn_constexpr_variant1(); -// expected-error@+1 {{'#pragma omp declare variant' does not support constexpr functions}} -#pragma omp declare variant(fn_constexpr_variant1) match(xxx = {}) + +#pragma omp declare variant(fn_constexpr_variant1) match(implementation = {}) // expected-error {{'#pragma omp declare variant' does not support constexpr functions}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int fn_constexpr1(); int fn_sc_variant(); -// expected-error@+1 {{function with '#pragma omp declare variant' has a different storage class}} -#pragma omp declare variant(fn_sc_variant) match(xxx = {}) + +#pragma omp declare variant(fn_sc_variant) match(xxx = {}) // expected-error {{function with '#pragma omp declare variant' has a different storage class}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} static int fn_sc(); static int fn_sc_variant1(); -// expected-error@+1 {{function with '#pragma omp declare variant' has a different storage class}} -#pragma omp declare variant(fn_sc_variant1) match(xxx = {}) + +#pragma omp declare variant(fn_sc_variant1) match(implementation = {}) // expected-error {{function with '#pragma omp declare variant' has a different storage class}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int fn_sc1(); int fn_inline_variant(); -// expected-error@+1 {{function with '#pragma omp declare variant' has a different inline specification}} -#pragma omp declare variant(fn_inline_variant) match(xxx = {}) + +#pragma omp declare variant(fn_inline_variant) match(xxx = {}) // expected-error {{function with '#pragma omp declare variant' has a different inline specification}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} inline int fn_inline(); inline int fn_inline_variant1(); -// expected-error@+1 {{function with '#pragma omp declare variant' has a different inline specification}} -#pragma omp declare variant(fn_inline_variant1) match(xxx = {}) + +#pragma omp declare variant(fn_inline_variant1) match(implementation = {}) // expected-error {{function with '#pragma omp declare variant' has a different inline specification}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} int fn_inline1(); auto fn_deduced_variant() { return 0; } -#pragma omp declare variant(fn_deduced_variant) match(xxx = {}) +#pragma omp declare variant(fn_deduced_variant) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} int fn_deduced(); int fn_deduced_variant1(); -#pragma omp declare variant(fn_deduced_variant1) match(xxx = {}) +#pragma omp declare variant(fn_deduced_variant1) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} auto fn_deduced1() { return 0; } auto fn_deduced3() { return 0; } -// expected-warning@+1 {{'#pragma omp declare variant' cannot be applied to the function that was defined already; the original function might be used}} -#pragma omp declare variant(fn_deduced_variant1) match(xxx = {}) + +#pragma omp declare variant(fn_deduced_variant1) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-warning {{'#pragma omp declare variant' cannot be applied to the function that was defined already; the original function might be used}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} auto fn_deduced3(); auto fn_deduced_variant2() { return 0; } -// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int ()' is incompatible with type 'float ()'}} -#pragma omp declare variant(fn_deduced_variant2) match(xxx = {}) + +#pragma omp declare variant(fn_deduced_variant2) match(xxx = {}) // expected-error {{variant in '#pragma omp declare variant' with type 'int ()' is incompatible with type 'float ()'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} float fn_deduced2(); -// expected-error@+1 {{exception specification in declaration does not match previous declaration}} -int fn_except_variant() noexcept(true); -// expected-note@+2 {{previous declaration is here}} -#pragma omp declare variant(fn_except_variant) match(xxx = {}) -int fn_except() noexcept(false); -// expected-error@+1 {{exception specification in declaration does not match previous declaration}} -int fn_except_variant1() noexcept(false); -// expected-note@+2 {{previous declaration is here}} -#pragma omp declare variant(fn_except_variant1) match(xxx = {}) -int fn_except1() noexcept(true); +int fn_except_variant() noexcept(true); // expected-error {{exception specification in declaration does not match previous declaration}} + +#pragma omp declare variant(fn_except_variant) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +int fn_except() noexcept(false); // expected-note {{previous declaration is here}} + + +int fn_except_variant1() noexcept(false); // expected-error {{exception specification in declaration does not match previous declaration}} + +#pragma omp declare variant(fn_except_variant1) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +int fn_except1() noexcept(true); // expected-note {{previous declaration is here}} struct SpecialFuncs { void vd(); - // expected-error@+2 {{'#pragma omp declare variant' does not support constructors}} -#pragma omp declare variant(SpecialFuncs::vd) match(xxx = {}) - SpecialFuncs(); - // expected-error@+2 {{'#pragma omp declare variant' does not support destructors}} -#pragma omp declare variant(SpecialFuncs::vd) match(xxx = {}) - ~SpecialFuncs(); + +#pragma omp declare variant(SpecialFuncs::vd) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} + SpecialFuncs(); // expected-error {{'#pragma omp declare variant' does not support constructors}} + +#pragma omp declare variant(SpecialFuncs::vd) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} + ~SpecialFuncs(); // expected-error {{'#pragma omp declare variant' does not support destructors}} void baz(); void bar(); void bar(int); -#pragma omp declare variant(SpecialFuncs::baz) match(xxx = {}) -#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) -// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (*)()' is incompatible with type 'void (SpecialFuncs::*)()'}} -#pragma omp declare variant(fn_sc_variant1) match(xxx = {}) +#pragma omp declare variant(SpecialFuncs::baz) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} + +#pragma omp declare variant(fn_sc_variant1) match(implementation = {}) // expected-error {{variant in '#pragma omp declare variant' with type 'int (*)()' is incompatible with type 'void (SpecialFuncs::*)()'}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} void foo1(); SpecialFuncs& foo(const SpecialFuncs&); SpecialFuncs& bar(SpecialFuncs&&); - // expected-error@+2 {{'#pragma omp declare variant' does not support defaulted functions}} -#pragma omp declare variant(SpecialFuncs::foo) match(xxx = {}) - SpecialFuncs& operator=(const SpecialFuncs&) = default; - // expected-error@+2 {{'#pragma omp declare variant' does not support deleted functions}} -#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) - SpecialFuncs& operator=(SpecialFuncs&&) = delete; + +#pragma omp declare variant(SpecialFuncs::foo) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} + SpecialFuncs& operator=(const SpecialFuncs&) = default; // expected-error {{'#pragma omp declare variant' does not support defaulted functions}} + +#pragma omp declare variant(SpecialFuncs::bar) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} + SpecialFuncs& operator=(SpecialFuncs&&) = delete; // expected-error {{'#pragma omp declare variant' does not support deleted functions}} }; namespace N { -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant + +#pragma omp declare variant // expected-error {{function declaration is expected after 'declare variant' directive}} } // namespace N -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant -// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} -#pragma omp declare variant + +#pragma omp declare variant // expected-error {{function declaration is expected after 'declare variant' directive}} + +#pragma omp declare variant // expected-error {{function declaration is expected after 'declare variant' directive}} diff --git a/clang/test/OpenMP/declare_variant_mixed_codegen.cpp b/clang/test/OpenMP/declare_variant_mixed_codegen.cpp --- a/clang/test/OpenMP/declare_variant_mixed_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_mixed_codegen.cpp @@ -49,7 +49,7 @@ static int stat_unused_no_emit() { return 1; } static int stat_unused_(); #pragma omp declare variant(stat_unused_) match(implementation = {vendor(llvm)}, device={kind(cpu)}) -#pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(xxx)}, device={kind(gpu)}) +#pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(unknown)}, device = {kind(gpu)}) static int stat_unused() { return 1; } static int stat_used_(); @@ -103,16 +103,16 @@ int prio() { return 81; } int prio1() { return 82; } -#pragma omp declare variant(prio) match(implementation = {vendor(score(2): llvm)}, device={kind(cpu,host)}) -#pragma omp declare variant(prio1) match(implementation = {vendor(score(1): llvm)}, device={kind(cpu)}) +#pragma omp declare variant(prio1) match(implementation = {vendor(score(2): llvm)}, device={kind(cpu,host)}) +#pragma omp declare variant(prio) match(implementation = {vendor(score(1): llvm)}, device={kind(cpu)}) int prio_() { return 1; } static int prio2() { return 83; } static int prio3() { return 84; } static int prio4() { return 84; } -#pragma omp declare variant(prio4) match(implementation = {vendor(score(8): llvm)},device={kind(cpu,host)}) -#pragma omp declare variant(prio2) match(implementation = {vendor(score(5): llvm)}) +#pragma omp declare variant(prio4) match(implementation = {vendor(score(5): llvm)}) +#pragma omp declare variant(prio2) match(implementation = {vendor(score(8): llvm)}, device={kind(cpu,host)}) #pragma omp declare variant(prio3) match(implementation = {vendor(score(7): llvm)}, device={kind(cpu)}) static int prio1_() { return 1; } @@ -137,7 +137,7 @@ #pragma omp declare variant(fn_variant2) match(implementation = {vendor(llvm)}, device={kind(fpga)}) int fn2() { return 87; } -#pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(xxx)}, device={kind(gpu)}) +#pragma omp declare variant(stat_unused_no_emit) match(implementation = {vendor(unknown)}, device = {kind(gpu)}) template static T stat_unused_T() { return 88; } diff --git a/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp b/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp --- a/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp +++ b/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp @@ -43,13 +43,13 @@ #define HEADER #ifdef GPU -#define CORRECT gpu -#define SUBSET nohost, gpu +#define SUBSET gpu +#define CORRECT nohost, gpu #define WRONG cpu, gpu #endif // GPU #ifdef NOHOST -#define CORRECT nohost -#define SUBSET nohost, gpu +#define SUBSET nohost +#define CORRECT nohost, gpu #define WRONG nohost, host #endif // NOHOST diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -107,6 +107,7 @@ .Case("IdentifierInfo *", "Record.readIdentifier()") .Case("StringRef", "Record.readString()") .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())") + .Case("OMPTraitInfo *", "Record.readOMPTraitInfo()") .Default("Record.readInt()"); } @@ -130,6 +131,8 @@ .Case("StringRef", "AddString(" + std::string(name) + ");\n") .Case("ParamIdx", "push_back(" + std::string(name) + ".serialize());\n") + .Case("OMPTraitInfo *", + "writeOMPTraitInfo(" + std::string(name) + ");\n") .Default("push_back(" + std::string(name) + ");\n"); } @@ -338,7 +341,7 @@ void writeDump(raw_ostream &OS) const override { if (type == "FunctionDecl *" || type == "NamedDecl *") { OS << " OS << \" \";\n"; - OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; + OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; } else if (type == "IdentifierInfo *") { // Some non-optional (comma required) identifier arguments can be the // empty string but are then recorded as a nullptr. @@ -360,6 +363,8 @@ OS << " if (SA->get" << getUpperName() << "().isValid())\n "; OS << " OS << \" \" << SA->get" << getUpperName() << "().getSourceIndex();\n"; + } else if (type == "OMPTraitInfo *") { + OS << " OS << \" \" << *SA->get" << getUpperName() << "();\n"; } else { llvm_unreachable("Unknown SimpleArgument type!"); } @@ -500,7 +505,7 @@ OS << " if (is" << getLowerName() << "Expr)\n"; OS << " return " << getLowerName() << "Expr && (" << getLowerName() << "Expr->isValueDependent() || " << getLowerName() - << "Expr->isTypeDependent());\n"; + << "Expr->isTypeDependent());\n"; OS << " else\n"; OS << " return " << getLowerName() << "Type->getType()->isDependentType();\n"; @@ -525,11 +530,11 @@ void writeASTVisitorTraversal(raw_ostream &OS) const override { StringRef Name = getUpperName(); OS << " if (A->is" << Name << "Expr()) {\n" - << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n" - << " return false;\n" + << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n" + << " return false;\n" << " } else if (auto *TSI = A->get" << Name << "Type()) {\n" << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" - << " return false;\n" + << " return false;\n" << " }\n"; } @@ -658,7 +663,7 @@ std::string IteratorType = getLowerName().str() + "_iterator"; std::string BeginFn = getLowerName().str() + "_begin()"; std::string EndFn = getLowerName().str() + "_end()"; - + OS << " typedef " << Type << "* " << IteratorType << ";\n"; OS << " " << IteratorType << " " << BeginFn << " const {" << " return " << ArgName << "; }\n"; @@ -915,14 +920,14 @@ for (size_t I = 0; I < enums.size(); ++I) { if (Uniques.insert(enums[I]).second) OS << " case " << getAttrName() << "Attr::" << enums[I] - << ": return \"" << values[I] << "\";\n"; + << ": return \"" << values[I] << "\";\n"; } OS << " }\n" << " llvm_unreachable(\"No enumerator with that value\");\n" << " }\n"; } }; - + class VariadicEnumArgument: public VariadicArgument { std::string type, QualifiedTypeName; std::vector values, enums, uniques; @@ -945,13 +950,13 @@ enums(Arg.getValueAsListOfStrings("Enums")), uniques(uniqueEnumsInOrder(enums)) { QualifiedTypeName = getAttrName().str() + "Attr::" + type; - + // FIXME: Emit a proper error assert(!uniques.empty()); } bool isVariadicEnumArg() const override { return true; } - + void writeDeclarations(raw_ostream &OS) const override { auto i = uniques.cbegin(), e = uniques.cend(); // The last one needs to not have a comma. @@ -964,7 +969,7 @@ OS << " " << *e << "\n"; OS << " };\n"; OS << "private:\n"; - + VariadicArgument::writeDeclarations(OS); } @@ -1041,7 +1046,7 @@ OS << " VersionTuple get" << getUpperName() << "() const {\n"; OS << " return " << getLowerName() << ";\n"; OS << " }\n"; - OS << " void set" << getUpperName() + OS << " void set" << getUpperName() << "(ASTContext &C, VersionTuple V) {\n"; OS << " " << getLowerName() << " = V;\n"; OS << " }"; @@ -1308,6 +1313,8 @@ Ptr = std::make_unique(Arg, Attr); else if (ArgName == "VersionArgument") Ptr = std::make_unique(Arg, Attr); + else if (ArgName == "OMPTraitInfoArgument") + Ptr = std::make_unique(Arg, Attr, "OMPTraitInfo *"); if (!Ptr) { // Search in reverse order so that the most-derived type is handled first. @@ -2252,10 +2259,10 @@ // When attribute documentation can be generated as part of the build // itself, this code can be removed. (void)R.getValueAsListOfDefs("Documentation"); - + if (!R.getValueAsBit("ASTNode")) continue; - + ArrayRef> Supers = R.getSuperClasses(); assert(!Supers.empty() && "Forgot to specify a superclass for the attr"); std::string SuperName; @@ -2437,7 +2444,7 @@ } OS << " {\n"; - + for (auto const &ai : Args) { if (!shouldEmitArg(ai)) continue; ai->writeCtorBody(OS); @@ -2452,7 +2459,7 @@ // Emit a constructor that takes all the non-fake arguments. if (HasFakeArg) emitCtor(true, false); - + // Emit a constructor that takes all the non-fake, non-optional arguments. if (HasOptArg) emitCtor(false, false); @@ -2461,7 +2468,7 @@ OS << " void printPretty(raw_ostream &OS,\n" << " const PrintingPolicy &Policy) const;\n"; OS << " const char *getSpelling() const;\n"; - + if (!ElideSpelling) { assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list"); OS << " Spelling getSemanticSpelling() const {\n"; @@ -2506,7 +2513,7 @@ for (auto *Attr : Attrs) { Record &R = *Attr; - + if (!R.getValueAsBit("ASTNode")) continue; @@ -2971,7 +2978,7 @@ // them. If the attribute has no scope, the version information must not // have the default value (1), as that's incorrect. Instead, the unscoped // attribute version information should be taken from the SD-6 standing - // document, which can be found at: + // document, which can be found at: // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations int Version = 1; @@ -3263,7 +3270,7 @@ OS << "#ifndef PARSED_ATTR\n"; OS << "#define PARSED_ATTR(NAME) NAME\n"; OS << "#endif\n\n"; - + ParsedAttrMap Names = getParsedAttrList(Records); for (const auto &I : Names) { OS << "PARSED_ATTR(" << I.first << ")\n"; diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h @@ -49,6 +49,9 @@ /// Parse \p Str and return the trait set it matches or TraitSet::invalid. TraitSet getOpenMPContextTraitSetKind(StringRef Str); +/// Return the trait set for which \p Selector is a selector. +TraitSet getOpenMPContextTraitSetForSelector(TraitSelector Selector); + /// Return the trait set for which \p Property is a property. TraitSet getOpenMPContextTraitSetForProperty(TraitProperty Property); @@ -67,9 +70,7 @@ /// Parse \p Str and return the trait set it matches or /// TraitProperty::invalid. -TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set, - TraitSelector Selector, - StringRef Str); +TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set, StringRef Str); /// Return the trait property for a singleton selector \p Selector. TraitProperty getOpenMPContextTraitPropertyForSelector(TraitSelector Selector); @@ -80,6 +81,16 @@ /// Return a textual representation of the trait property \p Kind with selector /// and set name included. StringRef getOpenMPContextTraitPropertyFullName(TraitProperty Kind); + +/// Return a string listing all trait sets. +std::string listOpenMPContextTraitSets(); + +/// Return a string listing all trait selectors for \p Set. +std::string listOpenMPContextTraitSelectors(TraitSet Set); + +/// Return a string listing all trait properties for \p Set and \p Selector. +std::string listOpenMPContextTraitProperties(TraitSet Set, + TraitSelector Selector); ///} /// Return true if \p Selector can be nested in \p Set. Also sets diff --git a/llvm/lib/Frontend/OpenMP/OMPContext.cpp b/llvm/lib/Frontend/OpenMP/OMPContext.cpp --- a/llvm/lib/Frontend/OpenMP/OMPContext.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp @@ -286,6 +286,16 @@ #include "llvm/Frontend/OpenMP/OMPKinds.def" .Default(TraitSet::invalid); } + +TraitSet +llvm::omp::getOpenMPContextTraitSetForSelector(TraitSelector Selector) { + switch (Selector) { +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp) \ + case TraitSelector::Enum: \ + return TraitSet::TraitSetEnum; +#include "llvm/Frontend/OpenMP/OMPKinds.def" + } +} TraitSet llvm::omp::getOpenMPContextTraitSetForProperty(TraitProperty Property) { switch (Property) { @@ -333,11 +343,10 @@ llvm_unreachable("Unknown trait selector!"); } -TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind( - TraitSet Set, TraitSelector Selector, StringRef S) { +TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind(TraitSet Set, + StringRef S) { #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ - if (Set == TraitSet::TraitSetEnum && \ - Selector == TraitSelector::TraitSelectorEnum && Str == S) \ + if (Set == TraitSet::TraitSetEnum && Str == S) \ return TraitProperty::Enum; #include "llvm/Frontend/OpenMP/OMPKinds.def" return TraitProperty::invalid; @@ -398,3 +407,36 @@ } llvm_unreachable("Unknown trait property!"); } + +std::string llvm::omp::listOpenMPContextTraitSets() { + std::string S; +#define OMP_TRAIT_SET(Enum, Str) \ + if (Str != "invalid") \ + S.append("'").append(Str).append("'").append(" "); +#include "llvm/Frontend/OpenMP/OMPKinds.def" + S.pop_back(); + return S; +} + +std::string llvm::omp::listOpenMPContextTraitSelectors(TraitSet Set) { + std::string S; +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp) \ + if (TraitSet::TraitSetEnum == Set && Str != "Invalid") \ + S.append("'").append(Str).append("'").append(" "); +#include "llvm/Frontend/OpenMP/OMPKinds.def" + S.pop_back(); + return S; +} + +std::string +llvm::omp::listOpenMPContextTraitProperties(TraitSet Set, + TraitSelector Selector) { + std::string S; +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ + if (TraitSet::TraitSetEnum == Set && \ + TraitSelector::TraitSelectorEnum == Selector && Str != "invalid") \ + S.append("'").append(Str).append("'").append(" "); +#include "llvm/Frontend/OpenMP/OMPKinds.def" + S.pop_back(); + return S; +} diff --git a/llvm/unittests/Frontend/OpenMPContextTest.cpp b/llvm/unittests/Frontend/OpenMPContextTest.cpp --- a/llvm/unittests/Frontend/OpenMPContextTest.cpp +++ b/llvm/unittests/Frontend/OpenMPContextTest.cpp @@ -38,12 +38,11 @@ #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ EXPECT_EQ(TraitProperty::Enum, \ getOpenMPContextTraitPropertyKind( \ - TraitSet::TraitSetEnum, TraitSelector::TraitSelectorEnum, \ + TraitSet::TraitSetEnum, \ getOpenMPContextTraitPropertyName(TraitProperty::Enum))); \ - EXPECT_EQ( \ - Str, \ - getOpenMPContextTraitPropertyName(getOpenMPContextTraitPropertyKind( \ - TraitSet::TraitSetEnum, TraitSelector::TraitSelectorEnum, Str))); \ + EXPECT_EQ(Str, getOpenMPContextTraitPropertyName( \ + getOpenMPContextTraitPropertyKind(TraitSet::TraitSetEnum, \ + Str))); \ EXPECT_EQ(TraitSet::TraitSetEnum, \ getOpenMPContextTraitSetForProperty(TraitProperty::Enum)); \ EXPECT_EQ(TraitSelector::TraitSelectorEnum, \