| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" |
| 9 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| 10 #include "vm/runtime_entry.h" | 11 #include "vm/runtime_entry.h" |
| 11 #include "vm/simulator.h" | 12 #include "vm/simulator.h" |
| 12 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 13 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
| 14 | 15 |
| 15 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
| 16 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
| 17 #error ARM cross-compile only supported on Linux | 18 #error ARM cross-compile only supported on Linux |
| 18 #endif | 19 #endif |
| 19 | 20 |
| 20 namespace dart { | 21 namespace dart { |
| 21 | 22 |
| 22 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); | 23 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); |
| 23 DECLARE_FLAG(bool, inline_alloc); | 24 DECLARE_FLAG(bool, inline_alloc); |
| 24 | 25 |
| 25 bool CPUFeatures::integer_division_supported_ = false; | |
| 26 bool CPUFeatures::neon_supported_ = false; | |
| 27 #if defined(DEBUG) | |
| 28 bool CPUFeatures::initialized_ = false; | |
| 29 #endif | |
| 30 | |
| 31 | |
| 32 bool CPUFeatures::integer_division_supported() { | |
| 33 DEBUG_ASSERT(initialized_); | |
| 34 return integer_division_supported_; | |
| 35 } | |
| 36 | |
| 37 | |
| 38 bool CPUFeatures::neon_supported() { | |
| 39 DEBUG_ASSERT(initialized_); | |
| 40 return neon_supported_; | |
| 41 } | |
| 42 | |
| 43 | |
| 44 // If we are using the simulator, allow tests to enable/disable support for | |
| 45 // integer division. | |
| 46 #if defined(USING_SIMULATOR) | |
| 47 void CPUFeatures::set_integer_division_supported(bool supported) { | |
| 48 integer_division_supported_ = supported; | |
| 49 } | |
| 50 | |
| 51 | |
| 52 void CPUFeatures::set_neon_supported(bool supported) { | |
| 53 neon_supported_ = supported; | |
| 54 } | |
| 55 #endif | |
| 56 | |
| 57 | |
| 58 // Probe /proc/cpuinfo for features of the ARM processor. | |
| 59 #if !defined(USING_SIMULATOR) | |
| 60 static bool CPUInfoContainsString(const char* search_string) { | |
| 61 const char* file_name = "/proc/cpuinfo"; | |
| 62 // This is written as a straight shot one pass parser | |
| 63 // and not using STL string and ifstream because, | |
| 64 // on Linux, it's reading from a (non-mmap-able) | |
| 65 // character special device. | |
| 66 FILE* f = NULL; | |
| 67 const char* what = search_string; | |
| 68 | |
| 69 if (NULL == (f = fopen(file_name, "r"))) | |
| 70 return false; | |
| 71 | |
| 72 int k; | |
| 73 while (EOF != (k = fgetc(f))) { | |
| 74 if (k == *what) { | |
| 75 ++what; | |
| 76 while ((*what != '\0') && (*what == fgetc(f))) { | |
| 77 ++what; | |
| 78 } | |
| 79 if (*what == '\0') { | |
| 80 fclose(f); | |
| 81 return true; | |
| 82 } else { | |
| 83 what = search_string; | |
| 84 } | |
| 85 } | |
| 86 } | |
| 87 fclose(f); | |
| 88 | |
| 89 // Did not find string in the proc file. | |
| 90 return false; | |
| 91 } | |
| 92 #endif | |
| 93 | |
| 94 | |
| 95 void CPUFeatures::InitOnce() { | |
| 96 #if defined(USING_SIMULATOR) | |
| 97 integer_division_supported_ = true; | |
| 98 neon_supported_ = true; | |
| 99 #else | |
| 100 ASSERT(CPUInfoContainsString("ARMv7")); // Implements ARMv7. | |
| 101 ASSERT(CPUInfoContainsString("vfp")); // Has floating point unit. | |
| 102 // Has integer division. | |
| 103 if (CPUInfoContainsString("QCT APQ8064")) { | |
| 104 // Special case for Qualcomm Krait CPUs in Nexus 4 and 7. | |
| 105 integer_division_supported_ = true; | |
| 106 } else { | |
| 107 integer_division_supported_ = CPUInfoContainsString("idiva"); | |
| 108 } | |
| 109 neon_supported_ = CPUInfoContainsString("neon"); | |
| 110 #endif // defined(USING_SIMULATOR) | |
| 111 #if defined(DEBUG) | |
| 112 initialized_ = true; | |
| 113 #endif | |
| 114 } | |
| 115 | |
| 116 | 26 |
| 117 // Instruction encoding bits. | 27 // Instruction encoding bits. |
| 118 enum { | 28 enum { |
| 119 H = 1 << 5, // halfword (or byte) | 29 H = 1 << 5, // halfword (or byte) |
| 120 L = 1 << 20, // load (or store) | 30 L = 1 << 20, // load (or store) |
| 121 S = 1 << 20, // set condition code (or leave unchanged) | 31 S = 1 << 20, // set condition code (or leave unchanged) |
| 122 W = 1 << 21, // writeback base register (or leave unchanged) | 32 W = 1 << 21, // writeback base register (or leave unchanged) |
| 123 A = 1 << 21, // accumulate in multiply instruction (or not) | 33 A = 1 << 21, // accumulate in multiply instruction (or not) |
| 124 B = 1 << 22, // unsigned byte (or word) | 34 B = 1 << 22, // unsigned byte (or word) |
| 125 D = 1 << 22, // high/lo bit of start of s/d register range | 35 D = 1 << 22, // high/lo bit of start of s/d register range |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 | 452 |
| 543 void Assembler::umlal(Register rd_lo, Register rd_hi, | 453 void Assembler::umlal(Register rd_lo, Register rd_hi, |
| 544 Register rn, Register rm, Condition cond) { | 454 Register rn, Register rm, Condition cond) { |
| 545 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 455 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 546 EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm); | 456 EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm); |
| 547 } | 457 } |
| 548 | 458 |
| 549 | 459 |
| 550 void Assembler::EmitDivOp(Condition cond, int32_t opcode, | 460 void Assembler::EmitDivOp(Condition cond, int32_t opcode, |
| 551 Register rd, Register rn, Register rm) { | 461 Register rd, Register rn, Register rm) { |
| 552 ASSERT(CPUFeatures::integer_division_supported()); | 462 ASSERT(TargetCPUFeatures::integer_division_supported()); |
| 553 ASSERT(rd != kNoRegister); | 463 ASSERT(rd != kNoRegister); |
| 554 ASSERT(rn != kNoRegister); | 464 ASSERT(rn != kNoRegister); |
| 555 ASSERT(rm != kNoRegister); | 465 ASSERT(rm != kNoRegister); |
| 556 ASSERT(cond != kNoCondition); | 466 ASSERT(cond != kNoCondition); |
| 557 int32_t encoding = opcode | | 467 int32_t encoding = opcode | |
| 558 (static_cast<int32_t>(cond) << kConditionShift) | | 468 (static_cast<int32_t>(cond) << kConditionShift) | |
| 559 (static_cast<int32_t>(rn) << kDivRnShift) | | 469 (static_cast<int32_t>(rn) << kDivRnShift) | |
| 560 (static_cast<int32_t>(rd) << kDivRdShift) | | 470 (static_cast<int32_t>(rd) << kDivRdShift) | |
| 561 B26 | B25 | B24 | B20 | B4 | | 471 B26 | B25 | B24 | B20 | B4 | |
| 562 (static_cast<int32_t>(rm) << kDivRmShift); | 472 (static_cast<int32_t>(rm) << kDivRmShift); |
| (...skipping 1887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2450 tst(rn, shifter_op, cond); | 2360 tst(rn, shifter_op, cond); |
| 2451 } else { | 2361 } else { |
| 2452 LoadImmediate(IP, imm); | 2362 LoadImmediate(IP, imm); |
| 2453 tst(rn, ShifterOperand(IP), cond); | 2363 tst(rn, ShifterOperand(IP), cond); |
| 2454 } | 2364 } |
| 2455 } | 2365 } |
| 2456 | 2366 |
| 2457 void Assembler::IntegerDivide(Register result, Register left, Register right, | 2367 void Assembler::IntegerDivide(Register result, Register left, Register right, |
| 2458 DRegister tmpl, DRegister tmpr) { | 2368 DRegister tmpl, DRegister tmpr) { |
| 2459 ASSERT(tmpl != tmpr); | 2369 ASSERT(tmpl != tmpr); |
| 2460 if (CPUFeatures::integer_division_supported()) { | 2370 if (TargetCPUFeatures::integer_division_supported()) { |
| 2461 sdiv(result, left, right); | 2371 sdiv(result, left, right); |
| 2462 } else { | 2372 } else { |
| 2463 SRegister stmpl = static_cast<SRegister>(2 * tmpl); | 2373 SRegister stmpl = static_cast<SRegister>(2 * tmpl); |
| 2464 SRegister stmpr = static_cast<SRegister>(2 * tmpr); | 2374 SRegister stmpr = static_cast<SRegister>(2 * tmpr); |
| 2465 vmovsr(stmpl, left); | 2375 vmovsr(stmpl, left); |
| 2466 vcvtdi(tmpl, stmpl); // left is in tmpl. | 2376 vcvtdi(tmpl, stmpl); // left is in tmpl. |
| 2467 vmovsr(stmpr, right); | 2377 vmovsr(stmpr, right); |
| 2468 vcvtdi(tmpr, stmpr); // right is in tmpr. | 2378 vcvtdi(tmpr, stmpr); // right is in tmpr. |
| 2469 vdivd(tmpr, tmpl, tmpr); | 2379 vdivd(tmpr, tmpl, tmpr); |
| 2470 vcvtid(stmpr, tmpr); | 2380 vcvtid(stmpr, tmpr); |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2844 | 2754 |
| 2845 | 2755 |
| 2846 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2756 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 2847 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 2757 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
| 2848 return fpu_reg_names[reg]; | 2758 return fpu_reg_names[reg]; |
| 2849 } | 2759 } |
| 2850 | 2760 |
| 2851 } // namespace dart | 2761 } // namespace dart |
| 2852 | 2762 |
| 2853 #endif // defined TARGET_ARCH_ARM | 2763 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |