aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp97
1 files changed, 50 insertions, 47 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 0c002b5..71192cb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3796,8 +3796,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// Forward declarations are emitted lazily on first use.
if (!FD->doesThisDeclarationHaveABody()) {
if (!FD->doesDeclarationForceExternallyVisibleDefinition() &&
- (!FD->isMultiVersion() ||
- !FD->getASTContext().getTargetInfo().getTriple().isAArch64()))
+ (!FD->isMultiVersion() || !getTarget().getTriple().isAArch64()))
return;
StringRef MangledName = getMangledName(GD);
@@ -4191,23 +4190,6 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
return llvm::GlobalValue::WeakODRLinkage;
}
-static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) {
- auto *DeclCtx = const_cast<DeclContext *>(FD->getDeclContext());
- TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
- StorageClass SC = FD->getStorageClass();
- DeclarationName Name = FD->getNameInfo().getName();
-
- FunctionDecl *NewDecl =
- FunctionDecl::Create(FD->getASTContext(), DeclCtx, FD->getBeginLoc(),
- FD->getEndLoc(), Name, TInfo->getType(), TInfo, SC);
-
- NewDecl->setIsMultiVersion();
- NewDecl->addAttr(TargetVersionAttr::CreateImplicit(
- NewDecl->getASTContext(), "default", NewDecl->getSourceRange()));
-
- return NewDecl;
-}
-
void CodeGenModule::emitMultiVersionFunctions() {
std::vector<GlobalDecl> MVFuncsToEmit;
MultiVersionFuncs.swap(MVFuncsToEmit);
@@ -4234,29 +4216,30 @@ void CodeGenModule::emitMultiVersionFunctions() {
return cast<llvm::Function>(Func);
};
- bool HasDefaultDecl = !FD->isTargetVersionMultiVersion();
- bool ShouldEmitResolver =
- !getContext().getTargetInfo().getTriple().isAArch64();
+ // For AArch64, a resolver is only emitted if a function marked with
+ // target_version("default")) or target_clones() is present and defined
+ // in this TU. For other architectures it is always emitted.
+ bool ShouldEmitResolver = !getTarget().getTriple().isAArch64();
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
getContext().forEachMultiversionedFunctionVersion(
FD, [&](const FunctionDecl *CurFD) {
llvm::SmallVector<StringRef, 8> Feats;
+ bool IsDefined = CurFD->doesThisDeclarationHaveABody();
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
TA->getAddedFeatures(Feats);
llvm::Function *Func = createFunction(CurFD);
Options.emplace_back(Func, TA->getArchitecture(), Feats);
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
- bool HasDefaultDef = TVA->isDefaultVersion() &&
- CurFD->doesThisDeclarationHaveABody();
- HasDefaultDecl |= TVA->isDefaultVersion();
- ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
+ if (TVA->isDefaultVersion() && IsDefined)
+ ShouldEmitResolver = true;
TVA->getFeatures(Feats);
llvm::Function *Func = createFunction(CurFD);
Options.emplace_back(Func, /*Architecture*/ "", Feats);
} else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
- ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody();
+ if (IsDefined)
+ ShouldEmitResolver = true;
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) {
if (!TC->isFirstOfVersion(I))
continue;
@@ -4282,13 +4265,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
if (!ShouldEmitResolver)
continue;
- if (!HasDefaultDecl) {
- FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD);
- llvm::Function *Func = createFunction(NewFD);
- llvm::SmallVector<StringRef, 1> Feats;
- Options.emplace_back(Func, /*Architecture*/ "", Feats);
- }
-
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
ResolverConstant = IFunc->getResolver();
@@ -4339,6 +4315,14 @@ void CodeGenModule::emitMultiVersionFunctions() {
emitMultiVersionFunctions();
}
+static void replaceDeclarationWith(llvm::GlobalValue *Old,
+ llvm::Constant *New) {
+ assert(cast<llvm::Function>(Old)->isDeclaration() && "Not a declaration");
+ New->takeName(Old);
+ Old->replaceAllUsesWith(New);
+ Old->eraseFromParent();
+}
+
void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
assert(FD && "Not a FunctionDecl?");
@@ -4443,12 +4427,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
// Fix up function declarations that were created for cpu_specific before
// cpu_dispatch was known
if (!isa<llvm::GlobalIFunc>(IFunc)) {
- assert(cast<llvm::Function>(IFunc)->isDeclaration());
auto *GI = llvm::GlobalIFunc::create(DeclTy, 0, Linkage, "", ResolverFunc,
&getModule());
- GI->takeName(IFunc);
- IFunc->replaceAllUsesWith(GI);
- IFunc->eraseFromParent();
+ replaceDeclarationWith(IFunc, GI);
IFunc = GI;
}
@@ -4478,7 +4459,8 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) {
}
/// If a dispatcher for the specified mangled name is not in the module, create
-/// and return an llvm Function with the specified type.
+/// and return it. The dispatcher is either an llvm Function with the specified
+/// type, or a global ifunc.
llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
assert(FD && "Not a FunctionDecl?");
@@ -4506,8 +4488,15 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
ResolverName += ".resolver";
}
- // If the resolver has already been created, just return it.
- if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName))
+ // If the resolver has already been created, just return it. This lookup may
+ // yield a function declaration instead of a resolver on AArch64. That is
+ // because we didn't know whether a resolver will be generated when we first
+ // encountered a use of the symbol named after this resolver. Therefore,
+ // targets which support ifuncs should not return here unless we actually
+ // found an ifunc.
+ llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName);
+ if (ResolverGV &&
+ (isa<llvm::GlobalIFunc>(ResolverGV) || !getTarget().supportsIFunc()))
return ResolverGV;
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
@@ -4533,7 +4522,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
-
+ if (ResolverGV)
+ replaceDeclarationWith(ResolverGV, GIF);
return GIF;
}
@@ -4542,6 +4532,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
assert(isa<llvm::GlobalValue>(Resolver) &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
+ if (ResolverGV)
+ replaceDeclarationWith(ResolverGV, Resolver);
return Resolver;
}
@@ -4571,6 +4563,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
ForDefinition_t IsForDefinition) {
const Decl *D = GD.getDecl();
+ std::string NameWithoutMultiVersionMangling;
// Any attempts to use a MultiVersion function should result in retrieving
// the iFunc instead. Name Mangling will handle the rest of the changes.
if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D)) {
@@ -4592,14 +4585,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
if (FD->isMultiVersion()) {
UpdateMultiVersionNames(GD, FD, MangledName);
- if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() &&
- !FD->isUsed())
- AddDeferredMultiVersionResolverToEmit(GD);
- else if (!IsForDefinition)
- return GetOrCreateMultiVersionResolver(GD);
+ if (!IsForDefinition) {
+ // On AArch64 we do not immediatelly emit an ifunc resolver when a
+ // function is used. Instead we defer the emission until we see a
+ // default definition. In the meantime we just reference the symbol
+ // without FMV mangling (it may or may not be replaced later).
+ if (getTarget().getTriple().isAArch64()) {
+ AddDeferredMultiVersionResolverToEmit(GD);
+ NameWithoutMultiVersionMangling = getMangledNameImpl(
+ *this, GD, FD, /*OmitMultiVersionMangling=*/true);
+ } else
+ return GetOrCreateMultiVersionResolver(GD);
+ }
}
}
+ if (!NameWithoutMultiVersionMangling.empty())
+ MangledName = NameWithoutMultiVersionMangling;
+
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {