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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to