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));
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));
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits