diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b274edb8470c8..9715657b4c6e1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3258,6 +3258,19 @@ TargetMVPriority(const TargetInfo &TI, return Priority; } +// Multiversion functions should be at most 'WeakODRLinkage' so that a different +// TU can forward declare the function without causing problems. Particularly +// in the cases of CPUDispatch, this causes issues. This also makes sure we +// work with internal linkage functions, so that the same function name can be +// used with internal linkage in multiple TUs. +llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, + GlobalDecl GD) { + const FunctionDecl *FD = cast(GD.getDecl()); + if (FD->getFormalLinkage() == InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + return llvm::GlobalValue::WeakODRLinkage; +} + void CodeGenModule::emitMultiVersionFunctions() { std::vector MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -3298,7 +3311,7 @@ void CodeGenModule::emitMultiVersionFunctions() { if (TI.supportsIFunc() || FD->isTargetMultiVersion()) { ResolverFunc = cast( GetGlobalValue((getMangledName(GD) + ".resolver").str())); - ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); } else { ResolverFunc = cast(GetGlobalValue(getMangledName(GD))); } @@ -3356,7 +3369,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); - ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); if (supportsCOMDAT()) ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); @@ -3433,9 +3446,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *IFunc = cast(GetOrCreateLLVMFunction( AliasName, DeclTy, GD, /*ForVTable=*/false, /*DontDefer=*/true, /*IsThunk=*/false, llvm::AttributeList(), NotForDefinition)); - auto *GA = llvm::GlobalAlias::create( - DeclTy, 0, getFunctionLinkage(GD), AliasName, IFunc, &getModule()); - GA->setLinkage(llvm::Function::WeakODRLinkage); + auto *GA = llvm::GlobalAlias::create(DeclTy, 0, + getMultiversionLinkage(*this, GD), + AliasName, IFunc, &getModule()); SetCommonAttributes(GD, GA); } } @@ -3474,8 +3487,9 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver( llvm::Constant *Resolver = GetOrCreateLLVMFunction( MangledName + ".resolver", ResolverType, GlobalDecl{}, /*ForVTable=*/false); - llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create( - DeclTy, 0, llvm::Function::WeakODRLinkage, "", Resolver, &getModule()); + llvm::GlobalIFunc *GIF = + llvm::GlobalIFunc::create(DeclTy, 0, getMultiversionLinkage(*this, GD), + "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); diff --git a/clang/test/CodeGen/unique-internal-linkage-names.cpp b/clang/test/CodeGen/unique-internal-linkage-names.cpp index 95591de308d37..65069c049b637 100644 --- a/clang/test/CodeGen/unique-internal-linkage-names.cpp +++ b/clang/test/CodeGen/unique-internal-linkage-names.cpp @@ -59,7 +59,7 @@ void test() { // PLAIN: @_ZN12_GLOBAL__N_16anon_mE = internal global // PLAIN: define internal i32 @_ZL3foov() // PLAIN: define internal i32 @_ZN12_GLOBAL__N_14getMEv -// PLAIN: define weak_odr i32 ()* @_ZL4mverv.resolver() +// PLAIN: define internal i32 ()* @_ZL4mverv.resolver() // PLAIN: define internal void @_ZN12_GLOBAL__N_11AC1Ev // PLAIN: define internal void @_ZN12_GLOBAL__N_11AD1Ev // PLAIN: define internal i32 @_ZL4mverv() @@ -70,7 +70,7 @@ void test() { // UNIQUE: @_ZN12_GLOBAL__N_16anon_mE = internal global // UNIQUE: define internal i32 @_ZL3foov.[[MODHASH:__uniq.[0-9]+]]() #[[#ATTR:]] { // UNIQUE: define internal i32 @_ZN12_GLOBAL__N_14getMEv.[[MODHASH]] -// UNIQUE: define weak_odr i32 ()* @_ZL4mverv.[[MODHASH]].resolver() +// UNIQUE: define internal i32 ()* @_ZL4mverv.[[MODHASH]].resolver() // UNIQUE: define internal void @_ZN12_GLOBAL__N_11AC1Ev.__uniq.68358509610070717889884130747296293671 // UNIQUE: define internal void @_ZN12_GLOBAL__N_11AD1Ev.__uniq.68358509610070717889884130747296293671 // UNIQUE: define internal i32 @_ZL4mverv.[[MODHASH]]() diff --git a/clang/test/CodeGenCXX/multi-versioning-internal-linkage.cpp b/clang/test/CodeGenCXX/multi-versioning-internal-linkage.cpp new file mode 100644 index 0000000000000..246599a591a7f --- /dev/null +++ b/clang/test/CodeGenCXX/multi-versioning-internal-linkage.cpp @@ -0,0 +1,49 @@ +// 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 + +__attribute__((target("default"))) static int static_target() { + return 0; +} +__attribute__((target("arch=sandybridge"))) static int static_target() { + return 1; +} + +__attribute__((cpu_dispatch(atom, generic))) static int static_dispatch() {} + +namespace { +int __attribute__((target("default"))) anon_target() { + return 0; +} +int __attribute__((target("arch=sandybridge"))) anon_target() { + return 1; +} +__attribute__((cpu_dispatch(atom, generic))) static int anon_dispatch() {} +} + + + +int usage() { + return static_target() + anon_target() + static_dispatch() + anon_dispatch(); +} + +// Ensure that these are all 'internal'. Windows doesn't have ifuncs or aliases, +// since Windows doesn't support ifuncs. +// aliases: +// LINUX: @_ZL15static_dispatchv = internal alias i32 (), i32 ()* @_ZL15static_dispatchv.ifunc +// LINUX: @_ZN12_GLOBAL__N_113anon_dispatchEv = internal alias i32 (), i32 ()* @_ZN12_GLOBAL__N_113anon_dispatchEv.ifunc + +// ifuncs: +// LINUX: @_ZL15static_dispatchv.ifunc = internal ifunc i32 (), i32 ()* ()* @_ZL15static_dispatchv.resolver +// LINUX: @_ZN12_GLOBAL__N_113anon_dispatchEv.ifunc = internal ifunc i32 (), i32 ()* ()* @_ZN12_GLOBAL__N_113anon_dispatchEv.resolver +// LINUX: @_ZL13static_targetv.ifunc = internal ifunc i32 (), i32 ()* ()* @_ZL13static_targetv.resolver +// LINUX: @_ZN12_GLOBAL__N_111anon_targetEv.ifunc = internal ifunc i32 (), i32 ()* ()* @_ZN12_GLOBAL__N_111anon_targetEv.resolver + +// resolvers: +// LINUX: define internal i32 ()* @_ZL15static_dispatchv.resolver() +// WINDOWS: define internal i32 @"?static_dispatch@@YAHXZ"() +// LINUX: define internal i32 ()* @_ZN12_GLOBAL__N_113anon_dispatchEv.resolver() +// WINDOWS: define internal i32 @"?anon_dispatch@?A0x7F72A7FB@@YAHXZ"() +// LINUX: define internal i32 ()* @_ZL13static_targetv.resolver() +// WINDOWS: define internal i32 @"?static_target@@YAHXZ.resolver"() +// LINUX: define internal i32 ()* @_ZN12_GLOBAL__N_111anon_targetEv.resolver() +// WINDOWS: define internal i32 @"?anon_target@?A0x7F72A7FB@@YAHXZ.resolver"()