assembler-mips.h 82.8 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
// 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.
33
// Copyright 2012 the V8 project authors. All rights reserved.
34

35 36
#ifndef V8_CODEGEN_MIPS_ASSEMBLER_MIPS_H_
#define V8_CODEGEN_MIPS_ASSEMBLER_MIPS_H_
37 38

#include <stdio.h>
39

40 41
#include <set>

42
#include "src/codegen/assembler.h"
43
#include "src/codegen/external-reference.h"
44
#include "src/codegen/label.h"
45 46
#include "src/codegen/mips/constants-mips.h"
#include "src/codegen/mips/register-mips.h"
47
#include "src/objects/smi.h"
48 49 50 51

namespace v8 {
namespace internal {

Yu Yin's avatar
Yu Yin committed
52 53
class SafepointTableBuilder;

54 55 56
// Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls.
enum BranchDelaySlot { USE_DELAY_SLOT, PROTECT };

57 58 59 60
// -----------------------------------------------------------------------------
// Machine instruction Operands.

// Class Operand represents a shifter operand in data processing instructions.
61
class Operand {
62 63
 public:
  // Immediate.
64 65
  V8_INLINE explicit Operand(int32_t immediate,
                             RelocInfo::Mode rmode = RelocInfo::NONE)
66 67 68
      : rm_(no_reg), rmode_(rmode) {
    value_.immediate = immediate;
  }
69
  V8_INLINE explicit Operand(const ExternalReference& f)
70
      : rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) {
71
    value_.immediate = static_cast<int32_t>(f.address());
72
  }
73
  V8_INLINE explicit Operand(const char* s);
74
  explicit Operand(Handle<HeapObject> handle);
75 76
  V8_INLINE explicit Operand(Smi value) : rm_(no_reg), rmode_(RelocInfo::NONE) {
    value_.immediate = static_cast<intptr_t>(value.ptr());
77
  }
78

79
  static Operand EmbeddedNumber(double number);  // Smi or HeapNumber.
80
  static Operand EmbeddedStringConstant(const StringConstantBase* str);
81

82
  // Register.
83
  V8_INLINE explicit Operand(Register rm) : rm_(rm) {}
84 85

  // Return true if this is a register operand.
86
  V8_INLINE bool is_reg() const;
87

88
  inline int32_t immediate() const;
89 90 91 92 93 94 95 96 97 98 99

  bool IsImmediate() const { return !rm_.is_valid(); }

  HeapObjectRequest heap_object_request() const {
    DCHECK(IsHeapObjectRequest());
    return value_.heap_object_request;
  }

  bool IsHeapObjectRequest() const {
    DCHECK_IMPLIES(is_heap_object_request_, IsImmediate());
    DCHECK_IMPLIES(is_heap_object_request_,
100
                   rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
101 102
                       rmode_ == RelocInfo::CODE_TARGET);
    return is_heap_object_request_;
103 104
  }

105 106
  Register rm() const { return rm_; }

107 108
  RelocInfo::Mode rmode() const { return rmode_; }

109 110
 private:
  Register rm_;
111 112 113 114 115 116
  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;
117 118 119
  RelocInfo::Mode rmode_;

  friend class Assembler;
120
  // friend class MacroAssembler;
121 122
};

123
// On MIPS we have only one addressing mode with base_reg + offset.
124 125 126
// Class MemOperand represents a memory operand in load and store instructions.
class MemOperand : public Operand {
 public:
plind44@gmail.com's avatar
plind44@gmail.com committed
127
  // Immediate value attached to offset.
128
  enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 };
plind44@gmail.com's avatar
plind44@gmail.com committed
129

130
  explicit MemOperand(Register rn, int32_t offset = 0);
plind44@gmail.com's avatar
plind44@gmail.com committed
131 132
  explicit MemOperand(Register rn, int32_t unit, int32_t multiplier,
                      OffsetAddend offset_addend = offset_zero);
133
  int32_t offset() const { return offset_; }
134

135
  bool OffsetIsInt16Encodable() const { return is_int16(offset_); }
136

137
 private:
138
  int32_t offset_;
139 140 141 142

  friend class Assembler;
};

143
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
144 145 146 147 148 149
 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).
  //
150
  // If the provided buffer is nullptr, the assembler allocates and grows its
151 152 153 154
  // own buffer. Otherwise it takes ownership of the provided buffer.
  explicit Assembler(const AssemblerOptions&,
                     std::unique_ptr<AssemblerBuffer> = {});

155
  virtual ~Assembler() {}
156

Yu Yin's avatar
Yu Yin committed
157 158 159 160 161 162 163 164 165 166 167
  // 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);
  }
168

169 170 171
  // Unused on this architecture.
  void MaybeEmitOutOfLineConstantPool() {}

172 173 174 175 176 177 178 179 180 181 182 183 184 185
  // 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.
186
  void bind(Label* L);  // Binds an unbound label L to current code position.
187 188 189

  enum OffsetSize : int { kOffset26 = 26, kOffset21 = 21, kOffset16 = 16 };

190 191 192
  // Determines if Label is bound and near enough so that branch instruction
  // can be used to reach it, instead of jump instruction.
  bool is_near(Label* L);
193 194
  bool is_near(Label* L, OffsetSize bits);
  bool is_near_branch(Label* L);
195 196 197 198 199 200 201 202 203 204
  inline bool is_near_pre_r6(Label* L) {
    DCHECK(!IsMipsArchVariant(kMips32r6));
    return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
  }
  inline bool is_near_r6(Label* L) {
    DCHECK(IsMipsArchVariant(kMips32r6));
    return pc_offset() - L->pos() < kMaxCompactBranchOffset - 4 * kInstrSize;
  }

  int BranchOffset(Instr instr);
205

206 207
  // 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.
208
  // Manages the jump elimination optimization if the second parameter is true.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
  int32_t branch_offset_helper(Label* L, OffsetSize bits);
  inline int32_t branch_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset16);
  }
  inline int32_t branch_offset21(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset21);
  }
  inline int32_t branch_offset26(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset26);
  }
  inline int32_t shifted_branch_offset(Label* L) {
    return branch_offset(L) >> 2;
  }
  inline int32_t shifted_branch_offset21(Label* L) {
    return branch_offset21(L) >> 2;
  }
  inline int32_t shifted_branch_offset26(Label* L) {
    return branch_offset26(L) >> 2;
227
  }
228
  uint32_t jump_address(Label* L);
229
  uint32_t branch_long_offset(Label* L);
230 231 232 233 234 235

  // Puts a labels target address at the given position.
  // The high 8 bits are set to zero.
  void label_at_put(Label* L, int at_offset);

  // Read/Modify the code target address in the branch/call instruction at pc.
236
  // The isolate argument is unused (and may be nullptr) when skipping flushing.
237
  static Address target_address_at(Address pc);
238 239 240
  V8_INLINE static void set_target_address_at(
      Address pc, Address target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) {
241
    set_target_value_at(pc, static_cast<uint32_t>(target), icache_flush_mode);
242
  }
243
  // On MIPS there is no Constant Pool so we skip that parameter.
244 245
  V8_INLINE static Address target_address_at(Address pc,
                                             Address constant_pool) {
246 247
    return target_address_at(pc);
  }
248
  V8_INLINE static void set_target_address_at(
249
      Address pc, Address constant_pool, Address target,
250
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) {
251
    set_target_address_at(pc, target, icache_flush_mode);
252
  }
253

254
  static void set_target_value_at(
255
      Address pc, uint32_t target,
256 257
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);

258
  // This sets the branch destination (which gets loaded at the call address).
259 260 261
  // This is for calls and branches within generated code.  The serializer
  // has already deserialized the lui/ori instructions etc.
  inline static void deserialization_set_special_target_at(
262
      Address instruction_payload, Code code, Address target);
263

264 265 266 267
  // Get the size of the special target encoded at 'instruction_payload'.
  inline static int deserialization_special_target_size(
      Address instruction_payload);

268 269
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
270
      Address pc, Address target,
271
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
272

273
  // Difference between address of current opcode and target address offset.
274
  static constexpr int kBranchPCOffset = kInstrSize;
275

276 277
  // Difference between address of current opcode and target address offset,
  // when we are generatinga sequence of instructions for long relative PC
278 279
  // branches. It is distance between address of the first instruction in
  // the jump sequence, and the value that ra gets after calling nal().
280
  static constexpr int kLongBranchPCOffset = 3 * kInstrSize;
281

282
  // Adjust ra register in branch delay slot of bal instruction in order to skip
283 284
  // instructions not needed after optimization of PIC in
  // TurboAssembler::BranchAndLink method.
285
  static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 3 * kInstrSize;
286

287 288 289 290 291 292 293
  // Offset of target relative address in calls/jumps for builtins. It is
  // distance between instruction that is placed just after calling
  // RecordRelocInfo, and the value that ra gets aftr calling nal().
  static constexpr int kRelativeJumpForBuiltinsOffset = 1 * kInstrSize;
  // Relative target address of jumps for builtins when we use lui, ori, dsll,
  // ori sequence when loading address that cannot fit into 32 bits.
  static constexpr int kRelativeCallForBuiltinsOffset = 3 * kInstrSize;
294

295 296 297 298 299 300
  // 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
  // MIPS 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.
301

302
  static constexpr int kSpecialTargetSize = 0;
303

304 305 306 307
  // Number of consecutive instructions used to store 32bit constant. This
  // constant is used in RelocInfo::target_address_address() function to tell
  // serializer address of the instruction that follows LUI/ORI instruction
  // pair.
308
  static constexpr int kInstructionsFor32BitConstant = 2;
309

310
  // Max offset for instructions with 16-bit offset field
311
  static constexpr int kMaxBranchOffset = (1 << (18 - 1)) - 1;
312 313

  // Max offset for compact branch instructions with 26-bit offset field
314
  static constexpr int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
315

316
  static constexpr int kTrampolineSlotsSize =
317
      IsMipsArchVariant(kMips32r6) ? 2 * kInstrSize : 7 * kInstrSize;
318

319 320
  RegList* GetScratchRegisterList() { return &scratch_register_list_; }

321 322 323
  // ---------------------------------------------------------------------------
  // Code generation.

324 325 326 327
  // 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);
328 329 330
  // 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);
331 332 333 334 335 336 337 338 339 340 341 342 343 344
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();

  // 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,
345
    FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED,
346 347
  };

348 349 350
  // Type == 0 is the default non-marking nop. For mips this is a
  // sll(zero_reg, zero_reg, 0). We use rt_reg == at for non-zero
  // marking, to avoid conflict with ssnop and ehb instructions.
351
  void nop(unsigned int type = 0) {
352
    DCHECK_LT(type, 32);
353 354
    Register nop_rt_reg = (type == 0) ? zero_reg : at;
    sll(zero_reg, nop_rt_reg, type, true);
355
  }
356

357
  // --------Branch-and-jump-instructions----------
358 359
  // We don't use likely variant of instructions.
  void b(int16_t offset);
360
  inline void b(Label* L) { b(shifted_branch_offset(L)); }
361
  void bal(int16_t offset);
362
  inline void bal(Label* L) { bal(shifted_branch_offset(L)); }
363
  void bc(int32_t offset);
364
  inline void bc(Label* L) { bc(shifted_branch_offset26(L)); }
365
  void balc(int32_t offset);
366
  inline void balc(Label* L) { balc(shifted_branch_offset26(L)); }
367 368

  void beq(Register rs, Register rt, int16_t offset);
369 370
  inline void beq(Register rs, Register rt, Label* L) {
    beq(rs, rt, shifted_branch_offset(L));
371 372
  }
  void bgez(Register rs, int16_t offset);
373
  void bgezc(Register rt, int16_t offset);
374 375
  inline void bgezc(Register rt, Label* L) {
    bgezc(rt, shifted_branch_offset(L));
376 377
  }
  void bgeuc(Register rs, Register rt, int16_t offset);
378 379
  inline void bgeuc(Register rs, Register rt, Label* L) {
    bgeuc(rs, rt, shifted_branch_offset(L));
380 381
  }
  void bgec(Register rs, Register rt, int16_t offset);
382 383
  inline void bgec(Register rs, Register rt, Label* L) {
    bgec(rs, rt, shifted_branch_offset(L));
384
  }
385
  void bgezal(Register rs, int16_t offset);
386
  void bgezalc(Register rt, int16_t offset);
387 388
  inline void bgezalc(Register rt, Label* L) {
    bgezalc(rt, shifted_branch_offset(L));
389 390
  }
  void bgezall(Register rs, int16_t offset);
391 392
  inline void bgezall(Register rs, Label* L) {
    bgezall(rs, branch_offset(L) >> 2);
393
  }
394
  void bgtz(Register rs, int16_t offset);
395
  void bgtzc(Register rt, int16_t offset);
396 397
  inline void bgtzc(Register rt, Label* L) {
    bgtzc(rt, shifted_branch_offset(L));
398
  }
399
  void blez(Register rs, int16_t offset);
400
  void blezc(Register rt, int16_t offset);
401 402
  inline void blezc(Register rt, Label* L) {
    blezc(rt, shifted_branch_offset(L));
403
  }
404
  void bltz(Register rs, int16_t offset);
405
  void bltzc(Register rt, int16_t offset);
406 407
  inline void bltzc(Register rt, Label* L) {
    bltzc(rt, shifted_branch_offset(L));
408 409
  }
  void bltuc(Register rs, Register rt, int16_t offset);
410 411
  inline void bltuc(Register rs, Register rt, Label* L) {
    bltuc(rs, rt, shifted_branch_offset(L));
412 413
  }
  void bltc(Register rs, Register rt, int16_t offset);
414 415
  inline void bltc(Register rs, Register rt, Label* L) {
    bltc(rs, rt, shifted_branch_offset(L));
416
  }
417
  void bltzal(Register rs, int16_t offset);
418
  void nal() { bltzal(zero_reg, 0); }
419
  void blezalc(Register rt, int16_t offset);
420 421
  inline void blezalc(Register rt, Label* L) {
    blezalc(rt, shifted_branch_offset(L));
422 423
  }
  void bltzalc(Register rt, int16_t offset);
424 425
  inline void bltzalc(Register rt, Label* L) {
    bltzalc(rt, shifted_branch_offset(L));
426 427
  }
  void bgtzalc(Register rt, int16_t offset);
428 429
  inline void bgtzalc(Register rt, Label* L) {
    bgtzalc(rt, shifted_branch_offset(L));
430 431
  }
  void beqzalc(Register rt, int16_t offset);
432 433
  inline void beqzalc(Register rt, Label* L) {
    beqzalc(rt, shifted_branch_offset(L));
434 435
  }
  void beqc(Register rs, Register rt, int16_t offset);
436 437
  inline void beqc(Register rs, Register rt, Label* L) {
    beqc(rs, rt, shifted_branch_offset(L));
438 439
  }
  void beqzc(Register rs, int32_t offset);
440 441
  inline void beqzc(Register rs, Label* L) {
    beqzc(rs, shifted_branch_offset21(L));
442 443
  }
  void bnezalc(Register rt, int16_t offset);
444 445
  inline void bnezalc(Register rt, Label* L) {
    bnezalc(rt, shifted_branch_offset(L));
446 447
  }
  void bnec(Register rs, Register rt, int16_t offset);
448 449
  inline void bnec(Register rs, Register rt, Label* L) {
    bnec(rs, rt, shifted_branch_offset(L));
450 451
  }
  void bnezc(Register rt, int32_t offset);
452 453
  inline void bnezc(Register rt, Label* L) {
    bnezc(rt, shifted_branch_offset21(L));
454
  }
455
  void bne(Register rs, Register rt, int16_t offset);
456 457
  inline void bne(Register rs, Register rt, Label* L) {
    bne(rs, rt, shifted_branch_offset(L));
458
  }
459
  void bovc(Register rs, Register rt, int16_t offset);
460 461
  inline void bovc(Register rs, Register rt, Label* L) {
    bovc(rs, rt, shifted_branch_offset(L));
462 463
  }
  void bnvc(Register rs, Register rt, int16_t offset);
