6 #if defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
7 #define WIN32_LEAN_AND_MEAN
9 #ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
10 #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
14 #if defined(HAVE_CPUID_H)
16 #elif defined(HAVE_INTRIN_H)
29 #if defined(HAVE_GCC_GET_CPUID) \
30 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
31 using reg_type
= unsigned int;
32 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
34 std::array
<reg_type
,4> ret
{};
35 __get_cpuid(f
, ret
.data(), &ret
[1], &ret
[2], &ret
[3]);
39 #elif defined(HAVE_CPUID_INTRINSIC) \
40 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
42 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
44 std::array
<reg_type
,4> ret
{};
45 (__cpuid
)(ret
.data(), f
);
53 al::optional
<CPUInfo
> GetCPUInfo()
58 auto cpuregs
= get_cpuid(0);
62 const reg_type maxfunc
{cpuregs
[0]};
64 cpuregs
= get_cpuid(0x80000000);
65 const reg_type maxextfunc
{cpuregs
[0]};
67 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[1]), 4);
68 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[3]), 4);
69 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[2]), 4);
70 auto iter_end
= std::remove(ret
.mVendor
.begin(), ret
.mVendor
.end(), '\0');
71 iter_end
= std::unique(ret
.mVendor
.begin(), iter_end
,
72 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
73 ret
.mVendor
.erase(iter_end
, ret
.mVendor
.end());
74 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.back()))
75 ret
.mVendor
.pop_back();
76 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.front()))
77 ret
.mVendor
.erase(ret
.mVendor
.begin());
79 if(maxextfunc
>= 0x80000004)
81 cpuregs
= get_cpuid(0x80000002);
82 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
83 cpuregs
= get_cpuid(0x80000003);
84 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
85 cpuregs
= get_cpuid(0x80000004);
86 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
87 iter_end
= std::remove(ret
.mName
.begin(), ret
.mName
.end(), '\0');
88 iter_end
= std::unique(ret
.mName
.begin(), iter_end
,
89 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
90 ret
.mName
.erase(iter_end
, ret
.mName
.end());
91 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.back()))
93 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.front()))
94 ret
.mName
.erase(ret
.mName
.begin());
99 cpuregs
= get_cpuid(1);
100 if((cpuregs
[3]&(1<<25)))
101 ret
.mCaps
|= CPU_CAP_SSE
;
102 if((ret
.mCaps
&CPU_CAP_SSE
) && (cpuregs
[3]&(1<<26)))
103 ret
.mCaps
|= CPU_CAP_SSE2
;
104 if((ret
.mCaps
&CPU_CAP_SSE2
) && (cpuregs
[2]&(1<<0)))
105 ret
.mCaps
|= CPU_CAP_SSE3
;
106 if((ret
.mCaps
&CPU_CAP_SSE3
) && (cpuregs
[2]&(1<<19)))
107 ret
.mCaps
|= CPU_CAP_SSE4_1
;
112 /* Assume support for whatever's supported if we can't check for it */
113 #if defined(HAVE_SSE4_1)
114 #warning "Assuming SSE 4.1 run-time support!"
115 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
116 #elif defined(HAVE_SSE3)
117 #warning "Assuming SSE 3 run-time support!"
118 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
119 #elif defined(HAVE_SSE2)
120 #warning "Assuming SSE 2 run-time support!"
121 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
122 #elif defined(HAVE_SSE)
123 #warning "Assuming SSE run-time support!"
124 ret
.mCaps
|= CPU_CAP_SSE
;
126 #endif /* CAN_GET_CPUID */
130 ret
.mCaps
|= CPU_CAP_NEON
;
131 #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
132 if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
))
133 ret
.mCaps
|= CPU_CAP_NEON
;
135 #warning "Assuming NEON run-time support!"
136 ret
.mCaps
|= CPU_CAP_NEON
;