diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3593,16 +3593,28 @@ CGF.EmitMultiVersionResolver(ResolverFunc, Options); if (getTarget().supportsIFunc()) { + llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD); + auto *IFunc = cast( + GetOrCreateMultiVersionResolver(GD, DeclTy, FD)); + + // Fix up function declarations that were created for cpu_specific before + // cpu_dispatch was known + if (!dyn_cast(IFunc)) { + assert(cast(IFunc)->isDeclaration()); + auto *GI = llvm::GlobalIFunc::create(DeclTy, 0, Linkage, "", ResolverFunc, + &getModule()); + GI->takeName(IFunc); + IFunc->replaceAllUsesWith(GI); + IFunc->eraseFromParent(); + IFunc = GI; + } + 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, - getMultiversionLinkage(*this, GD), - AliasName, IFunc, &getModule()); + auto *GA = llvm::GlobalAlias::create(DeclTy, 0, Linkage, AliasName, IFunc, + &getModule()); SetCommonAttributes(GD, GA); } } @@ -3650,7 +3662,9 @@ } } - if (getTarget().supportsIFunc()) { + // For cpu_specific, don't create an ifunc yet because we don't know if the + // cpu_dispatch will be emitted in this translation unit. + if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) { llvm::Type *ResolverType = llvm::FunctionType::get( llvm::PointerType::get( DeclTy, getContext().getTargetAddressSpace(FD->getType())), diff --git a/clang/test/CodeGen/attr-cpuspecific.c b/clang/test/CodeGen/attr-cpuspecific.c --- a/clang/test/CodeGen/attr-cpuspecific.c +++ b/clang/test/CodeGen/attr-cpuspecific.c @@ -8,6 +8,7 @@ #endif // _MSC_VER // Each version should have an IFunc and an alias. +// LINUX: @SingleVersion = weak_odr alias void (), void ()* @SingleVersion.ifunc // LINUX: @TwoVersions = weak_odr alias void (), void ()* @TwoVersions.ifunc // LINUX: @TwoVersionsSameAttr = weak_odr alias void (), void ()* @TwoVersionsSameAttr.ifunc // LINUX: @ThreeVersionsSameAttr = weak_odr alias void (), void ()* @ThreeVersionsSameAttr.ifunc @@ -18,8 +19,8 @@ // LINUX: @GenericAndPentium = weak_odr alias i32 (i32, double), i32 (i32, double)* @GenericAndPentium.ifunc // LINUX: @DispatchFirst = weak_odr alias i32 (), i32 ()* @DispatchFirst.ifunc -// LINUX: @TwoVersions.ifunc = weak_odr ifunc void (), void ()* ()* @TwoVersions.resolver // LINUX: @SingleVersion.ifunc = weak_odr ifunc void (), void ()* ()* @SingleVersion.resolver +// LINUX: @TwoVersions.ifunc = weak_odr ifunc void (), void ()* ()* @TwoVersions.resolver // LINUX: @TwoVersionsSameAttr.ifunc = weak_odr ifunc void (), void ()* ()* @TwoVersionsSameAttr.resolver // LINUX: @ThreeVersionsSameAttr.ifunc = weak_odr ifunc void (), void ()* ()* @ThreeVersionsSameAttr.resolver // LINUX: @NoSpecifics.ifunc = weak_odr ifunc void (), void ()* ()* @NoSpecifics.resolver @@ -34,6 +35,21 @@ // LINUX: define{{.*}} void @SingleVersion.S() #[[S:[0-9]+]] // WINDOWS: define dso_local void @SingleVersion.S() #[[S:[0-9]+]] +ATTR(cpu_dispatch(ivybridge)) +void SingleVersion(void); +// LINUX: define weak_odr void ()* @SingleVersion.resolver() +// LINUX: call void @__cpu_indicator_init +// LINUX: ret void ()* @SingleVersion.S +// LINUX: call void @llvm.trap +// LINUX: unreachable + +// WINDOWS: define weak_odr dso_local void @SingleVersion() comdat +// WINDOWS: call void @__cpu_indicator_init() +// WINDOWS: call void @SingleVersion.S() +// WINDOWS-NEXT: ret void +// WINDOWS: call void @llvm.trap +// WINDOWS: unreachable + ATTR(cpu_specific(ivybridge)) void NotCalled(void){} // LINUX: define{{.*}} void @NotCalled.S() #[[S]] @@ -80,6 +96,10 @@ // CHECK: define {{.*}}void @ThreeVersionsSameAttr.S() #[[S]] // CHECK: define {{.*}}void @ThreeVersionsSameAttr.Z() #[[K]] +ATTR(cpu_specific(knl)) +int CpuSpecificNoDispatch(void) { return 1; } +// CHECK: define {{.*}}i32 @CpuSpecificNoDispatch.Z() #[[K:[0-9]+]] + void usages(void) { SingleVersion(); // LINUX: @SingleVersion.ifunc() @@ -93,6 +113,9 @@ ThreeVersionsSameAttr(); // LINUX: @ThreeVersionsSameAttr.ifunc() // WINDOWS: @ThreeVersionsSameAttr() + CpuSpecificNoDispatch(); + // LINUX: @CpuSpecificNoDispatch.ifunc() + // WINDOWS: @CpuSpecificNoDispatch() } // has an extra config to emit!