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 2011 the V8 project authors. All rights reserved. 34 35 // A light-weight IA32 Assembler. 36 37 #ifndef V8_IA32_ASSEMBLER_IA32_H_ 38 #define V8_IA32_ASSEMBLER_IA32_H_ 39 40 #include "isolate.h" 41 #include "serialize.h" 42 43 namespace v8 { 44 namespace internal { 45 46 // CPU Registers. 47 // 48 // 1) We would prefer to use an enum, but enum values are assignment- 49 // compatible with int, which has caused code-generation bugs. 50 // 51 // 2) We would prefer to use a class instead of a struct but we don't like 52 // the register initialization to depend on the particular initialization 53 // order (which appears to be different on OS X, Linux, and Windows for the 54 // installed versions of C++ we tried). Using a struct permits C-style 55 // "initialization". Also, the Register objects cannot be const as this 56 // forces initialization stubs in MSVC, making us dependent on initialization 57 // order. 58 // 59 // 3) By not using an enum, we are possibly preventing the compiler from 60 // doing certain constant folds, which may significantly reduce the 61 // code generated for some assembly instructions (because they boil down 62 // to a few constants). If this is a problem, we could change the code 63 // such that we use an enum in optimized mode, and the struct in debug 64 // mode. This way we get the compile-time error checking in debug mode 65 // and best performance in optimized code. 66 // 67 struct Register { 68 static const int kMaxNumAllocatableRegisters = 6; 69 static int NumAllocatableRegisters() { 70 return kMaxNumAllocatableRegisters; 71 } 72 static const int kNumRegisters = 8; 73 74 static inline const char* AllocationIndexToString(int index); 75 76 static inline int ToAllocationIndex(Register reg); 77 78 static inline Register FromAllocationIndex(int index); 79 80 static Register from_code(int code) { 81 ASSERT(code >= 0); 82 ASSERT(code < kNumRegisters); 83 Register r = { code }; 84 return r; 85 } 86 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } 87 bool is(Register reg) const { return code_ == reg.code_; } 88 // eax, ebx, ecx and edx are byte registers, the rest are not. 89 bool is_byte_register() const { return code_ <= 3; } 90 int code() const { 91 ASSERT(is_valid()); 92 return code_; 93 } 94 int bit() const { 95 ASSERT(is_valid()); 96 return 1 << code_; 97 } 98 99 // Unfortunately we can't make this private in a struct. 100 int code_; 101 }; 102 103 const int kRegister_eax_Code = 0; 104 const int kRegister_ecx_Code = 1; 105 const int kRegister_edx_Code = 2; 106 const int kRegister_ebx_Code = 3; 107 const int kRegister_esp_Code = 4; 108 const int kRegister_ebp_Code = 5; 109 const int kRegister_esi_Code = 6; 110 const int kRegister_edi_Code = 7; 111 const int kRegister_no_reg_Code = -1; 112 113 const Register eax = { kRegister_eax_Code }; 114 const Register ecx = { kRegister_ecx_Code }; 115 const Register edx = { kRegister_edx_Code }; 116 const Register ebx = { kRegister_ebx_Code }; 117 const Register esp = { kRegister_esp_Code }; 118 const Register ebp = { kRegister_ebp_Code }; 119 const Register esi = { kRegister_esi_Code }; 120 const Register edi = { kRegister_edi_Code }; 121 const Register no_reg = { kRegister_no_reg_Code }; 122 123 124 inline const char* Register::AllocationIndexToString(int index) { 125 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); 126 // This is the mapping of allocation indices to registers. 127 const char* const kNames[] = { "eax", "ecx", "edx", "ebx", "esi", "edi" }; 128 return kNames[index]; 129 } 130 131 132 inline int Register::ToAllocationIndex(Register reg) { 133 ASSERT(reg.is_valid() && !reg.is(esp) && !reg.is(ebp)); 134 return (reg.code() >= 6) ? reg.code() - 2 : reg.code(); 135 } 136 137 138 inline Register Register::FromAllocationIndex(int index) { 139 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); 140 return (index >= 4) ? from_code(index + 2) : from_code(index); 141 } 142 143 144 struct IntelDoubleRegister { 145 static const int kMaxNumRegisters = 8; 146 static const int kMaxNumAllocatableRegisters = 7; 147 static int NumAllocatableRegisters(); 148 static int NumRegisters(); 149 static const char* AllocationIndexToString(int index); 150 151 static int ToAllocationIndex(IntelDoubleRegister reg) { 152 ASSERT(reg.code() != 0); 153 return reg.code() - 1; 154 } 155 156 static IntelDoubleRegister FromAllocationIndex(int index) { 157 ASSERT(index >= 0 && index < NumAllocatableRegisters()); 158 return from_code(index + 1); 159 } 160 161 static IntelDoubleRegister from_code(int code) { 162 IntelDoubleRegister result = { code }; 163 return result; 164 } 165 166 bool is_valid() const { 167 return 0 <= code_ && code_ < NumRegisters(); 168 } 169 int code() const { 170 ASSERT(is_valid()); 171 return code_; 172 } 173 174 int code_; 175 }; 176 177 178 const IntelDoubleRegister double_register_0 = { 0 }; 179 const IntelDoubleRegister double_register_1 = { 1 }; 180 const IntelDoubleRegister double_register_2 = { 2 }; 181 const IntelDoubleRegister double_register_3 = { 3 }; 182 const IntelDoubleRegister double_register_4 = { 4 }; 183 const IntelDoubleRegister double_register_5 = { 5 }; 184 const IntelDoubleRegister double_register_6 = { 6 }; 185 const IntelDoubleRegister double_register_7 = { 7 }; 186 const IntelDoubleRegister no_double_reg = { -1 }; 187 188 189 struct XMMRegister : IntelDoubleRegister { 190 static const int kNumAllocatableRegisters = 7; 191 static const int kNumRegisters = 8; 192 193 static XMMRegister from_code(int code) { 194 STATIC_ASSERT(sizeof(XMMRegister) == sizeof(IntelDoubleRegister)); 195 XMMRegister result; 196 result.code_ = code; 197 return result; 198 } 199 200 bool is(XMMRegister reg) const { return code_ == reg.code_; } 201 202 static XMMRegister FromAllocationIndex(int index) { 203 ASSERT(index >= 0 && index < NumAllocatableRegisters()); 204 return from_code(index + 1); 205 } 206 207 static const char* AllocationIndexToString(int index) { 208 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 209 const char* const names[] = { 210 "xmm1", 211 "xmm2", 212 "xmm3", 213 "xmm4", 214 "xmm5", 215 "xmm6", 216 "xmm7" 217 }; 218 return names[index]; 219 } 220 }; 221 222 223 #define xmm0 (static_cast<const XMMRegister&>(double_register_0)) 224 #define xmm1 (static_cast<const XMMRegister&>(double_register_1)) 225 #define xmm2 (static_cast<const XMMRegister&>(double_register_2)) 226 #define xmm3 (static_cast<const XMMRegister&>(double_register_3)) 227 #define xmm4 (static_cast<const XMMRegister&>(double_register_4)) 228 #define xmm5 (static_cast<const XMMRegister&>(double_register_5)) 229 #define xmm6 (static_cast<const XMMRegister&>(double_register_6)) 230 #define xmm7 (static_cast<const XMMRegister&>(double_register_7)) 231 #define no_xmm_reg (static_cast<const XMMRegister&>(no_double_reg)) 232 233 234 struct X87Register : IntelDoubleRegister { 235 static const int kNumAllocatableRegisters = 5; 236 static const int kNumRegisters = 5; 237 238 bool is(X87Register reg) const { 239 return code_ == reg.code_; 240 } 241 242 static const char* AllocationIndexToString(int index) { 243 ASSERT(index >= 0 && index < kNumAllocatableRegisters); 244 const char* const names[] = { 245 "stX_0", "stX_1", "stX_2", "stX_3", "stX_4" 246 }; 247 return names[index]; 248 } 249 250 static X87Register FromAllocationIndex(int index) { 251 STATIC_ASSERT(sizeof(X87Register) == sizeof(IntelDoubleRegister)); 252 ASSERT(index >= 0 && index < NumAllocatableRegisters()); 253 X87Register result; 254 result.code_ = index; 255 return result; 256 } 257 258 static int ToAllocationIndex(X87Register reg) { 259 return reg.code_; 260 } 261 }; 262 263 #define stX_0 static_cast<const X87Register&>(double_register_0) 264 #define stX_1 static_cast<const X87Register&>(double_register_1) 265 #define stX_2 static_cast<const X87Register&>(double_register_2) 266 #define stX_3 static_cast<const X87Register&>(double_register_3) 267 #define stX_4 static_cast<const X87Register&>(double_register_4) 268 269 270 typedef IntelDoubleRegister DoubleRegister; 271 272 273 enum Condition { 274 // any value < 0 is considered no_condition 275 no_condition = -1, 276 277 overflow = 0, 278 no_overflow = 1, 279 below = 2, 280 above_equal = 3, 281 equal = 4, 282 not_equal = 5, 283 below_equal = 6, 284 above = 7, 285 negative = 8, 286 positive = 9, 287 parity_even = 10, 288 parity_odd = 11, 289 less = 12, 290 greater_equal = 13, 291 less_equal = 14, 292 greater = 15, 293 294 // aliases 295 carry = below, 296 not_carry = above_equal, 297 zero = equal, 298 not_zero = not_equal, 299 sign = negative, 300 not_sign = positive 301 }; 302 303 304 // Returns the equivalent of !cc. 305 // Negation of the default no_condition (-1) results in a non-default 306 // no_condition value (-2). As long as tests for no_condition check 307 // for condition < 0, this will work as expected. 308 inline Condition NegateCondition(Condition cc) { 309 return static_cast<Condition>(cc ^ 1); 310 } 311 312 313 // Corresponds to transposing the operands of a comparison. 314 inline Condition ReverseCondition(Condition cc) { 315 switch (cc) { 316 case below: 317 return above; 318 case above: 319 return below; 320 case above_equal: 321 return below_equal; 322 case below_equal: 323 return above_equal; 324 case less: 325 return greater; 326 case greater: 327 return less; 328 case greater_equal: 329 return less_equal; 330 case less_equal: 331 return greater_equal; 332 default: 333 return cc; 334 }; 335 } 336 337 338 // ----------------------------------------------------------------------------- 339 // Machine instruction Immediates 340 341 class Immediate BASE_EMBEDDED { 342 public: 343 inline explicit Immediate(int x); 344 inline explicit Immediate(const ExternalReference& ext); 345 inline explicit Immediate(Handle<Object> handle); 346 inline explicit Immediate(Smi* value); 347 inline explicit Immediate(Address addr); 348 349 static Immediate CodeRelativeOffset(Label* label) { 350 return Immediate(label); 351 } 352 353 bool is_zero() const { return x_ == 0 && RelocInfo::IsNone(rmode_); } 354 bool is_int8() const { 355 return -128 <= x_ && x_ < 128 && RelocInfo::IsNone(rmode_); 356 } 357 bool is_int16() const { 358 return -32768 <= x_ && x_ < 32768 && RelocInfo::IsNone(rmode_); 359 } 360 361 private: 362 inline explicit Immediate(Label* value); 363 364 int x_; 365 RelocInfo::Mode rmode_; 366 367 friend class Assembler; 368 friend class MacroAssembler; 369 }; 370 371 372 // ----------------------------------------------------------------------------- 373 // Machine instruction Operands 374 375 enum ScaleFactor { 376 times_1 = 0, 377 times_2 = 1, 378 times_4 = 2, 379 times_8 = 3, 380 times_int_size = times_4, 381 times_half_pointer_size = times_2, 382 times_pointer_size = times_4, 383 times_twice_pointer_size = times_8 384 }; 385 386 387 class Operand BASE_EMBEDDED { 388 public: 389 // XMM reg 390 INLINE(explicit Operand(XMMRegister xmm_reg)); 391 392 // [disp/r] 393 INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode)); 394 // disp only must always be relocated 395 396 // [base + disp/r] 397 explicit Operand(Register base, int32_t disp, 398 RelocInfo::Mode rmode = RelocInfo::NONE32); 399 400 // [base + index*scale + disp/r] 401 explicit Operand(Register base, 402 Register index, 403 ScaleFactor scale, 404 int32_t disp, 405 RelocInfo::Mode rmode = RelocInfo::NONE32); 406 407 // [index*scale + disp/r] 408 explicit Operand(Register index, 409 ScaleFactor scale, 410 int32_t disp, 411 RelocInfo::Mode rmode = RelocInfo::NONE32); 412 413 static Operand StaticVariable(const ExternalReference& ext) { 414 return Operand(reinterpret_cast<int32_t>(ext.address()), 415 RelocInfo::EXTERNAL_REFERENCE); 416 } 417 418 static Operand StaticArray(Register index, 419 ScaleFactor scale, 420 const ExternalReference& arr) { 421 return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()), 422 RelocInfo::EXTERNAL_REFERENCE); 423 } 424 425 static Operand ForCell(Handle<Cell> cell) { 426 AllowDeferredHandleDereference embedding_raw_address; 427 return Operand(reinterpret_cast<int32_t>(cell.location()), 428 RelocInfo::CELL); 429 } 430 431 // Returns true if this Operand is a wrapper for the specified register. 432 bool is_reg(Register reg) const; 433 434 // Returns true if this Operand is a wrapper for one register. 435 bool is_reg_only() const; 436 437 // Asserts that this Operand is a wrapper for one register and returns the 438 // register. 439 Register reg() const; 440 441 private: 442 // reg 443 INLINE(explicit Operand(Register reg)); 444 445 // Set the ModRM byte without an encoded 'reg' register. The 446 // register is encoded later as part of the emit_operand operation. 447 inline void set_modrm(int mod, Register rm); 448 449 inline void set_sib(ScaleFactor scale, Register index, Register base); 450 inline void set_disp8(int8_t disp); 451 inline void set_dispr(int32_t disp, RelocInfo::Mode rmode); 452 453 byte buf_[6]; 454 // The number of bytes in buf_. 455 unsigned int len_; 456 // Only valid if len_ > 4. 457 RelocInfo::Mode rmode_; 458 459 friend class Assembler; 460 friend class MacroAssembler; 461 friend class LCodeGen; 462 }; 463 464 465 // ----------------------------------------------------------------------------- 466 // A Displacement describes the 32bit immediate field of an instruction which 467 // may be used together with a Label in order to refer to a yet unknown code 468 // position. Displacements stored in the instruction stream are used to describe 469 // the instruction and to chain a list of instructions using the same Label. 470 // A Displacement contains 2 different fields: 471 // 472 // next field: position of next displacement in the chain (0 = end of list) 473 // type field: instruction type 474 // 475 // A next value of null (0) indicates the end of a chain (note that there can 476 // be no displacement at position zero, because there is always at least one 477 // instruction byte before the displacement). 478 // 479 // Displacement _data field layout 480 // 481 // |31.....2|1......0| 482 // [ next | type | 483 484 class Displacement BASE_EMBEDDED { 485 public: 486 enum Type { 487 UNCONDITIONAL_JUMP, 488 CODE_RELATIVE, 489 OTHER 490 }; 491 492 int data() const { return data_; } 493 Type type() const { return TypeField::decode(data_); } 494 void next(Label* L) const { 495 int n = NextField::decode(data_); 496 n > 0 ? L->link_to(n) : L->Unuse(); 497 } 498 void link_to(Label* L) { init(L, type()); } 499 500 explicit Displacement(int data) { data_ = data; } 501 502 Displacement(Label* L, Type type) { init(L, type); } 503 504 void print() { 505 PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), 506 NextField::decode(data_)); 507 } 508 509 private: 510 int data_; 511 512 class TypeField: public BitField<Type, 0, 2> {}; 513 class NextField: public BitField<int, 2, 32-2> {}; 514 515 void init(Label* L, Type type); 516 }; 517 518 519 520 // CpuFeatures keeps track of which features are supported by the target CPU. 521 // Supported features must be enabled by a CpuFeatureScope before use. 522 // Example: 523 // if (assembler->IsSupported(SSE2)) { 524 // CpuFeatureScope fscope(assembler, SSE2); 525 // // Generate SSE2 floating point code. 526 // } else { 527 // // Generate standard x87 floating point code. 528 // } 529 class CpuFeatures : public AllStatic { 530 public: 531 // Detect features of the target CPU. Set safe defaults if the serializer 532 // is enabled (snapshots must be portable). 533 static void Probe(); 534 535 // Check whether a feature is supported by the target CPU. 536 static bool IsSupported(CpuFeature f) { 537 ASSERT(initialized_); 538 if (Check(f, cross_compile_)) return true; 539 if (f == SSE2 && !FLAG_enable_sse2) return false; 540 if (f == SSE3 && !FLAG_enable_sse3) return false; 541 if (f == SSE4_1 && !FLAG_enable_sse4_1) return false; 542 if (f == CMOV && !FLAG_enable_cmov) return false; 543 return Check(f, supported_); 544 } 545 546 static bool IsFoundByRuntimeProbingOnly(CpuFeature f) { 547 ASSERT(initialized_); 548 return Check(f, found_by_runtime_probing_only_); 549 } 550 551 static bool IsSafeForSnapshot(CpuFeature f) { 552 return Check(f, cross_compile_) || 553 (IsSupported(f) && 554 (!Serializer::enabled() || !IsFoundByRuntimeProbingOnly(f))); 555 } 556 557 static bool VerifyCrossCompiling() { 558 return cross_compile_ == 0; 559 } 560 561 static bool VerifyCrossCompiling(CpuFeature f) { 562 uint64_t mask = flag2set(f); 563 return cross_compile_ == 0 || 564 (cross_compile_ & mask) == mask; 565 } 566 567 private: 568 static bool Check(CpuFeature f, uint64_t set) { 569 return (set & flag2set(f)) != 0; 570 } 571 572 static uint64_t flag2set(CpuFeature f) { 573 return static_cast<uint64_t>(1) << f; 574 } 575 576 #ifdef DEBUG 577 static bool initialized_; 578 #endif 579 static uint64_t supported_; 580 static uint64_t found_by_runtime_probing_only_; 581 582 static uint64_t cross_compile_; 583 584 friend class ExternalReference; 585 friend class PlatformFeatureScope; 586 DISALLOW_COPY_AND_ASSIGN(CpuFeatures); 587 }; 588 589 590 class Assembler : public AssemblerBase { 591 private: 592 // We check before assembling an instruction that there is sufficient 593 // space to write an instruction and its relocation information. 594 // The relocation writer's position must be kGap bytes above the end of 595 // the generated instructions. This leaves enough space for the 596 // longest possible ia32 instruction, 15 bytes, and the longest possible 597 // relocation information encoding, RelocInfoWriter::kMaxLength == 16. 598 // (There is a 15 byte limit on ia32 instruction length that rules out some 599 // otherwise valid instructions.) 600 // This allows for a single, fast space check per instruction. 601 static const int kGap = 32; 602 603 public: 604 // Create an assembler. Instructions and relocation information are emitted 605 // into a buffer, with the instructions starting from the beginning and the 606 // relocation information starting from the end of the buffer. See CodeDesc 607 // for a detailed comment on the layout (globals.h). 608 // 609 // If the provided buffer is NULL, the assembler allocates and grows its own 610 // buffer, and buffer_size determines the initial buffer size. The buffer is 611 // owned by the assembler and deallocated upon destruction of the assembler. 612 // 613 // If the provided buffer is not NULL, the assembler uses the provided buffer 614 // for code generation and assumes its size to be buffer_size. If the buffer 615 // is too small, a fatal error occurs. No deallocation of the buffer is done 616 // upon destruction of the assembler. 617 // TODO(vitalyr): the assembler does not need an isolate. 618 Assembler(Isolate* isolate, void* buffer, int buffer_size); 619 virtual ~Assembler() { } 620 621 // GetCode emits any pending (non-emitted) code and fills the descriptor 622 // desc. GetCode() is idempotent; it returns the same result if no other 623 // Assembler functions are invoked in between GetCode() calls. 624 void GetCode(CodeDesc* desc); 625 626 // Read/Modify the code target in the branch/call instruction at pc. 627 inline static Address target_address_at(Address pc); 628 inline static void set_target_address_at(Address pc, Address target); 629 630 // Return the code target address at a call site from the return address 631 // of that call in the instruction stream. 632 inline static Address target_address_from_return_address(Address pc); 633 634 // This sets the branch destination (which is in the instruction on x86). 635 // This is for calls and branches within generated code. 636 inline static void deserialization_set_special_target_at( 637 Address instruction_payload, Address target) { 638 set_target_address_at(instruction_payload, target); 639 } 640 641 static const int kSpecialTargetSize = kPointerSize; 642 643 // Distance between the address of the code target in the call instruction 644 // and the return address 645 static const int kCallTargetAddressOffset = kPointerSize; 646 // Distance between start of patched return sequence and the emitted address 647 // to jump to. 648 static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32. 649 650 // Distance between start of patched debug break slot and the emitted address 651 // to jump to. 652 static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32. 653 654 static const int kCallInstructionLength = 5; 655 static const int kPatchDebugBreakSlotReturnOffset = kPointerSize; 656 static const int kJSReturnSequenceLength = 6; 657 658 // The debug break slot must be able to contain a call instruction. 659 static const int kDebugBreakSlotLength = kCallInstructionLength; 660 661 // One byte opcode for test al, 0xXX. 662 static const byte kTestAlByte = 0xA8; 663 // One byte opcode for nop. 664 static const byte kNopByte = 0x90; 665 666 // One byte opcode for a short unconditional jump. 667 static const byte kJmpShortOpcode = 0xEB; 668 // One byte prefix for a short conditional jump. 669 static const byte kJccShortPrefix = 0x70; 670 static const byte kJncShortOpcode = kJccShortPrefix | not_carry; 671 static const byte kJcShortOpcode = kJccShortPrefix | carry; 672 static const byte kJnzShortOpcode = kJccShortPrefix | not_zero; 673 static const byte kJzShortOpcode = kJccShortPrefix | zero; 674 675 676 // --------------------------------------------------------------------------- 677 // Code generation 678 // 679 // - function names correspond one-to-one to ia32 instruction mnemonics 680 // - unless specified otherwise, instructions operate on 32bit operands 681 // - instructions on 8bit (byte) operands/registers have a trailing '_b' 682 // - instructions on 16bit (word) operands/registers have a trailing '_w' 683 // - naming conflicts with C++ keywords are resolved via a trailing '_' 684 685 // NOTE ON INTERFACE: Currently, the interface is not very consistent 686 // in the sense that some operations (e.g. mov()) can be called in more 687 // the one way to generate the same instruction: The Register argument 688 // can in some cases be replaced with an Operand(Register) argument. 689 // This should be cleaned up and made more orthogonal. The questions 690 // is: should we always use Operands instead of Registers where an 691 // Operand is possible, or should we have a Register (overloaded) form 692 // instead? We must be careful to make sure that the selected instruction 693 // is obvious from the parameters to avoid hard-to-find code generation 694 // bugs. 695 696 // Insert the smallest number of nop instructions 697 // possible to align the pc offset to a multiple 698 // of m. m must be a power of 2. 699 void Align(int m); 700 void Nop(int bytes = 1); 701 // Aligns code to something that's optimal for a jump target for the platform. 702 void CodeTargetAlign(); 703 704 // Stack 705 void pushad(); 706 void popad(); 707 708 void pushfd(); 709 void popfd(); 710 711 void push(const Immediate& x); 712 void push_imm32(int32_t imm32); 713 void push(Register src); 714 void push(const Operand& src); 715 716 void pop(Register dst); 717 void pop(const Operand& dst); 718 719 void enter(const Immediate& size); 720 void leave(); 721 722 // Moves 723 void mov_b(Register dst, Register src) { mov_b(dst, Operand(src)); } 724 void mov_b(Register dst, const Operand& src); 725 void mov_b(Register dst, int8_t imm8) { mov_b(Operand(dst), imm8); } 726 void mov_b(const Operand& dst, int8_t imm8); 727 void mov_b(const Operand& dst, Register src); 728 729 void mov_w(Register dst, const Operand& src); 730 void mov_w(const Operand& dst, Register src); 731 void mov_w(const Operand& dst, int16_t imm16); 732 733 void mov(Register dst, int32_t imm32); 734 void mov(Register dst, const Immediate& x); 735 void mov(Register dst, Handle<Object> handle); 736 void mov(Register dst, const Operand& src); 737 void mov(Register dst, Register src); 738 void mov(const Operand& dst, const Immediate& x); 739 void mov(const Operand& dst, Handle<Object> handle); 740 void mov(const Operand& dst, Register src); 741 742 void movsx_b(Register dst, Register src) { movsx_b(dst, Operand(src)); } 743 void movsx_b(Register dst, const Operand& src); 744 745 void movsx_w(Register dst, Register src) { movsx_w(dst, Operand(src)); } 746 void movsx_w(Register dst, const Operand& src); 747 748 void movzx_b(Register dst, Register src) { movzx_b(dst, Operand(src)); } 749 void movzx_b(Register dst, const Operand& src); 750 751 void movzx_w(Register dst, Register src) { movzx_w(dst, Operand(src)); } 752 void movzx_w(Register dst, const Operand& src); 753 754 // Conditional moves 755 void cmov(Condition cc, Register dst, Register src) { 756 cmov(cc, dst, Operand(src)); 757 } 758 void cmov(Condition cc, Register dst, const Operand& src); 759 760 // Flag management. 761 void cld(); 762 763 // Repetitive string instructions. 764 void rep_movs(); 765 void rep_stos(); 766 void stos(); 767 768 // Exchange two registers 769 void xchg(Register dst, Register src); 770 771 // Arithmetics 772 void adc(Register dst, int32_t imm32); 773 void adc(Register dst, const Operand& src); 774 775 void add(Register dst, Register src) { add(dst, Operand(src)); } 776 void add(Register dst, const Operand& src); 777 void add(const Operand& dst, Register src); 778 void add(Register dst, const Immediate& imm) { add(Operand(dst), imm); } 779 void add(const Operand& dst, const Immediate& x); 780 781 void and_(Register dst, int32_t imm32); 782 void and_(Register dst, const Immediate& x); 783 void and_(Register dst, Register src) { and_(dst, Operand(src)); } 784 void and_(Register dst, const Operand& src); 785 void and_(const Operand& dst, Register src); 786 void and_(const Operand& dst, const Immediate& x); 787 788 void cmpb(Register reg, int8_t imm8) { cmpb(Operand(reg), imm8); } 789 void cmpb(const Operand& op, int8_t imm8); 790 void cmpb(Register reg, const Operand& op); 791 void cmpb(const Operand& op, Register reg); 792 void cmpb_al(const Operand& op); 793 void cmpw_ax(const Operand& op); 794 void cmpw(const Operand& op, Immediate imm16); 795 void cmp(Register reg, int32_t imm32); 796 void cmp(Register reg, Handle<Object> handle); 797 void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); } 798 void cmp(Register reg, const Operand& op); 799 void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); } 800 void cmp(const Operand& op, const Immediate& imm); 801 void cmp(const Operand& op, Handle<Object> handle); 802 803 void dec_b(Register dst); 804 void dec_b(const Operand& dst); 805 806 void dec(Register dst); 807 void dec(const Operand& dst); 808 809 void cdq(); 810 811 void idiv(Register src); 812 813 // Signed multiply instructions. 814 void imul(Register src); // edx:eax = eax * src. 815 void imul(Register dst, Register src) { imul(dst, Operand(src)); } 816 void imul(Register dst, const Operand& src); // dst = dst * src. 817 void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32. 818 819 void inc(Register dst); 820 void inc(const Operand& dst); 821 822 void lea(Register dst, const Operand& src); 823 824 // Unsigned multiply instruction. 825 void mul(Register src); // edx:eax = eax * reg. 826 827 void neg(Register dst); 828 829 void not_(Register dst); 830 831 void or_(Register dst, int32_t imm32); 832 void or_(Register dst, Register src) { or_(dst, Operand(src)); } 833 void or_(Register dst, const Operand& src); 834 void or_(const Operand& dst, Register src); 835 void or_(Register dst, const Immediate& imm) { or_(Operand(dst), imm); } 836 void or_(const Operand& dst, const Immediate& x); 837 838 void rcl(Register dst, uint8_t imm8); 839 void rcr(Register dst, uint8_t imm8); 840 void ror(Register dst, uint8_t imm8); 841 void ror_cl(Register dst); 842 843 void sar(Register dst, uint8_t imm8); 844 void sar_cl(Register dst); 845 846 void sbb(Register dst, const Operand& src); 847 848 void shld(Register dst, Register src) { shld(dst, Operand(src)); } 849 void shld(Register dst, const Operand& src); 850 851 void shl(Register dst, uint8_t imm8); 852 void shl_cl(Register dst); 853 854 void shrd(Register dst, Register src) { shrd(dst, Operand(src)); } 855 void shrd(Register dst, const Operand& src); 856 857 void shr(Register dst, uint8_t imm8); 858 void shr_cl(Register dst); 859 860 void sub(Register dst, const Immediate& imm) { sub(Operand(dst), imm); } 861 void sub(const Operand& dst, const Immediate& x); 862 void sub(Register dst, Register src) { sub(dst, Operand(src)); } 863 void sub(Register dst, const Operand& src); 864 void sub(const Operand& dst, Register src); 865 866 void test(Register reg, const Immediate& imm); 867 void test(Register reg0, Register reg1) { test(reg0, Operand(reg1)); } 868 void test(Register reg, const Operand& op); 869 void test_b(Register reg, const Operand& op); 870 void test(const Operand& op, const Immediate& imm); 871 void test_b(Register reg, uint8_t imm8); 872 void test_b(const Operand& op, uint8_t imm8); 873 874 void xor_(Register dst, int32_t imm32); 875 void xor_(Register dst, Register src) { xor_(dst, Operand(src)); } 876 void xor_(Register dst, const Operand& src); 877 void xor_(const Operand& dst, Register src); 878 void xor_(Register dst, const Immediate& imm) { xor_(Operand(dst), imm); } 879 void xor_(const Operand& dst, const Immediate& x); 880 881 // Bit operations. 882 void bt(const Operand& dst, Register src); 883 void bts(Register dst, Register src) { bts(Operand(dst), src); } 884 void bts(const Operand& dst, Register src); 885 886 // Miscellaneous 887 void hlt(); 888 void int3(); 889 void nop(); 890 void ret(int imm16); 891 892 // Label operations & relative jumps (PPUM Appendix D) 893 // 894 // Takes a branch opcode (cc) and a label (L) and generates 895 // either a backward branch or a forward branch and links it 896 // to the label fixup chain. Usage: 897 // 898 // Label L; // unbound label 899 // j(cc, &L); // forward branch to unbound label 900 // bind(&L); // bind label to the current pc 901 // j(cc, &L); // backward branch to bound label 902 // bind(&L); // illegal: a label may be bound only once 903 // 904 // Note: The same Label can be used for forward and backward branches 905 // but it may be bound only once. 906 907 void bind(Label* L); // binds an unbound label L to the current code position 908 909 // Calls 910 void call(Label* L); 911 void call(byte* entry, RelocInfo::Mode rmode); 912 int CallSize(const Operand& adr); 913 void call(Register reg) { call(Operand(reg)); } 914 void call(const Operand& adr); 915 int CallSize(Handle<Code> code, RelocInfo::Mode mode); 916 void call(Handle<Code> code, 917 RelocInfo::Mode rmode, 918 TypeFeedbackId id = TypeFeedbackId::None()); 919 920 // Jumps 921 // unconditional jump to L 922 void jmp(Label* L, Label::Distance distance = Label::kFar); 923 void jmp(byte* entry, RelocInfo::Mode rmode); 924 void jmp(Register reg) { jmp(Operand(reg)); } 925 void jmp(const Operand& adr); 926 void jmp(Handle<Code> code, RelocInfo::Mode rmode); 927 928 // Conditional jumps 929 void j(Condition cc, 930 Label* L, 931 Label::Distance distance = Label::kFar); 932 void j(Condition cc, byte* entry, RelocInfo::Mode rmode); 933 void j(Condition cc, Handle<Code> code); 934 935 // Floating-point operations 936 void fld(int i); 937 void fstp(int i); 938 939 void fld1(); 940 void fldz(); 941 void fldpi(); 942 void fldln2(); 943 944 void fld_s(const Operand& adr); 945 void fld_d(const Operand& adr); 946 947 void fstp_s(const Operand& adr); 948 void fst_s(const Operand& adr); 949 void fstp_d(const Operand& adr); 950 void fst_d(const Operand& adr); 951 952 void fild_s(const Operand& adr); 953 void fild_d(const Operand& adr); 954 955 void fist_s(const Operand& adr); 956 957 void fistp_s(const Operand& adr); 958 void fistp_d(const Operand& adr); 959 960 // The fisttp instructions require SSE3. 961 void fisttp_s(const Operand& adr); 962 void fisttp_d(const Operand& adr); 963 964 void fabs(); 965 void fchs(); 966 void fcos(); 967 void fsin(); 968 void fptan(); 969 void fyl2x(); 970 void f2xm1(); 971 void fscale(); 972 void fninit(); 973 974 void fadd(int i); 975 void fadd_i(int i); 976 void fsub(int i); 977 void fsub_i(int i); 978 void fmul(int i); 979 void fmul_i(int i); 980 void fdiv(int i); 981 void fdiv_i(int i); 982 983 void fisub_s(const Operand& adr); 984 985 void faddp(int i = 1); 986 void fsubp(int i = 1); 987 void fsubrp(int i = 1); 988 void fmulp(int i = 1); 989 void fdivp(int i = 1); 990 void fprem(); 991 void fprem1(); 992 993 void fxch(int i = 1); 994 void fincstp(); 995 void ffree(int i = 0); 996 997 void ftst(); 998 void fucomp(int i); 999 void fucompp(); 1000 void fucomi(int i); 1001 void fucomip(); 1002 void fcompp(); 1003 void fnstsw_ax(); 1004 void fwait(); 1005 void fnclex(); 1006 1007 void frndint(); 1008 1009 void sahf(); 1010 void setcc(Condition cc, Register reg); 1011 1012 void cpuid(); 1013 1014 // SSE instructions 1015 void movaps(XMMRegister dst, XMMRegister src); 1016 void shufps(XMMRegister dst, XMMRegister src, byte imm8); 1017 1018 void andps(XMMRegister dst, const Operand& src); 1019 void andps(XMMRegister dst, XMMRegister src) { andps(dst, Operand(src)); } 1020 void xorps(XMMRegister dst, const Operand& src); 1021 void xorps(XMMRegister dst, XMMRegister src) { xorps(dst, Operand(src)); } 1022 void orps(XMMRegister dst, const Operand& src); 1023 void orps(XMMRegister dst, XMMRegister src) { orps(dst, Operand(src)); } 1024 1025 void addps(XMMRegister dst, const Operand& src); 1026 void addps(XMMRegister dst, XMMRegister src) { addps(dst, Operand(src)); } 1027 void subps(XMMRegister dst, const Operand& src); 1028 void subps(XMMRegister dst, XMMRegister src) { subps(dst, Operand(src)); } 1029 void mulps(XMMRegister dst, const Operand& src); 1030 void mulps(XMMRegister dst, XMMRegister src) { mulps(dst, Operand(src)); } 1031 void divps(XMMRegister dst, const Operand& src); 1032 void divps(XMMRegister dst, XMMRegister src) { divps(dst, Operand(src)); } 1033 1034 // SSE2 instructions 1035 void cvttss2si(Register dst, const Operand& src); 1036 void cvttss2si(Register dst, XMMRegister src) { 1037 cvttss2si(dst, Operand(src)); 1038 } 1039 void cvttsd2si(Register dst, const Operand& src); 1040 void cvtsd2si(Register dst, XMMRegister src); 1041 1042 void cvtsi2sd(XMMRegister dst, Register src) { cvtsi2sd(dst, Operand(src)); } 1043 void cvtsi2sd(XMMRegister dst, const Operand& src); 1044 void cvtss2sd(XMMRegister dst, XMMRegister src); 1045 void cvtsd2ss(XMMRegister dst, XMMRegister src); 1046 1047 void addsd(XMMRegister dst, XMMRegister src); 1048 void addsd(XMMRegister dst, const Operand& src); 1049 void subsd(XMMRegister dst, XMMRegister src); 1050 void mulsd(XMMRegister dst, XMMRegister src); 1051 void mulsd(XMMRegister dst, const Operand& src); 1052 void divsd(XMMRegister dst, XMMRegister src); 1053 void xorpd(XMMRegister dst, XMMRegister src); 1054 void sqrtsd(XMMRegister dst, XMMRegister src); 1055 1056 void andpd(XMMRegister dst, XMMRegister src); 1057 void orpd(XMMRegister dst, XMMRegister src); 1058 1059 void ucomisd(XMMRegister dst, XMMRegister src) { ucomisd(dst, Operand(src)); } 1060 void ucomisd(XMMRegister dst, const Operand& src); 1061 1062 enum RoundingMode { 1063 kRoundToNearest = 0x0, 1064 kRoundDown = 0x1, 1065 kRoundUp = 0x2, 1066 kRoundToZero = 0x3 1067 }; 1068 1069 void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode); 1070 1071 void movmskpd(Register dst, XMMRegister src); 1072 void movmskps(Register dst, XMMRegister src); 1073 1074 void cmpltsd(XMMRegister dst, XMMRegister src); 1075 void pcmpeqd(XMMRegister dst, XMMRegister src); 1076 1077 void movdqa(XMMRegister dst, const Operand& src); 1078 void movdqa(const Operand& dst, XMMRegister src); 1079 void movdqu(XMMRegister dst, const Operand& src); 1080 void movdqu(const Operand& dst, XMMRegister src); 1081 void movdq(bool aligned, XMMRegister dst, const Operand& src) { 1082 if (aligned) { 1083 movdqa(dst, src); 1084 } else { 1085 movdqu(dst, src); 1086 } 1087 } 1088 1089 void movd(XMMRegister dst, Register src) { movd(dst, Operand(src)); } 1090 void movd(XMMRegister dst, const Operand& src); 1091 void movd(Register dst, XMMRegister src) { movd(Operand(dst), src); } 1092 void movd(const Operand& dst, XMMRegister src); 1093 void movsd(XMMRegister dst, XMMRegister src) { movsd(dst, Operand(src)); } 1094 void movsd(XMMRegister dst, const Operand& src); 1095 void movsd(const Operand& dst, XMMRegister src); 1096 1097 1098 void movss(XMMRegister dst, const Operand& src); 1099 void movss(const Operand& dst, XMMRegister src); 1100 void movss(XMMRegister dst, XMMRegister src) { movss(dst, Operand(src)); } 1101 void extractps(Register dst, XMMRegister src, byte imm8); 1102 1103 void pand(XMMRegister dst, XMMRegister src); 1104 void pxor(XMMRegister dst, XMMRegister src); 1105 void por(XMMRegister dst, XMMRegister src); 1106 void ptest(XMMRegister dst, XMMRegister src); 1107 1108 void psllq(XMMRegister reg, int8_t shift); 1109 void psllq(XMMRegister dst, XMMRegister src); 1110 void psrlq(XMMRegister reg, int8_t shift); 1111 void psrlq(XMMRegister dst, XMMRegister src); 1112 void pshufd(XMMRegister dst, XMMRegister src, uint8_t shuffle); 1113 void pextrd(Register dst, XMMRegister src, int8_t offset) { 1114 pextrd(Operand(dst), src, offset); 1115 } 1116 void pextrd(const Operand& dst, XMMRegister src, int8_t offset); 1117 void pinsrd(XMMRegister dst, Register src, int8_t offset) { 1118 pinsrd(dst, Operand(src), offset); 1119 } 1120 void pinsrd(XMMRegister dst, const Operand& src, int8_t offset); 1121 1122 // Parallel XMM operations. 1123 void movntdqa(XMMRegister dst, const Operand& src); 1124 void movntdq(const Operand& dst, XMMRegister src); 1125 // Prefetch src position into cache level. 1126 // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a 1127 // non-temporal 1128 void prefetch(const Operand& src, int level); 1129 // TODO(lrn): Need SFENCE for movnt? 1130 1131 // Debugging 1132 void Print(); 1133 1134 // Check the code size generated from label to here. 1135 int SizeOfCodeGeneratedSince(Label* label) { 1136 return pc_offset() - label->pos(); 1137 } 1138 1139 // Mark address of the ExitJSFrame code. 1140 void RecordJSReturn(); 1141 1142 // Mark address of a debug break slot. 1143 void RecordDebugBreakSlot(); 1144 1145 // Record a comment relocation entry that can be used by a disassembler. 1146 // Use --code-comments to enable, or provide "force = true" flag to always 1147 // write a comment. 1148 void RecordComment(const char* msg, bool force = false); 1149 1150 // Writes a single byte or word of data in the code stream. Used for 1151 // inline tables, e.g., jump-tables. 1152 void db(uint8_t data); 1153 void dd(uint32_t data); 1154 1155 // Check if there is less than kGap bytes available in the buffer. 1156 // If this is the case, we need to grow the buffer before emitting 1157 // an instruction or relocation information. 1158 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 1159 1160 // Get the number of bytes available in the buffer. 1161 inline int available_space() const { return reloc_info_writer.pos() - pc_; } 1162 1163 static bool IsNop(Address addr); 1164 1165 PositionsRecorder* positions_recorder() { return &positions_recorder_; } 1166 1167 int relocation_writer_size() { 1168 return (buffer_ + buffer_size_) - reloc_info_writer.pos(); 1169 } 1170 1171 // Avoid overflows for displacements etc. 1172 static const int kMaximalBufferSize = 512*MB; 1173 1174 byte byte_at(int pos) { return buffer_[pos]; } 1175 void set_byte_at(int pos, byte value) { buffer_[pos] = value; } 1176 1177 protected: 1178 void emit_sse_operand(XMMRegister reg, const Operand& adr); 1179 void emit_sse_operand(XMMRegister dst, XMMRegister src); 1180 void emit_sse_operand(Register dst, XMMRegister src); 1181 void emit_sse_operand(XMMRegister dst, Register src); 1182 1183 byte* addr_at(int pos) { return buffer_ + pos; } 1184 1185 1186 private: 1187 uint32_t long_at(int pos) { 1188 return *reinterpret_cast<uint32_t*>(addr_at(pos)); 1189 } 1190 void long_at_put(int pos, uint32_t x) { 1191 *reinterpret_cast<uint32_t*>(addr_at(pos)) = x; 1192 } 1193 1194 // code emission 1195 void GrowBuffer(); 1196 inline void emit(uint32_t x); 1197 inline void emit(Handle<Object> handle); 1198 inline void emit(uint32_t x, 1199 RelocInfo::Mode rmode, 1200 TypeFeedbackId id = TypeFeedbackId::None()); 1201 inline void emit(Handle<Code> code, 1202 RelocInfo::Mode rmode, 1203 TypeFeedbackId id = TypeFeedbackId::None()); 1204 inline void emit(const Immediate& x); 1205 inline void emit_w(const Immediate& x); 1206 1207 // Emit the code-object-relative offset of the label's position 1208 inline void emit_code_relative_offset(Label* label); 1209 1210 // instruction generation 1211 void emit_arith_b(int op1, int op2, Register dst, int imm8); 1212 1213 // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81) 1214 // with a given destination expression and an immediate operand. It attempts 1215 // to use the shortest encoding possible. 1216 // sel specifies the /n in the modrm byte (see the Intel PRM). 1217 void emit_arith(int sel, Operand dst, const Immediate& x); 1218 1219 void emit_operand(Register reg, const Operand& adr); 1220 1221 void emit_farith(int b1, int b2, int i); 1222 1223 // labels 1224 void print(Label* L); 1225 void bind_to(Label* L, int pos); 1226 1227 // displacements 1228 inline Displacement disp_at(Label* L); 1229 inline void disp_at_put(Label* L, Displacement disp); 1230 inline void emit_disp(Label* L, Displacement::Type type); 1231 inline void emit_near_disp(Label* L); 1232 1233 // record reloc info for current pc_ 1234 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 1235 1236 friend class CodePatcher; 1237 friend class EnsureSpace; 1238 1239 // code generation 1240 RelocInfoWriter reloc_info_writer; 1241 1242 PositionsRecorder positions_recorder_; 1243 friend class PositionsRecorder; 1244 }; 1245 1246 1247 // Helper class that ensures that there is enough space for generating 1248 // instructions and relocation information. The constructor makes 1249 // sure that there is enough space and (in debug mode) the destructor 1250 // checks that we did not generate too much. 1251 class EnsureSpace BASE_EMBEDDED { 1252 public: 1253 explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) { 1254 if (assembler_->overflow()) assembler_->GrowBuffer(); 1255 #ifdef DEBUG 1256 space_before_ = assembler_->available_space(); 1257 #endif 1258 } 1259 1260 #ifdef DEBUG 1261 ~EnsureSpace() { 1262 int bytes_generated = space_before_ - assembler_->available_space(); 1263 ASSERT(bytes_generated < assembler_->kGap); 1264 } 1265 #endif 1266 1267 private: 1268 Assembler* assembler_; 1269 #ifdef DEBUG 1270 int space_before_; 1271 #endif 1272 }; 1273 1274 } } // namespace v8::internal 1275 1276 #endif // V8_IA32_ASSEMBLER_IA32_H_ 1277