assembler-x87.h 36.2 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
#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)

77
#define FLOAT_REGISTERS DOUBLE_REGISTERS
78
#define SIMD128_REGISTERS DOUBLE_REGISTERS
79

80 81 82 83 84 85 86 87
#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
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// 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 {
110 111 112 113 114 115 116
  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
117

118
  static const int kNumRegisters = Code::kAfterLast;
danno@chromium.org's avatar
danno@chromium.org committed
119 120

  static Register from_code(int code) {
121 122
    DCHECK(code >= 0);
    DCHECK(code < kNumRegisters);
123
    Register r = {code};
danno@chromium.org's avatar
danno@chromium.org committed
124 125
    return r;
  }
126 127
  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
128
  int code() const {
129
    DCHECK(is_valid());
130
    return reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
131 132
  }
  int bit() const {
133
    DCHECK(is_valid());
134
    return 1 << reg_code;
danno@chromium.org's avatar
danno@chromium.org committed
135 136
  }

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

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

143

144 145 146 147
#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};
148

149 150
static const bool kSimpleFPAliasing = true;

151
struct X87Register {
152 153 154 155 156 157 158
  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
159

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

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

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

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

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

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

180 181 182 183 184 185 186
typedef X87Register FloatRegister;

typedef X87Register DoubleRegister;

// TODO(x87) Define SIMD registers.
typedef X87Register Simd128Register;

187 188 189 190 191
#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
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 229 230 231 232

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);
}


233
// Commute a condition such that {a cond b == b cond' a}.
234
inline Condition CommuteCondition(Condition cc) {
danno@chromium.org's avatar
danno@chromium.org committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  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;
  }
}


258 259 260 261 262 263 264 265
enum RoundingMode {
  kRoundToNearest = 0x0,
  kRoundDown = 0x1,
  kRoundUp = 0x2,
  kRoundToZero = 0x3
};


danno@chromium.org's avatar
danno@chromium.org committed
266 267 268 269 270 271 272 273 274 275
// -----------------------------------------------------------------------------
// 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);
276
  inline explicit Immediate(Address x, RelocInfo::Mode rmode);
danno@chromium.org's avatar
danno@chromium.org committed
277 278 279 280 281 282 283 284 285

  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_);
  }
286 287 288
  bool is_uint8() const {
    return v8::internal::is_uint8(x_) && RelocInfo::IsNone(rmode_);
  }
danno@chromium.org's avatar
danno@chromium.org committed
289 290 291
  bool is_int16() const {
    return -32768 <= x_ && x_ < 32768 && RelocInfo::IsNone(rmode_);
  }
292 293 294
  bool is_uint16() const {
    return v8::internal::is_uint16(x_) && RelocInfo::IsNone(rmode_);
  }
danno@chromium.org's avatar
danno@chromium.org committed
295 296 297 298 299 300 301

 private:
  inline explicit Immediate(Label* value);

  int x_;
  RelocInfo::Mode rmode_;

302
  friend class Operand;
danno@chromium.org's avatar
danno@chromium.org committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  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:
325 326 327
  // reg
  INLINE(explicit Operand(Register reg));

danno@chromium.org's avatar
danno@chromium.org committed
328 329
  // [disp/r]
  INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
330 331 332

  // [disp/r]
  INLINE(explicit Operand(Immediate imm));
danno@chromium.org's avatar
danno@chromium.org committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

  // [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);

351 352 353 354 355
  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
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
  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);
  }

374 375 376 377
  static Operand ForRegisterPlusImmediate(Register base, Immediate imm) {
    return Operand(base, imm.x_, imm.rmode_);
  }

danno@chromium.org's avatar
danno@chromium.org committed
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 418 419 420 421 422 423 424 425 426 427 428
  // 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:
429
  enum Type { UNCONDITIONAL_JUMP, CODE_RELATIVE, OTHER, CODE_ABSOLUTE };
danno@chromium.org's avatar
danno@chromium.org committed
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 484 485 486 487 488 489 490 491 492 493 494

  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.
495 496
  inline static Address target_address_at(Address pc, Address constant_pool);
  inline static void set_target_address_at(
497
      Isolate* isolate, Address pc, Address constant_pool, Address target,
498
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
danno@chromium.org's avatar
danno@chromium.org committed
499
  static inline Address target_address_at(Address pc, Code* code) {
500
    Address constant_pool = code ? code->constant_pool() : NULL;
danno@chromium.org's avatar
danno@chromium.org committed
501 502
    return target_address_at(pc, constant_pool);
  }
503 504 505
  static inline void set_target_address_at(
      Isolate* isolate, Address pc, Code* code, Address target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) {
506
    Address constant_pool = code ? code->constant_pool() : NULL;
507
    set_target_address_at(isolate, pc, constant_pool, target);
danno@chromium.org's avatar
danno@chromium.org committed
508 509 510 511 512 513 514 515 516
  }

  // 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(
517 518 519
      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
520 521
  }

522 523
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
524
      Isolate* isolate, Address pc, Address target,
525 526
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);

danno@chromium.org's avatar
danno@chromium.org committed
527 528 529 530 531 532 533 534 535 536 537
  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;

538 539 540 541
  // 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
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 570 571 572 573 574 575 576 577 578 579 580
  // 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);
581 582 583
  // 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
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
  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);
611
  void mov_b(const Operand& dst, const Immediate& src);
danno@chromium.org's avatar
danno@chromium.org committed
612 613 614 615 616
  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);
617 618
  void mov_w(const Operand& dst, const Immediate& src);

danno@chromium.org's avatar
danno@chromium.org committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648

  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();

649
  // Exchange
danno@chromium.org's avatar
danno@chromium.org committed
650
  void xchg(Register dst, Register src);
651
  void xchg(Register dst, const Operand& src);
652 653
  void xchg_b(Register reg, const Operand& op);
  void xchg_w(Register reg, const Operand& op);
danno@chromium.org's avatar
danno@chromium.org committed
654

655 656 657 658 659 660 661 662
  // Lock prefix
  void lock();

  // CompareExchange
  void cmpxchg(const Operand& dst, Register src);
  void cmpxchg_b(const Operand& dst, Register src);
  void cmpxchg_w(const Operand& dst, Register src);

danno@chromium.org's avatar
danno@chromium.org committed
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
  // 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);

680 681
  void cmpb(Register reg, Immediate imm8) { cmpb(Operand(reg), imm8); }
  void cmpb(const Operand& op, Immediate imm8);
danno@chromium.org's avatar
danno@chromium.org committed
682 683
  void cmpb(Register reg, const Operand& op);
  void cmpb(const Operand& op, Register reg);
684
  void cmpb(Register dst, Register src) { cmpb(Operand(dst), src); }
danno@chromium.org's avatar
danno@chromium.org committed
685 686
  void cmpb_al(const Operand& op);
  void cmpw_ax(const Operand& op);
687 688 689 690 691
  void cmpw(const Operand& dst, Immediate src);
  void cmpw(Register dst, Immediate src) { cmpw(Operand(dst), src); }
  void cmpw(Register dst, const Operand& src);
  void cmpw(Register dst, Register src) { cmpw(Operand(dst), src); }
  void cmpw(const Operand& dst, Register src);
danno@chromium.org's avatar
danno@chromium.org committed
692 693 694 695 696
  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); }
697
  void cmp(const Operand& op, Register reg);
danno@chromium.org's avatar
danno@chromium.org committed
698 699 700 701 702 703 704 705 706 707 708
  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();

709 710 711 712
  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
713 714 715 716 717 718

  // 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.
719
  void imul(Register dst, const Operand& src, int32_t imm32);
danno@chromium.org's avatar
danno@chromium.org committed
720 721 722 723 724 725 726 727 728 729

  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);
730
  void neg(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
731 732

  void not_(Register dst);
733
  void not_(const Operand& dst);
danno@chromium.org's avatar
danno@chromium.org committed
734 735 736 737 738 739 740 741 742 743

  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);
744 745 746 747 748

  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
749

750 751 752 753
  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
754 755 756

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

757 758 759 760
  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);
761 762
  void shld(Register dst, Register src, uint8_t shift);
  void shld_cl(Register dst, Register src);
danno@chromium.org's avatar
danno@chromium.org committed
763

764 765 766 767
  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);
768 769 770
  void shrd(Register dst, Register src, uint8_t shift);
  void shrd_cl(Register dst, Register src) { shrd_cl(Operand(dst), src); }
  void shrd_cl(const Operand& dst, Register src);
danno@chromium.org's avatar
danno@chromium.org committed
771 772 773 774 775 776 777 778 779 780 781

  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(const Operand& op, const Immediate& imm);
782 783
  void test(const Operand& op, Register reg) { test(reg, op); }
  void test_b(Register reg, const Operand& op);
784 785
  void test_b(Register reg, Immediate imm8);
  void test_b(const Operand& op, Immediate imm8);
