using Ryujinx.Memory; using System; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; namespace ARMeilleure.CodeGen.X86 { static class HardwareCapabilities { private delegate uint GetXcr0(); static HardwareCapabilities() { if (!X86Base.IsSupported) { return; } (int maxNum, _, _, _) = X86Base.CpuId(0x00000000, 0x00000000); (_, _, int ecx1, int edx1) = X86Base.CpuId(0x00000001, 0x00000000); FeatureInfo1Edx = (FeatureFlags1Edx)edx1; FeatureInfo1Ecx = (FeatureFlags1Ecx)ecx1; if (maxNum >= 7) { (_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000); FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7; FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7; } Xcr0InfoEax = (Xcr0FlagsEax)GetXcr0Eax(); } private static uint GetXcr0Eax() { if (!FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave)) { // XSAVE feature required for xgetbv return 0; } ReadOnlySpan asmGetXcr0 = new byte[] { 0x31, 0xc9, // xor ecx, ecx 0xf, 0x01, 0xd0, // xgetbv 0xc3, // ret }; using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length); memGetXcr0.Write(0, asmGetXcr0); memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute); var fGetXcr0 = Marshal.GetDelegateForFunctionPointer(memGetXcr0.Pointer); return fGetXcr0(); } [Flags] public enum FeatureFlags1Edx { Sse = 1 << 25, Sse2 = 1 << 26 } [Flags] public enum FeatureFlags1Ecx { Sse3 = 1 << 0, Pclmulqdq = 1 << 1, Ssse3 = 1 << 9, Fma = 1 << 12, Sse41 = 1 << 19, Sse42 = 1 << 20, Popcnt = 1 << 23, Aes = 1 << 25, Xsave = 1 << 26, Osxsave = 1 << 27, Avx = 1 << 28, F16c = 1 << 29 } [Flags] public enum FeatureFlags7Ebx { Avx2 = 1 << 5, Avx512f = 1 << 16, Avx512dq = 1 << 17, Sha = 1 << 29, Avx512bw = 1 << 30, Avx512vl = 1 << 31 } [Flags] public enum FeatureFlags7Ecx { Gfni = 1 << 8, } [Flags] public enum Xcr0FlagsEax { Sse = 1 << 1, YmmHi128 = 1 << 2, Opmask = 1 << 5, ZmmHi256 = 1 << 6, Hi16Zmm = 1 << 7 } public static FeatureFlags1Edx FeatureInfo1Edx { get; } public static FeatureFlags1Ecx FeatureInfo1Ecx { get; } public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0; public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0; public static Xcr0FlagsEax Xcr0InfoEax { get; } = 0; public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse); public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2); public static bool SupportsSse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse3); public static bool SupportsPclmulqdq => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Pclmulqdq); public static bool SupportsSsse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Ssse3); public static bool SupportsFma => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Fma); public static bool SupportsSse41 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse41); public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42); public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt); public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes); public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128); public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx; public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm); public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F; public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F; public static bool SupportsAvx512Dq => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512dq) && SupportsAvx512F; public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c); public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha); public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni); public static bool ForceLegacySse { get; set; } public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse; public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse; } }