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(
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();
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
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);
#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){}
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
// 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
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
// 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
// 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
// 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
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
// 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
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
// 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
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
// 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]]
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]]
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()
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(
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, ...)
// 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
// 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
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
// 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
// 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
// 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
// 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
// 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)
// 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
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"
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
// 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)
// 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)
// 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)
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
// 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"
// 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"
// 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"
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
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
// 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)
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
// 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"