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" | |
10 #include "vm/longjump.h" | 9 #include "vm/longjump.h" |
11 #include "vm/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
12 #include "vm/simulator.h" | 11 #include "vm/simulator.h" |
13 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
14 #include "vm/stub_code.h" | 13 #include "vm/stub_code.h" |
15 | 14 |
16 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 15 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 16 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
18 #error ARM cross-compile only supported on Linux | 17 #error ARM cross-compile only supported on Linux |
19 #endif | 18 #endif |
20 | 19 |
21 namespace dart { | 20 namespace dart { |
22 | 21 |
23 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); | 22 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); |
24 DECLARE_FLAG(bool, inline_alloc); | 23 DECLARE_FLAG(bool, inline_alloc); |
25 | 24 |
| 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 |
26 | 116 |
27 // Instruction encoding bits. | 117 // Instruction encoding bits. |
28 enum { | 118 enum { |
29 H = 1 << 5, // halfword (or byte) | 119 H = 1 << 5, // halfword (or byte) |
30 L = 1 << 20, // load (or store) | 120 L = 1 << 20, // load (or store) |
31 S = 1 << 20, // set condition code (or leave unchanged) | 121 S = 1 << 20, // set condition code (or leave unchanged) |
32 W = 1 << 21, // writeback base register (or leave unchanged) | 122 W = 1 << 21, // writeback base register (or leave unchanged) |
33 A = 1 << 21, // accumulate in multiply instruction (or not) | 123 A = 1 << 21, // accumulate in multiply instruction (or not) |
34 B = 1 << 22, // unsigned byte (or word) | 124 B = 1 << 22, // unsigned byte (or word) |
35 D = 1 << 22, // high/lo bit of start of s/d register range | 125 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... |
452 | 542 |
453 void Assembler::umlal(Register rd_lo, Register rd_hi, | 543 void Assembler::umlal(Register rd_lo, Register rd_hi, |
454 Register rn, Register rm, Condition cond) { | 544 Register rn, Register rm, Condition cond) { |
455 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 545 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
456 EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm); | 546 EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm); |
457 } | 547 } |
458 | 548 |
459 | 549 |
460 void Assembler::EmitDivOp(Condition cond, int32_t opcode, | 550 void Assembler::EmitDivOp(Condition cond, int32_t opcode, |
461 Register rd, Register rn, Register rm) { | 551 Register rd, Register rn, Register rm) { |
462 ASSERT(TargetCPUFeatures::integer_division_supported()); | 552 ASSERT(CPUFeatures::integer_division_supported()); |
463 ASSERT(rd != kNoRegister); | 553 ASSERT(rd != kNoRegister); |
464 ASSERT(rn != kNoRegister); | 554 ASSERT(rn != kNoRegister); |
465 ASSERT(rm != kNoRegister); | 555 ASSERT(rm != kNoRegister); |
466 ASSERT(cond != kNoCondition); | 556 ASSERT(cond != kNoCondition); |
467 int32_t encoding = opcode | | 557 int32_t encoding = opcode | |
468 (static_cast<int32_t>(cond) << kConditionShift) | | 558 (static_cast<int32_t>(cond) << kConditionShift) | |
469 (static_cast<int32_t>(rn) << kDivRnShift) | | 559 (static_cast<int32_t>(rn) << kDivRnShift) | |
470 (static_cast<int32_t>(rd) << kDivRdShift) | | 560 (static_cast<int32_t>(rd) << kDivRdShift) | |
471 B26 | B25 | B24 | B20 | B4 | | 561 B26 | B25 | B24 | B20 | B4 | |
472 (static_cast<int32_t>(rm) << kDivRmShift); | 562 (static_cast<int32_t>(rm) << kDivRmShift); |
(...skipping 1887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2360 tst(rn, shifter_op, cond); | 2450 tst(rn, shifter_op, cond); |
2361 } else { | 2451 } else { |
2362 LoadImmediate(IP, imm); | 2452 LoadImmediate(IP, imm); |
2363 tst(rn, ShifterOperand(IP), cond); | 2453 tst(rn, ShifterOperand(IP), cond); |
2364 } | 2454 } |
2365 } | 2455 } |
2366 | 2456 |
2367 void Assembler::IntegerDivide(Register result, Register left, Register right, | 2457 void Assembler::IntegerDivide(Register result, Register left, Register right, |
2368 DRegister tmpl, DRegister tmpr) { | 2458 DRegister tmpl, DRegister tmpr) { |
2369 ASSERT(tmpl != tmpr); | 2459 ASSERT(tmpl != tmpr); |
2370 if (TargetCPUFeatures::integer_division_supported()) { | 2460 if (CPUFeatures::integer_division_supported()) { |
2371 sdiv(result, left, right); | 2461 sdiv(result, left, right); |
2372 } else { | 2462 } else { |
2373 SRegister stmpl = static_cast<SRegister>(2 * tmpl); | 2463 SRegister stmpl = static_cast<SRegister>(2 * tmpl); |
2374 SRegister stmpr = static_cast<SRegister>(2 * tmpr); | 2464 SRegister stmpr = static_cast<SRegister>(2 * tmpr); |
2375 vmovsr(stmpl, left); | 2465 vmovsr(stmpl, left); |
2376 vcvtdi(tmpl, stmpl); // left is in tmpl. | 2466 vcvtdi(tmpl, stmpl); // left is in tmpl. |
2377 vmovsr(stmpr, right); | 2467 vmovsr(stmpr, right); |
2378 vcvtdi(tmpr, stmpr); // right is in tmpr. | 2468 vcvtdi(tmpr, stmpr); // right is in tmpr. |
2379 vdivd(tmpr, tmpl, tmpr); | 2469 vdivd(tmpr, tmpl, tmpr); |
2380 vcvtid(stmpr, tmpr); | 2470 vcvtid(stmpr, tmpr); |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2754 | 2844 |
2755 | 2845 |
2756 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2846 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
2757 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 2847 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
2758 return fpu_reg_names[reg]; | 2848 return fpu_reg_names[reg]; |
2759 } | 2849 } |
2760 | 2850 |
2761 } // namespace dart | 2851 } // namespace dart |
2762 | 2852 |
2763 #endif // defined TARGET_ARCH_ARM | 2853 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |