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 
ATTR(cpu_specific (ivybridge))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 
ATTR(cpu_specific (ivybridge))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 
ATTR(cpu_specific (ivybridge))48 ATTR(cpu_specific(ivybridge))
49 void TwoVersions(void){}
50 // CHECK: define {{.*}}void @TwoVersions.S() #[[S]]
51 
ATTR(cpu_specific (knl))52 ATTR(cpu_specific(knl))
53 void TwoVersions(void){}
54 // CHECK: define {{.*}}void @TwoVersions.Z() #[[K:[0-9]+]]
55 
ATTR(cpu_specific (ivybridge,knl))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 
ATTR(cpu_specific (atom,ivybridge,knl))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 
usages()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 
ATTR(cpu_dispatch (atom,ivybridge,knl))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 
ATTR(cpu_specific (atom))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 
ATTR(cpu_specific (pentium))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