assembler-ppc.h 53.7 KB
Newer Older
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 2014 the V8 project authors. All rights reserved.

// A light-weight PPC Assembler
// Generates user mode instructions for the PPC architecture up

40 41
#ifndef V8_CODEGEN_PPC_ASSEMBLER_PPC_H_
#define V8_CODEGEN_PPC_ASSEMBLER_PPC_H_
42 43

#include <stdio.h>
44
#include <memory>
45 46
#include <vector>

47 48
#include "src/codegen/assembler.h"
#include "src/codegen/constant-pool.h"
49
#include "src/codegen/external-reference.h"
50
#include "src/codegen/label.h"
51 52
#include "src/codegen/ppc/constants-ppc.h"
#include "src/codegen/ppc/register-ppc.h"
53
#include "src/numbers/double.h"
54
#include "src/objects/smi.h"
55 56 57 58

namespace v8 {
namespace internal {

59 60
class SafepointTableBuilder;

61 62 63 64
// -----------------------------------------------------------------------------
// Machine instruction Operands

// Class Operand represents a shifter operand in data processing instructions
65
class V8_EXPORT_PRIVATE Operand {
66 67
 public:
  // immediate
68 69 70
  V8_INLINE explicit Operand(intptr_t immediate,
                             RelocInfo::Mode rmode = RelocInfo::NONE)
      : rmode_(rmode) {
71 72
    value_.immediate = immediate;
  }
73 74 75
  V8_INLINE static Operand Zero() { return Operand(static_cast<intptr_t>(0)); }
  V8_INLINE explicit Operand(const ExternalReference& f)
      : rmode_(RelocInfo::EXTERNAL_REFERENCE) {
76
    value_.immediate = static_cast<intptr_t>(f.address());
77
  }
78
  explicit Operand(Handle<HeapObject> handle);
79 80
  V8_INLINE explicit Operand(Smi value) : rmode_(RelocInfo::NONE) {
    value_.immediate = static_cast<intptr_t>(value.ptr());
81
  }
82
  // rm
83
  V8_INLINE explicit Operand(Register rm);
84

85
  static Operand EmbeddedNumber(double number);  // Smi or HeapNumber.
86
  static Operand EmbeddedStringConstant(const StringConstantBase* str);
87

88
  // Return true if this is a register operand.
89
  V8_INLINE bool is_reg() const { return rm_.is_valid(); }
90 91 92 93

  bool must_output_reloc_info(const Assembler* assembler) const;

  inline intptr_t immediate() const {
94 95 96 97 98 99 100 101 102
    DCHECK(IsImmediate());
    DCHECK(!IsHeapObjectRequest());
    return value_.immediate;
  }
  bool IsImmediate() const { return !rm_.is_valid(); }

  HeapObjectRequest heap_object_request() const {
    DCHECK(IsHeapObjectRequest());
    return value_.heap_object_request;
103 104 105 106
  }

  Register rm() const { return rm_; }

107 108 109
  bool IsHeapObjectRequest() const {
    DCHECK_IMPLIES(is_heap_object_request_, IsImmediate());
    DCHECK_IMPLIES(is_heap_object_request_,
110
                   rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
111 112 113 114
                       rmode_ == RelocInfo::CODE_TARGET);
    return is_heap_object_request_;
  }

115
 private:
116
  Register rm_ = no_reg;
117 118 119 120 121 122 123
  union Value {
    Value() {}
    HeapObjectRequest heap_object_request;  // if is_heap_object_request_
    intptr_t immediate;                     // otherwise
  } value_;                                 // valid if rm_ == no_reg
  bool is_heap_object_request_ = false;

124 125 126 127 128 129 130 131 132
  RelocInfo::Mode rmode_;

  friend class Assembler;
  friend class MacroAssembler;
};

// Class MemOperand represents a memory operand in load and store instructions
// On PowerPC we have base register + 16bit signed value
// Alternatively we can have a 16bit signed value immediate
133
class V8_EXPORT_PRIVATE MemOperand {
134 135 136 137 138
 public:
  explicit MemOperand(Register rn, int32_t offset = 0);

  explicit MemOperand(Register ra, Register rb);

139
  int32_t offset() const { return offset_; }
140 141

  // PowerPC - base register
142
  Register ra() const { return ra_; }
143

144
  Register rb() const { return rb_; }
145 146 147 148 149 150 151 152 153

 private:
  Register ra_;     // base
  int32_t offset_;  // offset
  Register rb_;     // index

  friend class Assembler;
};

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
class DeferredRelocInfo {
 public:
  DeferredRelocInfo() {}
  DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
      : position_(position), rmode_(rmode), data_(data) {}

  int position() const { return position_; }
  RelocInfo::Mode rmode() const { return rmode_; }
  intptr_t data() const { return data_; }

 private:
  int position_;
  RelocInfo::Mode rmode_;
  intptr_t data_;
};

170 171 172 173 174 175 176
class Assembler : public AssemblerBase {
 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).
  //
177
  // If the provided buffer is nullptr, the assembler allocates and grows its
178 179 180 181
  // own buffer. Otherwise it takes ownership of the provided buffer.
  explicit Assembler(const AssemblerOptions&,
                     std::unique_ptr<AssemblerBuffer> = {});

182 183
  virtual ~Assembler() {}

184 185 186 187 188 189 190 191 192 193 194
  // 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);
  }
195

196 197
  void MaybeEmitOutOfLineConstantPool() { EmitConstantPool(); }

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  // 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
214 215 216 217 218 219

  // Links a label at the current pc_offset().  If already bound, returns the
  // bound position.  If already linked, returns the position of the prior link.
  // Otherwise, returns the current pc_offset().
  int link(Label* L);

220 221 222 223 224 225
  // Determines if Label is bound and near enough so that a single
  // branch instruction can be used to reach it.
  bool is_near(Label* L, Condition cond);

  // 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
226
  int branch_offset(Label* L) {
227 228 229 230
    if (L->is_unused() && !trampoline_emitted_) {
      TrackBranch();
    }
    return link(L) - pc_offset();
231
  }
232

233 234 235 236 237 238 239 240
  V8_INLINE static bool IsConstantPoolLoadStart(
      Address pc, ConstantPoolEntry::Access* access = nullptr);
  V8_INLINE static bool IsConstantPoolLoadEnd(
      Address pc, ConstantPoolEntry::Access* access = nullptr);
  V8_INLINE static int GetConstantPoolOffset(Address pc,
                                             ConstantPoolEntry::Access access,
                                             ConstantPoolEntry::Type type);
  V8_INLINE void PatchConstantPoolAccessInstruction(
241
      int pc_offset, int offset, ConstantPoolEntry::Access access,
242
      ConstantPoolEntry::Type type);
243 244 245

  // Return the address in the constant pool of the code target address used by
  // the branch/call instruction at pc, or the object in a mov.
246
  V8_INLINE static Address target_constant_pool_address_at(
247
      Address pc, Address constant_pool, ConstantPoolEntry::Access access,
248
      ConstantPoolEntry::Type type);
249

250
  // Read/Modify the code target address in the branch/call instruction at pc.
251
  // The isolate argument is unused (and may be nullptr) when skipping flushing.
252 253
  V8_INLINE static Address target_address_at(Address pc, Address constant_pool);
  V8_INLINE static void set_target_address_at(
254
      Address pc, Address constant_pool, Address target,
255
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
256

257 258 259 260 261 262 263 264 265 266 267 268
  // Read/Modify the code target address in the branch/call instruction at pc.
  inline static Tagged_t target_compressed_address_at(Address pc,
                                                      Address constant_pool);
  inline static void set_target_compressed_address_at(
      Address pc, Address constant_pool, Tagged_t target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);

  inline Handle<Object> code_target_object_handle_at(Address pc,
                                                     Address constant_pool);
  inline Handle<HeapObject> compressed_embedded_object_handle_at(
      Address pc, Address constant_pool);

269 270 271
  // This sets the branch destination.
  // This is for calls and branches within generated code.
  inline static void deserialization_set_special_target_at(
272
      Address instruction_payload, Code code, Address target);
273

274 275 276 277
  // Get the size of the special target encoded at 'instruction_payload'.
  inline static int deserialization_special_target_size(
      Address instruction_payload);

278 279
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
280
      Address pc, Address target,
281
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
282

283 284 285 286 287 288
  // Here we are patching the address in the LUI/ORI instruction pair.
  // These values are used in the serialization process and must be zero for
  // PPC platform, as Code, Embedded Object or External-reference pointers
  // are split across two consecutive instructions and don't exist separately
  // in the code, so the serializer should not step forwards in memory after
  // a target is resolved and written.
289
  static constexpr int kSpecialTargetSize = 0;
290 291 292

// Number of instructions to load an address via a mov sequence.
#if V8_TARGET_ARCH_PPC64
293 294
  static constexpr int kMovInstructionsConstantPool = 1;
  static constexpr int kMovInstructionsNoConstantPool = 5;
295
#if defined(V8_PPC_TAGGING_OPT)
296
  static constexpr int kTaggedLoadInstructions = 1;
297
#else
298
  static constexpr int kTaggedLoadInstructions = 2;
299
#endif
300
#else
301 302 303
  static constexpr int kMovInstructionsConstantPool = 1;
  static constexpr int kMovInstructionsNoConstantPool = 2;
  static constexpr int kTaggedLoadInstructions = 1;
304
#endif
305 306 307
  static constexpr int kMovInstructions = FLAG_enable_embedded_constant_pool
                                              ? kMovInstructionsConstantPool
                                              : kMovInstructionsNoConstantPool;
308 309 310 311 312

  static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) {
    return ((cr.code() * CRWIDTH) + crbit);
  }

313
#define DECLARE_PPC_X_INSTRUCTIONS_A_FORM(name, instr_name, instr_value)    \
314 315
  inline void name(const Register rt, const Register ra, const Register rb, \
                   const RCBit rc = LeaveRC) {                              \
316 317 318 319
    x_form(instr_name, rt, ra, rb, rc);                                     \
  }

#define DECLARE_PPC_X_INSTRUCTIONS_B_FORM(name, instr_name, instr_value)    \
320 321
  inline void name(const Register ra, const Register rs, const Register rb, \
                   const RCBit rc = LeaveRC) {                              \
322 323 324
    x_form(instr_name, rs, ra, rb, rc);                                     \
  }

325 326 327 328
#define DECLARE_PPC_X_INSTRUCTIONS_C_FORM(name, instr_name, instr_value) \
  inline void name(const Register dst, const Register src,               \
                   const RCBit rc = LeaveRC) {                           \
    x_form(instr_name, src, dst, r0, rc);                                \
329 330
  }

331 332 333 334 335 336 337 338 339
#define DECLARE_PPC_X_INSTRUCTIONS_D_FORM(name, instr_name, instr_value) \
  template <class R>                                                     \
  inline void name(const R rt, const Register ra, const Register rb,     \
                   const RCBit rc = LeaveRC) {                           \
    x_form(instr_name, rt.code(), ra.code(), rb.code(), rc);             \
  }                                                                      \
  template <class R>                                                     \
  inline void name(const R dst, const MemOperand& src) {                 \
    name(dst, src.ra(), src.rb());                                       \
340 341
  }

342 343 344 345
#define DECLARE_PPC_X_INSTRUCTIONS_E_FORM(name, instr_name, instr_value) \
  inline void name(const Register dst, const Register src, const int sh, \
                   const RCBit rc = LeaveRC) {                           \
    x_form(instr_name, src.code(), dst.code(), sh, rc);                  \
346 347 348 349 350 351 352 353 354 355 356 357
  }

#define DECLARE_PPC_X_INSTRUCTIONS_F_FORM(name, instr_name, instr_value)    \
  inline void name(const Register src1, const Register src2,                \
                   const CRegister cr = cr7, const RCBit rc = LeaveRC) {    \
    x_form(instr_name, cr, src1, src2, rc);                                 \
  }                                                                         \
  inline void name##w(const Register src1, const Register src2,             \
                      const CRegister cr = cr7, const RCBit rc = LeaveRC) { \
    x_form(instr_name, cr.code() * B2, src1.code(), src2.code(), LeaveRC);  \
  }

358 359 360 361 362 363
#define DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM(name, instr_name, instr_value) \
  inline void name(const Register dst, const MemOperand& src) {             \
    x_form(instr_name, src.ra(), dst, src.rb(), SetEH);                     \
  }
#define DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM(name, instr_name, instr_value) \
  inline void name(const Register dst, const MemOperand& src) {             \
364
    DCHECK(src.ra_ != r0);                                                  \
365 366 367
    x_form(instr_name, src.ra(), dst, src.rb(), SetEH);                     \
  }

368 369 370 371 372 373 374
  inline void x_form(Instr instr, int f1, int f2, int f3, int rc) {
    emit(instr | f1 * B21 | f2 * B16 | f3 * B11 | rc);
  }
  inline void x_form(Instr instr, Register rs, Register ra, Register rb,
                     RCBit rc) {
    emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | rc);
  }
375 376 377 378
  inline void x_form(Instr instr, Register ra, Register rs, Register rb,
                     EHBit eh = SetEH) {
    emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | eh);
  }
379 380 381 382 383 384 385
  inline void x_form(Instr instr, CRegister cr, Register s1, Register s2,
                     RCBit rc) {
#if V8_TARGET_ARCH_PPC64
    int L = 1;
#else
    int L = 0;
#endif
386 387
    emit(instr | cr.code() * B23 | L * B21 | s1.code() * B16 | s2.code() * B11 |
         rc);
388 389 390 391 392 393 394 395
  }

  PPC_X_OPCODE_A_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_A_FORM)
  PPC_X_OPCODE_B_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_B_FORM)
  PPC_X_OPCODE_C_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_C_FORM)
  PPC_X_OPCODE_D_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_D_FORM)
  PPC_X_OPCODE_E_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_E_FORM)
  PPC_X_OPCODE_F_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_F_FORM)
396 397
  PPC_X_OPCODE_EH_S_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM)
  PPC_X_OPCODE_EH_L_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM)
398 399 400 401 402 403 404 405

  inline void notx(Register dst, Register src, RCBit rc = LeaveRC) {
    nor(dst, src, src, rc);
  }
  inline void lwax(Register rt, const MemOperand& src) {
#if V8_TARGET_ARCH_PPC64
    Register ra = src.ra();
    Register rb = src.rb();
406
    DCHECK(ra != r0);
407 408 409 410 411 412 413 414 415 416
    x_form(LWAX, rt, ra, rb, LeaveRC);
#else
    lwzx(rt, src);
#endif
  }
  inline void extsw(Register rs, Register ra, RCBit rc = LeaveRC) {
#if V8_TARGET_ARCH_PPC64
    emit(EXT2 | EXTSW | ra.code() * B21 | rs.code() * B16 | rc);
#else
    // nop on 32-bit
417
    DCHECK(rs == ra && rc == LeaveRC);
418 419 420 421 422 423 424 425 426
#endif
  }

#undef DECLARE_PPC_X_INSTRUCTIONS_A_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_B_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_C_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_D_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_E_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_F_FORM
427 428
#undef DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM
#undef DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM
429

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
#define DECLARE_PPC_XX2_INSTRUCTIONS(name, instr_name, instr_value)      \
  inline void name(const Simd128Register rt, const Simd128Register rb) { \
    xx2_form(instr_name, rt, rb);                                        \
  }

  inline void xx2_form(Instr instr, Simd128Register t, Simd128Register b) {
    // Using VR (high VSR) registers.
    int BX = 1;
    int TX = 1;

    emit(instr | (t.code() & 0x1F) * B21 | (b.code() & 0x1F) * B11 | BX * B1 |
         TX);
  }

  PPC_XX2_OPCODE_A_FORM_LIST(DECLARE_PPC_XX2_INSTRUCTIONS)
#undef DECLARE_PPC_XX2_INSTRUCTIONS

447 448 449 450
#define DECLARE_PPC_XX3_INSTRUCTIONS(name, instr_name, instr_value)    \
  inline void name(const Simd128Register rt, const Simd128Register ra, \
                   const Simd128Register rb) {                         \
    xx3_form(instr_name, rt, ra, rb);                                  \
451 452
  }

453 454
  inline void xx3_form(Instr instr, Simd128Register t, Simd128Register a,
                       Simd128Register b) {
455 456 457 458
    // Using VR (high VSR) registers.
    int AX = 1;
    int BX = 1;
    int TX = 1;
459 460 461 462 463 464 465 466

    emit(instr | (t.code() & 0x1F) * B21 | (a.code() & 0x1F) * B16 |
         (b.code() & 0x1F) * B11 | AX * B2 | BX * B1 | TX);
  }

  PPC_XX3_OPCODE_LIST(DECLARE_PPC_XX3_INSTRUCTIONS)
#undef DECLARE_PPC_XX3_INSTRUCTIONS

467
#define DECLARE_PPC_VX_INSTRUCTIONS_A_FORM(name, instr_name, instr_value) \
468
  inline void name(const Simd128Register rt, const Simd128Register rb,    \
469 470 471
                   const Operand& imm) {                                  \
    vx_form(instr_name, rt, rb, imm);                                     \
  }
472 473 474 475 476
#define DECLARE_PPC_VX_INSTRUCTIONS_B_FORM(name, instr_name, instr_value) \
  inline void name(const Simd128Register rt, const Simd128Register ra,    \
                   const Simd128Register rb) {                            \
    vx_form(instr_name, rt, ra, rb);                                      \
  }
477 478 479 480
#define DECLARE_PPC_VX_INSTRUCTIONS_C_FORM(name, instr_name, instr_value) \
  inline void name(const Simd128Register rt, const Simd128Register rb) {  \
    vx_form(instr_name, rt, rb);                                          \
  }
481

482
  inline void vx_form(Instr instr, Simd128Register rt, Simd128Register rb,
483 484 485
                      const Operand& imm) {
    emit(instr | rt.code() * B21 | imm.immediate() * B16 | rb.code() * B11);
  }
486 487 488 489
  inline void vx_form(Instr instr, Simd128Register rt, Simd128Register ra,
                      Simd128Register rb) {
    emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11);
  }
490 491 492
  inline void vx_form(Instr instr, Simd128Register rt, Simd128Register rb) {
    emit(instr | rt.code() * B21 | rb.code() * B11);
  }
493 494

  PPC_VX_OPCODE_A_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_A_FORM)
495
  PPC_VX_OPCODE_B_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_B_FORM)
496
  PPC_VX_OPCODE_C_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_C_FORM)
497
#undef DECLARE_PPC_VX_INSTRUCTIONS_A_FORM
498
#undef DECLARE_PPC_VX_INSTRUCTIONS_B_FORM
499
#undef DECLARE_PPC_VX_INSTRUCTIONS_C_FORM
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

#define DECLARE_PPC_VA_INSTRUCTIONS_A_FORM(name, instr_name, instr_value) \
  inline void name(const Simd128Register rt, const Simd128Register ra,    \
                   const Simd128Register rb, const Simd128Register rc) {  \
    va_form(instr_name, rt, ra, rb, rc);                                  \
  }

  inline void va_form(Instr instr, Simd128Register rt, Simd128Register ra,
                      Simd128Register rb, Simd128Register rc) {
    emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
         rc.code() * B6);
  }

  PPC_VA_OPCODE_A_FORM_LIST(DECLARE_PPC_VA_INSTRUCTIONS_A_FORM)
