authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-07 23:37:07+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-07 18:53:34-05:00
logc5885f012a2d8785d505bb3ec03a8dfab99331d2
tree03a15a839b837feda0c82216fecc06ff981b2c35
parentc25d9417d34fc7745ed50fdfe2984895657254d5

std: Fix version detection on x86

Call xgetbv only if X{SAVE,RESTORE} and AVX are detected. Closes #4670

1 files changed, 31 insertions(+), 35 deletions(-)

lib/std/zig/system/x86.zig+31-35
......@@ -30,18 +30,15 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_ta
3030 leaf = cpuid(0x1, 0);
3131
3232 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;
4440 }
41 model += ((leaf.eax >> 16) & 0xf) << 4;
4542 }
4643
4744 // Now we detect the model.
......@@ -330,11 +327,11 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
330327 setFeature(cpu, .aes, bit(leaf.ecx, 25));
331328 setFeature(cpu, .rdrnd, bit(leaf.ecx, 30));
332329
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
336333 bit(leaf.ecx, 28) and
337 ((leaf.eax & 0x6) == 0x6);
334 ((getXCR0() & 0x6) == 0x6);
338335
339336 // LLVM approaches avx512_save by hardcoding it to true on Darwin,
340337 // 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 {
358355 // set right now.
359356 const has_avx512_save = switch (os_tag.isDarwin()) {
360357 true => true,
361 false => has_avx and ((leaf.eax & 0xE0) == 0xE0),
358 false => has_avx_save and ((leaf.eax & 0xE0) == 0xE0),
362359 };
363360
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));
366363 // 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));
369366
370367 leaf = cpuid(0x80000000, 0);
371368 const max_ext_level = leaf.eax;
......@@ -376,9 +373,9 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
376373 setFeature(cpu, .lzcnt, bit(leaf.ecx, 5));
377374 setFeature(cpu, .sse4a, bit(leaf.ecx, 6));
378375 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);
380377 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);
382379 setFeature(cpu, .tbm, bit(leaf.ecx, 21));
383380 setFeature(cpu, .mwaitx, bit(leaf.ecx, 29));
384381 setFeature(cpu, .@"64bit", bit(leaf.edx, 29));
......@@ -409,7 +406,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
409406 setFeature(cpu, .sgx, bit(leaf.ebx, 2));
410407 setFeature(cpu, .bmi, bit(leaf.ebx, 3));
411408 // 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);
413410 setFeature(cpu, .bmi2, bit(leaf.ebx, 8));
414411 setFeature(cpu, .invpcid, bit(leaf.ebx, 10));
415412 setFeature(cpu, .rtm, bit(leaf.ebx, 11));
......@@ -435,8 +432,8 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
435432 setFeature(cpu, .avx512vbmi2, bit(leaf.ecx, 6) and has_avx512_save);
436433 setFeature(cpu, .shstk, bit(leaf.ecx, 7));
437434 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);
440437 setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save);
441438 setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save);
442439 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 {
487484 }
488485 }
489486
490 if (max_level >= 0xD and has_avx) {
487 if (max_level >= 0xD and has_avx_save) {
491488 leaf = cpuid(0xD, 0x1);
492489 // Only enable XSAVE if OS has enabled support for saving YMM state.
493490 setFeature(cpu, .xsaveopt, bit(leaf.eax, 0));
......@@ -518,20 +515,19 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
518515 // Workaround for https://github.com/ziglang/zig/issues/215
519516 // Inline assembly in zig only supports one output,
520517 // 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;
523519
524520 // valid for both x86 and x86_64
525521 asm volatile (
526522 \\ cpuid
527 \\ movl %%eax, (%[leaf_ptr])
523 \\ movl %%eax, 0(%[leaf_ptr])
528524 \\ movl %%ebx, 4(%[leaf_ptr])
529525 \\ movl %%ecx, 8(%[leaf_ptr])
530526 \\ movl %%edx, 12(%[leaf_ptr])
531527 :
532528 : [leaf_id] "{eax}" (leaf_id),
533529 [subid] "{ecx}" (subid),
534 [leaf_ptr] "r" (leaf_ptr)
530 [leaf_ptr] "r" (&cpuid_leaf)
535531 : "eax", "ebx", "ecx", "edx"
536532 );
537533 return cpuid_leaf;
......@@ -539,11 +535,11 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
539535
540536// Read control register 0 (XCR0). Used to detect features such as AVX.
541537fn getXCR0() u32 {
542 return asm (
543 \\ .byte 0x0F, 0x01, 0xD0
538 return asm volatile (
539 \\ xor %%ecx, %%ecx
540 \\ xgetbv
544541 : [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"
548544 );
549545}