464 465
  inline void bnvc(Register rs, Register rt, Label* L) {
    bnvc(rs, rt, shifted_branch_offset(L));
466
  }
467 468

  // Never use the int16_t b(l)cond version with a branch offset
469
  // instead of using the Label* version.
470

471
  // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits.
472 473 474 475
  void j(int32_t target);
  void jal(int32_t target);
  void jalr(Register rs, Register rd = ra);
  void jr(Register target);
476 477
  void jic(Register rt, int16_t offset);
  void jialc(Register rt, int16_t offset);
478

479
  // -------Data-processing-instructions---------
480 481 482 483 484 485 486 487

  // Arithmetic.
  void addu(Register rd, Register rs, Register rt);
  void subu(Register rd, Register rs, Register rt);
  void mult(Register rs, Register rt);
  void multu(Register rs, Register rt);
  void div(Register rs, Register rt);
  void divu(Register rs, Register rt);
488 489 490 491
  void div(Register rd, Register rs, Register rt);
  void divu(Register rd, Register rs, Register rt);
  void mod(Register rd, Register rs, Register rt);
  void modu(Register rd, Register rs, Register rt);
492
  void mul(Register rd, Register rs, Register rt);
493 494 495
  void muh(Register rd, Register rs, Register rt);
  void mulu(Register rd, Register rs, Register rt);
  void muhu(Register rd, Register rs, Register rt);
496 497 498 499 500 501 502 503 504 505 506 507 508

  void addiu(Register rd, Register rs, int32_t j);

  // Logical.
  void and_(Register rd, Register rs, Register rt);
  void or_(Register rd, Register rs, Register rt);
  void xor_(Register rd, Register rs, Register rt);
  void nor(Register rd, Register rs, Register rt);

  void andi(Register rd, Register rs, int32_t j);
  void ori(Register rd, Register rs, int32_t j);
  void xori(Register rd, Register rs, int32_t j);
  void lui(Register rd, int32_t j);
509
  void aui(Register rs, Register rt, int32_t j);
510 511

  // Shifts.
512 513 514 515
  // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop
  // and may cause problems in normal code. coming_from_nop makes sure this
  // doesn't happen.
  void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false);
516 517 518 519 520
  void sllv(Register rd, Register rt, Register rs);
  void srl(Register rd, Register rt, uint16_t sa);
  void srlv(Register rd, Register rt, Register rs);
  void sra(Register rt, Register rd, uint16_t sa);
  void srav(Register rt, Register rd, Register rs);
521 522
  void rotr(Register rd, Register rt, uint16_t sa);
  void rotrv(Register rd, Register rt, Register rs);
523

524
  // ------------Memory-instructions-------------
525 526 527

  void lb(Register rd, const MemOperand& rs);
  void lbu(Register rd, const MemOperand& rs);
528 529
  void lh(Register rd, const MemOperand& rs);
  void lhu(Register rd, const MemOperand& rs);
530
  void lw(Register rd, const MemOperand& rs);
531 532
  void lwl(Register rd, const MemOperand& rs);
  void lwr(Register rd, const MemOperand& rs);
533
  void sb(Register rd, const MemOperand& rs);
534
  void sh(Register rd, const MemOperand& rs);
535
  void sw(Register rd, const MemOperand& rs);
536 537
  void swl(Register rd, const MemOperand& rs);
  void swr(Register rd, const MemOperand& rs);
538

539 540 541 542
  // ----------Atomic instructions--------------

  void ll(Register rd, const MemOperand& rs);
  void sc(Register rd, const MemOperand& rs);
543 544
  void llx(Register rd, const MemOperand& rs);
  void scx(Register rd, const MemOperand& rs);
545

546 547 548 549 550 551 552
  // ---------PC-Relative-instructions-----------

  void addiupc(Register rs, int32_t imm19);
  void lwpc(Register rs, int32_t offset19);
  void auipc(Register rs, int16_t imm16);
  void aluipc(Register rs, int16_t imm16);

553
  // ----------------Prefetch--------------------
plind44@gmail.com's avatar
plind44@gmail.com committed
554 555 556

  void pref(int32_t hint, const MemOperand& rs);

557
  // -------------Misc-instructions--------------
558 559

  // Break / Trap instructions.
560 561
  void break_(uint32_t code, bool break_as_stop = false);
  void stop(const char* msg, uint32_t code = kMaxStopCode);
562 563 564 565 566 567 568
  void tge(Register rs, Register rt, uint16_t code);
  void tgeu(Register rs, Register rt, uint16_t code);
  void tlt(Register rs, Register rt, uint16_t code);
  void tltu(Register rs, Register rt, uint16_t code);
  void teq(Register rs, Register rt, uint16_t code);
  void tne(Register rs, Register rt, uint16_t code);

569 570 571
  // Memory barrier instruction.
  void sync();

572 573 574 575 576 577 578 579 580 581
  // Move from HI/LO register.
  void mfhi(Register rd);
  void mflo(Register rd);

  // Set on less than.
  void slt(Register rd, Register rs, Register rt);
  void sltu(Register rd, Register rs, Register rt);
  void slti(Register rd, Register rs, int32_t j);
  void sltiu(Register rd, Register rs, int32_t j);

582 583 584 585 586 587
  // Conditional move.
  void movz(Register rd, Register rs, Register rt);
  void movn(Register rd, Register rs, Register rt);
  void movt(Register rd, Register rs, uint16_t cc = 0);
  void movf(Register rd, Register rs, uint16_t cc = 0);

588
  void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
589 590
  void sel_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void sel_d(FPURegister fd, FPURegister fs, FPURegister ft);
591 592 593 594 595 596
  void seleqz(Register rd, Register rs, Register rt);
  void seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
              FPURegister ft);
  void selnez(Register rd, Register rs, Register rt);
  void selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
              FPURegister ft);
597 598 599 600 601 602 603
  void seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void selnez_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void selnez_s(FPURegister fd, FPURegister fs, FPURegister ft);

  void movz_s(FPURegister fd, FPURegister fs, Register rt);
  void movz_d(FPURegister fd, FPURegister fs, Register rt);
604 605 606 607
  void movt_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
  void movt_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
  void movf_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
  void movf_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
608 609
  void movn_s(FPURegister fd, FPURegister fs, Register rt);
  void movn_d(FPURegister fd, FPURegister fs, Register rt);
610 611 612 613
  // Bit twiddling.
  void clz(Register rd, Register rs);
  void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
  void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
614
  void bitswap(Register rd, Register rt);
615
  void align(Register rd, Register rs, Register rt, uint8_t bp);
616

617 618 619 620
  void wsbh(Register rd, Register rt);
  void seh(Register rd, Register rt);
  void seb(Register rd, Register rt);

621
  // --------Coprocessor-instructions----------------
622 623 624 625 626

  // Load, store, and move.
  void lwc1(FPURegister fd, const MemOperand& src);
  void swc1(FPURegister fs, const MemOperand& dst);

627
  void mtc1(Register rt, FPURegister fs);
628 629
  void mthc1(Register rt, FPURegister fs);

630
  void mfc1(Register rt, FPURegister fs);
631
  void mfhc1(Register rt, FPURegister fs);
632 633 634 635 636

  void ctc1(Register rt, FPUControlRegister fs);
  void cfc1(Register rt, FPUControlRegister fs);

  // Arithmetic.
637
  void add_s(FPURegister fd, FPURegister fs, FPURegister ft);
638
  void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
639
  void sub_s(FPURegister fd, FPURegister fs, FPURegister ft);
640
  void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
641
  void mul_s(FPURegister fd, FPURegister fs, FPURegister ft);
642
  void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
643
  void madd_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
644
  void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
645 646 647 648 649 650
  void msub_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
  void msub_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
  void maddf_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void maddf_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void msubf_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void msubf_d(FPURegister fd, FPURegister fs, FPURegister ft);
651
  void div_s(FPURegister fd, FPURegister fs, FPURegister ft);
652
  void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
653
  void abs_s(FPURegister fd, FPURegister fs);
654 655
  void abs_d(FPURegister fd, FPURegister fs);
  void mov_d(FPURegister fd, FPURegister fs);
656
  void mov_s(FPURegister fd, FPURegister fs);
657
  void neg_s(FPURegister fd, FPURegister fs);
658
  void neg_d(FPURegister fd, FPURegister fs);
659
  void sqrt_s(FPURegister fd, FPURegister fs);
660
  void sqrt_d(FPURegister fd, FPURegister fs);
661 662 663 664
  void rsqrt_s(FPURegister fd, FPURegister fs);
  void rsqrt_d(FPURegister fd, FPURegister fs);
  void recip_d(FPURegister fd, FPURegister fs);
  void recip_s(FPURegister fd, FPURegister fs);
665 666 667 668

  // Conversion.
  void cvt_w_s(FPURegister fd, FPURegister fs);
  void cvt_w_d(FPURegister fd, FPURegister fs);
669 670 671 672 673 674 675 676
  void trunc_w_s(FPURegister fd, FPURegister fs);
  void trunc_w_d(FPURegister fd, FPURegister fs);
  void round_w_s(FPURegister fd, FPURegister fs);
  void round_w_d(FPURegister fd, FPURegister fs);
  void floor_w_s(FPURegister fd, FPURegister fs);
  void floor_w_d(FPURegister fd, FPURegister fs);
  void ceil_w_s(FPURegister fd, FPURegister fs);
  void ceil_w_d(FPURegister fd, FPURegister fs);
677 678 679
  void rint_s(FPURegister fd, FPURegister fs);
  void rint_d(FPURegister fd, FPURegister fs);
  void rint(SecondaryField fmt, FPURegister fd, FPURegister fs);
680 681 682

  void cvt_l_s(FPURegister fd, FPURegister fs);
  void cvt_l_d(FPURegister fd, FPURegister fs);
683 684 685 686 687 688 689 690
  void trunc_l_s(FPURegister fd, FPURegister fs);
  void trunc_l_d(FPURegister fd, FPURegister fs);
  void round_l_s(FPURegister fd, FPURegister fs);
  void round_l_d(FPURegister fd, FPURegister fs);
  void floor_l_s(FPURegister fd, FPURegister fs);
  void floor_l_d(FPURegister fd, FPURegister fs);
  void ceil_l_s(FPURegister fd, FPURegister fs);
  void ceil_l_d(FPURegister fd, FPURegister fs);
691

692 693 694
  void class_s(FPURegister fd, FPURegister fs);
  void class_d(FPURegister fd, FPURegister fs);

