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 |