]> granicus.if.org Git - clang/commitdiff
[CodeGen] Add alias for cpu_dispatch function with IFunc & Fix resolver linkage type
authorFangrui Song <maskray@google.com>
Wed, 11 Sep 2019 01:54:48 +0000 (01:54 +0000)
committerFangrui Song <maskray@google.com>
Wed, 11 Sep 2019 01:54:48 +0000 (01:54 +0000)
Multi-versioned functions defined by cpu_dispatch and implemented with IFunc
can not be called outside the translation units where they are defined due to
lack of symbols. This patch add function aliases for these functions and thus
make them visible outside.

Differential Revision: https://reviews.llvm.org/D67058
Patch by Senran Zhang

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371586 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
lib/CodeGen/CodeGenModule.cpp
test/CodeGen/attr-cpuspecific.c
test/CodeGen/attr-target-mv-func-ptrs.c
test/CodeGen/attr-target-mv-va-args.c
test/CodeGen/attr-target-mv.c
test/CodeGenCXX/attr-cpuspecific.cpp
test/CodeGenCXX/attr-target-mv-diff-ns.cpp
test/CodeGenCXX/attr-target-mv-inalloca.cpp
test/CodeGenCXX/attr-target-mv-member-funcs.cpp
test/CodeGenCXX/attr-target-mv-modules.cpp
test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
test/CodeGenCXX/attr-target-mv-overloads.cpp

index eedf70b8d50d4f0c0ad8cc19cc136bcaa635b5bb..be7dfc97a98ad9ca301a5875cf5fe3048d127171 100644 (file)
@@ -2836,11 +2836,13 @@ void CodeGenModule::emitMultiVersionFunctions() {
     llvm::Function *ResolverFunc;
     const TargetInfo &TI = getTarget();
 
-    if (TI.supportsIFunc() || FD->isTargetMultiVersion())
+    if (TI.supportsIFunc() || FD->isTargetMultiVersion()) {
       ResolverFunc = cast<llvm::Function>(
           GetGlobalValue((getMangledName(GD) + ".resolver").str()));
-    else
+      ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage);
+    } else {
       ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD)));
+    }
 
     if (supportsCOMDAT())
       ResolverFunc->setComdat(
@@ -2884,6 +2886,10 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
 
   auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
       ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
+  ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage);
+  if (supportsCOMDAT())
+    ResolverFunc->setComdat(
+        getModule().getOrInsertComdat(ResolverFunc->getName()));
 
   SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
   const TargetInfo &Target = getTarget();
@@ -2948,6 +2954,21 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
 
   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::WeakODRLinkage);
+      SetCommonAttributes(GD, GA);
+    }
+  }
 }
 
 /// If a dispatcher for the specified mangled name is not in the module, create
@@ -2984,7 +3005,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(
         MangledName + ".resolver", ResolverType, GlobalDecl{},
         /*ForVTable=*/false);
     llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
-        DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
+        DeclTy, 0, llvm::Function::WeakODRLinkage, "", Resolver, &getModule());
     GIF->setName(ResolverName);
     SetCommonAttributes(FD, GIF);
 
index 744af1454a974a34a5997afbdb8dd6fa1b0a843d..e249c87dfb46231ab43125048125990be1d772ec 100644 (file)
@@ -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 = 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
+// LINUX: @NoSpecifics = weak_odr alias void (), void ()* @NoSpecifics.ifunc
+// LINUX: @HasGeneric = weak_odr alias void (), void ()* @HasGeneric.ifunc
+// LINUX: @HasParams = weak_odr alias void (i32, double), void (i32, double)* @HasParams.ifunc
+// LINUX: @HasParamsAndReturn = weak_odr alias i32 (i32, double), i32 (i32, double)* @HasParamsAndReturn.ifunc
+// 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: @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
+// LINUX: @HasGeneric.ifunc = weak_odr ifunc void (), void ()* ()* @HasGeneric.resolver
+// LINUX: @HasParams.ifunc = weak_odr ifunc void (i32, double), void (i32, double)* ()* @HasParams.resolver
+// LINUX: @HasParamsAndReturn.ifunc = weak_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @HasParamsAndReturn.resolver
+// LINUX: @GenericAndPentium.ifunc = weak_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @GenericAndPentium.resolver
+// LINUX: @DispatchFirst.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @DispatchFirst.resolver
 
 ATTR(cpu_specific(ivybridge))
 void SingleVersion(void){}
@@ -29,14 +45,14 @@ void TwoVersions(void);
 
 ATTR(cpu_dispatch(ivybridge, knl))
 void TwoVersions(void);
-// LINUX: define void ()* @TwoVersions.resolver()
+// LINUX: define weak_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 weak_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 @@ void usages() {
 // has an extra config to emit!
 ATTR(cpu_dispatch(ivybridge, knl, atom))
 void TwoVersionsSameAttr(void);
-// LINUX: define void ()* @TwoVersionsSameAttr.resolver()
+// LINUX: define weak_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 weak_odr dso_local void @TwoVersionsSameAttr() comdat
 // WINDOWS: call void @TwoVersionsSameAttr.Z
 // WINDOWS-NEXT: ret void
 // WINDOWS: call void @TwoVersionsSameAttr.S
@@ -101,7 +117,7 @@ void TwoVersionsSameAttr(void);
 
 ATTR(cpu_dispatch(atom, ivybridge, knl))
 void ThreeVersionsSameAttr(void){}
-// LINUX: define void ()* @ThreeVersionsSameAttr.resolver()
+// LINUX: define weak_odr void ()* @ThreeVersionsSameAttr.resolver()
 // LINUX: call void @__cpu_indicator_init
 // LINUX: ret void ()* @ThreeVersionsSameAttr.Z
 // LINUX: ret void ()* @ThreeVersionsSameAttr.S
@@ -109,7 +125,7 @@ void ThreeVersionsSameAttr(void){}
 // LINUX: call void @llvm.trap
 // LINUX: unreachable
 
-// WINDOWS: define dso_local void @ThreeVersionsSameAttr()
+// WINDOWS: define weak_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 @@ void ThreeVersionsSameAttr(void){}
 // No Cpu Specific options.
 ATTR(cpu_dispatch(atom, ivybridge, knl))
 void NoSpecifics(void);
-// LINUX: define void ()* @NoSpecifics.resolver()
+// LINUX: define weak_odr void ()* @NoSpecifics.resolver()
 // LINUX: call void @__cpu_indicator_init
 // LINUX: ret void ()* @NoSpecifics.Z
 // LINUX: ret void ()* @NoSpecifics.S
@@ -131,7 +147,7 @@ void NoSpecifics(void);
 // LINUX: call void @llvm.trap
 // LINUX: unreachable
 
-// WINDOWS: define dso_local void @NoSpecifics()
+// WINDOWS: define weak_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 @@ void NoSpecifics(void);
 
 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
 void HasGeneric(void);
-// LINUX: define void ()* @HasGeneric.resolver()
+// LINUX: define weak_odr void ()* @HasGeneric.resolver()
 // LINUX: call void @__cpu_indicator_init
 // LINUX: ret void ()* @HasGeneric.Z
 // LINUX: ret void ()* @HasGeneric.S
@@ -152,7 +168,7 @@ void HasGeneric(void);
 // LINUX: ret void ()* @HasGeneric.A
 // LINUX-NOT: call void @llvm.trap
 
-// WINDOWS: define dso_local void @HasGeneric()
+// WINDOWS: define weak_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 @@ void HasGeneric(void);
 
 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
 void HasParams(int i, double d);
-// LINUX: define void (i32, double)* @HasParams.resolver()
+// LINUX: define weak_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 @@ void HasParams(int i, double d);
 // 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 weak_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 @@ void HasParams(int i, double d);
 
 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
 int HasParamsAndReturn(int i, double d);
-// LINUX: define i32 (i32, double)* @HasParamsAndReturn.resolver()
+// LINUX: define weak_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 @@ int HasParamsAndReturn(int i, double d);
 // 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 weak_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 @@ int HasParamsAndReturn(int i, double d);
 
 ATTR(cpu_dispatch(atom, generic, pentium))
 int GenericAndPentium(int i, double d);
-// LINUX: define i32 (i32, double)* @GenericAndPentium.resolver()
+// LINUX: define weak_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 weak_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 @@ int GenericAndPentium(int i, double d);
 
 ATTR(cpu_dispatch(atom, pentium))
 int DispatchFirst(void);
-// LINUX: define i32 ()* @DispatchFirst.resolver
+// LINUX: define weak_odr i32 ()* @DispatchFirst.resolver
 // LINUX: ret i32 ()* @DispatchFirst.O
 // LINUX: ret i32 ()* @DispatchFirst.B
 
-// WINDOWS: define dso_local i32 @DispatchFirst()
+// WINDOWS: define weak_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 d1ff80050c1474a226a2109c8cc27fb87d5a4e75..4361a7aeb980f415800fc5c462add22e60d4ab2e 100644 (file)
@@ -17,7 +17,7 @@ int bar() {
   return Free(1) + Free(2);
 }
 
