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());
}
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)
// 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
// 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
(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