3 #include "config_simd.h"
7 #if defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
8 #define WIN32_LEAN_AND_MEAN
10 #ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
11 #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
15 #if defined(HAVE_CPUID_H)
17 #elif defined(HAVE_INTRIN_H)
31 #if defined(HAVE_GCC_GET_CPUID) \
32 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
33 using reg_type
= unsigned int;
34 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
36 std::array
<reg_type
,4> ret
{};
37 __get_cpuid(f
, ret
.data(), &ret
[1], &ret
[2], &ret
[3]);
41 #elif defined(HAVE_CPUID_INTRINSIC) \
42 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
44 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
46 std::array
<reg_type
,4> ret
{};
47 (__cpuid
)(ret
.data(), f
);
55 std::optional
<CPUInfo
> GetCPUInfo()
60 auto cpuregs
= get_cpuid(0);
64 const reg_type maxfunc
{cpuregs
[0]};
66 cpuregs
= get_cpuid(0x80000000);
67 const reg_type maxextfunc
{cpuregs
[0]};
69 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[1]), 4);
70 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[3]), 4);
71 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[2]), 4);
72 auto iter_end
= std::remove(ret
.mVendor
.begin(), ret
.mVendor
.end(), '\0');
73 iter_end
= std::unique(ret
.mVendor
.begin(), iter_end
,
74 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
75 ret
.mVendor
.erase(iter_end
, ret
.mVendor
.end());
76 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.back()))
77 ret
.mVendor
.pop_back();
78 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.front()))
79 ret
.mVendor
.erase(ret
.mVendor
.begin());
81 if(maxextfunc
>= 0x80000004)
83 cpuregs
= get_cpuid(0x80000002);
84 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
85 cpuregs
= get_cpuid(0x80000003);
86 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
87 cpuregs
= get_cpuid(0x80000004);
88 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
89 iter_end
= std::remove(ret
.mName
.begin(), ret
.mName
.end(), '\0');
90 iter_end
= std::unique(ret
.mName
.begin(), iter_end
,
91 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
92 ret
.mName
.erase(iter_end
, ret
.mName
.end());
93 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.back()))
95 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.front()))
96 ret
.mName
.erase(ret
.mName
.begin());
101 cpuregs
= get_cpuid(1);
102 if((cpuregs
[3]&(1<<25)))
103 ret
.mCaps
|= CPU_CAP_SSE
;
104 if((ret
.mCaps
&CPU_CAP_SSE
) && (cpuregs
[3]&(1<<26)))
105 ret
.mCaps
|= CPU_CAP_SSE2
;
106 if((ret
.mCaps
&CPU_CAP_SSE2
) && (cpuregs
[2]&(1<<0)))
107 ret
.mCaps
|= CPU_CAP_SSE3
;
108 if((ret
.mCaps
&CPU_CAP_SSE3
) && (cpuregs
[2]&(1<<19)))
109 ret
.mCaps
|= CPU_CAP_SSE4_1
;
114 /* Assume support for whatever's supported if we can't check for it */
116 #warning "Assuming SSE 4.1 run-time support!"
117 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
119 #warning "Assuming SSE 3 run-time support!"
120 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
122 #warning "Assuming SSE 2 run-time support!"
123 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
125 #warning "Assuming SSE run-time support!"
126 ret
.mCaps
|= CPU_CAP_SSE
;
128 #endif /* CAN_GET_CPUID */
132 ret
.mCaps
|= CPU_CAP_NEON
;
133 #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
134 if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
))
135 ret
.mCaps
|= CPU_CAP_NEON
;
137 #warning "Assuming NEON run-time support!"
138 ret
.mCaps
|= CPU_CAP_NEON
;