assembler-x87.h 34.8 KB
Newer Older
danno@chromium.org's avatar
danno@chromium.org committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the name of Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2011 the V8 project authors. All rights reserved.

// A light-weight IA32 Assembler.

#ifndef V8_X87_ASSEMBLER_X87_H_
#define V8_X87_ASSEMBLER_X87_H_

40 41
#include <deque>

42
#include "src/assembler.h"
43
#include "src/isolate.h"
44
#include "src/utils.h"
danno@chromium.org's avatar
danno@chromium.org committed
45 46 47 48

namespace v8 {
namespace internal {

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
#define GENERAL_REGISTERS(V) \
  V(eax)                     \
  V(ecx)                     \
  V(edx)                     \
  V(ebx)                     \
  V(esp)                     \
  V(ebp)                     \
  V(esi)                     \
  V(edi)

#define ALLOCATABLE_GENERAL_REGISTERS(V) \
  V(eax)                                 \
  V(ecx)                                 \
  V(edx)                                 \
  V(ebx)                                 \
  V(esi)                                 \
  V(edi)

#define DOUBLE_REGISTERS(V) \
  V(stX_0)                  \
  V(stX_1)                  \
  V(stX_2)                  \
  V(stX_3)                  \
  V(stX_4)                  \
  V(stX_5)                  \
  V(stX_6)                  \
  V(stX_7)

#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
  V(stX_0)                              \
  V(stX_1)                              \
  V(stX_2)                              \
  V(stX_3)                              \
  V(stX_4)                              \
  V(stX_5)

danno@chromium.org's avatar
danno@chromium.org committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
// CPU Registers.
//
// 1) We would prefer to use an enum, but enum values are assignment-
// compatible with int, which has caused code-generation bugs.
//
// 2) We would prefer to use a class instead of a struct but we don't like
// the register initialization to depend on the particular initialization
// order (which appears to be different on OS X, Linux, and Windows for the
// installed versions of C++ we tried). Using a struct permits C-style
// "initialization". Also, the Register objects cannot be const as this
// forces initialization stubs in MSVC, making us dependent on initialization
// order.
//
// 3) By not using an enum, we are possibly preventing the compiler from
// doing certain constant folds, which may significantly reduce the
// code generated for some assembly instructions (because they boil down
// to a few constants). If this is a problem, we could change the code
// such that we use an enum in optimized mode, and the struct in debug
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
//
struct Register {
107 108 109 110 111 112 113
  enum Code {
#define REGISTER_CODE(R) kCode_##R,
    GENERAL_REGISTERS(REGISTER_CODE)
#undef REGISTER_CODE
        kAfterLast,
    kCode_no_reg = -1
  };
danno@chromium.org's avatar
danno@chromium.org committed
114

115
  static const int kNumRegisters = Code::kAfterLast;
danno@chromium.org's avatar
danno@chromium.org committed
116 117

  static Register from_code(int code) {
118 119
    DCHECK(code >= 0);
    DCHECK(code < kNumRegisters);
120
    Register r = {code};
danno@chromium.org's avatar
danno@chromium.org committed
121 122
    return r;
  }
123 124 125 126
  const char* ToString();
  bool IsAllocatable() const;
  bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
  bool is(Register reg) const { return reg_code == reg.reg_code; }
danno@chromium.org's avatar
danno@chromium.org committed
127
  int code() const {
128
    DCHECK(is_valid());
129
    return reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
130 131
  }
  int bit() const {
132
    DCHECK(is_valid());
133
    return 1 << reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
134 135
  }

136 137
  bool is_byte_register() const { return reg_code <= 3; }

danno@chromium.org's avatar
danno@chromium.org committed
138
  // Unfortunately we can't make this private in a struct.
139
  int reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
140 141
};

142

143 144 145 146
#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
GENERAL_REGISTERS(DECLARE_REGISTER)
#undef DECLARE_REGISTER
const Register no_reg = {Register::kCode_no_reg};
147 148


149 150 151 152 153 154 155 156
struct DoubleRegister {
  enum Code {
#define REGISTER_CODE(R) kCode_##R,
    DOUBLE_REGISTERS(REGISTER_CODE)
#undef REGISTER_CODE
        kAfterLast,
    kCode_no_reg = -1
  };
danno@chromium.org's avatar
danno@chromium.org committed
157

158 159
  static const int kMaxNumRegisters = Code::kAfterLast;
  static const int kMaxNumAllocatableRegisters = 6;
danno@chromium.org's avatar
danno@chromium.org committed
160

161 162
  static DoubleRegister from_code(int code) {
    DoubleRegister result = {code};
danno@chromium.org's avatar
danno@chromium.org committed
163 164 165
    return result;
  }

166 167
  bool IsAllocatable() const;
  bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
danno@chromium.org's avatar
danno@chromium.org committed
168 169

  int code() const {
170
    DCHECK(is_valid());
171
    return reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
172 173
  }

174
  bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
danno@chromium.org's avatar
danno@chromium.org committed
175

176
  const char* ToString();
danno@chromium.org's avatar
danno@chromium.org committed
177

178 179
  int reg_code;
};
danno@chromium.org's avatar
danno@chromium.org committed
180

181 182 183 184 185
#define DECLARE_REGISTER(R) \
  const DoubleRegister R = {DoubleRegister::kCode_##R};
DOUBLE_REGISTERS(DECLARE_REGISTER)
#undef DECLARE_REGISTER
const DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg};
danno@chromium.org's avatar
danno@chromium.org committed
186

187
typedef DoubleRegister X87Register;
danno@chromium.org's avatar
danno@chromium.org committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

enum Condition {
  // any value < 0 is considered no_condition
  no_condition  = -1,

  overflow      =  0,
  no_overflow   =  1,
  below         =  2,
  above_equal   =  3,
  equal         =  4,
  not_equal     =  5,
  below_equal   =  6,
  above         =  7,
  negative      =  8,
  positive      =  9,
  parity_even   = 10,
  parity_odd    = 11,
  less          = 12,
  greater_equal = 13,
  less_equal    = 14,
  greater       = 15,

  // aliases
  carry         = below,
  not_carry     = above_equal,
  zero          = equal,
  not_zero      = not_equal,
  sign          = negative,
  not_sign      = positive
};


// Returns the equivalent of !cc.
// Negation of the default no_condition (-1) results in a non-default
// no_condition value (-2). As long as tests for no_condition check
// for condition < 0, this will work as expected.
inline Condition NegateCondition(Condition cc) {
  return static_cast<Condition>(cc ^ 1);
}


229
// Commute a condition such that {a cond b == b cond' a}.
230
inline Condition CommuteCondition(Condition cc) {
danno@chromium.org's avatar
danno@chromium.org committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
  switch (cc) {
    case below:
      return above;
    case above:
      return below;
    case above_equal:
      return below_equal;
    case below_equal:
      return above_equal;
    case less:
      return greater;
    case greater:
      return less;
    case greater_equal:
      return less_equal;
    case less_equal:
      return greater_equal;
    default:
      return cc;
  }
}


254 255 256 257 258 259 260 261
enum RoundingMode {
  kRoundToNearest = 0x0,
  kRoundDown = 0x1,
  kRoundUp = 0x2,
  kRoundToZero = 0x3
};


danno@chromium.org's avatar
danno@chromium.org committed
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
// -----------------------------------------------------------------------------
// Machine instruction Immediates

class Immediate BASE_EMBEDDED {
 public:
  inline explicit Immediate(int x);
  inline explicit Immediate(const ExternalReference& ext);
  inline explicit Immediate(Handle<Object> handle);
  inline explicit Immediate(Smi* value);
  inline explicit Immediate(Address addr);

  static Immediate CodeRelativeOffset(Label* label) {
    return Immediate(label);
  }

  bool is_zero() const { return x_ == 0 && RelocInfo::IsNone(rmode_); }
  bool is_int8() const {
    return -128 <= x_ && x_ < 128 && RelocInfo::IsNone(rmode_);
  }
  bool is_int16() const {
    return -32768 <= x_ && x_ < 32768 && RelocInfo::IsNone(rmode_);
  }

 private:
  inline explicit Immediate(Label* value);

  int x_;
  RelocInfo::Mode rmode_;

291
  friend class Operand;
danno@chromium.org's avatar
danno@chromium.org committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
  friend class Assembler;
  friend class MacroAssembler;
};


// -----------------------------------------------------------------------------
// Machine instruction Operands

enum ScaleFactor {
  times_1 = 0,
  times_2 = 1,
  times_4 = 2,
  times_8 = 3,
  times_int_size = times_4,
  times_half_pointer_size = times_2,
  times_pointer_size = times_4,
  times_twice_pointer_size = times_8
};


class Operand BASE_EMBEDDED {
 public:
314 315 316
  // reg
  INLINE(explicit Operand(Register reg));

danno@chromium.org's avatar
danno@chromium.org committed
317 318
  // [disp/r]
  INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
319 320 321

  // [disp/r]
  INLINE(explicit Operand(Immediate imm));
danno@chromium.org's avatar
danno@chromium.org committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

  // [base + disp/r]
  explicit Operand(Register base, int32_t disp,
                   RelocInfo::Mode rmode = RelocInfo::NONE32);

  // [base + index*scale + disp/r]
  explicit Operand(Register base,
                   Register index,
                   ScaleFactor scale,
                   int32_t disp,
                   RelocInfo::Mode rmode = RelocInfo::NONE32);

  // [index*scale + disp/r]
  explicit Operand(Register index,
                   ScaleFactor scale,
                   int32_t disp,
                   RelocInfo::Mode rmode = RelocInfo::NONE32);

340 341 342 343 344
  static Operand JumpTable(Register index, ScaleFactor scale, Label* table) {
    return Operand(index, scale, reinterpret_cast<int32_t>(table),
                   RelocInfo::INTERNAL_REFERENCE);
  }

danno@chromium.org's avatar
danno@chromium.org committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
  static Operand StaticVariable(const ExternalReference& ext) {
    return Operand(reinterpret_cast<int32_t>(ext.address()),
                   RelocInfo::EXTERNAL_REFERENCE);
  }

  static Operand StaticArray(Register index,
                             ScaleFactor scale,
                             const ExternalReference& arr) {
    return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
                   RelocInfo::EXTERNAL_REFERENCE);
  }

  static Operand ForCell(Handle<Cell> cell) {
    AllowDeferredHandleDereference embedding_raw_address;
    return Operand(reinterpret_cast<int32_t>(cell.location()),
                   RelocInfo::CELL);
  }

363 364 365 366
  static Operand ForRegisterPlusImmediate(Register base, Immediate imm) {
    return Operand(base, imm.x_, imm.rmode_);
  }

danno@chromium.org's avatar
danno@chromium.org committed
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
  // Returns true if this Operand is a wrapper for the specified register.
  bool is_reg(Register reg) const;

  // Returns true if this Operand is a wrapper for one register.
  bool is_reg_only() const;

  // Asserts that this Operand is a wrapper for one register and returns the
  // register.
  Register reg() const;

 private:
  // Set the ModRM byte without an encoded 'reg' register. The
  // register is encoded later as part of the emit_operand operation.
  inline void set_modrm(int mod, Register rm);

  inline void set_sib(ScaleFactor scale, Register index, Register base);
  inline void set_disp8(int8_t disp);
  inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);

  byte buf_[6];
  // The number of bytes in buf_.
  unsigned int len_;
  // Only valid if len_ > 4.
  RelocInfo::Mode rmode_;

  friend class Assembler;
  friend class MacroAssembler;
};


// -----------------------------------------------------------------------------
// A Displacement describes the 32bit immediate field of an instruction which
// may be used together with a Label in order to refer to a yet unknown code
// position. Displacements stored in the instruction stream are used to describe
// the instruction and to chain a list of instructions using the same Label.
// A Displacement contains 2 different fields:
//
// next field: position of next displacement in the chain (0 = end of list)
// type field: instruction type
//
// A next value of null (0) indicates the end of a chain (note that there can
// be no displacement at position zero, because there is always at least one
// instruction byte before the displacement).
//
// Displacement _data field layout
//
// |31.....2|1......0|
// [  next  |  type  |

class Displacement BASE_EMBEDDED {
 public:
418
  enum Type { UNCONDITIONAL_JUMP, CODE_RELATIVE, OTHER, CODE_ABSOLUTE };
danno@chromium.org's avatar
danno@chromium.org committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483

  int data() const { return data_; }
  Type type() const { return TypeField::decode(data_); }
  void next(Label* L) const {
    int n = NextField::decode(data_);
    n > 0 ? L->link_to(n) : L->Unuse();
  }
  void link_to(Label* L) { init(L, type()); }

  explicit Displacement(int data) { data_ = data; }

  Displacement(Label* L, Type type) { init(L, type); }

  void print() {
    PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
                       NextField::decode(data_));
  }

 private:
  int data_;

  class TypeField: public BitField<Type, 0, 2> {};
  class NextField: public BitField<int,  2, 32-2> {};

  void init(Label* L, Type type);
};


class Assembler : public AssemblerBase {
 private:
  // We check before assembling an instruction that there is sufficient
  // space to write an instruction and its relocation information.
  // The relocation writer's position must be kGap bytes above the end of
  // the generated instructions. This leaves enough space for the
  // longest possible ia32 instruction, 15 bytes, and the longest possible
  // relocation information encoding, RelocInfoWriter::kMaxLength == 16.
  // (There is a 15 byte limit on ia32 instruction length that rules out some
  // otherwise valid instructions.)
  // This allows for a single, fast space check per instruction.
  static const int kGap = 32;

 public:
  // Create an assembler. Instructions and relocation information are emitted
  // into a buffer, with the instructions starting from the beginning and the
  // relocation information starting from the end of the buffer. See CodeDesc
  // for a detailed comment on the layout (globals.h).
  //
  // If the provided buffer is NULL, the assembler allocates and grows its own
  // buffer, and buffer_size determines the initial buffer size. The buffer is
  // owned by the assembler and deallocated upon destruction of the assembler.
  //
  // If the provided buffer is not NULL, the assembler uses the provided buffer
  // for code generation and assumes its size to be buffer_size. If the buffer
  // is too small, a fatal error occurs. No deallocation of the buffer is done
  // upon destruction of the assembler.
  // TODO(vitalyr): the assembler does not need an isolate.
  Assembler(Isolate* isolate, void* buffer, int buffer_size);
  virtual ~Assembler() { }

