diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc index 7f9933d9b9b..cd02b44a666 100644 --- a/runtime/vm/assembler_arm.cc +++ b/runtime/vm/assembler_arm.cc @@ -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(2 * tmpl); diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h index 87046cc070a..10d9a7f0682 100644 --- a/runtime/vm/assembler_arm.h +++ b/runtime/vm/assembler_arm.h @@ -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: diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc index c09075f02ba..f4f4887c3c0 100644 --- a/runtime/vm/assembler_arm_test.cc +++ b/runtime/vm/assembler_arm_test.cc @@ -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); diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc index 67b62df46fa..e1a4658c739 100644 --- a/runtime/vm/assembler_ia32.cc +++ b/runtime/vm/assembler_ia32.cc @@ -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(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); diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h index cfff9a9e860..d3d3dbe2c65 100644 --- a/runtime/vm/assembler_ia32.h +++ b/runtime/vm/assembler_ia32.h @@ -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(1) << 26; - static const uint64_t kSSE4_1BitMask = static_cast(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) diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc index bf3377eccd5..a652b8f048c 100644 --- a/runtime/vm/assembler_ia32_test.cc +++ b/runtime/vm/assembler_ia32_test.cc @@ -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(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(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(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(test->entry())(0); EXPECT_EQ(-1, res); diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h index d80baee4dc9..e0de57b5ade 100644 --- a/runtime/vm/assembler_mips.h +++ b/runtime/vm/assembler_mips.h @@ -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) diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc index d293395d67e..f2c075dc12f 100644 --- a/runtime/vm/assembler_mips_test.cc +++ b/runtime/vm/assembler_mips_test.cc @@ -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" diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc index b1de19d9f86..a3bc9eb8c15 100644 --- a/runtime/vm/assembler_x64.cc +++ b/runtime/vm/assembler_x64.cc @@ -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(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()), diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h index 1fb9c2eaeb1..1b12f5fb711 100644 --- a/runtime/vm/assembler_x64.h +++ b/runtime/vm/assembler_x64.h @@ -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(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); diff --git a/runtime/vm/cpu.h b/runtime/vm/cpu.h index c8f5e9c0348..9546f17cf7c 100644 --- a/runtime/vm/cpu.h +++ b/runtime/vm/cpu.h @@ -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_ diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc index 2807cee1a32..1100c26b5bc 100644 --- a/runtime/vm/cpu_arm.cc +++ b/runtime/vm/cpu_arm.cc @@ -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 /* NOLINT */ #include /* 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 diff --git a/runtime/vm/cpu_arm.h b/runtime/vm/cpu_arm.h new file mode 100644 index 00000000000..cbcac117027 --- /dev/null +++ b/runtime/vm/cpu_arm.h @@ -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_ diff --git a/runtime/vm/cpu_ia32.cc b/runtime/vm/cpu_ia32.cc index 8f3fae1871d..8158e3a0052 100644 --- a/runtime/vm/cpu_ia32.cc +++ b/runtime/vm/cpu_ia32.cc @@ -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 diff --git a/runtime/vm/cpu_ia32.h b/runtime/vm/cpu_ia32.h new file mode 100644 index 00000000000..66f47240765 --- /dev/null +++ b/runtime/vm/cpu_ia32.h @@ -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(1) << 26; + static const uint64_t kSSE4_1BitMask = static_cast(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_ diff --git a/runtime/vm/cpu_mips.cc b/runtime/vm/cpu_mips.cc index 095ec4cd38d..3d26cd669f4 100644 --- a/runtime/vm/cpu_mips.cc +++ b/runtime/vm/cpu_mips.cc @@ -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 /* NOLINT */ #include /* NOLINT */ #include /* 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 diff --git a/runtime/vm/cpu_mips.h b/runtime/vm/cpu_mips.h new file mode 100644 index 00000000000..e6c8f19ee07 --- /dev/null +++ b/runtime/vm/cpu_mips.h @@ -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_ diff --git a/runtime/vm/cpu_x64.cc b/runtime/vm/cpu_x64.cc index 295a2e60fbb..31c4ec7f81a 100644 --- a/runtime/vm/cpu_x64.cc +++ b/runtime/vm/cpu_x64.cc @@ -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 diff --git a/runtime/vm/cpu_x64.h b/runtime/vm/cpu_x64.h new file mode 100644 index 00000000000..579650a7fe8 --- /dev/null +++ b/runtime/vm/cpu_x64.h @@ -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(1) << 26; + static const uint64_t kSSE4_1BitMask = static_cast(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_ diff --git a/runtime/vm/cpuid.cc b/runtime/vm/cpuid.cc new file mode 100644 index 00000000000..45499b4f742 --- /dev/null +++ b/runtime/vm/cpuid.cc @@ -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 // NOLINT +#else +#include // 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(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(id_string) = info[1]; + *reinterpret_cast(id_string + 4) = info[3]; + *reinterpret_cast(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(brand_string + off) = info[0]; + *reinterpret_cast(brand_string + off + 4) = info[1]; + *reinterpret_cast(brand_string + off + 8) = info[2]; + *reinterpret_cast(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) diff --git a/runtime/vm/cpuid.h b/runtime/vm/cpuid.h new file mode 100644 index 00000000000..b9d193af326 --- /dev/null +++ b/runtime/vm/cpuid.h @@ -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_ diff --git a/runtime/vm/cpuinfo.h b/runtime/vm/cpuinfo.h new file mode 100644 index 00000000000..f0f73b52729 --- /dev/null +++ b/runtime/vm/cpuinfo.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_ diff --git a/runtime/vm/cpuinfo_android.cc b/runtime/vm/cpuinfo_android.cc new file mode 100644 index 00000000000..ba90d25e15f --- /dev/null +++ b/runtime/vm/cpuinfo_android.cc @@ -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) diff --git a/runtime/vm/cpuinfo_linux.cc b/runtime/vm/cpuinfo_linux.cc new file mode 100644 index 00000000000..e96e0d50278 --- /dev/null +++ b/runtime/vm/cpuinfo_linux.cc @@ -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(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(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) diff --git a/runtime/vm/cpuinfo_macos.cc b/runtime/vm/cpuinfo_macos.cc new file mode 100644 index 00000000000..6300d7c7f72 --- /dev/null +++ b/runtime/vm/cpuinfo_macos.cc @@ -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 // NOLINT +#include // NOLINT +#include // 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) diff --git a/runtime/vm/cpuinfo_test.cc b/runtime/vm/cpuinfo_test.cc new file mode 100644 index 00000000000..e717d28eb15 --- /dev/null +++ b/runtime/vm/cpuinfo_test.cc @@ -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 diff --git a/runtime/vm/cpuinfo_win.cc b/runtime/vm/cpuinfo_win.cc new file mode 100644 index 00000000000..b648566c5d8 --- /dev/null +++ b/runtime/vm/cpuinfo_win.cc @@ -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 // NOLINT +#include // 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(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(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) diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index ba59001606b..45f51e354c1 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -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; } diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc index 93cf6c4baa6..eb7fa01475c 100644 --- a/runtime/vm/flow_graph_compiler_arm.cc +++ b/runtime/vm/flow_graph_compiler_arm.cc @@ -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()); diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc index 27c34cbb15d..94af4b289ca 100644 --- a/runtime/vm/flow_graph_compiler_ia32.cc +++ b/runtime/vm/flow_graph_compiler_ia32.cc @@ -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(); } diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc index d2da155f5d8..4bc20e1fbfe 100644 --- a/runtime/vm/flow_graph_optimizer.cc +++ b/runtime/vm/flow_graph_optimizer.cc @@ -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); diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index e8a7da67c22..d8df9e53ac8 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -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: diff --git a/runtime/vm/proccpuinfo.cc b/runtime/vm/proccpuinfo.cc new file mode 100644 index 00000000000..17dc170c341 --- /dev/null +++ b/runtime/vm/proccpuinfo.cc @@ -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 // NOLINT +#include // 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) diff --git a/runtime/vm/proccpuinfo.h b/runtime/vm/proccpuinfo.h new file mode 100644 index 00000000000..0814c6aaa8e --- /dev/null +++ b/runtime/vm/proccpuinfo.h @@ -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_ diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 92955d3660d..cedc6ba01ad 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -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}, diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index 0e2218788f4..1ff38480e9f 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc @@ -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(); diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi index 660cbe439f2..65cd91c8c98 100644 --- a/runtime/vm/vm_sources.gypi +++ b/runtime/vm/vm_sources.gypi @@ -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',