xref: /aosp_15_r20/external/abseil-cpp/absl/crc/internal/cpu_detect.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2022 The Abseil Authors
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include "absl/crc/internal/cpu_detect.h"
16*9356374aSAndroid Build Coastguard Worker 
17*9356374aSAndroid Build Coastguard Worker #include <cstdint>
18*9356374aSAndroid Build Coastguard Worker #include <string>
19*9356374aSAndroid Build Coastguard Worker 
20*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
21*9356374aSAndroid Build Coastguard Worker 
22*9356374aSAndroid Build Coastguard Worker #if defined(__aarch64__) && defined(__linux__)
23*9356374aSAndroid Build Coastguard Worker #include <asm/hwcap.h>
24*9356374aSAndroid Build Coastguard Worker #include <sys/auxv.h>
25*9356374aSAndroid Build Coastguard Worker #endif
26*9356374aSAndroid Build Coastguard Worker 
27*9356374aSAndroid Build Coastguard Worker #if defined(_WIN32) || defined(_WIN64)
28*9356374aSAndroid Build Coastguard Worker #include <intrin.h>
29*9356374aSAndroid Build Coastguard Worker #endif
30*9356374aSAndroid Build Coastguard Worker 
31*9356374aSAndroid Build Coastguard Worker #if defined(__x86_64__) || defined(_M_X64)
32*9356374aSAndroid Build Coastguard Worker #if ABSL_HAVE_BUILTIN(__cpuid)
33*9356374aSAndroid Build Coastguard Worker // MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers
34*9356374aSAndroid Build Coastguard Worker // for non-Windows build environments.
35*9356374aSAndroid Build Coastguard Worker extern void __cpuid(int[4], int);
36*9356374aSAndroid Build Coastguard Worker #elif !defined(_WIN32) && !defined(_WIN64)
37*9356374aSAndroid Build Coastguard Worker // MSVC defines this function for us.
38*9356374aSAndroid Build Coastguard Worker // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
__cpuid(int cpu_info[4],int info_type)39*9356374aSAndroid Build Coastguard Worker static void __cpuid(int cpu_info[4], int info_type) {
40*9356374aSAndroid Build Coastguard Worker   __asm__ volatile("cpuid \n\t"
41*9356374aSAndroid Build Coastguard Worker                    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
42*9356374aSAndroid Build Coastguard Worker                      "=d"(cpu_info[3])
43*9356374aSAndroid Build Coastguard Worker                    : "a"(info_type), "c"(0));
44*9356374aSAndroid Build Coastguard Worker }
45*9356374aSAndroid Build Coastguard Worker #endif  // !defined(_WIN32) && !defined(_WIN64)
46*9356374aSAndroid Build Coastguard Worker #endif  // defined(__x86_64__) || defined(_M_X64)
47*9356374aSAndroid Build Coastguard Worker 
48*9356374aSAndroid Build Coastguard Worker namespace absl {
49*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
50*9356374aSAndroid Build Coastguard Worker namespace crc_internal {
51*9356374aSAndroid Build Coastguard Worker 
52*9356374aSAndroid Build Coastguard Worker #if defined(__x86_64__) || defined(_M_X64)
53*9356374aSAndroid Build Coastguard Worker 
54*9356374aSAndroid Build Coastguard Worker namespace {
55*9356374aSAndroid Build Coastguard Worker 
56*9356374aSAndroid Build Coastguard Worker enum class Vendor {
57*9356374aSAndroid Build Coastguard Worker   kUnknown,
58*9356374aSAndroid Build Coastguard Worker   kIntel,
59*9356374aSAndroid Build Coastguard Worker   kAmd,
60*9356374aSAndroid Build Coastguard Worker };
61*9356374aSAndroid Build Coastguard Worker 
GetVendor()62*9356374aSAndroid Build Coastguard Worker Vendor GetVendor() {
63*9356374aSAndroid Build Coastguard Worker   // Get the vendor string (issue CPUID with eax = 0).
64*9356374aSAndroid Build Coastguard Worker   int cpu_info[4];
65*9356374aSAndroid Build Coastguard Worker   __cpuid(cpu_info, 0);
66*9356374aSAndroid Build Coastguard Worker 
67*9356374aSAndroid Build Coastguard Worker   std::string vendor;
68*9356374aSAndroid Build Coastguard Worker   vendor.append(reinterpret_cast<char*>(&cpu_info[1]), 4);
69*9356374aSAndroid Build Coastguard Worker   vendor.append(reinterpret_cast<char*>(&cpu_info[3]), 4);
70*9356374aSAndroid Build Coastguard Worker   vendor.append(reinterpret_cast<char*>(&cpu_info[2]), 4);
71*9356374aSAndroid Build Coastguard Worker   if (vendor == "GenuineIntel") {
72*9356374aSAndroid Build Coastguard Worker     return Vendor::kIntel;
73*9356374aSAndroid Build Coastguard Worker   } else if (vendor == "AuthenticAMD") {
74*9356374aSAndroid Build Coastguard Worker     return Vendor::kAmd;
75*9356374aSAndroid Build Coastguard Worker   } else {
76*9356374aSAndroid Build Coastguard Worker     return Vendor::kUnknown;
77*9356374aSAndroid Build Coastguard Worker   }
78*9356374aSAndroid Build Coastguard Worker }
79*9356374aSAndroid Build Coastguard Worker 
GetIntelCpuType()80*9356374aSAndroid Build Coastguard Worker CpuType GetIntelCpuType() {
81*9356374aSAndroid Build Coastguard Worker   // To get general information and extended features we send eax = 1 and
82*9356374aSAndroid Build Coastguard Worker   // ecx = 0 to cpuid.  The response is returned in eax, ebx, ecx and edx.
83*9356374aSAndroid Build Coastguard Worker   // (See Intel 64 and IA-32 Architectures Software Developer's Manual
84*9356374aSAndroid Build Coastguard Worker   // Volume 2A: Instruction Set Reference, A-M CPUID).
85*9356374aSAndroid Build Coastguard Worker   // https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
86*9356374aSAndroid Build Coastguard Worker   // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
87*9356374aSAndroid Build Coastguard Worker   int cpu_info[4];
88*9356374aSAndroid Build Coastguard Worker   __cpuid(cpu_info, 1);
89*9356374aSAndroid Build Coastguard Worker 
90*9356374aSAndroid Build Coastguard Worker   // Response in eax bits as follows:
91*9356374aSAndroid Build Coastguard Worker   // 0-3 (stepping id)
92*9356374aSAndroid Build Coastguard Worker   // 4-7 (model number),
93*9356374aSAndroid Build Coastguard Worker   // 8-11 (family code),
94*9356374aSAndroid Build Coastguard Worker   // 12-13 (processor type),
95*9356374aSAndroid Build Coastguard Worker   // 16-19 (extended model)
96*9356374aSAndroid Build Coastguard Worker   // 20-27 (extended family)
97*9356374aSAndroid Build Coastguard Worker 
98*9356374aSAndroid Build Coastguard Worker   int family = (cpu_info[0] >> 8) & 0x0f;
99*9356374aSAndroid Build Coastguard Worker   int model_num = (cpu_info[0] >> 4) & 0x0f;
100*9356374aSAndroid Build Coastguard Worker   int ext_family = (cpu_info[0] >> 20) & 0xff;
101*9356374aSAndroid Build Coastguard Worker   int ext_model_num = (cpu_info[0] >> 16) & 0x0f;
102*9356374aSAndroid Build Coastguard Worker 
103*9356374aSAndroid Build Coastguard Worker   int brand_id = cpu_info[1] & 0xff;
104*9356374aSAndroid Build Coastguard Worker 
105*9356374aSAndroid Build Coastguard Worker   // Process the extended family and model info if necessary
106*9356374aSAndroid Build Coastguard Worker   if (family == 0x0f) {
107*9356374aSAndroid Build Coastguard Worker     family += ext_family;
108*9356374aSAndroid Build Coastguard Worker   }
109*9356374aSAndroid Build Coastguard Worker 
110*9356374aSAndroid Build Coastguard Worker   if (family == 0x0f || family == 0x6) {
111*9356374aSAndroid Build Coastguard Worker     model_num += (ext_model_num << 4);
112*9356374aSAndroid Build Coastguard Worker   }
113*9356374aSAndroid Build Coastguard Worker 
114*9356374aSAndroid Build Coastguard Worker   switch (brand_id) {
115*9356374aSAndroid Build Coastguard Worker     case 0:  // no brand ID, so parse CPU family/model
116*9356374aSAndroid Build Coastguard Worker       switch (family) {
117*9356374aSAndroid Build Coastguard Worker         case 6:  // Most PentiumIII processors are in this category
118*9356374aSAndroid Build Coastguard Worker           switch (model_num) {
119*9356374aSAndroid Build Coastguard Worker             case 0x2c:  // Westmere: Gulftown
120*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelWestmere;
121*9356374aSAndroid Build Coastguard Worker             case 0x2d:  // Sandybridge
122*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelSandybridge;
123*9356374aSAndroid Build Coastguard Worker             case 0x3e:  // Ivybridge
124*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelIvybridge;
125*9356374aSAndroid Build Coastguard Worker             case 0x3c:  // Haswell (client)
126*9356374aSAndroid Build Coastguard Worker             case 0x3f:  // Haswell
127*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelHaswell;
128*9356374aSAndroid Build Coastguard Worker             case 0x4f:  // Broadwell
129*9356374aSAndroid Build Coastguard Worker             case 0x56:  // BroadwellDE
130*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelBroadwell;
131*9356374aSAndroid Build Coastguard Worker             case 0x55:                 // Skylake Xeon
132*9356374aSAndroid Build Coastguard Worker               if ((cpu_info[0] & 0x0f) < 5) {  // stepping < 5 is skylake
133*9356374aSAndroid Build Coastguard Worker                 return CpuType::kIntelSkylakeXeon;
134*9356374aSAndroid Build Coastguard Worker               } else {  // stepping >= 5 is cascadelake
135*9356374aSAndroid Build Coastguard Worker                 return CpuType::kIntelCascadelakeXeon;
136*9356374aSAndroid Build Coastguard Worker               }
137*9356374aSAndroid Build Coastguard Worker             case 0x5e:  // Skylake (client)
138*9356374aSAndroid Build Coastguard Worker               return CpuType::kIntelSkylake;
139*9356374aSAndroid Build Coastguard Worker             default:
140*9356374aSAndroid Build Coastguard Worker               return CpuType::kUnknown;
141*9356374aSAndroid Build Coastguard Worker           }
142*9356374aSAndroid Build Coastguard Worker         default:
143*9356374aSAndroid Build Coastguard Worker           return CpuType::kUnknown;
144*9356374aSAndroid Build Coastguard Worker       }
145*9356374aSAndroid Build Coastguard Worker     default:
146*9356374aSAndroid Build Coastguard Worker       return CpuType::kUnknown;
147*9356374aSAndroid Build Coastguard Worker   }
148*9356374aSAndroid Build Coastguard Worker }
149*9356374aSAndroid Build Coastguard Worker 
GetAmdCpuType()150*9356374aSAndroid Build Coastguard Worker CpuType GetAmdCpuType() {
151*9356374aSAndroid Build Coastguard Worker   // To get general information and extended features we send eax = 1 and
152*9356374aSAndroid Build Coastguard Worker   // ecx = 0 to cpuid.  The response is returned in eax, ebx, ecx and edx.
153*9356374aSAndroid Build Coastguard Worker   // (See Intel 64 and IA-32 Architectures Software Developer's Manual
154*9356374aSAndroid Build Coastguard Worker   // Volume 2A: Instruction Set Reference, A-M CPUID).
155*9356374aSAndroid Build Coastguard Worker   // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
156*9356374aSAndroid Build Coastguard Worker   int cpu_info[4];
157*9356374aSAndroid Build Coastguard Worker   __cpuid(cpu_info, 1);
158*9356374aSAndroid Build Coastguard Worker 
159*9356374aSAndroid Build Coastguard Worker   // Response in eax bits as follows:
160*9356374aSAndroid Build Coastguard Worker   // 0-3 (stepping id)
161*9356374aSAndroid Build Coastguard Worker   // 4-7 (model number),
162*9356374aSAndroid Build Coastguard Worker   // 8-11 (family code),
163*9356374aSAndroid Build Coastguard Worker   // 12-13 (processor type),
164*9356374aSAndroid Build Coastguard Worker   // 16-19 (extended model)
165*9356374aSAndroid Build Coastguard Worker   // 20-27 (extended family)
166*9356374aSAndroid Build Coastguard Worker 
167*9356374aSAndroid Build Coastguard Worker   int family = (cpu_info[0] >> 8) & 0x0f;
168*9356374aSAndroid Build Coastguard Worker   int model_num = (cpu_info[0] >> 4) & 0x0f;
169*9356374aSAndroid Build Coastguard Worker   int ext_family = (cpu_info[0] >> 20) & 0xff;
170*9356374aSAndroid Build Coastguard Worker   int ext_model_num = (cpu_info[0] >> 16) & 0x0f;
171*9356374aSAndroid Build Coastguard Worker 
172*9356374aSAndroid Build Coastguard Worker   if (family == 0x0f) {
173*9356374aSAndroid Build Coastguard Worker     family += ext_family;
174*9356374aSAndroid Build Coastguard Worker     model_num += (ext_model_num << 4);
175*9356374aSAndroid Build Coastguard Worker   }
176*9356374aSAndroid Build Coastguard Worker 
177*9356374aSAndroid Build Coastguard Worker   switch (family) {
178*9356374aSAndroid Build Coastguard Worker     case 0x17:
179*9356374aSAndroid Build Coastguard Worker       switch (model_num) {
180*9356374aSAndroid Build Coastguard Worker         case 0x0:  // Stepping Ax
181*9356374aSAndroid Build Coastguard Worker         case 0x1:  // Stepping Bx
182*9356374aSAndroid Build Coastguard Worker           return CpuType::kAmdNaples;
183*9356374aSAndroid Build Coastguard Worker         case 0x30:  // Stepping Ax
184*9356374aSAndroid Build Coastguard Worker         case 0x31:  // Stepping Bx
185*9356374aSAndroid Build Coastguard Worker           return CpuType::kAmdRome;
186*9356374aSAndroid Build Coastguard Worker         default:
187*9356374aSAndroid Build Coastguard Worker           return CpuType::kUnknown;
188*9356374aSAndroid Build Coastguard Worker       }
189*9356374aSAndroid Build Coastguard Worker       break;
190*9356374aSAndroid Build Coastguard Worker     case 0x19:
191*9356374aSAndroid Build Coastguard Worker       switch (model_num) {
192*9356374aSAndroid Build Coastguard Worker         case 0x0:  // Stepping Ax
193*9356374aSAndroid Build Coastguard Worker         case 0x1:  // Stepping B0
194*9356374aSAndroid Build Coastguard Worker           return CpuType::kAmdMilan;
195*9356374aSAndroid Build Coastguard Worker         case 0x10:  // Stepping A0
196*9356374aSAndroid Build Coastguard Worker         case 0x11:  // Stepping B0
197*9356374aSAndroid Build Coastguard Worker           return CpuType::kAmdGenoa;
198*9356374aSAndroid Build Coastguard Worker         case 0x44:  // Stepping A0
199*9356374aSAndroid Build Coastguard Worker           return CpuType::kAmdRyzenV3000;
200*9356374aSAndroid Build Coastguard Worker         default:
201*9356374aSAndroid Build Coastguard Worker           return CpuType::kUnknown;
202*9356374aSAndroid Build Coastguard Worker       }
203*9356374aSAndroid Build Coastguard Worker       break;
204*9356374aSAndroid Build Coastguard Worker     default:
205*9356374aSAndroid Build Coastguard Worker       return CpuType::kUnknown;
206*9356374aSAndroid Build Coastguard Worker   }
207*9356374aSAndroid Build Coastguard Worker }
208*9356374aSAndroid Build Coastguard Worker 
209*9356374aSAndroid Build Coastguard Worker }  // namespace
210*9356374aSAndroid Build Coastguard Worker 
GetCpuType()211*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() {
212*9356374aSAndroid Build Coastguard Worker   switch (GetVendor()) {
213*9356374aSAndroid Build Coastguard Worker     case Vendor::kIntel:
214*9356374aSAndroid Build Coastguard Worker       return GetIntelCpuType();
215*9356374aSAndroid Build Coastguard Worker     case Vendor::kAmd:
216*9356374aSAndroid Build Coastguard Worker       return GetAmdCpuType();
217*9356374aSAndroid Build Coastguard Worker     default:
218*9356374aSAndroid Build Coastguard Worker       return CpuType::kUnknown;
219*9356374aSAndroid Build Coastguard Worker   }
220*9356374aSAndroid Build Coastguard Worker }
221*9356374aSAndroid Build Coastguard Worker 
SupportsArmCRC32PMULL()222*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() { return false; }
223*9356374aSAndroid Build Coastguard Worker 
224*9356374aSAndroid Build Coastguard Worker #elif defined(__aarch64__) && defined(__linux__)
225*9356374aSAndroid Build Coastguard Worker 
226*9356374aSAndroid Build Coastguard Worker #ifndef HWCAP_CPUID
227*9356374aSAndroid Build Coastguard Worker #define HWCAP_CPUID (1 << 11)
228*9356374aSAndroid Build Coastguard Worker #endif
229*9356374aSAndroid Build Coastguard Worker 
230*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_AARCH64_ID_REG_READ(id, val) \
231*9356374aSAndroid Build Coastguard Worker   asm("mrs %0, " #id : "=r"(val))
232*9356374aSAndroid Build Coastguard Worker 
233*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() {
234*9356374aSAndroid Build Coastguard Worker   // MIDR_EL1 is not visible to EL0, however the access will be emulated by
235*9356374aSAndroid Build Coastguard Worker   // linux if AT_HWCAP has HWCAP_CPUID set.
236*9356374aSAndroid Build Coastguard Worker   //
237*9356374aSAndroid Build Coastguard Worker   // This method will be unreliable on heterogeneous computing systems (ex:
238*9356374aSAndroid Build Coastguard Worker   // big.LITTLE) since the value of MIDR_EL1 will change based on the calling
239*9356374aSAndroid Build Coastguard Worker   // thread.
240*9356374aSAndroid Build Coastguard Worker   uint64_t hwcaps = getauxval(AT_HWCAP);
241*9356374aSAndroid Build Coastguard Worker   if (hwcaps & HWCAP_CPUID) {
242*9356374aSAndroid Build Coastguard Worker     uint64_t midr = 0;
243*9356374aSAndroid Build Coastguard Worker     ABSL_INTERNAL_AARCH64_ID_REG_READ(MIDR_EL1, midr);
244*9356374aSAndroid Build Coastguard Worker     uint32_t implementer = (midr >> 24) & 0xff;
245*9356374aSAndroid Build Coastguard Worker     uint32_t part_number = (midr >> 4) & 0xfff;
246*9356374aSAndroid Build Coastguard Worker     switch (implementer) {
247*9356374aSAndroid Build Coastguard Worker       case 0x41:
248*9356374aSAndroid Build Coastguard Worker         switch (part_number) {
249*9356374aSAndroid Build Coastguard Worker           case 0xd0c: return CpuType::kArmNeoverseN1;
250*9356374aSAndroid Build Coastguard Worker           case 0xd40: return CpuType::kArmNeoverseV1;
251*9356374aSAndroid Build Coastguard Worker           case 0xd49: return CpuType::kArmNeoverseN2;
252*9356374aSAndroid Build Coastguard Worker           case 0xd4f: return CpuType::kArmNeoverseV2;
253*9356374aSAndroid Build Coastguard Worker           default:
254*9356374aSAndroid Build Coastguard Worker             return CpuType::kUnknown;
255*9356374aSAndroid Build Coastguard Worker         }
256*9356374aSAndroid Build Coastguard Worker         break;
257*9356374aSAndroid Build Coastguard Worker       case 0xc0:
258*9356374aSAndroid Build Coastguard Worker         switch (part_number) {
259*9356374aSAndroid Build Coastguard Worker           case 0xac3: return CpuType::kAmpereSiryn;
260*9356374aSAndroid Build Coastguard Worker           default:
261*9356374aSAndroid Build Coastguard Worker             return CpuType::kUnknown;
262*9356374aSAndroid Build Coastguard Worker         }
263*9356374aSAndroid Build Coastguard Worker         break;
264*9356374aSAndroid Build Coastguard Worker       default:
265*9356374aSAndroid Build Coastguard Worker         return CpuType::kUnknown;
266*9356374aSAndroid Build Coastguard Worker     }
267*9356374aSAndroid Build Coastguard Worker   }
268*9356374aSAndroid Build Coastguard Worker   return CpuType::kUnknown;
269*9356374aSAndroid Build Coastguard Worker }
270*9356374aSAndroid Build Coastguard Worker 
271*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() {
272*9356374aSAndroid Build Coastguard Worker   uint64_t hwcaps = getauxval(AT_HWCAP);
273*9356374aSAndroid Build Coastguard Worker   return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL);
274*9356374aSAndroid Build Coastguard Worker }
275*9356374aSAndroid Build Coastguard Worker 
276*9356374aSAndroid Build Coastguard Worker #else
277*9356374aSAndroid Build Coastguard Worker 
278*9356374aSAndroid Build Coastguard Worker CpuType GetCpuType() { return CpuType::kUnknown; }
279*9356374aSAndroid Build Coastguard Worker 
280*9356374aSAndroid Build Coastguard Worker bool SupportsArmCRC32PMULL() { return false; }
281*9356374aSAndroid Build Coastguard Worker 
282*9356374aSAndroid Build Coastguard Worker #endif
283*9356374aSAndroid Build Coastguard Worker 
284*9356374aSAndroid Build Coastguard Worker }  // namespace crc_internal
285*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
286*9356374aSAndroid Build Coastguard Worker }  // namespace absl
287