  // GetCode emits any pending (non-emitted) code and fills the descriptor
  // desc. GetCode() is idempotent; it returns the same result if no other
  // Assembler functions are invoked in between GetCode() calls.
  void GetCode(CodeDesc* desc);

  // Read/Modify the code target in the branch/call instruction at pc.
484 485
  inline static Address target_address_at(Address pc, Address constant_pool);
  inline static void set_target_address_at(
486
      Isolate* isolate, Address pc, Address constant_pool, Address target,
487
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
danno@chromium.org's avatar
danno@chromium.org committed
488
  static inline Address target_address_at(Address pc, Code* code) {
489
    Address constant_pool = code ? code->constant_pool() : NULL;
danno@chromium.org's avatar
danno@chromium.org committed
490 491
    return target_address_at(pc, constant_pool);
  }
492 493 494
  static inline void set_target_address_at(
      Isolate* isolate, Address pc, Code* code, Address target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) {
495
    Address constant_pool = code ? code->constant_pool() : NULL;
496
    set_target_address_at(isolate, pc, constant_pool, target);
danno@chromium.org's avatar
danno@chromium.org committed
497 498 499 500 501 502 503 504 505
  }

  // Return the code target address at a call site from the return address
  // of that call in the instruction stream.
  inline static Address target_address_from_return_address(Address pc);

  // This sets the branch destination (which is in the instruction on x86).
  // This is for calls and branches within generated code.
  inline static void deserialization_set_special_target_at(
506 507 508
      Isolate* isolate, Address instruction_payload, Code* code,
      Address target) {
    set_target_address_at(isolate, instruction_payload, code, target);
danno@chromium.org's avatar
danno@chromium.org committed
509 510
  }

511 512
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
513
      Isolate* isolate, Address pc, Address target,
514 515
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);

danno@chromium.org's avatar
danno@chromium.org committed
516 517 518 519 520 521 522 523 524 525 526
  static const int kSpecialTargetSize = kPointerSize;

  // Distance between the address of the code target in the call instruction
  // and the return address
  static const int kCallTargetAddressOffset = kPointerSize;

  static const int kCallInstructionLength = 5;

  // The debug break slot must be able to contain a call instruction.
  static const int kDebugBreakSlotLength = kCallInstructionLength;

527 528 529 530
  // Distance between start of patched debug break slot and the emitted address
  // to jump to.
  static const int kPatchDebugBreakSlotAddressOffset = 1;  // JMP imm32.

danno@chromium.org's avatar
danno@chromium.org committed
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
  // One byte opcode for test al, 0xXX.
  static const byte kTestAlByte = 0xA8;
  // One byte opcode for nop.
  static const byte kNopByte = 0x90;

  // One byte opcode for a short unconditional jump.
  static const byte kJmpShortOpcode = 0xEB;
  // One byte prefix for a short conditional jump.
  static const byte kJccShortPrefix = 0x70;
  static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
  static const byte kJcShortOpcode = kJccShortPrefix | carry;
  static const byte kJnzShortOpcode = kJccShortPrefix | not_zero;
  static const byte kJzShortOpcode = kJccShortPrefix | zero;


  // ---------------------------------------------------------------------------
  // Code generation
  //
  // - function names correspond one-to-one to ia32 instruction mnemonics
  // - unless specified otherwise, instructions operate on 32bit operands
  // - instructions on 8bit (byte) operands/registers have a trailing '_b'
  // - instructions on 16bit (word) operands/registers have a trailing '_w'
  // - naming conflicts with C++ keywords are resolved via a trailing '_'

  // NOTE ON INTERFACE: Currently, the interface is not very consistent
  // in the sense that some operations (e.g. mov()) can be called in more
  // the one way to generate the same instruction: The Register argument
  // can in some cases be replaced with an Operand(Register) argument.
  // This should be cleaned up and made more orthogonal. The questions
  // is: should we always use Operands instead of Registers where an
  // Operand is possible, or should we have a Register (overloaded) form
  // instead? We must be careful to make sure that the selected instruction
  // is obvious from the parameters to avoid hard-to-find code generation
  // bugs.

  // Insert the smallest number of nop instructions
  // possible to align the pc offset to a multiple
  // of m. m must be a power of 2.
  void Align(int m);
570 571 572
  // Insert the smallest number of zero bytes possible to align the pc offset
  // to a mulitple of m. m must be a power of 2 (>= 2).
  void DataAlign(int m);
danno@chromium.org's avatar
danno@chromium.org committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  void Nop(int bytes = 1);
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();

