zsrkmyn updated this revision to Diff 218830.
zsrkmyn retitled this revision from "[clang][CodeGen] Add alias for
cpu_dispatch function with IFunc" to "[clang][CodeGen] Add alias for
cpu_dispatch function with IFunc & Fix resolver linkage type".
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D67058/new/
https://reviews.llvm.org/D67058
Files:
clang/lib/CodeGen/CodeGenModule.cpp
clang/test/CodeGen/attr-cpuspecific.c
clang/test/CodeGenCXX/attr-cpuspecific.cpp
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"
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/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2884,6 +2884,10 @@
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
+ ResolverFunc->setLinkage(llvm::Function::LinkOnceODRLinkage);
+ if (supportsCOMDAT())
+ ResolverFunc->setComdat(
+ getModule().getOrInsertComdat(ResolverFunc->getName()));
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> 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<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::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);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits