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

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

#ifndef V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_
#define V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_

#include <stdio.h>

#include <memory>
#include <set>

#include "src/codegen/assembler.h"
#include "src/codegen/constant-pool.h"
#include "src/codegen/external-reference.h"
#include "src/codegen/label.h"
#include "src/codegen/riscv64/constants-riscv64.h"
#include "src/codegen/riscv64/register-riscv64.h"
#include "src/objects/contexts.h"
#include "src/objects/smi.h"

namespace v8 {
namespace internal {

#define DEBUG_PRINTF(...) \
56
  if (FLAG_riscv_debug) { \
Brice Dobry's avatar
Brice Dobry committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70
    printf(__VA_ARGS__);  \
  }

class SafepointTableBuilder;

// -----------------------------------------------------------------------------
// Machine instruction Operands.
constexpr int kSmiShift = kSmiTagSize + kSmiShiftSize;
constexpr uint64_t kSmiShiftMask = (1UL << kSmiShift) - 1;
// Class Operand represents a shifter operand in data processing instructions.
class Operand {
 public:
  // Immediate.
  V8_INLINE explicit Operand(int64_t immediate,
71
                             RelocInfo::Mode rmode = RelocInfo::NO_INFO)
Brice Dobry's avatar
Brice Dobry committed
72 73 74 75 76 77 78 79 80
      : rm_(no_reg), rmode_(rmode) {
    value_.immediate = immediate;
  }
  V8_INLINE explicit Operand(const ExternalReference& f)
      : rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) {
    value_.immediate = static_cast<int64_t>(f.address());
  }
  V8_INLINE explicit Operand(const char* s);
  explicit Operand(Handle<HeapObject> handle);
81 82
  V8_INLINE explicit Operand(Smi value)
      : rm_(no_reg), rmode_(RelocInfo::NO_INFO) {
Brice Dobry's avatar
Brice Dobry committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    value_.immediate = static_cast<intptr_t>(value.ptr());
  }

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

  // Register.
  V8_INLINE explicit Operand(Register rm) : rm_(rm) {}

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

  inline int64_t immediate() const;

  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_,
                   rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
                       rmode_ == RelocInfo::CODE_TARGET);
    return is_heap_object_request_;
  }

  Register rm() const { return rm_; }

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

 private:
  Register rm_;
  union Value {
    Value() {}
    HeapObjectRequest heap_object_request;  // if is_heap_object_request_
    int64_t immediate;                      // otherwise
  } value_;                                 // valid if rm_ == no_reg
  bool is_heap_object_request_ = false;
  RelocInfo::Mode rmode_;

  friend class Assembler;
  friend class MacroAssembler;
};

// On RISC-V we have only one addressing mode with base_reg + offset.
// Class MemOperand represents a memory operand in load and store instructions.
class V8_EXPORT_PRIVATE MemOperand : public Operand {
 public:
  // Immediate value attached to offset.
  enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 };

  explicit MemOperand(Register rn, int32_t offset = 0);
  explicit MemOperand(Register rn, int32_t unit, int32_t multiplier,
                      OffsetAddend offset_addend = offset_zero);
  int32_t offset() const { return offset_; }

  bool OffsetIsInt12Encodable() const { return is_int12(offset_); }

 private:
  int32_t offset_;

  friend class Assembler;
};

class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
 public:
  // Create an assembler. Instructions and relocation information are emitted
  // into a buffer, with the instructions starting from the beginning and the
  // relocation information starting from the end of the buffer. See CodeDesc
  // for a detailed comment on the layout (globals.h).
  //
  // If the provided buffer is nullptr, the assembler allocates and grows its
  // own buffer. Otherwise it takes ownership of the provided buffer.
  explicit Assembler(const AssemblerOptions&,
                     std::unique_ptr<AssemblerBuffer> = {});

162 163
  virtual ~Assembler();
  void AbortedCodeGeneration();
Brice Dobry's avatar
Brice Dobry committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  // 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);
  }

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

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

  enum OffsetSize : int {
    kOffset21 = 21,  // RISCV jal
    kOffset12 = 12,  // RISCV imm12
    kOffset20 = 20,  // RISCV imm20
    kOffset13 = 13,  // RISCV branch
    kOffset32 = 32,  // RISCV auipc + instr_I
201 202
    kOffset11 = 11,  // RISCV C_J
    kOffset8 = 8     // RISCV compressed branch
Brice Dobry's avatar
Brice Dobry committed
203 204 205 206 207 208 209 210 211 212
  };

  // 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);
  bool is_near(Label* L, OffsetSize bits);
  bool is_near_branch(Label* L);

  // Get offset from instr.
  int BranchOffset(Instr instr);
213 214 215
  static int BrachlongOffset(Instr auipc, Instr jalr);
  static int PatchBranchlongOffset(Address pc, Instr auipc, Instr instr_I,
                                   int32_t offset);
Brice Dobry's avatar
Brice Dobry committed
216 217
  int JumpOffset(Instr instr);
  int CJumpOffset(Instr instr);
218
  int CBranchOffset(Instr instr);
Brice Dobry's avatar
Brice Dobry committed
219 220
  static int LdOffset(Instr instr);
  static int AuipcOffset(Instr instr);
221
  static int JalrOffset(Instr instr);
Brice Dobry's avatar
Brice Dobry committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235

  // 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.
  // Manages the jump elimination optimization if the second parameter is true.
  int32_t branch_offset_helper(Label* L, OffsetSize bits);
  inline int32_t branch_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset13);
  }
  inline int32_t jump_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset21);
  }
  inline int16_t cjump_offset(Label* L) {
    return (int16_t)branch_offset_helper(L, OffsetSize::kOffset11);
  }
236 237 238
  inline int32_t cbranch_offset(Label* L) {
    return branch_offset_helper(L, OffsetSize::kOffset8);
  }
Brice Dobry's avatar
Brice Dobry committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

  uint64_t jump_address(Label* L);
  uint64_t branch_long_offset(Label* L);

  // 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.
  // The isolate argument is unused (and may be nullptr) when skipping flushing.
  static Address target_address_at(Address pc);
  V8_INLINE static void set_target_address_at(
      Address pc, Address target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) {
    set_target_value_at(pc, target, icache_flush_mode);
  }

  static Address target_address_at(Address pc, Address constant_pool);

  static void set_target_address_at(
      Address pc, Address constant_pool, Address target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);

262 263 264 265 266 267 268 269 270 271 272 273
  // Read/Modify the code target address in the branch/call instruction at pc.
  inline static Tagged_t target_compressed_address_at(Address pc,
                                                      Address constant_pool);
  inline static void set_target_compressed_address_at(
      Address pc, Address constant_pool, Tagged_t target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);

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

Brice Dobry's avatar
Brice Dobry committed
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
  static bool IsConstantPoolAt(Instruction* instr);
  static int ConstantPoolSizeAt(Instruction* instr);
  // See Assembler::CheckConstPool for more info.
  void EmitPoolGuard();

  static void set_target_value_at(
      Address pc, uint64_t target,
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);

  static void JumpLabelToJumpRegister(Address pc);

  // This sets the branch destination (which gets loaded at the call address).
  // 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(
      Address instruction_payload, Code code, Address target);

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

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

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

  // Difference between address of current opcode and target address offset,
  // when we are generatinga sequence of instructions for long relative PC
  // branches
  static constexpr int kLongBranchPCOffset = 3 * kInstrSize;

  // Adjust ra register in branch delay slot of bal instruction so to skip
  // instructions not needed after optimization of PIC in
  // TurboAssembler::BranchAndLink method.

  static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 4 * kInstrSize;

  // Here we are patching the address in the LUI/ADDI instruction pair.
  // These values are used in the serialization process and must be zero for
  // RISC-V 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.
  static constexpr int kSpecialTargetSize = 0;

  // Number of consecutive instructions used to store 32bit/64bit constant.
  // This constant was used in RelocInfo::target_address_address() function
  // to tell serializer address of the instruction that follows
  // LUI/ADDI instruction pair.
  static constexpr int kInstructionsFor32BitConstant = 2;
  static constexpr int kInstructionsFor64BitConstant = 8;

  // Difference between address of current opcode and value read from pc
  // register.
  static constexpr int kPcLoadDelta = 4;

  // Bits available for offset field in branches
  static constexpr int kBranchOffsetBits = 13;

  // Bits available for offset field in jump
  static constexpr int kJumpOffsetBits = 21;

  // Bits available for offset field in compresed jump
  static constexpr int kCJalOffsetBits = 12;

342 343 344
  // Bits available for offset field in compressed branch
  static constexpr int kCBranchOffsetBits = 9;

Brice Dobry's avatar
Brice Dobry committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
  // Max offset for b instructions with 12-bit offset field (multiple of 2)
  static constexpr int kMaxBranchOffset = (1 << (13 - 1)) - 1;

  // Max offset for jal instruction with 20-bit offset field (multiple of 2)
  static constexpr int kMaxJumpOffset = (1 << (21 - 1)) - 1;

  static constexpr int kTrampolineSlotsSize = 2 * kInstrSize;

  RegList* GetScratchRegisterList() { return &scratch_register_list_; }

  // ---------------------------------------------------------------------------
  // Code generation.

  // Insert the smallest number of nop instructions
  // possible to align the pc offset to a multiple
  // of m. m must be a power of 2 (>= 4).
  void Align(int m);
  // 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);
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();
367
  void LoopHeaderAlign() { CodeTargetAlign(); }
Brice Dobry's avatar
Brice Dobry committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

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

  // RISC-V Instructions Emited to a buffer

  void lui(Register rd, int32_t imm20);
  void auipc(Register rd, int32_t imm20);

  // Jumps
  void jal(Register rd, int32_t imm20);
  void jalr(Register rd, Register rs1, int16_t imm12);

  // Branches
  void beq(Register rs1, Register rs2, int16_t imm12);
  inline void beq(Register rs1, Register rs2, Label* L) {
    beq(rs1, rs2, branch_offset(L));
  }
  void bne(Register rs1, Register rs2, int16_t imm12);
  inline void bne(Register rs1, Register rs2, Label* L) {
    bne(rs1, rs2, branch_offset(L));
  }
  void blt(Register rs1, Register rs2, int16_t imm12);
  inline void blt(Register rs1, Register rs2, Label* L) {
    blt(rs1, rs2, branch_offset(L));
  }
  void bge(Register rs1, Register rs2, int16_t imm12);
  inline void bge(Register rs1, Register rs2, Label* L) {
    bge(rs1, rs2, branch_offset(L));
  }
  void bltu(Register rs1, Register rs2, int16_t imm12);
  inline void bltu(Register rs1, Register rs2, Label* L) {
    bltu(rs1, rs2, branch_offset(L));
  }
  void bgeu(Register rs1, Register rs2, int16_t imm12);
  inline void bgeu(Register rs1, Register rs2, Label* L) {
    bgeu(rs1, rs2, branch_offset(L));
  }

  // Loads
  void lb(Register rd, Register rs1, int16_t imm12);
  void lh(Register rd, Register rs1, int16_t imm12);
  void lw(Register rd, Register rs1, int16_t imm12);
  void lbu(Register rd, Register rs1, int16_t imm12);
  void lhu(Register rd, Register rs1, int16_t imm12);

  // Stores
  void sb(Register source, Register base, int16_t imm12);
  void sh(Register source, Register base, int16_t imm12);
  void sw(Register source, Register base, int16_t imm12);

  // Arithmetic with immediate
  void addi(Register rd, Register rs1, int16_t imm12);
  void slti(Register rd, Register rs1, int16_t imm12);
  void sltiu(Register rd, Register rs1, int16_t imm12);
  void xori(Register rd, Register rs1, int16_t imm12);
  void ori(Register rd, Register rs1, int16_t imm12);
  void andi(Register rd, Register rs1, int16_t imm12);
  void slli(Register rd, Register rs1, uint8_t shamt);
  void srli(Register rd, Register rs1, uint8_t shamt);
  void srai(Register rd, Register rs1, uint8_t shamt);

  // Arithmetic
  void add(Register rd, Register rs1, Register rs2);
  void sub(Register rd, Register rs1, Register rs2);
  void sll(Register rd, Register rs1, Register rs2);
  void slt(Register rd, Register rs1, Register rs2);
  void sltu(Register rd, Register rs1, Register rs2);
  void xor_(Register rd, Register rs1, Register rs2);
  void srl(Register rd, Register rs1, Register rs2);
  void sra(Register rd, Register rs1, Register rs2);
  void or_(Register rd, Register rs1, Register rs2);
  void and_(Register rd, Register rs1, Register rs2);

  // Memory fences
  void fence(uint8_t pred, uint8_t succ);
  void fence_tso();

  // Environment call / break
  void ecall();
  void ebreak();

  // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
  // instruction (i.e., it should always trap, if your implementation has
  // invalid instruction traps).
  void unimp();

  // CSR
  void csrrw(Register rd, ControlStatusReg csr, Register rs1);
  void csrrs(Register rd, ControlStatusReg csr, Register rs1);
  void csrrc(Register rd, ControlStatusReg csr, Register rs1);
  void csrrwi(Register rd, ControlStatusReg csr, uint8_t imm5);
  void csrrsi(Register rd, ControlStatusReg csr, uint8_t imm5);
  void csrrci(Register rd, ControlStatusReg csr, uint8_t imm5);

  // RV64I
  void lwu(Register rd, Register rs1, int16_t imm12);
  void ld(Register rd, Register rs1, int16_t imm12);
  void sd(Register source, Register base, int16_t imm12);
  void addiw(Register rd, Register rs1, int16_t imm12);
  void slliw(Register rd, Register rs1, uint8_t shamt);
  void srliw(Register rd, Register rs1, uint8_t shamt);
  void sraiw(Register rd, Register rs1, uint8_t shamt);
  void addw(Register rd, Register rs1, Register rs2);
  void subw(Register rd, Register rs1, Register rs2);
  void sllw(Register rd, Register rs1, Register rs2);
  void srlw(Register rd, Register rs1, Register rs2);
  void sraw(Register rd, Register rs1, Register rs2);

  // RV32M Standard Extension
  void mul(Register rd, Register rs1, Register rs2);
  void mulh(Register rd, Register rs1, Register rs2);
  void mulhsu(Register rd, Register rs1, Register rs2);
  void mulhu(Register rd, Register rs1, Register rs2);
  void div(Register rd, Register rs1, Register rs2);
  void divu(Register rd, Register rs1, Register rs2);
  void rem(Register rd, Register rs1, Register rs2);
  void remu(Register rd, Register rs1, Register rs2);

  // RV64M Standard Extension (in addition to RV32M)
  void mulw(Register rd, Register rs1, Register rs2);
  void divw(Register rd, Register rs1, Register rs2);
  void divuw(Register rd, Register rs1, Register rs2);
  void remw(Register rd, Register rs1, Register rs2);
  void remuw(Register rd, Register rs1, Register rs2);

  // RV32A Standard Extension
  void lr_w(bool aq, bool rl, Register rd, Register rs1);
  void sc_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoswap_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoadd_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoxor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoand_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomin_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomax_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amominu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomaxu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2);

  // RV64A Standard Extension (in addition to RV32A)
  void lr_d(bool aq, bool rl, Register rd, Register rs1);
  void sc_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoswap_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoadd_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoxor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoand_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amoor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomin_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomax_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amominu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);
  void amomaxu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2);

  // RV32F Standard Extension
  void flw(FPURegister rd, Register rs1, int16_t imm12);
  void fsw(FPURegister source, Register base, int16_t imm12);
  void fmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
535
               FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
536
  void fmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
537
               FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
538
  void fnmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
539
                FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
540
  void fnmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
541
                FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
542
  void fadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
543
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
544
  void fsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
545
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
546
  void fmul_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
547
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
548
  void fdiv_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
549 550
              FPURoundingMode frm = RNE);
  void fsqrt_s(FPURegister rd, FPURegister rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
551 552 553 554 555
  void fsgnj_s(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fsgnjn_s(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fsgnjx_s(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fmin_s(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fmax_s(FPURegister rd, FPURegister rs1, FPURegister rs2);
556 557
  void fcvt_w_s(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_wu_s(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
558 559 560 561 562
  void fmv_x_w(Register rd, FPURegister rs1);
  void feq_s(Register rd, FPURegister rs1, FPURegister rs2);
  void flt_s(Register rd, FPURegister rs1, FPURegister rs2);
  void fle_s(Register rd, FPURegister rs1, FPURegister rs2);
  void fclass_s(Register rd, FPURegister rs1);
563 564
  void fcvt_s_w(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
  void fcvt_s_wu(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
565 566 567
  void fmv_w_x(FPURegister rd, Register rs1);

  // RV64F Standard Extension (in addition to RV32F)
568 569 570 571
  void fcvt_l_s(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_lu_s(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_s_l(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
  void fcvt_s_lu(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
572 573 574 575 576

  // RV32D Standard Extension
  void fld(FPURegister rd, Register rs1, int16_t imm12);
  void fsd(FPURegister source, Register base, int16_t imm12);
  void fmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
577
               FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
578
  void fmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
579
               FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
580
  void fnmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
581
                FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
582
  void fnmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
583
                FPURegister rs3, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
584
  void fadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
585
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
586
  void fsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
587
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
588
  void fmul_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
589
              FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
590
  void fdiv_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
591 592
              FPURoundingMode frm = RNE);
  void fsqrt_d(FPURegister rd, FPURegister rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
593 594 595 596 597
  void fsgnj_d(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fsgnjn_d(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fsgnjx_d(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fmin_d(FPURegister rd, FPURegister rs1, FPURegister rs2);
  void fmax_d(FPURegister rd, FPURegister rs1, FPURegister rs2);
598 599
  void fcvt_s_d(FPURegister rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_d_s(FPURegister rd, FPURegister rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
600 601 602 603
  void feq_d(Register rd, FPURegister rs1, FPURegister rs2);
  void flt_d(Register rd, FPURegister rs1, FPURegister rs2);
  void fle_d(Register rd, FPURegister rs1, FPURegister rs2);
  void fclass_d(Register rd, FPURegister rs1);
604 605 606 607
  void fcvt_w_d(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_wu_d(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_d_w(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
  void fcvt_d_wu(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
608 609

  // RV64D Standard Extension (in addition to RV32D)
610 611
  void fcvt_l_d(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
  void fcvt_lu_d(Register rd, FPURegister rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
612
  void fmv_x_d(Register rd, FPURegister rs1);
613 614
  void fcvt_d_l(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
  void fcvt_d_lu(FPURegister rd, Register rs1, FPURoundingMode frm = RNE);
Brice Dobry's avatar
Brice Dobry committed
615 616 617 618 619 620 621 622 623 624
  void fmv_d_x(FPURegister rd, Register rs1);

  // RV64C Standard Extension
  void c_nop();
  void c_addi(Register rd, int8_t imm6);
  void c_addiw(Register rd, int8_t imm6);
  void c_addi16sp(int16_t imm10);
  void c_addi4spn(Register rd, int16_t uimm10);
  void c_li(Register rd, int8_t imm6);
  void c_lui(Register rd, int8_t imm6);
625
  void c_slli(Register rd, uint8_t shamt6);
Brice Dobry's avatar
Brice Dobry committed
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
  void c_fldsp(FPURegister rd, uint16_t uimm9);
  void c_lwsp(Register rd, uint16_t uimm8);
  void c_ldsp(Register rd, uint16_t uimm9);
  void c_jr(Register rs1);
  void c_mv(Register rd, Register rs2);
  void c_ebreak();
  void c_jalr(Register rs1);
  void c_j(int16_t imm12);
  inline void c_j(Label* L) { c_j(cjump_offset(L)); }
  void c_add(Register rd, Register rs2);
  void c_sub(Register rd, Register rs2);
  void c_and(Register rd, Register rs2);
  void c_xor(Register rd, Register rs2);
  void c_or(Register rd, Register rs2);
  void c_subw(Register rd, Register rs2);
  void c_addw(Register rd, Register rs2);
  void c_swsp(Register rs2, uint16_t uimm8);
  void c_sdsp(Register rs2, uint16_t uimm9);
  void c_fsdsp(FPURegister rs2, uint16_t uimm9);
  void c_lw(Register rd, Register rs1, uint16_t uimm7);
  void c_ld(Register rd, Register rs1, uint16_t uimm8);
  void c_fld(FPURegister rd, Register rs1, uint16_t uimm8);
  void c_sw(Register rs2, Register rs1, uint16_t uimm7);
  void c_sd(Register rs2, Register rs1, uint16_t uimm8);
  void c_fsd(FPURegister rs2, Register rs1, uint16_t uimm8);
651 652 653 654
  void c_bnez(Register rs1, int16_t imm9);
  inline void c_bnez(Register rs1, Label* L) { c_bnez(rs1, branch_offset(L)); }
  void c_beqz(Register rs1, int16_t imm9);
  inline void c_beqz(Register rs1, Label* L) { c_beqz(rs1, branch_offset(L)); }
655 656
  void c_srli(Register rs1, int8_t shamt6);
  void c_srai(Register rs1, int8_t shamt6);
657 658 659
  void c_andi(Register rs1, int8_t imm6);
  void NOP();
  void EBREAK();
Brice Dobry's avatar
Brice Dobry committed
660

661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
  // RVV
  static int32_t GenZimm(VSew vsew, Vlmul vlmul, TailAgnosticType tail = tu,
                         MaskAgnosticType mask = mu) {
    return (mask << 7) | (tail << 6) | ((vsew & 0x7) << 3) | (vlmul & 0x7);
  }

  void vl(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
          MaskType mask = NoMask);
  void vls(VRegister vd, Register rs1, Register rs2, VSew vsew,
           MaskType mask = NoMask);
  void vlx(VRegister vd, Register rs1, VRegister vs3, VSew vsew,
           MaskType mask = NoMask);

  void vs(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
          MaskType mask = NoMask);
  void vss(VRegister vd, Register rs1, Register rs2, VSew vsew,
           MaskType mask = NoMask);
  void vsx(VRegister vd, Register rs1, VRegister vs3, VSew vsew,
           MaskType mask = NoMask);

  void vsu(VRegister vd, Register rs1, VRegister vs3, VSew vsew,
           MaskType mask = NoMask);

#define SegInstr(OP)  \
  void OP##seg2(ARG); \
  void OP##seg3(ARG); \
  void OP##seg4(ARG); \
  void OP##seg5(ARG); \
  void OP##seg6(ARG); \
  void OP##seg7(ARG); \
  void OP##seg8(ARG);

#define ARG \
  VRegister vd, Register rs1, uint8_t lumop, VSew vsew, MaskType mask = NoMask

  SegInstr(vl) SegInstr(vs)
#undef ARG

#define ARG \
  VRegister vd, Register rs1, Register rs2, VSew vsew, MaskType mask = NoMask

      SegInstr(vls) SegInstr(vss)
#undef ARG

#define ARG \
  VRegister vd, Register rs1, VRegister rs2, VSew vsew, MaskType mask = NoMask

          SegInstr(vsx) SegInstr(vlx)
#undef ARG
#undef SegInstr

  // RVV Vector Arithmetic Instruction

  void vmv_vv(VRegister vd, VRegister vs1);
  void vmv_vx(VRegister vd, Register rs1);
  void vmv_vi(VRegister vd, uint8_t simm5);
  void vmv_xs(Register rd, VRegister vs2);
  void vmv_sx(VRegister vd, Register rs1);
  void vmerge_vv(VRegister vd, VRegister vs1, VRegister vs2);
  void vmerge_vx(VRegister vd, Register rs1, VRegister vs2);
  void vmerge_vi(VRegister vd, uint8_t imm5, VRegister vs2);

723 724 725 726 727 728 729 730 731
  void vredmaxu_vs(VRegister vd, VRegister vs2, VRegister vs1,
                   MaskType mask = NoMask);
  void vredmax_vs(VRegister vd, VRegister vs2, VRegister vs1,
                  MaskType mask = NoMask);
  void vredmin_vs(VRegister vd, VRegister vs2, VRegister vs1,
                  MaskType mask = NoMask);
  void vredminu_vs(VRegister vd, VRegister vs2, VRegister vs1,
                   MaskType mask = NoMask);

732 733 734 735 736 737 738 739
  void vadc_vv(VRegister vd, VRegister vs1, VRegister vs2);
  void vadc_vx(VRegister vd, Register rs1, VRegister vs2);
  void vadc_vi(VRegister vd, uint8_t imm5, VRegister vs2);

  void vmadc_vv(VRegister vd, VRegister vs1, VRegister vs2);
  void vmadc_vx(VRegister vd, Register rs1, VRegister vs2);
  void vmadc_vi(VRegister vd, uint8_t imm5, VRegister vs2);

740
  void vfmv_vf(VRegister vd, FPURegister fs1, MaskType mask = NoMask);
741 742 743 744 745
  void vfmv_fs(FPURegister fd, VRegister vs2);
  void vfmv_sf(VRegister vd, FPURegister fs);

  void vwaddu_wx(VRegister vd, VRegister vs2, Register rs1,
                 MaskType mask = NoMask);
746
  void vid_v(VRegister vd, MaskType mask = Mask);
747

748 749 750 751 752 753 754 755 756 757 758 759 760
#define DEFINE_OPIVV(name, funct6)                           \
  void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \
                 MaskType mask = NoMask);

#define DEFINE_OPIVX(name, funct6)                          \
  void name##_vx(VRegister vd, VRegister vs2, Register rs1, \
                 MaskType mask = NoMask);

#define DEFINE_OPIVI(name, funct6)                         \
  void name##_vi(VRegister vd, VRegister vs2, int8_t imm5, \
                 MaskType mask = NoMask);

#define DEFINE_OPMVV(name, funct6)                           \
761
  void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \
762 763 764 765 766 767
                 MaskType mask = NoMask);

#define DEFINE_OPMVX(name, funct6)                          \
  void name##_vx(VRegister vd, VRegister vs2, Register rs1, \
                 MaskType mask = NoMask);

768 769 770 771
#define DEFINE_OPFVV(name, funct6)                           \
  void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \
                 MaskType mask = NoMask);

772 773 774 775
#define DEFINE_OPFWV(name, funct6)                           \
  void name##_wv(VRegister vd, VRegister vs2, VRegister vs1, \
                 MaskType mask = NoMask);

776 777 778 779
#define DEFINE_OPFRED(name, funct6)                          \
  void name##_vs(VRegister vd, VRegister vs2, VRegister vs1, \
                 MaskType mask = NoMask);

780 781 782 783
#define DEFINE_OPFVF(name, funct6)                             \
  void name##_vf(VRegister vd, VRegister vs2, FPURegister fs1, \
                 MaskType mask = NoMask);

784 785 786 787
#define DEFINE_OPFWF(name, funct6)                             \
  void name##_wf(VRegister vd, VRegister vs2, FPURegister fs1, \
                 MaskType mask = NoMask);

788 789 790 791 792 793 794 795
#define DEFINE_OPFVV_FMA(name, funct6)                       \
  void name##_vv(VRegister vd, VRegister vs1, VRegister vs2, \
                 MaskType mask = NoMask);

#define DEFINE_OPFVF_FMA(name, funct6)                         \
  void name##_vf(VRegister vd, FPURegister fs1, VRegister vs2, \
                 MaskType mask = NoMask);

796 797 798
#define DEFINE_OPMVV_VIE(name) \
  void name(VRegister vd, VRegister vs2, MaskType mask = NoMask);

799 800 801 802 803
  DEFINE_OPIVV(vadd, VADD_FUNCT6)
  DEFINE_OPIVX(vadd, VADD_FUNCT6)
  DEFINE_OPIVI(vadd, VADD_FUNCT6)
  DEFINE_OPIVV(vsub, VSUB_FUNCT6)
  DEFINE_OPIVX(vsub, VSUB_FUNCT6)
804 805 806 807 808 809 810 811 812 813 814 815
  DEFINE_OPMVX(vdiv, VDIV_FUNCT6)
  DEFINE_OPMVX(vdivu, VDIVU_FUNCT6)
  DEFINE_OPMVX(vmul, VMUL_FUNCT6)
  DEFINE_OPMVX(vmulhu, VMULHU_FUNCT6)
  DEFINE_OPMVX(vmulhsu, VMULHSU_FUNCT6)
  DEFINE_OPMVX(vmulh, VMULH_FUNCT6)
  DEFINE_OPMVV(vdiv, VDIV_FUNCT6)
  DEFINE_OPMVV(vdivu, VDIVU_FUNCT6)
  DEFINE_OPMVV(vmul, VMUL_FUNCT6)
  DEFINE_OPMVV(vmulhu, VMULHU_FUNCT6)
  DEFINE_OPMVV(vmulhsu, VMULHSU_FUNCT6)
  DEFINE_OPMVV(vmulh, VMULH_FUNCT6)
816 817
  DEFINE_OPMVV(vwmul, VWMUL_FUNCT6)
  DEFINE_OPMVV(vwmulu, VWMULU_FUNCT6)
818
  DEFINE_OPMVV(vwaddu, VWADDU_FUNCT6)
819 820
  DEFINE_OPMVV(vwadd, VWADD_FUNCT6)
  DEFINE_OPMVV(vcompress, VCOMPRESS_FUNCT6)
821 822 823 824
  DEFINE_OPIVX(vsadd, VSADD_FUNCT6)
  DEFINE_OPIVV(vsadd, VSADD_FUNCT6)
  DEFINE_OPIVI(vsadd, VSADD_FUNCT6)
  DEFINE_OPIVX(vsaddu, VSADD_FUNCT6)
Lu Yahan's avatar
Lu Yahan committed
825 826
  DEFINE_OPIVV(vsaddu, VSADDU_FUNCT6)
  DEFINE_OPIVI(vsaddu, VSADDU_FUNCT6)
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
  DEFINE_OPIVX(vssub, VSSUB_FUNCT6)
  DEFINE_OPIVV(vssub, VSSUB_FUNCT6)
  DEFINE_OPIVX(vssubu, VSSUBU_FUNCT6)
  DEFINE_OPIVV(vssubu, VSSUBU_FUNCT6)
  DEFINE_OPIVX(vrsub, VRSUB_FUNCT6)
  DEFINE_OPIVI(vrsub, VRSUB_FUNCT6)
  DEFINE_OPIVV(vminu, VMINU_FUNCT6)
  DEFINE_OPIVX(vminu, VMINU_FUNCT6)
  DEFINE_OPIVV(vmin, VMIN_FUNCT6)
  DEFINE_OPIVX(vmin, VMIN_FUNCT6)
  DEFINE_OPIVV(vmaxu, VMAXU_FUNCT6)
  DEFINE_OPIVX(vmaxu, VMAXU_FUNCT6)
  DEFINE_OPIVV(vmax, VMAX_FUNCT6)
  DEFINE_OPIVX(vmax, VMAX_FUNCT6)
  DEFINE_OPIVV(vand, VAND_FUNCT6)
  DEFINE_OPIVX(vand, VAND_FUNCT6)
  DEFINE_OPIVI(vand, VAND_FUNCT6)
  DEFINE_OPIVV(vor, VOR_FUNCT6)
  DEFINE_OPIVX(vor, VOR_FUNCT6)
  DEFINE_OPIVI(vor, VOR_FUNCT6)
  DEFINE_OPIVV(vxor, VXOR_FUNCT6)
  DEFINE_OPIVX(vxor, VXOR_FUNCT6)
  DEFINE_OPIVI(vxor, VXOR_FUNCT6)
  DEFINE_OPIVV(vrgather, VRGATHER_FUNCT6)
  DEFINE_OPIVX(vrgather, VRGATHER_FUNCT6)
  DEFINE_OPIVI(vrgather, VRGATHER_FUNCT6)

  DEFINE_OPIVX(vslidedown, VSLIDEDOWN_FUNCT6)
  DEFINE_OPIVI(vslidedown, VSLIDEDOWN_FUNCT6)
  DEFINE_OPIVX(vslideup, VSLIDEUP_FUNCT6)
  DEFINE_OPIVI(vslideup, VSLIDEUP_FUNCT6)

  DEFINE_OPIVV(vmseq, VMSEQ_FUNCT6)
  DEFINE_OPIVX(vmseq, VMSEQ_FUNCT6)
  DEFINE_OPIVI(vmseq, VMSEQ_FUNCT6)

  DEFINE_OPIVV(vmsne, VMSNE_FUNCT6)
  DEFINE_OPIVX(vmsne, VMSNE_FUNCT6)
  DEFINE_OPIVI(vmsne, VMSNE_FUNCT6)

  DEFINE_OPIVV(vmsltu, VMSLTU_FUNCT6)
  DEFINE_OPIVX(vmsltu, VMSLTU_FUNCT6)

  DEFINE_OPIVV(vmslt, VMSLT_FUNCT6)
  DEFINE_OPIVX(vmslt, VMSLT_FUNCT6)

  DEFINE_OPIVV(vmsle, VMSLE_FUNCT6)
  DEFINE_OPIVX(vmsle, VMSLE_FUNCT6)
  DEFINE_OPIVI(vmsle, VMSLE_FUNCT6)

  DEFINE_OPIVV(vmsleu, VMSLEU_FUNCT6)
  DEFINE_OPIVX(vmsleu, VMSLEU_FUNCT6)
  DEFINE_OPIVI(vmsleu, VMSLEU_FUNCT6)

  DEFINE_OPIVI(vmsgt, VMSGT_FUNCT6)
  DEFINE_OPIVX(vmsgt, VMSGT_FUNCT6)

  DEFINE_OPIVI(vmsgtu, VMSGTU_FUNCT6)
  DEFINE_OPIVX(vmsgtu, VMSGTU_FUNCT6)

  DEFINE_OPIVV(vsrl, VSRL_FUNCT6)
  DEFINE_OPIVX(vsrl, VSRL_FUNCT6)
  DEFINE_OPIVI(vsrl, VSRL_FUNCT6)

891 892 893 894
  DEFINE_OPIVV(vsra, VSRA_FUNCT6)
  DEFINE_OPIVX(vsra, VSRA_FUNCT6)
  DEFINE_OPIVI(vsra, VSRA_FUNCT6)

895 896 897 898
  DEFINE_OPIVV(vsll, VSLL_FUNCT6)
  DEFINE_OPIVX(vsll, VSLL_FUNCT6)
  DEFINE_OPIVI(vsll, VSLL_FUNCT6)

899 900
  DEFINE_OPIVV(vsmul, VSMUL_FUNCT6)
  DEFINE_OPIVX(vsmul, VSMUL_FUNCT6)
901 902 903 904 905 906 907 908 909 910

  DEFINE_OPFVV(vfadd, VFADD_FUNCT6)
  DEFINE_OPFVF(vfadd, VFADD_FUNCT6)
  DEFINE_OPFVV(vfsub, VFSUB_FUNCT6)
  DEFINE_OPFVF(vfsub, VFSUB_FUNCT6)
  DEFINE_OPFVV(vfdiv, VFDIV_FUNCT6)
  DEFINE_OPFVF(vfdiv, VFDIV_FUNCT6)
  DEFINE_OPFVV(vfmul, VFMUL_FUNCT6)
  DEFINE_OPFVF(vfmul, VFMUL_FUNCT6)

911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
  // Vector Widening Floating-Point Add/Subtract Instructions
  DEFINE_OPFVV(vfwadd, VFWADD_FUNCT6)
  DEFINE_OPFVF(vfwadd, VFWADD_FUNCT6)
  DEFINE_OPFVV(vfwsub, VFWSUB_FUNCT6)
  DEFINE_OPFVF(vfwsub, VFWSUB_FUNCT6)
  DEFINE_OPFWV(vfwadd, VFWADD_W_FUNCT6)
  DEFINE_OPFWF(vfwadd, VFWADD_W_FUNCT6)
  DEFINE_OPFWV(vfwsub, VFWSUB_W_FUNCT6)
  DEFINE_OPFWF(vfwsub, VFWSUB_W_FUNCT6)

  // Vector Widening Floating-Point Reduction Instructions
  DEFINE_OPFVV(vfwredusum, VFWREDUSUM_FUNCT6)
  DEFINE_OPFVV(vfwredosum, VFWREDOSUM_FUNCT6)

  // Vector Widening Floating-Point Multiply
  DEFINE_OPFVV(vfwmul, VFWMUL_FUNCT6)
  DEFINE_OPFVF(vfwmul, VFWMUL_FUNCT6)

929 930 931 932 933 934
  DEFINE_OPFVV(vmfeq, VMFEQ_FUNCT6)
  DEFINE_OPFVV(vmfne, VMFNE_FUNCT6)
  DEFINE_OPFVV(vmflt, VMFLT_FUNCT6)
  DEFINE_OPFVV(vmfle, VMFLE_FUNCT6)
  DEFINE_OPFVV(vfmax, VMFMAX_FUNCT6)
  DEFINE_OPFVV(vfmin, VMFMIN_FUNCT6)
935
  DEFINE_OPFRED(vfredmax, VFREDMAX_FUNCT6)
936 937 938 939 940 941 942 943

  DEFINE_OPFVV(vfsngj, VFSGNJ_FUNCT6)
  DEFINE_OPFVF(vfsngj, VFSGNJ_FUNCT6)
  DEFINE_OPFVV(vfsngjn, VFSGNJN_FUNCT6)
  DEFINE_OPFVF(vfsngjn, VFSGNJN_FUNCT6)
  DEFINE_OPFVV(vfsngjx, VFSGNJX_FUNCT6)
  DEFINE_OPFVF(vfsngjx, VFSGNJX_FUNCT6)

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
  // Vector Single-Width Floating-Point Fused Multiply-Add Instructions
  DEFINE_OPFVV_FMA(vfmadd, VFMADD_FUNCT6)
  DEFINE_OPFVF_FMA(vfmadd, VFMADD_FUNCT6)
  DEFINE_OPFVV_FMA(vfmsub, VFMSUB_FUNCT6)
  DEFINE_OPFVF_FMA(vfmsub, VFMSUB_FUNCT6)
  DEFINE_OPFVV_FMA(vfmacc, VFMACC_FUNCT6)
  DEFINE_OPFVF_FMA(vfmacc, VFMACC_FUNCT6)
  DEFINE_OPFVV_FMA(vfmsac, VFMSAC_FUNCT6)
  DEFINE_OPFVF_FMA(vfmsac, VFMSAC_FUNCT6)
  DEFINE_OPFVV_FMA(vfnmadd, VFNMADD_FUNCT6)
  DEFINE_OPFVF_FMA(vfnmadd, VFNMADD_FUNCT6)
  DEFINE_OPFVV_FMA(vfnmsub, VFNMSUB_FUNCT6)
  DEFINE_OPFVF_FMA(vfnmsub, VFNMSUB_FUNCT6)
  DEFINE_OPFVV_FMA(vfnmacc, VFNMACC_FUNCT6)
  DEFINE_OPFVF_FMA(vfnmacc, VFNMACC_FUNCT6)
  DEFINE_OPFVV_FMA(vfnmsac, VFNMSAC_FUNCT6)
  DEFINE_OPFVF_FMA(vfnmsac, VFNMSAC_FUNCT6)

962 963 964 965 966 967 968 969 970 971
  // Vector Widening Floating-Point Fused Multiply-Add Instructions
  DEFINE_OPFVV_FMA(vfwmacc, VFWMACC_FUNCT6)
  DEFINE_OPFVF_FMA(vfwmacc, VFWMACC_FUNCT6)
  DEFINE_OPFVV_FMA(vfwnmacc, VFWNMACC_FUNCT6)
  DEFINE_OPFVF_FMA(vfwnmacc, VFWNMACC_FUNCT6)
  DEFINE_OPFVV_FMA(vfwmsac, VFWMSAC_FUNCT6)
  DEFINE_OPFVF_FMA(vfwmsac, VFWMSAC_FUNCT6)
  DEFINE_OPFVV_FMA(vfwnmsac, VFWNMSAC_FUNCT6)
  DEFINE_OPFVF_FMA(vfwnmsac, VFWNMSAC_FUNCT6)

972 973 974 975 976 977 978 979
  // Vector Narrowing Fixed-Point Clip Instructions
  DEFINE_OPIVV(vnclip, VNCLIP_FUNCT6)
  DEFINE_OPIVX(vnclip, VNCLIP_FUNCT6)
  DEFINE_OPIVI(vnclip, VNCLIP_FUNCT6)
  DEFINE_OPIVV(vnclipu, VNCLIPU_FUNCT6)
  DEFINE_OPIVX(vnclipu, VNCLIPU_FUNCT6)
  DEFINE_OPIVI(vnclipu, VNCLIPU_FUNCT6)

980 981 982 983 984 985 986 987
  // Vector Integer Extension
  DEFINE_OPMVV_VIE(vzext_vf8)
  DEFINE_OPMVV_VIE(vsext_vf8)
  DEFINE_OPMVV_VIE(vzext_vf4)
  DEFINE_OPMVV_VIE(vsext_vf4)
  DEFINE_OPMVV_VIE(vzext_vf2)
  DEFINE_OPMVV_VIE(vsext_vf2)

988 989 990 991 992
#undef DEFINE_OPIVI
#undef DEFINE_OPIVV
#undef DEFINE_OPIVX
#undef DEFINE_OPMVV
#undef DEFINE_OPMVX
993
#undef DEFINE_OPFVV
994
#undef DEFINE_OPFWV
995
#undef DEFINE_OPFVF
996
#undef DEFINE_OPFWF
997 998
#undef DEFINE_OPFVV_FMA
#undef DEFINE_OPFVF_FMA
999
#undef DEFINE_OPMVV_VIE
1000
#undef DEFINE_OPFRED
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010

#define DEFINE_VFUNARY(name, funct6, vs1)                          \
  void name(VRegister vd, VRegister vs2, MaskType mask = NoMask) { \
    GenInstrV(funct6, OP_FVV, vd, vs1, vs2, mask);                 \
  }

  DEFINE_VFUNARY(vfcvt_xu_f_v, VFUNARY0_FUNCT6, VFCVT_XU_F_V)
  DEFINE_VFUNARY(vfcvt_x_f_v, VFUNARY0_FUNCT6, VFCVT_X_F_V)
  DEFINE_VFUNARY(vfcvt_f_x_v, VFUNARY0_FUNCT6, VFCVT_F_X_V)
  DEFINE_VFUNARY(vfcvt_f_xu_v, VFUNARY0_FUNCT6, VFCVT_F_XU_V)
1011 1012 1013 1014 1015 1016
  DEFINE_VFUNARY(vfwcvt_xu_f_v, VFUNARY0_FUNCT6, VFWCVT_XU_F_V)
  DEFINE_VFUNARY(vfwcvt_x_f_v, VFUNARY0_FUNCT6, VFWCVT_X_F_V)
  DEFINE_VFUNARY(vfwcvt_f_x_v, VFUNARY0_FUNCT6, VFWCVT_F_X_V)
  DEFINE_VFUNARY(vfwcvt_f_xu_v, VFUNARY0_FUNCT6, VFWCVT_F_XU_V)
  DEFINE_VFUNARY(vfwcvt_f_f_v, VFUNARY0_FUNCT6, VFWCVT_F_F_V)

1017
  DEFINE_VFUNARY(vfncvt_f_f_w, VFUNARY0_FUNCT6, VFNCVT_F_F_W)
1018 1019
  DEFINE_VFUNARY(vfncvt_x_f_w, VFUNARY0_FUNCT6, VFNCVT_X_F_W)
  DEFINE_VFUNARY(vfncvt_xu_f_w, VFUNARY0_FUNCT6, VFNCVT_XU_F_W)
1020 1021

  DEFINE_VFUNARY(vfclass_v, VFUNARY1_FUNCT6, VFCLASS_V)
1022
  DEFINE_VFUNARY(vfsqrt_v, VFUNARY1_FUNCT6, VFSQRT_V)
1023 1024
  DEFINE_VFUNARY(vfrsqrt7_v, VFUNARY1_FUNCT6, VFRSQRT7_V)
  DEFINE_VFUNARY(vfrec7_v, VFUNARY1_FUNCT6, VFREC7_V)
1025
#undef DEFINE_VFUNARY
1026

1027 1028 1029
  void vnot_vv(VRegister dst, VRegister src, MaskType mask = NoMask) {
    vxor_vi(dst, src, -1, mask);
  }
1030

1031 1032 1033
  void vneg_vv(VRegister dst, VRegister src, MaskType mask = NoMask) {
    vrsub_vx(dst, src, zero_reg, mask);
  }
1034

1035 1036 1037 1038 1039 1040
  void vfneg_vv(VRegister dst, VRegister src, MaskType mask = NoMask) {
    vfsngjn_vv(dst, src, src, mask);
  }
  void vfabs_vv(VRegister dst, VRegister src, MaskType mask = NoMask) {
    vfsngjx_vv(dst, src, src, mask);
  }
1041 1042 1043 1044
  void vfirst_m(Register rd, VRegister vs2, MaskType mask = NoMask);

  void vcpop_m(Register rd, VRegister vs2, MaskType mask = NoMask);

Brice Dobry's avatar
Brice Dobry committed
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
  // Privileged
  void uret();
  void sret();
  void mret();
  void wfi();
  void sfence_vma(Register rs1, Register rs2);

  // Assembler Pseudo Instructions (Tables 25.2, 25.3, RISC-V Unprivileged ISA)
  void nop();
  void RV_li(Register rd, int64_t imm);
  // Returns the number of instructions required to load the immediate
  static int li_estimate(int64_t imm, bool is_get_temp_reg = false);
  // Loads an immediate, always using 8 instructions, regardless of the value,
  // so that it can be modified later.
  void li_constant(Register rd, int64_t imm);
  void li_ptr(Register rd, int64_t imm);

  void mv(Register rd, Register rs) { addi(rd, rs, 0); }
  void not_(Register rd, Register rs) { xori(rd, rs, -1); }
  void neg(Register rd, Register rs) { sub(rd, zero_reg, rs); }
  void negw(Register rd, Register rs) { subw(rd, zero_reg, rs); }
  void sext_w(Register rd, Register rs) { addiw(rd, rs, 0); }
  void seqz(Register rd, Register rs) { sltiu(rd, rs, 1); }
  void snez(Register rd, Register rs) { sltu(rd, zero_reg, rs); }
  void sltz(Register rd, Register rs) { slt(rd, rs, zero_reg); }
  void sgtz(Register rd, Register rs) { slt(rd, zero_reg, rs); }

  void fmv_s(FPURegister rd, FPURegister rs) { fsgnj_s(rd, rs, rs); }
  void fabs_s(FPURegister rd, FPURegister rs) { fsgnjx_s(rd, rs, rs); }
  void fneg_s(FPURegister rd, FPURegister rs) { fsgnjn_s(rd, rs, rs); }
  void fmv_d(FPURegister rd, FPURegister rs) { fsgnj_d(rd, rs, rs); }
  void fabs_d(FPURegister rd, FPURegister rs) { fsgnjx_d(rd, rs, rs); }
  void fneg_d(FPURegister rd, FPURegister rs) { fsgnjn_d(rd, rs, rs); }

  void beqz(Register rs, int16_t imm13) { beq(rs, zero_reg, imm13); }
  inline void beqz(Register rs1, Label* L) { beqz(rs1, branch_offset(L)); }
  void bnez(Register rs, int16_t imm13) { bne(rs, zero_reg, imm13); }
  inline void bnez(Register rs1, Label* L) { bnez(rs1, branch_offset(L)); }
  void blez(Register rs, int16_t imm13) { bge(zero_reg, rs, imm13); }
  inline void blez(Register rs1, Label* L) { blez(rs1, branch_offset(L)); }
  void bgez(Register rs, int16_t imm13) { bge(rs, zero_reg, imm13); }
  inline void bgez(Register rs1, Label* L) { bgez(rs1, branch_offset(L)); }
  void bltz(Register rs, int16_t imm13) { blt(rs, zero_reg, imm13); }
  inline void bltz(Register rs1, Label* L) { bltz(rs1, branch_offset(L)); }
  void bgtz(Register rs, int16_t imm13) { blt(zero_reg, rs, imm13); }

  inline void bgtz(Register rs1, Label* L) { bgtz(rs1, branch_offset(L)); }
  void bgt(Register rs1, Register rs2, int16_t imm13) { blt(rs2, rs1, imm13); }
  inline void bgt(Register rs1, Register rs2, Label* L) {
    bgt(rs1, rs2, branch_offset(L));
  }
  void ble(Register rs1, Register rs2, int16_t imm13) { bge(rs2, rs1, imm13); }
  inline void ble(Register rs1, Register rs2, Label* L) {
    ble(rs1, rs2, branch_offset(L));
  }
  void bgtu(Register rs1, Register rs2, int16_t imm13) {
    bltu(rs2, rs1, imm13);
  }
  inline void bgtu(Register rs1, Register rs2, Label* L) {
    bgtu(rs1, rs2, branch_offset(L));
  }
  void bleu(Register rs1, Register rs2, int16_t imm13) {
    bgeu(rs2, rs1, imm13);
  }
  inline void bleu(Register rs1, Register rs2, Label* L) {
    bleu(rs1, rs2, branch_offset(L));
  }

  void j(int32_t imm21) { jal(zero_reg, imm21); }
  inline void j(Label* L) { j(jump_offset(L)); }
  inline void b(Label* L) { j(L); }
  void jal(int32_t imm21) { jal(ra, imm21); }
  inline void jal(Label* L) { jal(jump_offset(L)); }
  void jr(Register rs) { jalr(zero_reg, rs, 0); }
  void jr(Register rs, int32_t imm12) { jalr(zero_reg, rs, imm12); }
  void jalr(Register rs, int32_t imm12) { jalr(ra, rs, imm12); }
  void jalr(Register rs) { jalr(ra, rs, 0); }
  void ret() { jalr(zero_reg, ra, 0); }
  void call(int32_t offset) {
    auipc(ra, (offset >> 12) + ((offset & 0x800) >> 11));
    jalr(ra, ra, offset << 20 >> 20);
  }

  // Read instructions-retired counter
  void rdinstret(Register rd) { csrrs(rd, csr_instret, zero_reg); }
  void rdinstreth(Register rd) { csrrs(rd, csr_instreth, zero_reg); }
  void rdcycle(Register rd) { csrrs(rd, csr_cycle, zero_reg); }
  void rdcycleh(Register rd) { csrrs(rd, csr_cycleh, zero_reg); }
  void rdtime(Register rd) { csrrs(rd, csr_time, zero_reg); }
  void rdtimeh(Register rd) { csrrs(rd, csr_timeh, zero_reg); }

  void csrr(Register rd, ControlStatusReg csr) { csrrs(rd, csr, zero_reg); }
  void csrw(ControlStatusReg csr, Register rs) { csrrw(zero_reg, csr, rs); }
  void csrs(ControlStatusReg csr, Register rs) { csrrs(zero_reg, csr, rs); }
  void csrc(ControlStatusReg csr, Register rs) { csrrc(zero_reg, csr, rs); }

  void csrwi(ControlStatusReg csr, uint8_t imm) { csrrwi(zero_reg, csr, imm); }
  void csrsi(ControlStatusReg csr, uint8_t imm) { csrrsi(zero_reg, csr, imm); }
  void csrci(ControlStatusReg csr, uint8_t imm) { csrrci(zero_reg, csr, imm); }

  void frcsr(Register rd) { csrrs(rd, csr_fcsr, zero_reg); }
  void fscsr(Register rd, Register rs) { csrrw(rd, csr_fcsr, rs); }
  void fscsr(Register rs) { csrrw(zero_reg, csr_fcsr, rs); }

  void frrm(Register rd) { csrrs(rd, csr_frm, zero_reg); }
  void fsrm(Register rd, Register rs) { csrrw(rd, csr_frm, rs); }
  void fsrm(Register rs) { csrrw(zero_reg, csr_frm, rs); }

  void frflags(Register rd) { csrrs(rd, csr_fflags, zero_reg); }
  void fsflags(Register rd, Register rs) { csrrw(rd, csr_fflags, rs); }
  void fsflags(Register rs) { csrrw(zero_reg, csr_fflags, rs); }

  // Other pseudo instructions that are not part of RISCV pseudo assemly
  void nor(Register rd, Register rs, Register rt) {
    or_(rd, rs, rt);
    not_(rd, rd);
  }

  void sync() { fence(0b1111, 0b1111); }
  void break_(uint32_t code, bool break_as_stop = false);
  void stop(uint32_t code = kMaxStopCode);

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

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

  using BlockConstPoolScope = ConstantPool::BlockScope;
  // Class for scoping postponing the trampoline pool generation.
  class BlockTrampolinePoolScope {
   public:
    explicit BlockTrampolinePoolScope(Assembler* assem, int margin = 0)
        : assem_(assem) {
      assem_->StartBlockTrampolinePool();
    }

    explicit BlockTrampolinePoolScope(Assembler* assem, PoolEmissionCheck check)
        : assem_(assem) {
      assem_->StartBlockTrampolinePool();
    }
    ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }

   private:
    Assembler* assem_;
    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
  };

  // 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();
    }
    ~BlockGrowBufferScope() { assem_->EndBlockGrowBuffer(); }

   private:
    Assembler* assem_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope);
  };

  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
1216 1217
  void RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id,
                         SourcePosition position, int id);
Brice Dobry's avatar
Brice Dobry committed
1218 1219 1220

  static int RelocateInternalReference(RelocInfo::Mode rmode, Address pc,
                                       intptr_t pc_delta);
1221 1222
  static void RelocateRelativeReference(RelocInfo::Mode rmode, Address pc,
                                        intptr_t pc_delta);
Brice Dobry's avatar
Brice Dobry committed
1223 1224 1225 1226

  // 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);
1227 1228 1229
  void dd(uint32_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO);
  void dq(uint64_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO);
  void dp(uintptr_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO) {
Brice Dobry's avatar
Brice Dobry committed
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
    dq(data, rmode);
  }
  void dd(Label* label);

  Instruction* pc() const { return reinterpret_cast<Instruction*>(pc_); }

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

  // 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 intptr_t available_space() const {
    return reloc_info_writer.pos() - pc_;
  }

  // Read/patch instructions.
  static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); }
  static void instr_at_put(Address pc, Instr instr) {
    *reinterpret_cast<Instr*>(pc) = instr;
  }
  Instr instr_at(int pos) {
    return *reinterpret_cast<Instr*>(buffer_start_ + pos);
  }
  void instr_at_put(int pos, Instr instr) {
    *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
  }

  void instr_at_put(int pos, ShortInstr instr) {
    *reinterpret_cast<ShortInstr*>(buffer_start_ + pos) = instr;
  }

  Address toAddress(int pos) {
    return reinterpret_cast<Address>(buffer_start_ + pos);
  }

  // Check if an instruction is a branch of some kind.
  static bool IsBranch(Instr instr);
1272
  static bool IsCBranch(Instr instr);
1273
  static bool IsNop(Instr instr);
Brice Dobry's avatar
Brice Dobry committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
  static bool IsJump(Instr instr);
  static bool IsJal(Instr instr);
  static bool IsCJal(Instr instr);
  static bool IsJalr(Instr instr);
  static bool IsLui(Instr instr);
  static bool IsAuipc(Instr instr);
  static bool IsAddiw(Instr instr);
  static bool IsAddi(Instr instr);
  static bool IsOri(Instr instr);
  static bool IsSlli(Instr instr);
  static bool IsLd(Instr instr);
  void CheckTrampolinePool();

1287 1288 1289 1290
  // 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;

Brice Dobry's avatar
Brice Dobry committed
1291 1292
  inline int UnboundLabelsCount() { return unbound_labels_count_; }

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
  using BlockPoolsScope = BlockTrampolinePoolScope;

  void RecordConstPool(int size);

  void ForceConstantPoolEmissionWithoutJump() {
    constpool_.Check(Emission::kForced, Jump::kOmitted);
  }
  void ForceConstantPoolEmissionWithJump() {
    constpool_.Check(Emission::kForced, Jump::kRequired);
  }
  // Check if the const pool needs to be emitted while pretending that {margin}
  // more bytes of instructions have already been emitted.
  void EmitConstPoolWithJumpIfNeeded(size_t margin = 0) {
    constpool_.Check(Emission::kIfNeeded, Jump::kRequired, margin);
  }

  void EmitConstPoolWithoutJumpIfNeeded(size_t margin = 0) {
    constpool_.Check(Emission::kIfNeeded, Jump::kOmitted, margin);
  }

  void RecordEntry(uint32_t data, RelocInfo::Mode rmode) {
    constpool_.RecordEntry(data, rmode);
  }

  void RecordEntry(uint64_t data, RelocInfo::Mode rmode) {
    constpool_.RecordEntry(data, rmode);
  }

1321
  friend class VectorUnit;
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
  class VectorUnit {
   public:
    inline int32_t sew() const { return 2 ^ (sew_ + 3); }

    inline int32_t vlmax() const {
      if ((lmul_ & 0b100) != 0) {
        return (kRvvVLEN / sew()) >> (lmul_ & 0b11);
      } else {
        return ((kRvvVLEN << lmul_) / sew());
      }
    }

    explicit VectorUnit(Assembler* assm) : assm_(assm) {}

    void set(Register rd, VSew sew, Vlmul lmul) {
      if (sew != sew_ || lmul != lmul_ || vl != vlmax()) {
        sew_ = sew;
        lmul_ = lmul;
        vl = vlmax();
        assm_->vsetvlmax(rd, sew_, lmul_);
      }
    }

1345 1346 1347 1348 1349 1350 1351 1352
    void set(Register rd, int8_t sew, int8_t lmul) {
      DCHECK_GE(sew, E8);
      DCHECK_LE(sew, E64);
      DCHECK_GE(lmul, m1);
      DCHECK_LE(lmul, mf2);
      set(rd, VSew(sew), Vlmul(lmul));
    }

1353
    void set(FPURoundingMode mode) {
1354 1355 1356 1357 1358 1359
      if (mode_ != mode) {
        assm_->addi(kScratchReg, zero_reg, mode << kFcsrFrmShift);
        assm_->fscsr(kScratchReg);
        mode_ = mode;
      }
    }
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
    void set(Register rd, Register rs1, VSew sew, Vlmul lmul) {
      if (sew != sew_ || lmul != lmul_) {
        sew_ = sew;
        lmul_ = lmul;
        vl = 0;
        assm_->vsetvli(rd, rs1, sew_, lmul_);
      }
    }

    void set(VSew sew, Vlmul lmul) {
      if (sew != sew_ || lmul != lmul_) {
        sew_ = sew;
        lmul_ = lmul;
        assm_->vsetvl(sew_, lmul_);
      }
    }

   private:
    VSew sew_ = E8;
    Vlmul lmul_ = m1;
    int32_t vl = 0;
    Assembler* assm_;
1382
    FPURoundingMode mode_ = RNE;
1383 1384 1385 1386
  };

  VectorUnit VU;

1387 1388 1389 1390 1391 1392 1393 1394
  void CheckTrampolinePoolQuick(int extra_instructions = 0) {
    DEBUG_PRINTF("\tpc_offset:%d %d\n", pc_offset(),
                 next_buffer_check_ - extra_instructions * kInstrSize);
    if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
      CheckTrampolinePool();
    }
  }

Brice Dobry's avatar
Brice Dobry committed
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
 protected:
  // 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
  };

  // Determine whether need to adjust base and offset of memroy load/store
  bool NeedAdjustBaseAndOffset(
      const MemOperand& src, OffsetAccessType = OffsetAccessType::SINGLE_ACCESS,
      int second_Access_add_to_offset = 4);

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

  inline static void set_target_internal_reference_encoded_at(Address pc,
                                                              Address target);

  int64_t buffer_space() const { return reloc_info_writer.pos() - pc_; }

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

  // Patch branch instruction at pos to branch to given branch target pos.
1423 1424
  void target_at_put(int pos, int target_pos, bool is_internal,
                     bool trampoline = false);
Brice Dobry's avatar
Brice Dobry committed
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473

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

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

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

  void StartBlockTrampolinePool() {
    DEBUG_PRINTF("\tStartBlockTrampolinePool\n");
    trampoline_pool_blocked_nesting_++;
  }

  void EndBlockTrampolinePool() {
    trampoline_pool_blocked_nesting_--;
    DEBUG_PRINTF("\ttrampoline_pool_blocked_nesting:%d\n",
                 trampoline_pool_blocked_nesting_);
    if (trampoline_pool_blocked_nesting_ == 0) {
      CheckTrampolinePoolQuick(1);
    }
  }

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

  bool has_exception() const { return internal_trampoline_exception_; }

  bool is_trampoline_emitted() const { return trampoline_emitted_; }

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

  void EndBlockGrowBuffer() {
    DCHECK(block_buffer_growth_);
    block_buffer_growth_ = false;
  }

  bool is_buffer_growth_blocked() const { return block_buffer_growth_; }

 private:
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
  void vsetvli(Register rd, Register rs1, VSew vsew, Vlmul vlmul,
               TailAgnosticType tail = tu, MaskAgnosticType mask = mu);

  void vsetivli(Register rd, uint8_t uimm, VSew vsew, Vlmul vlmul,
                TailAgnosticType tail = tu, MaskAgnosticType mask = mu);

  inline void vsetvlmax(Register rd, VSew vsew, Vlmul vlmul,
                        TailAgnosticType tail = tu,
                        MaskAgnosticType mask = mu) {
    vsetvli(rd, zero_reg, vsew, vlmul, tu, mu);
  }

  inline void vsetvl(VSew vsew, Vlmul vlmul, TailAgnosticType tail = tu,
                     MaskAgnosticType mask = mu) {
    vsetvli(zero_reg, zero_reg, vsew, vlmul, tu, mu);
  }

  void vsetvl(Register rd, Register rs1, Register rs2);

Brice Dobry's avatar
Brice Dobry committed
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512 * MB;

  // Buffer size and constant pool distance are checked together at regular
  // intervals of kBufferCheckInterval emitted bytes.
  static constexpr int kBufferCheckInterval = 1 * KB / 2;

  // 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.
  static constexpr int kGap = 64;
1506
  static_assert(AssemblerBase::kMinimalBufferSize >= 2 * kGap);
Brice Dobry's avatar
Brice Dobry committed
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563

  // 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.
  static constexpr int kCheckConstIntervalInst = 32;
  static constexpr int kCheckConstInterval =
      kCheckConstIntervalInst * kInstrSize;

  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.

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

  // Relocation information generation.
  // Each relocation is encoded as a variable size value.
  static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
  RelocInfoWriter reloc_info_writer;

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

  // Code emission.
  inline void CheckBuffer();
  void GrowBuffer();
  inline void emit(Instr x);
  inline void emit(ShortInstr x);
  inline void emit(uint64_t x);
  template <typename T>
  inline void EmitHelper(T x);

  static void disassembleInstr(Instr instr);

  // Instruction generation.

  // ----- Top-level instruction formats match those in the ISA manual
  // (R, I, S, B, U, J). These match the formats defined in LLVM's
  // RISCVInstrFormats.td.
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd,
                 Register rs1, Register rs2);
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd,
                 FPURegister rs1, FPURegister rs2);
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd,
                 FPURegister rs1, Register rs2);
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd,
                 Register rs1, Register rs2);
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd,
                 FPURegister rs1, Register rs2);
  void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd,
                 FPURegister rs1, FPURegister rs2);
  void GenInstrR4(uint8_t funct2, Opcode opcode, Register rd, Register rs1,
1564
                  Register rs2, Register rs3, FPURoundingMode frm);
Brice Dobry's avatar
Brice Dobry committed
1565 1566
  void GenInstrR4(uint8_t funct2, Opcode opcode, FPURegister rd,
                  FPURegister rs1, FPURegister rs2, FPURegister rs3,
1567
                  FPURoundingMode frm);
Brice Dobry's avatar
Brice Dobry committed
1568 1569 1570
  void GenInstrRAtomic(uint8_t funct5, bool aq, bool rl, uint8_t funct3,
                       Register rd, Register rs1, Register rs2);
  void GenInstrRFrm(uint8_t funct7, Opcode opcode, Register rd, Register rs1,
1571
                    Register rs2, FPURoundingMode frm);
Brice Dobry's avatar
Brice Dobry committed
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
  void GenInstrI(uint8_t funct3, Opcode opcode, Register rd, Register rs1,
                 int16_t imm12);
  void GenInstrI(uint8_t funct3, Opcode opcode, FPURegister rd, Register rs1,
                 int16_t imm12);
  void GenInstrIShift(bool arithshift, uint8_t funct3, Opcode opcode,
                      Register rd, Register rs1, uint8_t shamt);
  void GenInstrIShiftW(bool arithshift, uint8_t funct3, Opcode opcode,
                       Register rd, Register rs1, uint8_t shamt);
  void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, Register rs2,
                 int16_t imm12);
  void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, FPURegister rs2,
                 int16_t imm12);
  void GenInstrB(uint8_t funct3, Opcode opcode, Register rs1, Register rs2,
                 int16_t imm12);
  void GenInstrU(Opcode opcode, Register rd, int32_t imm20);
  void GenInstrJ(Opcode opcode, Register rd, int32_t imm20);
  void GenInstrCR(uint8_t funct4, Opcode opcode, Register rd, Register rs2);
  void GenInstrCA(uint8_t funct6, Opcode opcode, Register rd, uint8_t funct,
                  Register rs2);
  void GenInstrCI(uint8_t funct3, Opcode opcode, Register rd, int8_t imm6);
  void GenInstrCIU(uint8_t funct3, Opcode opcode, Register rd, uint8_t uimm6);
  void GenInstrCIU(uint8_t funct3, Opcode opcode, FPURegister rd,
                   uint8_t uimm6);
  void GenInstrCIW(uint8_t funct3, Opcode opcode, Register rd, uint8_t uimm8);
  void GenInstrCSS(uint8_t funct3, Opcode opcode, FPURegister rs2,
                   uint8_t uimm6);
  void GenInstrCSS(uint8_t funct3, Opcode opcode, Register rs2, uint8_t uimm6);
  void GenInstrCL(uint8_t funct3, Opcode opcode, Register rd, Register rs1,
                  uint8_t uimm5);
  void GenInstrCL(uint8_t funct3, Opcode opcode, FPURegister rd, Register rs1,
                  uint8_t uimm5);
  void GenInstrCS(uint8_t funct3, Opcode opcode, Register rs2, Register rs1,
                  uint8_t uimm5);
  void GenInstrCS(uint8_t funct3, Opcode opcode, FPURegister rs2, Register rs1,
                  uint8_t uimm5);
  void GenInstrCJ(uint8_t funct3, Opcode opcode, uint16_t uint11);
1608 1609
  void GenInstrCB(uint8_t funct3, Opcode opcode, Register rs1, uint8_t uimm8);
  void GenInstrCBA(uint8_t funct3, uint8_t funct2, Opcode opcode, Register rs1,
1610
                   int8_t imm6);
Brice Dobry's avatar
Brice Dobry committed
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647

  // ----- Instruction class templates match those in LLVM's RISCVInstrInfo.td
  void GenInstrBranchCC_rri(uint8_t funct3, Register rs1, Register rs2,
                            int16_t imm12);
  void GenInstrLoad_ri(uint8_t funct3, Register rd, Register rs1,
                       int16_t imm12);
  void GenInstrStore_rri(uint8_t funct3, Register rs1, Register rs2,
                         int16_t imm12);
  void GenInstrALU_ri(uint8_t funct3, Register rd, Register rs1, int16_t imm12);
  void GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd,
                        Register rs1, uint8_t shamt);
  void GenInstrALU_rr(uint8_t funct7, uint8_t funct3, Register rd, Register rs1,
                      Register rs2);
  void GenInstrCSR_ir(uint8_t funct3, Register rd, ControlStatusReg csr,
                      Register rs1);
  void GenInstrCSR_ii(uint8_t funct3, Register rd, ControlStatusReg csr,
                      uint8_t rs1);
  void GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd,
                         Register rs1, uint8_t shamt);
  void GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, Register rd,
                       Register rs1, Register rs2);
  void GenInstrPriv(uint8_t funct7, Register rs1, Register rs2);
  void GenInstrLoadFP_ri(uint8_t funct3, FPURegister rd, Register rs1,
                         int16_t imm12);
  void GenInstrStoreFP_rri(uint8_t funct3, Register rs1, FPURegister rs2,
                           int16_t imm12);
  void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
                        FPURegister rs1, FPURegister rs2);
  void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
                        Register rs1, Register rs2);
  void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
                        FPURegister rs1, Register rs2);
  void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd,
                        FPURegister rs1, Register rs2);
  void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd,
                        FPURegister rs1, FPURegister rs2);

1648 1649 1650 1651 1652 1653 1654 1655
  // ----------------------------RVV------------------------------------------
  // vsetvl
  void GenInstrV(Register rd, Register rs1, Register rs2);
  // vsetvli
  void GenInstrV(Register rd, Register rs1, uint32_t zimm);
  // OPIVV OPFVV OPMVV
  void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, VRegister vs1,
                 VRegister vs2, MaskType mask = NoMask);
1656 1657
  void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, int8_t vs1,
                 VRegister vs2, MaskType mask = NoMask);
1658 1659
  void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, VRegister vs2,
                 MaskType mask = NoMask);
1660 1661 1662
  // OPMVV OPFVV
  void GenInstrV(uint8_t funct6, Opcode opcode, Register rd, VRegister vs1,
                 VRegister vs2, MaskType mask = NoMask);
1663 1664 1665
  // OPFVV
  void GenInstrV(uint8_t funct6, Opcode opcode, FPURegister fd, VRegister vs1,
                 VRegister vs2, MaskType mask = NoMask);
1666

1667
  // OPIVX OPMVX
1668 1669
  void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, Register rs1,
                 VRegister vs2, MaskType mask = NoMask);
1670 1671 1672
  // OPFVF
  void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, FPURegister fs1,
                 VRegister vs2, MaskType mask = NoMask);
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
  // OPMVX
  void GenInstrV(uint8_t funct6, Register rd, Register rs1, VRegister vs2,
                 MaskType mask = NoMask);
  // OPIVI
  void GenInstrV(uint8_t funct6, VRegister vd, int8_t simm5, VRegister vs2,
                 MaskType mask = NoMask);

  // VL VS
  void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1,
                 uint8_t umop, MaskType mask, uint8_t IsMop, bool IsMew,
                 uint8_t Nf);

  void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1,
                 Register rs2, MaskType mask, uint8_t IsMop, bool IsMew,
                 uint8_t Nf);
  // VL VS AMO
  void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1,
                 VRegister vs2, MaskType mask, uint8_t IsMop, bool IsMew,
                 uint8_t Nf);
