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