Fix the CPU feature detection.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 Aug 2013 09:37:39 +0000 (09:37 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 Aug 2013 09:37:39 +0000 (09:37 +0000)
Move all of the CPU detection logic to the CPU class, and make
all other code use the CPU class for feature detection.

This also fixes the ARM CPU feature detection logic, which was
based on fragile string search in /proc/cpuinfo. Now we use
ELF hwcaps if available, falling back to sane(!!) parsing of
/proc/cpuinfo for CPU features.

The ia32 and x64 code was also cleaned up to make it usable
outside the assembler.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/23401002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16315 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

17 files changed:
src/arm/assembler-arm.cc
src/cpu.cc [new file with mode: 0644]
src/cpu.h
src/ia32/assembler-ia32.cc
src/mips/assembler-mips.cc
src/platform-linux.cc
src/platform-nullos.cc
src/platform-posix.cc
src/platform.h
src/v8globals.h
src/x64/assembler-x64.cc
test/cctest/cctest.gyp
test/cctest/test-cpu-ia32.cc [new file with mode: 0644]
test/cctest/test-cpu-x64.cc [new file with mode: 0644]
test/cctest/test-cpu.cc [new file with mode: 0644]
test/cctest/test-disasm-ia32.cc
tools/gyp/v8.gyp

index a9db5a5..ae6db3a 100644 (file)
@@ -152,7 +152,8 @@ void CpuFeatures::Probe() {
 
 #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.
@@ -161,38 +162,40 @@ void CpuFeatures::Probe() {
         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;
   }
 
diff --git a/src/cpu.cc b/src/cpu.cc
new file mode 100644 (file)
index 0000000..d7c32dd
--- /dev/null
@@ -0,0 +1,446 @@
+// 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
index f8d33e4..ef58b4c 100644 (file)
--- a/src/cpu.h
+++ b/src/cpu.h
@@ -1,4 +1,4 @@
-// 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:
@@ -44,14 +44,61 @@ namespace internal {
 // ----------------------------------------------------------------------------
 // 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();
 
@@ -59,6 +106,34 @@ class CPU : public AllStatic {
 
   // 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
index ab4e0a4..7ff6913 100644 (file)
@@ -101,80 +101,28 @@ void CpuFeatures::Probe() {
     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;
 }
 
 
@@ -474,7 +422,6 @@ void Assembler::CodeTargetAlign() {
 
 
 void Assembler::cpuid() {
-  ASSERT(IsEnabled(CPUID));
   EnsureSpace ensure_space(this);
   EMIT(0x0F);
   EMIT(0xA2);
index 3e02f32..0bb00b4 100644 (file)
@@ -126,7 +126,8 @@ void CpuFeatures::Probe() {
   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;
index 8856833..ef97449 100644 (file)
@@ -80,139 +80,6 @@ static Mutex* limit_mutex = NULL;
 
 
 #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
@@ -255,60 +122,6 @@ bool OS::ArmUsingHardFloat() {
 #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));
index dd5a3dd..dc7adb6 100644 (file)
@@ -215,21 +215,6 @@ double OS::nan_value() {
 }
 
 
-CpuImplementer OS::GetCpuImplementer() {
-  UNIMPLEMENTED();
-}
-
-
-CpuPart OS::GetCpuPart(CpuImplementer implementer) {
-  UNIMPLEMENTED();
-}
-
-
-bool OS::ArmCpuHasFeature(CpuFeature feature) {
-  UNIMPLEMENTED();
-}
-
-
 bool OS::ArmUsingHardFloat() {
   UNIMPLEMENTED();
 }
index f7ab8a1..1244493 100644 (file)
@@ -79,11 +79,11 @@ static const pthread_t kNoThread = (pthread_t) 0;
 
 
 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
index 8b27c19..384ae15 100644 (file)
@@ -365,22 +365,10 @@ class OS {
   // 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();
index f76dcc2..8a1cc17 100644 (file)
@@ -412,33 +412,12 @@ enum StateTag {
 #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
index 68d2c05..f3ce4b9 100644 (file)
@@ -63,98 +63,32 @@ void CpuFeatures::Probe() {
     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;
 }
 
 
@@ -987,7 +921,6 @@ void Assembler::cmpb_al(Immediate imm8) {
 
 
 void Assembler::cpuid() {
-  ASSERT(IsEnabled(CPUID));
   EnsureSpace ensure_space(this);
   emit(0x0F);
   emit(0xA2);
index 9df5c7b..712823e 100644 (file)
@@ -56,6 +56,7 @@
         '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'
           ],
diff --git a/test/cctest/test-cpu-ia32.cc b/test/cctest/test-cpu-ia32.cc
new file mode 100644 (file)
index 0000000..245450b
--- /dev/null
@@ -0,0 +1,40 @@
+// 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());
+}
diff --git a/test/cctest/test-cpu-x64.cc b/test/cctest/test-cpu-x64.cc
new file mode 100644 (file)
index 0000000..a2c45cf
--- /dev/null
@@ -0,0 +1,44 @@
+// 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());
+}
diff --git a/test/cctest/test-cpu.cc b/test/cctest/test-cpu.cc
new file mode 100644 (file)
index 0000000..1c61ab1
--- /dev/null
@@ -0,0 +1,50 @@
+// 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());
+}
index 90469e5..1b6af47 100644 (file)
@@ -99,11 +99,7 @@ TEST(DisasmIa320) {
   __ 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);
index 6b6b115..8be7ded 100644 (file)
         '../../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',