v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
cpu.cc
Go to the documentation of this file.
1// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/base/cpu.h"
6
7#if defined(V8_OS_STARBOARD)
8#include "starboard/cpu_features.h"
9#endif
10
11#if V8_LIBC_MSVCRT
12#include <intrin.h> // __cpuid()
13#endif
14#if V8_OS_LINUX
15#include <linux/auxvec.h> // AT_HWCAP
16#endif
17#if V8_GLIBC_PREREQ(2, 16) || V8_OS_ANDROID
18#include <sys/auxv.h> // getauxval()
19#endif
20#if V8_OS_QNX
21#include <sys/syspage.h> // cpuinfo
22#endif
23#if V8_OS_LINUX && V8_HOST_ARCH_PPC64
24#include <elf.h>
25#endif
26#if V8_OS_AIX
27#include <sys/systemcfg.h> // _system_configuration
28#ifndef POWER_8
29#define POWER_8 0x10000
30#endif
31#ifndef POWER_9
32#define POWER_9 0x20000
33#endif
34#ifndef POWER_10
35#define POWER_10 0x40000
36#endif
37#endif
38#if V8_OS_DARWIN
39#include <sys/sysctl.h> // sysctlbyname
40#endif
41#if V8_OS_POSIX
42#include <unistd.h> // sysconf()
43#endif
44
45#include <ctype.h>
46#include <limits.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50
51#include <algorithm>
52
53#include "src/base/logging.h"
55#if V8_OS_WIN
56#include <windows.h>
57#endif
58
59namespace v8 {
60namespace base {
61
62#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
63
64// Define __cpuid() for non-MSVC libraries.
65#if !V8_LIBC_MSVCRT
66
67static V8_INLINE void __cpuid(int cpu_info[4], int info_type) {
68// Clear ecx to align with __cpuid() of MSVC:
69// https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
70#if defined(__i386__) && defined(__pic__)
71 // Make sure to preserve ebx, which contains the pointer
72 // to the GOT in case we're generating PIC.
73 __asm__ volatile(
74 "mov %%ebx, %%edi\n\t"
75 "cpuid\n\t"
76 "xchg %%edi, %%ebx\n\t"
77 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
78 "=d"(cpu_info[3])
79 : "a"(info_type), "c"(0));
80#else
81 __asm__ volatile("cpuid \n\t"
82 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
83 "=d"(cpu_info[3])
84 : "a"(info_type), "c"(0));
85#endif // defined(__i386__) && defined(__pic__)
86}
87
88static V8_INLINE void __cpuidex(int cpu_info[4], int info_type,
89 int sub_info_type) {
90// Gather additional information about the processor.
91// Set the value of the ECX register to sub_info_type before it generates the
92// cpuid instruction, align with __cpuidex() of MSVC:
93// https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
94#if defined(__i386__) && defined(__pic__)
95 // Make sure to preserve ebx, which contains the pointer
96 // to the GOT in case we're generating PIC.
97 __asm__ volatile(
98 "mov %%ebx, %%edi\n\t"
99 "cpuid\n\t"
100 "xchg %%edi, %%ebx\n\t"
101 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
102 "=d"(cpu_info[3])
103 : "a"(info_type), "c"(sub_info_type));
104#else
105 __asm__ volatile("cpuid \n\t"
106 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
107 "=d"(cpu_info[3])
108 : "a"(info_type), "c"(sub_info_type));
109#endif // defined(__i386__) && defined(__pic__)
110}
111
112#endif // !V8_LIBC_MSVCRT
113
114#elif V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 || V8_HOST_ARCH_MIPS64 || \
115 V8_HOST_ARCH_RISCV64
116
117#if V8_OS_LINUX
118
119#if V8_HOST_ARCH_ARM
120
121// See <uapi/asm/hwcap.h> kernel header.
122/*
123 * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
124 */
125#define HWCAP_SWP (1 << 0)
126#define HWCAP_HALF (1 << 1)
127#define HWCAP_THUMB (1 << 2)
128#define HWCAP_26BIT (1 << 3) /* Play it safe */
129#define HWCAP_FAST_MULT (1 << 4)
130#define HWCAP_FPA (1 << 5)
131#define HWCAP_VFP (1 << 6)
132#define HWCAP_EDSP (1 << 7)
133#define HWCAP_JAVA (1 << 8)
134#define HWCAP_IWMMXT (1 << 9)
135#define HWCAP_CRUNCH (1 << 10)
136#define HWCAP_THUMBEE (1 << 11)
137#define HWCAP_NEON (1 << 12)
138#define HWCAP_VFPv3 (1 << 13)
139#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
140#define HWCAP_TLS (1 << 15)
141#define HWCAP_VFPv4 (1 << 16)
142#define HWCAP_IDIVA (1 << 17)
143#define HWCAP_IDIVT (1 << 18)
144#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
145#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
146#define HWCAP_LPAE (1 << 20)
147
148#endif // V8_HOST_ARCH_ARM
149
150#if V8_HOST_ARCH_ARM64
151
152// See <uapi/asm/hwcap.h> kernel header.
153/*
154 * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
155 */
156#define HWCAP_FP (1 << 0)
157#define HWCAP_ASIMD (1 << 1)
158#define HWCAP_EVTSTRM (1 << 2)
159#define HWCAP_AES (1 << 3)
160#define HWCAP_PMULL (1 << 4)
161#define HWCAP_SHA1 (1 << 5)
162#define HWCAP_SHA2 (1 << 6)
163#define HWCAP_CRC32 (1 << 7)
164#define HWCAP_ATOMICS (1 << 8)
165#define HWCAP_FPHP (1 << 9)
166#define HWCAP_ASIMDHP (1 << 10)
167#define HWCAP_CPUID (1 << 11)
168#define HWCAP_ASIMDRDM (1 << 12)
169#define HWCAP_JSCVT (1 << 13)
170#define HWCAP_FCMA (1 << 14)
171#define HWCAP_LRCPC (1 << 15)
172#define HWCAP_DCPOP (1 << 16)
173#define HWCAP_SHA3 (1 << 17)
174#define HWCAP_SM3 (1 << 18)
175#define HWCAP_SM4 (1 << 19)
176#define HWCAP_ASIMDDP (1 << 20)
177#define HWCAP_SHA512 (1 << 21)
178#define HWCAP_SVE (1 << 22)
179#define HWCAP_ASIMDFHM (1 << 23)
180#define HWCAP_DIT (1 << 24)
181#define HWCAP_USCAT (1 << 25)
182#define HWCAP_ILRCPC (1 << 26)
183#define HWCAP_FLAGM (1 << 27)
184#define HWCAP_SSBS (1 << 28)
185#define HWCAP_SB (1 << 29)
186#define HWCAP_PACA (1 << 30)
187#define HWCAP_PACG (1UL << 31)
188// See <uapi/asm/hwcap.h> kernel header.
189/*
190 * HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2
191 */
192#define HWCAP2_MTE (1 << 18)
193#endif // V8_HOST_ARCH_ARM64
194
195#if V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64
196
197static std::tuple<uint32_t, uint32_t> ReadELFHWCaps() {
198 uint32_t hwcap = 0;
199 uint32_t hwcap2 = 0;
200#if (V8_GLIBC_PREREQ(2, 16) || V8_OS_ANDROID) && defined(AT_HWCAP)
201 hwcap = static_cast<uint32_t>(getauxval(AT_HWCAP));
202#if defined(AT_HWCAP2)
203 hwcap2 = static_cast<uint32_t>(getauxval(AT_HWCAP2));
204#endif // AT_HWCAP2
205#else
206 // Read the ELF HWCAP flags by parsing /proc/self/auxv.
207 // If getauxval is not available, the kernel/libc is also not new enough to
208 // expose hwcap2.
209 FILE* fp = base::Fopen("/proc/self/auxv", "r");
210 if (fp != nullptr) {
211 struct {
212 uint32_t tag;
213 uint32_t value;
214 } entry;
215 for (;;) {
216 size_t n = fread(&entry, sizeof(entry), 1, fp);
217 if (n == 0 || (entry.tag == 0 && entry.value == 0)) {
218 break;
219 }
220 if (entry.tag == AT_HWCAP) {
221 hwcap = entry.value;
222 break;
223 }
224 }
225 base::Fclose(fp);
226 }
227#endif
228 return std::make_tuple(hwcap, hwcap2);
229}
230
231#endif // V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64
232
233// Extract the information exposed by the kernel via /proc/cpuinfo.
234class CPUInfo final {
235 public:
236 CPUInfo() : datalen_(0) {
237 // Get the size of the cpuinfo file by reading it until the end. This is
238 // required because files under /proc do not always return a valid size
239 // when using fseek(0, SEEK_END) + ftell(). Nor can the be mmap()-ed.
240 static const char PATHNAME[] = "/proc/cpuinfo";
241 FILE* fp = base::Fopen(PATHNAME, "r");
242 if (fp != nullptr) {
243 for (;;) {
244 char buffer[256];
245 size_t n = fread(buffer, 1, sizeof(buffer), fp);
246 if (n == 0) {
247 break;
248 }
249 datalen_ += n;
250 }
251 base::Fclose(fp);
252 }
253
254 // Read the contents of the cpuinfo file.
255 data_ = new char[datalen_ + 1];
256 fp = base::Fopen(PATHNAME, "r");
257 if (fp != nullptr) {
258 for (size_t offset = 0; offset < datalen_; ) {
259 size_t n = fread(data_ + offset, 1, datalen_ - offset, fp);
260 if (n == 0) {
261 break;
262 }
263 offset += n;
264 }
265 base::Fclose(fp);
266 }
267
268 // Zero-terminate the data.
269 data_[datalen_] = '\0';
270 }
271
272 ~CPUInfo() {
273 delete[] data_;
274 }
275
276 // Extract the content of a the first occurrence of a given field in
277 // the content of the cpuinfo file and return it as a heap-allocated
278 // string that must be freed by the caller using delete[].
279 // Return nullptr if not found.
280 char* ExtractField(const char* field) const {
281 DCHECK_NOT_NULL(field);
282
283 // Look for first field occurrence, and ensure it starts the line.
284 size_t fieldlen = strlen(field);
285 char* p = data_;
286 for (;;) {
287 p = strstr(p, field);
288 if (p == nullptr) {
289 return nullptr;
290 }
291 if (p == data_ || p[-1] == '\n') {
292 break;
293 }
294 p += fieldlen;
295 }
296
297 // Skip to the first colon followed by a space.
298 p = strchr(p + fieldlen, ':');
299 if (p == nullptr || !isspace(p[1])) {
300 return nullptr;
301 }
302 p += 2;
303
304 // Find the end of the line.
305 char* q = strchr(p, '\n');
306 if (q == nullptr) {
307 q = data_ + datalen_;
308 }
309
310 // Copy the line into a heap-allocated buffer.
311 size_t len = q - p;
312 char* result = new char[len + 1];
313 if (result != nullptr) {
314 memcpy(result, p, len);
315 result[len] = '\0';
316 }
317 return result;
318 }
319
320 private:
321 char* data_;
322 size_t datalen_;
323};
324
325// Checks that a space-separated list of items contains one given 'item'.
326static bool HasListItem(const char* list, const char* item) {
327 ssize_t item_len = strlen(item);
328 const char* p = list;
329 if (p != nullptr) {
330 while (*p != '\0') {
331 // Skip whitespace.
332 while (isspace(*p)) ++p;
333
334 // Find end of current list item.
335 const char* q = p;
336 while (*q != '\0' && !isspace(*q)) ++q;
337
338 if (item_len == q - p && memcmp(p, item, item_len) == 0) {
339 return true;
340 }
341
342 // Skip to next item.
343 p = q;
344 }
345 }
346 return false;
347}
348
349#endif // V8_OS_LINUX
350
351#endif // V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 ||
352 // V8_HOST_ARCH_MIPS64 || V8_HOST_ARCH_RISCV64
353
354#if defined(V8_OS_STARBOARD)
355
356bool CPU::StarboardDetectCPU() {
357 SbCPUFeatures features;
358 if (!SbCPUFeaturesGet(&features)) {
359 return false;
360 }
361 architecture_ = features.arm.architecture_generation;
362 switch (features.architecture) {
363 case kSbCPUFeaturesArchitectureArm:
364 case kSbCPUFeaturesArchitectureArm64:
365 has_neon_ = features.arm.has_neon;
366 has_thumb2_ = features.arm.has_thumb2;
367 has_vfp_ = features.arm.has_vfp;
368 has_vfp3_ = features.arm.has_vfp3;
369 has_vfp3_d32_ = features.arm.has_vfp3_d32;
370 has_idiva_ = features.arm.has_idiva;
371 break;
372 case kSbCPUFeaturesArchitectureX86:
373 case kSbCPUFeaturesArchitectureX86_64:
374 // Following flags are mandatory for V8
375 has_cmov_ = features.x86.has_cmov;
376 has_sse2_ = features.x86.has_sse2;
377 // These flags are optional
378 has_sse3_ = features.x86.has_sse3;
379 has_ssse3_ = features.x86.has_ssse3;
380 has_sse41_ = features.x86.has_sse41;
381 has_sahf_ = features.x86.has_sahf;
382 has_avx_ = features.x86.has_avx;
383 has_avx2_ = features.x86.has_avx2;
384 // TODO: Support AVX-VNNI on Starboard
385 has_fma3_ = features.x86.has_fma3;
386 has_bmi1_ = features.x86.has_bmi1;
387 has_bmi2_ = features.x86.has_bmi2;
388 has_lzcnt_ = features.x86.has_lzcnt;
389 has_popcnt_ = features.x86.has_popcnt;
390 has_f16c_ = features.x86.has_f16c;
391 break;
392 default:
393 return false;
394 }
395
396 return true;
397}
398
399#endif
400
402 : stepping_(0),
403 model_(0),
404 ext_model_(0),
405 family_(0),
406 ext_family_(0),
407 type_(0),
408 implementer_(0),
409 architecture_(0),
410 variant_(-1),
411 part_(0),
412 icache_line_size_(kUnknownCacheLineSize),
413 dcache_line_size_(kUnknownCacheLineSize),
414 num_virtual_address_bits_(kUnknownNumVirtualAddressBits),
415 has_fpu_(false),
416 has_cmov_(false),
417 has_sahf_(false),
418 has_mmx_(false),
419 has_sse_(false),
420 has_sse2_(false),
421 has_sse3_(false),
422 has_ssse3_(false),
423 has_sse41_(false),
424 has_sse42_(false),
425 is_atom_(false),
426 has_intel_jcc_erratum_(false),
427 has_osxsave_(false),
428 has_avx_(false),
429 has_avx2_(false),
430 has_avx_vnni_(false),
431 has_avx_vnni_int8_(false),
432 has_fma3_(false),
433 has_f16c_(false),
434 has_bmi1_(false),
435 has_bmi2_(false),
436 has_lzcnt_(false),
437 has_popcnt_(false),
438 has_idiva_(false),
439 has_neon_(false),
440 has_thumb2_(false),
441 has_vfp_(false),
442 has_vfp3_(false),
443 has_vfp3_d32_(false),
444 has_jscvt_(false),
445 has_dot_prod_(false),
446 has_lse_(false),
447 has_mte_(false),
448 has_sha3_(false),
449 has_pmull1q_(false),
450 has_fp16_(false),
451 is_fp64_mode_(false),
452 has_non_stop_time_stamp_counter_(false),
453 is_running_in_vm_(false),
454 has_msa_(false),
455 riscv_mmu_(RV_MMU_MODE::kRiscvSV48),
456 has_rvv_(false),
457 has_zba_(false),
458 has_zbb_(false),
459 has_zbs_(false) {
460 memcpy(vendor_, "Unknown", 8);
461
462#if defined(V8_OS_STARBOARD)
463 if (StarboardDetectCPU()) {
464 return;
465 }
466#endif
467
468#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
469 int cpu_info[4];
470
471 // __cpuid with an InfoType argument of 0 returns the number of
472 // valid Ids in CPUInfo[0] and the CPU identification string in
473 // the other three array elements. The CPU identification string is
474 // not in linear order. The code below arranges the information
475 // in a human readable form. The human readable order is CPUInfo[1] |
476 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
477 // before using memcpy to copy these three array elements to cpu_string.
478 __cpuid(cpu_info, 0);
479 unsigned num_ids = cpu_info[0];
480 std::swap(cpu_info[2], cpu_info[3]);
481 memcpy(vendor_, cpu_info + 1, 12);
482 vendor_[12] = '\0';
483
484 // Interpret CPU feature information.
485 if (num_ids > 0) {
486 __cpuid(cpu_info, 1);
487
488 int cpu_info70[4] = {0};
489 int cpu_info71[4] = {0};
490 if (num_ids >= 7) {
491 __cpuid(cpu_info70, 7);
492 // Check the maximum input value for supported leaf 7 sub-leaves
493 if (cpu_info70[0] >= 1) {
494 __cpuidex(cpu_info71, 7, 1);
495 }
496 }
497
498 stepping_ = cpu_info[0] & 0xF;
499 model_ = ((cpu_info[0] >> 4) & 0xF) + ((cpu_info[0] >> 12) & 0xF0);
500 family_ = (cpu_info[0] >> 8) & 0xF;
501 type_ = (cpu_info[0] >> 12) & 0x3;
502 ext_model_ = (cpu_info[0] >> 16) & 0xF;
503 ext_family_ = (cpu_info[0] >> 20) & 0xFF;
504 has_fpu_ = (cpu_info[3] & 0x00000001) != 0;
505 has_cmov_ = (cpu_info[3] & 0x00008000) != 0;
506 has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
507 has_sse_ = (cpu_info[3] & 0x02000000) != 0;
508 has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
509 has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
510 has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
511 has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
512 has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
513 has_popcnt_ = (cpu_info[2] & 0x00800000) != 0;
514 has_osxsave_ = (cpu_info[2] & 0x08000000) != 0;
515 has_avx_ = (cpu_info[2] & 0x10000000) != 0;
516 has_avx2_ = (cpu_info70[1] & 0x00000020) != 0;
517 has_avx_vnni_ = (cpu_info71[0] & 0x00000010) != 0;
518 has_avx_vnni_int8_ = (cpu_info71[3] & 0x00000020) != 0;
519 has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
520 has_f16c_ = (cpu_info[2] & 0x20000000) != 0;
521 // CET shadow stack feature flag. See
522 // https://en.wikipedia.org/wiki/CPUID#EAX=7,_ECX=0:_Extended_Features
523 has_cetss_ = (cpu_info70[2] & 0x00000080) != 0;
524 // "Hypervisor Present Bit: Bit 31 of ECX of CPUID leaf 0x1."
525 // See https://lwn.net/Articles/301888/
526 // This is checking for any hypervisor. Hypervisors may choose not to
527 // announce themselves. Hypervisors trap CPUID and sometimes return
528 // different results to underlying hardware.
529 is_running_in_vm_ = (cpu_info[2] & 0x80000000) != 0;
530
531 if (family_ == 0x6) {
532 switch (model_) {
533 case 0x1C: // SLT
534 case 0x26:
535 case 0x36:
536 case 0x27:
537 case 0x35:
538 case 0x37: // SLM
539 case 0x4A:
540 case 0x4D:
541 case 0x4C: // AMT
542 case 0x6E:
543 is_atom_ = true;
544 }
545
546 // CPUs that are affected by Intel JCC erratum:
547 // https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf
548 switch (model_) {
549 case 0x4E:
551 break;
552 case 0x55:
553 has_intel_jcc_erratum_ = stepping_ == 0x4 || stepping_ == 0x7;
554 break;
555 case 0x5E:
557 break;
558 case 0x8E:
559 has_intel_jcc_erratum_ = stepping_ == 0x9 || stepping_ == 0xA ||
560 stepping_ == 0xB || stepping_ == 0xC;
561 break;
562 case 0x9E:
563 has_intel_jcc_erratum_ = stepping_ == 0x9 || stepping_ == 0xA ||
564 stepping_ == 0xB || stepping_ == 0xD;
565 break;
566 case 0xA6:
568 break;
569 case 0xAE:
571 break;
572 }
573 }
574 }
575
576 // There are separate feature flags for VEX-encoded GPR instructions.
577 if (num_ids >= 7) {
578 __cpuid(cpu_info, 7);
579 has_bmi1_ = (cpu_info[1] & 0x00000008) != 0;
580 has_bmi2_ = (cpu_info[1] & 0x00000100) != 0;
581 }
582
583 // Query extended IDs.
584 __cpuid(cpu_info, 0x80000000);
585 unsigned num_ext_ids = cpu_info[0];
586
587 // Interpret extended CPU feature information.
588 if (num_ext_ids > 0x80000000) {
589 __cpuid(cpu_info, 0x80000001);
590 has_lzcnt_ = (cpu_info[2] & 0x00000020) != 0;
591 // SAHF must be probed in long mode.
592 has_sahf_ = (cpu_info[2] & 0x00000001) != 0;
593 }
594
595 // Check if CPU has non stoppable time stamp counter.
596 const unsigned parameter_containing_non_stop_time_stamp_counter = 0x80000007;
597 if (num_ext_ids >= parameter_containing_non_stop_time_stamp_counter) {
598 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
599 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
600 }
601
602 const unsigned virtual_physical_address_bits = 0x80000008;
603 if (num_ext_ids >= virtual_physical_address_bits) {
604 __cpuid(cpu_info, virtual_physical_address_bits);
605 num_virtual_address_bits_ = (cpu_info[0] >> 8) & 0xff;
606 }
607
608 // This logic is replicated from cpu.cc present in chromium.src
610 int cpu_info_hv[4] = {};
611 __cpuid(cpu_info_hv, 0x40000000);
612 if (cpu_info_hv[1] == 0x7263694D && // Micr
613 cpu_info_hv[2] == 0x666F736F && // osof
614 cpu_info_hv[3] == 0x76482074) { // t Hv
615 // If CPUID says we have a variant TSC and a hypervisor has identified
616 // itself and the hypervisor says it is Microsoft Hyper-V, then treat
617 // TSC as invariant.
618 //
619 // Microsoft Hyper-V hypervisor reports variant TSC as there are some
620 // scenarios (eg. VM live migration) where the TSC is variant, but for
621 // our purposes we can treat it as invariant.
623 }
624 }
625#elif V8_HOST_ARCH_ARM
626
627#if V8_OS_LINUX
628
629 CPUInfo cpu_info;
630
631 // Extract implementor from the "CPU implementer" field.
632 char* implementer = cpu_info.ExtractField("CPU implementer");
633 if (implementer != nullptr) {
634 char* end;
635 implementer_ = strtol(implementer, &end, 0);
636 if (end == implementer) {
637 implementer_ = 0;
638 }
639 delete[] implementer;
640 }
641
642 char* variant = cpu_info.ExtractField("CPU variant");
643 if (variant != nullptr) {
644 char* end;
645 variant_ = strtol(variant, &end, 0);
646 if (end == variant) {
647 variant_ = -1;
648 }
649 delete[] variant;
650 }
651
652 // Extract part number from the "CPU part" field.
653 char* part = cpu_info.ExtractField("CPU part");
654 if (part != nullptr) {
655 char* end;
656 part_ = strtol(part, &end, 0);
657 if (end == part) {
658 part_ = 0;
659 }
660 delete[] part;
661 }
662
663 // Extract architecture from the "CPU Architecture" field.
664 // The list is well-known, unlike the the output of
665 // the 'Processor' field which can vary greatly.
666 // See the definition of the 'proc_arch' array in
667 // $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
668 // same file.
669 char* architecture = cpu_info.ExtractField("CPU architecture");
670 if (architecture != nullptr) {
671 char* end;
672 architecture_ = strtol(architecture, &end, 10);
673 if (end == architecture) {
674 // Kernels older than 3.18 report "CPU architecture: AArch64" on ARMv8.
675 if (strcmp(architecture, "AArch64") == 0) {
676 architecture_ = 8;
677 } else {
678 architecture_ = 0;
679 }
680 }
681 delete[] architecture;
682
683 // Unfortunately, it seems that certain ARMv6-based CPUs
684 // report an incorrect architecture number of 7!
685 //
686 // See http://code.google.com/p/android/issues/detail?id=10812
687 //
688 // We try to correct this by looking at the 'elf_platform'
689 // field reported by the 'Processor' field, which is of the
690 // form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
691 // an ARMv6-one. For example, the Raspberry Pi is one popular
692 // ARMv6 device that reports architecture 7.
693 if (architecture_ == 7) {
694 char* processor = cpu_info.ExtractField("Processor");
695 if (HasListItem(processor, "(v6l)")) {
696 architecture_ = 6;
697 }
698 delete[] processor;
699 }
700
701 // elf_platform moved to the model name field in Linux v3.8.
702 if (architecture_ == 7) {
703 char* processor = cpu_info.ExtractField("model name");
704 if (HasListItem(processor, "(v6l)")) {
705 architecture_ = 6;
706 }
707 delete[] processor;
708 }
709 }
710
711 // Try to extract the list of CPU features from ELF hwcaps.
712 uint32_t hwcaps, hwcaps2;
713 std::tie(hwcaps, hwcaps2) = ReadELFHWCaps();
714 if (hwcaps != 0) {
715 has_idiva_ = (hwcaps & HWCAP_IDIVA) != 0;
716 has_neon_ = (hwcaps & HWCAP_NEON) != 0;
717 has_vfp_ = (hwcaps & HWCAP_VFP) != 0;
718 has_vfp3_ = (hwcaps & (HWCAP_VFPv3 | HWCAP_VFPv3D16 | HWCAP_VFPv4)) != 0;
719 has_vfp3_d32_ = (has_vfp3_ && ((hwcaps & HWCAP_VFPv3D16) == 0 ||
720 (hwcaps & HWCAP_VFPD32) != 0));
721 } else {
722 // Try to fallback to "Features" CPUInfo field.
723 char* features = cpu_info.ExtractField("Features");
724 has_idiva_ = HasListItem(features, "idiva");
725 has_neon_ = HasListItem(features, "neon");
726 has_thumb2_ = HasListItem(features, "thumb2");
727 has_vfp_ = HasListItem(features, "vfp");
728 if (HasListItem(features, "vfpv3d16")) {
729 has_vfp3_ = true;
730 } else if (HasListItem(features, "vfpv3")) {
731 has_vfp3_ = true;
732 has_vfp3_d32_ = true;
733 }
734 delete[] features;
735 }
736
737 // Some old kernels will report vfp not vfpv3. Here we make an attempt
738 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
739 // available on architectures with vfpv3. Checking neon on its own is
740 // not enough as it is possible to have neon without vfp.
741 if (has_vfp_ && has_neon_) {
742 has_vfp3_ = true;
743 }
744
745 // VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6.
746 if (architecture_ < 7 && has_vfp3_) {
747 architecture_ = 7;
748 }
749
750 // ARMv7 implies Thumb2.
751 if (architecture_ >= 7) {
752 has_thumb2_ = true;
753 }
754
755 // The earliest architecture with Thumb2 is ARMv6T2.
756 if (has_thumb2_ && architecture_ < 6) {
757 architecture_ = 6;
758 }
759
760 // We don't support any FPUs other than VFP.
762
763#elif V8_OS_QNX
764
765 uint32_t cpu_flags = SYSPAGE_ENTRY(cpuinfo)->flags;
766 if (cpu_flags & ARM_CPU_FLAG_V7) {
767 architecture_ = 7;
768 has_thumb2_ = true;
769 } else if (cpu_flags & ARM_CPU_FLAG_V6) {
770 architecture_ = 6;
771 // QNX doesn't say if Thumb2 is available.
772 // Assume false for the architectures older than ARMv7.
773 }
775 has_fpu_ = (cpu_flags & CPU_FLAG_FPU) != 0;
777 if (cpu_flags & ARM_CPU_FLAG_NEON) {
778 has_neon_ = true;
780#ifdef ARM_CPU_FLAG_VFP_D32
781 has_vfp3_d32_ = (cpu_flags & ARM_CPU_FLAG_VFP_D32) != 0;
782#endif
783 }
784 has_idiva_ = (cpu_flags & ARM_CPU_FLAG_IDIV) != 0;
785
786#endif // V8_OS_LINUX
787
788#elif V8_HOST_ARCH_MIPS64
789
790 // Simple detection of FPU at runtime for Linux.
791 // It is based on /proc/cpuinfo, which reveals hardware configuration
792 // to user-space applications. According to MIPS (early 2010), no similar
793 // facility is universally available on the MIPS architectures,
794 // so it's up to individual OSes to provide such.
795 CPUInfo cpu_info;
796 char* cpu_model = cpu_info.ExtractField("cpu model");
797 has_fpu_ = HasListItem(cpu_model, "FPU");
798 char* ASEs = cpu_info.ExtractField("ASEs implemented");
799 has_msa_ = HasListItem(ASEs, "msa");
800 delete[] cpu_model;
801 delete[] ASEs;
802
803#elif V8_HOST_ARCH_ARM64
804#ifdef V8_OS_WIN
805 // Windows makes high-resolution thread timing information available in
806 // user-space.
808
809 // Defined in winnt.h, but only in 10.0.20348.0 version of the Windows SDK.
810 // Copy the value here to support older versions as well.
811#if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
812 constexpr int PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44;
813#endif
814#if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
815 constexpr int PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43;
816#endif
817#if !defined(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
818 constexpr int PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34;
819#endif
820#if !defined(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)
821 constexpr int PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30;
822#endif
823
824 has_jscvt_ =
825 IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE);
827 IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
828 has_lse_ =
829 IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);
831 IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
832
833#elif V8_OS_LINUX
834 // Try to extract the list of CPU features from ELF hwcaps.
835 uint32_t hwcaps, hwcaps2;
836 std::tie(hwcaps, hwcaps2) = ReadELFHWCaps();
837 has_mte_ = (hwcaps2 & HWCAP2_MTE) != 0;
838 if (hwcaps != 0) {
839 has_jscvt_ = (hwcaps & HWCAP_JSCVT) != 0;
840 has_dot_prod_ = (hwcaps & HWCAP_ASIMDDP) != 0;
841 has_lse_ = (hwcaps & HWCAP_ATOMICS) != 0;
842 has_pmull1q_ = (hwcaps & HWCAP_PMULL) != 0;
843 has_fp16_ = (hwcaps & HWCAP_FPHP) != 0;
844 has_sha3_ = (hwcaps & HWCAP_SHA3) != 0;
845 } else {
846 // Try to fallback to "Features" CPUInfo field
847 CPUInfo cpu_info;
848 char* features = cpu_info.ExtractField("Features");
849 has_jscvt_ = HasListItem(features, "jscvt");
850 has_dot_prod_ = HasListItem(features, "asimddp");
851 has_lse_ = HasListItem(features, "atomics");
852 has_pmull1q_ = HasListItem(features, "pmull");
853 has_fp16_ = HasListItem(features, "half");
854 has_sha3_ = HasListItem(features, "sha3");
855 delete[] features;
856 }
857#elif V8_OS_DARWIN
858#if V8_OS_IOS
859 int64_t feat_jscvt = 0;
860 size_t feat_jscvt_size = sizeof(feat_jscvt);
861 if (sysctlbyname("hw.optional.arm.FEAT_JSCVT", &feat_jscvt, &feat_jscvt_size,
862 nullptr, 0) == -1) {
863 has_jscvt_ = false;
864 } else {
865 has_jscvt_ = feat_jscvt;
866 }
867 int64_t feat_dot_prod = 0;
868 size_t feat_dot_prod_size = sizeof(feat_dot_prod);
869 if (sysctlbyname("hw.optional.arm.FEAT_DotProd", &feat_dot_prod,
870 &feat_dot_prod_size, nullptr, 0) == -1) {
871 has_dot_prod_ = false;
872 } else {
873 has_dot_prod_ = feat_dot_prod;
874 }
875 int64_t feat_lse = 0;
876 size_t feat_lse_size = sizeof(feat_lse);
877 if (sysctlbyname("hw.optional.arm.FEAT_LSE", &feat_lse, &feat_lse_size,
878 nullptr, 0) == -1) {
879 has_lse_ = false;
880 } else {
881 has_lse_ = feat_lse;
882 }
883 int64_t feat_pmull = 0;
884 size_t feat_pmull_size = sizeof(feat_pmull);
885 if (sysctlbyname("hw.optional.arm.FEAT_PMULL", &feat_pmull, &feat_pmull_size,
886 nullptr, 0) == -1) {
887 has_pmull1q_ = false;
888 } else {
889 has_pmull1q_ = feat_pmull;
890 }
891 int64_t fp16 = 0;
892 size_t fp16_size = sizeof(fp16);
893 if (sysctlbyname("hw.optional.arm.FEAT_FP16", &fp16, &fp16_size, nullptr,
894 0) == -1) {
895 has_fp16_ = false;
896 } else {
897 has_fp16_ = fp16;
898 }
899 int64_t feat_sha3 = 0;
900 size_t feat_sha3_size = sizeof(feat_sha3);
901 if (sysctlbyname("hw.optional.arm.FEAT_SHA3", &feat_sha3, &feat_sha3_size,
902 nullptr, 0) == -1) {
903 has_sha3_ = false;
904 } else {
905 has_sha3_ = feat_sha3;
906 }
907#else
908 // ARM64 Macs always have JSCVT, ASIMDDP, FP16 and LSE.
909 has_jscvt_ = true;
910 has_dot_prod_ = true;
911 has_lse_ = true;
912 has_pmull1q_ = true;
913 has_fp16_ = true;
914 has_sha3_ = true;
915#endif // V8_OS_IOS
916#endif // V8_OS_WIN
917
918#elif V8_HOST_ARCH_PPC64
919
920#ifndef USE_SIMULATOR
921#if V8_OS_LINUX
922 // Read processor info from /proc/self/auxv.
923 char* auxv_cpu_type = nullptr;
924 FILE* fp = base::Fopen("/proc/self/auxv", "r");
925 if (fp != nullptr) {
926 Elf64_auxv_t entry;
927 for (;;) {
928 size_t n = fread(&entry, sizeof(entry), 1, fp);
929 if (n == 0 || entry.a_type == AT_NULL) {
930 break;
931 }
932 switch (entry.a_type) {
933 case AT_PLATFORM:
934 auxv_cpu_type = reinterpret_cast<char*>(entry.a_un.a_val);
935 break;
936 case AT_ICACHEBSIZE:
937 icache_line_size_ = entry.a_un.a_val;
938 break;
939 case AT_DCACHEBSIZE:
940 dcache_line_size_ = entry.a_un.a_val;
941 break;
942 }
943 }
944 base::Fclose(fp);
945 }
946
947 part_ = -1;
948 if (auxv_cpu_type) {
949 if (strcmp(auxv_cpu_type, "power10") == 0) {
951 } else if (strcmp(auxv_cpu_type, "power9") == 0) {
953 } else if (strcmp(auxv_cpu_type, "power8") == 0) {
955 }
956 }
957
958#elif V8_OS_AIX
959 switch (_system_configuration.implementation) {
960 case POWER_10:
962 break;
963 case POWER_9:
965 break;
966 case POWER_8:
968 break;
969 }
970#endif // V8_OS_AIX
971#endif // !USE_SIMULATOR
972
973#elif V8_HOST_ARCH_RISCV64
974#if V8_OS_LINUX
975 CPUInfo cpu_info;
976#if (V8_GLIBC_PREREQ(2, 39))
977#include <asm/hwprobe.h>
978#include <asm/unistd.h>
979 riscv_hwprobe pairs[] = {{RISCV_HWPROBE_KEY_IMA_EXT_0, 0}};
980 if (!syscall(__NR_riscv_hwprobe, &pairs,
981 sizeof(pairs) / sizeof(riscv_hwprobe), 0, nullptr, 0)) {
982 if (pairs[0].value & RISCV_HWPROBE_IMA_V) {
983 has_rvv_ = true;
984 }
985 if (pairs[0].value & RISCV_HWPROBE_IMA_FD) {
986 has_fpu_ = true;
987 }
988 if (pairs[0].value & RISCV_HWPROBE_EXT_ZBA) {
989 has_zba_ = true;
990 }
991 if (pairs[0].value & RISCV_HWPROBE_EXT_ZBB) {
992 has_zbb_ = true;
993 }
994 if (pairs[0].value & RISCV_HWPROBE_EXT_ZBS) {
995 has_zbs_ = true;
996 }
997 }
998#else
999 char* features = cpu_info.ExtractField("isa");
1000
1001 if (HasListItem(features, "rv64imafdc")) {
1002 has_fpu_ = true;
1003 }
1004 if (HasListItem(features, "rv64imafdcv")) {
1005 has_fpu_ = true;
1006 has_rvv_ = true;
1007 }
1008#endif
1009
1010 char* mmu = cpu_info.ExtractField("mmu");
1011 if (HasListItem(mmu, "sv48")) {
1013 }
1014 if (HasListItem(mmu, "sv39")) {
1016 }
1017 if (HasListItem(mmu, "sv57")) {
1019 }
1020#endif
1021#endif // V8_HOST_ARCH_RISCV64
1022}
1023
1024} // namespace base
1025} // namespace v8
uint8_t data_[MAX_STACK_LENGTH]
bool has_sse2_
Definition cpu.h:166
bool has_jscvt_
Definition cpu.h:191
bool has_avx_vnni_
Definition cpu.h:177
int architecture() const
Definition cpu.h:50
int part() const
Definition cpu.h:53
bool has_intel_jcc_erratum_
Definition cpu.h:172
int part_
Definition cpu.h:157
bool has_sse_
Definition cpu.h:165
int architecture_
Definition cpu.h:155
bool has_vfp3_d32_
Definition cpu.h:190
bool has_avx_vnni_int8_
Definition cpu.h:178
bool has_pmull1q_
Definition cpu.h:196
bool has_osxsave_
Definition cpu.h:174
bool has_vfp3_
Definition cpu.h:189
bool has_lzcnt_
Definition cpu.h:183
int ext_model_
Definition cpu.h:150
int type_
Definition cpu.h:153
int num_virtual_address_bits_
Definition cpu.h:160
int implementer() const
Definition cpu.h:46
bool has_fp16_
Definition cpu.h:197
int stepping_
Definition cpu.h:148
bool has_f16c_
Definition cpu.h:180
int implementer_
Definition cpu.h:154
bool has_fma3_
Definition cpu.h:179
int icache_line_size_
Definition cpu.h:158
bool has_vfp_
Definition cpu.h:188
bool has_lse_
Definition cpu.h:193
bool is_running_in_vm_
Definition cpu.h:200
bool has_avx2_
Definition cpu.h:176
bool has_sse42_
Definition cpu.h:170
int ext_family_
Definition cpu.h:152
int family_
Definition cpu.h:151
bool has_bmi2_
Definition cpu.h:182
bool has_dot_prod_
Definition cpu.h:192
int dcache_line_size_
Definition cpu.h:159
bool has_msa_
Definition cpu.h:201
bool has_mmx_
Definition cpu.h:164
bool has_idiva_
Definition cpu.h:185
bool has_neon_
Definition cpu.h:186
int variant() const
Definition cpu.h:51
bool has_zbs_
Definition cpu.h:206
bool has_sse3_
Definition cpu.h:167
bool has_zba_
Definition cpu.h:204
bool has_sha3_
Definition cpu.h:195
RV_MMU_MODE riscv_mmu_
Definition cpu.h:202
bool has_bmi1_
Definition cpu.h:181
bool has_sahf_
Definition cpu.h:163
bool is_atom_
Definition cpu.h:171
bool has_fpu_
Definition cpu.h:161
bool has_mte_
Definition cpu.h:194
int model_
Definition cpu.h:149
bool has_popcnt_
Definition cpu.h:184
char vendor_[13]
Definition cpu.h:147
bool has_cetss_
Definition cpu.h:173
@ kPPCPower9
Definition cpu.h:67
@ kPPCPower10
Definition cpu.h:67
@ kPPCPower8
Definition cpu.h:67
bool has_rvv_
Definition cpu.h:203
bool has_avx_
Definition cpu.h:175
bool has_non_stop_time_stamp_counter_
Definition cpu.h:199
bool has_thumb2_
Definition cpu.h:187
bool has_zbb_
Definition cpu.h:205
bool has_sse41_
Definition cpu.h:169
bool has_ssse3_
Definition cpu.h:168
bool has_cmov_
Definition cpu.h:162
int variant_
Definition cpu.h:156
const ObjectRef type_
int end
int32_t offset
std::vector< PatternMap > pairs
ZoneVector< RpoNumber > & result
int n
Definition mul-fft.cc:296
digit_t ** part_
Definition mul-fft.cc:476
int Fclose(FILE *stream)
Definition wrappers.h:22
FILE * Fopen(const char *filename, const char *mode)
Definition wrappers.h:14
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define V8_INLINE
Definition v8config.h:500
std::unique_ptr< ValueMirror > value