HardwareCapabilities.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using Ryujinx.Memory;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using System.Runtime.Intrinsics.X86;
  5. namespace ARMeilleure.CodeGen.X86
  6. {
  7. static class HardwareCapabilities
  8. {
  9. private delegate uint GetXcr0();
  10. static HardwareCapabilities()
  11. {
  12. if (!X86Base.IsSupported)
  13. {
  14. return;
  15. }
  16. (int maxNum, _, _, _) = X86Base.CpuId(0x00000000, 0x00000000);
  17. (_, _, int ecx1, int edx1) = X86Base.CpuId(0x00000001, 0x00000000);
  18. FeatureInfo1Edx = (FeatureFlags1Edx)edx1;
  19. FeatureInfo1Ecx = (FeatureFlags1Ecx)ecx1;
  20. if (maxNum >= 7)
  21. {
  22. (_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
  23. FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
  24. FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
  25. }
  26. Xcr0InfoEax = (Xcr0FlagsEax)GetXcr0Eax();
  27. }
  28. private static uint GetXcr0Eax()
  29. {
  30. if (!FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave))
  31. {
  32. // XSAVE feature required for xgetbv
  33. return 0;
  34. }
  35. ReadOnlySpan<byte> asmGetXcr0 = new byte[]
  36. {
  37. 0x31, 0xc9, // xor ecx, ecx
  38. 0xf, 0x01, 0xd0, // xgetbv
  39. 0xc3, // ret
  40. };
  41. using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
  42. memGetXcr0.Write(0, asmGetXcr0);
  43. memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
  44. var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
  45. return fGetXcr0();
  46. }
  47. [Flags]
  48. public enum FeatureFlags1Edx
  49. {
  50. Sse = 1 << 25,
  51. Sse2 = 1 << 26
  52. }
  53. [Flags]
  54. public enum FeatureFlags1Ecx
  55. {
  56. Sse3 = 1 << 0,
  57. Pclmulqdq = 1 << 1,
  58. Ssse3 = 1 << 9,
  59. Fma = 1 << 12,
  60. Sse41 = 1 << 19,
  61. Sse42 = 1 << 20,
  62. Popcnt = 1 << 23,
  63. Aes = 1 << 25,
  64. Xsave = 1 << 26,
  65. Osxsave = 1 << 27,
  66. Avx = 1 << 28,
  67. F16c = 1 << 29
  68. }
  69. [Flags]
  70. public enum FeatureFlags7Ebx
  71. {
  72. Avx2 = 1 << 5,
  73. Avx512f = 1 << 16,
  74. Avx512dq = 1 << 17,
  75. Sha = 1 << 29,
  76. Avx512bw = 1 << 30,
  77. Avx512vl = 1 << 31
  78. }
  79. [Flags]
  80. public enum FeatureFlags7Ecx
  81. {
  82. Gfni = 1 << 8,
  83. }
  84. [Flags]
  85. public enum Xcr0FlagsEax
  86. {
  87. Sse = 1 << 1,
  88. YmmHi128 = 1 << 2,
  89. Opmask = 1 << 5,
  90. ZmmHi256 = 1 << 6,
  91. Hi16Zmm = 1 << 7
  92. }
  93. public static FeatureFlags1Edx FeatureInfo1Edx { get; }
  94. public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
  95. public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
  96. public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
  97. public static Xcr0FlagsEax Xcr0InfoEax { get; } = 0;
  98. public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
  99. public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
  100. public static bool SupportsSse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse3);
  101. public static bool SupportsPclmulqdq => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Pclmulqdq);
  102. public static bool SupportsSsse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Ssse3);
  103. public static bool SupportsFma => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Fma);
  104. public static bool SupportsSse41 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse41);
  105. public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
  106. public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
  107. public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
  108. public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
  109. public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
  110. public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave)
  111. && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm);
  112. public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F;
  113. public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F;
  114. public static bool SupportsAvx512Dq => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512dq) && SupportsAvx512F;
  115. public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
  116. public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
  117. public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
  118. public static bool ForceLegacySse { get; set; }
  119. public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
  120. public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
  121. }
  122. }