assembler-mips.h revision 7f4d5bd8c03935e2c0cd412e561b8fc5a6a880ae
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 44using namespace assembler::mips; 45 46namespace v8 { 47namespace 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. 75struct 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 91extern const Register no_reg; 92 93extern const Register zero_reg; 94extern const Register at; 95extern const Register v0; 96extern const Register v1; 97extern const Register a0; 98extern const Register a1; 99extern const Register a2; 100extern const Register a3; 101extern const Register t0; 102extern const Register t1; 103extern const Register t2; 104extern const Register t3; 105extern const Register t4; 106extern const Register t5; 107extern const Register t6; 108extern const Register t7; 109extern const Register s0; 110extern const Register s1; 111extern const Register s2; 112extern const Register s3; 113extern const Register s4; 114extern const Register s5; 115extern const Register s6; 116extern const Register s7; 117extern const Register t8; 118extern const Register t9; 119extern const Register k0; 120extern const Register k1; 121extern const Register gp; 122extern const Register sp; 123extern const Register s8_fp; 124extern const Register ra; 125 126int ToNumber(Register reg); 127 128Register ToRegister(int num); 129 130// Coprocessor register. 131struct 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 147extern const FPURegister no_creg; 148 149extern const FPURegister f0; 150extern const FPURegister f1; 151extern const FPURegister f2; 152extern const FPURegister f3; 153extern const FPURegister f4; 154extern const FPURegister f5; 155extern const FPURegister f6; 156extern const FPURegister f7; 157extern const FPURegister f8; 158extern const FPURegister f9; 159extern const FPURegister f10; 160extern const FPURegister f11; 161extern const FPURegister f12; // arg 162extern const FPURegister f13; 163extern const FPURegister f14; // arg 164extern const FPURegister f15; 165extern const FPURegister f16; 166extern const FPURegister f17; 167extern const FPURegister f18; 168extern const FPURegister f19; 169extern const FPURegister f20; 170extern const FPURegister f21; 171extern const FPURegister f22; 172extern const FPURegister f23; 173extern const FPURegister f24; 174extern const FPURegister f25; 175extern const FPURegister f26; 176extern const FPURegister f27; 177extern const FPURegister f28; 178extern const FPURegister f29; 179extern const FPURegister f30; 180extern 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. 187inline Condition NegateCondition(Condition cc); 188 189inline 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 213enum Hint { 214 no_hint = 0 215}; 216 217inline 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. 226class 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. 258class 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 270class 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 // Distance between start of patched debug break slot and the emitted address 359 // to jump to. 360 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize; 361 362 // --------------------------------------------------------------------------- 363 // Code generation. 364 365 void nop() { sll(zero_reg, zero_reg, 0); } 366 367 368 //------- Branch and jump instructions -------- 369 // We don't use likely variant of instructions. 370 void b(int16_t offset); 371 void b(Label* L) { b(branch_offset(L, false)>>2); } 372 void bal(int16_t offset); 373 void bal(Label* L) { bal(branch_offset(L, false)>>2); } 374 375 void beq(Register rs, Register rt, int16_t offset); 376 void beq(Register rs, Register rt, Label* L) { 377 beq(rs, rt, branch_offset(L, false) >> 2); 378 } 379 void bgez(Register rs, int16_t offset); 380 void bgezal(Register rs, int16_t offset); 381 void bgtz(Register rs, int16_t offset); 382 void blez(Register rs, int16_t offset); 383 void bltz(Register rs, int16_t offset); 384 void bltzal(Register rs, int16_t offset); 385 void bne(Register rs, Register rt, int16_t offset); 386 void bne(Register rs, Register rt, Label* L) { 387 bne(rs, rt, branch_offset(L, false)>>2); 388 } 389 390 // Never use the int16_t b(l)cond version with a branch offset 391 // instead of using the Label* version. See Twiki for infos. 392 393 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. 394 void j(int32_t target); 395 void jal(int32_t target); 396 void jalr(Register rs, Register rd = ra); 397 void jr(Register target); 398 399 400 //-------Data-processing-instructions--------- 401 402 // Arithmetic. 403 void add(Register rd, Register rs, Register rt); 404 void addu(Register rd, Register rs, Register rt); 405 void sub(Register rd, Register rs, Register rt); 406 void subu(Register rd, Register rs, Register rt); 407 void mult(Register rs, Register rt); 408 void multu(Register rs, Register rt); 409 void div(Register rs, Register rt); 410 void divu(Register rs, Register rt); 411 void mul(Register rd, Register rs, Register rt); 412 413 void addi(Register rd, Register rs, int32_t j); 414 void addiu(Register rd, Register rs, int32_t j); 415 416 // Logical. 417 void and_(Register rd, Register rs, Register rt); 418 void or_(Register rd, Register rs, Register rt); 419 void xor_(Register rd, Register rs, Register rt); 420 void nor(Register rd, Register rs, Register rt); 421 422 void andi(Register rd, Register rs, int32_t j); 423 void ori(Register rd, Register rs, int32_t j); 424 void xori(Register rd, Register rs, int32_t j); 425 void lui(Register rd, int32_t j); 426 427 // Shifts. 428 void sll(Register rd, Register rt, uint16_t sa); 429 void sllv(Register rd, Register rt, Register rs); 430 void srl(Register rd, Register rt, uint16_t sa); 431 void srlv(Register rd, Register rt, Register rs); 432 void sra(Register rt, Register rd, uint16_t sa); 433 void srav(Register rt, Register rd, Register rs); 434 435 436 //------------Memory-instructions------------- 437 438 void lb(Register rd, const MemOperand& rs); 439 void lbu(Register rd, const MemOperand& rs); 440 void lw(Register rd, const MemOperand& rs); 441 void sb(Register rd, const MemOperand& rs); 442 void sw(Register rd, const MemOperand& rs); 443 444 445 //-------------Misc-instructions-------------- 446 447 // Break / Trap instructions. 448 void break_(uint32_t code); 449 void tge(Register rs, Register rt, uint16_t code); 450 void tgeu(Register rs, Register rt, uint16_t code); 451 void tlt(Register rs, Register rt, uint16_t code); 452 void tltu(Register rs, Register rt, uint16_t code); 453 void teq(Register rs, Register rt, uint16_t code); 454 void tne(Register rs, Register rt, uint16_t code); 455 456 // Move from HI/LO register. 457 void mfhi(Register rd); 458 void mflo(Register rd); 459 460 // Set on less than. 461 void slt(Register rd, Register rs, Register rt); 462 void sltu(Register rd, Register rs, Register rt); 463 void slti(Register rd, Register rs, int32_t j); 464 void sltiu(Register rd, Register rs, int32_t j); 465 466 467 //--------Coprocessor-instructions---------------- 468 469 // Load, store, and move. 470 void lwc1(FPURegister fd, const MemOperand& src); 471 void ldc1(FPURegister fd, const MemOperand& src); 472 473 void swc1(FPURegister fs, const MemOperand& dst); 474 void sdc1(FPURegister fs, const MemOperand& dst); 475 476 // When paired with MTC1 to write a value to a 64-bit FPR, the MTC1 must be 477 // executed first, followed by the MTHC1. 478 void mtc1(FPURegister fs, Register rt); 479 void mthc1(FPURegister fs, Register rt); 480 void mfc1(FPURegister fs, Register rt); 481 void mfhc1(FPURegister fs, Register rt); 482 483 // Conversion. 484 void cvt_w_s(FPURegister fd, FPURegister fs); 485 void cvt_w_d(FPURegister fd, FPURegister fs); 486 487 void cvt_l_s(FPURegister fd, FPURegister fs); 488 void cvt_l_d(FPURegister fd, FPURegister fs); 489 490 void cvt_s_w(FPURegister fd, FPURegister fs); 491 void cvt_s_l(FPURegister fd, FPURegister fs); 492 void cvt_s_d(FPURegister fd, FPURegister fs); 493 494 void cvt_d_w(FPURegister fd, FPURegister fs); 495 void cvt_d_l(FPURegister fd, FPURegister fs); 496 void cvt_d_s(FPURegister fd, FPURegister fs); 497 498 // Conditions and branches. 499 void c(FPUCondition cond, SecondaryField fmt, 500 FPURegister ft, FPURegister fs, uint16_t cc = 0); 501 502 void bc1f(int16_t offset, uint16_t cc = 0); 503 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); } 504 void bc1t(int16_t offset, uint16_t cc = 0); 505 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } 506 507 508 // Check the code size generated from label to here. 509 int InstructionsGeneratedSince(Label* l) { 510 return (pc_offset() - l->pos()) / kInstrSize; 511 } 512 513 // Debugging. 514 515 // Mark address of the ExitJSFrame code. 516 void RecordJSReturn(); 517 518 // Record a comment relocation entry that can be used by a disassembler. 519 // Use --debug_code to enable. 520 void RecordComment(const char* msg); 521 522 void RecordPosition(int pos); 523 void RecordStatementPosition(int pos); 524 bool WriteRecordedPositions(); 525 526 int32_t pc_offset() const { return pc_ - buffer_; } 527 int32_t current_position() const { return current_position_; } 528 int32_t current_statement_position() const { 529 return current_statement_position_; 530 } 531 532 // Check if there is less than kGap bytes available in the buffer. 533 // If this is the case, we need to grow the buffer before emitting 534 // an instruction or relocation information. 535 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 536 537 // Get the number of bytes available in the buffer. 538 inline int available_space() const { return reloc_info_writer.pos() - pc_; } 539 540 protected: 541 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } 542 543 // Read/patch instructions. 544 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } 545 void instr_at_put(byte* pc, Instr instr) { 546 *reinterpret_cast<Instr*>(pc) = instr; 547 } 548 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } 549 void instr_at_put(int pos, Instr instr) { 550 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; 551 } 552 553 // Check if an instruction is a branch of some kind. 554 bool is_branch(Instr instr); 555 556 // Decode branch instruction at pos and return branch target pos. 557 int target_at(int32_t pos); 558 559 // Patch branch instruction at pos to branch to given branch target pos. 560 void target_at_put(int32_t pos, int32_t target_pos); 561 562 // Say if we need to relocate with this mode. 563 bool MustUseAt(RelocInfo::Mode rmode); 564 565 // Record reloc info for current pc_. 566 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 567 568 private: 569 // Code buffer: 570 // The buffer into which code and relocation info are generated. 571 byte* buffer_; 572 int buffer_size_; 573 // True if the assembler owns the buffer, false if buffer is external. 574 bool own_buffer_; 575 576 // Buffer size and constant pool distance are checked together at regular 577 // intervals of kBufferCheckInterval emitted bytes. 578 static const int kBufferCheckInterval = 1*KB/2; 579 580 // Code generation. 581 // The relocation writer's position is at least kGap bytes below the end of 582 // the generated instructions. This is so that multi-instruction sequences do 583 // not have to check for overflow. The same is true for writes of large 584 // relocation info entries. 585 static const int kGap = 32; 586 byte* pc_; // The program counter - moves forward. 587 588 // Relocation information generation. 589 // Each relocation is encoded as a variable size value. 590 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; 591 RelocInfoWriter reloc_info_writer; 592 593 // The bound position, before this we cannot do instruction elimination. 594 int last_bound_pos_; 595 596 // Source position information. 597 int current_position_; 598 int current_statement_position_; 599 int written_position_; 600 int written_statement_position_; 601 602 // Code emission. 603 inline void CheckBuffer(); 604 void GrowBuffer(); 605 inline void emit(Instr x); 606 607 // Instruction generation. 608 // We have 3 different kind of encoding layout on MIPS. 609 // However due to many different types of objects encoded in the same fields 610 // we have quite a few aliases for each mode. 611 // Using the same structure to refer to Register and FPURegister would spare a 612 // few aliases, but mixing both does not look clean to me. 613 // Anyway we could surely implement this differently. 614 615 void GenInstrRegister(Opcode opcode, 616 Register rs, 617 Register rt, 618 Register rd, 619 uint16_t sa = 0, 620 SecondaryField func = NULLSF); 621 622 void GenInstrRegister(Opcode opcode, 623 SecondaryField fmt, 624 FPURegister ft, 625 FPURegister fs, 626 FPURegister fd, 627 SecondaryField func = NULLSF); 628 629 void GenInstrRegister(Opcode opcode, 630 SecondaryField fmt, 631 Register rt, 632 FPURegister fs, 633 FPURegister fd, 634 SecondaryField func = NULLSF); 635 636 637 void GenInstrImmediate(Opcode opcode, 638 Register rs, 639 Register rt, 640 int32_t j); 641 void GenInstrImmediate(Opcode opcode, 642 Register rs, 643 SecondaryField SF, 644 int32_t j); 645 void GenInstrImmediate(Opcode opcode, 646 Register r1, 647 FPURegister r2, 648 int32_t j); 649 650 651 void GenInstrJump(Opcode opcode, 652 uint32_t address); 653 654 655 // Labels. 656 void print(Label* L); 657 void bind_to(Label* L, int pos); 658 void link_to(Label* L, Label* appendix); 659 void next(Label* L); 660 661 friend class RegExpMacroAssemblerMIPS; 662 friend class RelocInfo; 663}; 664 665} } // namespace v8::internal 666 667#endif // V8_ARM_ASSEMBLER_MIPS_H_ 668 669