[OPENMP50]Codegen support for scores in context selectors.
authorAlexey Bataev <a.bataev@hotmail.com>
Thu, 3 Oct 2019 20:49:48 +0000 (20:49 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Thu, 3 Oct 2019 20:49:48 +0000 (20:49 +0000)
If the context selector has associated score and several contexts
selectors matches current context, the function with the highest score
must be selected.

llvm-svn: 373661

clang/lib/CodeGen/CGOpenMPRuntime.cpp
clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp

index 27231db..bd74367 100644 (file)
@@ -11175,37 +11175,87 @@ bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
   return !A->getImplVendor().compare("llvm");
 }
 
+static bool greaterCtxScore(ASTContext &Ctx, const Expr *LHS, const Expr *RHS) {
+  // If both scores are unknown, choose the very first one.
+  if (!LHS && !RHS)
+    return true;
+  // If only one is known, return this one.
+  if (LHS && !RHS)
+    return true;
+  if (!LHS && RHS)
+    return false;
+  llvm::APSInt LHSVal = LHS->EvaluateKnownConstInt(Ctx);
+  llvm::APSInt RHSVal = RHS->EvaluateKnownConstInt(Ctx);
+  return llvm::APSInt::compareValues(LHSVal, RHSVal) <= 0;
+}
+
+namespace {
+/// Comparator for the priority queue for context selector.
+class OMPDeclareVariantAttrComparer
+    : public std::greater<const OMPDeclareVariantAttr *> {
+private:
+  ASTContext &Ctx;
+
+public:
+  OMPDeclareVariantAttrComparer(ASTContext &Ctx) : Ctx(Ctx) {}
+  bool operator()(const OMPDeclareVariantAttr *LHS,
+                  const OMPDeclareVariantAttr *RHS) const {
+    const Expr *LHSExpr = nullptr;
+    const Expr *RHSExpr = nullptr;
+    if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+      LHSExpr = LHS->getScore();
+    if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+      RHSExpr = RHS->getScore();
+    return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
+  }
+};
+} // anonymous namespace
+
 /// Finds the variant function that matches current context with its context
 /// selector.
-static const FunctionDecl *getDeclareVariantFunction(const FunctionDecl *FD) {
+static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx,
+                                                     const FunctionDecl *FD) {
   if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
     return FD;
   // Iterate through all DeclareVariant attributes and check context selectors.
-  SmallVector<const OMPDeclareVariantAttr *, 4> MatchingAttributes;
-  for (const auto * A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
+  auto &&Comparer = [&Ctx](const OMPDeclareVariantAttr *LHS,
+                           const OMPDeclareVariantAttr *RHS) {
+    const Expr *LHSExpr = nullptr;
+    const Expr *RHSExpr = nullptr;
+    if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+      LHSExpr = LHS->getScore();
+    if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+      RHSExpr = RHS->getScore();
+    return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
+  };
+  const OMPDeclareVariantAttr *TopMostAttr = nullptr;
+  for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
+    const OMPDeclareVariantAttr *SelectedAttr = nullptr;
     switch (A->getCtxSelectorSet()) {
     case OMPDeclareVariantAttr::CtxSetImplementation:
       switch (A->getCtxSelector()) {
       case OMPDeclareVariantAttr::CtxVendor:
         if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
                          OMPDeclareVariantAttr::CtxVendor>(A))
-          MatchingAttributes.push_back(A);
+          SelectedAttr = A;
         break;
       case OMPDeclareVariantAttr::CtxUnknown:
         llvm_unreachable(
-            "Unknown context selector in implementation selctor set.");
+            "Unknown context selector in implementation selector set.");
       }
       break;
     case OMPDeclareVariantAttr::CtxSetUnknown:
       llvm_unreachable("Unknown context selector set.");
     }
+    // If the attribute matches the context, find the attribute with the highest
+    // score.
+    if (SelectedAttr && (!TopMostAttr || Comparer(TopMostAttr, SelectedAttr)))
+      TopMostAttr = SelectedAttr;
   }
-  if (MatchingAttributes.empty())
+  if (!TopMostAttr)
     return FD;
-  // TODO: implement score analysis of multiple context selectors.
-  const OMPDeclareVariantAttr *MainAttr = MatchingAttributes.front();
   return cast<FunctionDecl>(
-      cast<DeclRefExpr>(MainAttr->getVariantFuncRef()->IgnoreParenImpCasts())
+      cast<DeclRefExpr>(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts())
           ->getDecl());
 }
 
@@ -11216,7 +11266,7 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
   llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
   if (Orig && !Orig->isDeclaration())
     return false;
-  const FunctionDecl *NewFD = getDeclareVariantFunction(D);
+  const FunctionDecl *NewFD = getDeclareVariantFunction(CGM.getContext(), D);
   // Emit original function if it does not have declare variant attribute or the
   // context does not match.
   if (NewFD == D)
index ed814b7..c8c9d0b 100644 (file)
@@ -3,11 +3,13 @@
 // RUN: %clang_cc1 -fopenmp -x c++ -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 | FileCheck %s
 // expected-no-diagnostics
 
-// CHECK-NOT: ret i32 {{1|4}}
+// CHECK-NOT: ret i32 {{1|4|81|84}}
 // CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov
 // CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
 // CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
 // CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
+// CHECK-DAG: @_Z5prio_v = alias i32 (), i32 ()* @_Z4priov
+// CHECK-DAG: @_ZL6prio1_v = internal alias i32 (), i32 ()* @_ZL5prio2v
 // CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv
 // CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v
 // CHECK-DAG: @_ZN12SpecialFuncs6MethodEv =  {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
@@ -18,7 +20,9 @@
 // CHECK-DAG: ret i32 5
 // CHECK-DAG: ret i32 6
 // CHECK-DAG: ret i32 7
-// CHECK-NOT: ret i32 {{1|4}}
+// CHECK-DAG: ret i32 82
+// CHECK-DAG: ret i32 83
+// CHECK-NOT: ret i32 {{1|4|81|84}}
 
 #ifndef HEADER
 #define HEADER
@@ -88,4 +92,22 @@ void xxx() {
   (void)s1.method();
 }
 
+int prio() { return 81; }
+int prio1() { return 82; }
+
+#pragma omp declare variant(prio) match(implementation = {vendor(llvm)})
+#pragma omp declare variant(prio1) match(implementation = {vendor(score(1): llvm)})
+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(3): llvm)})
+#pragma omp declare variant(prio2) match(implementation = {vendor(score(5): llvm)})
+#pragma omp declare variant(prio3) match(implementation = {vendor(score(1): llvm)})
+static int prio1_() { return 1; }
+
+int int_fn() { return prio1_(); }
+
 #endif // HEADER