assembler-arm.h 55.9 KB
Newer Older
1 2 3
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
4
// Redistribution and use in source and binary forms, with or without
5 6 7 8 9
// 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.
10
//
11 12 13 14 15 16 17 18
// - 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.
19 20 21
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 23 24 25 26 27 28 29 30 31 32
// 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.

33 34
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
35
// Copyright 2012 the V8 project authors. All rights reserved.
36 37 38 39

// A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5

40 41
#ifndef V8_ARM_ASSEMBLER_ARM_H_
#define V8_ARM_ASSEMBLER_ARM_H_
42

lrn@chromium.org's avatar
lrn@chromium.org committed
43
#include <stdio.h>
44 45
#include <vector>

46
#include "src/arm/constants-arm.h"
47
#include "src/arm/register-arm.h"
48
#include "src/assembler.h"
49
#include "src/boxed-float.h"
50
#include "src/constant-pool.h"
51
#include "src/double.h"
52

53 54
namespace v8 {
namespace internal {
55

56 57
class SafepointTableBuilder;

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
// Coprocessor number
enum Coprocessor {
  p0  = 0,
  p1  = 1,
  p2  = 2,
  p3  = 3,
  p4  = 4,
  p5  = 5,
  p6  = 6,
  p7  = 7,
  p8  = 8,
  p9  = 9,
  p10 = 10,
  p11 = 11,
  p12 = 12,
  p13 = 13,
  p14 = 14,
  p15 = 15
};

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

// Class Operand represents a shifter operand in data processing instructions
82
class Operand {
83 84
 public:
  // immediate
85 86 87 88
  V8_INLINE explicit Operand(int32_t immediate,
                             RelocInfo::Mode rmode = RelocInfo::NONE);
  V8_INLINE static Operand Zero();
  V8_INLINE explicit Operand(const ExternalReference& f);
89
  explicit Operand(Handle<HeapObject> handle);
90
  V8_INLINE explicit Operand(Smi value);
91 92

  // rm
93
  V8_INLINE explicit Operand(Register rm);
94 95 96

  // rm <shift_op> shift_imm
  explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
97
  V8_INLINE static Operand SmiUntag(Register rm) {
98 99
    return Operand(rm, ASR, kSmiTagSize);
  }
100
  V8_INLINE static Operand PointerOffsetFromSmiKey(Register key) {
101 102 103
    STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    return Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize);
  }
104
  V8_INLINE static Operand DoubleOffsetFromSmiKey(Register key) {
105 106 107
    STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kDoubleSizeLog2);
    return Operand(key, LSL, kDoubleSizeLog2 - kSmiTagSize);
  }
108 109 110 111

  // rm <shift_op> rs
  explicit Operand(Register rm, ShiftOp shift_op, Register rs);

112
  static Operand EmbeddedNumber(double number);  // Smi or HeapNumber.
113
  static Operand EmbeddedStringConstant(const StringConstantBase* str);
114

115
  // Return true if this is a register operand.
116
  bool IsRegister() const {
117 118
    return rm_.is_valid() && rs_ == no_reg && shift_op_ == LSL &&
           shift_imm_ == 0;
119
  }
120 121 122 123 124 125 126 127
  // Return true if this is a register operand shifted with an immediate.
  bool IsImmediateShiftedRegister() const {
    return rm_.is_valid() && !rs_.is_valid();
  }
  // Return true if this is a register operand shifted with a register.
  bool IsRegisterShiftedRegister() const {
    return rm_.is_valid() && rs_.is_valid();
  }
128

129 130
  // Return the number of actual instructions required to implement the given
  // instruction for this particular operand. This can be a single instruction,
131 132
  // if no load into a scratch register is necessary, or anything between 2 and
  // 4 instructions when we need to load from the constant pool (depending upon
133
  // whether the constant pool entry is in the small or extended section). If
134 135 136
  // the instruction this operand is used for is a MOV or MVN instruction the
  // actual instruction to use is required for this calculation. For other
  // instructions instr is ignored.
137 138 139
  //
  // The value returned is only valid as long as no entries are added to the
  // constant pool between this call and the actual instruction being emitted.
140 141
  int InstructionsRequired(const Assembler* assembler, Instr instr = 0) const;
  bool MustOutputRelocInfo(const Assembler* assembler) const;
142 143

  inline int32_t immediate() const {
144
    DCHECK(IsImmediate());
145
    DCHECK(!IsHeapObjectRequest());
146 147
    return value_.immediate;
  }
148 149 150
  bool IsImmediate() const {
    return !rm_.is_valid();
  }
151

152 153 154
  HeapObjectRequest heap_object_request() const {
    DCHECK(IsHeapObjectRequest());
    return value_.heap_object_request;
155
  }
156 157 158 159 160 161
  bool IsHeapObjectRequest() const {
    DCHECK_IMPLIES(is_heap_object_request_, IsImmediate());
    DCHECK_IMPLIES(is_heap_object_request_,
        rmode_ == RelocInfo::EMBEDDED_OBJECT ||
        rmode_ == RelocInfo::CODE_TARGET);
    return is_heap_object_request_;
162
  }
163

164
  Register rm() const { return rm_; }
165 166
  Register rs() const { return rs_; }
  ShiftOp shift_op() const { return shift_op_; }
167

168

169
 private:
170 171
  Register rm_ = no_reg;
  Register rs_ = no_reg;
172
  ShiftOp shift_op_;
173
  int shift_imm_;                // valid if rm_ != no_reg && rs_ == no_reg
174 175 176 177 178 179
  union Value {
    Value() {}
    HeapObjectRequest heap_object_request;  // if is_heap_object_request_
    int32_t immediate;                      // otherwise
  } value_;                                 // valid if rm_ == no_reg
  bool is_heap_object_request_ = false;
180
  RelocInfo::Mode rmode_;
181 182 183 184 185 186

  friend class Assembler;
};


// Class MemOperand represents a memory operand in load and store instructions
187
class MemOperand {
188 189 190 191
 public:
  // [rn +/- offset]      Offset/NegOffset
  // [rn +/- offset]!     PreIndex/NegPreIndex
  // [rn], +/- offset     PostIndex/NegPostIndex
192 193 194
  // offset is any signed 32-bit value; offset is first loaded to a scratch
  // register if it does not fit the addressing mode (12-bit unsigned and sign
  // bit)
195 196 197 198 199 200 201 202 203 204 205 206
  explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);

  // [rn +/- rm]          Offset/NegOffset
  // [rn +/- rm]!         PreIndex/NegPreIndex
  // [rn], +/- rm         PostIndex/NegPostIndex
  explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);

  // [rn +/- rm <shift_op> shift_imm]      Offset/NegOffset
  // [rn +/- rm <shift_op> shift_imm]!     PreIndex/NegPreIndex
  // [rn], +/- rm <shift_op> shift_imm     PostIndex/NegPostIndex
  explicit MemOperand(Register rn, Register rm,
                      ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
207 208 209
  V8_INLINE static MemOperand PointerAddressFromSmiKey(Register array,
                                                       Register key,
                                                       AddrMode am = Offset) {
210 211 212
    STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
    return MemOperand(array, key, LSL, kPointerSizeLog2 - kSmiTagSize, am);
  }
213

214
  void set_offset(int32_t offset) {
215 216
    DCHECK(rm_ == no_reg);
    offset_ = offset;
217 218
  }

219
  uint32_t offset() const {
220 221
    DCHECK(rm_ == no_reg);
    return offset_;
222 223
  }

224 225
  Register rn() const { return rn_; }
  Register rm() const { return rm_; }
226
  AddrMode am() const { return am_; }
227

228 229 230 231
  bool OffsetIsUint12Encodable() const {
    return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_);
  }

232 233 234 235 236 237 238 239 240 241 242
 private:
  Register rn_;  // base
  Register rm_;  // register offset
  int32_t offset_;  // valid if rm_ == no_reg
  ShiftOp shift_op_;
  int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg
  AddrMode am_;  // bits P, U, and W

  friend class Assembler;
};

243 244 245

// Class NeonMemOperand represents a memory operand in load and
// store NEON instructions
246
class NeonMemOperand {
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
 public:
  // [rn {:align}]       Offset
  // [rn {:align}]!      PostIndex
  explicit NeonMemOperand(Register rn, AddrMode am = Offset, int align = 0);

  // [rn {:align}], rm   PostIndex
  explicit NeonMemOperand(Register rn, Register rm, int align = 0);

  Register rn() const { return rn_; }
  Register rm() const { return rm_; }
  int align() const { return align_; }

 private:
  void SetAlignment(int align);

  Register rn_;  // base
  Register rm_;  // register increment
  int align_;
};


// Class NeonListOperand represents a list of NEON registers
269
class NeonListOperand {
270
 public:
271 272 273 274
  explicit NeonListOperand(DoubleRegister base, int register_count = 1)
    : base_(base), register_count_(register_count) {}
  explicit NeonListOperand(QwNeonRegister q_reg)
    : base_(q_reg.low()), register_count_(2) {}
275
  DoubleRegister base() const { return base_; }
276 277 278 279 280 281 282 283 284 285 286 287
  int register_count() { return register_count_; }
  int length() const { return register_count_ - 1; }
  NeonListType type() const {
    switch (register_count_) {
      default: UNREACHABLE();
      // Fall through.
      case 1: return nlt_1;
      case 2: return nlt_2;
      case 3: return nlt_3;
      case 4: return nlt_4;
    }
  }
288 289
 private:
  DoubleRegister base_;
290
  int register_count_;
291 292
};

293
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
294 295 296 297 298 299
 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).
  //
300
  // If the provided buffer is nullptr, the assembler allocates and grows its
301 302 303 304
  // own buffer. Otherwise it takes ownership of the provided buffer.
  explicit Assembler(const AssemblerOptions&,
                     std::unique_ptr<AssemblerBuffer> = {});

305
  virtual ~Assembler();
306

307 308 309 310
  virtual void AbortedCodeGeneration() {
    pending_32_bit_constants_.clear();
  }

311 312 313 314 315 316 317 318 319 320 321
  // GetCode emits any pending (non-emitted) code and fills the descriptor desc.
  static constexpr int kNoHandlerTable = 0;
  static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr;
  void GetCode(Isolate* isolate, CodeDesc* desc,
               SafepointTableBuilder* safepoint_table_builder,
               int handler_table_offset);

  // Convenience wrapper for code without safepoint or handler tables.
  void GetCode(Isolate* isolate, CodeDesc* desc) {
    GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable);
  }
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

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

  // Returns the branch offset to the given label from the current code position
  // Links the label to the current position if it is still unbound
342
  // Manages the jump elimination optimization if the second parameter is true.
343
  int branch_offset(Label* L);
344

345 346
  // Returns true if the given pc address is the start of a constant pool load
  // instruction sequence.
347
  V8_INLINE static bool is_constant_pool_load(Address pc);
348

349
  // Return the address in the constant pool of the code target address used by
350
  // the branch/call instruction at pc, or the object in a mov.
351 352
  V8_INLINE static Address constant_pool_entry_address(Address pc,
                                                       Address constant_pool);
353

354
  // Read/Modify the code target address in the branch/call instruction at pc.
355
  // The isolate argument is unused (and may be nullptr) when skipping flushing.
356 357
  V8_INLINE static Address target_address_at(Address pc, Address constant_pool);
  V8_INLINE static void set_target_address_at(
358
      Address pc, Address constant_pool, Address target,
359
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
360

361 362
  // Return the code target address at a call site from the return address
  // of that call in the instruction stream.
363
  V8_INLINE static Address target_address_from_return_address(Address pc);
364 365 366

  // Given the address of the beginning of a call, return the address
  // in the instruction stream that the call will return from.
367
  V8_INLINE static Address return_address_from_call_start(Address pc);
368

369 370
  // This sets the branch destination (which is in the constant pool on ARM).
  // This is for calls and branches within generated code.
371
  inline static void deserialization_set_special_target_at(
372
      Address constant_pool_entry, Code code, Address target);
373

374 375 376
  // Get the size of the special target encoded at 'location'.
  inline static int deserialization_special_target_size(Address location);

377 378
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
379
      Address pc, Address target,
380
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
381

382 383 384
  // Here we are patching the address in the constant pool, not the actual call
  // instruction.  The address in the constant pool is the same size as a
  // pointer.
385
  static constexpr int kSpecialTargetSize = kPointerSize;
386

387
  RegList* GetScratchRegisterList() { return &scratch_register_list_; }
388 389 390
  VfpRegList* GetScratchVfpRegisterList() {
    return &scratch_vfp_register_list_;
  }
391

392 393 394 395 396 397 398
  // ---------------------------------------------------------------------------
  // Code generation

  // 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 (>= 4).
  void Align(int m);
399 400 401
  // 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);
402 403
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();
404 405

  // Branch instructions
406 407 408 409
  void b(int branch_offset, Condition cond = al,
         RelocInfo::Mode rmode = RelocInfo::NONE);
  void bl(int branch_offset, Condition cond = al,
          RelocInfo::Mode rmode = RelocInfo::NONE);
410 411 412 413 414
  void blx(int branch_offset);  // v5 and above
  void blx(Register target, Condition cond = al);  // v5 and above
  void bx(Register target, Condition cond = al);  // v5 and above, plus v4t

  // Convenience branch instructions using labels
415
  void b(Label* L, Condition cond = al);
416
  void b(Condition cond, Label* L) { b(L, cond); }
417 418 419
  void bl(Label* L, Condition cond = al);
  void bl(Condition cond, Label* L) { bl(L, cond); }
  void blx(Label* L);  // v5 and above
420 421

  // Data-processing instructions
422

423 424
  void and_(Register dst, Register src1, const Operand& src2,
            SBit s = LeaveCC, Condition cond = al);
425 426
  void and_(Register dst, Register src1, Register src2, SBit s = LeaveCC,
            Condition cond = al);
427 428 429

  void eor(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);
430 431
  void eor(Register dst, Register src1, Register src2, SBit s = LeaveCC,
           Condition cond = al);
432 433 434

  void sub(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);
435
  void sub(Register dst, Register src1, Register src2,
436
           SBit s = LeaveCC, Condition cond = al);
437 438 439 440 441 442

  void rsb(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);

  void add(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);
443
  void add(Register dst, Register src1, Register src2,
444
           SBit s = LeaveCC, Condition cond = al);
445 446 447 448 449 450 451 452 453 454 455

  void adc(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);

  void sbc(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);

  void rsc(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);

  void tst(Register src1, const Operand& src2, Condition cond = al);
456
  void tst(Register src1, Register src2, Condition cond = al);
457 458 459 460

  void teq(Register src1, const Operand& src2, Condition cond = al);

  void cmp(Register src1, const Operand& src2, Condition cond = al);
461 462
  void cmp(Register src1, Register src2, Condition cond = al);

463
  void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al);
