[OPENMP50]Add parsing/sema analysis for declare variant score.
authorAlexey Bataev <a.bataev@hotmail.com>
Wed, 2 Oct 2019 18:19:02 +0000 (18:19 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Wed, 2 Oct 2019 18:19:02 +0000 (18:19 +0000)
Context selectors may include optional score clause in format
`score(<expr>):`, where `<expr>` must be a constant integer expression.
Added parsing/sema analysis only.

llvm-svn: 373502

clang/include/clang/Basic/Attr.td
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/OpenMP/declare_variant_ast_print.c
clang/test/OpenMP/declare_variant_ast_print.cpp
clang/test/OpenMP/declare_variant_messages.c
clang/test/OpenMP/declare_variant_messages.cpp

index 14834a1..283d0f3 100644 (file)
@@ -3290,12 +3290,19 @@ def OMPDeclareVariant : InheritableAttr {
   let Documentation = [OMPDeclareVariantDocs];
   let Args = [
     ExprArgument<"VariantFuncRef">,
+    ExprArgument<"Score">,
     EnumArgument<"CtxSelectorSet", "CtxSelectorSetType",
                  [ "", "implementation"
                  ],
                  [
                    "CtxSetUnknown", "CtxSetImplementation"
                  ]>,
+    EnumArgument<"CtxScore", "ScoreType",
+                 [ "", "score"
+                 ],
+                 [
+                   "ScoreUnknown", "ScoreSpecified"
+                 ]>,
     EnumArgument<"CtxSelector", "CtxSelectorType",
                  [ "", "vendor"
                  ],
@@ -3305,6 +3312,13 @@ def OMPDeclareVariant : InheritableAttr {
     StringArgument<"ImplVendor", 1>
   ];
   let AdditionalMembers = [{
+    void printScore(raw_ostream & OS, const PrintingPolicy &Policy) const {
+      if (const Expr *E = getScore()) {
+        OS << "score(";
+        E->printPretty(OS, nullptr, Policy);
+        OS << "):";
+      }
+    }
     void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
         const {
       assert(getCtxSelectorSet() != CtxSetUnknown &&
@@ -3322,6 +3336,7 @@ def OMPDeclareVariant : InheritableAttr {
         switch (getCtxSelector()) {
         case CtxVendor:
           OS << "vendor(";
+          printScore(OS, Policy);
           OS << getImplVendor();
           OS << ")";
           break;
index 1c587cf..1e763bd 100644 (file)
@@ -9109,11 +9109,14 @@ public:
     OMPDeclareVariantAttr::CtxSelectorType Ctx =
         OMPDeclareVariantAttr::CtxUnknown;
     StringRef ImplVendor;
+    ExprResult CtxScore;
     explicit OpenMPDeclareVariantCtsSelectorData() = default;
     explicit OpenMPDeclareVariantCtsSelectorData(
         OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
-        OMPDeclareVariantAttr::CtxSelectorType Ctx, StringRef ImplVendor)
-        : CtxSet(CtxSet), Ctx(Ctx), ImplVendor(ImplVendor) {}
+        OMPDeclareVariantAttr::CtxSelectorType Ctx, StringRef ImplVendor,
+        ExprResult CtxScore)
+        : CtxSet(CtxSet), Ctx(Ctx), ImplVendor(ImplVendor), CtxScore(CtxScore) {
+    }
   };
 
   /// Checks if the variant/multiversion functions are compatible.
index 46c8238..c7143fd 100644 (file)
@@ -786,6 +786,31 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
       LinModifiers, Steps, SourceRange(Loc, EndLoc));
 }
 
+/// Parse optional 'score' '(' <expr> ')' ':'.
+static ExprResult parseContextScore(Parser &P) {
+  ExprResult ScoreExpr;
+  SmallString<16> Buffer;
+  StringRef SelectorName =
+      P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
+  OMPDeclareVariantAttr::ScoreType ScoreKind =
+      OMPDeclareVariantAttr::ScoreUnknown;
+  (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind);
+  if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown)
+    return ScoreExpr;
+  assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified &&
+         "Expected \"score\" clause.");
+  (void)P.ConsumeToken();
+  SourceLocation RLoc;
+  ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);
+  // Parse ':'
+  if (P.getCurToken().is(tok::colon))
+    (void)P.ConsumeAnyToken();
+  else
+    P.Diag(P.getCurToken(), diag::warn_pragma_expected_colon)
+        << "context selector score clause";
+  return ScoreExpr;
+}
+
 /// Parse context selector for 'implementation' selector set:
 /// 'vendor' '(' <vendor> ')'
 static void
@@ -815,6 +840,7 @@ parseImplementationSelector(Parser &P,
     BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
     (void)T.expectAndConsume(diag::err_expected_lparen_after,
                              CtxSelectorName.data());
+    Data.CtxScore = parseContextScore(P);
     // Parse <vendor>.
     StringRef VendorName;
     if (Tok.is(tok::identifier)) {
index 42e1755..2b659f7 100644 (file)
@@ -5112,8 +5112,23 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
   if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
       Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
     return;
+  Expr *Score = nullptr;
+  OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
+  if (Data.CtxScore.isUsable()) {
+    ST = OMPDeclareVariantAttr::ScoreSpecified;
+    Score = Data.CtxScore.get();
+    if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+        !Score->isInstantiationDependent() &&
+        !Score->containsUnexpandedParameterPack()) {
+      llvm::APSInt Result;
+      ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
+      if (ICE.isInvalid())
+        return;
+    }
+  }
   auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
-      Context, VariantRef, Data.CtxSet, Data.Ctx, Data.ImplVendor, SR);
+      Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx, Data.ImplVendor,
+      SR);
   FD->addAttr(NewAttr);
 }
 
index f6cf369..881b4fd 100644 (file)
@@ -388,6 +388,10 @@ static void instantiateOMPDeclareVariantAttr(
   if (Expr *E = Attr.getVariantFuncRef())
     VariantFuncRef = Subst(E);
 
+  ExprResult Score;
+  if (Expr *E = Attr.getScore())
+    Score = Subst(E);
+
   // Check function/variant ref.
   Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
       S.checkOpenMPDeclareVariantFunction(
@@ -395,8 +399,9 @@ static void instantiateOMPDeclareVariantAttr(
   if (!DeclVarData)
     return;
   // Instantiate the attribute.
-  Sema::OpenMPDeclareVariantCtsSelectorData Data(
-      Attr.getCtxSelectorSet(), Attr.getCtxSelector(), Attr.getImplVendor());
+  Sema::OpenMPDeclareVariantCtsSelectorData Data(Attr.getCtxSelectorSet(),
+                                                 Attr.getCtxSelector(),
+                                                 Attr.getImplVendor(), Score);
   S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
                                        DeclVarData.getValue().second,
                                        Attr.getRange(), Data);
index 4c91e2e..ad1ef91 100644 (file)
@@ -10,9 +10,11 @@ int foo(void);
 #pragma omp declare variant(foo) match(xxx={vvv})
 #pragma omp declare variant(foo) match(implementation={vendor(ibm)}, implementation={vendor(llvm)})
 #pragma omp declare variant(foo) match(implementation={vendor(unknown)})
+#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm)})
 int bar(void);
 
 // CHECK:      int foo();
+// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):ibm)})
 // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(unknown)})
 // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(ibm)})
 // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(llvm)})
index 1760751..77f03f5 100644 (file)
@@ -17,7 +17,8 @@ T foofoo() { return T(); }
 // CHECK-NEXT: return int();
 // CHECK-NEXT: }
 
-// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(unknown)})
+// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(5):ibm)})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(unknown)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(ibm)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(llvm)})
 // CHECK-NEXT: int bar();
@@ -25,12 +26,14 @@ T foofoo() { return T(); }
 #pragma omp declare variant(foofoo <int>) match(xxx = {vvv})
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(ibm)}, implementation={vendor(llvm)})
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(unknown)})
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm)})
 int bar();
 
