From 2b1316954f169a88cfb694f4c1defc0d965455ea Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 8 Mar 2020 10:55:00 +0100 Subject: [PATCH] std: One more cpuid fix Don't read from stale eax value, rework the logic a bit so that's clear what's going on. --- lib/std/zig/system/x86.zig | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/std/zig/system/x86.zig b/lib/std/zig/system/x86.zig index c85b646f83..b4964596d2 100644 --- a/lib/std/zig/system/x86.zig +++ b/lib/std/zig/system/x86.zig @@ -2,6 +2,12 @@ const std = @import("std"); const Target = std.Target; const CrossTarget = std.zig.CrossTarget; +const XCR0_XMM = 0x02; +const XCR0_YMM = 0x04; +const XCR0_MASKREG = 0x20; +const XCR0_ZMM0_15 = 0x40; +const XCR0_ZMM16_31 = 0x80; + fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void { const idx = @as(Target.Cpu.Feature.Set.Index, @enumToInt(feature)); @@ -12,6 +18,10 @@ inline fn bit(input: u32, offset: u5) bool { return (input >> offset) & 1 != 0; } +inline fn hasMask(input: u32, mask: u32) bool { + return (input & mask) == mask; +} + pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) Target.Cpu { var cpu = Target.Cpu{ .arch = arch, @@ -309,7 +319,6 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { leaf = cpuid(1, 0); - setFeature(cpu, .cx8, bit(leaf.edx, 8)); setFeature(cpu, .cx8, bit(leaf.edx, 8)); setFeature(cpu, .cmov, bit(leaf.edx, 15)); setFeature(cpu, .mmx, bit(leaf.edx, 23)); @@ -327,11 +336,13 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { setFeature(cpu, .aes, bit(leaf.ecx, 25)); setFeature(cpu, .rdrnd, bit(leaf.ecx, 30)); - // If the CPU supports XSAVE/XRESTORE (bit 27) and AVX (bit 28) also check - // if the AVX registers are saved & restored on context switch - const has_avx_save = bit(leaf.ecx, 27) and - bit(leaf.ecx, 28) and - ((getXCR0() & 0x6) == 0x6); + const has_xsave = bit(leaf.ecx, 27); + const has_avx = bit(leaf.ecx, 28); + + // Make sure not to call xgetbv if xsave is not supported + const xcr0_eax = if (has_xsave and has_avx) getXCR0() else 0; + + const has_avx_save = hasMask(xcr0_eax, XCR0_XMM | XCR0_YMM); // LLVM approaches avx512_save by hardcoding it to true on Darwin, // because the kernel saves the context even if the bit is not set. @@ -355,7 +366,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void { // set right now. const has_avx512_save = switch (os_tag.isDarwin()) { true => true, - false => has_avx_save and ((leaf.eax & 0xE0) == 0xE0), + false => hasMask(xcr0_eax, XCR0_MASKREG | XCR0_ZMM0_15 | XCR0_ZMM16_31), }; setFeature(cpu, .avx, has_avx_save); @@ -530,6 +541,7 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf { [leaf_ptr] "r" (&cpuid_leaf) : "eax", "ebx", "ecx", "edx" ); + return cpuid_leaf; }