#undef DECLARE_PPC_VA_INSTRUCTIONS_A_FORM
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
#define DECLARE_PPC_VC_INSTRUCTIONS(name, instr_name, instr_value)       \
  inline void name(const Simd128Register rt, const Simd128Register ra,   \
                   const Simd128Register rb, const RCBit rc = LeaveRC) { \
    vc_form(instr_name, rt, ra, rb, rc);                                 \
  }

  inline void vc_form(Instr instr, Simd128Register rt, Simd128Register ra,
                      Simd128Register rb, int rc) {
    emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
         rc * B10);
  }

  PPC_VC_OPCODE_LIST(DECLARE_PPC_VC_INSTRUCTIONS)
#undef DECLARE_PPC_VC_INSTRUCTIONS

531
  RegList* GetScratchRegisterList() { return &scratch_register_list_; }
532 533 534 535 536 537 538
  // ---------------------------------------------------------------------------
  // 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);
539 540 541
  // 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);
542 543 544 545
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();

  // Branch instructions
546
  void bclr(BOfield bo, int condition_bit, LKBit lk);
547 548 549 550
  void blr();
  void bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk = LeaveLK);
  void b(int branch_offset, LKBit lk);

551
  void bcctr(BOfield bo, int condition_bit, LKBit lk);
552 553 554 555
  void bctr();
  void bctrl();

  // Convenience branch instructions using labels
556
  void b(Label* L, LKBit lk = LeaveLK) { b(branch_offset(L), lk); }
557

558
  inline CRegister cmpi_optimization(CRegister cr) {
559 560
    // Check whether the branch is preceded by an optimizable cmpi against 0.
    // The cmpi can be deleted if it is also preceded by an instruction that
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
    // sets the register used by the compare and supports a dot form.
    unsigned int sradi_mask = kOpcodeMask | kExt2OpcodeVariant2Mask;
    unsigned int srawi_mask = kOpcodeMask | kExt2OpcodeMask;
    int pos = pc_offset();
    int cmpi_pos = pc_offset() - kInstrSize;

    if (cmpi_pos > 0 && optimizable_cmpi_pos_ == cmpi_pos &&
        cmpi_cr_.code() == cr.code() && last_bound_pos_ != pos) {
      int xpos = cmpi_pos - kInstrSize;
      int xinstr = instr_at(xpos);
      int cmpi_ra = (instr_at(cmpi_pos) & 0x1f0000) >> 16;
      // ra is at the same bit position for the three cases below.
      int ra = (xinstr & 0x1f0000) >> 16;
      if (cmpi_ra == ra) {
        if ((xinstr & sradi_mask) == (EXT2 | SRADIX)) {
          cr = cr0;
          instr_at_put(xpos, xinstr | SetRC);
          pc_ -= kInstrSize;
        } else if ((xinstr & srawi_mask) == (EXT2 | SRAWIX)) {
          cr = cr0;
          instr_at_put(xpos, xinstr | SetRC);
          pc_ -= kInstrSize;
        } else if ((xinstr & kOpcodeMask) == ANDIx) {
          cr = cr0;
          pc_ -= kInstrSize;
          // nothing to do here since andi. records.
        }
        // didn't match one of the above, must keep cmpwi.
      }
    }
    return cr;
  }

594 595 596 597 598
  void bc_short(Condition cond, Label* L, CRegister cr = cr7,
                LKBit lk = LeaveLK) {
    DCHECK(cond != al);
    DCHECK(cr.code() >= 0 && cr.code() <= 7);

599 600
    cr = cmpi_optimization(cr);

601
    int b_offset = branch_offset(L);
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638

    switch (cond) {
      case eq:
        bc(b_offset, BT, encode_crbit(cr, CR_EQ), lk);
        break;
      case ne:
        bc(b_offset, BF, encode_crbit(cr, CR_EQ), lk);
        break;
      case gt:
        bc(b_offset, BT, encode_crbit(cr, CR_GT), lk);
        break;
      case le:
        bc(b_offset, BF, encode_crbit(cr, CR_GT), lk);
        break;
      case lt:
        bc(b_offset, BT, encode_crbit(cr, CR_LT), lk);
        break;
      case ge:
        bc(b_offset, BF, encode_crbit(cr, CR_LT), lk);
        break;
      case unordered:
        bc(b_offset, BT, encode_crbit(cr, CR_FU), lk);
        break;
      case ordered:
        bc(b_offset, BF, encode_crbit(cr, CR_FU), lk);
        break;
      case overflow:
        bc(b_offset, BT, encode_crbit(cr, CR_SO), lk);
        break;
      case nooverflow:
        bc(b_offset, BF, encode_crbit(cr, CR_SO), lk);
        break;
      default:
        UNIMPLEMENTED();
    }
  }

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
  void bclr(Condition cond, CRegister cr = cr7, LKBit lk = LeaveLK) {
    DCHECK(cond != al);
    DCHECK(cr.code() >= 0 && cr.code() <= 7);

    cr = cmpi_optimization(cr);

    switch (cond) {
      case eq:
        bclr(BT, encode_crbit(cr, CR_EQ), lk);
        break;
      case ne:
        bclr(BF, encode_crbit(cr, CR_EQ), lk);
        break;
      case gt:
        bclr(BT, encode_crbit(cr, CR_GT), lk);
        break;
      case le:
        bclr(BF, encode_crbit(cr, CR_GT), lk);
        break;
      case lt:
        bclr(BT, encode_crbit(cr, CR_LT), lk);
        break;
      case ge:
        bclr(BF, encode_crbit(cr, CR_LT), lk);
        break;
      case unordered:
        bclr(BT, encode_crbit(cr, CR_FU), lk);
        break;
      case ordered:
        bclr(BF, encode_crbit(cr, CR_FU), lk);
        break;
      case overflow:
        bclr(BT, encode_crbit(cr, CR_SO), lk);
        break;
      case nooverflow:
        bclr(BF, encode_crbit(cr, CR_SO), lk);
        break;
      default:
        UNIMPLEMENTED();
    }
  }

681 682 683 684 685 686
  void isel(Register rt, Register ra, Register rb, int cb);
  void isel(Condition cond, Register rt, Register ra, Register rb,
            CRegister cr = cr7) {
    DCHECK(cond != al);
    DCHECK(cr.code() >= 0 && cr.code() <= 7);

687 688
    cr = cmpi_optimization(cr);

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
    switch (cond) {
      case eq:
        isel(rt, ra, rb, encode_crbit(cr, CR_EQ));
        break;
      case ne:
        isel(rt, rb, ra, encode_crbit(cr, CR_EQ));
        break;
      case gt:
        isel(rt, ra, rb, encode_crbit(cr, CR_GT));
        break;
      case le:
        isel(rt, rb, ra, encode_crbit(cr, CR_GT));
        break;
      case lt:
        isel(rt, ra, rb, encode_crbit(cr, CR_LT));
        break;
      case ge:
        isel(rt, rb, ra, encode_crbit(cr, CR_LT));
        break;
      case unordered:
        isel(rt, ra, rb, encode_crbit(cr, CR_FU));
        break;
      case ordered:
        isel(rt, rb, ra, encode_crbit(cr, CR_FU));
        break;
      case overflow:
        isel(rt, ra, rb, encode_crbit(cr, CR_SO));
        break;
      case nooverflow:
        isel(rt, rb, ra, encode_crbit(cr, CR_SO));
        break;
      default:
        UNIMPLEMENTED();
    }
  }

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
  void b(Condition cond, Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    if (cond == al) {
      b(L, lk);
      return;
    }

    if ((L->is_bound() && is_near(L, cond)) || !is_trampoline_emitted()) {
      bc_short(cond, L, cr, lk);
      return;
    }

    Label skip;
    Condition neg_cond = NegateCondition(cond);
    bc_short(neg_cond, &skip, cr);
    b(L, lk);
    bind(&skip);
  }

  void bne(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(ne, L, cr, lk);
  }
  void beq(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(eq, L, cr, lk);
  }
  void blt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(lt, L, cr, lk);
  }
  void bge(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(ge, L, cr, lk);
  }
  void ble(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(le, L, cr, lk);
  }
  void bgt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(gt, L, cr, lk);
  }
  void bunordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(unordered, L, cr, lk);
  }
  void bordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
    b(ordered, L, cr, lk);
  }
  void boverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
    b(overflow, L, cr, lk);
  }
  void bnooverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
    b(nooverflow, L, cr, lk);
  }

  // Decrement CTR; branch if CTR != 0
  void bdnz(Label* L, LKBit lk = LeaveLK) {
776
    bc(branch_offset(L), DCBNZ, 0, lk);
777 778 779 780 781 782 783
  }

  // Data-processing instructions

  void sub(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
           RCBit r = LeaveRC);

784 785 786 787
  void subc(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
            RCBit r = LeaveRC);
  void sube(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
            RCBit r = LeaveRC);
788

789
  void subfic(Register dst, Register src, const Operand& imm);
790 791 792 793 794 795

  void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
           RCBit r = LeaveRC);

  void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
            RCBit r = LeaveRC);
796 797 798
  void adde(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
            RCBit r = LeaveRC);
  void addze(Register dst, Register src1, OEBit o = LeaveOE, RCBit r = LeaveRC);
799 800 801 802

  void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
             RCBit r = LeaveRC);

803 804
  void mulhw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
  void mulhwu(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
805 806 807

  void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
            RCBit r = LeaveRC);
808 809
  void divwu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
             RCBit r = LeaveRC);
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830

  void addi(Register dst, Register src, const Operand& imm);
  void addis(Register dst, Register src, const Operand& imm);
  void addic(Register dst, Register src, const Operand& imm);

  void andi(Register ra, Register rs, const Operand& imm);
  void andis(Register ra, Register rs, const Operand& imm);
  void ori(Register dst, Register src, const Operand& imm);
  void oris(Register dst, Register src, const Operand& imm);
  void xori(Register dst, Register src, const Operand& imm);
  void xoris(Register ra, Register rs, const Operand& imm);
  void cmpi(Register src1, const Operand& src2, CRegister cr = cr7);
  void cmpli(Register src1, const Operand& src2, CRegister cr = cr7);
  void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7);
  void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7);
  void li(Register dst, const Operand& src);
  void lis(Register dst, const Operand& imm);
  void mr(Register dst, Register src);

  void lbz(Register dst, const MemOperand& src);
  void lhz(Register dst, const MemOperand& src);
831
  void lha(Register dst, const MemOperand& src);
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 858 859 860 861 862 863 864
  void lwz(Register dst, const MemOperand& src);
  void lwzu(Register dst, const MemOperand& src);
  void lwa(Register dst, const MemOperand& src);
  void stb(Register dst, const MemOperand& src);
  void sth(Register dst, const MemOperand& src);
  void stw(Register dst, const MemOperand& src);
  void stwu(Register dst, const MemOperand& src);
  void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC);

#if V8_TARGET_ARCH_PPC64
  void ld(Register rd, const MemOperand& src);
  void ldu(Register rd, const MemOperand& src);
  void std(Register rs, const MemOperand& src);
  void stdu(Register rs, const MemOperand& src);
  void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
  void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
  void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC);
  void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC);
  void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
  void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
  void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
  void clrrdi(Register dst, Register src, const Operand& val,
              RCBit rc = LeaveRC);
  void clrldi(Register dst, Register src, const Operand& val,
              RCBit rc = LeaveRC);
  void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
  void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
  void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
  void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
  void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
             RCBit r = LeaveRC);
  void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
            RCBit r = LeaveRC);
865 866
  void divdu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
             RCBit r = LeaveRC);
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
#endif

  void rlwinm(Register ra, Register rs, int sh, int mb, int me,
              RCBit rc = LeaveRC);
  void rlwimi(Register ra, Register rs, int sh, int mb, int me,
              RCBit rc = LeaveRC);
  void rlwnm(Register ra, Register rs, Register rb, int mb, int me,
             RCBit rc = LeaveRC);
  void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
  void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
  void clrrwi(Register dst, Register src, const Operand& val,
              RCBit rc = LeaveRC);
  void clrlwi(Register dst, Register src, const Operand& val,
              RCBit rc = LeaveRC);
  void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
  void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
  void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);

  void subi(Register dst, Register src1, const Operand& src2);

  void mov(Register dst, const Operand& src);
888 889
  void bitwise_mov(Register dst, intptr_t value);
  void bitwise_mov32(Register dst, int32_t value);
890
  void bitwise_add32(Register dst, Register src, int32_t value);
891 892 893 894 895

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

896 897 898 899
  // dst = base + label position + delta
  void add_label_offset(Register dst, Register base, Label* label,
                        int delta = 0);

900 901 902 903 904 905 906 907
  // Load the address of the label in a register and associate with an
  // internal reference relocation.
  void mov_label_addr(Register dst, Label* label);

  // Emit the address of the label (i.e. a jump table entry) and associate with
  // an internal reference relocation.
  void emit_label_addr(Label* label);

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
  // Multiply instructions
  void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
           RCBit r = LeaveRC);

  // Miscellaneous arithmetic instructions

  // Special register access
  void crxor(int bt, int ba, int bb);
  void crclr(int bt) { crxor(bt, bt, bt); }
  void creqv(int bt, int ba, int bb);
  void crset(int bt) { creqv(bt, bt, bt); }
  void mflr(Register dst);
  void mtlr(Register src);
  void mtctr(Register src);
  void mtxer(Register src);
923
  void mcrfs(CRegister cr, FPSCRBit bit);
924
  void mfcr(Register dst);
925
  void mtcrf(Register src, uint8_t FXM);
926 927 928 929 930 931 932 933 934
#if V8_TARGET_ARCH_PPC64
  void mffprd(Register dst, DoubleRegister src);
  void mffprwz(Register dst, DoubleRegister src);
  void mtfprd(DoubleRegister dst, Register src);
  void mtfprwz(DoubleRegister dst, Register src);
  void mtfprwa(DoubleRegister dst, Register src);
#endif

  // Exception-generating instructions and debugging support
935 936
  void stop(Condition cond = al, int32_t code = kDefaultStopCode,
            CRegister cr = cr7);
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969

  void bkpt(uint32_t imm16);  // v5 and above

  void dcbf(Register ra, Register rb);
  void sync();
  void lwsync();
  void icbi(Register ra, Register rb);
  void isync();

  // Support for floating point
  void lfd(const DoubleRegister frt, const MemOperand& src);
  void lfdu(const DoubleRegister frt, const MemOperand& src);
  void lfs(const DoubleRegister frt, const MemOperand& src);
  void lfsu(const DoubleRegister frt, const MemOperand& src);
  void stfd(const DoubleRegister frs, const MemOperand& src);
  void stfdu(const DoubleRegister frs, const MemOperand& src);
  void stfs(const DoubleRegister frs, const MemOperand& src);
  void stfsu(const DoubleRegister frs, const MemOperand& src);

  void fadd(const DoubleRegister frt, const DoubleRegister fra,
            const DoubleRegister frb, RCBit rc = LeaveRC);
  void fsub(const DoubleRegister frt, const DoubleRegister fra,
            const DoubleRegister frb, RCBit rc = LeaveRC);
  void fdiv(const DoubleRegister frt, const DoubleRegister fra,
            const DoubleRegister frb, RCBit rc = LeaveRC);
  void fmul(const DoubleRegister frt, const DoubleRegister fra,
            const DoubleRegister frc, RCBit rc = LeaveRC);
  void fcmpu(const DoubleRegister fra, const DoubleRegister frb,
             CRegister cr = cr7);
  void fmr(const DoubleRegister frt, const DoubleRegister frb,
           RCBit rc = LeaveRC);
  void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
  void fctiw(const DoubleRegister frt, const DoubleRegister frb);
970
  void fctiwuz(const DoubleRegister frt, const DoubleRegister frb);
971 972 973 974 975 976 977 978
  void frin(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void friz(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void frip(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void frim(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
979 980 981 982
  void frsp(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void fcfid(const DoubleRegister frt, const DoubleRegister frb,
             RCBit rc = LeaveRC);
983 984
  void fcfidu(const DoubleRegister frt, const DoubleRegister frb,
              RCBit rc = LeaveRC);
985 986
  void fcfidus(const DoubleRegister frt, const DoubleRegister frb,
               RCBit rc = LeaveRC);
987 988
  void fcfids(const DoubleRegister frt, const DoubleRegister frb,
              RCBit rc = LeaveRC);
989 990 991 992
  void fctid(const DoubleRegister frt, const DoubleRegister frb,
             RCBit rc = LeaveRC);
  void fctidz(const DoubleRegister frt, const DoubleRegister frb,
              RCBit rc = LeaveRC);
993 994 995 996
  void fctidu(const DoubleRegister frt, const DoubleRegister frb,
              RCBit rc = LeaveRC);
  void fctiduz(const DoubleRegister frt, const DoubleRegister frb,
               RCBit rc = LeaveRC);
997 998 999 1000 1001
  void fsel(const DoubleRegister frt, const DoubleRegister fra,
            const DoubleRegister frc, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void fneg(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
1002 1003
  void mtfsb0(FPSCRBit bit, RCBit rc = LeaveRC);
  void mtfsb1(FPSCRBit bit, RCBit rc = LeaveRC);
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
  void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC);
  void mffs(const DoubleRegister frt, RCBit rc = LeaveRC);
  void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0,
             RCBit rc = LeaveRC);
  void fsqrt(const DoubleRegister frt, const DoubleRegister frb,
             RCBit rc = LeaveRC);
  void fabs(const DoubleRegister frt, const DoubleRegister frb,
            RCBit rc = LeaveRC);
  void fmadd(const DoubleRegister frt, const DoubleRegister fra,
             const DoubleRegister frc, const DoubleRegister frb,
             RCBit rc = LeaveRC);
  void fmsub(const DoubleRegister frt, const DoubleRegister fra,
             const DoubleRegister frc, const DoubleRegister frb,
             RCBit rc = LeaveRC);

1019
  // Vector instructions
1020 1021
  void mfvsrd(const Register ra, const Simd128Register r);
  void mfvsrwz(const Register ra, const Simd128Register r);
1022
  void mtvsrd(const Simd128Register rt, const Register ra);
1023
  void mtvsrdd(const Simd128Register rt, const Register ra, const Register rb);
1024
  void lxvd(const Simd128Register rt, const MemOperand& src);
1025 1026 1027 1028
  void lxsdx(const Simd128Register rt, const MemOperand& src);
  void lxsibzx(const Simd128Register rt, const MemOperand& src);
  void lxsihzx(const Simd128Register rt, const MemOperand& src);
  void lxsiwzx(const Simd128Register rt, const MemOperand& src);
1029 1030 1031 1032
  void stxsdx(const Simd128Register rs, const MemOperand& src);
  void stxsibx(const Simd128Register rs, const MemOperand& src);
  void stxsihx(const Simd128Register rs, const MemOperand& src);
  void stxsiwx(const Simd128Register rs, const MemOperand& src);
1033
  void stxvd(const Simd128Register rt, const MemOperand& src);
1034
  void xxspltib(const Simd128Register rt, const Operand& imm);
1035
  void xxbrq(const Simd128Register rt, const Simd128Register rb);
1036

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
  // Pseudo instructions

  // Different nop operations are used by the code generator to detect certain
  // states of the generated code.
  enum NopMarkerTypes {
    NON_MARKING_NOP = 0,
    GROUP_ENDING_NOP,
    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.

  void push(Register src) {
#if V8_TARGET_ARCH_PPC64
1058
    stdu(src, MemOperand(sp, -kSystemPointerSize));
1059
#else
1060
    stwu(src, MemOperand(sp, -kSystemPointerSize));
1061 1062 1063 1064 1065 1066 1067 1068 1069
#endif
  }

  void pop(Register dst) {
#if V8_TARGET_ARCH_PPC64
    ld(dst, MemOperand(sp));
#else
    lwz(dst, MemOperand(sp));
#endif
1070
    addi(sp, sp, Operand(kSystemPointerSize));
1071 1072
  }

1073
  void pop() { addi(sp, sp, Operand(kSystemPointerSize)); }
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

  // Jump unconditionally to given label.
  void jmp(Label* L) { b(L); }

  // Check the code size generated from label to here.
  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;
  }

  // Class for scoping postponing the trampoline pool generation.
1089
  class V8_NODISCARD BlockTrampolinePoolScope {
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
   public:
    explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
      assem_->StartBlockTrampolinePool();
    }
    ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }

   private:
    Assembler* assem_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
  };

1102
  // Class for scoping disabling constant pool entry merging
1103
  class V8_NODISCARD BlockConstantPoolEntrySharingScope {
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
   public:
    explicit BlockConstantPoolEntrySharingScope(Assembler* assem)
        : assem_(assem) {
      assem_->StartBlockConstantPoolEntrySharing();
    }
    ~BlockConstantPoolEntrySharingScope() {
      assem_->EndBlockConstantPoolEntrySharing();
    }

   private:
    Assembler* assem_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstantPoolEntrySharingScope);
  };

1119 1120
  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
1121 1122
  void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position,
                         int id);
1123

1124 1125 1126
  // 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);
1127 1128 1129
  void dd(uint32_t data, RelocInfo::Mode rmode = RelocInfo::NONE);
  void dq(uint64_t data, RelocInfo::Mode rmode = RelocInfo::NONE);
  void dp(uintptr_t data, RelocInfo::Mode rmode = RelocInfo::NONE);
1130 1131

  // Read/patch instructions
1132 1133 1134
  Instr instr_at(int pos) {
    return *reinterpret_cast<Instr*>(buffer_start_ + pos);
  }
1135
  void instr_at_put(int pos, Instr instr) {
1136
    *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
1137
  }
1138 1139
  static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); }
  static void instr_at_put(Address pc, Instr instr) {
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
    *reinterpret_cast<Instr*>(pc) = instr;
  }
  static Condition GetCondition(Instr instr);

  static bool IsLis(Instr instr);
  static bool IsLi(Instr instr);
  static bool IsAddic(Instr instr);
  static bool IsOri(Instr instr);

  static bool IsBranch(Instr instr);
  static Register GetRA(Instr instr);
  static Register GetRB(Instr instr);
#if V8_TARGET_ARCH_PPC64
  static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
                                 Instr instr4, Instr instr5);
#else
  static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2);
#endif

  static bool IsCmpRegister(Instr instr);
  static bool IsCmpImmediate(Instr instr);
  static bool IsRlwinm(Instr instr);
1162
  static bool IsAndi(Instr instr);
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
#if V8_TARGET_ARCH_PPC64
  static bool IsRldicl(Instr instr);
#endif
  static bool IsCrSet(Instr instr);
  static Register GetCmpImmediateRegister(Instr instr);
  static int GetCmpImmediateRawImmediate(Instr instr);
  static bool IsNop(Instr instr, int type = NON_MARKING_NOP);

  // Postpone the generation of the trampoline pool for the specified number of
  // instructions.
  void BlockTrampolinePoolFor(int instructions);
  void CheckTrampolinePool();

1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
  // For mov.  Return the number of actual instructions required to
  // load the operand into a register.  This can be anywhere from
  // one (constant pool small section) to five instructions (full
  // 64-bit sequence).
  //
  // 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.
  int instructions_required_for_mov(Register dst, const Operand& src) const;

  // Decide between using the constant pool vs. a mov immediate sequence.
  bool use_constant_pool_for_mov(Register dst, const Operand& src,
                                 bool canOptimize) const;

1189 1190 1191 1192 1193 1194 1195
  // The code currently calls CheckBuffer() too often. This has the side
  // effect of randomly growing the buffer in the middle of multi-instruction
  // sequences.
  //
  // This function allows outside callers to check and grow the buffer
  void EnsureSpaceFor(int space_needed);

1196
  int EmitConstantPool() { return constant_pool_builder_.Emit(this); }
1197

1198 1199 1200 1201 1202 1203 1204 1205
  bool ConstantPoolAccessIsInOverflow() const {
    return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) ==
           ConstantPoolEntry::OVERFLOWED;
  }

  Label* ConstantPoolPosition() {
    return constant_pool_builder_.EmittedPosition();
  }
1206

1207
  void EmitRelocations();
1208 1209 1210 1211

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

1212 1213
  // Decode instruction(s) at pos and return backchain to previous
  // label reference or kEndOfChain.
1214 1215
  int target_at(int pos);

1216 1217
  // Patch instruction(s) at pos to target target_pos (e.g. branch)
  void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
1218 1219 1220

  // Record reloc info for current pc_
  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1221 1222
  ConstantPoolEntry::Access ConstantPoolAddEntry(RelocInfo::Mode rmode,
                                                 intptr_t value) {
1223 1224 1225 1226 1227 1228 1229
    bool sharing_ok =
        RelocInfo::IsNone(rmode) ||
        (!options().record_reloc_info_for_serialization &&
         RelocInfo::IsShareableRelocMode(rmode) &&
         !is_constant_pool_entry_sharing_blocked() &&
         // TODO(johnyan): make the following rmode shareable
         !RelocInfo::IsWasmCall(rmode) && !RelocInfo::IsWasmStubCall(rmode));
1230 1231
    return constant_pool_builder_.AddEntry(pc_offset(), value, sharing_ok);
  }
1232
  ConstantPoolEntry::Access ConstantPoolAddEntry(Double value) {
1233 1234
    return constant_pool_builder_.AddEntry(pc_offset(), value);
  }
1235 1236 1237 1238 1239 1240 1241 1242

  // Block the emission of the trampoline pool before pc_offset.
  void BlockTrampolinePoolBefore(int pc_offset) {
    if (no_trampoline_pool_before_ < pc_offset)
      no_trampoline_pool_before_ = pc_offset;
  }

  void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
1243 1244 1245 1246
  void EndBlockTrampolinePool() {
    int count = --trampoline_pool_blocked_nesting_;
    if (count == 0) CheckTrampolinePoolQuick();
  }
1247 1248 1249 1250
  bool is_trampoline_pool_blocked() const {
    return trampoline_pool_blocked_nesting_ > 0;
  }

1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
  void StartBlockConstantPoolEntrySharing() {
    constant_pool_entry_sharing_blocked_nesting_++;
  }
  void EndBlockConstantPoolEntrySharing() {
    constant_pool_entry_sharing_blocked_nesting_--;
  }
  bool is_constant_pool_entry_sharing_blocked() const {
    return constant_pool_entry_sharing_blocked_nesting_ > 0;
  }

1261 1262 1263 1264 1265 1266 1267 1268 1269
  bool has_exception() const { return internal_trampoline_exception_; }

  bool is_trampoline_emitted() const { return trampoline_emitted_; }

  // 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.
1270
  static constexpr int kGap = 32;
1271
  STATIC_ASSERT(AssemblerBase::kMinimalBufferSize >= 2 * kGap);
1272

1273 1274 1275
  RelocInfoWriter reloc_info_writer;

 private:
1276 1277 1278
  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512 * MB;

1279 1280 1281
  // Repeated checking whether the trampoline pool should be emitted is rather
  // expensive. By default we only check again once a number of instructions
  // has been generated.
1282
  int next_trampoline_check_;  // pc offset of next buffer check.
1283 1284 1285 1286 1287

  // Emission of the trampoline pool may be blocked in some code sequences.
  int trampoline_pool_blocked_nesting_;  // Block emission if this is not zero.
  int no_trampoline_pool_before_;  // Block emission before this pc offset.

1288 1289 1290
  // Do not share constant pool entries.
  int constant_pool_entry_sharing_blocked_nesting_;

1291 1292
  // Relocation info generation
  // Each relocation is encoded as a variable size value
1293
  static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1294
  std::vector<DeferredRelocInfo> relocations_;
1295

1296 1297 1298
  // Scratch registers available for use by the Assembler.
  RegList scratch_register_list_;

1299 1300
  // The bound position, before this we cannot do instruction elimination.
  int last_bound_pos_;
1301 1302
  // Optimizable cmpi information.
  int optimizable_cmpi_pos_;
1303
  CRegister cmpi_cr_ = CRegister::no_reg();
1304

1305 1306
  ConstantPoolBuilder constant_pool_builder_;

1307 1308 1309 1310 1311 1312
  void CheckBuffer() {
    if (buffer_space() <= kGap) {
      GrowBuffer();
    }
  }

1313
  void GrowBuffer(int needed = 0);
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
  // Code emission
  void emit(Instr x) {
    CheckBuffer();
    *reinterpret_cast<Instr*>(pc_) = x;
    pc_ += kInstrSize;
    CheckTrampolinePoolQuick();
  }
  void TrackBranch() {
    DCHECK(!trampoline_emitted_);
    int count = tracked_branch_count_++;
    if (count == 0) {
      // We leave space (kMaxBlockTrampolineSectionSize)
      // for BlockTrampolinePoolScope buffer.
      next_trampoline_check_ =
          pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize;
    } else {
      next_trampoline_check_ -= kTrampolineSlotsSize;
    }
  }

1334
  inline void UntrackBranch();
1335 1336 1337 1338 1339
  void CheckTrampolinePoolQuick() {
    if (pc_offset() >= next_trampoline_check_) {
      CheckTrampolinePool();
    }
  }
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390

  // Instruction generation
  void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
              DoubleRegister frb, RCBit r);
  void d_form(Instr instr, Register rt, Register ra, const intptr_t val,
              bool signed_disp);
  void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o,
               RCBit r);
  void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit,
               RCBit r);
  void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit,
                RCBit r);

  // Labels
  void print(Label* L);
  int max_reach_from(int pos);
  void bind_to(Label* L, int pos);
  void next(Label* L);

  class Trampoline {
   public:
    Trampoline() {
      next_slot_ = 0;
      free_slot_count_ = 0;
    }
    Trampoline(int start, int slot_count) {
      next_slot_ = start;
      free_slot_count_ = slot_count;
    }
    int take_slot() {
      int trampoline_slot = kInvalidSlotPos;
      if (free_slot_count_ <= 0) {
        // We have run out of space on trampolines.
        // Make sure we fail in debug mode, so we become aware of each case
        // when this happens.
        DCHECK(0);
        // Internal exception will be caught.
      } else {
        trampoline_slot = next_slot_;
        free_slot_count_--;
        next_slot_ += kTrampolineSlotsSize;
      }
      return trampoline_slot;
    }

   private:
    int next_slot_;
    int free_slot_count_;
  };

  int32_t get_trampoline_entry();
1391
  int tracked_branch_count_;
1392 1393 1394 1395 1396 1397
  // If trampoline is emitted, generated code is becoming large. As
  // this is already a slow case which can possibly break our code
  // generation for the extreme case, we use this information to
  // trigger different mode of branch instruction generation, where we
  // no longer use a single branch instruction.
  bool trampoline_emitted_;
1398 1399 1400 1401
  static constexpr int kTrampolineSlotsSize = kInstrSize;
  static constexpr int kMaxCondBranchReach = (1 << (16 - 1)) - 1;
  static constexpr int kMaxBlockTrampolineSectionSize = 64 * kInstrSize;
  static constexpr int kInvalidSlotPos = -1;
1402 1403 1404 1405

  Trampoline trampoline_;
  bool internal_trampoline_exception_;

1406 1407
  void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);

1408 1409
  int WriteCodeComments();

1410 1411 1412 1413
  friend class RegExpMacroAssemblerPPC;
  friend class RelocInfo;
  friend class BlockTrampolinePoolScope;
  friend class EnsureSpace;
1414
  friend class UseScratchRegisterScope;
1415 1416
};

1417
class EnsureSpace {
1418 1419 1420
 public:
  explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
};
1421 1422 1423

class PatchingAssembler : public Assembler {
 public:
1424 1425
  PatchingAssembler(const AssemblerOptions& options, byte* address,
                    int instructions);
1426 1427 1428
  ~PatchingAssembler();
};

1429
class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope {
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
 public:
  explicit UseScratchRegisterScope(Assembler* assembler);
  ~UseScratchRegisterScope();

  Register Acquire();

  // Check if we have registers available to acquire.
  bool CanAcquire() const { return *assembler_->GetScratchRegisterList() != 0; }

 private:
  friend class Assembler;
  friend class TurboAssembler;

  Assembler* assembler_;
  RegList old_available_;
};

1447 1448
}  // namespace internal
}  // namespace v8
1449

1450
#endif  // V8_CODEGEN_PPC_ASSEMBLER_PPC_H_