| OLD | NEW |
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
| 2 // All Rights Reserved. | 2 // All Rights Reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
| 9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
| 10 // | 10 // |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 // The original source code covered by the above license above has been | 31 // The original source code covered by the above license above has been |
| 32 // modified significantly by Google Inc. | 32 // modified significantly by Google Inc. |
| 33 // Copyright 2012 the V8 project authors. All rights reserved. | 33 // Copyright 2012 the V8 project authors. All rights reserved. |
| 34 | 34 |
| 35 | 35 |
| 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ | 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ |
| 37 #define V8_MIPS_ASSEMBLER_MIPS_H_ | 37 #define V8_MIPS_ASSEMBLER_MIPS_H_ |
| 38 | 38 |
| 39 #include <stdio.h> | 39 #include <stdio.h> |
| 40 | |
| 41 #include "src/assembler.h" | 40 #include "src/assembler.h" |
| 42 #include "src/mips/constants-mips.h" | 41 #include "src/mips64/constants-mips64.h" |
| 43 #include "src/serialize.h" | 42 #include "src/serialize.h" |
| 44 | 43 |
| 45 namespace v8 { | 44 namespace v8 { |
| 46 namespace internal { | 45 namespace internal { |
| 47 | 46 |
| 48 // CPU Registers. | 47 // CPU Registers. |
| 49 // | 48 // |
| 50 // 1) We would prefer to use an enum, but enum values are assignment- | 49 // 1) We would prefer to use an enum, but enum values are assignment- |
| 51 // compatible with int, which has caused code-generation bugs. | 50 // compatible with int, which has caused code-generation bugs. |
| 52 // | 51 // |
| (...skipping 14 matching lines...) Expand all Loading... |
| 67 // and best performance in optimized code. | 66 // and best performance in optimized code. |
| 68 | 67 |
| 69 | 68 |
| 70 // ----------------------------------------------------------------------------- | 69 // ----------------------------------------------------------------------------- |
| 71 // Implementation of Register and FPURegister. | 70 // Implementation of Register and FPURegister. |
| 72 | 71 |
| 73 // Core register. | 72 // Core register. |
| 74 struct Register { | 73 struct Register { |
| 75 static const int kNumRegisters = v8::internal::kNumRegisters; | 74 static const int kNumRegisters = v8::internal::kNumRegisters; |
| 76 static const int kMaxNumAllocatableRegisters = 14; // v0 through t6 and cp. | 75 static const int kMaxNumAllocatableRegisters = 14; // v0 through t6 and cp. |
| 77 static const int kSizeInBytes = 4; | 76 static const int kSizeInBytes = 8; |
| 78 static const int kCpRegister = 23; // cp (s7) is the 23rd register. | 77 static const int kCpRegister = 23; // cp (s7) is the 23rd register. |
| 79 | 78 |
| 80 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
| 81 static const int kMantissaOffset = 0; | |
| 82 static const int kExponentOffset = 4; | |
| 83 #elif defined(V8_TARGET_BIG_ENDIAN) | |
| 84 static const int kMantissaOffset = 4; | |
| 85 static const int kExponentOffset = 0; | |
| 86 #else | |
| 87 #error Unknown endianness | |
| 88 #endif | |
| 89 | |
| 90 inline static int NumAllocatableRegisters(); | 79 inline static int NumAllocatableRegisters(); |
| 91 | 80 |
| 92 static int ToAllocationIndex(Register reg) { | 81 static int ToAllocationIndex(Register reg) { |
| 93 ASSERT((reg.code() - 2) < (kMaxNumAllocatableRegisters - 1) || | 82 ASSERT((reg.code() - 2) < (kMaxNumAllocatableRegisters - 1) || |
| 94 reg.is(from_code(kCpRegister))); | 83 reg.is(from_code(kCpRegister))); |
| 95 return reg.is(from_code(kCpRegister)) ? | 84 return reg.is(from_code(kCpRegister)) ? |
| 96 kMaxNumAllocatableRegisters - 1 : // Return last index for 'cp'. | 85 kMaxNumAllocatableRegisters - 1 : // Return last index for 'cp'. |
| 97 reg.code() - 2; // zero_reg and 'at' are skipped. | 86 reg.code() - 2; // zero_reg and 'at' are skipped. |
| 98 } | 87 } |
| 99 | 88 |
| 100 static Register FromAllocationIndex(int index) { | 89 static Register FromAllocationIndex(int index) { |
| 101 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); | 90 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); |
| 102 return index == kMaxNumAllocatableRegisters - 1 ? | 91 return index == kMaxNumAllocatableRegisters - 1 ? |
| 103 from_code(kCpRegister) : // Last index is always the 'cp' register. | 92 from_code(kCpRegister) : // Last index is always the 'cp' register. |
| 104 from_code(index + 2); // zero_reg and 'at' are skipped. | 93 from_code(index + 2); // zero_reg and 'at' are skipped. |
| 105 } | 94 } |
| 106 | 95 |
| 107 static const char* AllocationIndexToString(int index) { | 96 static const char* AllocationIndexToString(int index) { |
| 108 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); | 97 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); |
| 109 const char* const names[] = { | 98 const char* const names[] = { |
| 110 "v0", | 99 "v0", |
| 111 "v1", | 100 "v1", |
| 112 "a0", | 101 "a0", |
| 113 "a1", | 102 "a1", |
| 114 "a2", | 103 "a2", |
| 115 "a3", | 104 "a3", |
| 105 "a4", |
| 106 "a5", |
| 107 "a6", |
| 108 "a7", |
| 116 "t0", | 109 "t0", |
| 117 "t1", | 110 "t1", |
| 118 "t2", | 111 "t2", |
| 119 "t3", | |
| 120 "t4", | |
| 121 "t5", | |
| 122 "t6", | |
| 123 "s7", | 112 "s7", |
| 124 }; | 113 }; |
| 125 return names[index]; | 114 return names[index]; |
| 126 } | 115 } |
| 127 | 116 |
| 128 static Register from_code(int code) { | 117 static Register from_code(int code) { |
| 129 Register r = { code }; | 118 Register r = { code }; |
| 130 return r; | 119 return r; |
| 131 } | 120 } |
| 132 | 121 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 155 // at: Reserved for synthetic instructions. | 144 // at: Reserved for synthetic instructions. |
| 156 REGISTER(at, 1); | 145 REGISTER(at, 1); |
| 157 // v0, v1: Used when returning multiple values from subroutines. | 146 // v0, v1: Used when returning multiple values from subroutines. |
| 158 REGISTER(v0, 2); | 147 REGISTER(v0, 2); |
| 159 REGISTER(v1, 3); | 148 REGISTER(v1, 3); |
| 160 // a0 - a4: Used to pass non-FP parameters. | 149 // a0 - a4: Used to pass non-FP parameters. |
| 161 REGISTER(a0, 4); | 150 REGISTER(a0, 4); |
| 162 REGISTER(a1, 5); | 151 REGISTER(a1, 5); |
| 163 REGISTER(a2, 6); | 152 REGISTER(a2, 6); |
| 164 REGISTER(a3, 7); | 153 REGISTER(a3, 7); |
| 165 // t0 - t9: Can be used without reservation, act as temporary registers and are | 154 // a4 - a7 t0 - t3: Can be used without reservation, act as temporary registers |
| 166 // allowed to be destroyed by subroutines. | 155 // and are allowed to be destroyed by subroutines. |
| 167 REGISTER(t0, 8); | 156 REGISTER(a4, 8); |
| 168 REGISTER(t1, 9); | 157 REGISTER(a5, 9); |
| 169 REGISTER(t2, 10); | 158 REGISTER(a6, 10); |
| 170 REGISTER(t3, 11); | 159 REGISTER(a7, 11); |
| 171 REGISTER(t4, 12); | 160 REGISTER(t0, 12); |
| 172 REGISTER(t5, 13); | 161 REGISTER(t1, 13); |
| 173 REGISTER(t6, 14); | 162 REGISTER(t2, 14); |
| 174 REGISTER(t7, 15); | 163 REGISTER(t3, 15); |
| 175 // s0 - s7: Subroutine register variables. Subroutines that write to these | 164 // s0 - s7: Subroutine register variables. Subroutines that write to these |
| 176 // registers must restore their values before exiting so that the caller can | 165 // registers must restore their values before exiting so that the caller can |
| 177 // expect the values to be preserved. | 166 // expect the values to be preserved. |
| 178 REGISTER(s0, 16); | 167 REGISTER(s0, 16); |
| 179 REGISTER(s1, 17); | 168 REGISTER(s1, 17); |
| 180 REGISTER(s2, 18); | 169 REGISTER(s2, 18); |
| 181 REGISTER(s3, 19); | 170 REGISTER(s3, 19); |
| 182 REGISTER(s4, 20); | 171 REGISTER(s4, 20); |
| 183 REGISTER(s5, 21); | 172 REGISTER(s5, 21); |
| 184 REGISTER(s6, 22); | 173 REGISTER(s6, 22); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 } | 220 } |
| 232 | 221 |
| 233 static FPURegister from_code(int code) { | 222 static FPURegister from_code(int code) { |
| 234 FPURegister r = { code }; | 223 FPURegister r = { code }; |
| 235 return r; | 224 return r; |
| 236 } | 225 } |
| 237 | 226 |
| 238 bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; } | 227 bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; } |
| 239 bool is(FPURegister creg) const { return code_ == creg.code_; } | 228 bool is(FPURegister creg) const { return code_ == creg.code_; } |
| 240 FPURegister low() const { | 229 FPURegister low() const { |
| 230 // TODO(plind): Create ASSERT for FR=0 mode. This usage suspect for FR=1. |
| 241 // Find low reg of a Double-reg pair, which is the reg itself. | 231 // Find low reg of a Double-reg pair, which is the reg itself. |
| 242 ASSERT(code_ % 2 == 0); // Specified Double reg must be even. | 232 ASSERT(code_ % 2 == 0); // Specified Double reg must be even. |
| 243 FPURegister reg; | 233 FPURegister reg; |
| 244 reg.code_ = code_; | 234 reg.code_ = code_; |
| 245 ASSERT(reg.is_valid()); | 235 ASSERT(reg.is_valid()); |
| 246 return reg; | 236 return reg; |
| 247 } | 237 } |
| 248 FPURegister high() const { | 238 FPURegister high() const { |
| 239 // TODO(plind): Create ASSERT for FR=0 mode. This usage illegal in FR=1. |
| 249 // Find high reg of a Doubel-reg pair, which is reg + 1. | 240 // Find high reg of a Doubel-reg pair, which is reg + 1. |
| 250 ASSERT(code_ % 2 == 0); // Specified Double reg must be even. | 241 ASSERT(code_ % 2 == 0); // Specified Double reg must be even. |
| 251 FPURegister reg; | 242 FPURegister reg; |
| 252 reg.code_ = code_ + 1; | 243 reg.code_ = code_ + 1; |
| 253 ASSERT(reg.is_valid()); | 244 ASSERT(reg.is_valid()); |
| 254 return reg; | 245 return reg; |
| 255 } | 246 } |
| 256 | 247 |
| 257 int code() const { | 248 int code() const { |
| 258 ASSERT(is_valid()); | 249 ASSERT(is_valid()); |
| 259 return code_; | 250 return code_; |
| 260 } | 251 } |
| 261 int bit() const { | 252 int bit() const { |
| 262 ASSERT(is_valid()); | 253 ASSERT(is_valid()); |
| 263 return 1 << code_; | 254 return 1 << code_; |
| 264 } | 255 } |
| 265 void setcode(int f) { | 256 void setcode(int f) { |
| 266 code_ = f; | 257 code_ = f; |
| 267 ASSERT(is_valid()); | 258 ASSERT(is_valid()); |
| 268 } | 259 } |
| 269 // Unfortunately we can't make this private in a struct. | 260 // Unfortunately we can't make this private in a struct. |
| 270 int code_; | 261 int code_; |
| 271 }; | 262 }; |
| 272 | 263 |
| 273 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32 | 264 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32 |
| 274 // 32-bit registers, f0 through f31. When used as 'double' they are used | 265 // 32-bit registers, f0 through f31. When used as 'double' they are used |
| 275 // in pairs, starting with the even numbered register. So a double operation | 266 // in pairs, starting with the even numbered register. So a double operation |
| 276 // on f0 really uses f0 and f1. | 267 // on f0 really uses f0 and f1. |
| 277 // (Modern mips hardware also supports 32 64-bit registers, via setting | 268 // (Modern mips hardware also supports 32 64-bit registers, via setting |
| 278 // (priviledged) Status Register FR bit to 1. This is used by the N32 ABI, | 269 // (privileged) Status Register FR bit to 1. This is used by the N32 ABI, |
| 279 // but it is not in common use. Someday we will want to support this in v8.) | 270 // but it is not in common use. Someday we will want to support this in v8.) |
| 280 | 271 |
| 281 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. | 272 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. |
| 282 typedef FPURegister DoubleRegister; | 273 typedef FPURegister DoubleRegister; |
| 283 typedef FPURegister FloatRegister; | 274 typedef FPURegister FloatRegister; |
| 284 | 275 |
| 285 const FPURegister no_freg = { -1 }; | 276 const FPURegister no_freg = { -1 }; |
| 286 | 277 |
| 287 const FPURegister f0 = { 0 }; // Return value in hard float mode. | 278 const FPURegister f0 = { 0 }; // Return value in hard float mode. |
| 288 const FPURegister f1 = { 1 }; | 279 const FPURegister f1 = { 1 }; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 // Unfortunately we can't make this private in a struct. | 340 // Unfortunately we can't make this private in a struct. |
| 350 int code_; | 341 int code_; |
| 351 }; | 342 }; |
| 352 | 343 |
| 353 const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister }; | 344 const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister }; |
| 354 const FPUControlRegister FCSR = { kFCSRRegister }; | 345 const FPUControlRegister FCSR = { kFCSRRegister }; |
| 355 | 346 |
| 356 | 347 |
| 357 // ----------------------------------------------------------------------------- | 348 // ----------------------------------------------------------------------------- |
| 358 // Machine instruction Operands. | 349 // Machine instruction Operands. |
| 359 | 350 const int kSmiShift = kSmiTagSize + kSmiShiftSize; |
| 351 const uint64_t kSmiShiftMask = (1UL << kSmiShift) - 1; |
| 360 // Class Operand represents a shifter operand in data processing instructions. | 352 // Class Operand represents a shifter operand in data processing instructions. |
| 361 class Operand BASE_EMBEDDED { | 353 class Operand BASE_EMBEDDED { |
| 362 public: | 354 public: |
| 363 // Immediate. | 355 // Immediate. |
| 364 INLINE(explicit Operand(int32_t immediate, | 356 INLINE(explicit Operand(int64_t immediate, |
| 365 RelocInfo::Mode rmode = RelocInfo::NONE32)); | 357 RelocInfo::Mode rmode = RelocInfo::NONE64)); |
| 366 INLINE(explicit Operand(const ExternalReference& f)); | 358 INLINE(explicit Operand(const ExternalReference& f)); |
| 367 INLINE(explicit Operand(const char* s)); | 359 INLINE(explicit Operand(const char* s)); |
| 368 INLINE(explicit Operand(Object** opp)); | 360 INLINE(explicit Operand(Object** opp)); |
| 369 INLINE(explicit Operand(Context** cpp)); | 361 INLINE(explicit Operand(Context** cpp)); |
| 370 explicit Operand(Handle<Object> handle); | 362 explicit Operand(Handle<Object> handle); |
| 371 INLINE(explicit Operand(Smi* value)); | 363 INLINE(explicit Operand(Smi* value)); |
| 372 | 364 |
| 373 // Register. | 365 // Register. |
| 374 INLINE(explicit Operand(Register rm)); | 366 INLINE(explicit Operand(Register rm)); |
| 375 | 367 |
| 376 // Return true if this is a register operand. | 368 // Return true if this is a register operand. |
| 377 INLINE(bool is_reg() const); | 369 INLINE(bool is_reg() const); |
| 378 | 370 |
| 379 inline int32_t immediate() const { | 371 inline int64_t immediate() const { |
| 380 ASSERT(!is_reg()); | 372 ASSERT(!is_reg()); |
| 381 return imm32_; | 373 return imm64_; |
| 382 } | 374 } |
| 383 | 375 |
| 384 Register rm() const { return rm_; } | 376 Register rm() const { return rm_; } |
| 385 | 377 |
| 386 private: | 378 private: |
| 387 Register rm_; | 379 Register rm_; |
| 388 int32_t imm32_; // Valid if rm_ == no_reg. | 380 int64_t imm64_; // Valid if rm_ == no_reg. |
| 389 RelocInfo::Mode rmode_; | 381 RelocInfo::Mode rmode_; |
| 390 | 382 |
| 391 friend class Assembler; | 383 friend class Assembler; |
| 392 friend class MacroAssembler; | 384 friend class MacroAssembler; |
| 393 }; | 385 }; |
| 394 | 386 |
| 395 | 387 |
| 396 // On MIPS we have only one adressing mode with base_reg + offset. | 388 // On MIPS we have only one adressing mode with base_reg + offset. |
| 397 // Class MemOperand represents a memory operand in load and store instructions. | 389 // Class MemOperand represents a memory operand in load and store instructions. |
| 398 class MemOperand : public Operand { | 390 class MemOperand : public Operand { |
| 399 public: | 391 public: |
| 400 // Immediate value attached to offset. | 392 // Immediate value attached to offset. |
| 401 enum OffsetAddend { | 393 enum OffsetAddend { |
| 402 offset_minus_one = -1, | 394 offset_minus_one = -1, |
| 403 offset_zero = 0 | 395 offset_zero = 0 |
| 404 }; | 396 }; |
| 405 | 397 |
| 406 explicit MemOperand(Register rn, int32_t offset = 0); | 398 explicit MemOperand(Register rn, int64_t offset = 0); |
| 407 explicit MemOperand(Register rn, int32_t unit, int32_t multiplier, | 399 explicit MemOperand(Register rn, int64_t unit, int64_t multiplier, |
| 408 OffsetAddend offset_addend = offset_zero); | 400 OffsetAddend offset_addend = offset_zero); |
| 409 int32_t offset() const { return offset_; } | 401 int32_t offset() const { return offset_; } |
| 410 | 402 |
| 411 bool OffsetIsInt16Encodable() const { | 403 bool OffsetIsInt16Encodable() const { |
| 412 return is_int16(offset_); | 404 return is_int16(offset_); |
| 413 } | 405 } |
| 414 | 406 |
| 415 private: | 407 private: |
| 416 int32_t offset_; | 408 int32_t offset_; |
| 417 | 409 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 | 455 |
| 464 // Returns the branch offset to the given label from the current code | 456 // Returns the branch offset to the given label from the current code |
| 465 // position. Links the label to the current position if it is still unbound. | 457 // position. Links the label to the current position if it is still unbound. |
| 466 // Manages the jump elimination optimization if the second parameter is true. | 458 // Manages the jump elimination optimization if the second parameter is true. |
| 467 int32_t branch_offset(Label* L, bool jump_elimination_allowed); | 459 int32_t branch_offset(Label* L, bool jump_elimination_allowed); |
| 468 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { | 460 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { |
| 469 int32_t o = branch_offset(L, jump_elimination_allowed); | 461 int32_t o = branch_offset(L, jump_elimination_allowed); |
| 470 ASSERT((o & 3) == 0); // Assert the offset is aligned. | 462 ASSERT((o & 3) == 0); // Assert the offset is aligned. |
| 471 return o >> 2; | 463 return o >> 2; |
| 472 } | 464 } |
| 473 uint32_t jump_address(Label* L); | 465 uint64_t jump_address(Label* L); |
| 474 | 466 |
| 475 // Puts a labels target address at the given position. | 467 // Puts a labels target address at the given position. |
| 476 // The high 8 bits are set to zero. | 468 // The high 8 bits are set to zero. |
| 477 void label_at_put(Label* L, int at_offset); | 469 void label_at_put(Label* L, int at_offset); |
| 478 | 470 |
| 479 // Read/Modify the code target address in the branch/call instruction at pc. | 471 // Read/Modify the code target address in the branch/call instruction at pc. |
| 480 static Address target_address_at(Address pc); | 472 static Address target_address_at(Address pc); |
| 481 static void set_target_address_at(Address pc, | 473 static void set_target_address_at(Address pc, |
| 482 Address target, | 474 Address target, |
| 483 ICacheFlushMode icache_flush_mode = | 475 ICacheFlushMode icache_flush_mode = |
| (...skipping 30 matching lines...) Expand all Loading... |
| 514 static void JumpLabelToJumpRegister(Address pc); | 506 static void JumpLabelToJumpRegister(Address pc); |
| 515 | 507 |
| 516 static void QuietNaN(HeapObject* nan); | 508 static void QuietNaN(HeapObject* nan); |
| 517 | 509 |
| 518 // This sets the branch destination (which gets loaded at the call address). | 510 // This sets the branch destination (which gets loaded at the call address). |
| 519 // This is for calls and branches within generated code. The serializer | 511 // This is for calls and branches within generated code. The serializer |
| 520 // has already deserialized the lui/ori instructions etc. | 512 // has already deserialized the lui/ori instructions etc. |
| 521 inline static void deserialization_set_special_target_at( | 513 inline static void deserialization_set_special_target_at( |
| 522 Address instruction_payload, Code* code, Address target) { | 514 Address instruction_payload, Code* code, Address target) { |
| 523 set_target_address_at( | 515 set_target_address_at( |
| 524 instruction_payload - kInstructionsFor32BitConstant * kInstrSize, | 516 instruction_payload - kInstructionsFor64BitConstant * kInstrSize, |
| 525 code, | 517 code, |
| 526 target); | 518 target); |
| 527 } | 519 } |
| 528 | 520 |
| 529 // Size of an instruction. | 521 // Size of an instruction. |
| 530 static const int kInstrSize = sizeof(Instr); | 522 static const int kInstrSize = sizeof(Instr); |
| 531 | 523 |
| 532 // Difference between address of current opcode and target address offset. | 524 // Difference between address of current opcode and target address offset. |
| 533 static const int kBranchPCOffset = 4; | 525 static const int kBranchPCOffset = 4; |
| 534 | 526 |
| 535 // Here we are patching the address in the LUI/ORI instruction pair. | 527 // Here we are patching the address in the LUI/ORI instruction pair. |
| 536 // These values are used in the serialization process and must be zero for | 528 // These values are used in the serialization process and must be zero for |
| 537 // MIPS platform, as Code, Embedded Object or External-reference pointers | 529 // MIPS platform, as Code, Embedded Object or External-reference pointers |
| 538 // are split across two consecutive instructions and don't exist separately | 530 // are split across two consecutive instructions and don't exist separately |
| 539 // in the code, so the serializer should not step forwards in memory after | 531 // in the code, so the serializer should not step forwards in memory after |
| 540 // a target is resolved and written. | 532 // a target is resolved and written. |
| 541 static const int kSpecialTargetSize = 0; | 533 static const int kSpecialTargetSize = 0; |
| 542 | 534 |
| 543 // Number of consecutive instructions used to store 32bit constant. | 535 // Number of consecutive instructions used to store 32bit/64bit constant. |
| 544 // Before jump-optimizations, this constant was used in | 536 // Before jump-optimizations, this constant was used in |
| 545 // RelocInfo::target_address_address() function to tell serializer address of | 537 // RelocInfo::target_address_address() function to tell serializer address of |
| 546 // the instruction that follows LUI/ORI instruction pair. Now, with new jump | 538 // the instruction that follows LUI/ORI instruction pair. Now, with new jump |
| 547 // optimization, where jump-through-register instruction that usually | 539 // optimization, where jump-through-register instruction that usually |
| 548 // follows LUI/ORI pair is substituted with J/JAL, this constant equals | 540 // follows LUI/ORI pair is substituted with J/JAL, this constant equals |
| 549 // to 3 instructions (LUI+ORI+J/JAL/JR/JALR). | 541 // to 3 instructions (LUI+ORI+J/JAL/JR/JALR). |
| 550 static const int kInstructionsFor32BitConstant = 3; | 542 static const int kInstructionsFor32BitConstant = 3; |
| 543 static const int kInstructionsFor64BitConstant = 5; |
| 551 | 544 |
| 552 // Distance between the instruction referring to the address of the call | 545 // Distance between the instruction referring to the address of the call |
| 553 // target and the return address. | 546 // target and the return address. |
| 554 static const int kCallTargetAddressOffset = 4 * kInstrSize; | 547 static const int kCallTargetAddressOffset = 6 * kInstrSize; |
| 555 | 548 |
| 556 // Distance between start of patched return sequence and the emitted address | 549 // Distance between start of patched return sequence and the emitted address |
| 557 // to jump to. | 550 // to jump to. |
| 558 static const int kPatchReturnSequenceAddressOffset = 0; | 551 static const int kPatchReturnSequenceAddressOffset = 0; |
| 559 | 552 |
| 560 // Distance between start of patched debug break slot and the emitted address | 553 // Distance between start of patched debug break slot and the emitted address |
| 561 // to jump to. | 554 // to jump to. |
| 562 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize; | 555 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize; |
| 563 | 556 |
| 564 // Difference between address of current opcode and value read from pc | 557 // Difference between address of current opcode and value read from pc |
| 565 // register. | 558 // register. |
| 566 static const int kPcLoadDelta = 4; | 559 static const int kPcLoadDelta = 4; |
| 567 | 560 |
| 568 static const int kPatchDebugBreakSlotReturnOffset = 4 * kInstrSize; | 561 static const int kPatchDebugBreakSlotReturnOffset = 6 * kInstrSize; |
| 569 | 562 |
| 570 // Number of instructions used for the JS return sequence. The constant is | 563 // Number of instructions used for the JS return sequence. The constant is |
| 571 // used by the debugger to patch the JS return sequence. | 564 // used by the debugger to patch the JS return sequence. |
| 572 static const int kJSReturnSequenceInstructions = 7; | 565 static const int kJSReturnSequenceInstructions = 7; |
| 573 static const int kDebugBreakSlotInstructions = 4; | 566 static const int kDebugBreakSlotInstructions = 6; |
| 574 static const int kDebugBreakSlotLength = | 567 static const int kDebugBreakSlotLength = |
| 575 kDebugBreakSlotInstructions * kInstrSize; | 568 kDebugBreakSlotInstructions * kInstrSize; |
| 576 | 569 |
| 577 | 570 |
| 578 // --------------------------------------------------------------------------- | 571 // --------------------------------------------------------------------------- |
| 579 // Code generation. | 572 // Code generation. |
| 580 | 573 |
| 581 // Insert the smallest number of nop instructions | 574 // Insert the smallest number of nop instructions |
| 582 // possible to align the pc offset to a multiple | 575 // possible to align the pc offset to a multiple |
| 583 // of m. m must be a power of 2 (>= 4). | 576 // of m. m must be a power of 2 (>= 4). |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 631 void bltzal(Register rs, int16_t offset); | 624 void bltzal(Register rs, int16_t offset); |
| 632 void bne(Register rs, Register rt, int16_t offset); | 625 void bne(Register rs, Register rt, int16_t offset); |
| 633 void bne(Register rs, Register rt, Label* L) { | 626 void bne(Register rs, Register rt, Label* L) { |
| 634 bne(rs, rt, branch_offset(L, false)>>2); | 627 bne(rs, rt, branch_offset(L, false)>>2); |
| 635 } | 628 } |
| 636 | 629 |
| 637 // Never use the int16_t b(l)cond version with a branch offset | 630 // Never use the int16_t b(l)cond version with a branch offset |
| 638 // instead of using the Label* version. | 631 // instead of using the Label* version. |
| 639 | 632 |
| 640 // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits. | 633 // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits. |
| 641 void j(int32_t target); | 634 void j(int64_t target); |
| 642 void jal(int32_t target); | 635 void jal(int64_t target); |
| 643 void jalr(Register rs, Register rd = ra); | 636 void jalr(Register rs, Register rd = ra); |
| 644 void jr(Register target); | 637 void jr(Register target); |
| 645 void j_or_jr(int32_t target, Register rs); | 638 void j_or_jr(int64_t target, Register rs); |
| 646 void jal_or_jalr(int32_t target, Register rs); | 639 void jal_or_jalr(int64_t target, Register rs); |
| 647 | 640 |
| 648 | 641 |
| 649 // -------Data-processing-instructions--------- | 642 // -------Data-processing-instructions--------- |
| 650 | 643 |
| 651 // Arithmetic. | 644 // Arithmetic. |
| 652 void addu(Register rd, Register rs, Register rt); | 645 void addu(Register rd, Register rs, Register rt); |
| 653 void subu(Register rd, Register rs, Register rt); | 646 void subu(Register rd, Register rs, Register rt); |
| 654 void mult(Register rs, Register rt); | 647 void mult(Register rs, Register rt); |
| 655 void multu(Register rs, Register rt); | 648 void multu(Register rs, Register rt); |
| 656 void div(Register rs, Register rt); | 649 void div(Register rs, Register rt); |
| 657 void divu(Register rs, Register rt); | 650 void divu(Register rs, Register rt); |
| 658 void mul(Register rd, Register rs, Register rt); | 651 void mul(Register rd, Register rs, Register rt); |
| 652 void daddu(Register rd, Register rs, Register rt); |
| 653 void dsubu(Register rd, Register rs, Register rt); |
| 654 void dmult(Register rs, Register rt); |
| 655 void dmultu(Register rs, Register rt); |
| 656 void ddiv(Register rs, Register rt); |
| 657 void ddivu(Register rs, Register rt); |
| 659 | 658 |
| 660 void addiu(Register rd, Register rs, int32_t j); | 659 void addiu(Register rd, Register rs, int32_t j); |
| 660 void daddiu(Register rd, Register rs, int32_t j); |
| 661 | 661 |
| 662 // Logical. | 662 // Logical. |
| 663 void and_(Register rd, Register rs, Register rt); | 663 void and_(Register rd, Register rs, Register rt); |
| 664 void or_(Register rd, Register rs, Register rt); | 664 void or_(Register rd, Register rs, Register rt); |
| 665 void xor_(Register rd, Register rs, Register rt); | 665 void xor_(Register rd, Register rs, Register rt); |
| 666 void nor(Register rd, Register rs, Register rt); | 666 void nor(Register rd, Register rs, Register rt); |
| 667 | 667 |
| 668 void andi(Register rd, Register rs, int32_t j); | 668 void andi(Register rd, Register rs, int32_t j); |
| 669 void ori(Register rd, Register rs, int32_t j); | 669 void ori(Register rd, Register rs, int32_t j); |
| 670 void xori(Register rd, Register rs, int32_t j); | 670 void xori(Register rd, Register rs, int32_t j); |
| 671 void lui(Register rd, int32_t j); | 671 void lui(Register rd, int32_t j); |
| 672 | 672 |
| 673 // Shifts. | 673 // Shifts. |
| 674 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop | 674 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop |
| 675 // and may cause problems in normal code. coming_from_nop makes sure this | 675 // and may cause problems in normal code. coming_from_nop makes sure this |
| 676 // doesn't happen. | 676 // doesn't happen. |
| 677 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false); | 677 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false); |
| 678 void sllv(Register rd, Register rt, Register rs); | 678 void sllv(Register rd, Register rt, Register rs); |
| 679 void srl(Register rd, Register rt, uint16_t sa); | 679 void srl(Register rd, Register rt, uint16_t sa); |
| 680 void srlv(Register rd, Register rt, Register rs); | 680 void srlv(Register rd, Register rt, Register rs); |
| 681 void sra(Register rt, Register rd, uint16_t sa); | 681 void sra(Register rt, Register rd, uint16_t sa); |
| 682 void srav(Register rt, Register rd, Register rs); | 682 void srav(Register rt, Register rd, Register rs); |
| 683 void rotr(Register rd, Register rt, uint16_t sa); | 683 void rotr(Register rd, Register rt, uint16_t sa); |
| 684 void rotrv(Register rd, Register rt, Register rs); | 684 void rotrv(Register rd, Register rt, Register rs); |
| 685 void dsll(Register rd, Register rt, uint16_t sa); |
| 686 void dsllv(Register rd, Register rt, Register rs); |
| 687 void dsrl(Register rd, Register rt, uint16_t sa); |
| 688 void dsrlv(Register rd, Register rt, Register rs); |
| 689 void drotr(Register rd, Register rt, uint16_t sa); |
| 690 void drotrv(Register rd, Register rt, Register rs); |
| 691 void dsra(Register rt, Register rd, uint16_t sa); |
| 692 void dsrav(Register rd, Register rt, Register rs); |
| 693 void dsll32(Register rt, Register rd, uint16_t sa); |
| 694 void dsrl32(Register rt, Register rd, uint16_t sa); |
| 695 void dsra32(Register rt, Register rd, uint16_t sa); |
| 685 | 696 |
| 686 | 697 |
| 687 // ------------Memory-instructions------------- | 698 // ------------Memory-instructions------------- |
| 688 | 699 |
| 689 void lb(Register rd, const MemOperand& rs); | 700 void lb(Register rd, const MemOperand& rs); |
| 690 void lbu(Register rd, const MemOperand& rs); | 701 void lbu(Register rd, const MemOperand& rs); |
| 691 void lh(Register rd, const MemOperand& rs); | 702 void lh(Register rd, const MemOperand& rs); |
| 692 void lhu(Register rd, const MemOperand& rs); | 703 void lhu(Register rd, const MemOperand& rs); |
| 693 void lw(Register rd, const MemOperand& rs); | 704 void lw(Register rd, const MemOperand& rs); |
| 705 void lwu(Register rd, const MemOperand& rs); |
| 694 void lwl(Register rd, const MemOperand& rs); | 706 void lwl(Register rd, const MemOperand& rs); |
| 695 void lwr(Register rd, const MemOperand& rs); | 707 void lwr(Register rd, const MemOperand& rs); |
| 696 void sb(Register rd, const MemOperand& rs); | 708 void sb(Register rd, const MemOperand& rs); |
| 697 void sh(Register rd, const MemOperand& rs); | 709 void sh(Register rd, const MemOperand& rs); |
| 698 void sw(Register rd, const MemOperand& rs); | 710 void sw(Register rd, const MemOperand& rs); |
| 699 void swl(Register rd, const MemOperand& rs); | 711 void swl(Register rd, const MemOperand& rs); |
| 700 void swr(Register rd, const MemOperand& rs); | 712 void swr(Register rd, const MemOperand& rs); |
| 713 void ldl(Register rd, const MemOperand& rs); |
| 714 void ldr(Register rd, const MemOperand& rs); |
| 715 void sdl(Register rd, const MemOperand& rs); |
| 716 void sdr(Register rd, const MemOperand& rs); |
| 717 void ld(Register rd, const MemOperand& rs); |
| 718 void sd(Register rd, const MemOperand& rs); |
| 701 | 719 |
| 702 | 720 |
| 703 // ----------------Prefetch-------------------- | 721 // ----------------Prefetch-------------------- |
| 704 | 722 |
| 705 void pref(int32_t hint, const MemOperand& rs); | 723 void pref(int32_t hint, const MemOperand& rs); |
| 706 | 724 |
| 707 | 725 |
| 708 // -------------Misc-instructions-------------- | 726 // -------------Misc-instructions-------------- |
| 709 | 727 |
| 710 // Break / Trap instructions. | 728 // Break / Trap instructions. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 741 // --------Coprocessor-instructions---------------- | 759 // --------Coprocessor-instructions---------------- |
| 742 | 760 |
| 743 // Load, store, and move. | 761 // Load, store, and move. |
| 744 void lwc1(FPURegister fd, const MemOperand& src); | 762 void lwc1(FPURegister fd, const MemOperand& src); |
| 745 void ldc1(FPURegister fd, const MemOperand& src); | 763 void ldc1(FPURegister fd, const MemOperand& src); |
| 746 | 764 |
| 747 void swc1(FPURegister fs, const MemOperand& dst); | 765 void swc1(FPURegister fs, const MemOperand& dst); |
| 748 void sdc1(FPURegister fs, const MemOperand& dst); | 766 void sdc1(FPURegister fs, const MemOperand& dst); |
| 749 | 767 |
| 750 void mtc1(Register rt, FPURegister fs); | 768 void mtc1(Register rt, FPURegister fs); |
| 769 void mthc1(Register rt, FPURegister fs); |
| 770 void dmtc1(Register rt, FPURegister fs); |
| 771 |
| 751 void mfc1(Register rt, FPURegister fs); | 772 void mfc1(Register rt, FPURegister fs); |
| 773 void mfhc1(Register rt, FPURegister fs); |
| 774 void dmfc1(Register rt, FPURegister fs); |
| 752 | 775 |
| 753 void ctc1(Register rt, FPUControlRegister fs); | 776 void ctc1(Register rt, FPUControlRegister fs); |
| 754 void cfc1(Register rt, FPUControlRegister fs); | 777 void cfc1(Register rt, FPUControlRegister fs); |
| 755 | 778 |
| 756 // Arithmetic. | 779 // Arithmetic. |
| 757 void add_d(FPURegister fd, FPURegister fs, FPURegister ft); | 780 void add_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 758 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft); | 781 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 759 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft); | 782 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 760 void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); | 783 void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); |
| 761 void div_d(FPURegister fd, FPURegister fs, FPURegister ft); | 784 void div_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 970 | 993 |
| 971 // Generate the constant pool for the generated code. | 994 // Generate the constant pool for the generated code. |
| 972 void PopulateConstantPool(ConstantPoolArray* constant_pool); | 995 void PopulateConstantPool(ConstantPoolArray* constant_pool); |
| 973 | 996 |
| 974 protected: | 997 protected: |
| 975 // Relocation for a type-recording IC has the AST id added to it. This | 998 // Relocation for a type-recording IC has the AST id added to it. This |
| 976 // member variable is a way to pass the information from the call site to | 999 // member variable is a way to pass the information from the call site to |
| 977 // the relocation info. | 1000 // the relocation info. |
| 978 TypeFeedbackId recorded_ast_id_; | 1001 TypeFeedbackId recorded_ast_id_; |
| 979 | 1002 |
| 980 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } | 1003 int64_t buffer_space() const { return reloc_info_writer.pos() - pc_; } |
| 981 | 1004 |
| 982 // Decode branch instruction at pos and return branch target pos. | 1005 // Decode branch instruction at pos and return branch target pos. |
| 983 int target_at(int32_t pos); | 1006 int64_t target_at(int64_t pos); |
| 984 | 1007 |
| 985 // Patch branch instruction at pos to branch to given branch target pos. | 1008 // Patch branch instruction at pos to branch to given branch target pos. |
| 986 void target_at_put(int32_t pos, int32_t target_pos); | 1009 void target_at_put(int64_t pos, int64_t target_pos); |
| 987 | 1010 |
| 988 // Say if we need to relocate with this mode. | 1011 // Say if we need to relocate with this mode. |
| 989 bool MustUseReg(RelocInfo::Mode rmode); | 1012 bool MustUseReg(RelocInfo::Mode rmode); |
| 990 | 1013 |
| 991 // Record reloc info for current pc_. | 1014 // Record reloc info for current pc_. |
| 992 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); | 1015 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); |
| 993 | 1016 |
| 994 // Block the emission of the trampoline pool before pc_offset. | 1017 // Block the emission of the trampoline pool before pc_offset. |
| 995 void BlockTrampolinePoolBefore(int pc_offset) { | 1018 void BlockTrampolinePoolBefore(int pc_offset) { |
| 996 if (no_trampoline_pool_before_ < pc_offset) | 1019 if (no_trampoline_pool_before_ < pc_offset) |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1070 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 1093 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
| 1071 RelocInfoWriter reloc_info_writer; | 1094 RelocInfoWriter reloc_info_writer; |
| 1072 | 1095 |
| 1073 // The bound position, before this we cannot do instruction elimination. | 1096 // The bound position, before this we cannot do instruction elimination. |
| 1074 int last_bound_pos_; | 1097 int last_bound_pos_; |
| 1075 | 1098 |
| 1076 // Code emission. | 1099 // Code emission. |
| 1077 inline void CheckBuffer(); | 1100 inline void CheckBuffer(); |
| 1078 void GrowBuffer(); | 1101 void GrowBuffer(); |
| 1079 inline void emit(Instr x); | 1102 inline void emit(Instr x); |
| 1103 inline void emit(uint64_t x); |
| 1080 inline void CheckTrampolinePoolQuick(); | 1104 inline void CheckTrampolinePoolQuick(); |
| 1081 | 1105 |
| 1082 // Instruction generation. | 1106 // Instruction generation. |
| 1083 // We have 3 different kind of encoding layout on MIPS. | 1107 // We have 3 different kind of encoding layout on MIPS. |
| 1084 // However due to many different types of objects encoded in the same fields | 1108 // However due to many different types of objects encoded in the same fields |
| 1085 // we have quite a few aliases for each mode. | 1109 // we have quite a few aliases for each mode. |
| 1086 // Using the same structure to refer to Register and FPURegister would spare a | 1110 // Using the same structure to refer to Register and FPURegister would spare a |
| 1087 // few aliases, but mixing both does not look clean to me. | 1111 // few aliases, but mixing both does not look clean to me. |
| 1088 // Anyway we could surely implement this differently. | 1112 // Anyway we could surely implement this differently. |
| 1089 | 1113 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1206 }; | 1230 }; |
| 1207 | 1231 |
| 1208 int32_t get_trampoline_entry(int32_t pos); | 1232 int32_t get_trampoline_entry(int32_t pos); |
| 1209 int unbound_labels_count_; | 1233 int unbound_labels_count_; |
| 1210 // If trampoline is emitted, generated code is becoming large. As this is | 1234 // If trampoline is emitted, generated code is becoming large. As this is |
| 1211 // already a slow case which can possibly break our code generation for the | 1235 // already a slow case which can possibly break our code generation for the |
| 1212 // extreme case, we use this information to trigger different mode of | 1236 // extreme case, we use this information to trigger different mode of |
| 1213 // branch instruction generation, where we use jump instructions rather | 1237 // branch instruction generation, where we use jump instructions rather |
| 1214 // than regular branch instructions. | 1238 // than regular branch instructions. |
| 1215 bool trampoline_emitted_; | 1239 bool trampoline_emitted_; |
| 1216 static const int kTrampolineSlotsSize = 4 * kInstrSize; | 1240 static const int kTrampolineSlotsSize = 6 * kInstrSize; |
| 1217 static const int kMaxBranchOffset = (1 << (18 - 1)) - 1; | 1241 static const int kMaxBranchOffset = (1 << (18 - 1)) - 1; |
| 1218 static const int kInvalidSlotPos = -1; | 1242 static const int kInvalidSlotPos = -1; |
| 1219 | 1243 |
| 1220 Trampoline trampoline_; | 1244 Trampoline trampoline_; |
| 1221 bool internal_trampoline_exception_; | 1245 bool internal_trampoline_exception_; |
| 1222 | 1246 |
| 1223 friend class RegExpMacroAssemblerMIPS; | 1247 friend class RegExpMacroAssemblerMIPS; |
| 1224 friend class RelocInfo; | 1248 friend class RelocInfo; |
| 1225 friend class CodePatcher; | 1249 friend class CodePatcher; |
| 1226 friend class BlockTrampolinePoolScope; | 1250 friend class BlockTrampolinePoolScope; |
| 1227 | 1251 |
| 1228 PositionsRecorder positions_recorder_; | 1252 PositionsRecorder positions_recorder_; |
| 1229 friend class PositionsRecorder; | 1253 friend class PositionsRecorder; |
| 1230 friend class EnsureSpace; | 1254 friend class EnsureSpace; |
| 1231 }; | 1255 }; |
| 1232 | 1256 |
| 1233 | 1257 |
| 1234 class EnsureSpace BASE_EMBEDDED { | 1258 class EnsureSpace BASE_EMBEDDED { |
| 1235 public: | 1259 public: |
| 1236 explicit EnsureSpace(Assembler* assembler) { | 1260 explicit EnsureSpace(Assembler* assembler) { |
| 1237 assembler->CheckBuffer(); | 1261 assembler->CheckBuffer(); |
| 1238 } | 1262 } |
| 1239 }; | 1263 }; |
| 1240 | 1264 |
| 1241 } } // namespace v8::internal | 1265 } } // namespace v8::internal |
| 1242 | 1266 |
| 1243 #endif // V8_ARM_ASSEMBLER_MIPS_H_ | 1267 #endif // V8_ARM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |