Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -2884,6 +2884,10 @@ auto *ResolverFunc = cast(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); + ResolverFunc->setLinkage(llvm::Function::LinkOnceODRLinkage); + if (supportsCOMDAT()) + ResolverFunc->setComdat( + getModule().getOrInsertComdat(ResolverFunc->getName())); SmallVector Options; const TargetInfo &Target = getTarget(); @@ -2948,6 +2952,21 @@ CodeGenFunction CGF(*this); CGF.EmitMultiVersionResolver(ResolverFunc, Options); + + if (getTarget().supportsIFunc()) { + std::string AliasName = getMangledNameImpl( + *this, GD, FD, /*OmitMultiVersionMangling=*/true); + llvm::Constant *AliasFunc = GetGlobalValue(AliasName); + if (!AliasFunc) { + 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::LinkOnceODRLinkage); + SetCommonAttributes(GD, GA); + } + } } /// If a dispatcher for the specified mangled name is not in the module, create @@ -2983,8 +3002,11 @@ llvm::Constant *Resolver = GetOrCreateLLVMFunction( MangledName + ".resolver", ResolverType, GlobalDecl{}, /*ForVTable=*/false); + auto Linkage = (FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion()) + ? llvm::Function::LinkOnceODRLinkage + : llvm::Function::ExternalLinkage; llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create( - DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule()); + DeclTy, 0, Linkage, "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); Index: clang/test/CodeGen/attr-cpuspecific.c =================================================================== --- clang/test/CodeGen/attr-cpuspecific.c +++ clang/test/CodeGen/attr-cpuspecific.c @@ -7,11 +7,27 @@ #define ATTR(X) __attribute__((X)) #endif // _MSC_VER -// Each called version should have an IFunc. -// LINUX: @SingleVersion.ifunc = ifunc void (), void ()* ()* @SingleVersion.resolver -// LINUX: @TwoVersions.ifunc = ifunc void (), void ()* ()* @TwoVersions.resolver -// LINUX: @TwoVersionsSameAttr.ifunc = ifunc void (), void ()* ()* @TwoVersionsSameAttr.resolver -// LINUX: @ThreeVersionsSameAttr.ifunc = ifunc void (), void ()* ()* @ThreeVersionsSameAttr.resolver +// Each version should have an IFunc and an alias. +// LINUX: @TwoVersions = linkonce_odr alias void (), void ()* @TwoVersions.ifunc +// LINUX: @TwoVersionsSameAttr = linkonce_odr alias void (), void ()* @TwoVersionsSameAttr.ifunc +// LINUX: @ThreeVersionsSameAttr = linkonce_odr alias void (), void ()* @ThreeVersionsSameAttr.ifunc +// LINUX: @NoSpecifics = linkonce_odr alias void (), void ()* @NoSpecifics.ifunc +// LINUX: @HasGeneric = linkonce_odr alias void (), void ()* @HasGeneric.ifunc +// LINUX: @HasParams = linkonce_odr alias void (i32, double), void (i32, double)* @HasParams.ifunc +// LINUX: @HasParamsAndReturn = linkonce_odr alias i32 (i32, double), i32 (i32, double)* @HasParamsAndReturn.ifunc +// LINUX: @GenericAndPentium = linkonce_odr alias i32 (i32, double), i32 (i32, double)* @GenericAndPentium.ifunc +// LINUX: @DispatchFirst = linkonce_odr alias i32 (), i32 ()* @DispatchFirst.ifunc + +// LINUX: @TwoVersions.ifunc = linkonce_odr ifunc void (), void ()* ()* @TwoVersions.resolver +// LINUX: @SingleVersion.ifunc = linkonce_odr ifunc void (), void ()* ()* @SingleVersion.resolver +// LINUX: @TwoVersionsSameAttr.ifunc = linkonce_odr ifunc void (), void ()* ()* @TwoVersionsSameAttr.resolver +// LINUX: @ThreeVersionsSameAttr.ifunc = linkonce_odr ifunc void (), void ()* ()* @ThreeVersionsSameAttr.resolver +// LINUX: @NoSpecifics.ifunc = linkonce_odr ifunc void (), void ()* ()* @NoSpecifics.resolver +// LINUX: @HasGeneric.ifunc = linkonce_odr ifunc void (), void ()* ()* @HasGeneric.resolver +// LINUX: @HasParams.ifunc = linkonce_odr ifunc void (i32, double), void (i32, double)* ()* @HasParams.resolver +// LINUX: @HasParamsAndReturn.ifunc = linkonce_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @HasParamsAndReturn.resolver +// LINUX: @GenericAndPentium.ifunc = linkonce_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @GenericAndPentium.resolver +// LINUX: @DispatchFirst.ifunc = linkonce_odr ifunc i32 (), i32 ()* ()* @DispatchFirst.resolver ATTR(cpu_specific(ivybridge)) void SingleVersion(void){} @@ -29,14 +45,14 @@ ATTR(cpu_dispatch(ivybridge, knl)) void TwoVersions(void); -// LINUX: define void ()* @TwoVersions.resolver() +// LINUX: define linkonce_odr void ()* @TwoVersions.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @TwoVersions.Z // LINUX: ret void ()* @TwoVersions.S // LINUX: call void @llvm.trap // LINUX: unreachable -// WINDOWS: define dso_local void @TwoVersions() +// WINDOWS: define linkonce_odr dso_local void @TwoVersions() comdat // WINDOWS: call void @__cpu_indicator_init() // WINDOWS: call void @TwoVersions.Z() // WINDOWS-NEXT: ret void @@ -82,14 +98,14 @@ // has an extra config to emit! ATTR(cpu_dispatch(ivybridge, knl, atom)) void TwoVersionsSameAttr(void); -// LINUX: define void ()* @TwoVersionsSameAttr.resolver() +// LINUX: define linkonce_odr void ()* @TwoVersionsSameAttr.resolver() // LINUX: ret void ()* @TwoVersionsSameAttr.Z // LINUX: ret void ()* @TwoVersionsSameAttr.S // LINUX: ret void ()* @TwoVersionsSameAttr.O // LINUX: call void @llvm.trap // LINUX: unreachable -// WINDOWS: define dso_local void @TwoVersionsSameAttr() +// WINDOWS: define linkonce_odr dso_local void @TwoVersionsSameAttr() comdat // WINDOWS: call void @TwoVersionsSameAttr.Z // WINDOWS-NEXT: ret void // WINDOWS: call void @TwoVersionsSameAttr.S @@ -101,7 +117,7 @@ ATTR(cpu_dispatch(atom, ivybridge, knl)) void ThreeVersionsSameAttr(void){} -// LINUX: define void ()* @ThreeVersionsSameAttr.resolver() +// LINUX: define linkonce_odr void ()* @ThreeVersionsSameAttr.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @ThreeVersionsSameAttr.Z // LINUX: ret void ()* @ThreeVersionsSameAttr.S @@ -109,7 +125,7 @@ // LINUX: call void @llvm.trap // LINUX: unreachable -// WINDOWS: define dso_local void @ThreeVersionsSameAttr() +// WINDOWS: define linkonce_odr dso_local void @ThreeVersionsSameAttr() comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: call void @ThreeVersionsSameAttr.Z // WINDOWS-NEXT: ret void @@ -123,7 +139,7 @@ // No Cpu Specific options. ATTR(cpu_dispatch(atom, ivybridge, knl)) void NoSpecifics(void); -// LINUX: define void ()* @NoSpecifics.resolver() +// LINUX: define linkonce_odr void ()* @NoSpecifics.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @NoSpecifics.Z // LINUX: ret void ()* @NoSpecifics.S @@ -131,7 +147,7 @@ // LINUX: call void @llvm.trap // LINUX: unreachable -// WINDOWS: define dso_local void @NoSpecifics() +// WINDOWS: define linkonce_odr dso_local void @NoSpecifics() comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: call void @NoSpecifics.Z // WINDOWS-NEXT: ret void @@ -144,7 +160,7 @@ ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) void HasGeneric(void); -// LINUX: define void ()* @HasGeneric.resolver() +// LINUX: define linkonce_odr void ()* @HasGeneric.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @HasGeneric.Z // LINUX: ret void ()* @HasGeneric.S @@ -152,7 +168,7 @@ // LINUX: ret void ()* @HasGeneric.A // LINUX-NOT: call void @llvm.trap -// WINDOWS: define dso_local void @HasGeneric() +// WINDOWS: define linkonce_odr dso_local void @HasGeneric() comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: call void @HasGeneric.Z // WINDOWS-NEXT: ret void @@ -166,7 +182,7 @@ ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) void HasParams(int i, double d); -// LINUX: define void (i32, double)* @HasParams.resolver() +// LINUX: define linkonce_odr void (i32, double)* @HasParams.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void (i32, double)* @HasParams.Z // LINUX: ret void (i32, double)* @HasParams.S @@ -174,7 +190,7 @@ // LINUX: ret void (i32, double)* @HasParams.A // LINUX-NOT: call void @llvm.trap -// WINDOWS: define dso_local void @HasParams(i32 %0, double %1) +// WINDOWS: define linkonce_odr dso_local void @HasParams(i32 %0, double %1) comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: call void @HasParams.Z(i32 %0, double %1) // WINDOWS-NEXT: ret void @@ -188,7 +204,7 @@ ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) int HasParamsAndReturn(int i, double d); -// LINUX: define i32 (i32, double)* @HasParamsAndReturn.resolver() +// LINUX: define linkonce_odr i32 (i32, double)* @HasParamsAndReturn.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.Z // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.S @@ -196,7 +212,7 @@ // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.A // LINUX-NOT: call void @llvm.trap -// WINDOWS: define dso_local i32 @HasParamsAndReturn(i32 %0, double %1) +// WINDOWS: define linkonce_odr dso_local i32 @HasParamsAndReturn(i32 %0, double %1) comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.Z(i32 %0, double %1) // WINDOWS-NEXT: ret i32 %[[RET]] @@ -210,14 +226,14 @@ ATTR(cpu_dispatch(atom, generic, pentium)) int GenericAndPentium(int i, double d); -// LINUX: define i32 (i32, double)* @GenericAndPentium.resolver() +// LINUX: define linkonce_odr i32 (i32, double)* @GenericAndPentium.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret i32 (i32, double)* @GenericAndPentium.O // LINUX: ret i32 (i32, double)* @GenericAndPentium.B // LINUX-NOT: ret i32 (i32, double)* @GenericAndPentium.A // LINUX-NOT: call void @llvm.trap -// WINDOWS: define dso_local i32 @GenericAndPentium(i32 %0, double %1) +// WINDOWS: define linkonce_odr dso_local i32 @GenericAndPentium(i32 %0, double %1) comdat // WINDOWS: call void @__cpu_indicator_init // WINDOWS: %[[RET:.+]] = musttail call i32 @GenericAndPentium.O(i32 %0, double %1) // WINDOWS-NEXT: ret i32 %[[RET]] @@ -228,11 +244,11 @@ ATTR(cpu_dispatch(atom, pentium)) int DispatchFirst(void); -// LINUX: define i32 ()* @DispatchFirst.resolver +// LINUX: define linkonce_odr i32 ()* @DispatchFirst.resolver // LINUX: ret i32 ()* @DispatchFirst.O // LINUX: ret i32 ()* @DispatchFirst.B -// WINDOWS: define dso_local i32 @DispatchFirst() +// WINDOWS: define linkonce_odr dso_local i32 @DispatchFirst() comdat // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.O() // WINDOWS-NEXT: ret i32 %[[RET]] // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.B() Index: clang/test/CodeGenCXX/attr-cpuspecific.cpp =================================================================== --- clang/test/CodeGenCXX/attr-cpuspecific.cpp +++ clang/test/CodeGenCXX/attr-cpuspecific.cpp @@ -13,13 +13,15 @@ s.Func(); } -// LINUX: define void (%struct.S*)* @_ZN1S4FuncEv.resolver +// LINUX: @_ZN1S4FuncEv = linkonce_odr alias void (%struct.S*), void (%struct.S*)* @_ZN1S4FuncEv.ifunc +// LINUX: @_ZN1S4FuncEv.ifunc = linkonce_odr ifunc void (%struct.S*), void (%struct.S*)* ()* @_ZN1S4FuncEv.resolver +// LINUX: define linkonce_odr void (%struct.S*)* @_ZN1S4FuncEv.resolver // LINUX: ret void (%struct.S*)* @_ZN1S4FuncEv.S // LINUX: ret void (%struct.S*)* @_ZN1S4FuncEv.O // LINUX: declare void @_ZN1S4FuncEv.S // LINUX: define linkonce_odr void @_ZN1S4FuncEv.O -// WINDOWS: define dso_local void @"?Func@S@@QEAAXXZ"(%struct.S* %0) +// WINDOWS: define linkonce_odr dso_local void @"?Func@S@@QEAAXXZ"(%struct.S* %0) comdat // WINDOWS: musttail call void @"?Func@S@@QEAAXXZ.S"(%struct.S* %0) // WINDOWS: musttail call void @"?Func@S@@QEAAXXZ.O"(%struct.S* %0) // WINDOWS: declare dso_local void @"?Func@S@@QEAAXXZ.S"