-// LINUX: @foo.ifunc = ifunc i32 (i32), i32 (i32)* ()* @foo.resolver
+// LINUX: @foo.ifunc = weak_odr ifunc i32 (i32), i32 (i32)* ()* @foo.resolver
 // LINUX: define i32 @foo.sse4.2(
 // LINUX: ret i32 0
 // LINUX: define i32 @foo.arch_ivybridge(
index ac13e6452de509f38b43a09c6bca5af4d9a0322b..9d51d090b197b45b864a398e41dd97b14d557aa0 100644 (file)
@@ -9,7 +9,7 @@ int bar() {
   return foo(1, 'a', 1.1) + foo(2, 2.2, "asdf");
 }
 
-// LINUX: @foo.ifunc = ifunc i32 (i32, ...), i32 (i32, ...)* ()* @foo.resolver
+// LINUX: @foo.ifunc = weak_odr ifunc i32 (i32, ...), i32 (i32, ...)* ()* @foo.resolver
 // LINUX: define i32 @foo.sse4.2(i32 %i, ...)
 // LINUX: ret i32 0
 // LINUX: define i32 @foo.arch_ivybridge(i32 %i, ...)
@@ -20,7 +20,7 @@ int bar() {
 // LINUX: call i32 (i32, ...) @foo.ifunc(i32 1, i32 97, double
 // LINUX: call i32 (i32, ...) @foo.ifunc(i32 2, double 2.2{{[0-9Ee+]+}}, i8* getelementptr inbounds
 
-// LINUX: define i32 (i32, ...)* @foo.resolver() comdat
+// LINUX: define weak_odr i32 (i32, ...)* @foo.resolver() comdat
 // LINUX: ret i32 (i32, ...)* @foo.arch_sandybridge
 // LINUX: ret i32 (i32, ...)* @foo.arch_ivybridge
 // LINUX: ret i32 (i32, ...)* @foo.sse4.2
@@ -37,7 +37,7 @@ int bar() {
 // WINDOWS: call i32 (i32, ...) @foo.resolver(i32 1, i32 97, double
 // WINDOWS: call i32 (i32, ...) @foo.resolver(i32 2, double 2.2{{[0-9Ee+]+}}, i8* getelementptr inbounds
 
-// WINDOWS: define dso_local i32 @foo.resolver(i32 %0, ...) comdat
+// WINDOWS: define weak_odr dso_local i32 @foo.resolver(i32 %0, ...) comdat
 // WINDOWS: musttail call i32 (i32, ...) @foo.arch_sandybridge
 // WINDOWS: musttail call i32 (i32, ...) @foo.arch_ivybridge
 // WINDOWS: musttail call i32 (i32, ...) @foo.sse4.2
index 115432f011f341b3edfc54cb1c02f98864b7dcd0..c0c3de5f991a25c5ded20304a390877789612790 100644 (file)
@@ -47,12 +47,12 @@ void bar5() {
   fwd_decl_avx();
 }
 
-// LINUX: @foo.ifunc = ifunc i32 (), i32 ()* ()* @foo.resolver
-// LINUX: @foo_inline.ifunc = ifunc i32 (), i32 ()* ()* @foo_inline.resolver
-// LINUX: @foo_decls.ifunc = ifunc void (), void ()* ()* @foo_decls.resolver
-// LINUX: @foo_multi.ifunc = ifunc void (i32, double), void (i32, double)* ()* @foo_multi.resolver
-// LINUX: @fwd_decl_default.ifunc = ifunc i32 (), i32 ()* ()* @fwd_decl_default.resolver
-// LINUX: @fwd_decl_avx.ifunc = ifunc i32 (), i32 ()* ()* @fwd_decl_avx.resolver
+// LINUX: @foo.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo.resolver
+// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline.resolver
+// LINUX: @foo_decls.ifunc = weak_odr ifunc void (), void ()* ()* @foo_decls.resolver
+// LINUX: @foo_multi.ifunc = weak_odr ifunc void (i32, double), void (i32, double)* ()* @foo_multi.resolver
+// LINUX: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @fwd_decl_default.resolver
+// LINUX: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @fwd_decl_avx.resolver
 
 // LINUX: define i32 @foo.sse4.2()
 // LINUX: ret i32 0
@@ -72,14 +72,14 @@ void bar5() {
 // WINDOWS: define dso_local i32 @bar()
 // WINDOWS: call i32 @foo.resolver()
 
-// LINUX: define i32 ()* @foo.resolver() comdat
+// LINUX: define weak_odr i32 ()* @foo.resolver() comdat
 // LINUX: call void @__cpu_indicator_init()
 // LINUX: ret i32 ()* @foo.arch_sandybridge
 // LINUX: ret i32 ()* @foo.arch_ivybridge
 // LINUX: ret i32 ()* @foo.sse4.2
 // LINUX: ret i32 ()* @foo
 
-// WINDOWS: define dso_local i32 @foo.resolver() comdat
+// WINDOWS: define weak_odr dso_local i32 @foo.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
 // WINDOWS: call i32 @foo.arch_sandybridge
 // WINDOWS: call i32 @foo.arch_ivybridge
@@ -92,14 +92,14 @@ void bar5() {
 // WINDOWS: define dso_local i32 @bar2()
 // WINDOWS: call i32 @foo_inline.resolver()
 
-// LINUX: define i32 ()* @foo_inline.resolver() comdat
+// LINUX: define weak_odr i32 ()* @foo_inline.resolver() comdat
 // LINUX: call void @__cpu_indicator_init()
 // LINUX: ret i32 ()* @foo_inline.arch_sandybridge
 // LINUX: ret i32 ()* @foo_inline.arch_ivybridge
 // LINUX: ret i32 ()* @foo_inline.sse4.2
 // LINUX: ret i32 ()* @foo_inline
 
-// WINDOWS: define dso_local i32 @foo_inline.resolver() comdat
+// WINDOWS: define weak_odr dso_local i32 @foo_inline.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
 // WINDOWS: call i32 @foo_inline.arch_sandybridge
 // WINDOWS: call i32 @foo_inline.arch_ivybridge
@@ -112,11 +112,11 @@ void bar5() {
 // WINDOWS: define dso_local void @bar3()
 // WINDOWS: call void @foo_decls.resolver()
 
-// LINUX: define void ()* @foo_decls.resolver() comdat
+// LINUX: define weak_odr void ()* @foo_decls.resolver() comdat
 // LINUX: ret void ()* @foo_decls.sse4.2
 // LINUX: ret void ()* @foo_decls
 
-// WINDOWS: define dso_local void @foo_decls.resolver() comdat
+// WINDOWS: define weak_odr dso_local void @foo_decls.resolver() comdat
 // WINDOWS: call void @foo_decls.sse4.2
 // WINDOWS: call void @foo_decls
 
@@ -126,7 +126,7 @@ void bar5() {
 // WINDOWS: define dso_local void @bar4()
 // WINDOWS: call void @foo_multi.resolver(i32 1, double 5.{{[0+e]*}})
 
-// LINUX: define void (i32, double)* @foo_multi.resolver() comdat
+// LINUX: define weak_odr void (i32, double)* @foo_multi.resolver() comdat
 // LINUX: and i32 %{{.*}}, 4352
 // LINUX: icmp eq i32 %{{.*}}, 4352
 // LINUX: ret void (i32, double)* @foo_multi.fma4_sse4.2
@@ -139,7 +139,7 @@ void bar5() {
 // LINUX: ret void (i32, double)* @foo_multi.avx_sse4.2
 // LINUX: ret void (i32, double)* @foo_multi
 
-// WINDOWS: define dso_local void @foo_multi.resolver(i32 %0, double %1) comdat
+// WINDOWS: define weak_odr dso_local void @foo_multi.resolver(i32 %0, double %1) comdat
 // WINDOWS: and i32 %{{.*}}, 4352
 // WINDOWS: icmp eq i32 %{{.*}}, 4352
 // WINDOWS: call void @foo_multi.fma4_sse4.2(i32 %0, double %1)
@@ -178,18 +178,18 @@ void bar5() {
 // WINDOWS: call i32 @fwd_decl_default.resolver()
 // WINDOWS: call i32 @fwd_decl_avx.resolver()
 
-// LINUX: define i32 ()* @fwd_decl_default.resolver() comdat
+// LINUX: define weak_odr i32 ()* @fwd_decl_default.resolver() comdat
 // LINUX: call void @__cpu_indicator_init()
 // LINUX: ret i32 ()* @fwd_decl_default
-// LINUX: define i32 ()* @fwd_decl_avx.resolver() comdat
+// LINUX: define weak_odr i32 ()* @fwd_decl_avx.resolver() comdat
 // LINUX: call void @__cpu_indicator_init()
 // LINUX: ret i32 ()* @fwd_decl_avx.avx
 // LINUX: ret i32 ()* @fwd_decl_avx
 
-// WINDOWS: define dso_local i32 @fwd_decl_default.resolver() comdat
+// WINDOWS: define weak_odr dso_local i32 @fwd_decl_default.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
 // WINDOWS: call i32 @fwd_decl_default
-// WINDOWS: define dso_local i32 @fwd_decl_avx.resolver() comdat
+// WINDOWS: define weak_odr dso_local i32 @fwd_decl_avx.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
 // WINDOWS: call i32 @fwd_decl_avx.avx
 // WINDOWS: call i32 @fwd_decl_avx
index 7601859df241209713256eaa065ce373d6c8b8a1..efe6921ec11e4cbe5fee2d259633d203c759d617 100644 (file)
@@ -13,13 +13,15 @@ void foo() {
   s.Func();
 }
 
-// LINUX: define void (%struct.S*)* @_ZN1S4FuncEv.resolver
+// LINUX: @_ZN1S4FuncEv = weak_odr alias void (%struct.S*), void (%struct.S*)* @_ZN1S4FuncEv.ifunc
+// LINUX: @_ZN1S4FuncEv.ifunc = weak_odr ifunc void (%struct.S*), void (%struct.S*)* ()* @_ZN1S4FuncEv.resolver
+// LINUX: define weak_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 weak_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 4d4841d49c9865ab0b7c32403d28a60ae4462974..3c47af9bb9ca3d750afb656ee9004cb124a24847 100644 (file)
@@ -18,8 +18,8 @@ int bar() {
   return foo(1) + ns::foo(2);
 }
 
-// LINUX: @_Z3fooi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_Z3fooi.resolver
-// LINUX: @_ZN2ns3fooEi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_ZN2ns3fooEi.resolver
+// LINUX: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), i32 (i32)* ()* @_Z3fooi.resolver
+// LINUX: @_ZN2ns3fooEi.ifunc = weak_odr ifunc i32 (i32), i32 (i32)* ()* @_ZN2ns3fooEi.resolver
 
 // LINUX: define i32 @_Z3fooi.sse4.2(i32 %0)
 // LINUX: ret i32 0
@@ -57,25 +57,25 @@ int bar() {
 // WINDOWS: call i32 @"?foo@@YAHH@Z.resolver"(i32 1)
 // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.resolver"(i32 2)
 
-// LINUX: define i32 (i32)* @_Z3fooi.resolver() comdat
+// LINUX: define weak_odr i32 (i32)* @_Z3fooi.resolver() comdat
 // LINUX: ret i32 (i32)* @_Z3fooi.arch_sandybridge
 // LINUX: ret i32 (i32)* @_Z3fooi.arch_ivybridge
 // LINUX: ret i32 (i32)* @_Z3fooi.sse4.2
 // LINUX: ret i32 (i32)* @_Z3fooi
 
-// WINDOWS: define dso_local i32 @"?foo@@YAHH@Z.resolver"(i32 %0) comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo@@YAHH@Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo@@YAHH@Z.arch_sandybridge"(i32 %0)
 // WINDOWS: call i32 @"?foo@@YAHH@Z.arch_ivybridge"(i32 %0)
 // WINDOWS: call i32 @"?foo@@YAHH@Z.sse4.2"(i32 %0)
 // WINDOWS: call i32 @"?foo@@YAHH@Z"(i32 %0)
 
-// LINUX: define i32 (i32)* @_ZN2ns3fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (i32)* @_ZN2ns3fooEi.resolver() comdat
 // LINUX: ret i32 (i32)* @_ZN2ns3fooEi.arch_sandybridge
 // LINUX: ret i32 (i32)* @_ZN2ns3fooEi.arch_ivybridge
 // LINUX: ret i32 (i32)* @_ZN2ns3fooEi.sse4.2
 // LINUX: ret i32 (i32)* @_ZN2ns3fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@ns@@YAHH@Z.resolver"(i32 %0) comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo@ns@@YAHH@Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.arch_sandybridge"(i32 %0)
 // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.arch_ivybridge"(i32 %0)
 // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.sse4.2"(i32 %0)
index 1fb2b11da347ae9d094988dd452bf9f2fa5e129f..a611587b56f72728d58a24413efb5585b2c69df1 100644 (file)
@@ -41,7 +41,7 @@ void usage() {
 // WINDOWS: %[[ARGMEM:[0-9a-zA-Z]+]] = alloca inalloca <{ %struct.Foo }>
 // WINDOWS: %[[CALL:[0-9a-zA-Z]+]] = call i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* inalloca %[[ARGMEM]])
 
-// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* %0)
+// WINDOWS: define weak_odr dso_local i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* %0)
 // WINDOWS: %[[RET:[0-9a-zA-Z]+]] = musttail call i32 @"?bar@@YAHUFoo@@@Z.arch_ivybridge"(<{ %struct.Foo }>* %0)
 // WINDOWS-NEXT: ret i32 %[[RET]]
 // WINDOWS: %[[RET:[0-9a-zA-Z]+]] = musttail call i32 @"?bar@@YAHUFoo@@@Z.sse4.2"(<{ %struct.Foo }>* %0)
@@ -72,7 +72,7 @@ void usage() {
 // WINDOWS64: %[[ARG:[0-9a-zA-Z.]+]] = alloca %struct.Foo
 // WINDOWS64: %[[CALL:[0-9a-zA-Z]+]] = call i32 @"?bar@@YAHUFoo@@@Z.resolver"(%struct.Foo* %[[ARG]])
 
-// WINDOWS64: define dso_local i32 @"?bar@@YAHUFoo@@@Z.resolver"(%struct.Foo* %0)
+// WINDOWS64: define weak_odr dso_local i32 @"?bar@@YAHUFoo@@@Z.resolver"(%struct.Foo* %0)
 // WINDOWS64: %[[RET:[0-9a-zA-Z]+]] = musttail call i32 @"?bar@@YAHUFoo@@@Z.arch_ivybridge"(%struct.Foo* %0)
 // WINDOWS64-NEXT: ret i32 %[[RET]]
 // WINDOWS64: %[[RET:[0-9a-zA-Z]+]] = musttail call i32 @"?bar@@YAHUFoo@@@Z.sse4.2"(%struct.Foo* %0)
index 6a8aa8cfa7d04e3291c3ec9471e78cdd06b4b274..692a250d839384e4beede7402c17cf3d5e713b89 100644 (file)
@@ -65,13 +65,13 @@ int templ_use() {
   return a.foo(1) + b.foo(2);
 }
 
-// LINUX: @_ZN1SaSERKS_.ifunc = ifunc %struct.S* (%struct.S*, %struct.S*), %struct.S* (%struct.S*, %struct.S*)* ()* @_ZN1SaSERKS_.resolver
-// LINUX: @_ZNK9ConvertTocv1SEv.ifunc = ifunc void (%struct.ConvertTo*), void (%struct.ConvertTo*)* ()* @_ZNK9ConvertTocv1SEv.resolver
-// LINUX: @_ZN1S3fooEi.ifunc = ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
-// LINUX: @_ZN2S23fooEi.ifunc = ifunc i32 (%struct.S2*, i32), i32 (%struct.S2*, i32)* ()* @_ZN2S23fooEi.resolver
+// LINUX: @_ZN1SaSERKS_.ifunc = weak_odr ifunc %struct.S* (%struct.S*, %struct.S*), %struct.S* (%struct.S*, %struct.S*)* ()* @_ZN1SaSERKS_.resolver
+// LINUX: @_ZNK9ConvertTocv1SEv.ifunc = weak_odr ifunc void (%struct.ConvertTo*), void (%struct.ConvertTo*)* ()* @_ZNK9ConvertTocv1SEv.resolver
+// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
+// LINUX: @_ZN2S23fooEi.ifunc = weak_odr ifunc i32 (%struct.S2*, i32), i32 (%struct.S2*, i32)* ()* @_ZN2S23fooEi.resolver
 // Templates:
-// LINUX: @_ZN5templIiE3fooEi.ifunc = ifunc i32 (%struct.templ*, i32), i32 (%struct.templ*, i32)* ()* @_ZN5templIiE3fooEi.resolver
-// LINUX: @_ZN5templIdE3fooEi.ifunc = ifunc i32 (%struct.templ.0*, i32), i32 (%struct.templ.0*, i32)* ()* @_ZN5templIdE3fooEi.resolver
+// LINUX: @_ZN5templIiE3fooEi.ifunc = weak_odr ifunc i32 (%struct.templ*, i32), i32 (%struct.templ*, i32)* ()* @_ZN5templIiE3fooEi.resolver
+// LINUX: @_ZN5templIdE3fooEi.ifunc = weak_odr ifunc i32 (%struct.templ.0*, i32), i32 (%struct.templ.0*, i32)* ()* @_ZN5templIdE3fooEi.resolver
 
 // LINUX: define i32 @_Z3barv()
 // LINUX: %s = alloca %struct.S, align 1
@@ -91,29 +91,29 @@ int templ_use() {
 // WINDOWS: call dereferenceable(1) %struct.S* @"??4S@@QEAAAEAU0@AEBU0@@Z.resolver"(%struct.S* %s2
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %s, i32 0)
 
-// LINUX: define %struct.S* (%struct.S*, %struct.S*)* @_ZN1SaSERKS_.resolver() comdat
+// LINUX: define weak_odr %struct.S* (%struct.S*, %struct.S*)* @_ZN1SaSERKS_.resolver() comdat
 // LINUX: ret %struct.S* (%struct.S*, %struct.S*)* @_ZN1SaSERKS_.arch_ivybridge
 // LINUX: ret %struct.S* (%struct.S*, %struct.S*)* @_ZN1SaSERKS_
 
-// WINDOWS: define dso_local %struct.S* @"??4S@@QEAAAEAU0@AEBU0@@Z.resolver"(%struct.S* %0, %struct.S* %1)
+// WINDOWS: define weak_odr dso_local %struct.S* @"??4S@@QEAAAEAU0@AEBU0@@Z.resolver"(%struct.S* %0, %struct.S* %1)
 // WINDOWS: call %struct.S* @"??4S@@QEAAAEAU0@AEBU0@@Z.arch_ivybridge"
 // WINDOWS: call %struct.S* @"??4S@@QEAAAEAU0@AEBU0@@Z"
 
-// LINUX: define void (%struct.ConvertTo*)* @_ZNK9ConvertTocv1SEv.resolver() comdat
+// LINUX: define weak_odr void (%struct.ConvertTo*)* @_ZNK9ConvertTocv1SEv.resolver() comdat
 // LINUX: ret void (%struct.ConvertTo*)* @_ZNK9ConvertTocv1SEv.arch_ivybridge
 // LINUX: ret void (%struct.ConvertTo*)* @_ZNK9ConvertTocv1SEv
 
-// WINDOWS: define dso_local void @"??BConvertTo@@QEBA?AUS@@XZ.resolver"(%struct.ConvertTo* %0, %struct.S* %1)
+// WINDOWS: define weak_odr dso_local void @"??BConvertTo@@QEBA?AUS@@XZ.resolver"(%struct.ConvertTo* %0, %struct.S* %1)
 // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ.arch_ivybridge"
 // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ"
 
-// LINUX: define i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver() comdat
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_sandybridge
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_ivybridge
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.sse4.2
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %0, i32 %1)
+// WINDOWS: define weak_odr dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %0, i32 %1)
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge"
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_ivybridge"
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.sse4.2"
@@ -125,13 +125,13 @@ int templ_use() {
 // WINDOWS: define dso_local i32 @"?bar2@@YAHXZ"()
 // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.resolver"
 
-// LINUX: define i32 (%struct.S2*, i32)* @_ZN2S23fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (%struct.S2*, i32)* @_ZN2S23fooEi.resolver() comdat
 // LINUX: ret i32 (%struct.S2*, i32)* @_ZN2S23fooEi.arch_sandybridge
 // LINUX: ret i32 (%struct.S2*, i32)* @_ZN2S23fooEi.arch_ivybridge
 // LINUX: ret i32 (%struct.S2*, i32)* @_ZN2S23fooEi.sse4.2
 // LINUX: ret i32 (%struct.S2*, i32)* @_ZN2S23fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@S2@@QEAAHH@Z.resolver"(%struct.S2* %0, i32 %1)
+// WINDOWS: define weak_odr dso_local i32 @"?foo@S2@@QEAAHH@Z.resolver"(%struct.S2* %0, i32 %1)
 // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.arch_sandybridge"
 // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.arch_ivybridge"
 // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.sse4.2"
@@ -153,25 +153,25 @@ int templ_use() {
 // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.resolver"
 // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.resolver"
 
-// LINUX: define i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.resolver() comdat
 // LINUX: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.arch_sandybridge
 // LINUX: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.arch_ivybridge
 // LINUX: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi.sse4.2
 // LINUX: ret i32 (%struct.templ*, i32)* @_ZN5templIiE3fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@?$templ@H@@QEAAHH@Z.resolver"(%struct.templ* %0, i32 %1)
+// WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ@H@@QEAAHH@Z.resolver"(%struct.templ* %0, i32 %1)
 // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.arch_sandybridge"
 // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.arch_ivybridge"
 // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.sse4.2"
 // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z"
 
-// LINUX: define i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.resolver() comdat
 // LINUX: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.arch_sandybridge
 // LINUX: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.arch_ivybridge
 // LINUX: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.sse4.2
 // LINUX: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@?$templ@N@@QEAAHH@Z.resolver"(%struct.templ.0* %0, i32 %1) comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ@N@@QEAAHH@Z.resolver"(%struct.templ.0* %0, i32 %1) comdat
 // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.arch_sandybridge"
 // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.arch_ivybridge"
 // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.sse4.2"
index 6ff2046831e63e0d42374774dca58013b964c7ad..0fa15bfedf6e2e5038c81a9433f36bdf3a4ca1d0 100644 (file)
@@ -22,7 +22,7 @@ __attribute__((target("sse4.2"))) void f();
 void g() { f(); }
 
 // Negative tests to validate that the resolver only calls each 1x.
-// CHECK: define void ()* @_Z1fv.resolver
+// CHECK: define weak_odr void ()* @_Z1fv.resolver
 // CHECK: ret void ()* @_Z1fv.sse4.2
 // CHECK-NOT: ret void ()* @_Z1fv.sse4.2
 // CHECK: ret void ()* @_Z1fv
index 7952544f9334bc8855289e37fac39a4cf55566e1..1b9fb8f01ead8a869e1909d21f7dc02cc24ac704 100644 (file)
@@ -16,7 +16,7 @@ int bar() {
   return s.foo(0);
 }
 
-// LINUX: @_ZN1S3fooEi.ifunc = ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
+// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
 
 // LINUX: define i32 @_ZN1S3fooEi(%struct.S* %this, i32 %0)
 // LINUX: ret i32 2
@@ -44,13 +44,13 @@ int bar() {
 // WINDOWS: %s = alloca %struct.S, align 1
 // WINDOWS: %call = call i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %s, i32 0)
 
-// LINUX: define i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver() comdat
+// LINUX: define weak_odr i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver() comdat
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_sandybridge
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_ivybridge
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.sse4.2
 // LINUX: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi
 
-// WINDOWS: define dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %0, i32 %1) comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(%struct.S* %0, i32 %1) comdat
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge"(%struct.S* %0, i32 %1)
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_ivybridge"(%struct.S* %0, i32 %1)
 // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.sse4.2"(%struct.S* %0, i32 %1)
index 45db1ba0f1f6817ab736b7c221d7051ae924260a..75350fe88522d09c431258858976ea4815fef934 100644 (file)
@@ -14,8 +14,8 @@ int bar2() {
   return foo_overload() + foo_overload(1);
 }
 
-// LINUX: @_Z12foo_overloadv.ifunc = ifunc i32 (), i32 ()* ()* @_Z12foo_overloadv.resolver
-// LINUX: @_Z12foo_overloadi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_Z12foo_overloadi.resolver
+// LINUX: @_Z12foo_overloadv.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @_Z12foo_overloadv.resolver
+// LINUX: @_Z12foo_overloadi.ifunc = weak_odr ifunc i32 (i32), i32 (i32)* ()* @_Z12foo_overloadi.resolver
 
 // LINUX: define i32 @_Z12foo_overloadi.sse4.2(i32 %0)
 // LINUX: ret i32 0
@@ -51,25 +51,25 @@ int bar2() {
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.resolver"()
 // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.resolver"(i32 1)
 
-// LINUX: define i32 ()* @_Z12foo_overloadv.resolver() comdat
+// LINUX: define weak_odr i32 ()* @_Z12foo_overloadv.resolver() comdat
 // LINUX: ret i32 ()* @_Z12foo_overloadv.arch_sandybridge
 // LINUX: ret i32 ()* @_Z12foo_overloadv.arch_ivybridge
 // LINUX: ret i32 ()* @_Z12foo_overloadv.sse4.2
 // LINUX: ret i32 ()* @_Z12foo_overloadv
 
-// WINDOWS: define dso_local i32 @"?foo_overload@@YAHXZ.resolver"() comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHXZ.resolver"() comdat
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.arch_sandybridge"
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.arch_ivybridge"
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.sse4.2"
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ"
 
-// LINUX: define i32 (i32)* @_Z12foo_overloadi.resolver() comdat
+// LINUX: define weak_odr i32 (i32)* @_Z12foo_overloadi.resolver() comdat
 // LINUX: ret i32 (i32)* @_Z12foo_overloadi.arch_sandybridge
 // LINUX: ret i32 (i32)* @_Z12foo_overloadi.arch_ivybridge
 // LINUX: ret i32 (i32)* @_Z12foo_overloadi.sse4.2
 // LINUX: ret i32 (i32)* @_Z12foo_overloadi
 
-// WINDOWS: define dso_local i32 @"?foo_overload@@YAHH@Z.resolver"(i32 %0) comdat
+// WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHH@Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.arch_sandybridge"
 // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.arch_ivybridge"
 // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.sse4.2"