  // Stack
  void pushad();
  void popad();

  void pushfd();
  void popfd();

  void push(const Immediate& x);
  void push_imm32(int32_t imm32);
  void push(Register src);
  void push(const Operand& src);

  void pop(Register dst);
  void pop(const Operand& dst);

  void enter(const Immediate& size);
  void leave();

  // Moves
  void mov_b(Register dst, Register src) { mov_b(dst, Operand(src)); }
  void mov_b(Register dst, const Operand& src);
  void mov_b(Register dst, int8_t imm8) { mov_b(Operand(dst), imm8); }
  void mov_b(const Operand& dst, int8_t imm8);
600
  void mov_b(const Operand& dst, const Immediate& src);
danno@chromium.org's avatar
danno@chromium.org committed
601 602 603 604 605
  void mov_b(const Operand& dst, Register src);

  void mov_w(Register dst, const Operand& src);
  void mov_w(const Operand& dst, Register src);
  void mov_w(const Operand& dst, int16_t imm16);
606 607
  void mov_w(const Operand& dst, const Immediate& src);

danno@chromium.org's avatar
danno@chromium.org committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637

  void mov(Register dst, int32_t imm32);
  void mov(Register dst, const Immediate& x);
  void mov(Register dst, Handle<Object> handle);
  void mov(Register dst, const Operand& src);
  void mov(Register dst, Register src);
  void mov(const Operand& dst, const Immediate& x);
  void mov(const Operand& dst, Handle<Object> handle);
  void mov(const Operand& dst, Register src);

  void movsx_b(Register dst, Register src) { movsx_b(dst, Operand(src)); }
  void movsx_b(Register dst, const Operand& src);

  void movsx_w(Register dst, Register src) { movsx_w(dst, Operand(src)); }
  void movsx_w(Register dst, const Operand& src);

  void movzx_b(Register dst, Register src) { movzx_b(dst, Operand(src)); }
  void movzx_b(Register dst, const Operand& src);

  void movzx_w(Register dst, Register src) { movzx_w(dst, Operand(src)); }
  void movzx_w(Register dst, const Operand& src);

  // Flag management.
  void cld();

  // Repetitive string instructions.
  void rep_movs();
  void rep_stos();
  void stos();

638
  // Exchange
danno@chromium.org's avatar
danno@chromium.org committed
639
  void xchg(Register dst, Register src);
640
  void xchg(Register dst, const Operand& src);
danno@chromium.org's avatar
danno@chromium.org committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

  // Arithmetics
  void adc(Register dst, int32_t imm32);
  void adc(Register dst, const Operand& src);

  void add(Register dst, Register src) { add(dst, Operand(src)); }
  void add(Register dst, const Operand& src);
  void add(const Operand& dst, Register src);
  void add(Register dst, const Immediate& imm) { add(Operand(dst), imm); }
  void add(const Operand& dst, const Immediate& x);

  void and_(Register dst, int32_t imm32);
  void and_(Register dst, const Immediate& x);
  void and_(Register dst, Register src) { and_(dst, Operand(src)); }
  void and_(Register dst, const Operand& src);
  void and_(const Operand& dst, Register src);
  void and_(const Operand& dst, const Immediate& x);

  void cmpb(Register reg, int8_t imm8) { cmpb(Operand(reg), imm8); }
  void cmpb(const Operand& op, int8_t imm8);
  void cmpb(Register reg, const Operand& op);
  void cmpb(const Operand& op, Register reg);
  void cmpb_al(const Operand& op);
  void cmpw_ax(const Operand& op);
  void cmpw(const Operand& op, Immediate imm16);
  void cmp(Register reg, int32_t imm32);
  void cmp(Register reg, Handle<Object> handle);
  void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); }
  void cmp(Register reg, const Operand& op);
  void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); }
  void cmp(const Operand& op, const Immediate& imm);
  void cmp(const Operand& op, Handle<Object> handle);

  void dec_b(Register dst);
  void dec_b(const Operand& dst);

  void dec(Register dst);
  void dec(const Operand& dst);

  void cdq();

682 683 684 685
  void idiv(Register src) { idiv(Operand(src)); }
  void idiv(const Operand& src);
  void div(Register src) { div(Operand(src)); }
  void div(const Operand& src);
danno@chromium.org's avatar
danno@chromium.org committed
686 687 688 689 690 691

  // Signed multiply instructions.
  void imul(Register src);                               // edx:eax = eax * src.
  void imul(Register dst, Register src) { imul(dst, Operand(src)); }
  void imul(Register dst, const Operand& src);           // dst = dst * src.
  void imul(Register dst, Register src, int32_t imm32);  // dst = src * imm32.