1692 1693 1694
  // vmv_xs vcpop_m vfirst_m
  void GenInstrV(uint8_t funct6, Opcode opcode, Register rd, uint8_t vs1,
                 VRegister vs2, MaskType mask);
Brice Dobry's avatar
Brice Dobry committed
1695 1696 1697 1698 1699 1700 1701 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 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795
  // Labels.
  void print(const Label* L);
  void bind_to(Label* L, int pos);
  void next(Label* L, bool is_internal);

  // One trampoline consists of:
  // - space for trampoline slots,
  // - space for labels.
  //
  // Space for trampoline slots is equal to slot_count * 2 * kInstrSize.
  // Space for trampoline slots precedes space for labels. Each label is of one
  // instruction size, so total amount for labels is equal to
  // label_count *  kInstrSize.
  class Trampoline {
   public:
    Trampoline() {
      start_ = 0;
      next_slot_ = 0;
      free_slot_count_ = 0;
      end_ = 0;
    }
    Trampoline(int start, int slot_count) {
      start_ = start;
      next_slot_ = start;
      free_slot_count_ = slot_count;
      end_ = start + slot_count * kTrampolineSlotsSize;
    }
    int start() { return start_; }
    int end() { return end_; }
    int take_slot() {
      int trampoline_slot = kInvalidSlotPos;
      if (free_slot_count_ <= 0) {
        // We have run out of space on trampolines.
        // Make sure we fail in debug mode, so we become aware of each case
        // when this happens.
        DCHECK(0);
        // Internal exception will be caught.
      } else {
        trampoline_slot = next_slot_;
        free_slot_count_--;
        next_slot_ += kTrampolineSlotsSize;
      }
      return trampoline_slot;
    }

   private:
    int start_;
    int end_;
    int next_slot_;
    int free_slot_count_;
  };

  int32_t get_trampoline_entry(int32_t pos);
  int unbound_labels_count_;
  // After trampoline is emitted, long branches are used in generated code for
  // the forward branches whose target offsets could be beyond reach of branch
  // instruction. 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_ = false;
  static constexpr int kInvalidSlotPos = -1;

  // Internal reference positions, required for unbounded internal reference
  // labels.
  std::set<int64_t> internal_reference_positions_;
  bool is_internal_reference(Label* L) {
    return internal_reference_positions_.find(L->pos()) !=
           internal_reference_positions_.end();
  }

  Trampoline trampoline_;
  bool internal_trampoline_exception_;

  RegList scratch_register_list_;

 private:
  ConstantPool constpool_;

  void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);

  int WriteCodeComments();

  friend class RegExpMacroAssemblerRISCV;
  friend class RelocInfo;
  friend class BlockTrampolinePoolScope;
  friend class EnsureSpace;
  friend class ConstantPool;
};

