diff options
author | Erich Keane <erich.keane@intel.com> | 2018-07-20 14:13:28 +0000 |
---|---|---|
committer | Erich Keane <erich.keane@intel.com> | 2018-07-20 14:13:28 +0000 |
commit | 9eb2866868720b509babc97c7ab8b1000ed85426 (patch) | |
tree | 235715263d44d4aaf876c9d15896f3552d86c0ba /lib/Sema/Sema.cpp | |
parent | 0bb7730cf5a4fff5ff9caad7d38bc7ca193aa9c4 (diff) | |
download | clang-9eb2866868720b509babc97c7ab8b1000ed85426.tar.gz |
Implement cpu_dispatch/cpu_specific Multiversioning
As documented here: https://software.intel.com/en-us/node/682969 and
https://software.intel.com/en-us/node/523346. cpu_dispatch multiversioning
is an ICC feature that provides for function multiversioning.
This feature is implemented with two attributes: First, cpu_specific,
which specifies the individual function versions. Second, cpu_dispatch,
which specifies the location of the resolver function and the list of
resolvable functions.
This is valuable since it provides a mechanism where the resolver's TU
can be specified in one location, and the individual implementions
each in their own translation units.
The goal of this patch is to be source-compatible with ICC, so this
implementation diverges from the ICC implementation in a few ways:
1- Linux x86/64 only: This implementation uses ifuncs in order to
properly dispatch functions. This is is a valuable performance benefit
over the ICC implementation. A future patch will be provided to enable
this feature on Windows, but it will obviously more closely fit ICC's
implementation.
2- CPU Identification functions: ICC uses a set of custom functions to identify
the feature list of the host processor. This patch uses the cpu_supports
functionality in order to better align with 'target' multiversioning.
1- cpu_dispatch function def/decl: ICC's cpu_dispatch requires that the function
marked cpu_dispatch be an empty definition. This patch supports that as well,
however declarations are also permitted, since the linker will solve the
issue of multiple emissions.
Differential Revision: https://reviews.llvm.org/D47474
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@337552 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f81a34c40b..d57473c561 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -1585,6 +1585,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, } bool Ambiguous = false; + bool IsMV = false; if (Overloads) { for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), @@ -1598,11 +1599,16 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) { if (OverloadDecl->getMinRequiredArguments() == 0) { - if (!ZeroArgCallReturnTy.isNull() && !Ambiguous) { + if (!ZeroArgCallReturnTy.isNull() && !Ambiguous && + (!IsMV || !(OverloadDecl->isCPUDispatchMultiVersion() || + OverloadDecl->isCPUSpecificMultiVersion()))) { ZeroArgCallReturnTy = QualType(); Ambiguous = true; - } else + } else { ZeroArgCallReturnTy = OverloadDecl->getReturnType(); + IsMV = OverloadDecl->isCPUDispatchMultiVersion() || + OverloadDecl->isCPUSpecificMultiVersion(); + } } } } @@ -1683,7 +1689,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, NamedDecl *Fn = (*It)->getUnderlyingDecl(); // Don't print overloads for non-default multiversioned functions. if (const auto *FD = Fn->getAsFunction()) { - if (FD->isMultiVersion() && + if (FD->isMultiVersion() && FD->hasAttr<TargetAttr>() && !FD->getAttr<TargetAttr>()->isDefaultVersion()) continue; } @@ -1725,6 +1731,21 @@ static bool IsCallableWithAppend(Expr *E) { !isa<CXXOperatorCallExpr>(E)); } +static bool IsCPUDispatchCPUSpecificMultiVersion(const Expr *E) { + if (const auto *UO = dyn_cast<UnaryOperator>(E)) + E = UO->getSubExpr(); + + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + if (ULE->getNumDecls() == 0) + return false; + + const NamedDecl *ND = *ULE->decls_begin(); + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion(); + } + return false; +} + bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { @@ -1741,12 +1762,13 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // so we can emit a fixit and carry on pretending that E was // actually a CallExpr. SourceLocation ParenInsertionLoc = getLocForEndOfToken(Range.getEnd()); - Diag(Loc, PD) - << /*zero-arg*/ 1 << Range - << (IsCallableWithAppend(E.get()) - ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") - : FixItHint()); - notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + bool IsMV = IsCPUDispatchCPUSpecificMultiVersion(E.get()); + Diag(Loc, PD) << /*zero-arg*/ 1 << IsMV << Range + << (IsCallableWithAppend(E.get()) + ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") + : FixItHint()); + if (!IsMV) + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. @@ -1757,8 +1779,10 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, if (!ForceComplain) return false; - Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; - notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + bool IsMV = IsCPUDispatchCPUSpecificMultiVersion(E.get()); + Diag(Loc, PD) << /*not zero-arg*/ 0 << IsMV << Range; + if (!IsMV) + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); E = ExprError(); return true; } |