692
  void imul(Register dst, const Operand& src, int32_t imm32);
danno@chromium.org's avatar
danno@chromium.org committed
693 694 695 696 697 698 699 700 701 702

  void inc(Register dst);
  void inc(const Operand& dst);

  void lea(Register dst, const Operand& src);

  // Unsigned multiply instruction.
  void mul(Register src);                                // edx:eax = eax * reg.

  void neg(Register dst);
703
  void neg(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
704 705

  void not_(Register dst);
706
  void not_(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
707 708 709 710 711 712 713 714 715 716

  void or_(Register dst, int32_t imm32);
  void or_(Register dst, Register src) { or_(dst, Operand(src)); }
  void or_(Register dst, const Operand& src);
  void or_(const Operand& dst, Register src);
  void or_(Register dst, const Immediate& imm) { or_(Operand(dst), imm); }
  void or_(const Operand& dst, const Immediate& x);

  void rcl(Register dst, uint8_t imm8);
  void rcr(Register dst, uint8_t imm8);
717 718 719 720 721

  void ror(Register dst, uint8_t imm8) { ror(Operand(dst), imm8); }
  void ror(const Operand& dst, uint8_t imm8);
  void ror_cl(Register dst) { ror_cl(Operand(dst)); }
  void ror_cl(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
722

723 724 725 726
  void sar(Register dst, uint8_t imm8) { sar(Operand(dst), imm8); }
  void sar(const Operand& dst, uint8_t imm8);
  void sar_cl(Register dst) { sar_cl(Operand(dst)); }
  void sar_cl(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
727 728 729 730 731 732

  void sbb(Register dst, const Operand& src);

  void shld(Register dst, Register src) { shld(dst, Operand(src)); }
  void shld(Register dst, const Operand& src);

733 734 735 736
  void shl(Register dst, uint8_t imm8) { shl(Operand(dst), imm8); }
  void shl(const Operand& dst, uint8_t imm8);
  void shl_cl(Register dst) { shl_cl(Operand(dst)); }
  void shl_cl(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
737 738 739 740

  void shrd(Register dst, Register src) { shrd(dst, Operand(src)); }
  void shrd(Register dst, const Operand& src);

741 742 743 744
  void shr(Register dst, uint8_t imm8) { shr(Operand(dst), imm8); }
  void shr(const Operand& dst, uint8_t imm8);
  void shr_cl(Register dst) { shr_cl(Operand(dst)); }
  void shr_cl(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772

  void sub(Register dst, const Immediate& imm) { sub(Operand(dst), imm); }
  void sub(const Operand& dst, const Immediate& x);
  void sub(Register dst, Register src) { sub(dst, Operand(src)); }
  void sub(Register dst, const Operand& src);
  void sub(const Operand& dst, Register src);

  void test(Register reg, const Immediate& imm);
  void test(Register reg0, Register reg1) { test(reg0, Operand(reg1)); }
  void test(Register reg, const Operand& op);
  void test_b(Register reg, const Operand& op);
  void test(const Operand& op, const Immediate& imm);
  void test_b(Register reg, uint8_t imm8);
  void test_b(const Operand& op, uint8_t imm8);

  void xor_(Register dst, int32_t imm32);
  void xor_(Register dst, Register src) { xor_(dst, Operand(src)); }
  void xor_(Register dst, const Operand& src);
  void xor_(const Operand& dst, Register src);
  void xor_(Register dst, const Immediate& imm) { xor_(Operand(dst), imm); }
  void xor_(const Operand& dst, const Immediate& x);

  // Bit operations.
  void bt(const Operand& dst, Register src);
  void bts(Register dst, Register src) { bts(Operand(dst), src); }
  void bts(const Operand& dst, Register src);
  void bsr(Register dst, Register src) { bsr(dst, Operand(src)); }
  void bsr(Register dst, const Operand& src);
773 774
  void bsf(Register dst, Register src) { bsf(dst, Operand(src)); }
  void bsf(Register dst, const Operand& src);
danno@chromium.org's avatar
danno@chromium.org committed
775 776 777 778 779 780

  // Miscellaneous
  void hlt();
  void int3();
  void nop();
  void ret(int imm16);
781
  void ud2();
danno@chromium.org's avatar
danno@chromium.org committed
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823

  // Label operations & relative jumps (PPUM Appendix D)
  //
  // Takes a branch opcode (cc) and a label (L) and generates
  // either a backward branch or a forward branch and links it
  // to the label fixup chain. Usage:
  //
  // Label L;    // unbound label
  // j(cc, &L);  // forward branch to unbound label
  // bind(&L);   // bind label to the current pc
  // j(cc, &L);  // backward branch to bound label
  // bind(&L);   // illegal: a label may be bound only once
  //
  // Note: The same Label can be used for forward and backward branches
  // but it may be bound only once.

  void bind(Label* L);  // binds an unbound label L to the current code position

  // Calls
  void call(Label* L);
  void call(byte* entry, RelocInfo::Mode rmode);
  int CallSize(const Operand& adr);
  void call(Register reg) { call(Operand(reg)); }
  void call(const Operand& adr);
  int CallSize(Handle<Code> code, RelocInfo::Mode mode);
  void call(Handle<Code> code,
            RelocInfo::Mode rmode,
            TypeFeedbackId id = TypeFeedbackId::None());

  // Jumps
  // unconditional jump to L
  void jmp(Label* L, Label::Distance distance = Label::kFar);
  void jmp(byte* entry, RelocInfo::Mode rmode);
  void jmp(Register reg) { jmp(Operand(reg)); }
  void jmp(const Operand& adr);
  void jmp(Handle<Code> code, RelocInfo::Mode rmode);

  // Conditional jumps
  void j(Condition cc,
         Label* L,
         Label::Distance distance = Label::kFar);
  void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
824 825
  void j(Condition cc, Handle<Code> code,
         RelocInfo::Mode rmode = RelocInfo::CODE_TARGET);
danno@chromium.org's avatar
danno@chromium.org committed
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857

  // Floating-point operations
  void fld(int i);
  void fstp(int i);

  void fld1();
  void fldz();
  void fldpi();
  void fldln2();

  void fld_s(const Operand& adr);
  void fld_d(const Operand& adr);

  void fstp_s(const Operand& adr);
  void fst_s(const Operand& adr);
  void fstp_d(const Operand& adr);
  void fst_d(const Operand& adr);

  void fild_s(const Operand& adr);
  void fild_d(const Operand& adr);

  void fist_s(const Operand& adr);

  void fistp_s(const Operand& adr);
  void fistp_d(const Operand& adr);

  // The fisttp instructions require SSE3.
  void fisttp_s(const Operand& adr);
  void fisttp_d(const Operand& adr);

  void fabs();
  void fchs();
858
  void fsqrt();
danno@chromium.org's avatar
danno@chromium.org committed
859 860 861 862 863 864 865 866 867 868
  void fcos();
  void fsin();
  void fptan();
  void fyl2x();
  void f2xm1();
  void fscale();
  void fninit();

  void fadd(int i);
  void fadd_i(int i);
869
  void fadd_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
870 871
  void fsub(int i);
  void fsub_i(int i);
872 873
  void fsub_d(const Operand& adr);
  void fsubr_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
874
  void fmul(int i);
875
  void fmul_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
876 877
  void fmul_i(int i);
  void fdiv(int i);
878 879
  void fdiv_d(const Operand& adr);
  void fdivr_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
880 881 882 883 884 885
  void fdiv_i(int i);

  void fisub_s(const Operand& adr);

  void faddp(int i = 1);
  void fsubp(int i = 1);
886
  void fsubr(int i = 1);
danno@chromium.org's avatar
danno@chromium.org committed
887 888 889 890 891 892 893 894 895 896 897
  void fsubrp(int i = 1);
  void fmulp(int i = 1);
  void fdivp(int i = 1);
  void fprem();
  void fprem1();

  void fxch(int i = 1);
  void fincstp();
  void ffree(int i = 0);

  void ftst();
898
  void fxam();
danno@chromium.org's avatar
danno@chromium.org committed
899 900 901 902 903 904
  void fucomp(int i);
  void fucompp();
  void fucomi(int i);
  void fucomip();
  void fcompp();
  void fnstsw_ax();
905 906
  void fldcw(const Operand& adr);
  void fnstcw(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
907 908
  void fwait();
  void fnclex();
909 910
  void fnsave(const Operand& adr);
  void frstor(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925

  void frndint();

  void sahf();
  void setcc(Condition cc, Register reg);

  void cpuid();

  // TODO(lrn): Need SFENCE for movnt?

  // Check the code size generated from label to here.
  int SizeOfCodeGeneratedSince(Label* label) {
    return pc_offset() - label->pos();
  }

926 927 928
  // Mark generator continuation.
  void RecordGeneratorContinuation();

danno@chromium.org's avatar
danno@chromium.org committed
929
  // Mark address of a debug break slot.
930
  void RecordDebugBreakSlot(RelocInfo::Mode mode);
danno@chromium.org's avatar
danno@chromium.org committed
931 932

  // Record a comment relocation entry that can be used by a disassembler.
933 934
  // Use --code-comments to enable.
  void RecordComment(const char* msg);
danno@chromium.org's avatar
danno@chromium.org committed
935

936 937
  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
938
  void RecordDeoptReason(const int reason, int raw_position);
939

danno@chromium.org's avatar
danno@chromium.org committed
940 941 942 943
  // Writes a single byte or word of data in the code stream.  Used for
  // inline tables, e.g., jump-tables.
  void db(uint8_t data);
  void dd(uint32_t data);
944 945
  void dq(uint64_t data);
  void dp(uintptr_t data) { dd(data); }
946
  void dd(Label* label);
danno@chromium.org's avatar
danno@chromium.org committed
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971

  // Check if there is less than kGap bytes available in the buffer.
  // If this is the case, we need to grow the buffer before emitting
  // an instruction or relocation information.
  inline bool buffer_overflow() const {
    return pc_ >= reloc_info_writer.pos() - kGap;
  }

  // Get the number of bytes available in the buffer.
  inline int available_space() const { return reloc_info_writer.pos() - pc_; }

  static bool IsNop(Address addr);

  PositionsRecorder* positions_recorder() { return &positions_recorder_; }

  int relocation_writer_size() {
    return (buffer_ + buffer_size_) - reloc_info_writer.pos();
  }

  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512*MB;

  byte byte_at(int pos) { return buffer_[pos]; }
  void set_byte_at(int pos, byte value) { buffer_[pos] = value; }

972 973 974 975 976 977
  void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
                                          ConstantPoolEntry::Access access,
                                          ConstantPoolEntry::Type type) {
    // No embedded constant pool support.
    UNREACHABLE();
  }
danno@chromium.org's avatar
danno@chromium.org committed
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002

 protected:
  byte* addr_at(int pos) { return buffer_ + pos; }


 private:
  uint32_t long_at(int pos)  {
    return *reinterpret_cast<uint32_t*>(addr_at(pos));
  }
  void long_at_put(int pos, uint32_t x)  {
    *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
  }

  // code emission
  void GrowBuffer();
  inline void emit(uint32_t x);
  inline void emit(Handle<Object> handle);
  inline void emit(uint32_t x,
                   RelocInfo::Mode rmode,
                   TypeFeedbackId id = TypeFeedbackId::None());
  inline void emit(Handle<Code> code,
                   RelocInfo::Mode rmode,
                   TypeFeedbackId id = TypeFeedbackId::None());
  inline void emit(const Immediate& x);
  inline void emit_w(const Immediate& x);
1003
  inline void emit_q(uint64_t x);
danno@chromium.org's avatar
danno@chromium.org committed
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018

  // Emit the code-object-relative offset of the label's position
  inline void emit_code_relative_offset(Label* label);

  // instruction generation
  void emit_arith_b(int op1, int op2, Register dst, int imm8);

  // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
  // with a given destination expression and an immediate operand.  It attempts
  // to use the shortest encoding possible.
  // sel specifies the /n in the modrm byte (see the Intel PRM).
  void emit_arith(int sel, Operand dst, const Immediate& x);

  void emit_operand(Register reg, const Operand& adr);

1019 1020
  void emit_label(Label* label);

danno@chromium.org's avatar
danno@chromium.org committed
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
  void emit_farith(int b1, int b2, int i);

  // labels
  void print(Label* L);
  void bind_to(Label* L, int pos);

  // displacements
  inline Displacement disp_at(Label* L);
  inline void disp_at_put(Label* L, Displacement disp);
  inline void emit_disp(Label* L, Displacement::Type type);
  inline void emit_near_disp(Label* L);

  // record reloc info for current pc_
  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);

  friend class CodePatcher;
  friend class EnsureSpace;

1039 1040 1041 1042 1043
  // Internal reference positions, required for (potential) patching in
  // GrowBuffer(); contains only those internal references whose labels
  // are already bound.
  std::deque<int> internal_reference_positions_;

danno@chromium.org's avatar
danno@chromium.org committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
  // code generation
  RelocInfoWriter reloc_info_writer;

  PositionsRecorder positions_recorder_;
  friend class PositionsRecorder;
};


// Helper class that ensures that there is enough space for generating
// instructions and relocation information.  The constructor makes
// sure that there is enough space and (in debug mode) the destructor
// checks that we did not generate too much.
class EnsureSpace BASE_EMBEDDED {
 public:
  explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
    if (assembler_->buffer_overflow()) assembler_->GrowBuffer();
#ifdef DEBUG
    space_before_ = assembler_->available_space();
#endif
  }

#ifdef DEBUG
  ~EnsureSpace() {
    int bytes_generated = space_before_ - assembler_->available_space();
1068
    DCHECK(bytes_generated < assembler_->kGap);
danno@chromium.org's avatar
danno@chromium.org committed
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
  }
#endif

 private:
  Assembler* assembler_;
#ifdef DEBUG
  int space_before_;
#endif
};

1079 1080
}  // namespace internal
}  // namespace v8
danno@chromium.org's avatar
danno@chromium.org committed
1081 1082

#endif  // V8_X87_ASSEMBLER_X87_H_