class EnsureSpace {
 public:
  explicit inline EnsureSpace(Assembler* assembler);
};

class V8_EXPORT_PRIVATE UseScratchRegisterScope {
 public:
  explicit UseScratchRegisterScope(Assembler* assembler);
  ~UseScratchRegisterScope();

  Register Acquire();
  bool hasAvailable() const;
1796
  void Include(const RegList& list) { *available_ |= list; }
1797 1798 1799
  void Exclude(const RegList& list) {
    *available_ &= RegList::FromBits(~list.bits());
  }
1800
  void Include(const Register& reg1, const Register& reg2 = no_reg) {
1801
    RegList list({reg1, reg2});
1802 1803 1804
    Include(list);
  }
  void Exclude(const Register& reg1, const Register& reg2 = no_reg) {
1805
    RegList list({reg1, reg2});
1806 1807
    Exclude(list);
  }
Brice Dobry's avatar
Brice Dobry committed
1808 1809 1810 1811 1812 1813

 private:
  RegList* available_;
  RegList old_available_;
};

1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
class LoadStoreLaneParams {
 public:
  int sz;
  uint8_t laneidx;

  LoadStoreLaneParams(MachineRepresentation rep, uint8_t laneidx);

 private:
  LoadStoreLaneParams(uint8_t laneidx, int sz, int lanes)
      : sz(sz), laneidx(laneidx % lanes) {}
};

Brice Dobry's avatar
Brice Dobry committed
1826 1827 1828 1829
}  // namespace internal
}  // namespace v8

#endif  // V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_