695 696 697 698
  void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
  void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
  void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
  void maxa(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
699 700 701 702 703 704 705 706
  void min_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void min_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void max_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void max_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void mina_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void mina_d(FPURegister fd, FPURegister fs, FPURegister ft);
  void maxa_s(FPURegister fd, FPURegister fs, FPURegister ft);
  void maxa_d(FPURegister fd, FPURegister fs, FPURegister ft);
707

708 709 710 711 712 713 714 715
  void cvt_s_w(FPURegister fd, FPURegister fs);
  void cvt_s_l(FPURegister fd, FPURegister fs);
  void cvt_s_d(FPURegister fd, FPURegister fs);

  void cvt_d_w(FPURegister fd, FPURegister fs);
  void cvt_d_l(FPURegister fd, FPURegister fs);
  void cvt_d_s(FPURegister fd, FPURegister fs);

716
  // Conditions and branches for MIPSr6.
717 718
  void cmp(FPUCondition cond, SecondaryField fmt, FPURegister fd,
           FPURegister ft, FPURegister fs);
719 720
  void cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
  void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
721 722

  void bc1eqz(int16_t offset, FPURegister ft);
723 724
  inline void bc1eqz(Label* L, FPURegister ft) {
    bc1eqz(shifted_branch_offset(L), ft);
725 726
  }
  void bc1nez(int16_t offset, FPURegister ft);
727 728
  inline void bc1nez(Label* L, FPURegister ft) {
    bc1nez(shifted_branch_offset(L), ft);
729 730 731
  }

  // Conditions and branches for non MIPSr6.
732 733
  void c(FPUCondition cond, SecondaryField fmt, FPURegister ft, FPURegister fs,
         uint16_t cc = 0);
734 735
  void c_s(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
  void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
736 737

  void bc1f(int16_t offset, uint16_t cc = 0);
738 739 740
  inline void bc1f(Label* L, uint16_t cc = 0) {
    bc1f(shifted_branch_offset(L), cc);
  }
741
  void bc1t(int16_t offset, uint16_t cc = 0);
742 743 744
  inline void bc1t(Label* L, uint16_t cc = 0) {
    bc1t(shifted_branch_offset(L), cc);
  }
745
  void fcmp(FPURegister src1, const double src2, FPUCondition cond);
746

747 748
  // MSA instructions
  void bz_v(MSARegister wt, int16_t offset);
749 750 751
  inline void bz_v(MSARegister wt, Label* L) {
    bz_v(wt, shifted_branch_offset(L));
  }
752
  void bz_b(MSARegister wt, int16_t offset);
753 754 755
  inline void bz_b(MSARegister wt, Label* L) {
    bz_b(wt, shifted_branch_offset(L));
  }
756
  void bz_h(MSARegister wt, int16_t offset);
757 758 759
  inline void bz_h(MSARegister wt, Label* L) {
    bz_h(wt, shifted_branch_offset(L));
  }
760
  void bz_w(MSARegister wt, int16_t offset);
761 762 763
  inline void bz_w(MSARegister wt, Label* L) {
    bz_w(wt, shifted_branch_offset(L));
  }
764
  void bz_d(MSARegister wt, int16_t offset);
765 766 767
  inline void bz_d(MSARegister wt, Label* L) {
    bz_d(wt, shifted_branch_offset(L));
  }
768
  void bnz_v(MSARegister wt, int16_t offset);
769 770 771
  inline void bnz_v(MSARegister wt, Label* L) {
    bnz_v(wt, shifted_branch_offset(L));
  }
772
  void bnz_b(MSARegister wt, int16_t offset);
773 774 775
  inline void bnz_b(MSARegister wt, Label* L) {
    bnz_b(wt, shifted_branch_offset(L));
  }
776
  void bnz_h(MSARegister wt, int16_t offset);
777 778 779
  inline void bnz_h(MSARegister wt, Label* L) {
    bnz_h(wt, shifted_branch_offset(L));
  }
780
  void bnz_w(MSARegister wt, int16_t offset);
781 782 783
  inline void bnz_w(MSARegister wt, Label* L) {
    bnz_w(wt, shifted_branch_offset(L));
  }
784
  void bnz_d(MSARegister wt, int16_t offset);
785 786 787
  inline void bnz_d(MSARegister wt, Label* L) {
    bnz_d(wt, shifted_branch_offset(L));
  }
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 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 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333

  void ld_b(MSARegister wd, const MemOperand& rs);
  void ld_h(MSARegister wd, const MemOperand& rs);
  void ld_w(MSARegister wd, const MemOperand& rs);
  void ld_d(MSARegister wd, const MemOperand& rs);
  void st_b(MSARegister wd, const MemOperand& rs);
  void st_h(MSARegister wd, const MemOperand& rs);
  void st_w(MSARegister wd, const MemOperand& rs);
  void st_d(MSARegister wd, const MemOperand& rs);

  void ldi_b(MSARegister wd, int32_t imm10);
  void ldi_h(MSARegister wd, int32_t imm10);
  void ldi_w(MSARegister wd, int32_t imm10);
  void ldi_d(MSARegister wd, int32_t imm10);

  void addvi_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void addvi_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void addvi_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void addvi_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void subvi_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void subvi_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void subvi_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void subvi_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_s_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_s_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_s_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_s_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_u_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_u_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_u_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void maxi_u_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_s_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_s_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_s_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_s_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_u_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_u_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_u_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void mini_u_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void ceqi_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void ceqi_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void ceqi_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void ceqi_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_s_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_s_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_s_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_s_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_u_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_u_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_u_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clti_u_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_s_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_s_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_s_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_s_d(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_u_b(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_u_h(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_u_w(MSARegister wd, MSARegister ws, uint32_t imm5);
  void clei_u_d(MSARegister wd, MSARegister ws, uint32_t imm5);

  void andi_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void ori_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void nori_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void xori_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void bmnzi_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void bmzi_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void bseli_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void shf_b(MSARegister wd, MSARegister ws, uint32_t imm8);
  void shf_h(MSARegister wd, MSARegister ws, uint32_t imm8);
  void shf_w(MSARegister wd, MSARegister ws, uint32_t imm8);

  void and_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void or_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void nor_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void xor_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void bmnz_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void bmz_v(MSARegister wd, MSARegister ws, MSARegister wt);
  void bsel_v(MSARegister wd, MSARegister ws, MSARegister wt);

  void fill_b(MSARegister wd, Register rs);
  void fill_h(MSARegister wd, Register rs);
  void fill_w(MSARegister wd, Register rs);
  void pcnt_b(MSARegister wd, MSARegister ws);
  void pcnt_h(MSARegister wd, MSARegister ws);
  void pcnt_w(MSARegister wd, MSARegister ws);
  void pcnt_d(MSARegister wd, MSARegister ws);
  void nloc_b(MSARegister wd, MSARegister ws);
  void nloc_h(MSARegister wd, MSARegister ws);
  void nloc_w(MSARegister wd, MSARegister ws);
  void nloc_d(MSARegister wd, MSARegister ws);
  void nlzc_b(MSARegister wd, MSARegister ws);
  void nlzc_h(MSARegister wd, MSARegister ws);
  void nlzc_w(MSARegister wd, MSARegister ws);
  void nlzc_d(MSARegister wd, MSARegister ws);

  void fclass_w(MSARegister wd, MSARegister ws);
  void fclass_d(MSARegister wd, MSARegister ws);
  void ftrunc_s_w(MSARegister wd, MSARegister ws);
  void ftrunc_s_d(MSARegister wd, MSARegister ws);
  void ftrunc_u_w(MSARegister wd, MSARegister ws);
  void ftrunc_u_d(MSARegister wd, MSARegister ws);
  void fsqrt_w(MSARegister wd, MSARegister ws);
  void fsqrt_d(MSARegister wd, MSARegister ws);
  void frsqrt_w(MSARegister wd, MSARegister ws);
  void frsqrt_d(MSARegister wd, MSARegister ws);
  void frcp_w(MSARegister wd, MSARegister ws);
  void frcp_d(MSARegister wd, MSARegister ws);
  void frint_w(MSARegister wd, MSARegister ws);
  void frint_d(MSARegister wd, MSARegister ws);
  void flog2_w(MSARegister wd, MSARegister ws);
  void flog2_d(MSARegister wd, MSARegister ws);
  void fexupl_w(MSARegister wd, MSARegister ws);
  void fexupl_d(MSARegister wd, MSARegister ws);
  void fexupr_w(MSARegister wd, MSARegister ws);
  void fexupr_d(MSARegister wd, MSARegister ws);
  void ffql_w(MSARegister wd, MSARegister ws);
  void ffql_d(MSARegister wd, MSARegister ws);
  void ffqr_w(MSARegister wd, MSARegister ws);
  void ffqr_d(MSARegister wd, MSARegister ws);
  void ftint_s_w(MSARegister wd, MSARegister ws);
  void ftint_s_d(MSARegister wd, MSARegister ws);
  void ftint_u_w(MSARegister wd, MSARegister ws);
  void ftint_u_d(MSARegister wd, MSARegister ws);
  void ffint_s_w(MSARegister wd, MSARegister ws);
  void ffint_s_d(MSARegister wd, MSARegister ws);
  void ffint_u_w(MSARegister wd, MSARegister ws);
  void ffint_u_d(MSARegister wd, MSARegister ws);

  void sll_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void sll_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void sll_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void sll_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void sra_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void sra_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void sra_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void sra_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void srl_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void srl_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void srl_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void srl_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void bclr_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void bclr_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void bclr_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void bclr_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void bset_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void bset_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void bset_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void bset_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void bneg_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void bneg_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void bneg_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void bneg_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsl_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsl_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsl_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsl_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsr_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsr_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsr_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void binsr_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void addv_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void addv_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void addv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void addv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subv_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subv_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_a_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_a_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void max_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_a_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_a_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void min_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ceq_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ceq_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ceq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ceq_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void clt_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void cle_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void add_a_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void add_a_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void add_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void add_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_a_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_a_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void adds_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ave_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void aver_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subs_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsus_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void subsuu_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void asub_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulv_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulv_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddv_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddv_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubv_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubv_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void div_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void mod_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dotp_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpadd_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void dpsub_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void sld_b(MSARegister wd, MSARegister ws, Register rt);
  void sld_h(MSARegister wd, MSARegister ws, Register rt);
  void sld_w(MSARegister wd, MSARegister ws, Register rt);
  void sld_d(MSARegister wd, MSARegister ws, Register rt);
  void splat_b(MSARegister wd, MSARegister ws, Register rt);
  void splat_h(MSARegister wd, MSARegister ws, Register rt);
  void splat_w(MSARegister wd, MSARegister ws, Register rt);
  void splat_d(MSARegister wd, MSARegister ws, Register rt);
  void pckev_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckev_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckev_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckev_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckod_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckod_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckod_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void pckod_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvl_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvl_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvl_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvl_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvr_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvr_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvr_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvr_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvev_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvev_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvev_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvev_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvod_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvod_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvod_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ilvod_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void vshf_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void vshf_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void vshf_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void vshf_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void srar_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void srar_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void srar_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void srar_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void srlr_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void srlr_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void srlr_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void srlr_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void hadd_u_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_s_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_s_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_s_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_s_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_u_b(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_u_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_u_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void hsub_u_d(MSARegister wd, MSARegister ws, MSARegister wt);

  void fcaf_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcaf_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcun_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcun_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fceq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fceq_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcueq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcueq_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fclt_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fclt_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcult_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcult_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcle_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcle_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcule_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcule_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsaf_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsaf_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsun_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsun_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fseq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fseq_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsueq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsueq_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fslt_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fslt_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsult_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsult_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsle_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsle_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsule_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsule_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fadd_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fadd_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsub_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsub_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmul_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmul_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fdiv_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fdiv_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmadd_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmadd_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmsub_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmsub_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fexp2_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fexp2_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fexdo_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void fexdo_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void ftq_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void ftq_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmin_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmin_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmin_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmin_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmax_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmax_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmax_a_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fmax_a_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcor_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcor_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcune_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcune_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcne_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fcne_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void mul_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void mul_q_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void madd_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void madd_q_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void msub_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void msub_q_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsor_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsor_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsune_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsune_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsne_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void fsne_d(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulr_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void mulr_q_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddr_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void maddr_q_w(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubr_q_h(MSARegister wd, MSARegister ws, MSARegister wt);
  void msubr_q_w(MSARegister wd, MSARegister ws, MSARegister wt);

  void sldi_b(MSARegister wd, MSARegister ws, uint32_t n);
  void sldi_h(MSARegister wd, MSARegister ws, uint32_t n);
  void sldi_w(MSARegister wd, MSARegister ws, uint32_t n);
  void sldi_d(MSARegister wd, MSARegister ws, uint32_t n);
  void splati_b(MSARegister wd, MSARegister ws, uint32_t n);
  void splati_h(MSARegister wd, MSARegister ws, uint32_t n);
  void splati_w(MSARegister wd, MSARegister ws, uint32_t n);
  void splati_d(MSARegister wd, MSARegister ws, uint32_t n);
  void copy_s_b(Register rd, MSARegister ws, uint32_t n);
  void copy_s_h(Register rd, MSARegister ws, uint32_t n);
  void copy_s_w(Register rd, MSARegister ws, uint32_t n);
  void copy_u_b(Register rd, MSARegister ws, uint32_t n);
  void copy_u_h(Register rd, MSARegister ws, uint32_t n);
  void copy_u_w(Register rd, MSARegister ws, uint32_t n);
  void insert_b(MSARegister wd, uint32_t n, Register rs);
  void insert_h(MSARegister wd, uint32_t n, Register rs);
  void insert_w(MSARegister wd, uint32_t n, Register rs);
  void insve_b(MSARegister wd, uint32_t n, MSARegister ws);
  void insve_h(MSARegister wd, uint32_t n, MSARegister ws);
  void insve_w(MSARegister wd, uint32_t n, MSARegister ws);
  void insve_d(MSARegister wd, uint32_t n, MSARegister ws);
  void move_v(MSARegister wd, MSARegister ws);
  void ctcmsa(MSAControlRegister cd, Register rs);
  void cfcmsa(Register rd, MSAControlRegister cs);

  void slli_b(MSARegister wd, MSARegister ws, uint32_t m);
  void slli_h(MSARegister wd, MSARegister ws, uint32_t m);
  void slli_w(MSARegister wd, MSARegister ws, uint32_t m);
  void slli_d(MSARegister wd, MSARegister ws, uint32_t m);
  void srai_b(MSARegister wd, MSARegister ws, uint32_t m);
  void srai_h(MSARegister wd, MSARegister ws, uint32_t m);
  void srai_w(MSARegister wd, MSARegister ws, uint32_t m);
  void srai_d(MSARegister wd, MSARegister ws, uint32_t m);
  void srli_b(MSARegister wd, MSARegister ws, uint32_t m);
  void srli_h(MSARegister wd, MSARegister ws, uint32_t m);
  void srli_w(MSARegister wd, MSARegister ws, uint32_t m);
  void srli_d(MSARegister wd, MSARegister ws, uint32_t m);
  void bclri_b(MSARegister wd, MSARegister ws, uint32_t m);
  void bclri_h(MSARegister wd, MSARegister ws, uint32_t m);
  void bclri_w(MSARegister wd, MSARegister ws, uint32_t m);
  void bclri_d(MSARegister wd, MSARegister ws, uint32_t m);
  void bseti_b(MSARegister wd, MSARegister ws, uint32_t m);
  void bseti_h(MSARegister wd, MSARegister ws, uint32_t m);
  void bseti_w(MSARegister wd, MSARegister ws, uint32_t m);
  void bseti_d(MSARegister wd, MSARegister ws, uint32_t m);
  void bnegi_b(MSARegister wd, MSARegister ws, uint32_t m);
  void bnegi_h(MSARegister wd, MSARegister ws, uint32_t m);
  void bnegi_w(MSARegister wd, MSARegister ws, uint32_t m);
  void bnegi_d(MSARegister wd, MSARegister ws, uint32_t m);
  void binsli_b(MSARegister wd, MSARegister ws, uint32_t m);
  void binsli_h(MSARegister wd, MSARegister ws, uint32_t m);
  void binsli_w(MSARegister wd, MSARegister ws, uint32_t m);
  void binsli_d(MSARegister wd, MSARegister ws, uint32_t m);
  void binsri_b(MSARegister wd, MSARegister ws, uint32_t m);
  void binsri_h(MSARegister wd, MSARegister ws, uint32_t m);
  void binsri_w(MSARegister wd, MSARegister ws, uint32_t m);
  void binsri_d(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_s_b(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_s_h(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_s_w(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_s_d(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_u_b(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_u_h(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_u_w(MSARegister wd, MSARegister ws, uint32_t m);
  void sat_u_d(MSARegister wd, MSARegister ws, uint32_t m);
  void srari_b(MSARegister wd, MSARegister ws, uint32_t m);
  void srari_h(MSARegister wd, MSARegister ws, uint32_t m);
  void srari_w(MSARegister wd, MSARegister ws, uint32_t m);
  void srari_d(MSARegister wd, MSARegister ws, uint32_t m);
  void srlri_b(MSARegister wd, MSARegister ws, uint32_t m);
  void srlri_h(MSARegister wd, MSARegister ws, uint32_t m);
  void srlri_w(MSARegister wd, MSARegister ws, uint32_t m);
  void srlri_d(MSARegister wd, MSARegister ws, uint32_t m);

1334
  // Check the code size generated from label to here.
1335 1336 1337 1338 1339 1340 1341
  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;
1342 1343
  }

1344 1345 1346 1347 1348 1349
  // Class for scoping postponing the trampoline pool generation.
  class BlockTrampolinePoolScope {
   public:
    explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
      assem_->StartBlockTrampolinePool();
    }
1350
    ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }
1351 1352 1353 1354 1355 1356 1357

   private:
    Assembler* assem_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
  };

1358 1359 1360 1361 1362 1363 1364 1365 1366
  // Class for postponing the assembly buffer growth. Typically used for
  // sequences of instructions that must be emitted as a unit, before
  // buffer growth (and relocation) can occur.
  // This blocking scope is not nestable.
  class BlockGrowBufferScope {
   public:
    explicit BlockGrowBufferScope(Assembler* assem) : assem_(assem) {
      assem_->StartBlockGrowBuffer();
    }
1367
    ~BlockGrowBufferScope() { assem_->EndBlockGrowBuffer(); }
1368

1369 1370
   private:
    Assembler* assem_;
1371

1372
    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope);
1373 1374
  };

1375 1376
  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
1377 1378
  void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position,
                         int id);
1379

1380
  static int RelocateInternalReference(RelocInfo::Mode rmode, Address pc,
1381
                                       intptr_t pc_delta);
1382

1383 1384 1385
  static void RelocateRelativeReference(RelocInfo::Mode rmode, Address pc,
                                        intptr_t pc_delta);

1386 1387 1388 1389
  // Writes a single byte or word of data in the code stream.  Used for
  // inline tables, e.g., jump-tables.
  void db(uint8_t data);
  void dd(uint32_t data);
1390 1391
  void dq(uint64_t data);
  void dp(uintptr_t data) { dd(data); }
1392
  void dd(Label* label);
1393

1394 1395 1396 1397
  // Postpone the generation of the trampoline pool for the specified number of
  // instructions.
  void BlockTrampolinePoolFor(int instructions);

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

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

  // Read/patch instructions.
1407 1408
  static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); }
  static void instr_at_put(Address pc, Instr instr) {
1409 1410
    *reinterpret_cast<Instr*>(pc) = instr;
  }
1411 1412 1413
  Instr instr_at(int pos) {
    return *reinterpret_cast<Instr*>(buffer_start_ + pos);
  }
1414
  void instr_at_put(int pos, Instr instr) {
1415
    *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
1416 1417 1418
  }

  // Check if an instruction is a branch of some kind.
1419
  static bool IsBranch(Instr instr);
1420
  static bool IsMsaBranch(Instr instr);
1421
  static bool IsBc(Instr instr);
1422
  static bool IsNal(Instr instr);
1423
  static bool IsBzc(Instr instr);
1424 1425
  static bool IsBeq(Instr instr);
  static bool IsBne(Instr instr);
1426 1427 1428 1429
  static bool IsBeqzc(Instr instr);
  static bool IsBnezc(Instr instr);
  static bool IsBeqc(Instr instr);
  static bool IsBnec(Instr instr);
1430
  static bool IsJicOrJialc(Instr instr);
1431
  static bool IsMov(Instr instr, Register rd, Register rs);
1432

1433 1434 1435 1436
  static bool IsJump(Instr instr);
  static bool IsJ(Instr instr);
  static bool IsLui(Instr instr);
  static bool IsOri(Instr instr);
1437
  static bool IsAddu(Instr instr, Register rd, Register rs, Register rt);
1438

1439 1440 1441 1442
  static bool IsJal(Instr instr);
  static bool IsJr(Instr instr);
  static bool IsJalr(Instr instr);

1443 1444 1445 1446 1447 1448 1449 1450
  static bool IsNop(Instr instr, unsigned int type);
  static bool IsPop(Instr instr);
  static bool IsPush(Instr instr);
  static bool IsLwRegFpOffset(Instr instr);
  static bool IsSwRegFpOffset(Instr instr);
  static bool IsLwRegFpNegOffset(Instr instr);
  static bool IsSwRegFpNegOffset(Instr instr);

1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
  static Register GetRtReg(Instr instr);
  static Register GetRsReg(Instr instr);
  static Register GetRdReg(Instr instr);

  static uint32_t GetRt(Instr instr);
  static uint32_t GetRtField(Instr instr);
  static uint32_t GetRs(Instr instr);
  static uint32_t GetRsField(Instr instr);
  static uint32_t GetRd(Instr instr);
  static uint32_t GetRdField(Instr instr);
  static uint32_t GetSa(Instr instr);
  static uint32_t GetSaField(Instr instr);
  static uint32_t GetOpcodeField(Instr instr);
1464 1465
  static uint32_t GetFunction(Instr instr);
  static uint32_t GetFunctionField(Instr instr);
1466 1467
  static uint32_t GetImmediate16(Instr instr);
  static uint32_t GetLabelConst(Instr instr);
1468 1469 1470 1471

  static int32_t GetBranchOffset(Instr instr);
  static bool IsLw(Instr instr);
  static int16_t GetLwOffset(Instr instr);
1472 1473
  static int16_t GetJicOrJialcOffset(Instr instr);
  static int16_t GetLuiOffset(Instr instr);
1474 1475 1476 1477 1478 1479
  static Instr SetLwOffset(Instr instr, int16_t offset);

  static bool IsSw(Instr instr);
  static Instr SetSwOffset(Instr instr, int16_t offset);
  static bool IsAddImmediate(Instr instr);
  static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
1480 1481 1482 1483 1484 1485
  static uint32_t CreateTargetAddress(Instr instr_lui, Instr instr_jic);
  static void UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
                                  int16_t& jic_offset);
  static void UnpackTargetAddressUnsigned(uint32_t address,
                                          uint32_t& lui_offset,
                                          uint32_t& jic_offset);
1486

1487
  static bool IsAndImmediate(Instr instr);
1488
  static bool IsEmittedConstant(Instr instr);
1489

1490
  void CheckTrampolinePool();
1491

1492
  bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
1493 1494 1495
  static bool IsCompactBranchSupported() {
    return IsMipsArchVariant(kMips32r6);
  }
1496

1497 1498 1499 1500
  // 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;

1501 1502
  inline int UnboundLabelsCount() { return unbound_labels_count_; }

1503
 protected:
1504 1505 1506
  // Load Scaled Address instruction.
  void lsa(Register rd, Register rt, Register rs, uint8_t sa);

1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
  // Readable constants for base and offset adjustment helper, these indicate if
  // aside from offset, another value like offset + 4 should fit into int16.
  enum class OffsetAccessType : bool {
    SINGLE_ACCESS = false,
    TWO_ACCESSES = true
  };

  // Helper function for memory load/store using base register and offset.
  void AdjustBaseAndOffset(
      MemOperand& src,
      OffsetAccessType access_type = OffsetAccessType::SINGLE_ACCESS,
      int second_access_add_to_offset = 4);
1519

1520
  int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
1521 1522

  // Decode branch instruction at pos and return branch target pos.
1523
  int target_at(int pos, bool is_internal);
1524 1525

  // Patch branch instruction at pos to branch to given branch target pos.
1526
  void target_at_put(int pos, int target_pos, bool is_internal);
1527 1528

  // Say if we need to relocate with this mode.
1529
  bool MustUseReg(RelocInfo::Mode rmode);
1530 1531 1532 1533

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

1534 1535 1536
  // Read 32-bit immediate from lui, ori pair that is used to load immediate.
  static int32_t GetLuiOriImmediate(Instr instr1, Instr instr2);

1537 1538 1539 1540 1541 1542
  // 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;
  }

1543
  void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
1544

1545 1546
  void EndBlockTrampolinePool() {
    trampoline_pool_blocked_nesting_--;
1547 1548 1549
    if (trampoline_pool_blocked_nesting_ == 0) {
      CheckTrampolinePoolQuick(1);
    }
1550 1551 1552 1553 1554 1555
  }

  bool is_trampoline_pool_blocked() const {
    return trampoline_pool_blocked_nesting_ > 0;
  }

1556
  bool has_exception() const { return internal_trampoline_exception_; }
1557

1558
  bool is_trampoline_emitted() const { return trampoline_emitted_; }
1559 1560 1561

  // Temporarily block automatic assembly buffer growth.
  void StartBlockGrowBuffer() {
1562
    DCHECK(!block_buffer_growth_);
1563 1564 1565 1566
    block_buffer_growth_ = true;
  }

  void EndBlockGrowBuffer() {
1567
    DCHECK(block_buffer_growth_);
1568 1569 1570
    block_buffer_growth_ = false;
  }

1571
  bool is_buffer_growth_blocked() const { return block_buffer_growth_; }
1572

1573 1574 1575 1576 1577 1578
  void EmitForbiddenSlotInstruction() {
    if (IsPrevInstrCompactBranch()) {
      nop();
    }
  }

1579 1580 1581 1582 1583
  inline void CheckTrampolinePoolQuick(int extra_instructions = 0) {
    if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
      CheckTrampolinePool();
    }
  }
1584

1585 1586
  inline void CheckBuffer();

1587 1588
  RegList scratch_register_list_;

1589 1590 1591 1592 1593 1594
  // Generate common instruction sequence.
  void GenPCRelativeJump(Register tf, Register ts, int32_t imm32,
                         RelocInfo::Mode rmode, BranchDelaySlot bdslot);
  void GenPCRelativeJumpAndLink(Register t, int32_t imm32,
                                RelocInfo::Mode rmode, BranchDelaySlot bdslot);

1595
 private:
1596 1597 1598
  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512 * MB;

1599 1600 1601
  inline static void set_target_internal_reference_encoded_at(Address pc,
                                                              Address target);

1602 1603
  // Buffer size and constant pool distance are checked together at regular
  // intervals of kBufferCheckInterval emitted bytes.
1604
  static constexpr int kBufferCheckInterval = 1 * KB / 2;
1605 1606 1607 1608 1609 1610

  // 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.
1611
  static constexpr int kGap = 32;
1612 1613 1614 1615

  // 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.
1616 1617 1618
  static constexpr int kCheckConstIntervalInst = 32;
  static constexpr int kCheckConstInterval =
      kCheckConstIntervalInst * kInstrSize;
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628

  int next_buffer_check_;  // pc offset of next buffer check.

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

  // Keep track of the last emitted pool to guarantee a maximal distance.
  int last_trampoline_pool_end_;  // pc offset of the end of the last pool.

1629 1630 1631
  // Automatic growth of the assembly buffer may be blocked for some sequences.
  bool block_buffer_growth_;  // Block growth when true.

1632 1633
  // Relocation information generation.
  // Each relocation is encoded as a variable size value.
1634
  static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1635 1636 1637 1638 1639
  RelocInfoWriter reloc_info_writer;

  // The bound position, before this we cannot do instruction elimination.
  int last_bound_pos_;

1640 1641 1642
  // Readable constants for compact branch handling in emit()
  enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true };

1643 1644
  // Code emission.
  void GrowBuffer();
1645 1646
  inline void emit(Instr x,
                   CompactBranchType is_compact_branch = CompactBranchType::NO);
1647 1648 1649 1650 1651
  inline void emit(uint64_t x);
  inline void CheckForEmitInForbiddenSlot();
  template <typename T>
  inline void EmitHelper(T x);
  inline void EmitHelper(Instr x, CompactBranchType is_compact_branch);
1652 1653 1654 1655 1656 1657 1658 1659 1660

  // Instruction generation.
  // We have 3 different kind of encoding layout on MIPS.
  // However due to many different types of objects encoded in the same fields
  // we have quite a few aliases for each mode.
  // Using the same structure to refer to Register and FPURegister would spare a
  // few aliases, but mixing both does not look clean to me.
  // Anyway we could surely implement this differently.

1661 1662
  void GenInstrRegister(Opcode opcode, Register rs, Register rt, Register rd,
                        uint16_t sa = 0, SecondaryField func = nullptrSF);
1663

1664 1665
  void GenInstrRegister(Opcode opcode, Register rs, Register rt, uint16_t msb,
                        uint16_t lsb, SecondaryField func);
1666

1667 1668 1669
  void GenInstrRegister(Opcode opcode, SecondaryField fmt, FPURegister ft,
                        FPURegister fs, FPURegister fd,
                        SecondaryField func = nullptrSF);
1670

1671 1672 1673
  void GenInstrRegister(Opcode opcode, FPURegister fr, FPURegister ft,
                        FPURegister fs, FPURegister fd,
                        SecondaryField func = nullptrSF);
1674

1675 1676 1677
  void GenInstrRegister(Opcode opcode, SecondaryField fmt, Register rt,
                        FPURegister fs, FPURegister fd,
                        SecondaryField func = nullptrSF);
1678

1679 1680
  void GenInstrRegister(Opcode opcode, SecondaryField fmt, Register rt,
                        FPUControlRegister fs, SecondaryField func = nullptrSF);
1681

1682 1683 1684 1685 1686 1687 1688 1689 1690
  void GenInstrImmediate(
      Opcode opcode, Register rs, Register rt, int32_t j,
      CompactBranchType is_compact_branch = CompactBranchType::NO);
  void GenInstrImmediate(
      Opcode opcode, Register rs, SecondaryField SF, int32_t j,
      CompactBranchType is_compact_branch = CompactBranchType::NO);
  void GenInstrImmediate(
      Opcode opcode, Register r1, FPURegister r2, int32_t j,
      CompactBranchType is_compact_branch = CompactBranchType::NO);
1691 1692
  void GenInstrImmediate(Opcode opcode, Register base, Register rt,
                         int32_t offset9, int bit6, SecondaryField func);
1693 1694 1695 1696 1697 1698 1699
  void GenInstrImmediate(
      Opcode opcode, Register rs, int32_t offset21,
      CompactBranchType is_compact_branch = CompactBranchType::NO);
  void GenInstrImmediate(Opcode opcode, Register rs, uint32_t offset21);
  void GenInstrImmediate(
      Opcode opcode, int32_t offset26,
      CompactBranchType is_compact_branch = CompactBranchType::NO);
1700

1701
  void GenInstrJump(Opcode opcode, uint32_t address);
1702

1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
  // MSA
  void GenInstrMsaI8(SecondaryField operation, uint32_t imm8, MSARegister ws,
                     MSARegister wd);

  void GenInstrMsaI5(SecondaryField operation, SecondaryField df, int32_t imm5,
                     MSARegister ws, MSARegister wd);

  void GenInstrMsaBit(SecondaryField operation, SecondaryField df, uint32_t m,
                      MSARegister ws, MSARegister wd);

  void GenInstrMsaI10(SecondaryField operation, SecondaryField df,
                      int32_t imm10, MSARegister wd);

  template <typename RegType>
  void GenInstrMsa3R(SecondaryField operation, SecondaryField df, RegType t,
                     MSARegister ws, MSARegister wd);

  template <typename DstType, typename SrcType>
  void GenInstrMsaElm(SecondaryField operation, SecondaryField df, uint32_t n,
                      SrcType src, DstType dst);

  void GenInstrMsa3RF(SecondaryField operation, uint32_t df, MSARegister wt,
                      MSARegister ws, MSARegister wd);

  void GenInstrMsaVec(SecondaryField operation, MSARegister wt, MSARegister ws,
                      MSARegister wd);

  void GenInstrMsaMI10(SecondaryField operation, int32_t s10, Register rs,
                       MSARegister wd);

  void GenInstrMsa2R(SecondaryField operation, SecondaryField df,
                     MSARegister ws, MSARegister wd);

  void GenInstrMsa2RF(SecondaryField operation, SecondaryField df,
                      MSARegister ws, MSARegister wd);

  void GenInstrMsaBranch(SecondaryField operation, MSARegister wt,
                         int32_t offset16);

  inline bool is_valid_msa_df_m(SecondaryField bit_df, uint32_t m) {
    switch (bit_df) {
      case BIT_DF_b:
        return is_uint3(m);
      case BIT_DF_h:
        return is_uint4(m);
      case BIT_DF_w:
        return is_uint5(m);
      case BIT_DF_d:
        return is_uint6(m);
      default:
        return false;
    }
  }

  inline bool is_valid_msa_df_n(SecondaryField elm_df, uint32_t n) {
    switch (elm_df) {
      case ELM_DF_B:
        return is_uint4(n);
      case ELM_DF_H:
        return is_uint3(n);
      case ELM_DF_W:
        return is_uint2(n);
      case ELM_DF_D:
        return is_uint1(n);
      default:
        return false;
    }
  }
1771 1772

  // Labels.
1773
  void print(const Label* L);
1774
  void bind_to(Label* L, int pos);
1775
  void next(Label* L, bool is_internal);
1776

1777 1778 1779 1780 1781 1782 1783 1784
  // Patching lui/ori pair which is commonly used for loading constants.
  static void PatchLuiOriImmediate(Address pc, int32_t imm, Instr instr1,
                                   Address offset_lui, Instr instr2,
                                   Address offset_ori);
  void PatchLuiOriImmediate(int pc, int32_t imm, Instr instr1,
                            Address offset_lui, Instr instr2,
                            Address offset_ori);

1785 1786 1787 1788 1789
  // One trampoline consists of:
  // - space for trampoline slots,
  // - space for labels.
  //
  // Space for trampoline slots is equal to slot_count * 2 * kInstrSize.
1790
  // Space for trampoline slots precedes space for labels. Each label is of one
1791 1792 1793 1794
  // instruction size, so total amount for labels is equal to
  // label_count *  kInstrSize.
  class Trampoline {
   public:
1795 1796 1797 1798 1799 1800 1801
    Trampoline() {
      start_ = 0;
      next_slot_ = 0;
      free_slot_count_ = 0;
      end_ = 0;
    }
    Trampoline(int start, int slot_count) {
1802 1803 1804
      start_ = start;
      next_slot_ = start;
      free_slot_count_ = slot_count;
1805
      end_ = start + slot_count * kTrampolineSlotsSize;
1806
    }
1807 1808
    int start() { return start_; }
    int end() { return end_; }
1809
    int take_slot() {
1810 1811 1812 1813 1814
      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.
1815
        DCHECK(0);
1816 1817 1818 1819
        // Internal exception will be caught.
      } else {
        trampoline_slot = next_slot_;
        free_slot_count_--;
1820
        next_slot_ += kTrampolineSlotsSize;
1821
      }
1822 1823
      return trampoline_slot;
    }
1824

1825 1826 1827 1828 1829 1830 1831
   private:
    int start_;
    int end_;
    int next_slot_;
    int free_slot_count_;
  };

1832 1833 1834 1835 1836 1837 1838 1839
  int32_t get_trampoline_entry(int32_t pos);
  int unbound_labels_count_;
  // 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 use jump instructions rather
  // than regular branch instructions.
  bool trampoline_emitted_;
1840
  static constexpr int kInvalidSlotPos = -1;
1841

1842 1843 1844
  // Internal reference positions, required for unbounded internal reference
  // labels.
  std::set<int> internal_reference_positions_;
1845 1846 1847 1848
  bool is_internal_reference(Label* L) {
    return internal_reference_positions_.find(L->pos()) !=
           internal_reference_positions_.end();
  }
1849

1850 1851 1852 1853
  void EmittedCompactBranchInstruction() { prev_instr_compact_branch_ = true; }
  void ClearCompactBranchState() { prev_instr_compact_branch_ = false; }
  bool prev_instr_compact_branch_ = false;

1854
  Trampoline trampoline_;
1855
  bool internal_trampoline_exception_;
1856

1857
 private:
1858 1859
  void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);

1860 1861
  int WriteCodeComments();

1862 1863
  friend class RegExpMacroAssemblerMIPS;
  friend class RelocInfo;
1864 1865 1866 1867
  friend class BlockTrampolinePoolScope;
  friend class EnsureSpace;
};

1868
class EnsureSpace {
1869
 public:
1870
  explicit inline EnsureSpace(Assembler* assembler);
1871 1872
};

1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
class UseScratchRegisterScope {
 public:
  explicit UseScratchRegisterScope(Assembler* assembler);
  ~UseScratchRegisterScope();

  Register Acquire();
  bool hasAvailable() const;

 private:
  RegList* available_;
  RegList old_available_;
};

1886 1887
}  // namespace internal
}  // namespace v8
1888

1889
#endif  // V8_CODEGEN_MIPS_ASSEMBLER_MIPS_H_