464 465 466 467 468

  void cmn(Register src1, const Operand& src2, Condition cond = al);

  void orr(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);
469
  void orr(Register dst, Register src1, Register src2,
470
           SBit s = LeaveCC, Condition cond = al);
471 472 473

  void mov(Register dst, const Operand& src,
           SBit s = LeaveCC, Condition cond = al);
474
  void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al);
475

476 477 478 479
  // Load the position of the label relative to the generated code object
  // pointer in a register.
  void mov_label_offset(Register dst, Label* label);

480
  // ARMv7 instructions for loading a 32 bit immediate in two instructions.
481
  // The constant for movw and movt should be in the range 0-0xffff.
482 483 484
  void movw(Register reg, uint32_t immediate, Condition cond = al);
  void movt(Register reg, uint32_t immediate, Condition cond = al);

485 486 487 488 489 490
  void bic(Register dst, Register src1, const Operand& src2,
           SBit s = LeaveCC, Condition cond = al);

  void mvn(Register dst, const Operand& src,
           SBit s = LeaveCC, Condition cond = al);

491 492 493
  // Shift instructions

  void asr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
494
           Condition cond = al);
495 496

  void lsl(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
497
           Condition cond = al);
498 499

  void lsr(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC,
500
           Condition cond = al);
501

502 503 504 505 506
  // Multiply instructions

  void mla(Register dst, Register src1, Register src2, Register srcA,
           SBit s = LeaveCC, Condition cond = al);

507 508 509 510 511 512
  void mls(Register dst, Register src1, Register src2, Register srcA,
           Condition cond = al);

  void sdiv(Register dst, Register src1, Register src2,
            Condition cond = al);

513 514
  void udiv(Register dst, Register src1, Register src2, Condition cond = al);

515 516 517
  void mul(Register dst, Register src1, Register src2,
           SBit s = LeaveCC, Condition cond = al);

518 519 520 521 522
  void smmla(Register dst, Register src1, Register src2, Register srcA,
             Condition cond = al);

  void smmul(Register dst, Register src1, Register src2, Condition cond = al);

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
  void smlal(Register dstL, Register dstH, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al);

  void smull(Register dstL, Register dstH, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al);

  void umlal(Register dstL, Register dstH, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al);

  void umull(Register dstL, Register dstH, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al);

  // Miscellaneous arithmetic instructions

  void clz(Register dst, Register src, Condition cond = al);  // v5 and above

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
  // Saturating instructions. v6 and above.

  // Unsigned saturate.
  //
  // Saturate an optionally shifted signed value to an unsigned range.
  //
  //   usat dst, #satpos, src
  //   usat dst, #satpos, src, lsl #sh
  //   usat dst, #satpos, src, asr #sh
  //
  // Register dst will contain:
  //
  //   0,                 if s < 0
  //   (1 << satpos) - 1, if s > ((1 << satpos) - 1)
  //   s,                 otherwise
  //
  // where s is the contents of src after shifting (if used.)
  void usat(Register dst, int satpos, const Operand& src, Condition cond = al);

558 559 560 561 562 563 564 565 566 567 568 569 570
  // Bitfield manipulation instructions. v7 and above.

  void ubfx(Register dst, Register src, int lsb, int width,
            Condition cond = al);

  void sbfx(Register dst, Register src, int lsb, int width,
            Condition cond = al);

  void bfc(Register dst, int lsb, int width, Condition cond = al);

  void bfi(Register dst, Register src, int lsb, int width,
           Condition cond = al);

571 572 573 574 575 576
  void pkhbt(Register dst, Register src1, const Operand& src2,
             Condition cond = al);

  void pkhtb(Register dst, Register src1, const Operand& src2,
             Condition cond = al);

577 578 579 580 581
  void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
  void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
             Condition cond = al);
  void sxth(Register dst, Register src, int rotate = 0, Condition cond = al);
  void sxtah(Register dst, Register src1, Register src2, int rotate = 0,
582 583
             Condition cond = al);

584 585 586 587 588 589 590
  void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
  void uxtab(Register dst, Register src1, Register src2, int rotate = 0,
             Condition cond = al);
  void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al);
  void uxth(Register dst, Register src, int rotate = 0, Condition cond = al);
  void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
             Condition cond = al);
591

592 593
  // Reverse the bits in a register.
  void rbit(Register dst, Register src, Condition cond = al);
594
  void rev(Register dst, Register src, Condition cond = al);
595

596 597 598 599 600 601 602 603 604 605 606 607 608 609
  // Status register access instructions

  void mrs(Register dst, SRegister s, Condition cond = al);
  void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);

  // Load/Store instructions
  void ldr(Register dst, const MemOperand& src, Condition cond = al);
  void str(Register src, const MemOperand& dst, Condition cond = al);
  void ldrb(Register dst, const MemOperand& src, Condition cond = al);
  void strb(Register src, const MemOperand& dst, Condition cond = al);
  void ldrh(Register dst, const MemOperand& src, Condition cond = al);
  void strh(Register src, const MemOperand& dst, Condition cond = al);
  void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
  void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
610 611 612 613 614 615
  void ldrd(Register dst1,
            Register dst2,
            const MemOperand& src, Condition cond = al);
  void strd(Register src1,
            Register src2,
            const MemOperand& dst, Condition cond = al);
616

617 618 619
  // Load literal from a pc relative address.
  void ldr_pcrel(Register dst, int imm12, Condition cond = al);

620 621 622 623 624 625 626
  // Load/Store exclusive instructions
  void ldrex(Register dst, Register src, Condition cond = al);
  void strex(Register src1, Register src2, Register dst, Condition cond = al);
  void ldrexb(Register dst, Register src, Condition cond = al);
  void strexb(Register src1, Register src2, Register dst, Condition cond = al);
  void ldrexh(Register dst, Register src, Condition cond = al);
  void strexh(Register src1, Register src2, Register dst, Condition cond = al);
627 628
  void ldrexd(Register dst1, Register dst2, Register src, Condition cond = al);
  void strexd(Register res, Register src1, Register src2, Register dst,
629
              Condition cond = al);
630

631 632 633
  // Preload instructions
  void pld(const MemOperand& address);

634 635 636 637 638
  // Load/Store multiple instructions
  void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
  void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);

  // Exception-generating instructions and debugging support
639 640 641
  void stop(const char* msg,
            Condition cond = al,
            int32_t code = kDefaultStopCode);
642 643

  void bkpt(uint32_t imm16);  // v5 and above
644
  void svc(uint32_t imm24, Condition cond = al);
645

646 647
  // Synchronization instructions.
  // On ARMv6, an equivalent CP15 operation will be used.
648 649 650 651
  void dmb(BarrierOption option);
  void dsb(BarrierOption option);
  void isb(BarrierOption option);

652 653 654
  // Conditional speculation barrier.
  void csdb();

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 682 683 684 685 686 687 688 689 690
  // Coprocessor instructions

  void cdp(Coprocessor coproc, int opcode_1,
           CRegister crd, CRegister crn, CRegister crm,
           int opcode_2, Condition cond = al);

  void cdp2(Coprocessor coproc, int opcode_1,
            CRegister crd, CRegister crn, CRegister crm,
            int opcode_2);  // v5 and above

  void mcr(Coprocessor coproc, int opcode_1,
           Register rd, CRegister crn, CRegister crm,
           int opcode_2 = 0, Condition cond = al);

  void mcr2(Coprocessor coproc, int opcode_1,
            Register rd, CRegister crn, CRegister crm,
            int opcode_2 = 0);  // v5 and above

  void mrc(Coprocessor coproc, int opcode_1,
           Register rd, CRegister crn, CRegister crm,
           int opcode_2 = 0, Condition cond = al);

  void mrc2(Coprocessor coproc, int opcode_1,
            Register rd, CRegister crn, CRegister crm,
            int opcode_2 = 0);  // v5 and above

  void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
           LFlag l = Short, Condition cond = al);
  void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
           LFlag l = Short, Condition cond = al);

  void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
            LFlag l = Short);  // v5 and above
  void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
            LFlag l = Short);  // v5 and above

691
  // Support for VFP.
692
  // All these APIs support S0 to S31 and D0 to D31.
693

694 695
  void vldr(const DwVfpRegister dst,
            const Register base,
696 697 698 699
            int offset,
            const Condition cond = al);
  void vldr(const DwVfpRegister dst,
            const MemOperand& src,
700
            const Condition cond = al);
701 702 703

  void vldr(const SwVfpRegister dst,
            const Register base,
704 705 706 707
            int offset,
            const Condition cond = al);
  void vldr(const SwVfpRegister dst,
            const MemOperand& src,
708 709
            const Condition cond = al);

710 711
  void vstr(const DwVfpRegister src,
            const Register base,
712 713 714 715
            int offset,
            const Condition cond = al);
  void vstr(const DwVfpRegister src,
            const MemOperand& dst,
716
            const Condition cond = al);
717

718 719
  void vstr(const SwVfpRegister src,
            const Register base,
720 721 722 723
            int offset,
            const Condition cond = al);
  void vstr(const SwVfpRegister src,
            const MemOperand& dst,
724 725
            const Condition cond = al);

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
  void vldm(BlockAddrMode am,
            Register base,
            DwVfpRegister first,
            DwVfpRegister last,
            Condition cond = al);

  void vstm(BlockAddrMode am,
            Register base,
            DwVfpRegister first,
            DwVfpRegister last,
            Condition cond = al);

  void vldm(BlockAddrMode am,
            Register base,
            SwVfpRegister first,
            SwVfpRegister last,
            Condition cond = al);

  void vstm(BlockAddrMode am,
            Register base,
            SwVfpRegister first,
            SwVfpRegister last,
            Condition cond = al);

750
  void vmov(const SwVfpRegister dst, Float32 imm);
751
  void vmov(const DwVfpRegister dst,
752
            Double imm,
753
            const Register extra_scratch = no_reg);
754 755 756
  void vmov(const SwVfpRegister dst,
            const SwVfpRegister src,
            const Condition cond = al);
757 758 759
  void vmov(const DwVfpRegister dst,
            const DwVfpRegister src,
            const Condition cond = al);
760 761 762 763 764 765 766
  void vmov(const DwVfpRegister dst,
            const Register src1,
            const Register src2,
            const Condition cond = al);
  void vmov(const Register dst1,
            const Register dst2,
            const DwVfpRegister src,
767
            const Condition cond = al);
768
  void vmov(const SwVfpRegister dst,
769 770
            const Register src,
            const Condition cond = al);
771 772 773
  void vmov(const Register dst,
            const SwVfpRegister src,
            const Condition cond = al);
774 775
  void vcvt_f64_s32(const DwVfpRegister dst,
                    const SwVfpRegister src,
776
                    VFPConversionMode mode = kDefaultRoundToZero,
777 778 779
                    const Condition cond = al);
  void vcvt_f32_s32(const SwVfpRegister dst,
                    const SwVfpRegister src,
780
                    VFPConversionMode mode = kDefaultRoundToZero,
781 782 783
                    const Condition cond = al);
  void vcvt_f64_u32(const DwVfpRegister dst,
                    const SwVfpRegister src,
784 785
                    VFPConversionMode mode = kDefaultRoundToZero,
                    const Condition cond = al);
786 787 788 789
  void vcvt_f32_u32(const SwVfpRegister dst,
                    const SwVfpRegister src,
                    VFPConversionMode mode = kDefaultRoundToZero,
                    const Condition cond = al);
790 791
  void vcvt_s32_f32(const SwVfpRegister dst,
                    const SwVfpRegister src,
792 793 794 795
                    VFPConversionMode mode = kDefaultRoundToZero,
                    const Condition cond = al);
  void vcvt_u32_f32(const SwVfpRegister dst,
                    const SwVfpRegister src,
796
                    VFPConversionMode mode = kDefaultRoundToZero,
797 798 799
                    const Condition cond = al);
  void vcvt_s32_f64(const SwVfpRegister dst,
                    const DwVfpRegister src,
800
                    VFPConversionMode mode = kDefaultRoundToZero,
801 802 803
                    const Condition cond = al);
  void vcvt_u32_f64(const SwVfpRegister dst,
                    const DwVfpRegister src,
804
                    VFPConversionMode mode = kDefaultRoundToZero,
805 806 807
                    const Condition cond = al);
  void vcvt_f64_f32(const DwVfpRegister dst,
                    const SwVfpRegister src,
808
                    VFPConversionMode mode = kDefaultRoundToZero,
809 810 811
                    const Condition cond = al);
  void vcvt_f32_f64(const SwVfpRegister dst,
                    const DwVfpRegister src,
812
                    VFPConversionMode mode = kDefaultRoundToZero,
813
                    const Condition cond = al);
