[PATCH] D158666: [Clang] Fix linker error for function multiversioning
Elizabeth Andrews via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 23 13:13:29 PDT 2023
eandrews created this revision.
eandrews added reviewers: erichkeane, tahonermann, aaron.ballman, zsrkmyn.
Herald added a project: All.
eandrews requested review of this revision.
Currently target_clones attribute results in a linker error when there are no multi-versioned function declarations in the calling TU.
foo.cpp
int foo1();
__attribute__((target_clones("default", "arch=core2")))
int foo1() { return 0; }
main.cpp
int foo1();
int main()
{ return foo1(); }
$ clang++ main.cpp foo.cpp
/usr/bin/ld: /tmp/main-981c32.o: in function `main':
main.cpp:(.text+0x10): undefined reference to `foo1()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
In the calling TU, the call is generated with ‘normal’ assembly name. This does not match any of the versions since their mangling includes a .versionstring. The linker error is not seen with GCC since the mangling for the ifunc symbol in GCC is the ‘normal’ assembly name for function.
Clang –
$nm foo.o
U __cpu_indicator_init
U __cpu_model
T _Z4foo1v.arch_core2.0
T _Z4foo1v.default.1
i _Z4foo1v.ifunc <----------
W _Z4foo1v.resolver
$ nm main.o
T main
U _Z4foo1v
GCC
$ nm foo.o
U __cpu_indicator_init
U __cpu_model
i _Z4foo1v <---------------
t _Z4foo1v.arch_core2.0
t _Z4foo1v.default.1
W _Z4foo1v.resolver
$ nm main.o
T main
U _Z4foo1v
I was initially inclined to match GCC behavior here and remove the ifunc suffix but I decided against it because I am not sure why ifunc mangling was used in the first place. Maybe to maintain consistency between various multiversion attributes? I see target attribute also uses ifunc mangling (while GCC has some other mangling scheme for this attribute). As a less disruptive solution I just added an alias to the ifunc function, similar to what was done for CPU dispatch here - https://reviews.llvm.org/D67058. If the correct solution here is to remove the ifunc suffix, I can make that change instead.
https://reviews.llvm.org/D158666
Files:
clang/lib/CodeGen/CodeGenModule.cpp
clang/test/CodeGen/attr-target-clones.c
clang/test/CodeGenCXX/attr-target-clones.cpp
Index: clang/test/CodeGenCXX/attr-target-clones.cpp
===================================================================
--- clang/test/CodeGenCXX/attr-target-clones.cpp
+++ clang/test/CodeGenCXX/attr-target-clones.cpp
@@ -1,6 +1,13 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
+// Alias for ifunc
+// LINUX: @_Z10overloadedi = weak_odr alias i32 (i32), ptr @_Z10overloadedi.ifunc
+// LINUX: @_Z10overloadedPKc = weak_odr alias i32 (ptr), ptr @_Z10overloadedPKc.ifunc
+// LINUX: @_ZN1CIssE3fooEv = weak_odr alias i32 (ptr), ptr @_ZN1CIssE3fooEv.ifunc
+// LINUX: @_ZN1CIisE3fooEv = weak_odr alias i32 (ptr), ptr @_ZN1CIisE3fooEv.ifunc
+// LINUX: @_ZN1CIdfE3fooEv = weak_odr alias i32 (ptr), ptr @_ZN1CIdfE3fooEv.ifunc
+
// Overloaded ifuncs
// LINUX: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z10overloadedi.resolver
// LINUX: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (ptr), ptr @_Z10overloadedPKc.resolver
Index: clang/test/CodeGen/attr-target-clones.c
===================================================================
--- clang/test/CodeGen/attr-target-clones.c
+++ clang/test/CodeGen/attr-target-clones.c
@@ -13,6 +13,13 @@
// WINDOWS: $foo_inline = comdat any
// WINDOWS: $foo_inline2 = comdat any
+// LINUX: @foo = weak_odr alias i32 (), ptr @foo.ifunc
+// LINUX: @foo_dupes = weak_odr alias void (), ptr @foo_dupes.ifunc
+// LINUX: @unused = weak_odr alias void (), ptr @unused.ifunc
+// LINUX: @foo_inline = weak_odr alias i32 (), ptr @foo_inline.ifunc
+// LINUX: @foo_inline2 = weak_odr alias i32 (), ptr @foo_inline2.ifunc
+// LINUX: @foo_used_no_defn = weak_odr alias i32 (), ptr @foo_used_no_defn.ifunc
+
// LINUX: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver
// LINUX: @foo_dupes.ifunc = weak_odr ifunc void (), ptr @foo_dupes.resolver
// LINUX: @unused.ifunc = weak_odr ifunc void (), ptr @unused.resolver
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -4053,8 +4053,20 @@
}
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
- if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant))
+ if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
ResolverConstant = IFunc->getResolver();
+ if (FD->isTargetClonesMultiVersion()) {
+ const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
+ llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
+ std::string MangledName = getMangledNameImpl(
+ *this, GD, FD, /*OmitMultiVersionMangling=*/true);
+ auto *Alias =
+ llvm::GlobalAlias::create(DeclTy, 0, llvm::Function::WeakODRLinkage,
+ MangledName, IFunc, &getModule());
+ SetCommonAttributes(FD, Alias);
+ }
+ }
+
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D158666.552862.patch
Type: text/x-patch
Size: 3228 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230823/c1e13d9d/attachment.bin>
More information about the cfe-commits
mailing list