Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: runtime/vm/assembler_arm64.cc

Issue 283513002: Adds far-branches to arm64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/assembler_arm64.h ('k') | runtime/vm/constants_arm64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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)) {
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 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 // TODO(zra): Evaluate putting all VM heap objects into the pool. 483 // TODO(zra): Evaluate putting all VM heap objects into the pool.
420 (!object.InVMHeap() || (object.raw() == Object::null()) || 484 (!object.InVMHeap() || (object.raw() == Object::null()) ||
421 (object.raw() == Bool::True().raw()) || 485 (object.raw() == Bool::True().raw()) ||
422 (object.raw() == Bool::False().raw())); 486 (object.raw() == Bool::False().raw()));
423 } 487 }
424 488
425 489
426 bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) { 490 bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) {
427 return !Utils::IsInt(32, imm) && 491 return !Utils::IsInt(32, imm) &&
428 (pp != kNoPP) && 492 (pp != kNoPP) &&
493 // We *could* put constants in the pool in a VM isolate, but it is
494 // simpler to maintain the invariant that the object pool is not used
495 // in the VM isolate.
429 (Isolate::Current() != Dart::vm_isolate()); 496 (Isolate::Current() != Dart::vm_isolate());
430 } 497 }
431 498
432 499
433 void Assembler::LoadExternalLabel(Register dst, 500 void Assembler::LoadExternalLabel(Register dst,
434 const ExternalLabel* label, 501 const ExternalLabel* label,
435 Patchability patchable, 502 Patchability patchable,
436 Register pp) { 503 Register pp) {
437 const int32_t offset = 504 const int64_t target = static_cast<int64_t>(label->address());
438 Array::element_offset(FindExternalLabel(label, patchable)); 505 if (CanLoadImmediateFromPool(target, pp)) {
439 LoadWordFromPoolOffset(dst, pp, offset); 506 const int32_t offset =
507 Array::element_offset(FindExternalLabel(label, patchable));
508 LoadWordFromPoolOffset(dst, pp, offset);
509 } else {
510 LoadImmediate(dst, target, kNoPP);
511 }
440 } 512 }
441 513
442 514
443 void Assembler::LoadExternalLabelFixed(Register dst, 515 void Assembler::LoadExternalLabelFixed(Register dst,
444 const ExternalLabel* label, 516 const ExternalLabel* label,
445 Patchability patchable, 517 Patchability patchable,
446 Register pp) { 518 Register pp) {
447 const int32_t offset = 519 const int32_t offset =
448 Array::element_offset(FindExternalLabel(label, patchable)); 520 Array::element_offset(FindExternalLabel(label, patchable));
449 LoadWordFromPoolOffsetFixed(dst, pp, offset); 521 LoadWordFromPoolOffsetFixed(dst, pp, offset);
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 Register object, intptr_t class_id, Register pp) { 1010 Register object, intptr_t class_id, Register pp) {
939 LoadClassId(TMP, object, pp); 1011 LoadClassId(TMP, object, pp);
940 CompareImmediate(TMP, class_id, pp); 1012 CompareImmediate(TMP, class_id, pp);
941 } 1013 }
942 1014
943 1015
944 // Frame entry and exit. 1016 // Frame entry and exit.
945 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { 1017 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
946 // Reserve space for arguments and align frame before entering 1018 // Reserve space for arguments and align frame before entering
947 // the C++ world. 1019 // the C++ world.
948 AddImmediate(SP, SP, -frame_space, kNoPP); 1020 if (frame_space != 0) {
1021 AddImmediate(SP, SP, -frame_space, kNoPP);
1022 }
949 if (OS::ActivationFrameAlignment() > 1) { 1023 if (OS::ActivationFrameAlignment() > 1) {
950 mov(TMP, SP); // SP can't be register operand of andi. 1024 mov(TMP, SP); // SP can't be register operand of andi.
951 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); 1025 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1));
952 mov(SP, TMP); 1026 mov(SP, TMP);
953 } 1027 }
954 } 1028 }
955 1029
956 1030
957 void Assembler::EnterFrame(intptr_t frame_size) { 1031 void Assembler::EnterFrame(intptr_t frame_size) {
958 Push(LR); 1032 Push(LR);
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1250 LoadImmediate(TMP, tags, pp); 1324 LoadImmediate(TMP, tags, pp);
1251 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); 1325 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp);
1252 } else { 1326 } else {
1253 b(failure); 1327 b(failure);
1254 } 1328 }
1255 } 1329 }
1256 1330
1257 } // namespace dart 1331 } // namespace dart
1258 1332
1259 #endif // defined TARGET_ARCH_ARM64 1333 #endif // defined TARGET_ARCH_ARM64
OLDNEW
« no previous file with comments | « runtime/vm/assembler_arm64.h ('k') | runtime/vm/constants_arm64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698