814 815 816
  void vcvt_f64_s32(const DwVfpRegister dst,
                    int fraction_bits,
                    const Condition cond = al);
817

818 819 820
  void vmrs(const Register dst, const Condition cond = al);
  void vmsr(const Register dst, const Condition cond = al);

821 822 823
  void vneg(const DwVfpRegister dst,
            const DwVfpRegister src,
            const Condition cond = al);
824 825
  void vneg(const SwVfpRegister dst, const SwVfpRegister src,
            const Condition cond = al);
826 827 828
  void vabs(const DwVfpRegister dst,
            const DwVfpRegister src,
            const Condition cond = al);
829 830
  void vabs(const SwVfpRegister dst, const SwVfpRegister src,
            const Condition cond = al);
831 832 833 834
  void vadd(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
835 836
  void vadd(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
837 838 839 840
  void vsub(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
841 842
  void vsub(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
843 844 845 846
  void vmul(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
847 848
  void vmul(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
849 850 851 852
  void vmla(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
853 854
  void vmla(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
855 856 857 858
  void vmls(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
859 860
  void vmls(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
861 862 863 864
  void vdiv(const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2,
            const Condition cond = al);
865 866
  void vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
            const SwVfpRegister src2, const Condition cond = al);
867 868
  void vcmp(const DwVfpRegister src1,
            const DwVfpRegister src2,
869
            const Condition cond = al);
870 871
  void vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
            const Condition cond = al);
872 873 874
  void vcmp(const DwVfpRegister src1,
            const double src2,
            const Condition cond = al);
875
  void vcmp(const SwVfpRegister src1, const float src2,
876
            const Condition cond = al);
877

878 879 880 881 882 883 884 885 886 887 888 889 890
  void vmaxnm(const DwVfpRegister dst,
              const DwVfpRegister src1,
              const DwVfpRegister src2);
  void vmaxnm(const SwVfpRegister dst,
              const SwVfpRegister src1,
              const SwVfpRegister src2);
  void vminnm(const DwVfpRegister dst,
              const DwVfpRegister src1,
              const DwVfpRegister src2);
  void vminnm(const SwVfpRegister dst,
              const SwVfpRegister src1,
              const SwVfpRegister src2);

891 892 893 894 895 896 897 898 899 900
  // VSEL supports cond in {eq, ne, ge, lt, gt, le, vs, vc}.
  void vsel(const Condition cond,
            const DwVfpRegister dst,
            const DwVfpRegister src1,
            const DwVfpRegister src2);
  void vsel(const Condition cond,
            const SwVfpRegister dst,
            const SwVfpRegister src1,
            const SwVfpRegister src2);

901 902 903
  void vsqrt(const DwVfpRegister dst,
             const DwVfpRegister src,
             const Condition cond = al);
904 905
  void vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
             const Condition cond = al);
906

907
  // ARMv8 rounding instructions.
908
  void vrinta(const SwVfpRegister dst, const SwVfpRegister src);
909
  void vrinta(const DwVfpRegister dst, const DwVfpRegister src);
910
  void vrintn(const SwVfpRegister dst, const SwVfpRegister src);
911
  void vrintn(const DwVfpRegister dst, const DwVfpRegister src);
912
  void vrintm(const SwVfpRegister dst, const SwVfpRegister src);
913
  void vrintm(const DwVfpRegister dst, const DwVfpRegister src);
914
  void vrintp(const SwVfpRegister dst, const SwVfpRegister src);
915
  void vrintp(const DwVfpRegister dst, const DwVfpRegister src);
916 917
  void vrintz(const SwVfpRegister dst, const SwVfpRegister src,
              const Condition cond = al);
918 919 920
  void vrintz(const DwVfpRegister dst, const DwVfpRegister src,
              const Condition cond = al);

921
  // Support for NEON.
922

923
  // All these APIs support D0 to D31 and Q0 to Q15.
924 925 926 927 928 929
  void vld1(NeonSize size,
            const NeonListOperand& dst,
            const NeonMemOperand& src);
  void vst1(NeonSize size,
            const NeonListOperand& src,
            const NeonMemOperand& dst);
930
  // dt represents the narrower type
931
  void vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src);
932 933
  // dt represents the narrower type.
  void vqmovn(NeonDataType dt, DwVfpRegister dst, QwNeonRegister src);
934

935 936 937 938
  // Only unconditional core <-> scalar moves are currently supported.
  void vmov(NeonDataType dt, DwVfpRegister dst, int index, Register src);
  void vmov(NeonDataType dt, Register dst, DwVfpRegister src, int index);

939 940
  void vmov(QwNeonRegister dst, QwNeonRegister src);
  void vdup(NeonSize size, QwNeonRegister dst, Register src);
941 942
  void vdup(NeonSize size, QwNeonRegister dst, DwVfpRegister src, int index);
  void vdup(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int index);
943 944 945 946 947 948 949

  void vcvt_f32_s32(QwNeonRegister dst, QwNeonRegister src);
  void vcvt_f32_u32(QwNeonRegister dst, QwNeonRegister src);
  void vcvt_s32_f32(QwNeonRegister dst, QwNeonRegister src);
  void vcvt_u32_f32(QwNeonRegister dst, QwNeonRegister src);

  void vmvn(QwNeonRegister dst, QwNeonRegister src);
950 951
  void vswp(DwVfpRegister dst, DwVfpRegister src);
  void vswp(QwNeonRegister dst, QwNeonRegister src);
952 953 954 955 956
  void vabs(QwNeonRegister dst, QwNeonRegister src);
  void vabs(NeonSize size, QwNeonRegister dst, QwNeonRegister src);
  void vneg(QwNeonRegister dst, QwNeonRegister src);
  void vneg(NeonSize size, QwNeonRegister dst, QwNeonRegister src);

957
  void vand(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
958
  void veor(DwVfpRegister dst, DwVfpRegister src1, DwVfpRegister src2);
959
  void veor(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
960
  void vbsl(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
961
  void vorr(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
962 963 964
  void vadd(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vadd(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
965 966
  void vqadd(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
             QwNeonRegister src2);
967 968 969
  void vsub(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vsub(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
970 971
  void vqsub(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
             QwNeonRegister src2);
972 973 974 975 976 977 978 979 980 981
  void vmul(QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
  void vmul(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
  void vmin(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vmin(NeonDataType dt, QwNeonRegister dst,
            QwNeonRegister src1, QwNeonRegister src2);
  void vmax(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vmax(NeonDataType dt, QwNeonRegister dst,
            QwNeonRegister src1, QwNeonRegister src2);
982 983 984
  void vpadd(DwVfpRegister dst, DwVfpRegister src1, DwVfpRegister src2);
  void vpadd(NeonSize size, DwVfpRegister dst, DwVfpRegister src1,
             DwVfpRegister src2);
985 986 987 988
  void vpmin(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1,
             DwVfpRegister src2);
  void vpmax(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1,
             DwVfpRegister src2);
989 990
  void vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift);
  void vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift);
991 992
  void vsli(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift);
  void vsri(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift);
993
  // vrecpe and vrsqrte only support floating point lanes.
994 995 996 997 998 999 1000 1001 1002 1003
  void vrecpe(QwNeonRegister dst, QwNeonRegister src);
  void vrsqrte(QwNeonRegister dst, QwNeonRegister src);
  void vrecps(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vrsqrts(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vtst(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
  void vceq(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
  void vceq(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
  void vcge(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
1004 1005
  void vcge(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
1006
  void vcgt(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2);
1007 1008 1009 1010
  void vcgt(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
            QwNeonRegister src2);
  void vext(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2,
            int bytes);
1011
  void vzip(NeonSize size, DwVfpRegister src1, DwVfpRegister src2);
1012
  void vzip(NeonSize size, QwNeonRegister src1, QwNeonRegister src2);
1013
  void vuzp(NeonSize size, DwVfpRegister src1, DwVfpRegister src2);
1014 1015 1016 1017
  void vuzp(NeonSize size, QwNeonRegister src1, QwNeonRegister src2);
  void vrev16(NeonSize size, QwNeonRegister dst, QwNeonRegister src);
  void vrev32(NeonSize size, QwNeonRegister dst, QwNeonRegister src);
  void vrev64(NeonSize size, QwNeonRegister dst, QwNeonRegister src);
1018
  void vtrn(NeonSize size, DwVfpRegister src1, DwVfpRegister src2);
1019 1020 1021 1022 1023
  void vtrn(NeonSize size, QwNeonRegister src1, QwNeonRegister src2);
  void vtbl(DwVfpRegister dst, const NeonListOperand& list,
            DwVfpRegister index);
  void vtbx(DwVfpRegister dst, const NeonListOperand& list,
            DwVfpRegister index);
1024

1025
  // Pseudo instructions
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041

  // Different nop operations are used by the code generator to detect certain
  // states of the generated code.
  enum NopMarkerTypes {
    NON_MARKING_NOP = 0,
    DEBUG_BREAK_NOP,
    // IC markers.
    PROPERTY_ACCESS_INLINED,
    PROPERTY_ACCESS_INLINED_CONTEXT,
    PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
    // Helper values.
    LAST_CODE_MARKER,
    FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
  };

  void nop(int type = 0);   // 0 is the default non-marking type.
1042

1043 1044
  void push(Register src, Condition cond = al) {
    str(src, MemOperand(sp, 4, NegPreIndex), cond);
1045 1046
  }

1047 1048
  void pop(Register dst, Condition cond = al) {
    ldr(dst, MemOperand(sp, 4, PostIndex), cond);
1049 1050
  }

1051
  void pop();
1052

1053 1054 1055 1056
  void vpush(QwNeonRegister src, Condition cond = al) {
    vstm(db_w, sp, src.low(), src.high(), cond);
  }

1057 1058 1059 1060
  void vpush(DwVfpRegister src, Condition cond = al) {
    vstm(db_w, sp, src, src, cond);
  }

1061 1062 1063 1064
  void vpush(SwVfpRegister src, Condition cond = al) {
    vstm(db_w, sp, src, src, cond);
  }

1065 1066 1067 1068
  void vpop(DwVfpRegister dst, Condition cond = al) {
    vldm(ia_w, sp, dst, dst, cond);
  }

1069 1070 1071
  // Jump unconditionally to given label.
  void jmp(Label* L) { b(L, al); }

1072
  // Check the code size generated from label to here.
1073 1074 1075 1076 1077 1078 1079
  int SizeOfCodeGeneratedSince(Label* label) {
    return pc_offset() - label->pos();
  }

  // Check the number of instructions generated from label to here.
  int InstructionsGeneratedSince(Label* label) {
    return SizeOfCodeGeneratedSince(label) / kInstrSize;
1080
  }
1081

1082
  // Check whether an immediate fits an addressing mode 1 instruction.
1083
  static bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
1084

1085 1086 1087
  // Check whether an immediate fits an addressing mode 2 instruction.
  bool ImmediateFitsAddrMode2Instruction(int32_t imm32);

1088 1089 1090 1091
  // Class for scoping postponing the constant pool generation.
  class BlockConstPoolScope {
   public:
    explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
1092
      assem_->StartBlockConstPool();
1093 1094
    }
    ~BlockConstPoolScope() {
1095
      assem_->EndBlockConstPool();
1096 1097 1098 1099
    }

   private:
    Assembler* assem_;
sgjesse@chromium.org's avatar
sgjesse@chromium.org committed
1100 1101

    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
1102
  };
1103

1104 1105 1106
  // Unused on this architecture.
  void MaybeEmitOutOfLineConstantPool() {}

1107 1108
  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
1109 1110
  void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position,
                         int id);
1111

1112 1113 1114 1115 1116 1117 1118 1119
  // Record the emission of a constant pool.
  //
  // The emission of constant pool depends on the size of the code generated and
  // the number of RelocInfo recorded.
  // The Debug mechanism needs to map code offsets between two versions of a
  // function, compiled with and without debugger support (see for example
  // Debug::PrepareForBreakPoints()).
  // Compiling functions with debugger support generates additional code
1120 1121 1122
  // (DebugCodegen::GenerateSlot()). This may affect the emission of the
  // constant pools and cause the version of the code with debugger support to
  // have constant pools generated in different places.
1123 1124 1125 1126 1127 1128 1129 1130
  // Recording the position and size of emitted constant pools allows to
  // correctly compute the offset mappings between the different versions of a
  // function in all situations.
  //
  // The parameter indicates the size of the constant pool (in bytes), including
  // the marker and branch over the data.
  void RecordConstPool(int size);

1131
  // Writes a single byte or word of data in the code stream.  Used
1132 1133
  // for inline tables, e.g., jump-tables. CheckConstantPool() should be
  // called before any use of db/dd/dq/dp to ensure that constant pools
1134
  // are not emitted as part of the tables generated.
1135 1136
  void db(uint8_t data);
  void dd(uint32_t data);
1137 1138
  void dq(uint64_t data);
  void dp(uintptr_t data) { dd(data); }
1139

1140
  // Read/patch instructions
1141 1142 1143
  Instr instr_at(int pos) {
    return *reinterpret_cast<Instr*>(buffer_start_ + pos);
  }
1144
  void instr_at_put(int pos, Instr instr) {
1145
    *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
1146
  }
1147 1148
  static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); }
  static void instr_at_put(Address pc, Instr instr) {
1149 1150
    *reinterpret_cast<Instr*>(pc) = instr;
  }
1151
  static Condition GetCondition(Instr instr);
1152
  static bool IsLdrRegisterImmediate(Instr instr);
1153
  static bool IsVldrDRegisterImmediate(Instr instr);
1154
  static int GetLdrRegisterImmediateOffset(Instr instr);
1155
  static int GetVldrDRegisterImmediateOffset(Instr instr);
1156
  static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset);
1157
  static Instr SetVldrDRegisterImmediateOffset(Instr instr, int offset);
1158 1159 1160 1161
  static bool IsStrRegisterImmediate(Instr instr);
  static Instr SetStrRegisterImmediateOffset(Instr instr, int offset);
  static bool IsAddRegisterImmediate(Instr instr);
  static Instr SetAddRegisterImmediateOffset(Instr instr, int offset);
1162
  static Register GetRd(Instr instr);
1163 1164
  static Register GetRn(Instr instr);
  static Register GetRm(Instr instr);
1165 1166 1167 1168 1169 1170
  static bool IsPush(Instr instr);
  static bool IsPop(Instr instr);
  static bool IsStrRegFpOffset(Instr instr);
  static bool IsLdrRegFpOffset(Instr instr);
  static bool IsStrRegFpNegOffset(Instr instr);
  static bool IsLdrRegFpNegOffset(Instr instr);
1171
  static bool IsLdrPcImmediateOffset(Instr instr);
1172
  static bool IsBOrBlPcImmediateOffset(Instr instr);
1173
  static bool IsVldrDPcImmediateOffset(Instr instr);
1174 1175
  static bool IsBlxReg(Instr instr);
  static bool IsBlxIp(Instr instr);
1176 1177 1178 1179 1180
  static bool IsTstImmediate(Instr instr);
  static bool IsCmpRegister(Instr instr);
  static bool IsCmpImmediate(Instr instr);
  static Register GetCmpImmediateRegister(Instr instr);
  static int GetCmpImmediateRawImmediate(Instr instr);
1181
  static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
1182 1183
  static bool IsMovImmed(Instr instr);
  static bool IsOrrImmed(Instr instr);
1184
  static bool IsMovT(Instr instr);
1185
  static Instr GetMovTPattern();
1186
  static bool IsMovW(Instr instr);
1187 1188 1189
  static Instr GetMovWPattern();
  static Instr EncodeMovwImmediate(uint32_t immediate);
  static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate);
1190 1191
  static int DecodeShiftImm(Instr instr);
  static Instr PatchShiftImm(Instr instr, int immed);
1192

1193
  // Constants in pools are accessed via pc relative addressing, which can
1194 1195 1196
  // reach +/-4KB for integer PC-relative loads and +/-1KB for floating-point
  // PC-relative loads, thereby defining a maximum distance between the
  // instruction and the accessed constant.
1197
  static constexpr int kMaxDistToIntPool = 4 * KB;
1198
  // All relocations could be integer, it therefore acts as the limit.
1199 1200 1201
  static constexpr int kMinNumPendingConstants = 4;
  static constexpr int kMaxNumPending32Constants =
      kMaxDistToIntPool / kInstrSize;
1202

1203 1204 1205 1206 1207
  // Postpone the generation of the constant pool for the specified number of
  // instructions.
  void BlockConstPoolFor(int instructions);

  // Check if is time to emit a constant pool.
1208
  void CheckConstPool(bool force_emit, bool require_jump);
1209

1210 1211 1212 1213 1214 1215
  void MaybeCheckConstPool() {
    if (pc_offset() >= next_buffer_check_) {
      CheckConstPool(false, true);
    }
  }

1216 1217 1218
  // Move a 32-bit immediate into a register, potentially via the constant pool.
  void Move32BitImmediate(Register rd, const Operand& x, Condition cond = al);

1219 1220 1221 1222
  // Get the code target object for a pc-relative call or jump.
  V8_INLINE Handle<Code> relative_code_target_object_handle_at(
      Address pc_) const;

1223 1224 1225
 protected:
  int buffer_space() const { return reloc_info_writer.pos() - pc_; }

1226 1227 1228 1229 1230 1231
  // Decode branch instruction at pos and return branch target pos
  int target_at(int pos);

  // Patch branch instruction at pos to branch to given branch target pos
  void target_at_put(int pos, int target_pos);

1232
  // Prevent contant pool emission until EndBlockConstPool is called.
1233
  // Calls to this function can be nested but must be followed by an equal
1234
  // number of call to EndBlockConstpool.
1235
  void StartBlockConstPool() {
1236 1237 1238 1239 1240
    if (const_pool_blocked_nesting_++ == 0) {
      // Prevent constant pool checks happening by setting the next check to
      // the biggest possible offset.
      next_buffer_check_ = kMaxInt;
    }
1241
  }
1242

1243
  // Resume constant pool emission. Needs to be called as many times as
1244
  // StartBlockConstPool to have an effect.
1245
  void EndBlockConstPool() {
1246
    if (--const_pool_blocked_nesting_ == 0) {
1247 1248 1249
#ifdef DEBUG
      // Max pool start (if we need a jump and an alignment).
      int start = pc_offset() + kInstrSize + 2 * kPointerSize;
1250
      // Check the constant pool hasn't been blocked for too long.
1251
      DCHECK(pending_32_bit_constants_.empty() ||
1252
             (start < first_const_pool_32_use_ + kMaxDistToIntPool));
1253
#endif
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
      // Two cases:
      //  * no_const_pool_before_ >= next_buffer_check_ and the emission is
      //    still blocked
      //  * no_const_pool_before_ < next_buffer_check_ and the next emit will
      //    trigger a check.
      next_buffer_check_ = no_const_pool_before_;
    }
  }

  bool is_const_pool_blocked() const {
    return (const_pool_blocked_nesting_ > 0) ||
           (pc_offset() < no_const_pool_before_);
1266 1267
  }

1268 1269 1270
  bool VfpRegisterIsAvailable(DwVfpRegister reg) {
    DCHECK(reg.is_valid());
    return IsEnabled(VFP32DREGS) ||
1271
           (reg.code() < LowDwVfpRegister::kNumRegisters);
1272 1273
  }

1274 1275 1276
  bool VfpRegisterIsAvailable(QwNeonRegister reg) {
    DCHECK(reg.is_valid());
    return IsEnabled(VFP32DREGS) ||
1277
           (reg.code() < LowDwVfpRegister::kNumRegisters / 2);
1278 1279
  }

1280
  inline void emit(Instr x);
1281 1282 1283 1284 1285 1286

  // Code generation
  // The relocation writer's position is at least kGap bytes below the end of
  // the generated instructions. This is so that multi-instruction sequences do
  // not have to check for overflow. The same is true for writes of large
  // relocation info entries.
1287
  static constexpr int kGap = 32;
1288

1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
  // Relocation info generation
  // Each relocation is encoded as a variable size value
  static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
  RelocInfoWriter reloc_info_writer;

  // ConstantPoolEntry records are used during code generation as temporary
  // containers for constants and code target addresses until they are emitted
  // to the constant pool. These records are temporarily stored in a separate
  // buffer until a constant pool is emitted.
  // If every instruction in a long sequence is accessing the pool, we need one
  // pending relocation entry per instruction.

  // The buffers of pending constant pool entries.
  std::vector<ConstantPoolEntry> pending_32_bit_constants_;

1304 1305
  // Scratch registers available for use by the Assembler.
  RegList scratch_register_list_;
1306
  VfpRegList scratch_vfp_register_list_;
1307

1308
 private:
1309 1310 1311
  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512 * MB;

1312 1313
  int next_buffer_check_;  // pc offset of next buffer check

1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
  // Constant pool generation
  // Pools are emitted in the instruction stream, preferably after unconditional
  // jumps or after returns from functions (in dead code locations).
  // If a long code sequence does not contain unconditional jumps, it is
  // necessary to emit the constant pool before the pool gets too far from the
  // location it is accessed from. In this case, we emit a jump over the emitted
  // constant pool.
  // Constants in the pool may be addresses of functions that gets relocated;
  // if so, a relocation info entry is associated to the constant pool entry.

  // Repeated checking whether the constant pool should be emitted is rather
  // expensive. By default we only check again once a number of instructions
  // has been generated. That also means that the sizing of the buffers is not
  // an exact science, and that we rely on some slop to not overrun buffers.
1328 1329
  static constexpr int kCheckPoolIntervalInst = 32;
  static constexpr int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize;
1330

1331 1332 1333
  // Emission of the constant pool may be blocked in some code sequences.
  int const_pool_blocked_nesting_;  // Block emission if this is not zero.
  int no_const_pool_before_;  // Block emission before this pc offset.
1334

1335 1336
  // Keep track of the first instruction requiring a constant pool entry
  // since the previous constant pool was emitted.
1337
  int first_const_pool_32_use_;
1338

1339
  // The bound position, before this we cannot do instruction elimination.
1340 1341 1342 1343 1344 1345
  int last_bound_pos_;

  inline void CheckBuffer();
  void GrowBuffer();

  // Instruction generation
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
  void AddrMode1(Instr instr, Register rd, Register rn, const Operand& x);
  // Attempt to encode operand |x| for instruction |instr| and return true on
  // success. The result will be encoded in |instr| directly. This method may
  // change the opcode if deemed beneficial, for instance, MOV may be turned
  // into MVN, ADD into SUB, AND into BIC, ...etc.  The only reason this method
  // may fail is that the operand is an immediate that cannot be encoded.
  bool AddrMode1TryEncodeOperand(Instr* instr, const Operand& x);

  void AddrMode2(Instr instr, Register rd, const MemOperand& x);
  void AddrMode3(Instr instr, Register rd, const MemOperand& x);
  void AddrMode4(Instr instr, Register rn, RegList rl);
  void AddrMode5(Instr instr, CRegister crd, const MemOperand& x);
1358 1359

  // Labels
1360
  void print(const Label* L);
1361 1362 1363 1364
  void bind_to(Label* L, int pos);
  void next(Label* L);

  // Record reloc info for current pc_
1365
  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1366 1367
  void ConstantPoolAddEntry(int position, RelocInfo::Mode rmode,
                            intptr_t value);
1368
  void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
lrn@chromium.org's avatar
lrn@chromium.org committed
1369

1370 1371
  int WriteCodeComments();

1372
  friend class RelocInfo;
1373
  friend class BlockConstPoolScope;
1374
  friend class EnsureSpace;
1375
  friend class UseScratchRegisterScope;
1376 1377
};

1378
class EnsureSpace {
1379
 public:
1380
  V8_INLINE explicit EnsureSpace(Assembler* assembler);
1381 1382
};

1383 1384
class PatchingAssembler : public Assembler {
 public:
1385 1386
  PatchingAssembler(const AssemblerOptions& options, byte* address,
                    int instructions);
1387 1388 1389
  ~PatchingAssembler();

  void Emit(Address addr);
1390
  void PadWithNops();
1391 1392
};

1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
// This scope utility allows scratch registers to be managed safely. The
// Assembler's GetScratchRegisterList() is used as a pool of scratch
// registers. These registers can be allocated on demand, and will be returned
// at the end of the scope.
//
// When the scope ends, the Assembler's list will be restored to its original
// state, even if the list is modified by some other means. Note that this scope
// can be nested but the destructors need to run in the opposite order as the
// constructors. We do not have assertions for this.
class UseScratchRegisterScope {
 public:
  explicit UseScratchRegisterScope(Assembler* assembler);
  ~UseScratchRegisterScope();

  // Take a register from the list and return it.
  Register Acquire();
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
  SwVfpRegister AcquireS() { return AcquireVfp<SwVfpRegister>(); }
  LowDwVfpRegister AcquireLowD() { return AcquireVfp<LowDwVfpRegister>(); }
  DwVfpRegister AcquireD() {
    DwVfpRegister reg = AcquireVfp<DwVfpRegister>();
    DCHECK(assembler_->VfpRegisterIsAvailable(reg));
    return reg;
  }
  QwNeonRegister AcquireQ() {
    QwNeonRegister reg = AcquireVfp<QwNeonRegister>();
    DCHECK(assembler_->VfpRegisterIsAvailable(reg));
    return reg;
  }
1421

1422 1423 1424 1425
  // Check if we have registers available to acquire.
  bool CanAcquire() const { return *assembler_->GetScratchRegisterList() != 0; }
  bool CanAcquireD() const { return CanAcquireVfp<DwVfpRegister>(); }

1426
 private:
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
  friend class Assembler;
  friend class TurboAssembler;

  template <typename T>
  bool CanAcquireVfp() const;

  template <typename T>
  T AcquireVfp();

  Assembler* assembler_;
1437 1438
  // Available scratch registers at the start of this scope.
  RegList old_available_;
1439
  VfpRegList old_available_vfp_;
1440
};
1441

1442 1443
}  // namespace internal
}  // namespace v8
1444

1445
#endif  // V8_ARM_ASSEMBLER_ARM_H_