Vxsort (#37159)
[platform/upstream/dotnet/runtime.git] / src / coreclr / src / gc / vxsort / isa_detection.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 #include "common.h"
5 #include <intrin.h>
6
7 #include "do_vxsort.h"
8
9 enum class SupportedISA
10 {
11     None = 0,
12     AVX2 = 1 << (int)InstructionSet::AVX2,
13     AVX512F = 1 << (int)InstructionSet::AVX512F
14 };
15
16 #if defined(TARGET_AMD64) && defined(TARGET_WINDOWS)
17
18 static DWORD64 GetEnabledXStateFeaturesHelper()
19 {
20     LIMITED_METHOD_CONTRACT;
21
22     // On Windows we have an api(GetEnabledXStateFeatures) to check if AVX is supported
23     typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
24     PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL;
25
26     HMODULE hMod = WszLoadLibraryEx(WINDOWS_KERNEL32_DLLNAME_W, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
27     if (hMod == NULL)
28         return 0;
29
30     pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures");
31
32     if (pfnGetEnabledXStateFeatures == NULL)
33     {
34         return 0;
35     }
36
37     DWORD64 FeatureMask = pfnGetEnabledXStateFeatures();
38
39     return FeatureMask;
40 }
41
42 SupportedISA DetermineSupportedISA()
43 {
44     // register definitions to make the following code more readable
45     enum reg
46     {
47         EAX = 0,
48         EBX = 1,
49         ECX = 2,
50         EDX = 3,
51         COUNT = 4
52     };
53
54     // bit definitions to make code more readable
55     enum bits
56     {
57         OCXSAVE = 1<<27,
58         AVX = 1<<28,
59         AVX2 = 1<<5,
60         AVX512F=1<<16,
61     };
62     int reg[COUNT];
63
64     __cpuid(reg, 0);
65     if (reg[EAX] < 7)
66         return SupportedISA::None;
67
68     __cpuid(reg, 1);
69
70     // both AVX and OCXSAVE feature flags must be enabled
71     if ((reg[ECX] & (OCXSAVE|AVX)) != (OCXSAVE | AVX))
72         return SupportedISA::None;
73
74     // get xcr0 register
75     DWORD64 xcr0 = _xgetbv(0);
76
77     // get OS XState info 
78     DWORD64 FeatureMask = GetEnabledXStateFeaturesHelper();
79
80     // get processor extended feature flag info
81     __cpuid(reg, 7);
82
83     // check if both AVX2 and AVX512F are supported by both processor and OS
84     if ((reg[EBX] & (AVX2 | AVX512F)) == (AVX2 | AVX512F) &&
85         (xcr0 & 0xe6) == 0xe6 &&
86         (FeatureMask & (XSTATE_MASK_AVX | XSTATE_MASK_AVX512)) == (XSTATE_MASK_AVX | XSTATE_MASK_AVX512))
87     {
88         return (SupportedISA)((int)SupportedISA::AVX2 | (int)SupportedISA::AVX512F);
89     }
90
91     // check if AVX2 is supported by both processor and OS
92     if ((reg[EBX] & AVX2) &&
93         (xcr0 & 0x06) == 0x06 &&
94         (FeatureMask & XSTATE_MASK_AVX) == XSTATE_MASK_AVX)
95     {
96         return SupportedISA::AVX2;
97     }
98
99     return SupportedISA::None;
100 }
101
102 #elif defined(TARGET_UNIX)
103
104 SupportedISA DetermineSupportedISA()
105 {
106     __builtin_cpu_init();
107     if (__builtin_cpu_supports("avx2"))
108     {
109         if (__builtin_cpu_supports("avx512f"))
110             return (SupportedISA)((int)SupportedISA::AVX2 | (int)SupportedISA::AVX512F);
111         else
112             return SupportedISA::AVX2;
113     }
114     else
115     {
116         return SupportedISA::None;
117     }
118 }
119
120 #endif // defined(TARGET_UNIX)
121
122 static bool s_initialized;
123 static SupportedISA s_supportedISA;
124
125 bool IsSupportedInstructionSet (InstructionSet instructionSet)
126 {
127     assert(s_initialized);
128     assert(instructionSet == InstructionSet::AVX2 || instructionSet == InstructionSet::AVX512F);
129     return ((int)s_supportedISA & (1 << (int)instructionSet)) != 0;
130 }
131
132 void InitSupportedInstructionSet (int32_t configSetting)
133 {
134     s_supportedISA = (SupportedISA)((int)DetermineSupportedISA() & configSetting);
135     // we are assuming that AVX2 can be used if AVX512F can,
136     // so if AVX2 is disabled, we need to disable AVX512F as well
137     if (!((int)s_supportedISA & (int)SupportedISA::AVX2))
138         s_supportedISA = SupportedISA::None;
139     s_initialized = true;
140 }