aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorelizabethandrews <elizabeth.andrews@intel.com>2023-12-05 18:11:53 -0500
committerGitHub <noreply@github.com>2023-12-05 18:11:53 -0500
commitcee5b8777fa98312b05bf8aa81554910a8f867c5 (patch)
treed1e0961be566a804870ca22dd36b1561c433b157 /clang/lib/CodeGen/CodeGenModule.cpp
parent651a49c4b6bdef81c8deddbe653258c066867a58 (diff)
downloadllvm-cee5b8777fa98312b05bf8aa81554910a8f867c5.zip
llvm-cee5b8777fa98312b05bf8aa81554910a8f867c5.tar.gz
llvm-cee5b8777fa98312b05bf8aa81554910a8f867c5.tar.bz2
[Clang] Fix linker error for function multiversioning (#71706)
Currently target_clones attribute results in a linker error when there are no multi-versioned function declarations in the calling TU. In the calling TU, the call is generated with the ‘normal’ assembly name. This does not match any of the versions or the ifunc, since version mangling includes a .versionstring, and the ifunc includes .ifunc suffix. The linker error is not seen with GCC since the mangling for the ifunc symbol in GCC is the ‘normal’ assembly name for function i.e. no ifunc suffix. This PR removes the .ifunc suffix to match GCC. It also adds alias with the .ifunc suffix so as to ensure backward compatibility. The changes exclude aarch64 target because the mangling for default versions on aarch64 does not include a .default suffix and is the 'normal' assembly name, unlike other targets. It is not clear to me what the correct behavior for this target is. Old Phabricator review - https://reviews.llvm.org/D158666 --------- Co-authored-by: Tom Honermann <tom@honermann.net>
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp38
1 files changed, 34 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dea58a7..6a20723 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4178,8 +4178,29 @@ void CodeGenModule::emitMultiVersionFunctions() {
}
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
- if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant))
+ if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
ResolverConstant = IFunc->getResolver();
+ // In Aarch64, default versions of multiversioned functions are mangled to
+ // their 'normal' assembly name. This deviates from other targets which
+ // append a '.default' string. As a result we need to continue appending
+ // .ifunc in Aarch64.
+ // FIXME: Should Aarch64 mangling for 'default' multiversion function and
+ // in turn ifunc function match that of other targets?
+ if (FD->isTargetClonesMultiVersion() &&
+ !getTarget().getTriple().isAArch64()) {
+ const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
+ llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
+ std::string MangledName = getMangledNameImpl(
+ *this, GD, FD, /*OmitMultiVersionMangling=*/true);
+ // In prior versions of Clang, the mangling for ifuncs incorrectly
+ // included an .ifunc suffix. This alias is generated for backward
+ // compatibility. It is deprecated, and may be removed in the future.
+ auto *Alias = llvm::GlobalAlias::create(
+ DeclTy, 0, getMultiversionLinkage(*this, GD),
+ MangledName + ".ifunc", IFunc, &getModule());
+ SetCommonAttributes(FD, Alias);
+ }
+ }
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
@@ -4346,10 +4367,19 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
// Holds the name of the resolver, in ifunc mode this is the ifunc (which has
// a separate resolver).
std::string ResolverName = MangledName;
- if (getTarget().supportsIFunc())
- ResolverName += ".ifunc";
- else if (FD->isTargetMultiVersion())
+ if (getTarget().supportsIFunc()) {
+ // In Aarch64, default versions of multiversioned functions are mangled to
+ // their 'normal' assembly name. This deviates from other targets which
+ // append a '.default' string. As a result we need to continue appending
+ // .ifunc in Aarch64.
+ // FIXME: Should Aarch64 mangling for 'default' multiversion function and
+ // in turn ifunc function match that of other targets?
+ if (!FD->isTargetClonesMultiVersion() ||
+ getTarget().getTriple().isAArch64())
+ ResolverName += ".ifunc";
+ } else if (FD->isTargetMultiVersion()) {
ResolverName += ".resolver";
+ }
// If the resolver has already been created, just return it.
if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName))