#else // __arm__
// Probe for additional features not already known to be available.
- if (!IsSupported(VFP3) && FLAG_enable_vfp3 && OS::ArmCpuHasFeature(VFP3)) {
+ CPU cpu;
+ if (!IsSupported(VFP3) && FLAG_enable_vfp3 && cpu.has_vfp3()) {
// This implementation also sets the VFP flags if runtime
// detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
// 0406B, page A1-6.
static_cast<uint64_t>(1) << ARMv7;
}
- if (!IsSupported(NEON) && FLAG_enable_neon && OS::ArmCpuHasFeature(NEON)) {
+ if (!IsSupported(NEON) && FLAG_enable_neon && cpu.has_neon()) {
found_by_runtime_probing_only_ |= 1u << NEON;
}
- if (!IsSupported(ARMv7) && FLAG_enable_armv7 && OS::ArmCpuHasFeature(ARMv7)) {
+ if (!IsSupported(ARMv7) && FLAG_enable_armv7 && cpu.architecture() >= 7) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << ARMv7;
}
- if (!IsSupported(SUDIV) && FLAG_enable_sudiv && OS::ArmCpuHasFeature(SUDIV)) {
+ if (!IsSupported(SUDIV) && FLAG_enable_sudiv && cpu.has_idiva()) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << SUDIV;
}
if (!IsSupported(UNALIGNED_ACCESSES) && FLAG_enable_unaligned_accesses
- && OS::ArmCpuHasFeature(ARMv7)) {
+ && cpu.architecture() >= 7) {
found_by_runtime_probing_only_ |=
static_cast<uint64_t>(1) << UNALIGNED_ACCESSES;
}
- CpuImplementer implementer = OS::GetCpuImplementer();
- if (implementer == QUALCOMM_IMPLEMENTER &&
- FLAG_enable_movw_movt && OS::ArmCpuHasFeature(ARMv7)) {
+ // Use movw/movt for QUALCOMM ARMv7 cores.
+ if (cpu.implementer() == CPU::QUALCOMM &&
+ cpu.architecture() >= 7 &&
+ FLAG_enable_movw_movt) {
found_by_runtime_probing_only_ |=
static_cast<uint64_t>(1) << MOVW_MOVT_IMMEDIATE_LOADS;
}
- CpuPart part = OS::GetCpuPart(implementer);
- if ((part == CORTEX_A9) || (part == CORTEX_A5)) {
+ // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines.
+ if (cpu.implementer() == CPU::ARM &&
+ (cpu.part() == CPU::ARM_CORTEX_A5 ||
+ cpu.part() == CPU::ARM_CORTEX_A9)) {
cache_line_size_ = 32;
}
- if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs
- && OS::ArmCpuHasFeature(VFP32DREGS)) {
+ if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs && cpu.has_vfp3_d32()) {
found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP32DREGS;
}
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "cpu.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "checks.h"
+
+namespace v8 {
+namespace internal {
+
+#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+
+#if V8_CC_MSVC
+
+#include <intrin.h> // NOLINT
+
+#elif defined(__i386__) && defined(__pic__)
+
+static V8_INLINE(void __cpuid(int cpu_info[4], int info_type)) {
+ __asm__ volatile (
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type)
+ );
+}
+
+#else // !V8_CC_MSVC || (!defined(__i386__) && !defined(__pic__))
+
+static void V8_INLINE(__cpuid(int cpu_info[4], int info_type)) {
+ __asm__ volatile (
+ "cpuid \n\t"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type)
+ );
+}
+
+#endif
+
+#elif V8_HOST_ARCH_ARM || V8_HOST_ARCH_MIPS
+
+#if V8_HOST_ARCH_ARM
+
+// See <uapi/asm/hwcap.h> kernel header.
+/*
+ * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
+ */
+#define HWCAP_SWP (1 << 0)
+#define HWCAP_HALF (1 << 1)
+#define HWCAP_THUMB (1 << 2)
+#define HWCAP_26BIT (1 << 3) /* Play it safe */
+#define HWCAP_FAST_MULT (1 << 4)
+#define HWCAP_FPA (1 << 5)
+#define HWCAP_VFP (1 << 6)
+#define HWCAP_EDSP (1 << 7)
+#define HWCAP_JAVA (1 << 8)
+#define HWCAP_IWMMXT (1 << 9)
+#define HWCAP_CRUNCH (1 << 10)
+#define HWCAP_THUMBEE (1 << 11)
+#define HWCAP_NEON (1 << 12)
+#define HWCAP_VFPv3 (1 << 13)
+#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
+#define HWCAP_TLS (1 << 15)
+#define HWCAP_VFPv4 (1 << 16)
+#define HWCAP_IDIVA (1 << 17)
+#define HWCAP_IDIVT (1 << 18)
+#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
+#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
+#define HWCAP_LPAE (1 << 20)
+
+#define AT_HWCAP 16
+
+// Read the ELF HWCAP flags by parsing /proc/self/auxv.
+static uint32_t ReadELFHWCaps() {
+ uint32_t result = 0;
+ FILE* fp = fopen("/proc/self/auxv", "r");
+ if (fp != NULL) {
+ 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) {
+ result = entry.value;
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ return result;
+}
+
+#endif // V8_HOST_ARCH_ARM
+
+// Extract the information exposed by the kernel via /proc/cpuinfo.
+class CPUInfo V8_FINAL BASE_EMBEDDED {
+ public:
+ CPUInfo() : datalen_(0) {
+ // Get the size of the cpuinfo file by reading it until the end. This is
+ // required because files under /proc do not always return a valid size
+ // when using fseek(0, SEEK_END) + ftell(). Nor can the be mmap()-ed.
+ static const char PATHNAME[] = "/proc/cpuinfo";
+ FILE* fp = fopen(PATHNAME, "r");
+ if (fp != NULL) {
+ for (;;) {
+ char buffer[256];
+ size_t n = fread(buffer, 1, sizeof(buffer), fp);
+ if (n == 0) {
+ break;
+ }
+ datalen_ += n;
+ }
+ fclose(fp);
+ }
+
+ // Read the contents of the cpuinfo file.
+ data_ = new char[datalen_ + 1];
+ fp = fopen(PATHNAME, "r");
+ if (fp != NULL) {
+ for (size_t offset = 0; offset < datalen_; ) {
+ size_t n = fread(data_ + offset, 1, datalen_ - offset, fp);
+ if (n == 0) {
+ break;
+ }
+ offset += n;
+ }
+ fclose(fp);
+ }
+
+ // Zero-terminate the data.
+ data_[datalen_] = '\0';
+ }
+
+ ~CPUInfo() {
+ delete[] data_;
+ }
+
+ // Extract the content of a the first occurence of a given field in
+ // the content of the cpuinfo file and return it as a heap-allocated
+ // string that must be freed by the caller using delete[].
+ // Return NULL if not found.
+ char* ExtractField(const char* field) const {
+ ASSERT(field != NULL);
+
+ // Look for first field occurence, and ensure it starts the line.
+ size_t fieldlen = strlen(field);
+ char* p = data_;
+ for (;;) {
+ p = strstr(p, field);
+ if (p == NULL) {
+ return NULL;
+ }
+ if (p == data_ || p[-1] == '\n') {
+ break;
+ }
+ p += fieldlen;
+ }
+
+ // Skip to the first colon followed by a space.
+ p = strchr(p + fieldlen, ':');
+ if (p == NULL || !isspace(p[1])) {
+ return NULL;
+ }
+ p += 2;
+
+ // Find the end of the line.
+ char* q = strchr(p, '\n');
+ if (q == NULL) {
+ q = data_ + datalen_;
+ }
+
+ // Copy the line into a heap-allocated buffer.
+ size_t len = q - p;
+ char* result = new char[len + 1];
+ if (result != NULL) {
+ memcpy(result, p, len);
+ result[len] = '\0';
+ }
+ return result;
+ }
+
+ private:
+ char* data_;
+ size_t datalen_;
+};
+
+
+// Checks that a space-separated list of items contains one given 'item'.
+static bool HasListItem(const char* list, const char* item) {
+ ssize_t item_len = strlen(item);
+ const char* p = list;
+ if (p != NULL) {
+ while (*p != '\0') {
+ // Skip whitespace.
+ while (isspace(*p)) ++p;
+
+ // Find end of current list item.
+ const char* q = p;
+ while (*q != '\0' && !isspace(*q)) ++q;
+
+ if (item_len == q - p && memcmp(p, item, item_len) == 0) {
+ return true;
+ }
+
+ // Skip to next item.
+ p = q;
+ }
+ }
+ return false;
+}
+
+#endif // V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+
+CPU::CPU() : stepping_(0),
+ model_(0),
+ ext_model_(0),
+ family_(0),
+ ext_family_(0),
+ type_(0),
+ implementer_(0),
+ architecture_(0),
+ part_(0),
+ has_fpu_(false),
+ has_cmov_(false),
+ has_sahf_(false),
+ has_mmx_(false),
+ has_sse_(false),
+ has_sse2_(false),
+ has_sse3_(false),
+ has_ssse3_(false),
+ has_sse41_(false),
+ has_sse42_(false),
+ has_idiva_(false),
+ has_neon_(false),
+ has_thumbee_(false),
+ has_vfp_(false),
+ has_vfp3_(false),
+ has_vfp3_d32_(false) {
+ memcpy(vendor_, "Unknown", 8);
+#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+ int cpu_info[4];
+
+ // __cpuid with an InfoType argument of 0 returns the number of
+ // valid Ids in CPUInfo[0] and the CPU identification string in
+ // the other three array elements. The CPU identification string is
+ // not in linear order. The code below arranges the information
+ // in a human readable form. The human readable order is CPUInfo[1] |
+ // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
+ // before using memcpy to copy these three array elements to cpu_string.
+ __cpuid(cpu_info, 0);
+ unsigned num_ids = cpu_info[0];
+ std::swap(cpu_info[2], cpu_info[3]);
+ memcpy(vendor_, cpu_info + 1, 12);
+ vendor_[12] = '\0';
+
+ // Interpret CPU feature information.
+ if (num_ids > 0) {
+ __cpuid(cpu_info, 1);
+ stepping_ = cpu_info[0] & 0xf;
+ model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
+ family_ = (cpu_info[0] >> 8) & 0xf;
+ type_ = (cpu_info[0] >> 12) & 0x3;
+ ext_model_ = (cpu_info[0] >> 16) & 0xf;
+ ext_family_ = (cpu_info[0] >> 20) & 0xff;
+ has_fpu_ = (cpu_info[3] & 0x00000001) != 0;
+ has_cmov_ = (cpu_info[3] & 0x00008000) != 0;
+ has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
+ has_sse_ = (cpu_info[3] & 0x02000000) != 0;
+ has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
+ has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
+ has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
+ has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
+ has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
+ }
+
+ // Query extended IDs.
+ __cpuid(cpu_info, 0x80000000);
+ unsigned num_ext_ids = cpu_info[0];
+
+ // Interpret extended CPU feature information.
+ if (num_ext_ids > 0x80000000) {
+ __cpuid(cpu_info, 0x80000001);
+ // SAHF is always available in compat/legacy mode,
+ // but must be probed in long mode.
+#if V8_HOST_ARCH_IA32
+ has_sahf_ = true;
+#else
+ has_sahf_ = (cpu_info[2] & 0x00000001) != 0;
+#endif
+ }
+#elif V8_HOST_ARCH_ARM
+ CPUInfo cpu_info;
+
+ // Extract implementor from the "CPU implementer" field.
+ char* implementer = cpu_info.ExtractField("CPU implementer");
+ if (implementer != NULL) {
+ char* end ;
+ implementer_ = strtol(implementer, &end, 0);
+ if (end == implementer) {
+ implementer_ = 0;
+ }
+ delete[] implementer;
+ }
+
+ // Extract part number from the "CPU part" field.
+ char* part = cpu_info.ExtractField("CPU part");
+ if (part != NULL) {
+ char* end ;
+ part_ = strtol(part, &end, 0);
+ if (end == part) {
+ part_ = 0;
+ }
+ delete[] part;
+ }
+
+ // Extract architecture from the "CPU Architecture" field.
+ // The list is well-known, unlike the the output of
+ // the 'Processor' field which can vary greatly.
+ // See the definition of the 'proc_arch' array in
+ // $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
+ // same file.
+ char* architecture = cpu_info.ExtractField("CPU architecture");
+ if (architecture != NULL) {
+ char* end;
+ architecture_ = strtol(architecture, &end, 10);
+ if (end == architecture) {
+ architecture_ = 0;
+ }
+ delete[] architecture;
+
+ // Unfortunately, it seems that certain ARMv6-based CPUs
+ // report an incorrect architecture number of 7!
+ //
+ // See http://code.google.com/p/android/issues/detail?id=10812
+ //
+ // We try to correct this by looking at the 'elf_format'
+ // field reported by the 'Processor' field, which is of the
+ // form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
+ // an ARMv6-one. For example, the Raspberry Pi is one popular
+ // ARMv6 device that reports architecture 7.
+ if (architecture_ == 7) {
+ char* processor = cpu_info.ExtractField("Processor");
+ if (HasListItem(processor, "(v6l)")) {
+ architecture_ = 6;
+ }
+ delete[] processor;
+ }
+ }
+
+ // Try to extract the list of CPU features from ELF hwcaps.
+ uint32_t hwcaps = ReadELFHWCaps();
+ if (hwcaps != 0) {
+ has_idiva_ = (hwcaps & HWCAP_IDIVA) != 0;
+ has_neon_ = (hwcaps & HWCAP_NEON) != 0;
+ has_thumbee_ = (hwcaps & HWCAP_THUMBEE) != 0;
+ has_vfp_ = (hwcaps & HWCAP_VFP) != 0;
+ has_vfp3_ = (hwcaps & (HWCAP_VFPv3 | HWCAP_VFPv3D16 | HWCAP_VFPv4)) != 0;
+ has_vfp3_d32_ = (has_vfp3_ && ((hwcaps & HWCAP_VFPv3D16) == 0 ||
+ (hwcaps & HWCAP_VFPD32) != 0));
+ } else {
+ // Try to fallback to "Features" CPUInfo field.
+ char* features = cpu_info.ExtractField("Features");
+ has_idiva_ = HasListItem(features, "idiva");
+ has_neon_ = HasListItem(features, "neon");
+ has_thumbee_ = HasListItem(features, "thumbee");
+ has_vfp_ = HasListItem(features, "vfp");
+ if (HasListItem(features, "vfpv3")) {
+ has_vfp3_ = true;
+ has_vfp3_d32_ = true;
+ } else if (HasListItem(features, "vfpv3d16")) {
+ has_vfp3_ = true;
+ }
+ delete[] features;
+ }
+
+ // Some old kernels will report vfp not vfpv3. Here we make an attempt
+ // to detect vfpv3 by checking for vfp *and* neon, since neon is only
+ // available on architectures with vfpv3. Checking neon on its own is
+ // not enough as it is possible to have neon without vfp.
+ if (has_vfp_ && has_neon_) {
+ has_vfp3_ = true;
+ }
+
+ // VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6.
+ if (architecture_ < 7 && has_vfp3_) {
+ architecture_ = 7;
+ }
+
+ // ARMv7 implies ThumbEE.
+ if (architecture_ >= 7) {
+ has_thumbee_ = true;
+ }
+
+ // The earliest architecture with ThumbEE is ARMv6T2.
+ if (has_thumbee_ && architecture_ < 6) {
+ architecture_ = 6;
+ }
+
+ // We don't support any FPUs other than VFP.
+ has_fpu_ = has_vfp_;
+#elif V8_HOST_ARCH_MIPS
+ // Simple detection of FPU at runtime for Linux.
+ // It is based on /proc/cpuinfo, which reveals hardware configuration
+ // to user-space applications. According to MIPS (early 2010), no similar
+ // facility is universally available on the MIPS architectures,
+ // so it's up to individual OSes to provide such.
+ CPUInfo cpu_info;
+ char* cpu_model = cpu_info.ExtractField("cpu model");
+ has_fpu_ = HasListItem(cpu_model, "FPU");
+ delete[] cpu_model;
+#endif
+}
+
+} } // namespace v8::internal
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2006-2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// ----------------------------------------------------------------------------
// CPU
//
-// This class has static methods for the architecture specific functions. Add
-// methods here to cope with differences between the supported architectures.
+// Query information about the processor.
//
-// For each architecture the file cpu_<arch>.cc contains the implementation of
-// these functions.
+// This class also has static methods for the architecture specific functions.
+// Add methods here to cope with differences between the supported
+// architectures. For each architecture the file cpu_<arch>.cc contains the
+// implementation of these static functions.
-class CPU : public AllStatic {
+class CPU V8_FINAL BASE_EMBEDDED {
public:
+ CPU();
+
+ // x86 CPUID information
+ const char* vendor() const { return vendor_; }
+ int stepping() const { return stepping_; }
+ int model() const { return model_; }
+ int ext_model() const { return ext_model_; }
+ int family() const { return family_; }
+ int ext_family() const { return ext_family_; }
+ int type() const { return type_; }
+
+ // arm implementer/part information
+ int implementer() const { return implementer_; }
+ static const int ARM = 0x41;
+ static const int QUALCOMM = 0x51;
+ int architecture() const { return architecture_; }
+ int part() const { return part_; }
+ static const int ARM_CORTEX_A5 = 0xc05;
+ static const int ARM_CORTEX_A7 = 0xc07;
+ static const int ARM_CORTEX_A8 = 0xc08;
+ static const int ARM_CORTEX_A9 = 0xc09;
+ static const int ARM_CORTEX_A12 = 0xc0c;
+ static const int ARM_CORTEX_A15 = 0xc0f;
+
+ // General features
+ bool has_fpu() const { return has_fpu_; }
+
+ // x86 features
+ bool has_cmov() const { return has_cmov_; }
+ bool has_sahf() const { return has_sahf_; }
+ bool has_mmx() const { return has_mmx_; }
+ bool has_sse() const { return has_sse_; }
+ bool has_sse2() const { return has_sse2_; }
+ bool has_sse3() const { return has_sse3_; }
+ bool has_ssse3() const { return has_ssse3_; }
+ bool has_sse41() const { return has_sse41_; }
+ bool has_sse42() const { return has_sse42_; }
+
+ // arm features
+ bool has_idiva() const { return has_idiva_; }
+ bool has_neon() const { return has_neon_; }
+ bool has_thumbee() const { return has_thumbee_; }
+ bool has_vfp() const { return has_vfp_; }
+ bool has_vfp3() const { return has_vfp3_; }
+ bool has_vfp3_d32() const { return has_vfp3_d32_; }
+
// Initializes the cpu architecture support. Called once at VM startup.
static void SetUp();
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
+
+ private:
+ char vendor_[13];
+ int stepping_;
+ int model_;
+ int ext_model_;
+ int family_;
+ int ext_family_;
+ int type_;
+ int implementer_;
+ int architecture_;
+ int part_;
+ bool has_fpu_;
+ bool has_cmov_;
+ bool has_sahf_;
+ bool has_mmx_;
+ bool has_sse_;
+ bool has_sse2_;
+ bool has_sse3_;
+ bool has_ssse3_;
+ bool has_sse41_;
+ bool has_sse42_;
+ bool has_idiva_;
+ bool has_neon_;
+ bool has_thumbee_;
+ bool has_vfp_;
+ bool has_vfp3_;
+ bool has_vfp3_d32_;
};
} } // namespace v8::internal
return; // No features if we might serialize.
}
- const int kBufferSize = 4 * KB;
- VirtualMemory* memory = new VirtualMemory(kBufferSize);
- if (!memory->IsReserved()) {
- delete memory;
- return;
+ uint64_t probed_features = 0;
+ CPU cpu;
+ if (cpu.has_sse41()) {
+ probed_features |= static_cast<uint64_t>(1) << SSE4_1;
}
- ASSERT(memory->size() >= static_cast<size_t>(kBufferSize));
- if (!memory->Commit(memory->address(), kBufferSize, true/*executable*/)) {
- delete memory;
- return;
+ if (cpu.has_sse3()) {
+ probed_features |= static_cast<uint64_t>(1) << SSE3;
}
-
- Assembler assm(NULL, memory->address(), kBufferSize);
- Label cpuid, done;
-#define __ assm.
- // Save old esp, since we are going to modify the stack.
- __ push(ebp);
- __ pushfd();
- __ push(ecx);
- __ push(ebx);
- __ mov(ebp, esp);
-
- // If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
- __ pushfd();
- __ pop(eax);
- __ mov(edx, eax);
- __ xor_(eax, 0x200000); // Flip bit 21.
- __ push(eax);
- __ popfd();
- __ pushfd();
- __ pop(eax);
- __ xor_(eax, edx); // Different if CPUID is supported.
- __ j(not_zero, &cpuid);
-
- // CPUID not supported. Clear the supported features in edx:eax.
- __ xor_(eax, eax);
- __ xor_(edx, edx);
- __ jmp(&done);
-
- // Invoke CPUID with 1 in eax to get feature information in
- // ecx:edx. Temporarily enable CPUID support because we know it's
- // safe here.
- __ bind(&cpuid);
- __ mov(eax, 1);
- supported_ = (1 << CPUID);
- { CpuFeatureScope fscope(&assm, CPUID);
- __ cpuid();
+ if (cpu.has_sse2()) {
+ probed_features |= static_cast<uint64_t>(1) << SSE2;
+ }
+ if (cpu.has_cmov()) {
+ probed_features |= static_cast<uint64_t>(1) << CMOV;
}
- supported_ = 0;
-
- // Move the result from ecx:edx to edx:eax and make sure to mark the
- // CPUID feature as supported.
- __ mov(eax, edx);
- __ or_(eax, 1 << CPUID);
- __ mov(edx, ecx);
-
- // Done.
- __ bind(&done);
- __ mov(esp, ebp);
- __ pop(ebx);
- __ pop(ecx);
- __ popfd();
- __ pop(ebp);
- __ ret(0);
-#undef __
-
- typedef uint64_t (*F0)();
- F0 probe = FUNCTION_CAST<F0>(reinterpret_cast<Address>(memory->address()));
- uint64_t probed_features = probe();
+
+ // SAHF must be available in compat/legacy mode.
+ ASSERT(cpu.has_sahf());
+ probed_features |= static_cast<uint64_t>(1) << SAHF;
+
uint64_t platform_features = OS::CpuFeaturesImpliedByPlatform();
supported_ = probed_features | platform_features;
found_by_runtime_probing_only_ = probed_features & ~platform_features;
-
- delete memory;
}
void Assembler::cpuid() {
- ASSERT(IsEnabled(CPUID));
EnsureSpace ensure_space(this);
EMIT(0x0F);
EMIT(0xA2);
supported_ |= static_cast<uint64_t>(1) << FPU;
#else
// Probe for additional features not already known to be available.
- if (OS::MipsCpuHasFeature(FPU)) {
+ CPU cpu;
+ if (cpu.has_fpu()) {
// This implementation also sets the FPU flags if
// runtime detection of FPU returns true.
supported_ |= static_cast<uint64_t>(1) << FPU;
#ifdef __arm__
-static bool CPUInfoContainsString(const char * search_string) {
- const char* file_name = "/proc/cpuinfo";
- // This is written as a straight shot one pass parser
- // and not using STL string and ifstream because,
- // on Linux, it's reading from a (non-mmap-able)
- // character special device.
- FILE* f = NULL;
- const char* what = search_string;
-
- if (NULL == (f = fopen(file_name, "r"))) {
- OS::PrintError("Failed to open /proc/cpuinfo\n");
- return false;
- }
-
- int k;
- while (EOF != (k = fgetc(f))) {
- if (k == *what) {
- ++what;
- while ((*what != '\0') && (*what == fgetc(f))) {
- ++what;
- }
- if (*what == '\0') {
- fclose(f);
- return true;
- } else {
- what = search_string;
- }
- }
- }
- fclose(f);
-
- // Did not find string in the proc file.
- return false;
-}
-
-
-bool OS::ArmCpuHasFeature(CpuFeature feature) {
- const char* search_string = NULL;
- // Simple detection of VFP at runtime for Linux.
- // It is based on /proc/cpuinfo, which reveals hardware configuration
- // to user-space applications. According to ARM (mid 2009), no similar
- // facility is universally available on the ARM architectures,
- // so it's up to individual OSes to provide such.
- switch (feature) {
- case VFP3:
- search_string = "vfpv3";
- break;
- case NEON:
- search_string = "neon";
- break;
- case ARMv7:
- search_string = "ARMv7";
- break;
- case SUDIV:
- search_string = "idiva";
- break;
- case VFP32DREGS:
- // This case is handled specially below.
- break;
- default:
- UNREACHABLE();
- }
-
- if (feature == VFP32DREGS) {
- return ArmCpuHasFeature(VFP3) && !CPUInfoContainsString("d16");
- }
-
- if (CPUInfoContainsString(search_string)) {
- return true;
- }
-
- if (feature == VFP3) {
- // Some old kernels will report vfp not vfpv3. Here we make a last attempt
- // to detect vfpv3 by checking for vfp *and* neon, since neon is only
- // available on architectures with vfpv3.
- // Checking neon on its own is not enough as it is possible to have neon
- // without vfp.
- if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
- return true;
- }
- }
-
- return false;
-}
-
-
-CpuImplementer OS::GetCpuImplementer() {
- static bool use_cached_value = false;
- static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER;
- if (use_cached_value) {
- return cached_value;
- }
- if (CPUInfoContainsString("CPU implementer\t: 0x41")) {
- cached_value = ARM_IMPLEMENTER;
- } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) {
- cached_value = QUALCOMM_IMPLEMENTER;
- } else {
- cached_value = UNKNOWN_IMPLEMENTER;
- }
- use_cached_value = true;
- return cached_value;
-}
-
-
-CpuPart OS::GetCpuPart(CpuImplementer implementer) {
- static bool use_cached_value = false;
- static CpuPart cached_value = CPU_UNKNOWN;
- if (use_cached_value) {
- return cached_value;
- }
- if (implementer == ARM_IMPLEMENTER) {
- if (CPUInfoContainsString("CPU part\t: 0xc0f")) {
- cached_value = CORTEX_A15;
- } else if (CPUInfoContainsString("CPU part\t: 0xc0c")) {
- cached_value = CORTEX_A12;
- } else if (CPUInfoContainsString("CPU part\t: 0xc09")) {
- cached_value = CORTEX_A9;
- } else if (CPUInfoContainsString("CPU part\t: 0xc08")) {
- cached_value = CORTEX_A8;
- } else if (CPUInfoContainsString("CPU part\t: 0xc07")) {
- cached_value = CORTEX_A7;
- } else if (CPUInfoContainsString("CPU part\t: 0xc05")) {
- cached_value = CORTEX_A5;
- } else {
- cached_value = CPU_UNKNOWN;
- }
- } else {
- cached_value = CPU_UNKNOWN;
- }
- use_cached_value = true;
- return cached_value;
-}
-
bool OS::ArmUsingHardFloat() {
// GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
#endif // def __arm__
-#ifdef __mips__
-bool OS::MipsCpuHasFeature(CpuFeature feature) {
- const char* search_string = NULL;
- const char* file_name = "/proc/cpuinfo";
- // Simple detection of FPU at runtime for Linux.
- // It is based on /proc/cpuinfo, which reveals hardware configuration
- // to user-space applications. According to MIPS (early 2010), no similar
- // facility is universally available on the MIPS architectures,
- // so it's up to individual OSes to provide such.
- //
- // This is written as a straight shot one pass parser
- // and not using STL string and ifstream because,
- // on Linux, it's reading from a (non-mmap-able)
- // character special device.
-
- switch (feature) {
- case FPU:
- search_string = "FPU";
- break;
- default:
- UNREACHABLE();
- }
-
- FILE* f = NULL;
- const char* what = search_string;
-
- if (NULL == (f = fopen(file_name, "r"))) {
- OS::PrintError("Failed to open /proc/cpuinfo\n");
- return false;
- }
-
- int k;
- while (EOF != (k = fgetc(f))) {
- if (k == *what) {
- ++what;
- while ((*what != '\0') && (*what == fgetc(f))) {
- ++what;
- }
- if (*what == '\0') {
- fclose(f);
- return true;
- } else {
- what = search_string;
- }
- }
- }
- fclose(f);
-
- // Did not find string in the proc file.
- return false;
-}
-#endif // def __mips__
-
-
const char* OS::LocalTimezone(double time) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(floor(time/msPerSecond));
}
-CpuImplementer OS::GetCpuImplementer() {
- UNIMPLEMENTED();
-}
-
-
-CpuPart OS::GetCpuPart(CpuImplementer implementer) {
- UNIMPLEMENTED();
-}
-
-
-bool OS::ArmCpuHasFeature(CpuFeature feature) {
- UNIMPLEMENTED();
-}
-
-
bool OS::ArmUsingHardFloat() {
UNIMPLEMENTED();
}
uint64_t OS::CpuFeaturesImpliedByPlatform() {
-#if defined(__APPLE__)
+#if V8_OS_MACOSX
// Mac OS X requires all these to install so we can assume they are present.
// These constants are defined by the CPUid instructions.
const uint64_t one = 1;
- return (one << SSE2) | (one << CMOV) | (one << CPUID);
+ return (one << SSE2) | (one << CMOV);
#else
return 0; // Nothing special about the other systems.
#endif
// Returns the double constant NAN
static double nan_value();
- // Support runtime detection of Cpu implementer
- static CpuImplementer GetCpuImplementer();
-
- // Support runtime detection of Cpu implementer
- static CpuPart GetCpuPart(CpuImplementer implementer);
-
- // Support runtime detection of VFP3 on ARM CPUs.
- static bool ArmCpuHasFeature(CpuFeature feature);
-
// Support runtime detection of whether the hard float option of the
// EABI is used.
static bool ArmUsingHardFloat();
- // Support runtime detection of FPU on MIPS CPUs.
- static bool MipsCpuHasFeature(CpuFeature feature);
-
// Returns the activation frame alignment constraint or zero if
// the platform doesn't care. Guaranteed to be a power of two.
static int ActivationFrameAlignment();
#endif
-enum CpuImplementer {
- UNKNOWN_IMPLEMENTER,
- ARM_IMPLEMENTER,
- QUALCOMM_IMPLEMENTER
-};
-
-
-enum CpuPart {
- CPU_UNKNOWN,
- CORTEX_A15,
- CORTEX_A12,
- CORTEX_A9,
- CORTEX_A8,
- CORTEX_A7,
- CORTEX_A5
-};
-
-
// Feature flags bit positions. They are mostly based on the CPUID spec.
-// (We assign CPUID itself to one of the currently reserved bits --
-// feel free to change this if needed.)
// On X86/X64, values below 32 are bits in EDX, values above 32 are bits in ECX.
enum CpuFeature { SSE4_1 = 32 + 19, // x86
SSE3 = 32 + 0, // x86
SSE2 = 26, // x86
CMOV = 15, // x86
- CPUID = 10, // x86
VFP3 = 1, // ARM
ARMv7 = 2, // ARM
SUDIV = 3, // ARM
return; // No features if we might serialize.
}
- const int kBufferSize = 4 * KB;
- VirtualMemory* memory = new VirtualMemory(kBufferSize);
- if (!memory->IsReserved()) {
- delete memory;
- return;
+ uint64_t probed_features = 0;
+ CPU cpu;
+ if (cpu.has_sse41()) {
+ probed_features |= static_cast<uint64_t>(1) << SSE4_1;
}
- ASSERT(memory->size() >= static_cast<size_t>(kBufferSize));
- if (!memory->Commit(memory->address(), kBufferSize, true/*executable*/)) {
- delete memory;
- return;
+ if (cpu.has_sse3()) {
+ probed_features |= static_cast<uint64_t>(1) << SSE3;
}
- Assembler assm(NULL, memory->address(), kBufferSize);
- Label cpuid, done;
-#define __ assm.
- // Save old rsp, since we are going to modify the stack.
- __ push(rbp);
- __ pushfq();
- __ push(rdi);
- __ push(rcx);
- __ push(rbx);
- __ movq(rbp, rsp);
-
- // If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
- __ pushfq();
- __ pop(rax);
- __ movq(rdx, rax);
- __ xor_(rax, Immediate(0x200000)); // Flip bit 21.
- __ push(rax);
- __ popfq();
- __ pushfq();
- __ pop(rax);
- __ xor_(rax, rdx); // Different if CPUID is supported.
- __ j(not_zero, &cpuid);
-
- // CPUID not supported. Clear the supported features in rax.
- __ xor_(rax, rax);
- __ jmp(&done);
-
- // Invoke CPUID with 1 in eax to get feature information in
- // ecx:edx. Temporarily enable CPUID support because we know it's
- // safe here.
- __ bind(&cpuid);
- __ movl(rax, Immediate(1));
- supported_ = kDefaultCpuFeatures | (1 << CPUID);
- { CpuFeatureScope fscope(&assm, CPUID);
- __ cpuid();
- // Move the result from ecx:edx to rdi.
- __ movl(rdi, rdx); // Zero-extended to 64 bits.
- __ shl(rcx, Immediate(32));
- __ or_(rdi, rcx);
-
- // Get the sahf supported flag, from CPUID(0x80000001)
- __ movq(rax, 0x80000001, RelocInfo::NONE64);
- __ cpuid();
+ // SSE2 must be available on every x64 CPU.
+ ASSERT(cpu.has_sse2());
+ probed_features |= static_cast<uint64_t>(1) << SSE2;
+
+ // CMOD must be available on every x64 CPU.
+ ASSERT(cpu.has_cmov());
+ probed_features |= static_cast<uint64_t>(1) << CMOV;
+
+ // SAHF is not generally available in long mode.
+ if (cpu.has_sahf()) {
+ probed_features |= static_cast<uint64_t>(1) << SAHF;
}
- supported_ = kDefaultCpuFeatures;
- // Put the CPU flags in rax.
- // rax = (rcx & 1) | (rdi & ~1) | (1 << CPUID).
- __ movl(rax, Immediate(1));
- __ and_(rcx, rax); // Bit 0 is set if SAHF instruction supported.
- __ not_(rax);
- __ and_(rax, rdi);
- __ or_(rax, rcx);
- __ or_(rax, Immediate(1 << CPUID));
-
- // Done.
- __ bind(&done);
- __ movq(rsp, rbp);
- __ pop(rbx);
- __ pop(rcx);
- __ pop(rdi);
- __ popfq();
- __ pop(rbp);
- __ ret(0);
-#undef __
-
- typedef uint64_t (*F0)();
- F0 probe = FUNCTION_CAST<F0>(reinterpret_cast<Address>(memory->address()));
-
- uint64_t probed_features = probe();
uint64_t platform_features = OS::CpuFeaturesImpliedByPlatform();
supported_ = probed_features | platform_features;
found_by_runtime_probing_only_
= probed_features & ~kDefaultCpuFeatures & ~platform_features;
-
- // CMOV must be available on an X64 CPU.
- ASSERT(IsSupported(CPUID));
- ASSERT(IsSupported(CMOV));
-
- delete memory;
}
void Assembler::cpuid() {
- ASSERT(IsEnabled(CPUID));
EnsureSpace ensure_space(this);
emit(0x0F);
emit(0xA2);
'test-circular-queue.cc',
'test-compiler.cc',
'test-conversions.cc',
+ 'test-cpu.cc',
'test-cpu-profiler.cc',
'test-dataflow.cc',
'test-date.cc',
'test-assembler-ia32.cc',
'test-code-stubs.cc',
'test-code-stubs-ia32.cc',
+ 'test-cpu-ia32.cc',
'test-disasm-ia32.cc',
'test-log-stack-tracer.cc'
],
'test-assembler-x64.cc',
'test-code-stubs.cc',
'test-code-stubs-x64.cc',
+ 'test-cpu-x64.cc',
'test-macro-assembler-x64.cc',
'test-log-stack-tracer.cc'
],
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "cpu.h"
+
+using namespace v8::internal;
+
+
+TEST(RequiredFeaturesX64) {
+ // Test for the features required by every x86 CPU in compat/legacy mode.
+ CPU cpu;
+ CHECK(cpu.has_sahf());
+}
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "cpu.h"
+
+using namespace v8::internal;
+
+
+TEST(RequiredFeaturesX64) {
+ // Test for the features required by every x64 CPU.
+ CPU cpu;
+ CHECK(cpu.has_fpu());
+ CHECK(cpu.has_cmov());
+ CHECK(cpu.has_mmx());
+ CHECK(cpu.has_sse());
+ CHECK(cpu.has_sse2());
+}
--- /dev/null
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "cpu.h"
+
+using namespace v8::internal;
+
+
+TEST(FeatureImplications) {
+ // Test for features implied by other features.
+ CPU cpu;
+
+ // ia32 and x64 features
+ CHECK(!cpu.has_sse() || cpu.has_mmx());
+ CHECK(!cpu.has_sse2() || cpu.has_sse());
+ CHECK(!cpu.has_sse3() || cpu.has_sse2());
+ CHECK(!cpu.has_ssse3() || cpu.has_sse3());
+ CHECK(!cpu.has_sse41() || cpu.has_sse3());
+ CHECK(!cpu.has_sse42() || cpu.has_sse41());
+
+ // arm features
+ CHECK(!cpu.has_vfp3_d32() || cpu.has_vfp3());
+}
__ or_(edx, 3);
__ xor_(edx, 3);
__ nop();
- {
- CHECK(CpuFeatures::IsSupported(CPUID));
- CpuFeatureScope fscope(&assm, CPUID);
- __ cpuid();
- }
+ __ cpuid();
__ movsx_b(edx, ecx);
__ movsx_w(edx, ecx);
__ movzx_b(edx, ecx);
'../../src/cpu-profiler-inl.h',
'../../src/cpu-profiler.cc',
'../../src/cpu-profiler.h',
+ '../../src/cpu.cc',
'../../src/cpu.h',
'../../src/data-flow.cc',
'../../src/data-flow.h',