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

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

Issue 21363003: Enables per-function far-branches for ARM and MIPS. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 4 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
OLDNEW
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_MIPS) 6 #if defined(TARGET_ARCH_MIPS)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/longjump.h"
9 #include "vm/runtime_entry.h" 10 #include "vm/runtime_entry.h"
10 #include "vm/simulator.h" 11 #include "vm/simulator.h"
11 #include "vm/stack_frame.h" 12 #include "vm/stack_frame.h"
12 #include "vm/stub_code.h" 13 #include "vm/stub_code.h"
13 14
14 namespace dart { 15 namespace dart {
15 16
16 #if defined(USING_SIMULATOR) 17 #if defined(USING_SIMULATOR)
17 DECLARE_FLAG(bool, trace_sim); 18 DECLARE_FLAG(bool, trace_sim);
18 #endif 19 #endif
(...skipping 22 matching lines...) Expand all
41 } 42 }
42 } 43 }
43 44
44 45
45 static bool CanEncodeBranchOffset(int32_t offset) { 46 static bool CanEncodeBranchOffset(int32_t offset) {
46 ASSERT(Utils::IsAligned(offset, 4)); 47 ASSERT(Utils::IsAligned(offset, 4));
47 return Utils::IsInt(18, offset); 48 return Utils::IsInt(18, offset);
48 } 49 }
49 50
50 51
51 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr) { 52 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t instr) {
52 ASSERT(Utils::IsAligned(offset, 4)); 53 if (!CanEncodeBranchOffset(offset)) {
53 ASSERT(Utils::IsInt(18, offset)); 54 ASSERT(!use_far_branches());
55 const Error& error = Error::Handle(LanguageError::New(
56 String::Handle(String::New("Branch offset overflow"))));
57 Isolate::Current()->long_jump_base()->Jump(1, error);
58 }
54 59
55 // Properly preserve only the bits supported in the instruction. 60 // Properly preserve only the bits supported in the instruction.
56 offset >>= 2; 61 offset >>= 2;
57 offset &= kBranchOffsetMask; 62 offset &= kBranchOffsetMask;
58 return (instr & ~kBranchOffsetMask) | offset; 63 return (instr & ~kBranchOffsetMask) | offset;
59 } 64 }
60 65
61 66
62 static int DecodeBranchOffset(int32_t instr) { 67 static int DecodeBranchOffset(int32_t instr) {
63 // Sign-extend, left-shift by 2. 68 // Sign-extend, left-shift by 2.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 return; 104 return;
100 } 105 }
101 // If the offset loading instructions aren't there, we must have replaced 106 // If the offset loading instructions aren't there, we must have replaced
102 // the far branch with a near one, and so these instructions should be NOPs. 107 // the far branch with a near one, and so these instructions should be NOPs.
103 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction)); 108 ASSERT((high == Instr::kNopInstruction) && (low == Instr::kNopInstruction));
104 } 109 }
105 }; 110 };
106 111
107 112
108 void Assembler::EmitFarJump(int32_t offset, bool link) { 113 void Assembler::EmitFarJump(int32_t offset, bool link) {
114 ASSERT(use_far_branches());
109 const uint16_t low = Utils::Low16Bits(offset); 115 const uint16_t low = Utils::Low16Bits(offset);
110 const uint16_t high = Utils::High16Bits(offset); 116 const uint16_t high = Utils::High16Bits(offset);
111 buffer_.EmitFixup(new PatchFarJump()); 117 buffer_.EmitFixup(new PatchFarJump());
112 lui(TMP, Immediate(high)); 118 lui(TMP, Immediate(high));
113 ori(TMP, TMP, Immediate(low)); 119 ori(TMP, TMP, Immediate(low));
114 if (link) { 120 if (link) {
115 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); 121 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR);
116 } else { 122 } else {
117 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); 123 EmitRType(SPECIAL, TMP, R0, R0, 0, JR);
118 } 124 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 nop(); 178 nop();
173 EmitFarJump(offset, false); 179 EmitFarJump(offset, false);
174 } 180 }
175 181
176 182
177 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) { 183 void Assembler::EmitBranch(Opcode b, Register rs, Register rt, Label* label) {
178 if (label->IsBound()) { 184 if (label->IsBound()) {
179 // Relative destination from an instruction after the branch. 185 // Relative destination from an instruction after the branch.
180 const int32_t dest = 186 const int32_t dest =
181 label->Position() - (buffer_.Size() + Instr::kInstrSize); 187 label->Position() - (buffer_.Size() + Instr::kInstrSize);
182 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { 188 if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
183 EmitFarBranch(b, rs, rt, label->Position()); 189 EmitFarBranch(b, rs, rt, label->Position());
184 } else { 190 } else {
185 const uint16_t dest_off = EncodeBranchOffset(dest, 0); 191 const uint16_t dest_off = EncodeBranchOffset(dest, 0);
186 EmitIType(b, rs, rt, dest_off); 192 EmitIType(b, rs, rt, dest_off);
187 } 193 }
188 } else { 194 } else {
189 const int position = buffer_.Size(); 195 const int position = buffer_.Size();
190 if (FLAG_use_far_branches) { 196 if (use_far_branches()) {
191 const uint32_t dest_off = label->position_; 197 const uint32_t dest_off = label->position_;
192 EmitFarBranch(b, rs, rt, dest_off); 198 EmitFarBranch(b, rs, rt, dest_off);
193 } else { 199 } else {
194 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); 200 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0);
195 EmitIType(b, rs, rt, dest_off); 201 EmitIType(b, rs, rt, dest_off);
196 } 202 }
197 label->LinkTo(position); 203 label->LinkTo(position);
198 } 204 }
199 } 205 }
200 206
201 207
202 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { 208 void Assembler::EmitRegImmBranch(RtRegImm b, Register rs, Label* label) {
203 if (label->IsBound()) { 209 if (label->IsBound()) {
204 // Relative destination from an instruction after the branch. 210 // Relative destination from an instruction after the branch.
205 const int32_t dest = 211 const int32_t dest =
206 label->Position() - (buffer_.Size() + Instr::kInstrSize); 212 label->Position() - (buffer_.Size() + Instr::kInstrSize);
207 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { 213 if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
208 EmitFarRegImmBranch(b, rs, label->Position()); 214 EmitFarRegImmBranch(b, rs, label->Position());
209 } else { 215 } else {
210 const uint16_t dest_off = EncodeBranchOffset(dest, 0); 216 const uint16_t dest_off = EncodeBranchOffset(dest, 0);
211 EmitRegImmType(REGIMM, rs, b, dest_off); 217 EmitRegImmType(REGIMM, rs, b, dest_off);
212 } 218 }
213 } else { 219 } else {
214 const int position = buffer_.Size(); 220 const int position = buffer_.Size();
215 if (FLAG_use_far_branches) { 221 if (use_far_branches()) {
216 const uint32_t dest_off = label->position_; 222 const uint32_t dest_off = label->position_;
217 EmitFarRegImmBranch(b, rs, dest_off); 223 EmitFarRegImmBranch(b, rs, dest_off);
218 } else { 224 } else {
219 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); 225 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0);
220 EmitRegImmType(REGIMM, rs, b, dest_off); 226 EmitRegImmType(REGIMM, rs, b, dest_off);
221 } 227 }
222 label->LinkTo(position); 228 label->LinkTo(position);
223 } 229 }
224 } 230 }
225 231
226 232
227 void Assembler::EmitFpuBranch(bool kind, Label *label) { 233 void Assembler::EmitFpuBranch(bool kind, Label *label) {
228 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. 234 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true.
229 if (label->IsBound()) { 235 if (label->IsBound()) {
230 // Relative destination from an instruction after the branch. 236 // Relative destination from an instruction after the branch.
231 const int32_t dest = 237 const int32_t dest =
232 label->Position() - (buffer_.Size() + Instr::kInstrSize); 238 label->Position() - (buffer_.Size() + Instr::kInstrSize);
233 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { 239 if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
234 EmitFarFpuBranch(kind, label->Position()); 240 EmitFarFpuBranch(kind, label->Position());
235 } else { 241 } else {
236 const uint16_t dest_off = EncodeBranchOffset(dest, 0); 242 const uint16_t dest_off = EncodeBranchOffset(dest, 0);
237 Emit(COP1 << kOpcodeShift | 243 Emit(COP1 << kOpcodeShift |
238 COP1_BC << kCop1SubShift | 244 COP1_BC << kCop1SubShift |
239 b16 | 245 b16 |
240 dest_off); 246 dest_off);
241 } 247 }
242 } else { 248 } else {
243 const int position = buffer_.Size(); 249 const int position = buffer_.Size();
244 if (FLAG_use_far_branches) { 250 if (use_far_branches()) {
245 const uint32_t dest_off = label->position_; 251 const uint32_t dest_off = label->position_;
246 EmitFarFpuBranch(kind, dest_off); 252 EmitFarFpuBranch(kind, dest_off);
247 } else { 253 } else {
248 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); 254 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0);
249 Emit(COP1 << kOpcodeShift | 255 Emit(COP1 << kOpcodeShift |
250 COP1_BC << kCop1SubShift | 256 COP1_BC << kCop1SubShift |
251 b16 | 257 b16 |
252 dest_off); 258 dest_off);
253 } 259 }
254 label->LinkTo(position); 260 label->LinkTo(position);
(...skipping 17 matching lines...) Expand all
272 278
273 279
274 void Assembler::Bind(Label* label) { 280 void Assembler::Bind(Label* label) {
275 ASSERT(!label->IsBound()); 281 ASSERT(!label->IsBound());
276 int bound_pc = buffer_.Size(); 282 int bound_pc = buffer_.Size();
277 283
278 while (label->IsLinked()) { 284 while (label->IsLinked()) {
279 int32_t position = label->Position(); 285 int32_t position = label->Position();
280 int32_t dest = bound_pc - (position + Instr::kInstrSize); 286 int32_t dest = bound_pc - (position + Instr::kInstrSize);
281 287
282 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { 288 if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
283 // Far branches are enabled and we can't encode the branch offset. 289 // Far branches are enabled and we can't encode the branch offset.
284 290
285 // Grab the branch instruction. We'll need to flip it later. 291 // Grab the branch instruction. We'll need to flip it later.
286 const int32_t branch = buffer_.Load<int32_t>(position); 292 const int32_t branch = buffer_.Load<int32_t>(position);
287 293
288 // Grab instructions that load the offset. 294 // Grab instructions that load the offset.
289 const int32_t high = 295 const int32_t high =
290 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); 296 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
291 const int32_t low = 297 const int32_t low =
292 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); 298 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
293 299
294 // Change from relative to the branch to relative to the assembler buffer. 300 // Change from relative to the branch to relative to the assembler buffer.
295 dest = buffer_.Size(); 301 dest = buffer_.Size();
296 const int32_t encoded_low = 302 const int32_t encoded_low =
297 EncodeLoadImmediate(dest & kBranchOffsetMask, low); 303 EncodeLoadImmediate(dest & kBranchOffsetMask, low);
298 const int32_t encoded_high = 304 const int32_t encoded_high =
299 EncodeLoadImmediate(dest >> 16, high); 305 EncodeLoadImmediate(dest >> 16, high);
300 306
301 // Skip the unconditional far jump if the test fails by flipping the 307 // Skip the unconditional far jump if the test fails by flipping the
302 // sense of the branch instruction. 308 // sense of the branch instruction.
303 buffer_.Store<int32_t>(position, FlipBranchInstruction(branch)); 309 buffer_.Store<int32_t>(position, FlipBranchInstruction(branch));
304 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, encoded_high); 310 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, encoded_high);
305 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, encoded_low); 311 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, encoded_low);
306 label->position_ = DecodeLoadImmediate(low, high); 312 label->position_ = DecodeLoadImmediate(low, high);
307 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) { 313 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) {
308 // We assembled a far branch, but we don't need it. Replace with a near 314 // We assembled a far branch, but we don't need it. Replace with a near
309 // branch. 315 // branch.
310 316
311 // Grab the link to the next branch. 317 // Grab the link to the next branch.
312 const int32_t high = 318 const int32_t high =
313 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); 319 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
314 const int32_t low = 320 const int32_t low =
315 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); 321 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
316 322
317 // Grab the original branch instruction. 323 // Grab the original branch instruction.
(...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 Bind(&msg); 978 Bind(&msg);
973 break_(Instr::kMsgMessageCode); 979 break_(Instr::kMsgMessageCode);
974 } 980 }
975 #endif 981 #endif
976 } 982 }
977 983
978 } // namespace dart 984 } // namespace dart
979 985
980 #endif // defined TARGET_ARCH_MIPS 986 #endif // defined TARGET_ARCH_MIPS
981 987
OLDNEW
« no previous file with comments | « runtime/vm/assembler_mips.h ('k') | runtime/vm/assembler_x64.h » ('j') | runtime/vm/compiler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698