1 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX
2 // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WINDOWS
3
4 #ifdef _WIN64
5 #define ATTR(X) __declspec(X)
6 #else
7 #define ATTR(X) __attribute__((X))
8 #endif // _MSC_VER
9
10 // Each version should have an IFunc and an alias.
11 // LINUX: @TwoVersions = weak_odr alias void (), void ()* @TwoVersions.ifunc
12 // LINUX: @TwoVersionsSameAttr = weak_odr alias void (), void ()* @TwoVersionsSameAttr.ifunc
13 // LINUX: @ThreeVersionsSameAttr = weak_odr alias void (), void ()* @ThreeVersionsSameAttr.ifunc
14 // LINUX: @NoSpecifics = weak_odr alias void (), void ()* @NoSpecifics.ifunc
15 // LINUX: @HasGeneric = weak_odr alias void (), void ()* @HasGeneric.ifunc
16 // LINUX: @HasParams = weak_odr alias void (i32, double), void (i32, double)* @HasParams.ifunc
17 // LINUX: @HasParamsAndReturn = weak_odr alias i32 (i32, double), i32 (i32, double)* @HasParamsAndReturn.ifunc
18 // LINUX: @GenericAndPentium = weak_odr alias i32 (i32, double), i32 (i32, double)* @GenericAndPentium.ifunc
19 // LINUX: @DispatchFirst = weak_odr alias i32 (), i32 ()* @DispatchFirst.ifunc
20
21 // LINUX: @TwoVersions.ifunc = weak_odr ifunc void (), void ()* ()* @TwoVersions.resolver
22 // LINUX: @SingleVersion.ifunc = weak_odr ifunc void (), void ()* ()* @SingleVersion.resolver
23 // LINUX: @TwoVersionsSameAttr.ifunc = weak_odr ifunc void (), void ()* ()* @TwoVersionsSameAttr.resolver
24 // LINUX: @ThreeVersionsSameAttr.ifunc = weak_odr ifunc void (), void ()* ()* @ThreeVersionsSameAttr.resolver
25 // LINUX: @NoSpecifics.ifunc = weak_odr ifunc void (), void ()* ()* @NoSpecifics.resolver
26 // LINUX: @HasGeneric.ifunc = weak_odr ifunc void (), void ()* ()* @HasGeneric.resolver
27 // LINUX: @HasParams.ifunc = weak_odr ifunc void (i32, double), void (i32, double)* ()* @HasParams.resolver
28 // LINUX: @HasParamsAndReturn.ifunc = weak_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @HasParamsAndReturn.resolver
29 // LINUX: @GenericAndPentium.ifunc = weak_odr ifunc i32 (i32, double), i32 (i32, double)* ()* @GenericAndPentium.resolver
30 // LINUX: @DispatchFirst.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @DispatchFirst.resolver
31
ATTR(cpu_specific (ivybridge))32 ATTR(cpu_specific(ivybridge))
33 void SingleVersion(void){}
34 // LINUX: define void @SingleVersion.S() #[[S:[0-9]+]]
35 // WINDOWS: define dso_local void @SingleVersion.S() #[[S:[0-9]+]]
36
ATTR(cpu_specific (ivybridge))37 ATTR(cpu_specific(ivybridge))
38 void NotCalled(void){}
39 // LINUX: define void @NotCalled.S() #[[S]]
40 // WINDOWS: define dso_local void @NotCalled.S() #[[S:[0-9]+]]
41
42 // Done before any of the implementations. Also has an undecorated forward
43 // declaration.
44 void TwoVersions(void);
45
46 ATTR(cpu_dispatch(ivybridge, knl))
47 void TwoVersions(void);
48 // LINUX: define weak_odr void ()* @TwoVersions.resolver()
49 // LINUX: call void @__cpu_indicator_init
50 // LINUX: ret void ()* @TwoVersions.Z
51 // LINUX: ret void ()* @TwoVersions.S
52 // LINUX: call void @llvm.trap
53 // LINUX: unreachable
54
55 // WINDOWS: define weak_odr dso_local void @TwoVersions() comdat
56 // WINDOWS: call void @__cpu_indicator_init()
57 // WINDOWS: call void @TwoVersions.Z()
58 // WINDOWS-NEXT: ret void
59 // WINDOWS: call void @TwoVersions.S()
60 // WINDOWS-NEXT: ret void
61 // WINDOWS: call void @llvm.trap
62 // WINDOWS: unreachable
63
ATTR(cpu_specific (ivybridge))64 ATTR(cpu_specific(ivybridge))
65 void TwoVersions(void){}
66 // CHECK: define {{.*}}void @TwoVersions.S() #[[S]]
67
ATTR(cpu_specific (knl))68 ATTR(cpu_specific(knl))
69 void TwoVersions(void){}
70 // CHECK: define {{.*}}void @TwoVersions.Z() #[[K:[0-9]+]]
71
ATTR(cpu_specific (ivybridge,knl))72 ATTR(cpu_specific(ivybridge, knl))
73 void TwoVersionsSameAttr(void){}
74 // CHECK: define {{.*}}void @TwoVersionsSameAttr.S() #[[S]]
75 // CHECK: define {{.*}}void @TwoVersionsSameAttr.Z() #[[K]]
76
ATTR(cpu_specific (atom,ivybridge,knl))77 ATTR(cpu_specific(atom, ivybridge, knl))
78 void ThreeVersionsSameAttr(void){}
79 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.O() #[[O:[0-9]+]]
80 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.S() #[[S]]
81 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.Z() #[[K]]
82
usages()83 void usages() {
84 SingleVersion();
85 // LINUX: @SingleVersion.ifunc()
86 // WINDOWS: @SingleVersion()
87 TwoVersions();
88 // LINUX: @TwoVersions.ifunc()
89 // WINDOWS: @TwoVersions()
90 TwoVersionsSameAttr();
91 // LINUX: @TwoVersionsSameAttr.ifunc()
92 // WINDOWS: @TwoVersionsSameAttr()
93 ThreeVersionsSameAttr();
94 // LINUX: @ThreeVersionsSameAttr.ifunc()
95 // WINDOWS: @ThreeVersionsSameAttr()
96 }
97
98 // has an extra config to emit!
99 ATTR(cpu_dispatch(ivybridge, knl, atom))
100 void TwoVersionsSameAttr(void);
101 // LINUX: define weak_odr void ()* @TwoVersionsSameAttr.resolver()
102 // LINUX: ret void ()* @TwoVersionsSameAttr.Z
103 // LINUX: ret void ()* @TwoVersionsSameAttr.S
104 // LINUX: ret void ()* @TwoVersionsSameAttr.O
105 // LINUX: call void @llvm.trap
106 // LINUX: unreachable
107
108 // WINDOWS: define weak_odr dso_local void @TwoVersionsSameAttr() comdat
109 // WINDOWS: call void @TwoVersionsSameAttr.Z
110 // WINDOWS-NEXT: ret void
111 // WINDOWS: call void @TwoVersionsSameAttr.S
112 // WINDOWS-NEXT: ret void
113 // WINDOWS: call void @TwoVersionsSameAttr.O
114 // WINDOWS-NEXT: ret void
115 // WINDOWS: call void @llvm.trap
116 // WINDOWS: unreachable
117
ATTR(cpu_dispatch (atom,ivybridge,knl))118 ATTR(cpu_dispatch(atom, ivybridge, knl))
119 void ThreeVersionsSameAttr(void){}
120 // LINUX: define weak_odr void ()* @ThreeVersionsSameAttr.resolver()
121 // LINUX: call void @__cpu_indicator_init
122 // LINUX: ret void ()* @ThreeVersionsSameAttr.Z
123 // LINUX: ret void ()* @ThreeVersionsSameAttr.S
124 // LINUX: ret void ()* @ThreeVersionsSameAttr.O
125 // LINUX: call void @llvm.trap
126 // LINUX: unreachable
127
128 // WINDOWS: define weak_odr dso_local void @ThreeVersionsSameAttr() comdat
129 // WINDOWS: call void @__cpu_indicator_init
130 // WINDOWS: call void @ThreeVersionsSameAttr.Z
131 // WINDOWS-NEXT: ret void
132 // WINDOWS: call void @ThreeVersionsSameAttr.S
133 // WINDOWS-NEXT: ret void
134 // WINDOWS: call void @ThreeVersionsSameAttr.O
135 // WINDOWS-NEXT: ret void
136 // WINDOWS: call void @llvm.trap
137 // WINDOWS: unreachable
138
139 // No Cpu Specific options.
140 ATTR(cpu_dispatch(atom, ivybridge, knl))
141 void NoSpecifics(void);
142 // LINUX: define weak_odr void ()* @NoSpecifics.resolver()
143 // LINUX: call void @__cpu_indicator_init
144 // LINUX: ret void ()* @NoSpecifics.Z
145 // LINUX: ret void ()* @NoSpecifics.S
146 // LINUX: ret void ()* @NoSpecifics.O
147 // LINUX: call void @llvm.trap
148 // LINUX: unreachable
149
150 // WINDOWS: define weak_odr dso_local void @NoSpecifics() comdat
151 // WINDOWS: call void @__cpu_indicator_init
152 // WINDOWS: call void @NoSpecifics.Z
153 // WINDOWS-NEXT: ret void
154 // WINDOWS: call void @NoSpecifics.S
155 // WINDOWS-NEXT: ret void
156 // WINDOWS: call void @NoSpecifics.O
157 // WINDOWS-NEXT: ret void
158 // WINDOWS: call void @llvm.trap
159 // WINDOWS: unreachable
160
161 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
162 void HasGeneric(void);
163 // LINUX: define weak_odr void ()* @HasGeneric.resolver()
164 // LINUX: call void @__cpu_indicator_init
165 // LINUX: ret void ()* @HasGeneric.Z
166 // LINUX: ret void ()* @HasGeneric.S
167 // LINUX: ret void ()* @HasGeneric.O
168 // LINUX: ret void ()* @HasGeneric.A
169 // LINUX-NOT: call void @llvm.trap
170
171 // WINDOWS: define weak_odr dso_local void @HasGeneric() comdat
172 // WINDOWS: call void @__cpu_indicator_init
173 // WINDOWS: call void @HasGeneric.Z
174 // WINDOWS-NEXT: ret void
175 // WINDOWS: call void @HasGeneric.S
176 // WINDOWS-NEXT: ret void
177 // WINDOWS: call void @HasGeneric.O
178 // WINDOWS-NEXT: ret void
179 // WINDOWS: call void @HasGeneric.A
180 // WINDOWS-NEXT: ret void
181 // WINDOWS-NOT: call void @llvm.trap
182
183 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
184 void HasParams(int i, double d);
185 // LINUX: define weak_odr void (i32, double)* @HasParams.resolver()
186 // LINUX: call void @__cpu_indicator_init
187 // LINUX: ret void (i32, double)* @HasParams.Z
188 // LINUX: ret void (i32, double)* @HasParams.S
189 // LINUX: ret void (i32, double)* @HasParams.O
190 // LINUX: ret void (i32, double)* @HasParams.A
191 // LINUX-NOT: call void @llvm.trap
192
193 // WINDOWS: define weak_odr dso_local void @HasParams(i32 %0, double %1) comdat
194 // WINDOWS: call void @__cpu_indicator_init
195 // WINDOWS: call void @HasParams.Z(i32 %0, double %1)
196 // WINDOWS-NEXT: ret void
197 // WINDOWS: call void @HasParams.S(i32 %0, double %1)
198 // WINDOWS-NEXT: ret void
199 // WINDOWS: call void @HasParams.O(i32 %0, double %1)
200 // WINDOWS-NEXT: ret void
201 // WINDOWS: call void @HasParams.A(i32 %0, double %1)
202 // WINDOWS-NEXT: ret void
203 // WINDOWS-NOT: call void @llvm.trap
204
205 ATTR(cpu_dispatch(atom, generic, ivybridge, knl))
206 int HasParamsAndReturn(int i, double d);
207 // LINUX: define weak_odr i32 (i32, double)* @HasParamsAndReturn.resolver()
208 // LINUX: call void @__cpu_indicator_init
209 // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.Z
210 // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.S
211 // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.O
212 // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.A
213 // LINUX-NOT: call void @llvm.trap
214
215 // WINDOWS: define weak_odr dso_local i32 @HasParamsAndReturn(i32 %0, double %1) comdat
216 // WINDOWS: call void @__cpu_indicator_init
217 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.Z(i32 %0, double %1)
218 // WINDOWS-NEXT: ret i32 %[[RET]]
219 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.S(i32 %0, double %1)
220 // WINDOWS-NEXT: ret i32 %[[RET]]
221 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.O(i32 %0, double %1)
222 // WINDOWS-NEXT: ret i32 %[[RET]]
223 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.A(i32 %0, double %1)
224 // WINDOWS-NEXT: ret i32 %[[RET]]
225 // WINDOWS-NOT: call void @llvm.trap
226
227 ATTR(cpu_dispatch(atom, generic, pentium))
228 int GenericAndPentium(int i, double d);
229 // LINUX: define weak_odr i32 (i32, double)* @GenericAndPentium.resolver()
230 // LINUX: call void @__cpu_indicator_init
231 // LINUX: ret i32 (i32, double)* @GenericAndPentium.O
232 // LINUX: ret i32 (i32, double)* @GenericAndPentium.B
233 // LINUX-NOT: ret i32 (i32, double)* @GenericAndPentium.A
234 // LINUX-NOT: call void @llvm.trap
235
236 // WINDOWS: define weak_odr dso_local i32 @GenericAndPentium(i32 %0, double %1) comdat
237 // WINDOWS: call void @__cpu_indicator_init
238 // WINDOWS: %[[RET:.+]] = musttail call i32 @GenericAndPentium.O(i32 %0, double %1)
239 // WINDOWS-NEXT: ret i32 %[[RET]]
240 // WINDOWS: %[[RET:.+]] = musttail call i32 @GenericAndPentium.B(i32 %0, double %1)
241 // WINDOWS-NEXT: ret i32 %[[RET]]
242 // WINDOWS-NOT: call i32 @GenericAndPentium.A
243 // WINDOWS-NOT: call void @llvm.trap
244
245 ATTR(cpu_dispatch(atom, pentium))
246 int DispatchFirst(void);
247 // LINUX: define weak_odr i32 ()* @DispatchFirst.resolver
248 // LINUX: ret i32 ()* @DispatchFirst.O
249 // LINUX: ret i32 ()* @DispatchFirst.B
250
251 // WINDOWS: define weak_odr dso_local i32 @DispatchFirst() comdat
252 // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.O()
253 // WINDOWS-NEXT: ret i32 %[[RET]]
254 // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.B()
255 // WINDOWS-NEXT: ret i32 %[[RET]]
256
ATTR(cpu_specific (atom))257 ATTR(cpu_specific(atom))
258 int DispatchFirst(void) {return 0;}
259 // LINUX: define i32 @DispatchFirst.O
260 // LINUX: ret i32 0
261
262 // WINDOWS: define dso_local i32 @DispatchFirst.O()
263 // WINDOWS: ret i32 0
264
ATTR(cpu_specific (pentium))265 ATTR(cpu_specific(pentium))
266 int DispatchFirst(void) {return 1;}
267 // LINUX: define i32 @DispatchFirst.B
268 // LINUX: ret i32 1
269
270 // WINDOWS: define dso_local i32 @DispatchFirst.B
271 // WINDOWS: ret i32 1
272
273 // CHECK: attributes #[[S]] = {{.*}}"target-features"="+avx,+cmov,+cx8,+f16c,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave"
274 // CHECK: attributes #[[K]] = {{.*}}"target-features"="+adx,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+bmi,+cmov,+cx8,+f16c,+fma,+lzcnt,+mmx,+movbe,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave"
275 // CHECK: attributes #[[O]] = {{.*}}"target-features"="+cmov,+cx8,+mmx,+movbe,+sse,+sse2,+sse3,+ssse3,+x87"
276