blob: 2c4b95ca04370a02fbc8be6f12833b77418fa7c1 [file] [log] [blame]
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
// RUN: %clang_cc1 -triple x86_64-apple-macos -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
// RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
int __attribute__((target("sse4.2"))) foo(void) { return 0; }
int __attribute__((target("arch=sandybridge"))) foo(void);
int __attribute__((target("arch=ivybridge"))) foo(void) {return 1;}
int __attribute__((target("arch=goldmont"))) foo(void) {return 3;}
int __attribute__((target("arch=goldmont-plus"))) foo(void) {return 4;}
int __attribute__((target("arch=tremont"))) foo(void) {return 5;}
int __attribute__((target("arch=icelake-client"))) foo(void) {return 6;}
int __attribute__((target("arch=icelake-server"))) foo(void) {return 7;}
int __attribute__((target("arch=cooperlake"))) foo(void) {return 8;}
int __attribute__((target("arch=tigerlake"))) foo(void) {return 9;}
int __attribute__((target("arch=sapphirerapids"))) foo(void) {return 10;}
int __attribute__((target("arch=alderlake"))) foo(void) {return 11;}
int __attribute__((target("arch=rocketlake"))) foo(void) {return 12;}
int __attribute__((target("arch=core2"))) foo(void) {return 13;}
int __attribute__((target("arch=raptorlake"))) foo(void) {return 14;}
int __attribute__((target("arch=meteorlake"))) foo(void) {return 15;}
int __attribute__((target("arch=sierraforest"))) foo(void) {return 16;}
int __attribute__((target("arch=grandridge"))) foo(void) {return 17;}
int __attribute__((target("arch=graniterapids"))) foo(void) {return 18;}
int __attribute__((target("arch=emeraldrapids"))) foo(void) {return 19;}
int __attribute__((target("arch=graniterapids-d"))) foo(void) {return 20;}
int __attribute__((target("arch=arrowlake"))) foo(void) {return 21;}
int __attribute__((target("arch=arrowlake-s"))) foo(void) {return 22;}
int __attribute__((target("arch=lunarlake"))) foo(void) {return 23;}
int __attribute__((target("arch=gracemont"))) foo(void) {return 24;}
int __attribute__((target("arch=pantherlake"))) foo(void) {return 25;}
int __attribute__((target("arch=clearwaterforest"))) foo(void) {return 26;}
int __attribute__((target("default"))) foo(void) { return 2; }
int bar(void) {
return foo();
}
static int __attribute__((target("arch=meteorlake"))) foo_internal(void) {return 15;}
static int __attribute__((target("default"))) foo_internal(void) { return 2; }
int bar1(void) {
return foo_internal();
}
inline int __attribute__((target("sse4.2"))) foo_inline(void) { return 0; }
inline int __attribute__((target("arch=sandybridge"))) foo_inline(void);
inline int __attribute__((target("arch=ivybridge"))) foo_inline(void) {return 1;}
inline int __attribute__((target("default"))) foo_inline(void) { return 2; }
int bar2(void) {
return foo_inline();
}
inline __attribute__((target("default"))) void foo_decls(void);
inline __attribute__((target("sse4.2"))) void foo_decls(void);
void bar3(void) {
foo_decls();
}
inline __attribute__((target("default"))) void foo_decls(void) {}
inline __attribute__((target("sse4.2"))) void foo_decls(void) {}
inline __attribute__((target("default"))) void foo_multi(int i, double d) {}
inline __attribute__((target("avx,sse4.2"))) void foo_multi(int i, double d) {}
inline __attribute__((target("sse4.2,fma4"))) void foo_multi(int i, double d) {}
inline __attribute__((target("arch=ivybridge,fma4,sse4.2"))) void foo_multi(int i, double d) {}
void bar4(void) {
foo_multi(1, 5.0);
}
int fwd_decl_default(void);
int __attribute__((target("default"))) fwd_decl_default(void) { return 2; }
int fwd_decl_avx(void);
int __attribute__((target("avx"))) fwd_decl_avx(void) { return 2; }
int __attribute__((target("default"))) fwd_decl_avx(void) { return 2; }
void bar5(void) {
fwd_decl_default();
fwd_decl_avx();
}
int __attribute__((target("avx"))) changed_to_mv(void) { return 0;}
int __attribute__((target("fma4"))) changed_to_mv(void) { return 1;}
__attribute__((target("default"), used)) inline void foo_used(int i, double d) {}
__attribute__((target("avx,sse4.2"))) inline void foo_used(int i, double d) {}
__attribute__((target("default"))) inline void foo_used2(int i, double d) {}
__attribute__((target("avx,sse4.2"), used)) inline void foo_used2(int i, double d) {}
// PR50025:
static void must_be_emitted(void) {}
inline __attribute__((target("default"))) void pr50025(void) { must_be_emitted(); }
void calls_pr50025(void) { pr50025(); }
// Also need to make sure we get other multiversion functions.
inline __attribute__((target("default"))) void pr50025b(void) { must_be_emitted(); }
inline __attribute__((target("default"))) void pr50025c(void) { pr50025b(); }
void calls_pr50025c(void) { pr50025c(); }
// LINUX: $foo.resolver = comdat any
// LINUX: $foo_inline.resolver = comdat any
// LINUX: $foo_decls.resolver = comdat any
// LINUX: $foo_multi.resolver = comdat any
// LINUX: $fwd_decl_default.resolver = comdat any
// LINUX: $fwd_decl_avx.resolver = comdat any
// LINUX: $pr50025.resolver = comdat any
// LINUX: $pr50025c.resolver = comdat any
// LINUX: $pr50025b.resolver = comdat any
// DARWIN-NOT: comdat
// WINDOWS: $foo.resolver = comdat any
// WINDOWS: $foo_inline.resolver = comdat any
// WINDOWS: $foo_decls.resolver = comdat any
// WINDOWS: $foo_multi.resolver = comdat any
// WINDOWS: $fwd_decl_default.resolver = comdat any
// WINDOWS: $fwd_decl_avx.resolver = comdat any
// WINDOWS: $foo_used = comdat any
// WINDOWS: $foo_used2.avx_sse4.2 = comdat any
// WINDOWS: $pr50025.resolver = comdat any
// WINDOWS: $pr50025c.resolver = comdat any
// WINDOWS: $foo_inline.sse4.2 = comdat any
// WINDOWS: $foo_inline.arch_ivybridge = comdat any
// WINDOWS: $foo_inline = comdat any
// WINDOWS: $foo_decls = comdat any
// WINDOWS: $foo_decls.sse4.2 = comdat any
// WINDOWS: $foo_multi = comdat any
// WINDOWS: $foo_multi.avx_sse4.2 = comdat any
// WINDOWS: $foo_multi.fma4_sse4.2 = comdat any
// WINDOWS: $foo_multi.arch_ivybridge_fma4_sse4.2 = comdat any
// WINDOWS: $pr50025 = comdat any
// WINDOWS: $pr50025c = comdat any
// WINDOWS: $pr50025b.resolver = comdat any
// WINDOWS: $pr50025b = comdat any
// LINUX: @llvm.compiler.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
// DARWIN: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
// WINDOWS: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
// ITANIUM: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver
// ITANIUM: @foo_internal.ifunc = internal ifunc i32 (), ptr @foo_internal.resolver
// ITANIUM: @foo_inline.ifunc = weak_odr ifunc i32 (), ptr @foo_inline.resolver
// ITANIUM: @foo_decls.ifunc = weak_odr ifunc void (), ptr @foo_decls.resolver
// ITANIUM: @foo_multi.ifunc = weak_odr ifunc void (i32, double), ptr @foo_multi.resolver
// ITANIUM: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_default.resolver
// ITANIUM: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_avx.resolver
// ITANIUM: define{{.*}} i32 @foo.sse4.2()
// ITANIUM: ret i32 0
// ITANIUM: define{{.*}} i32 @foo.arch_ivybridge()
// ITANIUM: ret i32 1
// ITANIUM: define{{.*}} i32 @foo.arch_goldmont()
// ITANIUM: ret i32 3
// ITANIUM: define{{.*}} i32 @foo.arch_goldmont-plus()
// ITANIUM: ret i32 4
// ITANIUM: define{{.*}} i32 @foo.arch_tremont()
// ITANIUM: ret i32 5
// ITANIUM: define{{.*}} i32 @foo.arch_icelake-client()
// ITANIUM: ret i32 6
// ITANIUM: define{{.*}} i32 @foo.arch_icelake-server()
// ITANIUM: ret i32 7
// ITANIUM: define{{.*}} i32 @foo.arch_cooperlake()
// ITANIUM: ret i32 8
// ITANIUM: define{{.*}} i32 @foo.arch_tigerlake()
// ITANIUM: ret i32 9
// ITANIUM: define{{.*}} i32 @foo.arch_sapphirerapids()
// ITANIUM: ret i32 10
// ITANIUM: define{{.*}} i32 @foo.arch_alderlake()
// ITANIUM: ret i32 11
// ITANIUM: define{{.*}} i32 @foo.arch_rocketlake()
// ITANIUM: ret i32 12
// ITANIUM: define{{.*}} i32 @foo.arch_core2()
// ITANIUM: ret i32 13
// ITANIUM: define{{.*}} i32 @foo.arch_raptorlake()
// ITANIUM: ret i32 14
// ITANIUM: define{{.*}} i32 @foo.arch_meteorlake()
// ITANIUM: ret i32 15
// ITANIUM: define{{.*}} i32 @foo.arch_sierraforest()
// ITANIUM: ret i32 16
// ITANIUM: define{{.*}} i32 @foo.arch_grandridge()
// ITANIUM: ret i32 17
// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids()
// ITANIUM: ret i32 18
// ITANIUM: define{{.*}} i32 @foo.arch_emeraldrapids()
// ITANIUM: ret i32 19
// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids-d()
// ITANIUM: ret i32 20
// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake()
// ITANIUM: ret i32 21
// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake-s()
// ITANIUM: ret i32 22
// ITANIUM: define{{.*}} i32 @foo.arch_lunarlake()
// ITANIUM: ret i32 23
// ITANIUM: define{{.*}} i32 @foo.arch_gracemont()
// ITANIUM: ret i32 24
// ITANIUM: define{{.*}} i32 @foo.arch_pantherlake()
// ITANIUM: ret i32 25
// ITANIUM: define{{.*}} i32 @foo.arch_clearwaterforest()
// ITANIUM: ret i32 26
// ITANIUM: define{{.*}} i32 @foo()
// ITANIUM: ret i32 2
// ITANIUM: define{{.*}} i32 @bar()
// ITANIUM: call i32 @foo.ifunc()
// WINDOWS: define dso_local i32 @foo.sse4.2()
// WINDOWS: ret i32 0
// WINDOWS: define dso_local i32 @foo.arch_ivybridge()
// WINDOWS: ret i32 1
// WINDOWS: define dso_local i32 @foo.arch_goldmont()
// WINDOWS: ret i32 3
// WINDOWS: define dso_local i32 @foo.arch_goldmont-plus()
// WINDOWS: ret i32 4
// WINDOWS: define dso_local i32 @foo.arch_tremont()
// WINDOWS: ret i32 5
// WINDOWS: define dso_local i32 @foo.arch_icelake-client()
// WINDOWS: ret i32 6
// WINDOWS: define dso_local i32 @foo.arch_icelake-server()
// WINDOWS: ret i32 7
// WINDOWS: define dso_local i32 @foo.arch_cooperlake()
// WINDOWS: ret i32 8
// WINDOWS: define dso_local i32 @foo.arch_tigerlake()
// WINDOWS: ret i32 9
// WINDOWS: define dso_local i32 @foo.arch_sapphirerapids()
// WINDOWS: ret i32 10
// WINDOWS: define dso_local i32 @foo.arch_alderlake()
// WINDOWS: ret i32 11
// WINDOWS: define dso_local i32 @foo.arch_rocketlake()
// WINDOWS: ret i32 12
// WINDOWS: define dso_local i32 @foo.arch_core2()
// WINDOWS: ret i32 13
// WINDOWS: define dso_local i32 @foo.arch_raptorlake()
// WINDOWS: ret i32 14
// WINDOWS: define dso_local i32 @foo.arch_meteorlake()
// WINDOWS: ret i32 15
// WINDOWS: define{{.*}} i32 @foo.arch_sierraforest()
// WINDOWS: ret i32 16
// WINDOWS: define{{.*}} i32 @foo.arch_grandridge()
// WINDOWS: ret i32 17
// WINDOWS: define{{.*}} i32 @foo.arch_graniterapids()
// WINDOWS: ret i32 18
// WINDOWS: define dso_local i32 @foo.arch_emeraldrapids()
// WINDOWS: ret i32 19
// WINDOWS: define dso_local i32 @foo.arch_graniterapids-d()
// WINDOWS: ret i32 20
// WINDOWS: define dso_local i32 @foo.arch_arrowlake()
// WINDOWS: ret i32 21
// WINDOWS: define dso_local i32 @foo.arch_arrowlake-s()
// WINDOWS: ret i32 22
// WINDOWS: define dso_local i32 @foo.arch_lunarlake()
// WINDOWS: ret i32 23
// WINDOWS: define dso_local i32 @foo.arch_gracemont()
// WINDOWS: ret i32 24
// WINDOWS: define dso_local i32 @foo.arch_pantherlake()
// WINDOWS: ret i32 25
// WINDOWS: define dso_local i32 @foo.arch_clearwaterforest()
// WINDOWS: ret i32 26
// WINDOWS: define dso_local i32 @foo()
// WINDOWS: ret i32 2
// WINDOWS: define dso_local i32 @bar()
// WINDOWS: call i32 @foo.resolver()
// ITANIUM: define weak_odr ptr @foo.resolver()
// LINUX-SAME: comdat
// ITANIUM: call void @__cpu_indicator_init()
// ITANIUM: ret ptr @foo.arch_sandybridge
// ITANIUM: ret ptr @foo.arch_ivybridge
// ITANIUM: ret ptr @foo.sse4.2
// ITANIUM: ret ptr @foo
// 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: call i32 @foo.sse4.2
// WINDOWS: call i32 @foo
/// Internal linkage resolvers do not use comdat.
// ITANIUM: define internal ptr @foo_internal.resolver() {
// WINDOWS: define internal i32 @foo_internal.resolver() {
// ITANIUM: define{{.*}} i32 @bar2()
// ITANIUM: call i32 @foo_inline.ifunc()
// WINDOWS: define dso_local i32 @bar2()
// WINDOWS: call i32 @foo_inline.resolver()
// ITANIUM: define weak_odr ptr @foo_inline.resolver()
// LINUX-SAME: comdat
// ITANIUM: call void @__cpu_indicator_init()
// ITANIUM: ret ptr @foo_inline.arch_sandybridge
// ITANIUM: ret ptr @foo_inline.arch_ivybridge
// ITANIUM: ret ptr @foo_inline.sse4.2
// ITANIUM: ret ptr @foo_inline
// 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: call i32 @foo_inline.sse4.2
// WINDOWS: call i32 @foo_inline
// ITANIUM: define{{.*}} void @bar3()
// ITANIUM: call void @foo_decls.ifunc()
// WINDOWS: define dso_local void @bar3()
// WINDOWS: call void @foo_decls.resolver()
// ITANIUM: define weak_odr ptr @foo_decls.resolver()
// LINUX-SAME: comdat
// ITANIUM: ret ptr @foo_decls.sse4.2
// ITANIUM: ret ptr @foo_decls
// WINDOWS: define weak_odr dso_local void @foo_decls.resolver() comdat
// WINDOWS: call void @foo_decls.sse4.2
// WINDOWS: call void @foo_decls
// ITANIUM: define{{.*}} void @bar4()
// ITANIUM: call void @foo_multi.ifunc(i32 noundef 1, double noundef 5.{{[0+e]*}})
// WINDOWS: define dso_local void @bar4()
// WINDOWS: call void @foo_multi.resolver(i32 noundef 1, double noundef 5.{{[0+e]*}})
// ITANIUM: define weak_odr ptr @foo_multi.resolver()
// LINUX-SAME: comdat
// ITANIUM: and i32 %{{.*}}, 4352
// ITANIUM: icmp eq i32 %{{.*}}, 4352
// ITANIUM: ret ptr @foo_multi.fma4_sse4.2
// ITANIUM: icmp eq i32 %{{.*}}, 12
// ITANIUM: and i32 %{{.*}}, 4352
// ITANIUM: icmp eq i32 %{{.*}}, 4352
// ITANIUM: ret ptr @foo_multi.arch_ivybridge_fma4_sse4.2
// ITANIUM: and i32 %{{.*}}, 768
// ITANIUM: icmp eq i32 %{{.*}}, 768
// ITANIUM: ret ptr @foo_multi.avx_sse4.2
// ITANIUM: ret ptr @foo_multi
// 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-NEXT: ret void
// WINDOWS: icmp eq i32 %{{.*}}, 12
// WINDOWS: and i32 %{{.*}}, 4352
// WINDOWS: icmp eq i32 %{{.*}}, 4352
// WINDOWS: call void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 %0, double %1)
// WINDOWS-NEXT: ret void
// WINDOWS: and i32 %{{.*}}, 768
// WINDOWS: icmp eq i32 %{{.*}}, 768
// WINDOWS: call void @foo_multi.avx_sse4.2(i32 %0, double %1)
// WINDOWS-NEXT: ret void
// WINDOWS: call void @foo_multi(i32 %0, double %1)
// WINDOWS-NEXT: ret void
// ITANIUM: define{{.*}} i32 @fwd_decl_default()
// ITANIUM: ret i32 2
// ITANIUM: define{{.*}} i32 @fwd_decl_avx.avx()
// ITANIUM: ret i32 2
// ITANIUM: define{{.*}} i32 @fwd_decl_avx()
// ITANIUM: ret i32 2
// WINDOWS: define dso_local i32 @fwd_decl_default()
// WINDOWS: ret i32 2
// WINDOWS: define dso_local i32 @fwd_decl_avx.avx()
// WINDOWS: ret i32 2
// WINDOWS: define dso_local i32 @fwd_decl_avx()
// WINDOWS: ret i32 2
// ITANIUM: define{{.*}} void @bar5()
// ITANIUM: call i32 @fwd_decl_default.ifunc()
// ITANIUM: call i32 @fwd_decl_avx.ifunc()
// WINDOWS: define dso_local void @bar5()
// WINDOWS: call i32 @fwd_decl_default.resolver()
// WINDOWS: call i32 @fwd_decl_avx.resolver()
// ITANIUM: define weak_odr ptr @fwd_decl_default.resolver()
// LINUX-SAME: comdat
// ITANIUM: call void @__cpu_indicator_init()
// ITANIUM: ret ptr @fwd_decl_default
// ITANIUM: define weak_odr ptr @fwd_decl_avx.resolver()
// LINUX-SAME: comdat
// ITANIUM: call void @__cpu_indicator_init()
// ITANIUM: ret ptr @fwd_decl_avx.avx
// ITANIUM: ret ptr @fwd_decl_avx
// 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 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
// ITANIUM: define{{.*}} i32 @changed_to_mv.avx()
// ITANIUM: define{{.*}} i32 @changed_to_mv.fma4()
// WINDOWS: define dso_local i32 @changed_to_mv.avx()
// WINDOWS: define dso_local i32 @changed_to_mv.fma4()
// ITANIUM: define linkonce void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}})
// ITANIUM-NOT: @foo_used.avx_sse4.2(
// ITANIUM-NOT: @foo_used2(
// ITANIUM: define linkonce void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}})
// WINDOWS: define linkonce_odr dso_local void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}})
// WINDOWS-NOT: @foo_used.avx_sse4.2(
// WINDOWS-NOT: @foo_used2(
// WINDOWS: define linkonce_odr dso_local void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}})
// ITANIUM: declare i32 @foo.arch_sandybridge()
// WINDOWS: declare dso_local i32 @foo.arch_sandybridge()
// ITANIUM: define linkonce i32 @foo_inline.sse4.2()
// ITANIUM: ret i32 0
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2()
// WINDOWS: ret i32 0
// ITANIUM: declare i32 @foo_inline.arch_sandybridge()
// WINDOWS: declare dso_local i32 @foo_inline.arch_sandybridge()
// ITANIUM: define linkonce i32 @foo_inline.arch_ivybridge()
// ITANIUM: ret i32 1
// ITANIUM: define linkonce i32 @foo_inline()
// ITANIUM: ret i32 2
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_ivybridge()
// WINDOWS: ret i32 1
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline()
// WINDOWS: ret i32 2
// ITANIUM: define linkonce void @foo_decls()
// ITANIUM: define linkonce void @foo_decls.sse4.2()
// WINDOWS: define linkonce_odr dso_local void @foo_decls()
// WINDOWS: define linkonce_odr dso_local void @foo_decls.sse4.2()
// ITANIUM: define linkonce void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// ITANIUM: define linkonce void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// ITANIUM: define linkonce void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// ITANIUM: define linkonce void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// WINDOWS: define linkonce_odr dso_local void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// WINDOWS: define linkonce_odr dso_local void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// WINDOWS: define linkonce_odr dso_local void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// WINDOWS: define linkonce_odr dso_local void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
// Ensure that we emit the 'static' function here.
// ITANIUM: define linkonce void @pr50025()
// ITANIUM: call void @must_be_emitted
// ITANIUM: define internal void @must_be_emitted()
// WINDOWS: define linkonce_odr dso_local void @pr50025() #{{[0-9]*}} comdat
// WINDOWS: call void @must_be_emitted
// WINDOWS: define internal void @must_be_emitted()
// ITANIUM: define linkonce void @pr50025c()
// ITANIUM: call void @pr50025b.ifunc()
// WINDOWS: define linkonce_odr dso_local void @pr50025c() #{{[0-9]*}} comdat
// WINDOWS: call void @pr50025b.resolver()
// ITANIUM: define weak_odr ptr @pr50025b.resolver()
// LINUX-SAME: comdat
// ITANIUM: ret ptr @pr50025b
// ITANIUM: define linkonce void @pr50025b()
// ITANIUM: call void @must_be_emitted()
// WINDOWS: define weak_odr dso_local void @pr50025b.resolver() comdat
// WINDOWS: musttail call void @pr50025b()
// WINDOWS: define linkonce_odr dso_local void @pr50025b() #{{[0-9]*}} comdat
// WINDOWS: call void @must_be_emitted()