Author: Erich Keane Date: 2021-09-17T05:56:38-07:00 New Revision: e3b10525b489b604d6a1e540be78bda80afb5868
URL: https://github.com/llvm/llvm-project/commit/e3b10525b489b604d6a1e540be78bda80afb5868 DIFF: https://github.com/llvm/llvm-project/commit/e3b10525b489b604d6a1e540be78bda80afb5868.diff LOG: Make multiversioning work with internal linkage We previously made all multiversioning resolvers/ifuncs have weak ODR linkage in IR, since we NEED to emit the whole resolver every time we see a call, but it is not necessarily the place where all the definitions live. HOWEVER, when doing so, we neglected the case where the versions have internal linkage. This patch ensures we do this, so you don't get weird behavior with static functions. Added: clang/test/CodeGenCXX/multi-versioning-internal-linkage.cpp Modified: clang/lib/CodeGen/CodeGenModule.cpp clang/test/CodeGen/unique-internal-linkage-names.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b274edb8470c..9715657b4c6e 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 diff erent +// 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<FunctionDecl>(GD.getDecl()); + if (FD->getFormalLinkage() == InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + return llvm::GlobalValue::WeakODRLinkage; +} + void CodeGenModule::emitMultiVersionFunctions() { std::vector<GlobalDecl> MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -3298,7 +3311,7 @@ void CodeGenModule::emitMultiVersionFunctions() { if (TI.supportsIFunc() || FD->isTargetMultiVersion()) { ResolverFunc = cast<llvm::Function>( GetGlobalValue((getMangledName(GD) + ".resolver").str())); - ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); } else { ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD))); } @@ -3356,7 +3369,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast<llvm::Function>(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<llvm::GlobalIFunc>(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 95591de308d3..65069c049b63 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 000000000000..246599a591a7 --- /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"() _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits