Updates refactoring of CPU feature detection
with fix that uses cpuid for Intel/Linux. R=asiva@google.com Review URL: https://codereview.chromium.org//136303012 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32980 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#if defined(TARGET_ARCH_ARM)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/longjump.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
#include "vm/simulator.h"
|
||||
@@ -22,97 +23,6 @@ namespace dart {
|
||||
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
|
||||
DECLARE_FLAG(bool, inline_alloc);
|
||||
|
||||
bool CPUFeatures::integer_division_supported_ = false;
|
||||
bool CPUFeatures::neon_supported_ = false;
|
||||
#if defined(DEBUG)
|
||||
bool CPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
bool CPUFeatures::integer_division_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return integer_division_supported_;
|
||||
}
|
||||
|
||||
|
||||
bool CPUFeatures::neon_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return neon_supported_;
|
||||
}
|
||||
|
||||
|
||||
// If we are using the simulator, allow tests to enable/disable support for
|
||||
// integer division.
|
||||
#if defined(USING_SIMULATOR)
|
||||
void CPUFeatures::set_integer_division_supported(bool supported) {
|
||||
integer_division_supported_ = supported;
|
||||
}
|
||||
|
||||
|
||||
void CPUFeatures::set_neon_supported(bool supported) {
|
||||
neon_supported_ = supported;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Probe /proc/cpuinfo for features of the ARM processor.
|
||||
#if !defined(USING_SIMULATOR)
|
||||
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")))
|
||||
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
|
||||
|
||||
|
||||
void CPUFeatures::InitOnce() {
|
||||
#if defined(USING_SIMULATOR)
|
||||
integer_division_supported_ = true;
|
||||
neon_supported_ = true;
|
||||
#else
|
||||
ASSERT(CPUInfoContainsString("ARMv7")); // Implements ARMv7.
|
||||
ASSERT(CPUInfoContainsString("vfp")); // Has floating point unit.
|
||||
// Has integer division.
|
||||
if (CPUInfoContainsString("QCT APQ8064")) {
|
||||
// Special case for Qualcomm Krait CPUs in Nexus 4 and 7.
|
||||
integer_division_supported_ = true;
|
||||
} else {
|
||||
integer_division_supported_ = CPUInfoContainsString("idiva");
|
||||
}
|
||||
neon_supported_ = CPUInfoContainsString("neon");
|
||||
#endif // defined(USING_SIMULATOR)
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Instruction encoding bits.
|
||||
enum {
|
||||
@@ -549,7 +459,7 @@ void Assembler::umlal(Register rd_lo, Register rd_hi,
|
||||
|
||||
void Assembler::EmitDivOp(Condition cond, int32_t opcode,
|
||||
Register rd, Register rn, Register rm) {
|
||||
ASSERT(CPUFeatures::integer_division_supported());
|
||||
ASSERT(TargetCPUFeatures::integer_division_supported());
|
||||
ASSERT(rd != kNoRegister);
|
||||
ASSERT(rn != kNoRegister);
|
||||
ASSERT(rm != kNoRegister);
|
||||
@@ -2457,7 +2367,7 @@ void Assembler::TestImmediate(Register rn, int32_t imm, Condition cond) {
|
||||
void Assembler::IntegerDivide(Register result, Register left, Register right,
|
||||
DRegister tmpl, DRegister tmpr) {
|
||||
ASSERT(tmpl != tmpr);
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
sdiv(result, left, right);
|
||||
} else {
|
||||
SRegister stmpl = static_cast<SRegister>(2 * tmpl);
|
||||
|
||||
@@ -63,26 +63,6 @@ class Label : public ValueObject {
|
||||
DISALLOW_COPY_AND_ASSIGN(Label);
|
||||
};
|
||||
|
||||
|
||||
class CPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static bool double_truncate_round_supported() { return false; }
|
||||
static bool integer_division_supported();
|
||||
static bool neon_supported();
|
||||
#if defined(USING_SIMULATOR)
|
||||
static void set_integer_division_supported(bool supported);
|
||||
static void set_neon_supported(bool supported);
|
||||
#endif
|
||||
private:
|
||||
static bool integer_division_supported_;
|
||||
static bool neon_supported_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Encodes Addressing Mode 1 - Data-processing operands.
|
||||
class ShifterOperand : public ValueObject {
|
||||
public:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#if defined(TARGET_ARCH_ARM)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/unit_test.h"
|
||||
#include "vm/virtual_memory.h"
|
||||
@@ -1457,7 +1458,7 @@ ASSEMBLER_TEST_RUN(VstmsVldms_off, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Udiv, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ mov(R1, ShifterOperand(9));
|
||||
__ udiv(R2, R0, R1);
|
||||
@@ -1477,7 +1478,7 @@ ASSEMBLER_TEST_RUN(Udiv, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sdiv, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ LoadImmediate(R1, -9);
|
||||
__ sdiv(R2, R0, R1);
|
||||
@@ -1497,7 +1498,7 @@ ASSEMBLER_TEST_RUN(Sdiv, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Udiv_zero, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ mov(R1, ShifterOperand(0));
|
||||
__ udiv(R2, R0, R1);
|
||||
@@ -1517,7 +1518,7 @@ ASSEMBLER_TEST_RUN(Udiv_zero, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sdiv_zero, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ mov(R1, ShifterOperand(0));
|
||||
__ udiv(R2, R0, R1);
|
||||
@@ -1537,7 +1538,7 @@ ASSEMBLER_TEST_RUN(Sdiv_zero, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Udiv_corner, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ LoadImmediate(R0, 0x80000000);
|
||||
__ LoadImmediate(R1, 0xffffffff);
|
||||
__ udiv(R2, R0, R1);
|
||||
@@ -1557,7 +1558,7 @@ ASSEMBLER_TEST_RUN(Udiv_corner, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sdiv_corner, assembler) {
|
||||
if (CPUFeatures::integer_division_supported()) {
|
||||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
__ LoadImmediate(R0, 0x80000000);
|
||||
__ LoadImmediate(R1, 0xffffffff);
|
||||
__ sdiv(R2, R0, R1);
|
||||
@@ -1579,12 +1580,12 @@ ASSEMBLER_TEST_RUN(Sdiv_corner, test) {
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(IntDiv_supported, assembler) {
|
||||
#if defined(USING_SIMULATOR)
|
||||
bool orig = CPUFeatures::integer_division_supported();
|
||||
CPUFeatures::set_integer_division_supported(true);
|
||||
bool orig = TargetCPUFeatures::integer_division_supported();
|
||||
HostCPUFeatures::set_integer_division_supported(true);
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ mov(R1, ShifterOperand(9));
|
||||
__ IntegerDivide(R0, R0, R1, D0, D1);
|
||||
CPUFeatures::set_integer_division_supported(orig);
|
||||
HostCPUFeatures::set_integer_division_supported(orig);
|
||||
__ bx(LR);
|
||||
#else
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
@@ -1604,12 +1605,12 @@ ASSEMBLER_TEST_RUN(IntDiv_supported, test) {
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(IntDiv_unsupported, assembler) {
|
||||
#if defined(USING_SIMULATOR)
|
||||
bool orig = CPUFeatures::integer_division_supported();
|
||||
CPUFeatures::set_integer_division_supported(false);
|
||||
bool orig = TargetCPUFeatures::integer_division_supported();
|
||||
HostCPUFeatures::set_integer_division_supported(false);
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
__ mov(R1, ShifterOperand(9));
|
||||
__ IntegerDivide(R0, R0, R1, D0, D1);
|
||||
CPUFeatures::set_integer_division_supported(orig);
|
||||
HostCPUFeatures::set_integer_division_supported(orig);
|
||||
__ bx(LR);
|
||||
#else
|
||||
__ mov(R0, ShifterOperand(27));
|
||||
@@ -1644,7 +1645,7 @@ ASSEMBLER_TEST_RUN(Muls, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vaddqi8, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1688,7 +1689,7 @@ ASSEMBLER_TEST_RUN(Vaddqi8, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vaddqi16, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1732,7 +1733,7 @@ ASSEMBLER_TEST_RUN(Vaddqi16, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vaddqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1776,7 +1777,7 @@ ASSEMBLER_TEST_RUN(Vaddqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vaddqi64, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1808,7 +1809,7 @@ ASSEMBLER_TEST_RUN(Vaddqi64, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vsubqi8, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1852,7 +1853,7 @@ ASSEMBLER_TEST_RUN(Vsubqi8, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vsubqi16, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1896,7 +1897,7 @@ ASSEMBLER_TEST_RUN(Vsubqi16, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vsubqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1940,7 +1941,7 @@ ASSEMBLER_TEST_RUN(Vsubqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vsubqi64, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -1972,7 +1973,7 @@ ASSEMBLER_TEST_RUN(Vsubqi64, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmulqi8, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2016,7 +2017,7 @@ ASSEMBLER_TEST_RUN(Vmulqi8, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmulqi16, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2060,7 +2061,7 @@ ASSEMBLER_TEST_RUN(Vmulqi16, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmulqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2104,7 +2105,7 @@ ASSEMBLER_TEST_RUN(Vmulqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vaddqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -2139,7 +2140,7 @@ ASSEMBLER_TEST_RUN(Vaddqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vsubqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -2174,7 +2175,7 @@ ASSEMBLER_TEST_RUN(Vsubqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmulqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -2209,7 +2210,7 @@ ASSEMBLER_TEST_RUN(Vmulqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(VtblX, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Index.
|
||||
__ LoadImmediate(R0, 0x03020100);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2252,7 +2253,7 @@ ASSEMBLER_TEST_RUN(VtblX, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(VtblY, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Index.
|
||||
__ LoadImmediate(R0, 0x07060504);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2295,7 +2296,7 @@ ASSEMBLER_TEST_RUN(VtblY, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(VtblZ, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Index.
|
||||
__ LoadImmediate(R0, 0x0b0a0908);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2338,7 +2339,7 @@ ASSEMBLER_TEST_RUN(VtblZ, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(VtblW, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Index.
|
||||
__ LoadImmediate(R0, 0x0f0e0d0c);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2381,7 +2382,7 @@ ASSEMBLER_TEST_RUN(VtblW, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Veorq, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Q0
|
||||
__ LoadImmediate(R0, 0xaaaaaaab);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2423,7 +2424,7 @@ ASSEMBLER_TEST_RUN(Veorq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vornq, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Q0
|
||||
__ LoadImmediate(R0, 0xfffffff0);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2465,7 +2466,7 @@ ASSEMBLER_TEST_RUN(Vornq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vorrq, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Q0
|
||||
__ LoadImmediate(R0, 0xaaaaaaaa);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2507,7 +2508,7 @@ ASSEMBLER_TEST_RUN(Vorrq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vandq, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Q0
|
||||
__ LoadImmediate(R0, 0xaaaaaaab);
|
||||
__ vmovsr(S0, R0);
|
||||
@@ -2549,7 +2550,7 @@ ASSEMBLER_TEST_RUN(Vandq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmovq, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
// Q0
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ vmovs(S1, S0);
|
||||
@@ -2587,7 +2588,7 @@ ASSEMBLER_TEST_RUN(Vmovq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vdupb, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadImmediate(R0, 0x00000000);
|
||||
__ LoadImmediate(R1, 0x00ff0000);
|
||||
__ vmovsr(S4, R0);
|
||||
@@ -2620,7 +2621,7 @@ ASSEMBLER_TEST_RUN(Vdupb, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vduph, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadImmediate(R0, 0xffff0000);
|
||||
__ LoadImmediate(R1, 0x00000000);
|
||||
__ vmovsr(S4, R0);
|
||||
@@ -2653,7 +2654,7 @@ ASSEMBLER_TEST_RUN(Vduph, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vdupw, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadImmediate(R0, 0x00000000);
|
||||
__ LoadImmediate(R1, 0xffffffff);
|
||||
__ vmovsr(S4, R0);
|
||||
@@ -2686,7 +2687,7 @@ ASSEMBLER_TEST_RUN(Vdupw, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vzipqw, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 0.0);
|
||||
__ LoadSImmediate(S1, 1.0);
|
||||
__ LoadSImmediate(S2, 2.0);
|
||||
@@ -2720,7 +2721,7 @@ ASSEMBLER_TEST_RUN(Vzipqw, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vceqqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2764,7 +2765,7 @@ ASSEMBLER_TEST_RUN(Vceqqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vceqqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -2800,7 +2801,7 @@ ASSEMBLER_TEST_RUN(Vceqqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcgeqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2844,7 +2845,7 @@ ASSEMBLER_TEST_RUN(Vcgeqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcugeqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2888,7 +2889,7 @@ ASSEMBLER_TEST_RUN(Vcugeqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcgeqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -2924,7 +2925,7 @@ ASSEMBLER_TEST_RUN(Vcgeqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcgtqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -2968,7 +2969,7 @@ ASSEMBLER_TEST_RUN(Vcgtqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcugtqi32, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ mov(R0, ShifterOperand(1));
|
||||
__ vmovsr(S0, R0);
|
||||
__ mov(R0, ShifterOperand(2));
|
||||
@@ -3012,7 +3013,7 @@ ASSEMBLER_TEST_RUN(Vcugtqi32, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vcgtqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -3048,7 +3049,7 @@ ASSEMBLER_TEST_RUN(Vcgtqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vminqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -3083,7 +3084,7 @@ ASSEMBLER_TEST_RUN(Vminqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vmaxqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S0, 1.0);
|
||||
__ LoadSImmediate(S1, 2.0);
|
||||
__ LoadSImmediate(S2, 3.0);
|
||||
@@ -3153,7 +3154,7 @@ static float arm_recip_estimate(float a) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vrecpeqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 147.0);
|
||||
__ vmovs(S5, S4);
|
||||
__ vmovs(S6, S4);
|
||||
@@ -3178,7 +3179,7 @@ ASSEMBLER_TEST_RUN(Vrecpeqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vrecpsqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 5.0);
|
||||
__ LoadSImmediate(S5, 2.0);
|
||||
__ LoadSImmediate(S6, 3.0);
|
||||
@@ -3208,7 +3209,7 @@ ASSEMBLER_TEST_RUN(Vrecpsqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Reciprocal, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 147000.0);
|
||||
__ vmovs(S5, S4);
|
||||
__ vmovs(S6, S4);
|
||||
@@ -3290,7 +3291,7 @@ static float arm_reciprocal_sqrt_estimate(float a) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vrsqrteqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 147.0);
|
||||
__ vmovs(S5, S4);
|
||||
__ vmovs(S6, S4);
|
||||
@@ -3315,7 +3316,7 @@ ASSEMBLER_TEST_RUN(Vrsqrteqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vrsqrtsqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 5.0);
|
||||
__ LoadSImmediate(S5, 2.0);
|
||||
__ LoadSImmediate(S6, 3.0);
|
||||
@@ -3345,7 +3346,7 @@ ASSEMBLER_TEST_RUN(Vrsqrtsqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(ReciprocalSqrt, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 147000.0);
|
||||
__ vmovs(S5, S4);
|
||||
__ vmovs(S6, S4);
|
||||
@@ -3380,7 +3381,7 @@ ASSEMBLER_TEST_RUN(ReciprocalSqrt, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(SIMDSqrt, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 147000.0);
|
||||
__ vmovs(S5, S4);
|
||||
__ vmovs(S6, S4);
|
||||
@@ -3425,7 +3426,7 @@ ASSEMBLER_TEST_RUN(SIMDSqrt, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(SIMDSqrt2, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 1.0);
|
||||
__ LoadSImmediate(S5, 4.0);
|
||||
__ LoadSImmediate(S6, 9.0);
|
||||
@@ -3474,7 +3475,7 @@ ASSEMBLER_TEST_RUN(SIMDSqrt2, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(SIMDDiv, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 1.0);
|
||||
__ LoadSImmediate(S5, 4.0);
|
||||
__ LoadSImmediate(S6, 9.0);
|
||||
@@ -3515,7 +3516,7 @@ ASSEMBLER_TEST_RUN(SIMDDiv, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vabsqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 1.0);
|
||||
__ LoadSImmediate(S5, -1.0);
|
||||
__ LoadSImmediate(S6, 1.0);
|
||||
@@ -3544,7 +3545,7 @@ ASSEMBLER_TEST_RUN(Vabsqs, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Vnegqs, assembler) {
|
||||
if (CPUFeatures::neon_supported()) {
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
__ LoadSImmediate(S4, 1.0);
|
||||
__ LoadSImmediate(S5, -2.0);
|
||||
__ LoadSImmediate(S6, 1.0);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/code_generator.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/memory_region.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
@@ -16,62 +17,9 @@
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
|
||||
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
|
||||
DECLARE_FLAG(bool, inline_alloc);
|
||||
|
||||
|
||||
bool CPUFeatures::sse2_supported_ = false;
|
||||
bool CPUFeatures::sse4_1_supported_ = false;
|
||||
#ifdef DEBUG
|
||||
bool CPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
bool CPUFeatures::sse2_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse2_supported_;
|
||||
}
|
||||
|
||||
|
||||
bool CPUFeatures::sse4_1_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse4_1_supported_ && FLAG_use_sse41;
|
||||
}
|
||||
|
||||
|
||||
#define __ assembler.
|
||||
|
||||
void CPUFeatures::InitOnce() {
|
||||
Assembler assembler;
|
||||
__ pushl(EBP);
|
||||
__ pushl(EBX);
|
||||
__ movl(EBP, ESP);
|
||||
// Get feature information in ECX:EDX and return it in EDX:EAX.
|
||||
__ movl(EAX, Immediate(1));
|
||||
__ cpuid();
|
||||
__ movl(EAX, EDX);
|
||||
__ movl(EDX, ECX);
|
||||
__ movl(ESP, EBP);
|
||||
__ popl(EBX);
|
||||
__ popl(EBP);
|
||||
__ ret();
|
||||
|
||||
const Code& code =
|
||||
Code::Handle(Code::FinalizeCode("DetectCPUFeatures", &assembler));
|
||||
Instructions& instructions = Instructions::Handle(code.instructions());
|
||||
typedef uint64_t (*DetectCPUFeatures)();
|
||||
uint64_t features =
|
||||
reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())();
|
||||
sse2_supported_ = (features & kSSE2BitMask) != 0;
|
||||
sse4_1_supported_ = (features & kSSE4_1BitMask) != 0;
|
||||
#ifdef DEBUG
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
class DirectCallRelocation : public AssemblerFixup {
|
||||
public:
|
||||
void Process(const MemoryRegion& region, intptr_t position) {
|
||||
@@ -1222,7 +1170,7 @@ void Assembler::andpd(XmmRegister dst, XmmRegister src) {
|
||||
|
||||
|
||||
void Assembler::pextrd(Register dst, XmmRegister src, const Immediate& imm) {
|
||||
ASSERT(CPUFeatures::sse4_1_supported());
|
||||
ASSERT(TargetCPUFeatures::sse4_1_supported());
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x66);
|
||||
EmitUint8(0x0F);
|
||||
@@ -1235,7 +1183,7 @@ void Assembler::pextrd(Register dst, XmmRegister src, const Immediate& imm) {
|
||||
|
||||
|
||||
void Assembler::pmovsxdq(XmmRegister dst, XmmRegister src) {
|
||||
ASSERT(CPUFeatures::sse4_1_supported());
|
||||
ASSERT(TargetCPUFeatures::sse4_1_supported());
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x66);
|
||||
EmitUint8(0x0F);
|
||||
@@ -1246,7 +1194,7 @@ void Assembler::pmovsxdq(XmmRegister dst, XmmRegister src) {
|
||||
|
||||
|
||||
void Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) {
|
||||
ASSERT(CPUFeatures::sse4_1_supported());
|
||||
ASSERT(TargetCPUFeatures::sse4_1_supported());
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x66);
|
||||
EmitUint8(0x0F);
|
||||
@@ -1266,7 +1214,7 @@ void Assembler::pxor(XmmRegister dst, XmmRegister src) {
|
||||
|
||||
|
||||
void Assembler::roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode) {
|
||||
ASSERT(CPUFeatures::sse4_1_supported());
|
||||
ASSERT(TargetCPUFeatures::sse4_1_supported());
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x66);
|
||||
EmitUint8(0x0F);
|
||||
|
||||
@@ -286,25 +286,6 @@ class Label : public ValueObject {
|
||||
};
|
||||
|
||||
|
||||
class CPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static bool sse2_supported();
|
||||
static bool sse4_1_supported();
|
||||
static bool double_truncate_round_supported() { return sse4_1_supported(); }
|
||||
|
||||
private:
|
||||
static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
|
||||
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
|
||||
|
||||
static bool sse2_supported_;
|
||||
static bool sse4_1_supported_;
|
||||
#ifdef DEBUG
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Assembler : public ValueObject {
|
||||
public:
|
||||
explicit Assembler(bool use_far_branches = false)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/unit_test.h"
|
||||
#include "vm/virtual_memory.h"
|
||||
@@ -2808,7 +2809,7 @@ ASSEMBLER_TEST_RUN(Orpd, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Pextrd0, assembler) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
__ movsd(XMM0, Address(ESP, kWordSize));
|
||||
__ pextrd(EAX, XMM0, Immediate(0));
|
||||
}
|
||||
@@ -2817,7 +2818,7 @@ ASSEMBLER_TEST_GENERATE(Pextrd0, assembler) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Pextrd0, test) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
typedef int32_t (*PextrdCode0)(double d);
|
||||
int32_t res = reinterpret_cast<PextrdCode0>(test->entry())(123456789);
|
||||
EXPECT_EQ(0x54000000, res);
|
||||
@@ -2826,7 +2827,7 @@ ASSEMBLER_TEST_RUN(Pextrd0, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Pextrd1, assembler) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
__ movsd(XMM0, Address(ESP, kWordSize));
|
||||
__ pextrd(EAX, XMM0, Immediate(1));
|
||||
}
|
||||
@@ -2835,7 +2836,7 @@ ASSEMBLER_TEST_GENERATE(Pextrd1, assembler) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Pextrd1, test) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
typedef int32_t (*PextrdCode1)(double d);
|
||||
int32_t res = reinterpret_cast<PextrdCode1>(test->entry())(123456789);
|
||||
EXPECT_EQ(0x419d6f34, res);
|
||||
@@ -2844,7 +2845,7 @@ ASSEMBLER_TEST_RUN(Pextrd1, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Pmovsxdq, assembler) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
__ movsd(XMM0, Address(ESP, kWordSize));
|
||||
__ pmovsxdq(XMM0, XMM0);
|
||||
__ pextrd(EAX, XMM0, Immediate(1));
|
||||
@@ -2854,7 +2855,7 @@ ASSEMBLER_TEST_GENERATE(Pmovsxdq, assembler) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Pmovsxdq, test) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
typedef int32_t (*PmovsxdqCode)(double d);
|
||||
int32_t res = reinterpret_cast<PmovsxdqCode>(test->entry())(123456789);
|
||||
EXPECT_EQ(0, res);
|
||||
@@ -2863,7 +2864,7 @@ ASSEMBLER_TEST_RUN(Pmovsxdq, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Pcmpeqq, assembler) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
__ movsd(XMM0, Address(ESP, kWordSize));
|
||||
__ xorpd(XMM1, XMM1);
|
||||
__ pcmpeqq(XMM0, XMM1);
|
||||
@@ -2874,7 +2875,7 @@ ASSEMBLER_TEST_GENERATE(Pcmpeqq, assembler) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Pcmpeqq, test) {
|
||||
if (CPUFeatures::sse4_1_supported()) {
|
||||
if (TargetCPUFeatures::sse4_1_supported()) {
|
||||
typedef int32_t (*PcmpeqqCode)(double d);
|
||||
int32_t res = reinterpret_cast<PcmpeqqCode>(test->entry())(0);
|
||||
EXPECT_EQ(-1, res);
|
||||
|
||||
@@ -135,15 +135,6 @@ class Label : public ValueObject {
|
||||
};
|
||||
|
||||
|
||||
class CPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() { }
|
||||
static bool double_truncate_round_supported() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Assembler : public ValueObject {
|
||||
public:
|
||||
explicit Assembler(bool use_far_branches = false)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#if defined(TARGET_ARCH_MIPS)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/unit_test.h"
|
||||
#include "vm/virtual_memory.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/memory_region.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
@@ -15,56 +16,9 @@
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
|
||||
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
|
||||
DECLARE_FLAG(bool, inline_alloc);
|
||||
|
||||
|
||||
bool CPUFeatures::sse4_1_supported_ = false;
|
||||
#ifdef DEBUG
|
||||
bool CPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
bool CPUFeatures::sse4_1_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse4_1_supported_ && FLAG_use_sse41;
|
||||
}
|
||||
|
||||
|
||||
#define __ assembler.
|
||||
|
||||
void CPUFeatures::InitOnce() {
|
||||
Assembler assembler;
|
||||
__ pushq(RBP);
|
||||
__ pushq(RBX);
|
||||
__ movq(RBP, RSP);
|
||||
// Get feature information in ECX:EDX and return it in RAX.
|
||||
// Note that cpuid operates the same in 64-bit and 32-bit mode.
|
||||
__ movq(RAX, Immediate(1));
|
||||
__ cpuid();
|
||||
__ movl(RAX, RCX); // Zero extended.
|
||||
__ shlq(RAX, Immediate(32));
|
||||
__ movl(RCX, RDX); // Zero extended.
|
||||
__ orq(RAX, RCX);
|
||||
__ movq(RSP, RBP);
|
||||
__ popq(RBX);
|
||||
__ popq(RBP);
|
||||
__ ret();
|
||||
|
||||
const Code& code =
|
||||
Code::Handle(Code::FinalizeCode("DetectCPUFeatures", &assembler));
|
||||
Instructions& instructions = Instructions::Handle(code.instructions());
|
||||
typedef uint64_t (*DetectCPUFeatures)();
|
||||
uint64_t features =
|
||||
reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())();
|
||||
sse4_1_supported_ = (features & kSSE4_1BitMask) != 0;
|
||||
#ifdef DEBUG
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
Assembler::Assembler(bool use_far_branches)
|
||||
: buffer_(),
|
||||
object_pool_(GrowableObjectArray::Handle()),
|
||||
|
||||
@@ -317,24 +317,6 @@ class Label : public ValueObject {
|
||||
};
|
||||
|
||||
|
||||
class CPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
// x64 always has at least SSE2.
|
||||
static bool sse2_supported() { return true; }
|
||||
static bool sse4_1_supported();
|
||||
static bool double_truncate_round_supported() { return sse4_1_supported(); }
|
||||
|
||||
private:
|
||||
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
|
||||
|
||||
static bool sse4_1_supported_;
|
||||
#ifdef DEBUG
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Assembler : public ValueObject {
|
||||
public:
|
||||
explicit Assembler(bool use_far_branches = false);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef VM_CPU_H_
|
||||
#define VM_CPU_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#include "vm/allocation.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -22,4 +23,16 @@ class CPU : public AllStatic {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
#include "vm/cpu_ia32.h"
|
||||
#elif defined(TARGET_ARCH_X64)
|
||||
#include "vm/cpu_x64.h"
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#include "vm/cpu_arm.h"
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
#include "vm/cpu_mips.h"
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
||||
#endif // VM_CPU_H_
|
||||
|
||||
+73
-2
@@ -6,13 +6,15 @@
|
||||
|
||||
#if defined(TARGET_ARCH_ARM)
|
||||
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
#if defined(HOST_ARCH_ARM)
|
||||
#include <sys/syscall.h> /* NOLINT */
|
||||
#include <unistd.h> /* NOLINT */
|
||||
#endif
|
||||
|
||||
#include "vm/cpu.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
void CPU::FlushICache(uword start, uword size) {
|
||||
@@ -48,6 +50,75 @@ const char* CPU::Id() {
|
||||
"arm";
|
||||
}
|
||||
|
||||
|
||||
bool HostCPUFeatures::integer_division_supported_ = false;
|
||||
bool HostCPUFeatures::neon_supported_ = false;
|
||||
const char* HostCPUFeatures::hardware_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
bool HostCPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HOST_ARCH_ARM)
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
// Implements ARMv7.
|
||||
ASSERT(CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv7"));
|
||||
// Has floating point unit.
|
||||
ASSERT(CpuInfo::FieldContains(kCpuInfoFeatures, "vfp"));
|
||||
// Has integer division.
|
||||
bool is_krait = CpuInfo::FieldContains(kCpuInfoModel, "QCT APQ8064");
|
||||
if (is_krait) {
|
||||
// Special case for Qualcomm Krait CPUs in Nexus 4 and 7.
|
||||
integer_division_supported_ = true;
|
||||
} else {
|
||||
integer_division_supported_ =
|
||||
CpuInfo::FieldContains(kCpuInfoFeatures, "idiva");
|
||||
}
|
||||
neon_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "neon");
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
integer_division_supported_ = true;
|
||||
neon_supported_ = true;
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
#endif // defined(HOST_ARCH_ARM)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_ARM
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPU_ARM_H_
|
||||
#define VM_CPU_ARM_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// TargetCPUFeatures gives CPU features for the architecture that we are
|
||||
// generating code for. HostCPUFeatures gives the CPU features for the
|
||||
// architecture that we are actually running on. When the architectures
|
||||
// are the same, TargetCPUFeatures will query HostCPUFeatures. When they are
|
||||
// different (i.e. we are running in a simulator), HostCPUFeatures will
|
||||
// additionally mock the options needed for the target architecture so that
|
||||
// they may be altered for testing.
|
||||
|
||||
class HostCPUFeatures: public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static const char* hardware() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return hardware_;
|
||||
}
|
||||
static bool integer_division_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return integer_division_supported_;
|
||||
}
|
||||
static bool neon_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return neon_supported_;
|
||||
}
|
||||
|
||||
#if !defined(HOST_ARCH_ARM)
|
||||
static void set_integer_division_supported(bool supported) {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
integer_division_supported_ = supported;
|
||||
}
|
||||
static void set_neon_supported(bool supported) {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
neon_supported_ = supported;
|
||||
}
|
||||
#endif // !defined(HOST_ARCH_ARM)
|
||||
|
||||
private:
|
||||
static const char* hardware_;
|
||||
static bool integer_division_supported_;
|
||||
static bool neon_supported_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TargetCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() {
|
||||
HostCPUFeatures::InitOnce();
|
||||
}
|
||||
static void Cleanup() {
|
||||
HostCPUFeatures::Cleanup();
|
||||
}
|
||||
static bool double_truncate_round_supported() {
|
||||
return false;
|
||||
}
|
||||
static bool integer_division_supported() {
|
||||
return HostCPUFeatures::integer_division_supported();
|
||||
}
|
||||
static bool neon_supported() {
|
||||
return HostCPUFeatures::neon_supported();
|
||||
}
|
||||
static const char* hardware() {
|
||||
return HostCPUFeatures::hardware();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPU_ARM_H_
|
||||
+39
-1
@@ -3,18 +3,22 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
|
||||
#include "vm/cpu.h"
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/constants_ia32.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/thread.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
|
||||
|
||||
void CPU::FlushICache(uword start, uword size) {
|
||||
// Nothing to be done here.
|
||||
}
|
||||
@@ -24,6 +28,40 @@ const char* CPU::Id() {
|
||||
return "ia32";
|
||||
}
|
||||
|
||||
|
||||
bool HostCPUFeatures::sse2_supported_ = false;
|
||||
bool HostCPUFeatures::sse4_1_supported_ = false;
|
||||
const char* HostCPUFeatures::hardware_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
bool HostCPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
sse2_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "sse2");
|
||||
sse4_1_supported_ =
|
||||
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4_1") ||
|
||||
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4.1");
|
||||
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_IA32
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPU_IA32_H_
|
||||
#define VM_CPU_IA32_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/flags.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DECLARE_FLAG(bool, use_sse41);
|
||||
|
||||
class HostCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static const char* hardware() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return hardware_;
|
||||
}
|
||||
static bool sse2_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse2_supported_;
|
||||
}
|
||||
static bool sse4_1_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse4_1_supported_ && FLAG_use_sse41;
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
|
||||
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
|
||||
static const char* hardware_;
|
||||
static bool sse2_supported_;
|
||||
static bool sse4_1_supported_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TargetCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() {
|
||||
HostCPUFeatures::InitOnce();
|
||||
}
|
||||
static void Cleanup() {
|
||||
HostCPUFeatures::Cleanup();
|
||||
}
|
||||
static const char* hardware() {
|
||||
return HostCPUFeatures::hardware();
|
||||
}
|
||||
static bool sse2_supported() {
|
||||
return HostCPUFeatures::sse2_supported();
|
||||
}
|
||||
static bool sse4_1_supported() {
|
||||
return HostCPUFeatures::sse4_1_supported();
|
||||
}
|
||||
static bool double_truncate_round_supported() {
|
||||
return sse4_1_supported();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPU_IA32_H_
|
||||
+57
-2
@@ -6,14 +6,16 @@
|
||||
|
||||
#if defined(TARGET_ARCH_MIPS)
|
||||
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/simulator.h"
|
||||
|
||||
#if defined(HOST_ARCH_MIPS)
|
||||
#include <asm/cachectl.h> /* NOLINT */
|
||||
#include <sys/syscall.h> /* NOLINT */
|
||||
#include <unistd.h> /* NOLINT */
|
||||
#endif
|
||||
|
||||
#include "vm/cpu.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
void CPU::FlushICache(uword start, uword size) {
|
||||
@@ -37,6 +39,59 @@ const char* CPU::Id() {
|
||||
"mips";
|
||||
}
|
||||
|
||||
|
||||
const char* HostCPUFeatures::hardware_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
bool HostCPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HOST_ARCH_MIPS)
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
// Has a floating point unit.
|
||||
ASSERT(CpuInfo::FieldContains(kCpuInfoModel, "FPU"));
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
#endif // defined(HOST_ARCH_MIPS)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_MIPS
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPU_MIPS_H_
|
||||
#define VM_CPU_MIPS_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// TargetCPUFeatures gives CPU features for the architecture that we are
|
||||
// generating code for. HostCPUFeatures gives the CPU features for the
|
||||
// architecture that we are actually running on. When the architectures
|
||||
// are the same, TargetCPUFeatures will query HostCPUFeatures. When they are
|
||||
// different (i.e. we are running in a simulator), HostCPUFeatures will
|
||||
// additionally mock the options needed for the target architecture so that
|
||||
// they may be altered for testing.
|
||||
|
||||
class HostCPUFeatures: public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static const char* hardware() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return hardware_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* hardware_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TargetCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() {
|
||||
HostCPUFeatures::InitOnce();
|
||||
}
|
||||
static void Cleanup() {
|
||||
HostCPUFeatures::Cleanup();
|
||||
}
|
||||
static const char* hardware() {
|
||||
return HostCPUFeatures::hardware();
|
||||
}
|
||||
static bool double_truncate_round_supported() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPU_MIPS_H_
|
||||
@@ -8,13 +8,18 @@
|
||||
|
||||
#include "vm/cpu.h"
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/constants_x64.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
|
||||
|
||||
|
||||
void CPU::FlushICache(uword start, uword size) {
|
||||
// Nothing to be done here.
|
||||
}
|
||||
@@ -24,6 +29,38 @@ const char* CPU::Id() {
|
||||
return "x64";
|
||||
}
|
||||
|
||||
|
||||
bool HostCPUFeatures::sse2_supported_ = true;
|
||||
bool HostCPUFeatures::sse4_1_supported_ = false;
|
||||
const char* HostCPUFeatures::hardware_ = NULL;
|
||||
#if defined(DEBUG)
|
||||
bool HostCPUFeatures::initialized_ = false;
|
||||
#endif
|
||||
|
||||
void HostCPUFeatures::InitOnce() {
|
||||
CpuInfo::InitOnce();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
sse4_1_supported_ =
|
||||
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4_1") ||
|
||||
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4.1");
|
||||
|
||||
#if defined(DEBUG)
|
||||
initialized_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HostCPUFeatures::Cleanup() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
#if defined(DEBUG)
|
||||
initialized_ = false;
|
||||
#endif
|
||||
ASSERT(hardware_ != NULL);
|
||||
delete[] hardware_;
|
||||
hardware_ = NULL;
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_X64
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPU_X64_H_
|
||||
#define VM_CPU_X64_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/flags.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DECLARE_FLAG(bool, use_sse41);
|
||||
|
||||
class HostCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static const char* hardware() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return hardware_;
|
||||
}
|
||||
static bool sse2_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse2_supported_;
|
||||
}
|
||||
static bool sse4_1_supported() {
|
||||
DEBUG_ASSERT(initialized_);
|
||||
return sse4_1_supported_ && FLAG_use_sse41;
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
|
||||
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
|
||||
static const char* hardware_;
|
||||
static bool sse2_supported_;
|
||||
static bool sse4_1_supported_;
|
||||
#if defined(DEBUG)
|
||||
static bool initialized_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TargetCPUFeatures : public AllStatic {
|
||||
public:
|
||||
static void InitOnce() {
|
||||
HostCPUFeatures::InitOnce();
|
||||
}
|
||||
static void Cleanup() {
|
||||
HostCPUFeatures::Cleanup();
|
||||
}
|
||||
static const char* hardware() {
|
||||
return HostCPUFeatures::hardware();
|
||||
}
|
||||
static bool sse2_supported() {
|
||||
return HostCPUFeatures::sse2_supported();
|
||||
}
|
||||
static bool sse4_1_supported() {
|
||||
return HostCPUFeatures::sse4_1_supported();
|
||||
}
|
||||
static bool double_truncate_round_supported() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPU_X64_H_
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(TARGET_OS_MACOS)
|
||||
#include "vm/cpuid.h"
|
||||
|
||||
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
|
||||
// GetCpuId() on Windows, __get_cpuid() on Linux
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
#include <intrin.h> // NOLINT
|
||||
#else
|
||||
#include <cpuid.h> // NOLINT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
bool CpuId::sse2_ = false;
|
||||
bool CpuId::sse41_ = false;
|
||||
const char* CpuId::id_string_ = NULL;
|
||||
const char* CpuId::brand_string_ = NULL;
|
||||
|
||||
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
|
||||
|
||||
void CpuId::GetCpuId(int32_t level, uint32_t info[4]) {
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
// The documentation for __cpuid is at:
|
||||
// http://msdn.microsoft.com/en-us/library/hskdteyh(v=vs.90).aspx
|
||||
__cpuid(reinterpret_cast<int*>(info), level);
|
||||
#else
|
||||
__get_cpuid(level, &info[0], &info[1], &info[2], &info[3]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CpuId::InitOnce() {
|
||||
uint32_t info[4] = {-1};
|
||||
|
||||
GetCpuId(0, info);
|
||||
char* id_string = new char[3 * sizeof(int32_t)];
|
||||
// Yes, these are supposed to be out of order.
|
||||
*reinterpret_cast<uint32_t*>(id_string) = info[1];
|
||||
*reinterpret_cast<uint32_t*>(id_string + 4) = info[3];
|
||||
*reinterpret_cast<uint32_t*>(id_string + 8) = info[2];
|
||||
CpuId::id_string_ = id_string;
|
||||
|
||||
GetCpuId(1, info);
|
||||
CpuId::sse41_ = (info[2] & (1 << 19)) != 0;
|
||||
CpuId::sse2_ = (info[3] & (1 << 26)) != 0;
|
||||
|
||||
char* brand_string = new char[3 * 4 * sizeof(uint32_t)];
|
||||
for (uint32_t i = 0x80000002; i <= 0x80000004; i++) {
|
||||
uint32_t off = (i - 0x80000002U) * 4 * sizeof(uint32_t);
|
||||
GetCpuId(i, info);
|
||||
*reinterpret_cast<int32_t*>(brand_string + off) = info[0];
|
||||
*reinterpret_cast<int32_t*>(brand_string + off + 4) = info[1];
|
||||
*reinterpret_cast<int32_t*>(brand_string + off + 8) = info[2];
|
||||
*reinterpret_cast<int32_t*>(brand_string + off + 12) = info[3];
|
||||
}
|
||||
CpuId::brand_string_ = brand_string;
|
||||
}
|
||||
|
||||
|
||||
void CpuId::Cleanup() {
|
||||
ASSERT(id_string_ != NULL);
|
||||
delete[] id_string_;
|
||||
id_string_ = NULL;
|
||||
|
||||
ASSERT(brand_string_ != NULL);
|
||||
delete[] brand_string_;
|
||||
brand_string_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
const char* CpuId::id_string() {
|
||||
return strdup(id_string_);
|
||||
}
|
||||
|
||||
|
||||
const char* CpuId::brand_string() {
|
||||
return strdup(brand_string_);
|
||||
}
|
||||
|
||||
|
||||
const char* CpuId::field(CpuInfoIndices idx) {
|
||||
switch (idx) {
|
||||
case kCpuInfoProcessor:
|
||||
return id_string();
|
||||
case kCpuInfoModel:
|
||||
return brand_string();
|
||||
case kCpuInfoHardware:
|
||||
return brand_string();
|
||||
case kCpuInfoFeatures: {
|
||||
if (sse2() && sse41()) {
|
||||
return strdup("sse2 sse4.1");
|
||||
} else if (sse2()) {
|
||||
return strdup("sse2");
|
||||
} else if (sse41()) {
|
||||
return strdup("sse4.1");
|
||||
} else {
|
||||
return strdup("");
|
||||
}
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_OS_MACOS)
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPUID_H_
|
||||
#define VM_CPUID_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(TARGET_OS_MACOS)
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class CpuId : public AllStatic {
|
||||
public:
|
||||
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
|
||||
// Caller must free the result of field.
|
||||
static const char* field(CpuInfoIndices idx);
|
||||
#else
|
||||
static void InitOnce() {}
|
||||
static void Cleanup() {}
|
||||
static const char* field(CpuInfoIndices idx) { return NULL; }
|
||||
#endif
|
||||
|
||||
static bool sse2() { return sse2_; }
|
||||
static bool sse41() { return sse41_; }
|
||||
|
||||
// Caller must free the result of id_string and brand_string.
|
||||
static const char* id_string();
|
||||
static const char* brand_string();
|
||||
|
||||
private:
|
||||
static bool sse2_;
|
||||
static bool sse41_;
|
||||
static const char* id_string_;
|
||||
static const char* brand_string_;
|
||||
|
||||
static void GetCpuId(int32_t level, uint32_t info[4]);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(TARGET_OS_MACOS)
|
||||
#endif // VM_CPUID_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_CPUINFO_H_
|
||||
#define VM_CPUINFO_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/allocation.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Indices into cpuinfo field name arrays.
|
||||
enum CpuInfoIndices {
|
||||
kCpuInfoProcessor = 0,
|
||||
kCpuInfoModel = 1,
|
||||
kCpuInfoHardware = 2,
|
||||
kCpuInfoFeatures = 3,
|
||||
kCpuInfoMax = 4,
|
||||
};
|
||||
|
||||
// For Intel architectures, the method to use to get CPU information.
|
||||
enum CpuInfoMethod {
|
||||
// Use the cpuid instruction.
|
||||
kCpuInfoCpuId,
|
||||
|
||||
// Use system calls.
|
||||
kCpuInfoSystem,
|
||||
|
||||
// Use whatever the default is for a particular OS:
|
||||
// Linux, Windows -> CpuId,
|
||||
// Android, MacOS -> System.
|
||||
kCpuInfoDefault,
|
||||
};
|
||||
|
||||
class CpuInfo : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
|
||||
static const char* FieldName(CpuInfoIndices idx) {
|
||||
ASSERT((idx >= 0) && (idx < kCpuInfoMax));
|
||||
return fields_[idx];
|
||||
}
|
||||
|
||||
// Returns true if the cpuinfo field contains the string.
|
||||
static bool FieldContains(CpuInfoIndices idx, const char* search_string);
|
||||
static bool FieldContainsByString(
|
||||
const char* field, const char* search_string);
|
||||
|
||||
// Returns true if the cpuinfo field [field] exists and is non-empty.
|
||||
static bool HasField(const char* field);
|
||||
|
||||
// Returns the field. Caller is responsible for freeing the result.
|
||||
static const char* ExtractField(CpuInfoIndices idx);
|
||||
static const char* ExtractFieldByString(const char* field);
|
||||
|
||||
// Returns the field describing the CPU model. Caller is responsible for
|
||||
// freeing the result.
|
||||
static const char* GetCpuModel() {
|
||||
ASSERT(HasField(FieldName(kCpuInfoModel)));
|
||||
return ExtractField(kCpuInfoModel);
|
||||
}
|
||||
|
||||
private:
|
||||
// The method to use to acquire info about the CPU.
|
||||
static CpuInfoMethod method_;
|
||||
|
||||
// Cpuinfo field names.
|
||||
static const char* fields_[kCpuInfoMax];
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_CPUINFO_H_
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_ANDROID)
|
||||
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/proccpuinfo.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
CpuInfoMethod CpuInfo::method_ = kCpuInfoDefault;
|
||||
const char* CpuInfo::fields_[kCpuInfoMax] = {0};
|
||||
|
||||
void CpuInfo::InitOnce() {
|
||||
// Initialize our read from /proc/cpuinfo.
|
||||
method_ = kCpuInfoSystem;
|
||||
ProcCpuInfo::InitOnce();
|
||||
|
||||
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
|
||||
fields_[kCpuInfoProcessor] = "vendor_id";
|
||||
fields_[kCpuInfoModel] = "model name";
|
||||
fields_[kCpuInfoHardware] = "model name";
|
||||
fields_[kCpuInfoFeatures] = "flags";
|
||||
#elif defined(HOST_ARCH_ARM)
|
||||
fields_[kCpuInfoProcessor] = "Processor";
|
||||
fields_[kCpuInfoModel] = "Hardware";
|
||||
fields_[kCpuInfoHardware] = "Hardware";
|
||||
fields_[kCpuInfoFeatures] = "Features";
|
||||
#elif defined(HOST_ARCH_MIPS)
|
||||
fields_[kCpuInfoProcessor] = "system type";
|
||||
fields_[kCpuInfoModel] = "cpu model";
|
||||
fields_[kCpuInfoHardware] = "cpu model";
|
||||
fields_[kCpuInfoFeatures] = "ASEs implemented";
|
||||
#else
|
||||
#error Unrecognized target architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CpuInfo::Cleanup() {
|
||||
ProcCpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ProcCpuInfo::FieldContains(FieldName(idx), search_string);
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContainsByString(const char* field,
|
||||
const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ProcCpuInfo::FieldContains(field, search_string);
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ProcCpuInfo::ExtractField(FieldName(idx));
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractFieldByString(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ProcCpuInfo::ExtractField(field);
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::HasField(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ProcCpuInfo::HasField(field);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_ANDROID)
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_LINUX)
|
||||
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/cpuid.h"
|
||||
#include "vm/proccpuinfo.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
// As with Windows, on IA32 and X64, we use the cpuid instruction.
|
||||
// The analogous instruction is privileged on ARM and MIPS, so we resort to
|
||||
// reading from /proc/cpuinfo.
|
||||
|
||||
namespace dart {
|
||||
|
||||
CpuInfoMethod CpuInfo::method_ = kCpuInfoDefault;
|
||||
const char* CpuInfo::fields_[kCpuInfoMax] = {0};
|
||||
|
||||
void CpuInfo::InitOnce() {
|
||||
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
|
||||
fields_[kCpuInfoProcessor] = "vendor_id";
|
||||
fields_[kCpuInfoModel] = "model name";
|
||||
fields_[kCpuInfoHardware] = "model name";
|
||||
fields_[kCpuInfoFeatures] = "flags";
|
||||
method_ = kCpuInfoCpuId;
|
||||
CpuId::InitOnce();
|
||||
#elif defined(HOST_ARCH_ARM)
|
||||
fields_[kCpuInfoProcessor] = "Processor";
|
||||
fields_[kCpuInfoModel] = "model name";
|
||||
fields_[kCpuInfoHardware] = "Hardware";
|
||||
fields_[kCpuInfoFeatures] = "Features";
|
||||
method_ = kCpuInfoSystem;
|
||||
ProcCpuInfo::InitOnce();
|
||||
#elif defined(HOST_ARCH_MIPS)
|
||||
fields_[kCpuInfoProcessor] = "system type";
|
||||
fields_[kCpuInfoModel] = "cpu model";
|
||||
fields_[kCpuInfoHardware] = "cpu model";
|
||||
fields_[kCpuInfoFeatures] = "ASEs implemented";
|
||||
method_ = kCpuInfoSystem;
|
||||
ProcCpuInfo::InitOnce();
|
||||
#else
|
||||
#error Unrecognized target architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CpuInfo::Cleanup() {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
CpuId::Cleanup();
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
ProcCpuInfo::Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
return strstr(CpuId::field(idx), search_string);
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
return ProcCpuInfo::FieldContains(FieldName(idx), search_string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContainsByString(const char* field,
|
||||
const char* search_string) {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
for (int i = 0; i < kCpuInfoMax; i++) {
|
||||
if (strcmp(field, fields_[i]) == 0) {
|
||||
return FieldContains(static_cast<CpuInfoIndices>(i), search_string);
|
||||
}
|
||||
}
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
return ProcCpuInfo::FieldContains(field, search_string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
return CpuId::field(idx);
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
return ProcCpuInfo::ExtractField(FieldName(idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractFieldByString(const char* field) {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
for (int i = 0; i < kCpuInfoMax; i++) {
|
||||
if (strcmp(field, fields_[i]) == 0) {
|
||||
return ExtractField(static_cast<CpuInfoIndices>(i));
|
||||
}
|
||||
}
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
return ProcCpuInfo::ExtractField(field);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::HasField(const char* field) {
|
||||
if (method_ == kCpuInfoCpuId) {
|
||||
return (strcmp(field, fields_[kCpuInfoProcessor]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoModel]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoHardware]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoFeatures]) == 0);
|
||||
} else {
|
||||
ASSERT(method_ == kCpuInfoSystem);
|
||||
return ProcCpuInfo::HasField(field);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_LINUX)
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_MACOS)
|
||||
|
||||
#include "vm/cpuinfo.h"
|
||||
|
||||
#include <errno.h> // NOLINT
|
||||
#include <sys/types.h> // NOLINT
|
||||
#include <sys/sysctl.h> // NOLINT
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
CpuInfoMethod CpuInfo::method_ = kCpuInfoDefault;
|
||||
const char* CpuInfo::fields_[kCpuInfoMax] = {0};
|
||||
|
||||
void CpuInfo::InitOnce() {
|
||||
method_ = kCpuInfoSystem;
|
||||
|
||||
fields_[kCpuInfoProcessor] = "machdep.cpu.vendor";
|
||||
fields_[kCpuInfoModel] = "machdep.cpu.brand_string";
|
||||
fields_[kCpuInfoHardware] = "machdep.cpu.brand_string";
|
||||
fields_[kCpuInfoFeatures] = "machdep.cpu.features";
|
||||
}
|
||||
|
||||
|
||||
void CpuInfo::Cleanup() {}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContainsByString(const char* field,
|
||||
const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
ASSERT(search_string != NULL);
|
||||
char dest[1024];
|
||||
size_t dest_len = 1024;
|
||||
|
||||
ASSERT(HasField(field));
|
||||
if (sysctlbyname(field, dest, &dest_len, NULL, 0) != 0) {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
return (strcasestr(dest, search_string) != NULL);
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return FieldContainsByString(FieldName(idx), search_string);
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractFieldByString(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
ASSERT(field != NULL);
|
||||
size_t result_len;
|
||||
|
||||
ASSERT(HasField(field));
|
||||
if (sysctlbyname(field, NULL, &result_len, NULL, 0) != 0) {
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* result = new char[result_len];
|
||||
if (sysctlbyname(field, result, &result_len, NULL, 0) != 0) {
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return ExtractFieldByString(FieldName(idx));
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::HasField(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
ASSERT(field != NULL);
|
||||
int ret = sysctlbyname(field, NULL, NULL, NULL, 0);
|
||||
return (ret != ENOENT);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_MACOS)
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
UNIT_TEST_CASE(GetCpuModelTest) {
|
||||
CpuInfo::InitOnce();
|
||||
const char* cpumodel = CpuInfo::GetCpuModel();
|
||||
EXPECT_NE(strlen(cpumodel), 0UL);
|
||||
CpuInfo::Cleanup();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
|
||||
#include "vm/cpuinfo.h"
|
||||
#include "vm/cpuid.h"
|
||||
|
||||
// __cpuid()
|
||||
#include <intrin.h> // NOLINT
|
||||
#include <string.h> // NOLINT
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
CpuInfoMethod CpuInfo::method_ = kCpuInfoDefault;
|
||||
const char* CpuInfo::fields_[kCpuInfoMax] = {0};
|
||||
|
||||
void CpuInfo::InitOnce() {
|
||||
method_ = kCpuInfoCpuId;
|
||||
|
||||
// Initialize the CpuId information.
|
||||
CpuId::InitOnce();
|
||||
|
||||
fields_[kCpuInfoProcessor] = "Processor";
|
||||
fields_[kCpuInfoModel] = "Hardware";
|
||||
fields_[kCpuInfoHardware] = "Hardware";
|
||||
fields_[kCpuInfoFeatures] = "Features";
|
||||
}
|
||||
|
||||
|
||||
void CpuInfo::Cleanup() {
|
||||
CpuId::Cleanup();
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return strstr(CpuId::field(idx), search_string);
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::FieldContainsByString(const char* field,
|
||||
const char* search_string) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
for (int i = 0; i < kCpuInfoMax; i++) {
|
||||
if (strcmp(field, fields_[i]) == 0) {
|
||||
return FieldContains(static_cast<CpuInfoIndices>(i), search_string);
|
||||
}
|
||||
}
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return CpuId::field(idx);
|
||||
}
|
||||
|
||||
|
||||
const char* CpuInfo::ExtractFieldByString(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
for (int i = 0; i < kCpuInfoMax; i++) {
|
||||
if (strcmp(field, fields_[i]) == 0) {
|
||||
return ExtractField(static_cast<CpuInfoIndices>(i));
|
||||
}
|
||||
}
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool CpuInfo::HasField(const char* field) {
|
||||
ASSERT(method_ != kCpuInfoDefault);
|
||||
return (strcmp(field, fields_[kCpuInfoProcessor]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoModel]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoHardware]) == 0) ||
|
||||
(strcmp(field, fields_[kCpuInfoFeatures]) == 0);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_WINDOWS)
|
||||
+4
-2
@@ -5,6 +5,7 @@
|
||||
#include "vm/dart.h"
|
||||
|
||||
#include "vm/code_observers.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_api_state.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/flags.h"
|
||||
@@ -123,10 +124,10 @@ const char* Dart::InitOnce(Dart_IsolateCreateCallback create,
|
||||
Symbols::InitOnce(vm_isolate_);
|
||||
Scanner::InitOnce();
|
||||
Object::CreateInternalMetaData();
|
||||
CPUFeatures::InitOnce();
|
||||
TargetCPUFeatures::InitOnce();
|
||||
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
|
||||
// Dart VM requires at least SSE2.
|
||||
if (!CPUFeatures::sse2_supported()) {
|
||||
if (!TargetCPUFeatures::sse2_supported()) {
|
||||
return "SSE2 is required.";
|
||||
}
|
||||
#endif
|
||||
@@ -178,6 +179,7 @@ const char* Dart::Cleanup() {
|
||||
|
||||
Profiler::Shutdown();
|
||||
CodeObservers::DeleteAll();
|
||||
TargetCPUFeatures::Cleanup();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "vm/ast_printer.h"
|
||||
#include "vm/compiler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/deopt_instructions.h"
|
||||
#include "vm/il_printer.h"
|
||||
@@ -44,7 +45,7 @@ bool FlowGraphCompiler::SupportsUnboxedMints() {
|
||||
|
||||
|
||||
bool FlowGraphCompiler::SupportsUnboxedFloat32x4() {
|
||||
return CPUFeatures::neon_supported() && FLAG_enable_simd_inline;
|
||||
return TargetCPUFeatures::neon_supported() && FLAG_enable_simd_inline;
|
||||
}
|
||||
|
||||
|
||||
@@ -718,7 +719,9 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
|
||||
|
||||
|
||||
void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
|
||||
if (is_optimizing()) return;
|
||||
if (is_optimizing()) {
|
||||
return;
|
||||
}
|
||||
Definition* defn = instr->AsDefinition();
|
||||
if ((defn != NULL) && defn->is_used()) {
|
||||
__ Push(defn->locs()->out().reg());
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "vm/ast_printer.h"
|
||||
#include "vm/compiler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/deopt_instructions.h"
|
||||
#include "vm/il_printer.h"
|
||||
@@ -43,7 +44,7 @@ FlowGraphCompiler::~FlowGraphCompiler() {
|
||||
|
||||
bool FlowGraphCompiler::SupportsUnboxedMints() {
|
||||
// Support unboxed mints when SSE 4.1 is available.
|
||||
return FLAG_unbox_mints && CPUFeatures::sse4_1_supported();
|
||||
return FLAG_unbox_mints && TargetCPUFeatures::sse4_1_supported();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/cha.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/flow_graph_builder.h"
|
||||
#include "vm/flow_graph_compiler.h"
|
||||
@@ -2778,7 +2779,7 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
||||
case MethodRecognizer::kDoubleTruncate:
|
||||
case MethodRecognizer::kDoubleFloor:
|
||||
case MethodRecognizer::kDoubleCeil:
|
||||
if (!CPUFeatures::double_truncate_round_supported()) {
|
||||
if (!TargetCPUFeatures::double_truncate_round_supported()) {
|
||||
ReplaceWithMathCFunction(call, recognized_kind);
|
||||
} else {
|
||||
AddReceiverCheck(call);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "vm/bigint_operations.h"
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/flow_graph_allocator.h"
|
||||
#include "vm/flow_graph_builder.h"
|
||||
@@ -3108,7 +3109,7 @@ intptr_t InvokeMathCFunctionInstr::ArgumentCountFor(
|
||||
case MethodRecognizer::kDoubleTruncate:
|
||||
case MethodRecognizer::kDoubleFloor:
|
||||
case MethodRecognizer::kDoubleCeil: {
|
||||
ASSERT(!CPUFeatures::double_truncate_round_supported());
|
||||
ASSERT(!TargetCPUFeatures::double_truncate_round_supported());
|
||||
return 1;
|
||||
}
|
||||
case MethodRecognizer::kDoubleRound:
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
|
||||
|
||||
#include "vm/proccpuinfo.h"
|
||||
|
||||
#include <ctype.h> // NOLINT
|
||||
#include <string.h> // NOLINT
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
|
||||
char* ProcCpuInfo::data_ = NULL;
|
||||
intptr_t ProcCpuInfo::datalen_ = 0;
|
||||
|
||||
|
||||
void ProcCpuInfo::InitOnce() {
|
||||
// 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 they 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 (intptr_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';
|
||||
}
|
||||
|
||||
|
||||
void ProcCpuInfo::Cleanup() {
|
||||
ASSERT(data_);
|
||||
delete[] data_;
|
||||
data_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
char* ProcCpuInfo::FieldStart(const char* field) {
|
||||
// Look for first field occurrence, 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;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
bool ProcCpuInfo::FieldContains(const char* field, const char* search_string) {
|
||||
ASSERT(data_ != NULL);
|
||||
ASSERT(search_string != NULL);
|
||||
|
||||
char* p = FieldStart(field);
|
||||
if (p == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the end of the line.
|
||||
char* q = strchr(p, '\n');
|
||||
if (q == NULL) {
|
||||
q = data_ + datalen_;
|
||||
}
|
||||
|
||||
char saved_end = *q;
|
||||
*q = '\0';
|
||||
bool ret = (strcasestr(p, search_string) != NULL);
|
||||
*q = saved_end;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Extract the content of a the first occurrence 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.
|
||||
const char* ProcCpuInfo::ExtractField(const char* field) {
|
||||
ASSERT(field != NULL);
|
||||
ASSERT(data_ != NULL);
|
||||
|
||||
char* p = FieldStart(field);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find the end of the line.
|
||||
char* q = strchr(p, '\n');
|
||||
if (q == NULL) {
|
||||
q = data_ + datalen_;
|
||||
}
|
||||
|
||||
intptr_t len = q - p;
|
||||
char* result = new char[len + 1]; // plus one for null-terminator.
|
||||
// Copy the line into result, leaving enough room for a null-terminator.
|
||||
char saved_end = *q;
|
||||
*q = '\0';
|
||||
strncpy(result, p, len);
|
||||
result[len] = '\0';
|
||||
*q = saved_end;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool ProcCpuInfo::HasField(const char* field) {
|
||||
ASSERT(field != NULL);
|
||||
ASSERT(data_ != NULL);
|
||||
return (FieldStart(field) != NULL);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef VM_PROCCPUINFO_H_
|
||||
#define VM_PROCCPUINFO_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
|
||||
|
||||
#include "vm/allocation.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class ProcCpuInfo : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void Cleanup();
|
||||
static bool FieldContains(const char* field, const char* search_string);
|
||||
static const char* ExtractField(const char* field);
|
||||
static bool HasField(const char* field);
|
||||
|
||||
private:
|
||||
static char* data_;
|
||||
static intptr_t datalen_;
|
||||
|
||||
static char* FieldStart(const char* field);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
|
||||
|
||||
#endif // VM_PROCCPUINFO_H_
|
||||
@@ -1048,6 +1048,15 @@ static bool HandleDebug(Isolate* isolate, JSONStream* js) {
|
||||
}
|
||||
|
||||
|
||||
static bool HandleCpu(Isolate* isolate, JSONStream* js) {
|
||||
JSONObject jsobj(js);
|
||||
jsobj.AddProperty("type", "CPU");
|
||||
jsobj.AddProperty("targetCPU", CPU::Id());
|
||||
jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool HandleCode(Isolate* isolate, JSONStream* js) {
|
||||
REQUIRE_COLLECTION_ID("code");
|
||||
uintptr_t pc;
|
||||
@@ -1089,6 +1098,7 @@ static IsolateMessageHandlerEntry isolate_handlers[] = {
|
||||
{ "classes", HandleClasses },
|
||||
{ "code", HandleCode },
|
||||
{ "coverage", HandleCoverage },
|
||||
{ "cpu", HandleCpu },
|
||||
{ "debug", HandleDebug },
|
||||
{ "libraries", HandleLibraries },
|
||||
{ "objecthistogram", HandleObjectHistogram},
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "vm/assembler.h"
|
||||
#include "vm/constants_arm.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/disassembler.h"
|
||||
#include "vm/native_arguments.h"
|
||||
#include "vm/stack_frame.h"
|
||||
@@ -2303,7 +2304,7 @@ void Simulator::DecodeType2(Instr* instr) {
|
||||
|
||||
|
||||
void Simulator::DoDivision(Instr* instr) {
|
||||
ASSERT(CPUFeatures::integer_division_supported());
|
||||
ASSERT(TargetCPUFeatures::integer_division_supported());
|
||||
Register rd = instr->DivRdField();
|
||||
Register rn = instr->DivRnField();
|
||||
Register rm = instr->DivRmField();
|
||||
|
||||
@@ -100,6 +100,14 @@
|
||||
'cpu_mips.cc',
|
||||
'cpu_test.cc',
|
||||
'cpu_x64.cc',
|
||||
'cpuid.h',
|
||||
'cpuid.cc',
|
||||
'cpuinfo.h',
|
||||
'cpuinfo_android.cc',
|
||||
'cpuinfo_linux.cc',
|
||||
'cpuinfo_macos.cc',
|
||||
'cpuinfo_test.cc',
|
||||
'cpuinfo_win.cc',
|
||||
'custom_isolate_test.cc',
|
||||
'dart.cc',
|
||||
'dart.h',
|
||||
@@ -278,6 +286,8 @@
|
||||
'port.cc',
|
||||
'port.h',
|
||||
'port_test.cc',
|
||||
'proccpuinfo.h',
|
||||
'proccpuinfo.cc',
|
||||
'profiler.cc',
|
||||
'profiler.h',
|
||||
'profiler_test.cc',
|
||||
|
||||
Reference in New Issue
Block a user