-// CHECK:      #pragma omp declare variant(foofoo<T>) match(implementation={vendor(unknown)})
+// CHECK:      #pragma omp declare variant(foofoo<T>) match(implementation={vendor(score(C + 5):ibm)})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(unknown)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(ibm)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<T>) match(implementation={vendor(llvm)})
-// CHECK-NEXT: template <typename T> T barbar();
+// CHECK-NEXT: template <typename T, int C> T barbar();
 #pragma omp declare variant(foofoo <T>) match(xxx = {})
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv})
 #pragma omp declare variant(foofoo <T>) match(user = {score(<expr>) : condition(<expr>)})
@@ -39,19 +42,21 @@ int bar();
 #pragma omp declare variant(foofoo <T>) match(user = {condition(<expr>)})
 #pragma omp declare variant(foofoo <T>) match(implementation={vendor(ibm)}, implementation={vendor(llvm)})
 #pragma omp declare variant(foofoo <T>) match(implementation={vendor(unknown)})
-template <typename T>
+#pragma omp declare variant(foofoo <T>) match(implementation={vendor(score(C+5): ibm)})
+template <typename T, int C>
 T barbar();
 
-// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(unknown)})
+// CHECK:      #pragma omp declare variant(foofoo<int>) match(implementation={vendor(score(3 + 5):ibm)})
+// CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(unknown)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(ibm)})
 // CHECK-NEXT: #pragma omp declare variant(foofoo<int>) match(implementation={vendor(llvm)})
-// CHECK-NEXT: template<> int barbar<int>();
+// CHECK-NEXT: template<> int barbar<int, 3>();
 
 // CHECK-NEXT: int baz() {
-// CHECK-NEXT: return barbar<int>();
+// CHECK-NEXT: return barbar<int, 3>();
 // CHECK-NEXT: }
 int baz() {
-  return barbar<int>();
+  return barbar<int, 3>();
 }
 
 // CHECK:      template <class C> void h_ref(C *hp, C *hp2, C *hq, C *lin) {
index 0eeaae0..7e69cec 100644 (file)
@@ -30,6 +30,11 @@ int foo(void);
 #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 ')'}} 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 ')'}} 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 ')'}} 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 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)})
 int bar(void);
 
 // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}}
index ca61c53..88e724d 100644 (file)
@@ -8,7 +8,7 @@
 int foo();
 
 template <typename T>
-T foofoo();
+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 '('}}
@@ -33,6 +33,11 @@ T foofoo();
 #pragma omp declare variant(foofoo <int>) 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 ')'}} expected-note {{to match this '('}}
 #pragma omp declare variant(foofoo <int>) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-note {{to match this '('}}
 #pragma omp declare variant(foofoo <int>) 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 <int>) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // 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 <int>) match(implementation={vendor(score(2 ibm)}) // 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 <int>) match(implementation={vendor(score(foofoo <int>()) 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<int>' cannot be used in a constant expression}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(5): ibm)})
 int bar();
 
 #pragma omp declare variant                            // expected-error {{expected '(' after 'declare variant'}}
@@ -57,7 +62,12 @@ int bar();
 #pragma omp declare variant(foofoo <T>) match(user = {condition(<expr>)})
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}}
 #pragma omp declare variant(foofoo <T>) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}
-template <typename T>
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score( ibm)}) // 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 <int>) match(implementation={vendor(score(C ibm)}) // 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 <int>) match(implementation={vendor(score(foofoo <int>()) 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<int>' cannot be used in a constant expression}}
+#pragma omp declare variant(foofoo <int>) match(implementation={vendor(score(C+5): ibm)})
+template <typename T, int C>
 T barbar();
 
 // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}}