#include "src/base/cpu.h"
#if defined(V8_OS_STARBOARD)
#include "starboard/cpu_features.h"
#endif
#if V8_LIBC_MSVCRT
#include <intrin.h>
#endif
#if V8_OS_LINUX
#include <linux/auxvec.h>
#endif
#if V8_GLIBC_PREREQ(2, 16) || V8_OS_ANDROID
#include <sys/auxv.h>
#endif
#if V8_OS_QNX
#include <sys/syspage.h>
#endif
#if V8_OS_LINUX && V8_HOST_ARCH_PPC64
#include <elf.h>
#endif
#if V8_OS_AIX
#include <sys/systemcfg.h>
#ifndef POWER_8
#define POWER_8 …
#endif
#ifndef POWER_9
#define POWER_9 …
#endif
#ifndef POWER_10
#define POWER_10 …
#endif
#endif
#if V8_OS_DARWIN
#include <sys/sysctl.h>
#endif
#if V8_OS_POSIX
#include <unistd.h>
#endif
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "src/base/logging.h"
#include "src/base/platform/wrappers.h"
#if V8_OS_WIN
#include <windows.h>
#endif
namespace v8 {
namespace base {
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
#if !V8_LIBC_MSVCRT
static V8_INLINE void __cpuid(int cpu_info[4], int info_type) { … }
static V8_INLINE void __cpuidex(int cpu_info[4], int info_type,
int sub_info_type) { … }
#endif
#elif V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 || V8_HOST_ARCH_MIPS64 || \
V8_HOST_ARCH_RISCV64
#if V8_OS_LINUX
#if V8_HOST_ARCH_ARM
#define HWCAP_SWP …
#define HWCAP_HALF …
#define HWCAP_THUMB …
#define HWCAP_26BIT …
#define HWCAP_FAST_MULT …
#define HWCAP_FPA …
#define HWCAP_VFP …
#define HWCAP_EDSP …
#define HWCAP_JAVA …
#define HWCAP_IWMMXT …
#define HWCAP_CRUNCH …
#define HWCAP_THUMBEE …
#define HWCAP_NEON …
#define HWCAP_VFPv3 …
#define HWCAP_VFPv3D16 …
#define HWCAP_TLS …
#define HWCAP_VFPv4 …
#define HWCAP_IDIVA …
#define HWCAP_IDIVT …
#define HWCAP_VFPD32 …
#define HWCAP_IDIV …
#define HWCAP_LPAE …
#endif
#if V8_HOST_ARCH_ARM64
#define HWCAP_FP …
#define HWCAP_ASIMD …
#define HWCAP_EVTSTRM …
#define HWCAP_AES …
#define HWCAP_PMULL …
#define HWCAP_SHA1 …
#define HWCAP_SHA2 …
#define HWCAP_CRC32 …
#define HWCAP_ATOMICS …
#define HWCAP_FPHP …
#define HWCAP_ASIMDHP …
#define HWCAP_CPUID …
#define HWCAP_ASIMDRDM …
#define HWCAP_JSCVT …
#define HWCAP_FCMA …
#define HWCAP_LRCPC …
#define HWCAP_DCPOP …
#define HWCAP_SHA3 …
#define HWCAP_SM3 …
#define HWCAP_SM4 …
#define HWCAP_ASIMDDP …
#define HWCAP_SHA512 …
#define HWCAP_SVE …
#define HWCAP_ASIMDFHM …
#define HWCAP_DIT …
#define HWCAP_USCAT …
#define HWCAP_ILRCPC …
#define HWCAP_FLAGM …
#define HWCAP_SSBS …
#define HWCAP_SB …
#define HWCAP_PACA …
#define HWCAP_PACG …
#define HWCAP2_MTE …
#endif
#if V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64
static std::tuple<uint32_t, uint32_t> ReadELFHWCaps() {
uint32_t hwcap = 0;
uint32_t hwcap2 = 0;
#if (V8_GLIBC_PREREQ(2, 16) || V8_OS_ANDROID) && defined(AT_HWCAP)
hwcap = static_cast<uint32_t>(getauxval(AT_HWCAP));
#if defined(AT_HWCAP2)
hwcap2 = static_cast<uint32_t>(getauxval(AT_HWCAP2));
#endif
#else
FILE* fp = base::Fopen("/proc/self/auxv", "r");
if (fp != nullptr) {
struct {
uint32_t tag;
uint32_t value;
} entry;
for (;;) {
size_t n = fread(&entry, sizeof(entry), 1, fp);
if (n == 0 || (entry.tag == 0 && entry.value == 0)) {
break;
}
if (entry.tag == AT_HWCAP) {
hwcap = entry.value;
break;
}
}
base::Fclose(fp);
}
#endif
return std::make_tuple(hwcap, hwcap2);
}
#endif
class CPUInfo final {
public:
CPUInfo() : datalen_(0) {
static const char PATHNAME[] = "/proc/cpuinfo";
FILE* fp = base::Fopen(PATHNAME, "r");
if (fp != nullptr) {
for (;;) {
char buffer[256];
size_t n = fread(buffer, 1, sizeof(buffer), fp);
if (n == 0) {
break;
}
datalen_ += n;
}
base::Fclose(fp);
}
data_ = new char[datalen_ + 1];
fp = base::Fopen(PATHNAME, "r");
if (fp != nullptr) {
for (size_t offset = 0; offset < datalen_; ) {
size_t n = fread(data_ + offset, 1, datalen_ - offset, fp);
if (n == 0) {
break;
}
offset += n;
}
base::Fclose(fp);
}
data_[datalen_] = '\0';
}
~CPUInfo() {
delete[] data_;
}
char* ExtractField(const char* field) const {
DCHECK_NOT_NULL(field);
size_t fieldlen = strlen(field);
char* p = data_;
for (;;) {
p = strstr(p, field);
if (p == nullptr) {
return nullptr;
}
if (p == data_ || p[-1] == '\n') {
break;
}
p += fieldlen;
}
p = strchr(p + fieldlen, ':');
if (p == nullptr || !isspace(p[1])) {
return nullptr;
}
p += 2;
char* q = strchr(p, '\n');
if (q == nullptr) {
q = data_ + datalen_;
}
size_t len = q - p;
char* result = new char[len + 1];
if (result != nullptr) {
memcpy(result, p, len);
result[len] = '\0';
}
return result;
}
private:
char* data_;
size_t datalen_;
};
static bool HasListItem(const char* list, const char* item) {
ssize_t item_len = strlen(item);
const char* p = list;
if (p != nullptr) {
while (*p != '\0') {
while (isspace(*p)) ++p;
const char* q = p;
while (*q != '\0' && !isspace(*q)) ++q;
if (item_len == q - p && memcmp(p, item, item_len) == 0) {
return true;
}
p = q;
}
}
return false;
}
#endif
#endif
#if defined(V8_OS_STARBOARD)
bool CPU::StarboardDetectCPU() {
SbCPUFeatures features;
if (!SbCPUFeaturesGet(&features)) {
return false;
}
architecture_ = features.arm.architecture_generation;
switch (features.architecture) {
case kSbCPUFeaturesArchitectureArm:
case kSbCPUFeaturesArchitectureArm64:
has_neon_ = features.arm.has_neon;
has_thumb2_ = features.arm.has_thumb2;
has_vfp_ = features.arm.has_vfp;
has_vfp3_ = features.arm.has_vfp3;
has_vfp3_d32_ = features.arm.has_vfp3_d32;
has_idiva_ = features.arm.has_idiva;
break;
case kSbCPUFeaturesArchitectureX86:
case kSbCPUFeaturesArchitectureX86_64:
has_cmov_ = features.x86.has_cmov;
has_sse2_ = features.x86.has_sse2;
has_sse3_ = features.x86.has_sse3;
has_ssse3_ = features.x86.has_ssse3;
has_sse41_ = features.x86.has_sse41;
has_sahf_ = features.x86.has_sahf;
has_avx_ = features.x86.has_avx;
has_avx2_ = features.x86.has_avx2;
has_fma3_ = features.x86.has_fma3;
has_bmi1_ = features.x86.has_bmi1;
has_bmi2_ = features.x86.has_bmi2;
has_lzcnt_ = features.x86.has_lzcnt;
has_popcnt_ = features.x86.has_popcnt;
has_f16c_ = features.x86.has_f16c;
break;
default:
return false;
}
return true;
}
#endif
CPU::CPU()
: … { … }
}
}