summaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorErich Keane <erich.keane@intel.com>2021-11-05 06:25:34 -0700
committerErich Keane <erich.keane@intel.com>2021-11-11 11:11:16 -0800
commit9deab60ae710f8c4cc810cd680edfb64c803f42d (patch)
tree95b99e10e7db68dd224fcd6f75337dcbc7c14ef2 /clang/lib/CodeGen/CodeGenModule.cpp
parent42102bce98e527f994a7bc68b2255d9e0462f6eb (diff)
Implement target_clones multiversioning
As discussed here: https://lwn.net/Articles/691932/ GCC6.0 adds target_clones multiversioning. This functionality is an odd cross between the cpu_dispatch and 'target' MV, but is compatible with neither. This attribute allows you to list all options, then emits a separately optimized version of each function per-option (similar to the cpu_specific attribute). It automatically generates a resolver, just like the other two. The mangling however, is... ODD to say the least. The mangling format is: <normal_mangling>.<option string>.<option ordinal>. Differential Revision:https://reviews.llvm.org/D51650
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp103
1 files changed, 101 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c28c2e2e85d8..2e497ae45994 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1264,6 +1264,20 @@ static bool isUniqueInternalLinkageDecl(GlobalDecl GD,
(CGM.getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage);
}
+static void AppendTargetClonesMangling(const CodeGenModule &CGM,
+ const TargetClonesAttr *Attr,
+ unsigned VersionIndex,
+ raw_ostream &Out) {
+ Out << '.';
+ StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
+ if (FeatureStr.startswith("arch="))
+ Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1);
+ else
+ Out << FeatureStr;
+
+ Out << '.' << Attr->getMangledIndex(VersionIndex);
+}
+
static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
const NamedDecl *ND,
bool OmitMultiVersionMangling = false) {
@@ -1317,6 +1331,10 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
case MultiVersionKind::Target:
AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
break;
+ case MultiVersionKind::TargetClones:
+ AppendTargetClonesMangling(CGM, FD->getAttr<TargetClonesAttr>(),
+ GD.getMultiVersionIndex(), Out);
+ break;
case MultiVersionKind::None:
llvm_unreachable("None multiversion type isn't valid here");
}
@@ -1981,8 +1999,9 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
FD = FD ? FD->getMostRecentDecl() : FD;
const auto *TD = FD ? FD->getAttr<TargetAttr>() : nullptr;
const auto *SD = FD ? FD->getAttr<CPUSpecificAttr>() : nullptr;
+ const auto *TC = FD ? FD->getAttr<TargetClonesAttr>() : nullptr;
bool AddedAttr = false;
- if (TD || SD) {
+ if (TD || SD || TC) {
llvm::StringMap<bool> FeatureMap;
getContext().getFunctionFeatureMap(FeatureMap, GD);
@@ -3224,6 +3243,12 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
for (unsigned I = 0; I < Spec->cpus_size(); ++I)
EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
// Requires multiple emits.
+ } else if (FD->isTargetClonesMultiVersion()) {
+ auto *Clone = FD->getAttr<TargetClonesAttr>();
+ for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I)
+ if (Clone->isFirstOfVersion(I))
+ EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
+ EmitTargetClonesResolver(GD);
} else
EmitGlobalFunctionDefinition(GD, GV);
}
@@ -3305,6 +3330,63 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
return llvm::GlobalValue::WeakODRLinkage;
}
+void CodeGenModule::EmitTargetClonesResolver(GlobalDecl GD) {
+ const auto *FD = cast<FunctionDecl>(GD.getDecl());
+ assert(FD && "Not a FunctionDecl?");
+ const auto *TC = FD->getAttr<TargetClonesAttr>();
+ assert(TC && "Not a target_clones Function?");
+
+ QualType CanonTy = Context.getCanonicalType(FD->getType());
+ llvm::Type *DeclTy = getTypes().ConvertType(CanonTy);
+
+ if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CGFunctionInfo &FInfo = getTypes().arrangeCXXMethodDeclaration(CXXFD);
+ DeclTy = getTypes().GetFunctionType(FInfo);
+ }
+
+ llvm::Function *ResolverFunc;
+ if (getTarget().supportsIFunc()) {
+ auto *IFunc = cast<llvm::GlobalIFunc>(
+ GetOrCreateMultiVersionResolver(GD, DeclTy, FD));
+ ResolverFunc = cast<llvm::Function>(IFunc->getResolver());
+ } else
+ ResolverFunc =
+ cast<llvm::Function>(GetOrCreateMultiVersionResolver(GD, DeclTy, FD));
+
+ SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
+ for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size();
+ ++VersionIndex) {
+ if (!TC->isFirstOfVersion(VersionIndex))
+ continue;
+ StringRef Version = TC->getFeatureStr(VersionIndex);
+ StringRef MangledName =
+ getMangledName(GD.getWithMultiVersionIndex(VersionIndex));
+ llvm::Constant *Func = GetGlobalValue(MangledName);
+ assert(Func &&
+ "Should have already been created before calling resolver emit");
+
+ StringRef Architecture;
+ llvm::SmallVector<StringRef, 1> Feature;
+
+ if (Version.startswith("arch="))
+ Architecture = Version.drop_front(sizeof("arch=") - 1);
+ else if (Version != "default")
+ Feature.push_back(Version);
+
+ Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
+ }
+
+ const TargetInfo &TI = getTarget();
+ std::stable_sort(
+ Options.begin(), Options.end(),
+ [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
+ const CodeGenFunction::MultiVersionResolverOption &RHS) {
+ return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
+ });
+ CodeGenFunction CGF(*this);
+ CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+}
+
void CodeGenModule::emitMultiVersionFunctions() {
std::vector<GlobalDecl> MVFuncsToEmit;
MultiVersionFuncs.swap(MVFuncsToEmit);
@@ -3509,8 +3591,25 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(
// Since this is the first time we've created this IFunc, make sure
// that we put this multiversioned function into the list to be
// replaced later if necessary (target multiversioning only).
- if (!FD->isCPUDispatchMultiVersion() && !FD->isCPUSpecificMultiVersion())
+ if (FD->isTargetMultiVersion())
MultiVersionFuncs.push_back(GD);
+ else if (FD->isTargetClonesMultiVersion()) {
+ // In target_clones multiversioning, make sure we emit this if used.
+ auto DDI =
+ DeferredDecls.find(getMangledName(GD.getWithMultiVersionIndex(0)));
+ if (DDI != DeferredDecls.end()) {
+ addDeferredDeclToEmit(GD);
+ DeferredDecls.erase(DDI);
+ } else {
+ // Emit the symbol of the 1st variant, so that the deferred decls know we
+ // need it, otherwise the only global value will be the resolver/ifunc,
+ // which end up getting broken if we search for them with GetGlobalValue'.
+ GetOrCreateLLVMFunction(
+ getMangledName(GD.getWithMultiVersionIndex(0)), DeclTy, FD,
+ /*ForVTable=*/false, /*DontDefer=*/true,
+ /*IsThunk=*/false, llvm::AttributeList(), ForDefinition);
+ }
+ }
if (getTarget().supportsIFunc()) {
llvm::Type *ResolverType = llvm::FunctionType::get(