1 // Copyright (c) 1994-2006 Sun Microsystems Inc. 2 // All Rights Reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // - Redistributions of source code must retain the above copyright notice, 9 // this list of conditions and the following disclaimer. 10 // 11 // - Redistribution in binary form must reproduce the above copyright 12 // notice, this list of conditions and the following disclaimer in the 13 // documentation and/or other materials provided with the distribution. 14 // 15 // - Neither the name of Sun Microsystems or the names of contributors may 16 // be used to endorse or promote products derived from this software without 17 // specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // The original source code covered by the above license above has been 32 // modified significantly by Google Inc. 33 // Copyright 2010 the V8 project authors. All rights reserved. 34 35 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ 37 #define V8_MIPS_ASSEMBLER_MIPS_H_ 38 39 #include <stdio.h> 40 #include "assembler.h" 41 #include "constants-mips.h" 42 #include "serialize.h" 43 44 using namespace assembler::mips; 45 46 namespace v8 { 47 namespace internal { 48 49 // CPU Registers. 50 // 51 // 1) We would prefer to use an enum, but enum values are assignment- 52 // compatible with int, which has caused code-generation bugs. 53 // 54 // 2) We would prefer to use a class instead of a struct but we don't like 55 // the register initialization to depend on the particular initialization 56 // order (which appears to be different on OS X, Linux, and Windows for the 57 // installed versions of C++ we tried). Using a struct permits C-style 58 // "initialization". Also, the Register objects cannot be const as this 59 // forces initialization stubs in MSVC, making us dependent on initialization 60 // order. 61 // 62 // 3) By not using an enum, we are possibly preventing the compiler from 63 // doing certain constant folds, which may significantly reduce the 64 // code generated for some assembly instructions (because they boil down 65 // to a few constants). If this is a problem, we could change the code 66 // such that we use an enum in optimized mode, and the struct in debug 67 // mode. This way we get the compile-time error checking in debug mode 68 // and best performance in optimized code. 69 70 71 // ----------------------------------------------------------------------------- 72 // Implementation of Register and FPURegister 73 74 // Core register. 75 struct Register { 76 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } 77 bool is(Register reg) const { return code_ == reg.code_; } 78 int code() const { 79 ASSERT(is_valid()); 80 return code_; 81 } 82 int bit() const { 83 ASSERT(is_valid()); 84 return 1 << code_; 85 } 86 87 // Unfortunately we can't make this private in a struct. 88 int code_; 89 }; 90 91 extern const Register no_reg; 92 93 extern const Register zero_reg; 94 extern const Register at; 95 extern const Register v0; 96 extern const Register v1; 97 extern const Register a0; 98 extern const Register a1; 99 extern const Register a2; 100 extern const Register a3; 101 extern const Register t0; 102 extern const Register t1; 103 extern const Register t2; 104 extern const Register t3; 105 extern const Register t4; 106 extern const Register t5; 107 extern const Register t6; 108 extern const Register t7; 109 extern const Register s0; 110 extern const Register s1; 111 extern const Register s2; 112 extern const Register s3; 113 extern const Register s4; 114 extern const Register s5; 115 extern const Register s6; 116 extern const Register s7; 117 extern const Register t8; 118 extern const Register t9; 119 extern const Register k0; 120 extern const Register k1; 121 extern const Register gp; 122 extern const Register sp; 123 extern const Register s8_fp; 124 extern const Register ra; 125 126 int ToNumber(Register reg); 127 128 Register ToRegister(int num); 129 130 // Coprocessor register. 131 struct FPURegister { 132 bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegister ; } 133 bool is(FPURegister creg) const { return code_ == creg.code_; } 134 int code() const { 135 ASSERT(is_valid()); 136 return code_; 137 } 138 int bit() const { 139 ASSERT(is_valid()); 140 return 1 << code_; 141 } 142 143 // Unfortunately we can't make this private in a struct. 144 int code_; 145 }; 146 147 extern const FPURegister no_creg; 148 149 extern const FPURegister f0; 150 extern const FPURegister f1; 151 extern const FPURegister f2; 152 extern const FPURegister f3; 153 extern const FPURegister f4; 154 extern const FPURegister f5; 155 extern const FPURegister f6; 156 extern const FPURegister f7; 157 extern const FPURegister f8; 158 extern const FPURegister f9; 159 extern const FPURegister f10; 160 extern const FPURegister f11; 161 extern const FPURegister f12; // arg 162 extern const FPURegister f13; 163 extern const FPURegister f14; // arg 164 extern const FPURegister f15; 165 extern const FPURegister f16; 166 extern const FPURegister f17; 167 extern const FPURegister f18; 168 extern const FPURegister f19; 169 extern const FPURegister f20; 170 extern const FPURegister f21; 171 extern const FPURegister f22; 172 extern const FPURegister f23; 173 extern const FPURegister f24; 174 extern const FPURegister f25; 175 extern const FPURegister f26; 176 extern const FPURegister f27; 177 extern const FPURegister f28; 178 extern const FPURegister f29; 179 extern const FPURegister f30; 180 extern const FPURegister f31; 181 182 183 // Returns the equivalent of !cc. 184 // Negation of the default no_condition (-1) results in a non-default 185 // no_condition value (-2). As long as tests for no_condition check 186 // for condition < 0, this will work as expected. 187 inline Condition NegateCondition(Condition cc); 188 189 inline Condition ReverseCondition(Condition cc) { 190 switch (cc) { 191 case Uless: 192 return Ugreater; 193 case Ugreater: 194 return Uless; 195 case Ugreater_equal: 196 return Uless_equal; 197 case Uless_equal: 198 return Ugreater_equal; 199 case less: 200 return greater; 201 case greater: 202 return less; 203 case greater_equal: 204 return less_equal; 205 case less_equal: 206 return greater_equal; 207 default: 208 return cc; 209 }; 210 } 211 212 213 enum Hint { 214 no_hint = 0 215 }; 216 217 inline Hint NegateHint(Hint hint) { 218 return no_hint; 219 } 220 221 222 // ----------------------------------------------------------------------------- 223 // Machine instruction Operands. 224 225 // Class Operand represents a shifter operand in data processing instructions. 226 class Operand BASE_EMBEDDED { 227 public: 228 // Immediate. 229 INLINE(explicit Operand(int32_t immediate, 230 RelocInfo::Mode rmode = RelocInfo::NONE)); 231 INLINE(explicit Operand(const ExternalReference& f)); 232 INLINE(explicit Operand(const char* s)); 233 INLINE(explicit Operand(Object** opp)); 234 INLINE(explicit Operand(Context** cpp)); 235 explicit Operand(Handle<Object> handle); 236 INLINE(explicit Operand(Smi* value)); 237 238 // Register. 239 INLINE(explicit Operand(Register rm)); 240 241 // Return true if this is a register operand. 242 INLINE(bool is_reg() const); 243 244 Register rm() const { return rm_; } 245 246 private: 247 Register rm_; 248 int32_t imm32_; // Valid if rm_ == no_reg 249 RelocInfo::Mode rmode_; 250 251 friend class Assembler; 252 friend class MacroAssembler; 253 }; 254 255 256 // On MIPS we have only one adressing mode with base_reg + offset. 257 // Class MemOperand represents a memory operand in load and store instructions. 258 class MemOperand : public Operand { 259 public: 260 261 explicit MemOperand(Register rn, int16_t offset = 0); 262 263 private: 264 int16_t offset_; 265 266 friend class Assembler; 267 }; 268 269 270 class Assembler : public Malloced { 271 public: 272 // Create an assembler. Instructions and relocation information are emitted 273 // into a buffer, with the instructions starting from the beginning and the 274 // relocation information starting from the end of the buffer. See CodeDesc 275 // for a detailed comment on the layout (globals.h). 276 // 277 // If the provided buffer is NULL, the assembler allocates and grows its own 278 // buffer, and buffer_size determines the initial buffer size. The buffer is 279 // owned by the assembler and deallocated upon destruction of the assembler. 280 // 281 // If the provided buffer is not NULL, the assembler uses the provided buffer 282 // for code generation and assumes its size to be buffer_size. If the buffer 283 // is too small, a fatal error occurs. No deallocation of the buffer is done 284 // upon destruction of the assembler. 285 Assembler(void* buffer, int buffer_size); 286 ~Assembler(); 287 288 // GetCode emits any pending (non-emitted) code and fills the descriptor 289 // desc. GetCode() is idempotent; it returns the same result if no other 290 // Assembler functions are invoked in between GetCode() calls. 291 void GetCode(CodeDesc* desc); 292 293 // Label operations & relative jumps (PPUM Appendix D). 294 // 295 // Takes a branch opcode (cc) and a label (L) and generates 296 // either a backward branch or a forward branch and links it 297 // to the label fixup chain. Usage: 298 // 299 // Label L; // unbound label 300 // j(cc, &L); // forward branch to unbound label 301 // bind(&L); // bind label to the current pc 302 // j(cc, &L); // backward branch to bound label 303 // bind(&L); // illegal: a label may be bound only once 304 // 305 // Note: The same Label can be used for forward and backward branches 306 // but it may be bound only once. 307 void bind(Label* L); // binds an unbound label L to the current code position 308 309 // Returns the branch offset to the given label from the current code position 310 // Links the label to the current position if it is still unbound 311 // Manages the jump elimination optimization if the second parameter is true. 312 int32_t branch_offset(Label* L, bool jump_elimination_allowed); 313 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { 314 int32_t o = branch_offset(L, jump_elimination_allowed); 315 ASSERT((o & 3) == 0); // Assert the offset is aligned. 316 return o >> 2; 317 } 318 319 // Puts a labels target address at the given position. 320 // The high 8 bits are set to zero. 321 void label_at_put(Label* L, int at_offset); 322 323 // Size of an instruction. 324 static const int kInstrSize = sizeof(Instr); 325 326 // Difference between address of current opcode and target address offset. 327 static const int kBranchPCOffset = 4; 328 329 // Read/Modify the code target address in the branch/call instruction at pc. 330 static Address target_address_at(Address pc); 331 static void set_target_address_at(Address pc, Address target); 332 333 // This sets the branch destination (which gets loaded at the call address). 334 // This is for calls and branches within generated code. 335 inline static void set_target_at(Address instruction_payload, 336 Address target) { 337 set_target_address_at(instruction_payload, target); 338 } 339 340 // This sets the branch destination. 341 // This is for calls and branches to runtime code. 342 inline static void set_external_target_at(Address instruction_payload, 343 Address target) { 344 set_target_address_at(instruction_payload, target); 345 } 346 347 static const int kCallTargetSize = 3 * kPointerSize; 348 static const int kExternalTargetSize = 3 * kPointerSize; 349 350 // Distance between the instruction referring to the address of the call 351 // target and the return address. 352 static const int kCallTargetAddressOffset = 4 * kInstrSize; 353 354 // Distance between start of patched return sequence and the emitted address 355 // to jump to. 356 static const int kPatchReturnSequenceAddressOffset = kInstrSize; 357 358 359 // --------------------------------------------------------------------------- 360 // Code generation. 361 362 void nop() { sll(zero_reg, zero_reg, 0); } 363 364 365 //------- Branch and jump instructions -------- 366 // We don't use likely variant of instructions. 367 void b(int16_t offset); 368 void b(Label* L) { b(branch_offset(L, false)>>2); } 369 void bal(int16_t offset); 370 void bal(Label* L) { bal(branch_offset(L, false)>>2); } 371 372 void beq(Register rs, Register rt, int16_t offset); 373 void beq(Register rs, Register rt, Label* L) { 374 beq(rs, rt, branch_offset(L, false) >> 2); 375 } 376 void bgez(Register rs, int16_t offset); 377 void bgezal(Register rs, int16_t offset); 378 void bgtz(Register rs, int16_t offset); 379 void blez(Register rs, int16_t offset); 380 void bltz(Register rs, int16_t offset); 381 void bltzal(Register rs, int16_t offset); 382 void bne(Register rs, Register rt, int16_t offset); 383 void bne(Register rs, Register rt, Label* L) { 384 bne(rs, rt, branch_offset(L, false)>>2); 385 } 386 387 // Never use the int16_t b(l)cond version with a branch offset 388 // instead of using the Label* version. See Twiki for infos. 389 390 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. 391 void j(int32_t target); 392 void jal(int32_t target); 393 void jalr(Register rs, Register rd = ra); 394 void jr(Register target); 395 396 397 //-------Data-processing-instructions--------- 398 399 // Arithmetic. 400 void add(Register rd, Register rs, Register rt); 401 void addu(Register rd, Register rs, Register rt); 402 void sub(Register rd, Register rs, Register rt); 403 void subu(Register rd, Register rs, Register rt); 404 void mult(Register rs, Register rt); 405 void multu(Register rs, Register rt); 406 void div(Register rs, Register rt); 407 void divu(Register rs, Register rt); 408 void mul(Register rd, Register rs, Register rt); 409 410 void addi(Register rd, Register rs, int32_t j); 411 void addiu(Register rd, Register rs, int32_t j); 412 413 // Logical. 414 void and_(Register rd, Register rs, Register rt); 415 void or_(Register rd, Register rs, Register rt); 416 void xor_(Register rd, Register rs, Register rt); 417 void nor(Register rd, Register rs, Register rt); 418 419 void andi(Register rd, Register rs, int32_t j); 420 void ori(Register rd, Register rs, int32_t j); 421 void xori(Register rd, Register rs, int32_t j); 422 void lui(Register rd, int32_t j); 423 424 // Shifts. 425 void sll(Register rd, Register rt, uint16_t sa); 426 void sllv(Register rd, Register rt, Register rs); 427 void srl(Register rd, Register rt, uint16_t sa); 428 void srlv(Register rd, Register rt, Register rs); 429 void sra(Register rt, Register rd, uint16_t sa); 430 void srav(Register rt, Register rd, Register rs); 431 432 433 //------------Memory-instructions------------- 434 435 void lb(Register rd, const MemOperand& rs); 436 void lbu(Register rd, const MemOperand& rs); 437 void lw(Register rd, const MemOperand& rs); 438 void sb(Register rd, const MemOperand& rs); 439 void sw(Register rd, const MemOperand& rs); 440 441 442 //-------------Misc-instructions-------------- 443 444 // Break / Trap instructions. 445 void break_(uint32_t code); 446 void tge(Register rs, Register rt, uint16_t code); 447 void tgeu(Register rs, Register rt, uint16_t code); 448 void tlt(Register rs, Register rt, uint16_t code); 449 void tltu(Register rs, Register rt, uint16_t code); 450 void teq(Register rs, Register rt, uint16_t code); 451 void tne(Register rs, Register rt, uint16_t code); 452 453 // Move from HI/LO register. 454 void mfhi(Register rd); 455 void mflo(Register rd); 456 457 // Set on less than. 458 void slt(Register rd, Register rs, Register rt); 459 void sltu(Register rd, Register rs, Register rt); 460 void slti(Register rd, Register rs, int32_t j); 461 void sltiu(Register rd, Register rs, int32_t j); 462 463 464 //--------Coprocessor-instructions---------------- 465 466 // Load, store, and move. 467 void lwc1(FPURegister fd, const MemOperand& src); 468 void ldc1(FPURegister fd, const MemOperand& src); 469 470 void swc1(FPURegister fs, const MemOperand& dst); 471 void sdc1(FPURegister fs, const MemOperand& dst); 472 473 // When paired with MTC1 to write a value to a 64-bit FPR, the MTC1 must be 474 // executed first, followed by the MTHC1. 475 void mtc1(FPURegister fs, Register rt); 476 void mthc1(FPURegister fs, Register rt); 477 void mfc1(FPURegister fs, Register rt); 478 void mfhc1(FPURegister fs, Register rt); 479 480 // Conversion. 481 void cvt_w_s(FPURegister fd, FPURegister fs); 482 void cvt_w_d(FPURegister fd, FPURegister fs); 483 484 void cvt_l_s(FPURegister fd, FPURegister fs); 485 void cvt_l_d(FPURegister fd, FPURegister fs); 486 487 void cvt_s_w(FPURegister fd, FPURegister fs); 488 void cvt_s_l(FPURegister fd, FPURegister fs); 489 void cvt_s_d(FPURegister fd, FPURegister fs); 490 491 void cvt_d_w(FPURegister fd, FPURegister fs); 492 void cvt_d_l(FPURegister fd, FPURegister fs); 493 void cvt_d_s(FPURegister fd, FPURegister fs); 494 495 // Conditions and branches. 496 void c(FPUCondition cond, SecondaryField fmt, 497 FPURegister ft, FPURegister fs, uint16_t cc = 0); 498 499 void bc1f(int16_t offset, uint16_t cc = 0); 500 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); } 501 void bc1t(int16_t offset, uint16_t cc = 0); 502 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } 503 504 505 // Check the code size generated from label to here. 506 int InstructionsGeneratedSince(Label* l) { 507 return (pc_offset() - l->pos()) / kInstrSize; 508 } 509 510 // Debugging. 511 512 // Mark address of the ExitJSFrame code. 513 void RecordJSReturn(); 514 515 // Record a comment relocation entry that can be used by a disassembler. 516 // Use --debug_code to enable. 517 void RecordComment(const char* msg); 518 519 void RecordPosition(int pos); 520 void RecordStatementPosition(int pos); 521 void WriteRecordedPositions(); 522 523 int32_t pc_offset() const { return pc_ - buffer_; } 524 int32_t current_position() const { return current_position_; } 525 int32_t current_statement_position() const { return current_position_; } 526 527 // Check if there is less than kGap bytes available in the buffer. 528 // If this is the case, we need to grow the buffer before emitting 529 // an instruction or relocation information. 530 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 531 532 // Get the number of bytes available in the buffer. 533 inline int available_space() const { return reloc_info_writer.pos() - pc_; } 534 535 protected: 536 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } 537 538 // Read/patch instructions. 539 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } 540 void instr_at_put(byte* pc, Instr instr) { 541 *reinterpret_cast<Instr*>(pc) = instr; 542 } 543 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } 544 void instr_at_put(int pos, Instr instr) { 545 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; 546 } 547 548 // Check if an instruction is a branch of some kind. 549 bool is_branch(Instr instr); 550 551 // Decode branch instruction at pos and return branch target pos. 552 int target_at(int32_t pos); 553 554 // Patch branch instruction at pos to branch to given branch target pos. 555 void target_at_put(int32_t pos, int32_t target_pos); 556 557 // Say if we need to relocate with this mode. 558 bool MustUseAt(RelocInfo::Mode rmode); 559 560 // Record reloc info for current pc_. 561 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 562 563 private: 564 // Code buffer: 565 // The buffer into which code and relocation info are generated. 566 byte* buffer_; 567 int buffer_size_; 568 // True if the assembler owns the buffer, false if buffer is external. 569 bool own_buffer_; 570 571 // Buffer size and constant pool distance are checked together at regular 572 // intervals of kBufferCheckInterval emitted bytes. 573 static const int kBufferCheckInterval = 1*KB/2; 574 575 // Code generation. 576 // The relocation writer's position is at least kGap bytes below the end of 577 // the generated instructions. This is so that multi-instruction sequences do 578 // not have to check for overflow. The same is true for writes of large 579 // relocation info entries. 580 static const int kGap = 32; 581 byte* pc_; // The program counter - moves forward. 582 583 // Relocation information generation. 584 // Each relocation is encoded as a variable size value. 585 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; 586 RelocInfoWriter reloc_info_writer; 587 588 // The bound position, before this we cannot do instruction elimination. 589 int last_bound_pos_; 590 591 // Source position information. 592 int current_position_; 593 int current_statement_position_; 594 int written_position_; 595 int written_statement_position_; 596 597 // Code emission. 598 inline void CheckBuffer(); 599 void GrowBuffer(); 600 inline void emit(Instr x); 601 602 // Instruction generation. 603 // We have 3 different kind of encoding layout on MIPS. 604 // However due to many different types of objects encoded in the same fields 605 // we have quite a few aliases for each mode. 606 // Using the same structure to refer to Register and FPURegister would spare a 607 // few aliases, but mixing both does not look clean to me. 608 // Anyway we could surely implement this differently. 609 610 void GenInstrRegister(Opcode opcode, 611 Register rs, 612 Register rt, 613 Register rd, 614 uint16_t sa = 0, 615 SecondaryField func = NULLSF); 616 617 void GenInstrRegister(Opcode opcode, 618 SecondaryField fmt, 619 FPURegister ft, 620 FPURegister fs, 621 FPURegister fd, 622 SecondaryField func = NULLSF); 623 624 void GenInstrRegister(Opcode opcode, 625 SecondaryField fmt, 626 Register rt, 627 FPURegister fs, 628 FPURegister fd, 629 SecondaryField func = NULLSF); 630 631 632 void GenInstrImmediate(Opcode opcode, 633 Register rs, 634 Register rt, 635 int32_t j); 636 void GenInstrImmediate(Opcode opcode, 637 Register rs, 638 SecondaryField SF, 639 int32_t j); 640 void GenInstrImmediate(Opcode opcode, 641 Register r1, 642 FPURegister r2, 643 int32_t j); 644 645 646 void GenInstrJump(Opcode opcode, 647 uint32_t address); 648 649 650 // Labels. 651 void print(Label* L); 652 void bind_to(Label* L, int pos); 653 void link_to(Label* L, Label* appendix); 654 void next(Label* L); 655 656 friend class RegExpMacroAssemblerMIPS; 657 friend class RelocInfo; 658 }; 659 660 } } // namespace v8::internal 661 662 #endif // V8_ARM_ASSEMBLER_MIPS_H_ 663 664