786 787 788 789 790 791 792
  void test_b(const Operand& op, Register reg) { test_b(reg, op); }
  void test_b(Register dst, Register src) { test_b(dst, Operand(src)); }
  void test_w(Register reg, const Operand& op);
  void test_w(Register reg, Immediate imm16);
  void test_w(const Operand& op, Immediate imm16);
  void test_w(const Operand& op, Register reg) { test_w(reg, op); }
  void test_w(Register dst, Register src) { test_w(dst, Operand(src)); }
danno@chromium.org's avatar
danno@chromium.org committed
793 794 795 796 797 798 799 800 801 802 803 804 805 806

  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);
807 808
  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
809 810 811 812 813 814

  // Miscellaneous
  void hlt();
  void int3();
  void nop();
  void ret(int imm16);
815
  void ud2();
danno@chromium.org's avatar
danno@chromium.org committed
816 817 818 819 820 821 822 823 824 825 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

  // 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);
858 859
  void j(Condition cc, Handle<Code> code,
         RelocInfo::Mode rmode = RelocInfo::CODE_TARGET);
danno@chromium.org's avatar
danno@chromium.org committed
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891

  // 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();
892
  void fsqrt();
danno@chromium.org's avatar
danno@chromium.org committed
893 894 895 896 897 898 899 900 901 902
  void fcos();
  void fsin();
  void fptan();
  void fyl2x();
  void f2xm1();
  void fscale();
  void fninit();

  void fadd(int i);
  void fadd_i(int i);
903
  void fadd_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
904 905
  void fsub(int i);
  void fsub_i(int i);
906 907
  void fsub_d(const Operand& adr);
  void fsubr_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
908
  void fmul(int i);
909
  void fmul_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
910 911
  void fmul_i(int i);
  void fdiv(int i);
912 913
  void fdiv_d(const Operand& adr);
  void fdivr_d(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
914 915 916 917 918 919
  void fdiv_i(int i);

  void fisub_s(const Operand& adr);

  void faddp(int i = 1);
  void fsubp(int i = 1);
920
  void fsubr(int i = 1);
danno@chromium.org's avatar
danno@chromium.org committed
921 922 923 924 925 926 927 928 929 930 931
  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();
932
  void fxam();
danno@chromium.org's avatar
danno@chromium.org committed
933 934 935 936 937 938
  void fucomp(int i);
  void fucompp();
  void fucomi(int i);
  void fucomip();
  void fcompp();
  void fnstsw_ax();
939 940
  void fldcw(const Operand& adr);
  void fnstcw(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
941 942
  void fwait();
  void fnclex();
943 944
  void fnsave(const Operand& adr);
  void frstor(const Operand& adr);
danno@chromium.org's avatar
danno@chromium.org committed
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959

  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();
  }

960 961 962
  // Mark generator continuation.
  void RecordGeneratorContinuation();

danno@chromium.org's avatar
danno@chromium.org committed
963
  // Mark address of a debug break slot.
964
  void RecordDebugBreakSlot(RelocInfo::Mode mode);
danno@chromium.org's avatar
danno@chromium.org committed
965 966

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

970 971
  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
972
  void RecordDeoptReason(DeoptimizeReason reason, int raw_position, int id);
973

danno@chromium.org's avatar
danno@chromium.org committed
974 975 976 977
  // 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);
978 979
  void dq(uint64_t data);
  void dp(uintptr_t data) { dd(data); }
980
  void dd(Label* label);
danno@chromium.org's avatar
danno@chromium.org committed
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003

  // 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);

  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; }

1004 1005 1006 1007 1008 1009
  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
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033

 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);
1034
  inline void emit_b(Immediate x);
danno@chromium.org's avatar
danno@chromium.org committed
1035
  inline void emit_w(const Immediate& x);
1036
  inline void emit_q(uint64_t x);
danno@chromium.org's avatar
danno@chromium.org committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

  // 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);

1052 1053
  void emit_label(Label* label);

danno@chromium.org's avatar
danno@chromium.org committed
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
  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;

1072 1073 1074 1075 1076
  // 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
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
  // code generation
  RelocInfoWriter reloc_info_writer;
};


// 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();
1098
    DCHECK(bytes_generated < assembler_->kGap);
danno@chromium.org's avatar
danno@chromium.org committed
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
  }
#endif

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

1109 1110
}  // namespace internal
}  // namespace v8
danno@chromium.org's avatar
danno@chromium.org committed
1111 1112

#endif  // V8_X87_ASSEMBLER_X87_H_