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