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-apple-macos -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX 3 // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WINDOWS 4 5 #ifdef _WIN64 6 #define ATTR(X) __declspec(X) 7 #else 8 #define ATTR(X) __attribute__((X)) 9 #endif // _WIN64 10 11 // Each version should have an IFunc and an alias. 12 // LINUX: @SingleVersion = weak_odr alias void (), ptr @SingleVersion.ifunc 13 // LINUX: @TwoVersions = weak_odr alias void (), ptr @TwoVersions.ifunc 14 // LINUX: @OrderDispatchUsageSpecific = weak_odr alias void (), ptr @OrderDispatchUsageSpecific.ifunc 15 // LINUX: @TwoVersionsSameAttr = weak_odr alias void (), ptr @TwoVersionsSameAttr.ifunc 16 // LINUX: @ThreeVersionsSameAttr = weak_odr alias void (), ptr @ThreeVersionsSameAttr.ifunc 17 // LINUX: @OrderSpecificUsageDispatch = weak_odr alias void (), ptr @OrderSpecificUsageDispatch.ifunc 18 // LINUX: @NoSpecifics = weak_odr alias void (), ptr @NoSpecifics.ifunc 19 // LINUX: @HasGeneric = weak_odr alias void (), ptr @HasGeneric.ifunc 20 // LINUX: @HasParams = weak_odr alias void (i32, double), ptr @HasParams.ifunc 21 // LINUX: @HasParamsAndReturn = weak_odr alias i32 (i32, double), ptr @HasParamsAndReturn.ifunc 22 // LINUX: @GenericAndPentium = weak_odr alias i32 (i32, double), ptr @GenericAndPentium.ifunc 23 // LINUX: @DispatchFirst = weak_odr alias i32 (), ptr @DispatchFirst.ifunc 24 25 // LINUX: @SingleVersion.ifunc = weak_odr ifunc void (), ptr @SingleVersion.resolver 26 // LINUX: @TwoVersions.ifunc = weak_odr ifunc void (), ptr @TwoVersions.resolver 27 // LINUX: @OrderDispatchUsageSpecific.ifunc = weak_odr ifunc void (), ptr @OrderDispatchUsageSpecific.resolver 28 // LINUX: @TwoVersionsSameAttr.ifunc = weak_odr ifunc void (), ptr @TwoVersionsSameAttr.resolver 29 // LINUX: @ThreeVersionsSameAttr.ifunc = weak_odr ifunc void (), ptr @ThreeVersionsSameAttr.resolver 30 // LINUX: @OrderSpecificUsageDispatch.ifunc = weak_odr ifunc void (), ptr @OrderSpecificUsageDispatch.resolver 31 // LINUX: @NoSpecifics.ifunc = weak_odr ifunc void (), ptr @NoSpecifics.resolver 32 // LINUX: @HasGeneric.ifunc = weak_odr ifunc void (), ptr @HasGeneric.resolver 33 // LINUX: @HasParams.ifunc = weak_odr ifunc void (i32, double), ptr @HasParams.resolver 34 // LINUX: @HasParamsAndReturn.ifunc = weak_odr ifunc i32 (i32, double), ptr @HasParamsAndReturn.resolver 35 // LINUX: @GenericAndPentium.ifunc = weak_odr ifunc i32 (i32, double), ptr @GenericAndPentium.resolver 36 // LINUX: @DispatchFirst.ifunc = weak_odr ifunc i32 (), ptr @DispatchFirst.resolver 37 38 ATTR(cpu_specific(ivybridge)) 39 void SingleVersion(void){} 40 // LINUX: define{{.*}} void @SingleVersion.S() #[[S:[0-9]+]] 41 // WINDOWS: define dso_local void @SingleVersion.S() #[[S:[0-9]+]] 42 43 ATTR(cpu_dispatch(ivybridge)) 44 void SingleVersion(void); 45 // LINUX: define weak_odr ptr @SingleVersion.resolver() 46 // LINUX: call void @__cpu_indicator_init 47 // LINUX: %[[FEAT_INIT:.+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4 48 // LINUX: %[[FEAT_JOIN:.+]] = and i32 %[[FEAT_INIT]], 525311 49 // LINUX: %[[FEAT_CHECK:.+]] = icmp eq i32 %[[FEAT_JOIN]], 525311 50 // LINUX: ret ptr @SingleVersion.S 51 // LINUX: call void @llvm.trap 52 // LINUX: unreachable 53 54 // WINDOWS: define weak_odr dso_local void @SingleVersion() comdat 55 // WINDOWS: call void @__cpu_indicator_init() 56 // WINDOWS: %[[FEAT_INIT:.+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4 57 // WINDOWS: %[[FEAT_JOIN:.+]] = and i32 %[[FEAT_INIT]], 525311 58 // WINDOWS: %[[FEAT_CHECK:.+]] = icmp eq i32 %[[FEAT_JOIN]], 525311 59 // WINDOWS: call void @SingleVersion.S() 60 // WINDOWS-NEXT: ret void 61 // WINDOWS: call void @llvm.trap 62 // WINDOWS: unreachable 63 64 ATTR(cpu_specific(ivybridge)) 65 void NotCalled(void){} 66 // LINUX: define{{.*}} void @NotCalled.S() #[[S]] 67 // WINDOWS: define dso_local void @NotCalled.S() #[[S:[0-9]+]] 68 69 // Done before any of the implementations. Also has an undecorated forward 70 // declaration. 71 void TwoVersions(void); 72 73 ATTR(cpu_dispatch(ivybridge, knl)) 74 void TwoVersions(void); 75 // LINUX: define weak_odr ptr @TwoVersions.resolver() 76 // LINUX: call void @__cpu_indicator_init 77 // LINUX: %[[FEAT_INIT:.+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4 78 // LINUX: %[[FEAT_JOIN:.+]] = and i32 %[[FEAT_INIT]], 9422847 79 // LINUX: %[[FEAT_CHECK:.+]] = icmp eq i32 %[[FEAT_JOIN]], 9422847 80 // LINUX: ret ptr @TwoVersions.Z 81 // LINUX: ret ptr @TwoVersions.S 82 // LINUX: call void @llvm.trap 83 // LINUX: unreachable 84 85 // WINDOWS: define weak_odr dso_local void @TwoVersions() comdat 86 // WINDOWS: call void @__cpu_indicator_init() 87 // WINDOWS: %[[FEAT_INIT:.+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4 88 // WINDOWS: %[[FEAT_JOIN:.+]] = and i32 %[[FEAT_INIT]], 9422847 89 // WINDOWS: %[[FEAT_CHECK:.+]] = icmp eq i32 %[[FEAT_JOIN]], 9422847 90 // WINDOWS: call void @TwoVersions.Z() 91 // WINDOWS-NEXT: ret void 92 // WINDOWS: call void @TwoVersions.S() 93 // WINDOWS-NEXT: ret void 94 // WINDOWS: call void @llvm.trap 95 // WINDOWS: unreachable 96 97 ATTR(cpu_specific(ivybridge)) 98 void TwoVersions(void){} 99 // CHECK: define {{.*}}void @TwoVersions.S() #[[S]] 100 101 ATTR(cpu_specific(knl)) 102 void TwoVersions(void){} 103 // CHECK: define {{.*}}void @TwoVersions.Z() #[[K:[0-9]+]] 104 105 ATTR(cpu_specific(ivybridge, knl)) 106 void TwoVersionsSameAttr(void){} 107 // CHECK: define {{.*}}void @TwoVersionsSameAttr.S() #[[S]] 108 // CHECK: define {{.*}}void @TwoVersionsSameAttr.Z() #[[K]] 109 110 ATTR(cpu_specific(atom, ivybridge, knl)) 111 void ThreeVersionsSameAttr(void){} 112 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.O() #[[O:[0-9]+]] 113 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.S() #[[S]] 114 // CHECK: define {{.*}}void @ThreeVersionsSameAttr.Z() #[[K]] 115 116 ATTR(cpu_specific(knl)) 117 void CpuSpecificNoDispatch(void) {} 118 // CHECK: define {{.*}}void @CpuSpecificNoDispatch.Z() #[[K:[0-9]+]] 119 120 ATTR(cpu_dispatch(knl)) 121 void OrderDispatchUsageSpecific(void); 122 // LINUX: define weak_odr ptr @OrderDispatchUsageSpecific.resolver() 123 // LINUX: call void @__cpu_indicator_init 124 // LINUX: ret ptr @OrderDispatchUsageSpecific.Z 125 // LINUX: call void @llvm.trap 126 // LINUX: unreachable 127 128 // WINDOWS: define weak_odr dso_local void @OrderDispatchUsageSpecific() comdat 129 // WINDOWS: call void @__cpu_indicator_init() 130 // WINDOWS: call void @OrderDispatchUsageSpecific.Z() 131 // WINDOWS-NEXT: ret void 132 // WINDOWS: call void @llvm.trap 133 // WINDOWS: unreachable 134 135 // CHECK: define {{.*}}void @OrderDispatchUsageSpecific.Z() 136 137 ATTR(cpu_specific(knl)) 138 void OrderSpecificUsageDispatch(void) {} 139 // CHECK: define {{.*}}void @OrderSpecificUsageDispatch.Z() #[[K:[0-9]+]] 140 141 void usages(void) { 142 SingleVersion(); 143 // LINUX: @SingleVersion.ifunc() 144 // WINDOWS: @SingleVersion() 145 TwoVersions(); 146 // LINUX: @TwoVersions.ifunc() 147 // WINDOWS: @TwoVersions() 148 TwoVersionsSameAttr(); 149 // LINUX: @TwoVersionsSameAttr.ifunc() 150 // WINDOWS: @TwoVersionsSameAttr() 151 ThreeVersionsSameAttr(); 152 // LINUX: @ThreeVersionsSameAttr.ifunc() 153 // WINDOWS: @ThreeVersionsSameAttr() 154 CpuSpecificNoDispatch(); 155 // LINUX: @CpuSpecificNoDispatch.ifunc() 156 // WINDOWS: @CpuSpecificNoDispatch() 157 // 158 // Adding another use of CpuSpecificNoDispatch reproduces the 159 // crash in https://github.com/llvm/llvm-project/issues/115299 160 CpuSpecificNoDispatch(); 161 // LINUX: @CpuSpecificNoDispatch.ifunc() 162 // WINDOWS: @CpuSpecificNoDispatch() 163 OrderDispatchUsageSpecific(); 164 // LINUX: @OrderDispatchUsageSpecific.ifunc() 165 // WINDOWS: @OrderDispatchUsageSpecific() 166 OrderSpecificUsageDispatch(); 167 // LINUX: @OrderSpecificUsageDispatch.ifunc() 168 // WINDOWS: @OrderSpecificUsageDispatch() 169 } 170 171 // LINUX: declare void @CpuSpecificNoDispatch.ifunc() 172 173 // has an extra config to emit! 174 ATTR(cpu_dispatch(ivybridge, knl, atom)) 175 void TwoVersionsSameAttr(void); 176 // LINUX: define weak_odr ptr @TwoVersionsSameAttr.resolver() 177 // LINUX: ret ptr @TwoVersionsSameAttr.Z 178 // LINUX: ret ptr @TwoVersionsSameAttr.S 179 // LINUX: ret ptr @TwoVersionsSameAttr.O 180 // LINUX: call void @llvm.trap 181 // LINUX: unreachable 182 183 // WINDOWS: define weak_odr dso_local void @TwoVersionsSameAttr() comdat 184 // WINDOWS: call void @TwoVersionsSameAttr.Z 185 // WINDOWS-NEXT: ret void 186 // WINDOWS: call void @TwoVersionsSameAttr.S 187 // WINDOWS-NEXT: ret void 188 // WINDOWS: call void @TwoVersionsSameAttr.O 189 // WINDOWS-NEXT: ret void 190 // WINDOWS: call void @llvm.trap 191 // WINDOWS: unreachable 192 193 ATTR(cpu_dispatch(atom, ivybridge, knl)) 194 void ThreeVersionsSameAttr(void){} 195 // LINUX: define weak_odr ptr @ThreeVersionsSameAttr.resolver() 196 // LINUX: call void @__cpu_indicator_init 197 // LINUX: ret ptr @ThreeVersionsSameAttr.Z 198 // LINUX: ret ptr @ThreeVersionsSameAttr.S 199 // LINUX: ret ptr @ThreeVersionsSameAttr.O 200 // LINUX: call void @llvm.trap 201 // LINUX: unreachable 202 203 // WINDOWS: define weak_odr dso_local void @ThreeVersionsSameAttr() comdat 204 // WINDOWS: call void @__cpu_indicator_init 205 // WINDOWS: call void @ThreeVersionsSameAttr.Z 206 // WINDOWS-NEXT: ret void 207 // WINDOWS: call void @ThreeVersionsSameAttr.S 208 // WINDOWS-NEXT: ret void 209 // WINDOWS: call void @ThreeVersionsSameAttr.O 210 // WINDOWS-NEXT: ret void 211 // WINDOWS: call void @llvm.trap 212 // WINDOWS: unreachable 213 214 ATTR(cpu_dispatch(knl)) 215 void OrderSpecificUsageDispatch(void); 216 // LINUX: define weak_odr ptr @OrderSpecificUsageDispatch.resolver() 217 // LINUX: ret ptr @OrderSpecificUsageDispatch.Z 218 219 // WINDOWS: define weak_odr dso_local void @OrderSpecificUsageDispatch() comdat 220 // WINDOWS: call void @__cpu_indicator_init 221 // WINDOWS: call void @OrderSpecificUsageDispatch.Z 222 // WINDOWS-NEXT: ret void 223 224 // No Cpu Specific options. 225 ATTR(cpu_dispatch(atom, ivybridge, knl)) 226 void NoSpecifics(void); 227 // LINUX: define weak_odr ptr @NoSpecifics.resolver() 228 // LINUX: call void @__cpu_indicator_init 229 // LINUX: ret ptr @NoSpecifics.Z 230 // LINUX: ret ptr @NoSpecifics.S 231 // LINUX: ret ptr @NoSpecifics.O 232 // LINUX: call void @llvm.trap 233 // LINUX: unreachable 234 235 // WINDOWS: define weak_odr dso_local void @NoSpecifics() comdat 236 // WINDOWS: call void @__cpu_indicator_init 237 // WINDOWS: call void @NoSpecifics.Z 238 // WINDOWS-NEXT: ret void 239 // WINDOWS: call void @NoSpecifics.S 240 // WINDOWS-NEXT: ret void 241 // WINDOWS: call void @NoSpecifics.O 242 // WINDOWS-NEXT: ret void 243 // WINDOWS: call void @llvm.trap 244 // WINDOWS: unreachable 245 246 ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) 247 void HasGeneric(void); 248 // LINUX: define weak_odr ptr @HasGeneric.resolver() 249 // LINUX: call void @__cpu_indicator_init 250 // LINUX: ret ptr @HasGeneric.Z 251 // LINUX: ret ptr @HasGeneric.S 252 // LINUX: ret ptr @HasGeneric.O 253 // LINUX: ret ptr @HasGeneric.A 254 // LINUX-NOT: call void @llvm.trap 255 256 // WINDOWS: define weak_odr dso_local void @HasGeneric() comdat 257 // WINDOWS: call void @__cpu_indicator_init 258 // WINDOWS: call void @HasGeneric.Z 259 // WINDOWS-NEXT: ret void 260 // WINDOWS: call void @HasGeneric.S 261 // WINDOWS-NEXT: ret void 262 // WINDOWS: call void @HasGeneric.O 263 // WINDOWS-NEXT: ret void 264 // WINDOWS: call void @HasGeneric.A 265 // WINDOWS-NEXT: ret void 266 // WINDOWS-NOT: call void @llvm.trap 267 268 ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) 269 void HasParams(int i, double d); 270 // LINUX: define weak_odr ptr @HasParams.resolver() 271 // LINUX: call void @__cpu_indicator_init 272 // LINUX: ret ptr @HasParams.Z 273 // LINUX: ret ptr @HasParams.S 274 // LINUX: ret ptr @HasParams.O 275 // LINUX: ret ptr @HasParams.A 276 // LINUX-NOT: call void @llvm.trap 277 278 // WINDOWS: define weak_odr dso_local void @HasParams(i32 %0, double %1) comdat 279 // WINDOWS: call void @__cpu_indicator_init 280 // WINDOWS: call void @HasParams.Z(i32 %0, double %1) 281 // WINDOWS-NEXT: ret void 282 // WINDOWS: call void @HasParams.S(i32 %0, double %1) 283 // WINDOWS-NEXT: ret void 284 // WINDOWS: call void @HasParams.O(i32 %0, double %1) 285 // WINDOWS-NEXT: ret void 286 // WINDOWS: call void @HasParams.A(i32 %0, double %1) 287 // WINDOWS-NEXT: ret void 288 // WINDOWS-NOT: call void @llvm.trap 289 290 ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) 291 int HasParamsAndReturn(int i, double d); 292 // LINUX: define weak_odr ptr @HasParamsAndReturn.resolver() 293 // LINUX: call void @__cpu_indicator_init 294 // LINUX: ret ptr @HasParamsAndReturn.Z 295 // LINUX: ret ptr @HasParamsAndReturn.S 296 // LINUX: ret ptr @HasParamsAndReturn.O 297 // LINUX: ret ptr @HasParamsAndReturn.A 298 // LINUX-NOT: call void @llvm.trap 299 300 // WINDOWS: define weak_odr dso_local i32 @HasParamsAndReturn(i32 %0, double %1) comdat 301 // WINDOWS: call void @__cpu_indicator_init 302 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.Z(i32 %0, double %1) 303 // WINDOWS-NEXT: ret i32 %[[RET]] 304 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.S(i32 %0, double %1) 305 // WINDOWS-NEXT: ret i32 %[[RET]] 306 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.O(i32 %0, double %1) 307 // WINDOWS-NEXT: ret i32 %[[RET]] 308 // WINDOWS: %[[RET:.+]] = musttail call i32 @HasParamsAndReturn.A(i32 %0, double %1) 309 // WINDOWS-NEXT: ret i32 %[[RET]] 310 // WINDOWS-NOT: call void @llvm.trap 311 312 ATTR(cpu_dispatch(atom, generic, pentium)) 313 int GenericAndPentium(int i, double d); 314 // LINUX: define weak_odr ptr @GenericAndPentium.resolver() 315 // LINUX: call void @__cpu_indicator_init 316 // LINUX: ret ptr @GenericAndPentium.O 317 // LINUX: ret ptr @GenericAndPentium.B 318 // LINUX-NOT: ret ptr @GenericAndPentium.A 319 // LINUX-NOT: call void @llvm.trap 320 321 // WINDOWS: define weak_odr dso_local i32 @GenericAndPentium(i32 %0, double %1) comdat 322 // WINDOWS: call void @__cpu_indicator_init 323 // WINDOWS: %[[RET:.+]] = musttail call i32 @GenericAndPentium.O(i32 %0, double %1) 324 // WINDOWS-NEXT: ret i32 %[[RET]] 325 // WINDOWS: %[[RET:.+]] = musttail call i32 @GenericAndPentium.B(i32 %0, double %1) 326 // WINDOWS-NEXT: ret i32 %[[RET]] 327 // WINDOWS-NOT: call i32 @GenericAndPentium.A 328 // WINDOWS-NOT: call void @llvm.trap 329 330 ATTR(cpu_dispatch(atom, pentium)) 331 int DispatchFirst(void); 332 // LINUX: define weak_odr ptr @DispatchFirst.resolver 333 // LINUX: ret ptr @DispatchFirst.O 334 // LINUX: ret ptr @DispatchFirst.B 335 336 // WINDOWS: define weak_odr dso_local i32 @DispatchFirst() comdat 337 // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.O() 338 // WINDOWS-NEXT: ret i32 %[[RET]] 339 // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.B() 340 // WINDOWS-NEXT: ret i32 %[[RET]] 341 342 ATTR(cpu_specific(atom)) 343 int DispatchFirst(void) {return 0;} 344 // LINUX: define{{.*}} i32 @DispatchFirst.O 345 // LINUX: ret i32 0 346 347 // WINDOWS: define dso_local i32 @DispatchFirst.O() 348 // WINDOWS: ret i32 0 349 350 ATTR(cpu_specific(pentium)) 351 int DispatchFirst(void) {return 1;} 352 // LINUX: define{{.*}} i32 @DispatchFirst.B 353 // LINUX: ret i32 1 354 355 // WINDOWS: define dso_local i32 @DispatchFirst.B 356 // WINDOWS: ret i32 1 357 358 ATTR(cpu_specific(knl)) 359 void OrderDispatchUsageSpecific(void) {} 360 361 // CHECK: attributes #[[S]] = {{.*}}"target-features"="+avx,+cmov,+crc32,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" 362 // CHECK-SAME: "tune-cpu"="ivybridge" 363 // CHECK: attributes #[[K]] = {{.*}}"target-features"="+adx,+aes,+avx,+avx2,+avx512cd,+avx512f,+bmi,+bmi2,+cmov,+crc32,+cx16,+cx8,+evex512,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" 364 // CHECK-SAME: "tune-cpu"="knl" 365 // CHECK: attributes #[[O]] = {{.*}}"target-features"="+cmov,+cx16,+cx8,+fxsr,+mmx,+movbe,+sahf,+sse,+sse2,+sse3,+ssse3,+x87" 366 // CHECK-SAME: "tune-cpu"="atom" 367