| ... | ... | @@ -30,18 +30,15 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_ta |
| 30 | 30 | leaf = cpuid(0x1, 0); |
| 31 | 31 | |
| 32 | 32 | const brand_id = leaf.ebx & 0xff; |
| 33 | | var family: u32 = 0; |
| 34 | | var model: u32 = 0; |
| 35 | | |
| 36 | | { // Detect model and family |
| 37 | | family = (leaf.eax >> 8) & 0xf; |
| 38 | | model = (leaf.eax >> 4) & 0xf; |
| 39 | | if (family == 6 or family == 0xf) { |
| 40 | | if (family == 0xf) { |
| 41 | | family += (leaf.eax >> 20) & 0xff; |
| 42 | | } |
| 43 | | model += ((leaf.eax >> 16) & 0xf) << 4; |
| 33 | |
| 34 | // Detect model and family |
| 35 | var family = (leaf.eax >> 8) & 0xf; |
| 36 | var model = (leaf.eax >> 4) & 0xf; |
| 37 | if (family == 6 or family == 0xf) { |
| 38 | if (family == 0xf) { |
| 39 | family += (leaf.eax >> 20) & 0xff; |
| 44 | 40 | } |
| 41 | model += ((leaf.eax >> 16) & 0xf) << 4; |
| 45 | 42 | } |
| 46 | 43 | |
| 47 | 44 | // Now we detect the model. |
| ... | ... | @@ -330,11 +327,11 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 330 | 327 | setFeature(cpu, .aes, bit(leaf.ecx, 25)); |
| 331 | 328 | setFeature(cpu, .rdrnd, bit(leaf.ecx, 30)); |
| 332 | 329 | |
| 333 | | leaf.eax = getXCR0(); |
| 334 | | |
| 335 | | const has_avx = bit(leaf.ecx, 27) and |
| 330 | // If the CPU supports XSAVE/XRESTORE (bit 27) and AVX (bit 28) also check |
| 331 | // if the AVX registers are saved & restored on context switch |
| 332 | const has_avx_save = bit(leaf.ecx, 27) and |
| 336 | 333 | bit(leaf.ecx, 28) and |
| 337 | | ((leaf.eax & 0x6) == 0x6); |
| 334 | ((getXCR0() & 0x6) == 0x6); |
| 338 | 335 | |
| 339 | 336 | // LLVM approaches avx512_save by hardcoding it to true on Darwin, |
| 340 | 337 | // because the kernel saves the context even if the bit is not set. |
| ... | ... | @@ -358,14 +355,14 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 358 | 355 | // set right now. |
| 359 | 356 | const has_avx512_save = switch (os_tag.isDarwin()) { |
| 360 | 357 | true => true, |
| 361 | | false => has_avx and ((leaf.eax & 0xE0) == 0xE0), |
| 358 | false => has_avx_save and ((leaf.eax & 0xE0) == 0xE0), |
| 362 | 359 | }; |
| 363 | 360 | |
| 364 | | setFeature(cpu, .avx, has_avx); |
| 365 | | setFeature(cpu, .fma, has_avx and bit(leaf.ecx, 12)); |
| 361 | setFeature(cpu, .avx, has_avx_save); |
| 362 | setFeature(cpu, .fma, has_avx_save and bit(leaf.ecx, 12)); |
| 366 | 363 | // Only enable XSAVE if OS has enabled support for saving YMM state. |
| 367 | | setFeature(cpu, .xsave, has_avx and bit(leaf.ecx, 26)); |
| 368 | | setFeature(cpu, .f16c, has_avx and bit(leaf.ecx, 29)); |
| 364 | setFeature(cpu, .xsave, has_avx_save and bit(leaf.ecx, 26)); |
| 365 | setFeature(cpu, .f16c, has_avx_save and bit(leaf.ecx, 29)); |
| 369 | 366 | |
| 370 | 367 | leaf = cpuid(0x80000000, 0); |
| 371 | 368 | const max_ext_level = leaf.eax; |
| ... | ... | @@ -376,9 +373,9 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 376 | 373 | setFeature(cpu, .lzcnt, bit(leaf.ecx, 5)); |
| 377 | 374 | setFeature(cpu, .sse4a, bit(leaf.ecx, 6)); |
| 378 | 375 | setFeature(cpu, .prfchw, bit(leaf.ecx, 8)); |
| 379 | | setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx); |
| 376 | setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx_save); |
| 380 | 377 | setFeature(cpu, .lwp, bit(leaf.ecx, 15)); |
| 381 | | setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx); |
| 378 | setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx_save); |
| 382 | 379 | setFeature(cpu, .tbm, bit(leaf.ecx, 21)); |
| 383 | 380 | setFeature(cpu, .mwaitx, bit(leaf.ecx, 29)); |
| 384 | 381 | setFeature(cpu, .@"64bit", bit(leaf.edx, 29)); |
| ... | ... | @@ -409,7 +406,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 409 | 406 | setFeature(cpu, .sgx, bit(leaf.ebx, 2)); |
| 410 | 407 | setFeature(cpu, .bmi, bit(leaf.ebx, 3)); |
| 411 | 408 | // AVX2 is only supported if we have the OS save support from AVX. |
| 412 | | setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx); |
| 409 | setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx_save); |
| 413 | 410 | setFeature(cpu, .bmi2, bit(leaf.ebx, 8)); |
| 414 | 411 | setFeature(cpu, .invpcid, bit(leaf.ebx, 10)); |
| 415 | 412 | setFeature(cpu, .rtm, bit(leaf.ebx, 11)); |
| ... | ... | @@ -435,8 +432,8 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 435 | 432 | setFeature(cpu, .avx512vbmi2, bit(leaf.ecx, 6) and has_avx512_save); |
| 436 | 433 | setFeature(cpu, .shstk, bit(leaf.ecx, 7)); |
| 437 | 434 | setFeature(cpu, .gfni, bit(leaf.ecx, 8)); |
| 438 | | setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx); |
| 439 | | setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx); |
| 435 | setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx_save); |
| 436 | setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx_save); |
| 440 | 437 | setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save); |
| 441 | 438 | setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save); |
| 442 | 439 | setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save); |
| ... | ... | @@ -487,7 +484,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { |
| 487 | 484 | } |
| 488 | 485 | } |
| 489 | 486 | |
| 490 | | if (max_level >= 0xD and has_avx) { |
| 487 | if (max_level >= 0xD and has_avx_save) { |
| 491 | 488 | leaf = cpuid(0xD, 0x1); |
| 492 | 489 | // Only enable XSAVE if OS has enabled support for saving YMM state. |
| 493 | 490 | setFeature(cpu, .xsaveopt, bit(leaf.eax, 0)); |
| ... | ... | @@ -518,20 +515,19 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf { |
| 518 | 515 | // Workaround for https://github.com/ziglang/zig/issues/215 |
| 519 | 516 | // Inline assembly in zig only supports one output, |
| 520 | 517 | // so we pass a pointer to the struct. |
| 521 | | var cpuid_leaf = CpuidLeaf{ .eax = 0, .ebx = 0, .ecx = 0, .edx = 0 }; |
| 522 | | const leaf_ptr = &cpuid_leaf; |
| 518 | var cpuid_leaf: CpuidLeaf = undefined; |
| 523 | 519 | |
| 524 | 520 | // valid for both x86 and x86_64 |
| 525 | 521 | asm volatile ( |
| 526 | 522 | \\ cpuid |
| 527 | | \\ movl %%eax, (%[leaf_ptr]) |
| 523 | \\ movl %%eax, 0(%[leaf_ptr]) |
| 528 | 524 | \\ movl %%ebx, 4(%[leaf_ptr]) |
| 529 | 525 | \\ movl %%ecx, 8(%[leaf_ptr]) |
| 530 | 526 | \\ movl %%edx, 12(%[leaf_ptr]) |
| 531 | 527 | : |
| 532 | 528 | : [leaf_id] "{eax}" (leaf_id), |
| 533 | 529 | [subid] "{ecx}" (subid), |
| 534 | | [leaf_ptr] "r" (leaf_ptr) |
| 530 | [leaf_ptr] "r" (&cpuid_leaf) |
| 535 | 531 | : "eax", "ebx", "ecx", "edx" |
| 536 | 532 | ); |
| 537 | 533 | return cpuid_leaf; |
| ... | ... | @@ -539,11 +535,11 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf { |
| 539 | 535 | |
| 540 | 536 | // Read control register 0 (XCR0). Used to detect features such as AVX. |
| 541 | 537 | fn getXCR0() u32 { |
| 542 | | return asm ( |
| 543 | | \\ .byte 0x0F, 0x01, 0xD0 |
| 538 | return asm volatile ( |
| 539 | \\ xor %%ecx, %%ecx |
| 540 | \\ xgetbv |
| 544 | 541 | : [ret] "={eax}" (-> u32) |
| 545 | | : [number] "{eax}" (@as(u32, 0)), |
| 546 | | [number] "{edx}" (@as(u32, 0)), |
| 547 | | [number] "{ecx}" (@as(u32, 0)) |
| 542 | : |
| 543 | : "eax", "edx", "ecx" |
| 548 | 544 | ); |
| 549 | 545 | } |