Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| 11 #include "vm/runtime_entry.h" | 11 #include "vm/runtime_entry.h" |
| 12 #include "vm/simulator.h" | 12 #include "vm/simulator.h" |
| 13 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 14 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
| 15 | 15 |
| 16 // 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. |
| 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
| 18 #error ARM64 cross-compile only supported on Linux | 18 #error ARM64 cross-compile only supported on Linux |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); | |
| 23 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 24 DECLARE_FLAG(bool, inline_alloc); | 25 DECLARE_FLAG(bool, inline_alloc); |
| 25 | 26 |
| 26 | 27 |
| 27 Assembler::Assembler(bool use_far_branches) | 28 Assembler::Assembler(bool use_far_branches) |
| 28 : buffer_(), | 29 : buffer_(), |
| 29 object_pool_(GrowableObjectArray::Handle()), | 30 object_pool_(GrowableObjectArray::Handle()), |
| 30 patchable_pool_entries_(), | 31 patchable_pool_entries_(), |
| 31 prologue_offset_(-1), | 32 prologue_offset_(-1), |
| 32 use_far_branches_(use_far_branches), | 33 use_far_branches_(use_far_branches), |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", | 117 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", |
| 117 }; | 118 }; |
| 118 | 119 |
| 119 | 120 |
| 120 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 121 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 121 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 122 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
| 122 return fpu_reg_names[reg]; | 123 return fpu_reg_names[reg]; |
| 123 } | 124 } |
| 124 | 125 |
| 125 | 126 |
| 126 // TODO(zra): Support for far branches. Requires loading large immediates. | |
| 127 void Assembler::Bind(Label* label) { | 127 void Assembler::Bind(Label* label) { |
| 128 ASSERT(!label->IsBound()); | 128 ASSERT(!label->IsBound()); |
| 129 intptr_t bound_pc = buffer_.Size(); | 129 const intptr_t bound_pc = buffer_.Size(); |
| 130 | 130 |
| 131 while (label->IsLinked()) { | 131 while (label->IsLinked()) { |
| 132 const int64_t position = label->Position(); | 132 const int64_t position = label->Position(); |
| 133 const int64_t dest = bound_pc - position; | 133 const int64_t dest = bound_pc - position; |
| 134 const int32_t next = buffer_.Load<int32_t>(position); | 134 if (use_far_branches() /*&& !CanEncodeImm19BranchOffset(dest)*/) { |
|
regis
2014/05/12 16:05:02
Left over commented code?
zra
2014/05/12 18:42:50
Ah, yah, thanks. I was testing without the optimiz
| |
| 135 const int32_t encoded = EncodeImm19BranchOffset(dest, next); | 135 // Far branches are enabled, and we can't encode the branch offset in |
| 136 buffer_.Store<int32_t>(position, encoded); | 136 // 19 bits. |
| 137 label->position_ = DecodeImm19BranchOffset(next); | 137 |
| 138 // Grab the guarding branch instruction. | |
| 139 const int32_t guard_branch = | |
| 140 buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); | |
| 141 | |
| 142 // Grab the far branch instruction. | |
| 143 const int32_t far_branch = | |
| 144 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
| 145 | |
| 146 const Condition c = DecodeImm19BranchCondition(guard_branch); | |
| 147 | |
| 148 // Grab the link to the next branch. | |
| 149 const int32_t next = DecodeImm26BranchOffset(far_branch); | |
| 150 | |
| 151 // dest is the offset is from the guarding branch instruction. | |
| 152 // Correct it to be from the following instruction. | |
| 153 const int64_t offset = dest - Instr::kInstrSize; | |
| 154 | |
| 155 // Encode the branch. | |
| 156 const int32_t encoded_branch = | |
| 157 EncodeImm26BranchOffset(offset, far_branch); | |
| 158 | |
| 159 // If the guard branch is conditioned on NV, replace it with a nop. | |
| 160 if (c == NV) { | |
| 161 buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, | |
| 162 Instr::kNopInstruction); | |
| 163 } | |
| 164 | |
| 165 // Write the far branch into the buffer and link to the next branch. | |
| 166 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch); | |
| 167 label->position_ = next; | |
| 168 } else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) { | |
| 169 // We assembled a far branch, but we don't need it. Replace it with a near | |
| 170 // branch. | |
| 171 | |
| 172 // Grab the guarding branch instruction. | |
| 173 const int32_t guard_branch = | |
| 174 buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); | |
| 175 | |
| 176 // Grab the far branch instruction. | |
| 177 const int32_t far_branch = | |
| 178 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
| 179 | |
| 180 // Grab the link to the next branch. | |
| 181 const int32_t next = DecodeImm26BranchOffset(far_branch); | |
| 182 | |
| 183 // Re-target the guarding branch and flip the conditional sense. | |
| 184 int32_t encoded_guard_branch = | |
| 185 EncodeImm19BranchOffset(dest, guard_branch); | |
| 186 const Condition c = DecodeImm19BranchCondition(encoded_guard_branch); | |
| 187 encoded_guard_branch = EncodeImm19BranchCondition( | |
| 188 InvertCondition(c), encoded_guard_branch); | |
| 189 | |
| 190 // Write back the re-encoded instructions. The far branch becomes a nop. | |
| 191 buffer_.Store<int32_t>( | |
| 192 position + 0 * Instr::kInstrSize, encoded_guard_branch); | |
| 193 buffer_.Store<int32_t>( | |
| 194 position + 1 * Instr::kInstrSize, Instr::kNopInstruction); | |
| 195 label->position_ = next; | |
| 196 } else { | |
| 197 const int32_t next = buffer_.Load<int32_t>(position); | |
| 198 const int32_t encoded = EncodeImm19BranchOffset(dest, next); | |
| 199 buffer_.Store<int32_t>(position, encoded); | |
| 200 label->position_ = DecodeImm19BranchOffset(next); | |
| 201 } | |
| 138 } | 202 } |
| 139 label->BindTo(bound_pc); | 203 label->BindTo(bound_pc); |
| 140 } | 204 } |
| 141 | 205 |
| 142 | 206 |
| 143 void Assembler::Stop(const char* message) { | 207 void Assembler::Stop(const char* message) { |
| 144 if (FLAG_print_stop_message) { | 208 if (FLAG_print_stop_message) { |
| 145 UNIMPLEMENTED(); | 209 UNIMPLEMENTED(); |
| 146 } | 210 } |
| 147 Label stop; | 211 Label stop; |
| (...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 938 Register object, intptr_t class_id, Register pp) { | 1002 Register object, intptr_t class_id, Register pp) { |
| 939 LoadClassId(TMP, object, pp); | 1003 LoadClassId(TMP, object, pp); |
| 940 CompareImmediate(TMP, class_id, pp); | 1004 CompareImmediate(TMP, class_id, pp); |
| 941 } | 1005 } |
| 942 | 1006 |
| 943 | 1007 |
| 944 // Frame entry and exit. | 1008 // Frame entry and exit. |
| 945 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 1009 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 946 // Reserve space for arguments and align frame before entering | 1010 // Reserve space for arguments and align frame before entering |
| 947 // the C++ world. | 1011 // the C++ world. |
| 948 AddImmediate(SP, SP, -frame_space, kNoPP); | 1012 if (frame_space != 0) { |
| 1013 AddImmediate(SP, SP, -frame_space, kNoPP); | |
| 1014 } | |
| 949 if (OS::ActivationFrameAlignment() > 1) { | 1015 if (OS::ActivationFrameAlignment() > 1) { |
| 950 mov(TMP, SP); // SP can't be register operand of andi. | 1016 mov(TMP, SP); // SP can't be register operand of andi. |
| 951 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); | 1017 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); |
| 952 mov(SP, TMP); | 1018 mov(SP, TMP); |
| 953 } | 1019 } |
| 954 } | 1020 } |
| 955 | 1021 |
| 956 | 1022 |
| 957 void Assembler::EnterFrame(intptr_t frame_size) { | 1023 void Assembler::EnterFrame(intptr_t frame_size) { |
| 958 Push(LR); | 1024 Push(LR); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1250 LoadImmediate(TMP, tags, pp); | 1316 LoadImmediate(TMP, tags, pp); |
| 1251 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); | 1317 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); |
| 1252 } else { | 1318 } else { |
| 1253 b(failure); | 1319 b(failure); |
| 1254 } | 1320 } |
| 1255 } | 1321 } |
| 1256 | 1322 |
| 1257 } // namespace dart | 1323 } // namespace dart |
| 1258 | 1324 |
| 1259 #endif // defined TARGET_ARCH_ARM64 | 1325 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |