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
30 #if defined(HAVE_GCC_GET_CPUID) \
31 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
32 using reg_type
= unsigned int;
33 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
35 std::array
<reg_type
,4> ret
{};
36 __get_cpuid(f
, &ret
[0], &ret
[1], &ret
[2], &ret
[3]);
40 #elif defined(HAVE_CPUID_INTRINSIC) \
41 && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
43 inline std::array
<reg_type
,4> get_cpuid(unsigned int f
)
45 std::array
<reg_type
,4> ret
{};
46 (__cpuid
)(ret
.data(), f
);
54 al::optional
<CPUInfo
> GetCPUInfo()
59 auto cpuregs
= get_cpuid(0);
63 const reg_type maxfunc
{cpuregs
[0]};
65 cpuregs
= get_cpuid(0x80000000);
66 const reg_type maxextfunc
{cpuregs
[0]};
68 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[1]), 4);
69 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[3]), 4);
70 ret
.mVendor
.append(reinterpret_cast<char*>(&cpuregs
[2]), 4);
71 auto iter_end
= std::remove(ret
.mVendor
.begin(), ret
.mVendor
.end(), '\0');
72 iter_end
= std::unique(ret
.mVendor
.begin(), iter_end
,
73 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
74 ret
.mVendor
.erase(iter_end
, ret
.mVendor
.end());
75 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.back()))
76 ret
.mVendor
.pop_back();
77 if(!ret
.mVendor
.empty() && std::isspace(ret
.mVendor
.front()))
78 ret
.mVendor
.erase(ret
.mVendor
.begin());
80 if(maxextfunc
>= 0x80000004)
82 cpuregs
= get_cpuid(0x80000002);
83 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
84 cpuregs
= get_cpuid(0x80000003);
85 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
86 cpuregs
= get_cpuid(0x80000004);
87 ret
.mName
.append(reinterpret_cast<char*>(cpuregs
.data()), 16);
88 iter_end
= std::remove(ret
.mName
.begin(), ret
.mName
.end(), '\0');
89 iter_end
= std::unique(ret
.mName
.begin(), iter_end
,
90 [](auto&& c0
, auto&& c1
) { return std::isspace(c0
) && std::isspace(c1
); });
91 ret
.mName
.erase(iter_end
, ret
.mName
.end());
92 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.back()))
94 if(!ret
.mName
.empty() && std::isspace(ret
.mName
.front()))
95 ret
.mName
.erase(ret
.mName
.begin());
100 cpuregs
= get_cpuid(1);
101 if((cpuregs
[3]&(1<<25)))
102 ret
.mCaps
|= CPU_CAP_SSE
;
103 if((ret
.mCaps
&CPU_CAP_SSE
) && (cpuregs
[3]&(1<<26)))
104 ret
.mCaps
|= CPU_CAP_SSE2
;
105 if((ret
.mCaps
&CPU_CAP_SSE2
) && (cpuregs
[2]&(1<<0)))
106 ret
.mCaps
|= CPU_CAP_SSE3
;
107 if((ret
.mCaps
&CPU_CAP_SSE3
) && (cpuregs
[2]&(1<<19)))
108 ret
.mCaps
|= CPU_CAP_SSE4_1
;
113 /* Assume support for whatever's supported if we can't check for it */
114 #if defined(HAVE_SSE4_1)
115 #warning "Assuming SSE 4.1 run-time support!"
116 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
117 #elif defined(HAVE_SSE3)
118 #warning "Assuming SSE 3 run-time support!"
119 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
120 #elif defined(HAVE_SSE2)
121 #warning "Assuming SSE 2 run-time support!"
122 ret
.mCaps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
123 #elif defined(HAVE_SSE)
124 #warning "Assuming SSE run-time support!"
125 ret
.mCaps
|= CPU_CAP_SSE
;
127 #endif /* CAN_GET_CPUID */
131 ret
.mCaps
|= CPU_CAP_NEON
;
132 #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
133 if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
))
134 ret
.mCaps
|= CPU_CAP_NEON
;
136 #warning "Assuming NEON run-time support!"
137 ret
.mCaps
|= CPU_CAP_NEON
;
141 return al::make_optional(ret
);