From 1228d42ddab832a236563515da5e6de3312fd93c Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Thu, 19 Dec 2019 20:42:12 -0600 Subject: [PATCH] [OpenMP][Part 2] Use reusable OpenMP context/traits handling This patch implements an almost complete handling of OpenMP contexts/traits such that we can reuse most of the logic in Flang through the OMPContext.{h,cpp} in llvm/Frontend/OpenMP. All but construct SIMD specifiers, e.g., inbranch, and the device ISA selector are define in `llvm/lib/Frontend/OpenMP/OMPKinds.def`. From these definitions we generate the enum classes `TraitSet`, `TraitSelector`, and `TraitProperty` as well as conversion and helper functions in `llvm/lib/Frontend/OpenMP/OMPContext.{h,cpp}`. The above enum classes are used in the parser, sema, and the AST attribute. The latter is not a collection of multiple primitive variant arguments that contain encodings via numbers and strings but instead a tree that mirrors the `match` clause (see `struct OpenMPTraitInfo`). The changes to the parser make it more forgiving when wrong syntax is read and they also resulted in more specialized diagnostics. The tests are updated and the core issues are detected as before. Here and elsewhere this patch tries to be generic, thus we do not distinguish what selector set, selector, or property is parsed except if they do behave exceptionally, as for example `user={condition(EXPR)}` does. The sema logic changed in two ways: First, the OMPDeclareVariantAttr representation changed, as mentioned above, and the sema was adjusted to work with the new `OpenMPTraitInfo`. Second, the matching and scoring logic moved into `OMPContext.{h,cpp}`. It is implemented on a flat representation of the `match` clause that is not tied to clang. `OpenMPTraitInfo` provides a method to generate this flat structure (see `struct VariantMatchInfo`) by computing integer score values and boolean user conditions from the `clang::Expr` we keep for them. The OpenMP context is now an explicit object (see `struct OMPContext`). This is in anticipation of construct traits that need to be tracked. The OpenMP context, as well as the `VariantMatchInfo`, are basically made up of a set of active or respectively required traits, e.g., 'host', and an ordered container of constructs which allows duplication. Matching and scoring is kept as generic as possible to allow easy extension in the future. --- Test changes: The messages checked in `OpenMP/declare_variant_messages.{c,cpp}` have been auto generated to match the new warnings and notes of the parser. The "subset" checks were reversed causing the wrong version to be picked. The tests have been adjusted to correct this. We do not print scores if the user did not provide one. We print spaces to make lists in the `match` clause more legible. Reviewers: kiranchandramohan, ABataev, RaviNarayanaswamy, gtbercea, grokos, sdmitriev, JonChesterfield, hfinkel, fghanim Subscribers: merge_guards_bot, rampitec, mgorny, hiraditya, aheejin, fedor.sergeev, simoncook, bollu, guansong, dexonsmith, jfb, s.egerton, llvm-commits, cfe-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D71830 --- clang/include/clang/AST/Attr.h | 1 + clang/include/clang/AST/OpenMPClause.h | 48 ++ clang/include/clang/Basic/Attr.td | 95 +-- clang/include/clang/Basic/DiagnosticParseKinds.td | 86 ++- clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 + clang/include/clang/Basic/OpenMPKinds.def | 16 - clang/include/clang/Basic/OpenMPKinds.h | 39 -- clang/include/clang/Parse/Parser.h | 42 +- clang/include/clang/Sema/Sema.h | 15 +- .../include/clang/Serialization/ASTRecordReader.h | 4 + .../include/clang/Serialization/ASTRecordWriter.h | 3 + clang/lib/AST/OpenMPClause.cpp | 104 +++ clang/lib/Basic/OpenMPKinds.cpp | 43 -- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 257 +------- clang/lib/Parse/ParseOpenMP.cpp | 712 ++++++++++++++------- clang/lib/Sema/SemaOpenMP.cpp | 115 ++-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 71 +- clang/lib/Serialization/ASTReader.cpp | 19 + clang/lib/Serialization/ASTReaderDecl.cpp | 2 + clang/lib/Serialization/ASTWriter.cpp | 16 + clang/test/OpenMP/declare_variant_ast_print.c | 10 +- clang/test/OpenMP/declare_variant_ast_print.cpp | 102 +-- .../OpenMP/declare_variant_device_kind_codegen.cpp | 12 +- clang/test/OpenMP/declare_variant_messages.c | 161 ++--- clang/test/OpenMP/declare_variant_messages.cpp | 367 ++++++----- .../test/OpenMP/declare_variant_mixed_codegen.cpp | 12 +- .../nvptx_declare_variant_device_kind_codegen.cpp | 8 +- clang/utils/TableGen/ClangAttrEmitter.cpp | 47 +- llvm/include/llvm/Frontend/OpenMP/OMPContext.h | 17 +- llvm/lib/Frontend/OpenMP/OMPContext.cpp | 50 +- llvm/unittests/Frontend/OpenMPContextTest.cpp | 9 +- 31 files changed, 1348 insertions(+), 1141 deletions(-) diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index bbaa463..b2b53e8 100644 --- 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 index f103530..ec47010 100644 --- 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 @@ public: #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 index 7d01181..be68a9b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -180,6 +180,27 @@ class FunctionArgument : Argument : 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 @@ def OMPDeclareVariant : InheritableAttr { 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 @@ def OMPDeclareVariant : InheritableAttr { 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 index 8661330..3b37a8e 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1258,30 +1258,68 @@ def err_omp_mapper_expected_declarator : Error< "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 index 37f0acf0..afaafb1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9910,6 +9910,12 @@ def warn_omp_declare_target_after_first_use : Warning< 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.def b/clang/include/clang/Basic/OpenMPKinds.def index dd840b2..3ab69a1 100644 --- 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 @@ OPENMP_FLUSH_CLAUSE(release) #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/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 86c4ad1..2a08ef6 100644 --- 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/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d1e9784..621e179 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1701,6 +1701,8 @@ public: unsigned &NumLineToksConsumed, bool IsUnevaluated); + ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); + private: ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); @@ -1793,8 +1795,6 @@ private: SourceLocation LParenLoc, SourceLocation RParenLoc); - ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); - ExprResult ParseGenericSelectionExpression(); ExprResult ParseObjCBoolLiteral(); @@ -2920,11 +2920,39 @@ private: 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 index a93addc..7912681 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9716,9 +9716,6 @@ private: 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 @@ public: /// 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 @@ public: /// 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 index f6dc8b2..3622960 100644 --- 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 @@ public: 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 index 43af686..2a35c69 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -266,6 +266,9 @@ public: 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 index 6eac982..1cd1c82 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1722,3 +1722,107 @@ void OMPClausePrinter::VisitOMPOrderClause(OMPOrderClause *Node) { 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 index 70817f8..ff0f287 100644 --- 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 index 7440434..60b8149 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11065,257 +11065,34 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, 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 index fbabe92..e1bcbdb 100644 --- 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 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, 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 @@ static ExprResult parseContextScore(Parser &P) { 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 Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, (void)ConsumeAnnotationToken(); return; } - Optional> DeclVarData = - Actions.checkOpenMPDeclareVariantFunction( - Ptr, AssociatedFunction.get(), SourceRange(Loc, Tok.getLocation())); // Parse 'match'. OpenMPClauseKind CKind = Tok.isAnnotation() @@ -1132,24 +1365,27 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, } // 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 index 5c79eb2..9b3f5d8 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5369,7 +5369,8 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto, 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 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, 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 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, 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 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( 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 index 37dace3..6571c82 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -393,50 +393,43 @@ static void instantiateOMPDeclareVariantAttr( 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 index a1161d2..fbd59b9 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12612,3 +12612,22 @@ void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { 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 index 20a4f78..45c10be 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2756,6 +2756,8 @@ public: 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 index f935a69..018a738 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6578,3 +6578,19 @@ void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { 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 index 0173626..515d316 100644 --- a/clang/test/OpenMP/declare_variant_ast_print.c +++ b/clang/test/OpenMP/declare_variant_ast_print.c @@ -8,7 +8,7 @@ int foo(void); #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 @@ int bar(void); // 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 index 4964c69..fdc6d18 100644 --- a/clang/test/OpenMP/declare_variant_ast_print.cpp +++ b/clang/test/OpenMP/declare_variant_ast_print.cpp @@ -17,36 +17,40 @@ T foofoo() { return T(); } // 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 @@ template 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 @@ void h(C *hp, C *hp2, C *hq, C *lin) { // 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 @@ void h(double *hp, double *hp2, double *hq, double *lin) { 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 @@ auto fn_deduced1() { return 0; } // 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 @@ struct SpecialFuncs { 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 @@ void SpecialFuncs::xxx() {} // 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 @@ void bazzzz() { // 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 index 225990d..55195ff 100644 --- 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 index 2650762..7b87e69 100644 --- 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 @@ int bar() { 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 index ca1e4c3..f9950a8 100644 --- 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 @@ int bar() { 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 index 0c13f5f..4609a4f 100644 --- a/clang/test/OpenMP/declare_variant_mixed_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_mixed_codegen.cpp @@ -49,7 +49,7 @@ int call() { return 1; } 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 @@ void xxx() { 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 @@ int fn_variant2() { return 1; } #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 index 7f84709..a9ed8f7 100644 --- 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 index 92792bb..b56a050 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -107,6 +107,7 @@ static std::string ReadPCHRecord(StringRef type) { .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 @@ static std::string WritePCHRecord(StringRef type, StringRef name) { .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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { OS << " " << *e << "\n"; OS << " };\n"; OS << "private:\n"; - + VariadicArgument::writeDeclarations(OS); } @@ -1041,7 +1046,7 @@ namespace { 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 @@ createArgument(const Record &Arg, StringRef Attr, 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 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { // 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 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { } OS << " {\n"; - + for (auto const &ai : Args) { if (!shouldEmitArg(ai)) continue; ai->writeCtorBody(OS); @@ -2452,7 +2459,7 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { // 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 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { 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 @@ void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { for (auto *Attr : Attrs) { Record &R = *Attr; - + if (!R.getValueAsBit("ASTNode")) continue; @@ -2971,7 +2978,7 @@ static void GenerateHasAttrSpellingStringSwitch( // 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 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { 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 index 3b401b7..960c557 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h @@ -49,6 +49,9 @@ enum class TraitProperty { /// 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 @@ StringRef getOpenMPContextTraitSelectorName(TraitSelector Kind); /// 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 @@ StringRef getOpenMPContextTraitPropertyName(TraitProperty Kind); /// 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 index 7bdc16a..f4c4bdf 100644 --- a/llvm/lib/Frontend/OpenMP/OMPContext.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp @@ -286,6 +286,16 @@ TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) { #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 @@ StringRef llvm::omp::getOpenMPContextTraitSelectorName(TraitSelector Kind) { 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 @@ bool llvm::omp::isValidTraitPropertyForTraitSetAndSelector( } 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 index 8741b82..eb505be 100644 --- a/llvm/unittests/Frontend/OpenMPContextTest.cpp +++ b/llvm/unittests/Frontend/OpenMPContextTest.cpp @@ -38,12 +38,11 @@ TEST_F(OpenMPContextTest, RoundTripAndAssociation) { #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, \ -- 2.7.4