Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -2836,11 +2836,13 @@ llvm::Function *ResolverFunc; const TargetInfo &TI = getTarget(); - if (TI.supportsIFunc() || FD->isTargetMultiVersion()) + if (TI.supportsIFunc() || FD->isTargetMultiVersion()) { ResolverFunc = cast( GetGlobalValue((getMangledName(GD) + ".resolver").str())); - else + ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + } else { ResolverFunc = cast(GetGlobalValue(getMangledName(GD))); + } if (supportsCOMDAT()) ResolverFunc->setComdat( @@ -2884,6 +2886,10 @@ auto *ResolverFunc = cast(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); + ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + if (supportsCOMDAT()) + ResolverFunc->setComdat( + getModule().getOrInsertComdat(ResolverFunc->getName())); SmallVector Options; const TargetInfo &Target = getTarget(); @@ -2948,6 +2954,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(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 @@ 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: cfe/trunk/test/CodeGen/attr-cpuspecific.c =================================================================== --- cfe/trunk/test/CodeGen/attr-cpuspecific.c +++ cfe/trunk/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 = 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ 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: cfe/trunk/test/CodeGen/attr-target-mv-func-ptrs.c =================================================================== --- cfe/trunk/test/CodeGen/attr-target-mv-func-ptrs.c +++ cfe/trunk/test/CodeGen/attr-target-mv-func-ptrs.c @@ -17,7 +17,7 @@ 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: cfe/trunk/test/CodeGen/attr-target-mv-va-args.c =================================================================== --- cfe/trunk/test/CodeGen/attr-target-mv-va-args.c +++ cfe/trunk/test/CodeGen/attr-target-mv-va-args.c @@ -9,7 +9,7 @@ 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 @@ // 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 @@ // 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: cfe/trunk/test/CodeGen/attr-target-mv.c =================================================================== --- cfe/trunk/test/CodeGen/attr-target-mv.c +++ cfe/trunk/test/CodeGen/attr-target-mv.c @@ -47,12 +47,12 @@ 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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: cfe/trunk/test/CodeGenCXX/attr-cpuspecific.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-cpuspecific.cpp +++ cfe/trunk/test/CodeGenCXX/attr-cpuspecific.cpp @@ -13,13 +13,15 @@ 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-diff-ns.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-diff-ns.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-diff-ns.cpp @@ -18,8 +18,8 @@ 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 @@ // 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-inalloca.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-inalloca.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-inalloca.cpp @@ -41,7 +41,7 @@ // 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 @@ // 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-member-funcs.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-member-funcs.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-member-funcs.cpp @@ -65,13 +65,13 @@ 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 @@ // 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 @@ // 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 @@ // 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-modules.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-modules.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-modules.cpp @@ -22,7 +22,7 @@ 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp @@ -16,7 +16,7 @@ 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 @@ // 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: cfe/trunk/test/CodeGenCXX/attr-target-mv-overloads.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-target-mv-overloads.cpp +++ cfe/trunk/test/CodeGenCXX/attr-target-mv-overloads.cpp @@ -14,8 +14,8 @@ 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 @@ // 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"