1 // Copyright (c) 1994-2006 Sun Microsystems Inc. 2 // All Rights Reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // - Redistributions of source code must retain the above copyright notice, 9 // this list of conditions and the following disclaimer. 10 // 11 // - Redistribution in binary form must reproduce the above copyright 12 // notice, this list of conditions and the following disclaimer in the 13 // documentation and/or other materials provided with the distribution. 14 // 15 // - Neither the name of Sun Microsystems or the names of contributors may 16 // be used to endorse or promote products derived from this software without 17 // specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // The original source code covered by the above license above has been 32 // modified significantly by Google Inc. 33 // Copyright 2021 the V8 project authors. All rights reserved. 34 35 #ifndef V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_ 36 #define V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_ 37 38 #include <stdio.h> 39 40 #include <memory> 41 #include <set> 42 43 #include "src/codegen/assembler.h" 44 #include "src/codegen/constant-pool.h" 45 #include "src/codegen/external-reference.h" 46 #include "src/codegen/label.h" 47 #include "src/codegen/riscv64/constants-riscv64.h" 48 #include "src/codegen/riscv64/register-riscv64.h" 49 #include "src/objects/contexts.h" 50 #include "src/objects/smi.h" 51 52 namespace v8 { 53 namespace internal { 54 55 #define DEBUG_PRINTF(...) \ 56 if (FLAG_riscv_debug) { \ 57 printf(__VA_ARGS__); \ 58 } 59 60 class SafepointTableBuilder; 61 62 // ----------------------------------------------------------------------------- 63 // Machine instruction Operands. 64 constexpr int kSmiShift = kSmiTagSize + kSmiShiftSize; 65 constexpr uint64_t kSmiShiftMask = (1UL << kSmiShift) - 1; 66 // Class Operand represents a shifter operand in data processing instructions. 67 class Operand { 68 public: 69 // Immediate. 70 V8_INLINE explicit Operand(int64_t immediate, 71 RelocInfo::Mode rmode = RelocInfo::NO_INFO) rm_(no_reg)72 : rm_(no_reg), rmode_(rmode) { 73 value_.immediate = immediate; 74 } Operand(const ExternalReference & f)75 V8_INLINE explicit Operand(const ExternalReference& f) 76 : rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) { 77 value_.immediate = static_cast<int64_t>(f.address()); 78 } 79 V8_INLINE explicit Operand(const char* s); 80 explicit Operand(Handle<HeapObject> handle); Operand(Smi value)81 V8_INLINE explicit Operand(Smi value) 82 : rm_(no_reg), rmode_(RelocInfo::NO_INFO) { 83 value_.immediate = static_cast<intptr_t>(value.ptr()); 84 } 85 86 static Operand EmbeddedNumber(double number); // Smi or HeapNumber. 87 static Operand EmbeddedStringConstant(const StringConstantBase* str); 88 89 // Register. Operand(Register rm)90 V8_INLINE explicit Operand(Register rm) : rm_(rm) {} 91 92 // Return true if this is a register operand. 93 V8_INLINE bool is_reg() const; 94 95 inline int64_t immediate() const; 96 IsImmediate()97 bool IsImmediate() const { return !rm_.is_valid(); } 98 heap_object_request()99 HeapObjectRequest heap_object_request() const { 100 DCHECK(IsHeapObjectRequest()); 101 return value_.heap_object_request; 102 } 103 IsHeapObjectRequest()104 bool IsHeapObjectRequest() const { 105 DCHECK_IMPLIES(is_heap_object_request_, IsImmediate()); 106 DCHECK_IMPLIES(is_heap_object_request_, 107 rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT || 108 rmode_ == RelocInfo::CODE_TARGET); 109 return is_heap_object_request_; 110 } 111 rm()112 Register rm() const { return rm_; } 113 rmode()114 RelocInfo::Mode rmode() const { return rmode_; } 115 116 private: 117 Register rm_; 118 union Value { Value()119 Value() {} 120 HeapObjectRequest heap_object_request; // if is_heap_object_request_ 121 int64_t immediate; // otherwise 122 } value_; // valid if rm_ == no_reg 123 bool is_heap_object_request_ = false; 124 RelocInfo::Mode rmode_; 125 126 friend class Assembler; 127 friend class MacroAssembler; 128 }; 129 130 // On RISC-V we have only one addressing mode with base_reg + offset. 131 // Class MemOperand represents a memory operand in load and store instructions. 132 class V8_EXPORT_PRIVATE MemOperand : public Operand { 133 public: 134 // Immediate value attached to offset. 135 enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 }; 136 137 explicit MemOperand(Register rn, int32_t offset = 0); 138 explicit MemOperand(Register rn, int32_t unit, int32_t multiplier, 139 OffsetAddend offset_addend = offset_zero); offset()140 int32_t offset() const { return offset_; } 141 OffsetIsInt12Encodable()142 bool OffsetIsInt12Encodable() const { return is_int12(offset_); } 143 144 private: 145 int32_t offset_; 146 147 friend class Assembler; 148 }; 149 150 class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { 151 public: 152 // Create an assembler. Instructions and relocation information are emitted 153 // into a buffer, with the instructions starting from the beginning and the 154 // relocation information starting from the end of the buffer. See CodeDesc 155 // for a detailed comment on the layout (globals.h). 156 // 157 // If the provided buffer is nullptr, the assembler allocates and grows its 158 // own buffer. Otherwise it takes ownership of the provided buffer. 159 explicit Assembler(const AssemblerOptions&, 160 std::unique_ptr<AssemblerBuffer> = {}); 161 162 virtual ~Assembler(); 163 void AbortedCodeGeneration(); 164 // GetCode emits any pending (non-emitted) code and fills the descriptor desc. 165 static constexpr int kNoHandlerTable = 0; 166 static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr; 167 void GetCode(Isolate* isolate, CodeDesc* desc, 168 SafepointTableBuilder* safepoint_table_builder, 169 int handler_table_offset); 170 171 // Convenience wrapper for code without safepoint or handler tables. GetCode(Isolate * isolate,CodeDesc * desc)172 void GetCode(Isolate* isolate, CodeDesc* desc) { 173 GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable); 174 } 175 176 // Unused on this architecture. MaybeEmitOutOfLineConstantPool()177 void MaybeEmitOutOfLineConstantPool() {} 178 179 // Label operations & relative jumps (PPUM Appendix D). 180 // 181 // Takes a branch opcode (cc) and a label (L) and generates 182 // either a backward branch or a forward branch and links it 183 // to the label fixup chain. Usage: 184 // 185 // Label L; // unbound label 186 // j(cc, &L); // forward branch to unbound label 187 // bind(&L); // bind label to the current pc 188 // j(cc, &L); // backward branch to bound label 189 // bind(&L); // illegal: a label may be bound only once 190 // 191 // Note: The same Label can be used for forward and backward branches 192 // but it may be bound only once. 193 void bind(Label* L); // Binds an unbound label L to current code position. 194 195 enum OffsetSize : int { 196 kOffset21 = 21, // RISCV jal 197 kOffset12 = 12, // RISCV imm12 198 kOffset20 = 20, // RISCV imm20 199 kOffset13 = 13, // RISCV branch 200 kOffset32 = 32, // RISCV auipc + instr_I 201 kOffset11 = 11, // RISCV C_J 202 kOffset8 = 8 // RISCV compressed branch 203 }; 204 205 // Determines if Label is bound and near enough so that branch instruction 206 // can be used to reach it, instead of jump instruction. 207 bool is_near(Label* L); 208 bool is_near(Label* L, OffsetSize bits); 209 bool is_near_branch(Label* L); 210 211 // Get offset from instr. 212 int BranchOffset(Instr instr); 213 static int BrachlongOffset(Instr auipc, Instr jalr); 214 static int PatchBranchlongOffset(Address pc, Instr auipc, Instr instr_I, 215 int32_t offset); 216 int JumpOffset(Instr instr); 217 int CJumpOffset(Instr instr); 218 int CBranchOffset(Instr instr); 219 static int LdOffset(Instr instr); 220 static int AuipcOffset(Instr instr); 221 static int JalrOffset(Instr instr); 222 223 // Returns the branch offset to the given label from the current code 224 // position. Links the label to the current position if it is still unbound. 225 // Manages the jump elimination optimization if the second parameter is true. 226 int32_t branch_offset_helper(Label* L, OffsetSize bits); branch_offset(Label * L)227 inline int32_t branch_offset(Label* L) { 228 return branch_offset_helper(L, OffsetSize::kOffset13); 229 } jump_offset(Label * L)230 inline int32_t jump_offset(Label* L) { 231 return branch_offset_helper(L, OffsetSize::kOffset21); 232 } cjump_offset(Label * L)233 inline int16_t cjump_offset(Label* L) { 234 return (int16_t)branch_offset_helper(L, OffsetSize::kOffset11); 235 } cbranch_offset(Label * L)236 inline int32_t cbranch_offset(Label* L) { 237 return branch_offset_helper(L, OffsetSize::kOffset8); 238 } 239 240 uint64_t jump_address(Label* L); 241 uint64_t branch_long_offset(Label* L); 242 243 // Puts a labels target address at the given position. 244 // The high 8 bits are set to zero. 245 void label_at_put(Label* L, int at_offset); 246 247 // Read/Modify the code target address in the branch/call instruction at pc. 248 // The isolate argument is unused (and may be nullptr) when skipping flushing. 249 static Address target_address_at(Address pc); 250 V8_INLINE static void set_target_address_at( 251 Address pc, Address target, 252 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) { 253 set_target_value_at(pc, target, icache_flush_mode); 254 } 255 256 static Address target_address_at(Address pc, Address constant_pool); 257 258 static void set_target_address_at( 259 Address pc, Address constant_pool, Address target, 260 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 261 262 // Read/Modify the code target address in the branch/call instruction at pc. 263 inline static Tagged_t target_compressed_address_at(Address pc, 264 Address constant_pool); 265 inline static void set_target_compressed_address_at( 266 Address pc, Address constant_pool, Tagged_t target, 267 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 268 269 inline Handle<Object> code_target_object_handle_at(Address pc, 270 Address constant_pool); 271 inline Handle<HeapObject> compressed_embedded_object_handle_at( 272 Address pc, Address constant_pool); 273 274 static bool IsConstantPoolAt(Instruction* instr); 275 static int ConstantPoolSizeAt(Instruction* instr); 276 // See Assembler::CheckConstPool for more info. 277 void EmitPoolGuard(); 278 279 static void set_target_value_at( 280 Address pc, uint64_t target, 281 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 282 283 static void JumpLabelToJumpRegister(Address pc); 284 285 // This sets the branch destination (which gets loaded at the call address). 286 // This is for calls and branches within generated code. The serializer 287 // has already deserialized the lui/ori instructions etc. 288 inline static void deserialization_set_special_target_at( 289 Address instruction_payload, Code code, Address target); 290 291 // Get the size of the special target encoded at 'instruction_payload'. 292 inline static int deserialization_special_target_size( 293 Address instruction_payload); 294 295 // This sets the internal reference at the pc. 296 inline static void deserialization_set_target_internal_reference_at( 297 Address pc, Address target, 298 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE); 299 300 // Difference between address of current opcode and target address offset. 301 static constexpr int kBranchPCOffset = kInstrSize; 302 303 // Difference between address of current opcode and target address offset, 304 // when we are generatinga sequence of instructions for long relative PC 305 // branches 306 static constexpr int kLongBranchPCOffset = 3 * kInstrSize; 307 308 // Adjust ra register in branch delay slot of bal instruction so to skip 309 // instructions not needed after optimization of PIC in 310 // TurboAssembler::BranchAndLink method. 311 312 static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 4 * kInstrSize; 313 314 // Here we are patching the address in the LUI/ADDI instruction pair. 315 // These values are used in the serialization process and must be zero for 316 // RISC-V platform, as Code, Embedded Object or External-reference pointers 317 // are split across two consecutive instructions and don't exist separately 318 // in the code, so the serializer should not step forwards in memory after 319 // a target is resolved and written. 320 static constexpr int kSpecialTargetSize = 0; 321 322 // Number of consecutive instructions used to store 32bit/64bit constant. 323 // This constant was used in RelocInfo::target_address_address() function 324 // to tell serializer address of the instruction that follows 325 // LUI/ADDI instruction pair. 326 static constexpr int kInstructionsFor32BitConstant = 2; 327 static constexpr int kInstructionsFor64BitConstant = 8; 328 329 // Difference between address of current opcode and value read from pc 330 // register. 331 static constexpr int kPcLoadDelta = 4; 332 333 // Bits available for offset field in branches 334 static constexpr int kBranchOffsetBits = 13; 335 336 // Bits available for offset field in jump 337 static constexpr int kJumpOffsetBits = 21; 338 339 // Bits available for offset field in compresed jump 340 static constexpr int kCJalOffsetBits = 12; 341 342 // Bits available for offset field in compressed branch 343 static constexpr int kCBranchOffsetBits = 9; 344 345 // Max offset for b instructions with 12-bit offset field (multiple of 2) 346 static constexpr int kMaxBranchOffset = (1 << (13 - 1)) - 1; 347 348 // Max offset for jal instruction with 20-bit offset field (multiple of 2) 349 static constexpr int kMaxJumpOffset = (1 << (21 - 1)) - 1; 350 351 static constexpr int kTrampolineSlotsSize = 2 * kInstrSize; 352 GetScratchRegisterList()353 RegList* GetScratchRegisterList() { return &scratch_register_list_; } 354 355 // --------------------------------------------------------------------------- 356 // Code generation. 357 358 // Insert the smallest number of nop instructions 359 // possible to align the pc offset to a multiple 360 // of m. m must be a power of 2 (>= 4). 361 void Align(int m); 362 // Insert the smallest number of zero bytes possible to align the pc offset 363 // to a mulitple of m. m must be a power of 2 (>= 2). 364 void DataAlign(int m); 365 // Aligns code to something that's optimal for a jump target for the platform. 366 void CodeTargetAlign(); LoopHeaderAlign()367 void LoopHeaderAlign() { CodeTargetAlign(); } 368 369 // Different nop operations are used by the code generator to detect certain 370 // states of the generated code. 371 enum NopMarkerTypes { 372 NON_MARKING_NOP = 0, 373 DEBUG_BREAK_NOP, 374 // IC markers. 375 PROPERTY_ACCESS_INLINED, 376 PROPERTY_ACCESS_INLINED_CONTEXT, 377 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, 378 // Helper values. 379 LAST_CODE_MARKER, 380 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED, 381 }; 382 383 // RISC-V Instructions Emited to a buffer 384 385 void lui(Register rd, int32_t imm20); 386 void auipc(Register rd, int32_t imm20); 387 388 // Jumps 389 void jal(Register rd, int32_t imm20); 390 void jalr(Register rd, Register rs1, int16_t imm12); 391 392 // Branches 393 void beq(Register rs1, Register rs2, int16_t imm12); beq(Register rs1,Register rs2,Label * L)394 inline void beq(Register rs1, Register rs2, Label* L) { 395 beq(rs1, rs2, branch_offset(L)); 396 } 397 void bne(Register rs1, Register rs2, int16_t imm12); bne(Register rs1,Register rs2,Label * L)398 inline void bne(Register rs1, Register rs2, Label* L) { 399 bne(rs1, rs2, branch_offset(L)); 400 } 401 void blt(Register rs1, Register rs2, int16_t imm12); blt(Register rs1,Register rs2,Label * L)402 inline void blt(Register rs1, Register rs2, Label* L) { 403 blt(rs1, rs2, branch_offset(L)); 404 } 405 void bge(Register rs1, Register rs2, int16_t imm12); bge(Register rs1,Register rs2,Label * L)406 inline void bge(Register rs1, Register rs2, Label* L) { 407 bge(rs1, rs2, branch_offset(L)); 408 } 409 void bltu(Register rs1, Register rs2, int16_t imm12); bltu(Register rs1,Register rs2,Label * L)410 inline void bltu(Register rs1, Register rs2, Label* L) { 411 bltu(rs1, rs2, branch_offset(L)); 412 } 413 void bgeu(Register rs1, Register rs2, int16_t imm12); bgeu(Register rs1,Register rs2,Label * L)414 inline void bgeu(Register rs1, Register rs2, Label* L) { 415 bgeu(rs1, rs2, branch_offset(L)); 416 } 417 418 // Loads 419 void lb(Register rd, Register rs1, int16_t imm12); 420 void lh(Register rd, Register rs1, int16_t imm12); 421 void lw(Register rd, Register rs1, int16_t imm12); 422 void lbu(Register rd, Register rs1, int16_t imm12); 423 void lhu(Register rd, Register rs1, int16_t imm12); 424 425 // Stores 426 void sb(Register source, Register base, int16_t imm12); 427 void sh(Register source, Register base, int16_t imm12); 428 void sw(Register source, Register base, int16_t imm12); 429 430 // Arithmetic with immediate 431 void addi(Register rd, Register rs1, int16_t imm12); 432 void slti(Register rd, Register rs1, int16_t imm12); 433 void sltiu(Register rd, Register rs1, int16_t imm12); 434 void xori(Register rd, Register rs1, int16_t imm12); 435 void ori(Register rd, Register rs1, int16_t imm12); 436 void andi(Register rd, Register rs1, int16_t imm12); 437 void slli(Register rd, Register rs1, uint8_t shamt); 438 void srli(Register rd, Register rs1, uint8_t shamt); 439 void srai(Register rd, Register rs1, uint8_t shamt); 440 441 // Arithmetic 442 void add(Register rd, Register rs1, Register rs2); 443 void sub(Register rd, Register rs1, Register rs2); 444 void sll(Register rd, Register rs1, Register rs2); 445 void slt(Register rd, Register rs1, Register rs2); 446 void sltu(Register rd, Register rs1, Register rs2); 447 void xor_(Register rd, Register rs1, Register rs2); 448 void srl(Register rd, Register rs1, Register rs2); 449 void sra(Register rd, Register rs1, Register rs2); 450 void or_(Register rd, Register rs1, Register rs2); 451 void and_(Register rd, Register rs1, Register rs2); 452 453 // Memory fences 454 void fence(uint8_t pred, uint8_t succ); 455 void fence_tso(); 456 457 // Environment call / break 458 void ecall(); 459 void ebreak(); 460 461 // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented 462 // instruction (i.e., it should always trap, if your implementation has 463 // invalid instruction traps). 464 void unimp(); 465 466 // CSR 467 void csrrw(Register rd, ControlStatusReg csr, Register rs1); 468 void csrrs(Register rd, ControlStatusReg csr, Register rs1); 469 void csrrc(Register rd, ControlStatusReg csr, Register rs1); 470 void csrrwi(Register rd, ControlStatusReg csr, uint8_t imm5); 471 void csrrsi(Register rd, ControlStatusReg csr, uint8_t imm5); 472 void csrrci(Register rd, ControlStatusReg csr, uint8_t imm5); 473 474 // RV64I 475 void lwu(Register rd, Register rs1, int16_t imm12); 476 void ld(Register rd, Register rs1, int16_t imm12); 477 void sd(Register source, Register base, int16_t imm12); 478 void addiw(Register rd, Register rs1, int16_t imm12); 479 void slliw(Register rd, Register rs1, uint8_t shamt); 480 void srliw(Register rd, Register rs1, uint8_t shamt); 481 void sraiw(Register rd, Register rs1, uint8_t shamt); 482 void addw(Register rd, Register rs1, Register rs2); 483 void subw(Register rd, Register rs1, Register rs2); 484 void sllw(Register rd, Register rs1, Register rs2); 485 void srlw(Register rd, Register rs1, Register rs2); 486 void sraw(Register rd, Register rs1, Register rs2); 487 488 // RV32M Standard Extension 489 void mul(Register rd, Register rs1, Register rs2); 490 void mulh(Register rd, Register rs1, Register rs2); 491 void mulhsu(Register rd, Register rs1, Register rs2); 492 void mulhu(Register rd, Register rs1, Register rs2); 493 void div(Register rd, Register rs1, Register rs2); 494 void divu(Register rd, Register rs1, Register rs2); 495 void rem(Register rd, Register rs1, Register rs2); 496 void remu(Register rd, Register rs1, Register rs2); 497 498 // RV64M Standard Extension (in addition to RV32M) 499 void mulw(Register rd, Register rs1, Register rs2); 500 void divw(Register rd, Register rs1, Register rs2); 501 void divuw(Register rd, Register rs1, Register rs2); 502 void remw(Register rd, Register rs1, Register rs2); 503 void remuw(Register rd, Register rs1, Register rs2); 504 505 // RV32A Standard Extension 506 void lr_w(bool aq, bool rl, Register rd, Register rs1); 507 void sc_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 508 void amoswap_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 509 void amoadd_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 510 void amoxor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 511 void amoand_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 512 void amoor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 513 void amomin_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 514 void amomax_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 515 void amominu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 516 void amomaxu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); 517 518 // RV64A Standard Extension (in addition to RV32A) 519 void lr_d(bool aq, bool rl, Register rd, Register rs1); 520 void sc_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 521 void amoswap_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 522 void amoadd_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 523 void amoxor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 524 void amoand_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 525 void amoor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 526 void amomin_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 527 void amomax_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 528 void amominu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 529 void amomaxu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); 530 531 // RV32F Standard Extension 532 void flw(FPURegister rd, Register rs1, int16_t imm12); 533 void fsw(FPURegister source, Register base, int16_t imm12); 534 void fmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 535 FPURegister rs3, RoundingMode frm = RNE); 536 void fmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 537 FPURegister rs3, RoundingMode frm = RNE); 538 void fnmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 539 FPURegister rs3, RoundingMode frm = RNE); 540 void fnmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 541 FPURegister rs3, RoundingMode frm = RNE); 542 void fadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 543 RoundingMode frm = RNE); 544 void fsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 545 RoundingMode frm = RNE); 546 void fmul_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 547 RoundingMode frm = RNE); 548 void fdiv_s(FPURegister rd, FPURegister rs1, FPURegister rs2, 549 RoundingMode frm = RNE); 550 void fsqrt_s(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); 551 void fsgnj_s(FPURegister rd, FPURegister rs1, FPURegister rs2); 552 void fsgnjn_s(FPURegister rd, FPURegister rs1, FPURegister rs2); 553 void fsgnjx_s(FPURegister rd, FPURegister rs1, FPURegister rs2); 554 void fmin_s(FPURegister rd, FPURegister rs1, FPURegister rs2); 555 void fmax_s(FPURegister rd, FPURegister rs1, FPURegister rs2); 556 void fcvt_w_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); 557 void fcvt_wu_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); 558 void fmv_x_w(Register rd, FPURegister rs1); 559 void feq_s(Register rd, FPURegister rs1, FPURegister rs2); 560 void flt_s(Register rd, FPURegister rs1, FPURegister rs2); 561 void fle_s(Register rd, FPURegister rs1, FPURegister rs2); 562 void fclass_s(Register rd, FPURegister rs1); 563 void fcvt_s_w(FPURegister rd, Register rs1, RoundingMode frm = RNE); 564 void fcvt_s_wu(FPURegister rd, Register rs1, RoundingMode frm = RNE); 565 void fmv_w_x(FPURegister rd, Register rs1); 566 567 // RV64F Standard Extension (in addition to RV32F) 568 void fcvt_l_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); 569 void fcvt_lu_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); 570 void fcvt_s_l(FPURegister rd, Register rs1, RoundingMode frm = RNE); 571 void fcvt_s_lu(FPURegister rd, Register rs1, RoundingMode frm = RNE); 572 573 // RV32D Standard Extension 574 void fld(FPURegister rd, Register rs1, int16_t imm12); 575 void fsd(FPURegister source, Register base, int16_t imm12); 576 void fmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 577 FPURegister rs3, RoundingMode frm = RNE); 578 void fmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 579 FPURegister rs3, RoundingMode frm = RNE); 580 void fnmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 581 FPURegister rs3, RoundingMode frm = RNE); 582 void fnmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 583 FPURegister rs3, RoundingMode frm = RNE); 584 void fadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 585 RoundingMode frm = RNE); 586 void fsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 587 RoundingMode frm = RNE); 588 void fmul_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 589 RoundingMode frm = RNE); 590 void fdiv_d(FPURegister rd, FPURegister rs1, FPURegister rs2, 591 RoundingMode frm = RNE); 592 void fsqrt_d(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); 593 void fsgnj_d(FPURegister rd, FPURegister rs1, FPURegister rs2); 594 void fsgnjn_d(FPURegister rd, FPURegister rs1, FPURegister rs2); 595 void fsgnjx_d(FPURegister rd, FPURegister rs1, FPURegister rs2); 596 void fmin_d(FPURegister rd, FPURegister rs1, FPURegister rs2); 597 void fmax_d(FPURegister rd, FPURegister rs1, FPURegister rs2); 598 void fcvt_s_d(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); 599 void fcvt_d_s(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); 600 void feq_d(Register rd, FPURegister rs1, FPURegister rs2); 601 void flt_d(Register rd, FPURegister rs1, FPURegister rs2); 602 void fle_d(Register rd, FPURegister rs1, FPURegister rs2); 603 void fclass_d(Register rd, FPURegister rs1); 604 void fcvt_w_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); 605 void fcvt_wu_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); 606 void fcvt_d_w(FPURegister rd, Register rs1, RoundingMode frm = RNE); 607 void fcvt_d_wu(FPURegister rd, Register rs1, RoundingMode frm = RNE); 608 609 // RV64D Standard Extension (in addition to RV32D) 610 void fcvt_l_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); 611 void fcvt_lu_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); 612 void fmv_x_d(Register rd, FPURegister rs1); 613 void fcvt_d_l(FPURegister rd, Register rs1, RoundingMode frm = RNE); 614 void fcvt_d_lu(FPURegister rd, Register rs1, RoundingMode frm = RNE); 615 void fmv_d_x(FPURegister rd, Register rs1); 616 617 // RV64C Standard Extension 618 void c_nop(); 619 void c_addi(Register rd, int8_t imm6); 620 void c_addiw(Register rd, int8_t imm6); 621 void c_addi16sp(int16_t imm10); 622 void c_addi4spn(Register rd, int16_t uimm10); 623 void c_li(Register rd, int8_t imm6); 624 void c_lui(Register rd, int8_t imm6); 625 void c_slli(Register rd, uint8_t shamt6); 626 void c_fldsp(FPURegister rd, uint16_t uimm9); 627 void c_lwsp(Register rd, uint16_t uimm8); 628 void c_ldsp(Register rd, uint16_t uimm9); 629 void c_jr(Register rs1); 630 void c_mv(Register rd, Register rs2); 631 void c_ebreak(); 632 void c_jalr(Register rs1); 633 void c_j(int16_t imm12); c_j(Label * L)634 inline void c_j(Label* L) { c_j(cjump_offset(L)); } 635 void c_add(Register rd, Register rs2); 636 void c_sub(Register rd, Register rs2); 637 void c_and(Register rd, Register rs2); 638 void c_xor(Register rd, Register rs2); 639 void c_or(Register rd, Register rs2); 640 void c_subw(Register rd, Register rs2); 641 void c_addw(Register rd, Register rs2); 642 void c_swsp(Register rs2, uint16_t uimm8); 643 void c_sdsp(Register rs2, uint16_t uimm9); 644 void c_fsdsp(FPURegister rs2, uint16_t uimm9); 645 void c_lw(Register rd, Register rs1, uint16_t uimm7); 646 void c_ld(Register rd, Register rs1, uint16_t uimm8); 647 void c_fld(FPURegister rd, Register rs1, uint16_t uimm8); 648 void c_sw(Register rs2, Register rs1, uint16_t uimm7); 649 void c_sd(Register rs2, Register rs1, uint16_t uimm8); 650 void c_fsd(FPURegister rs2, Register rs1, uint16_t uimm8); 651 void c_bnez(Register rs1, int16_t imm9); c_bnez(Register rs1,Label * L)652 inline void c_bnez(Register rs1, Label* L) { c_bnez(rs1, branch_offset(L)); } 653 void c_beqz(Register rs1, int16_t imm9); c_beqz(Register rs1,Label * L)654 inline void c_beqz(Register rs1, Label* L) { c_beqz(rs1, branch_offset(L)); } 655 void c_srli(Register rs1, int8_t shamt6); 656 void c_srai(Register rs1, int8_t shamt6); 657 void c_andi(Register rs1, int8_t imm6); 658 void NOP(); 659 void EBREAK(); 660 661 // RVV 662 static int32_t GenZimm(VSew vsew, Vlmul vlmul, TailAgnosticType tail = tu, 663 MaskAgnosticType mask = mu) { 664 return (mask << 7) | (tail << 6) | ((vsew & 0x7) << 3) | (vlmul & 0x7); 665 } 666 667 void vl(VRegister vd, Register rs1, uint8_t lumop, VSew vsew, 668 MaskType mask = NoMask); 669 void vls(VRegister vd, Register rs1, Register rs2, VSew vsew, 670 MaskType mask = NoMask); 671 void vlx(VRegister vd, Register rs1, VRegister vs3, VSew vsew, 672 MaskType mask = NoMask); 673 674 void vs(VRegister vd, Register rs1, uint8_t sumop, VSew vsew, 675 MaskType mask = NoMask); 676 void vss(VRegister vd, Register rs1, Register rs2, VSew vsew, 677 MaskType mask = NoMask); 678 void vsx(VRegister vd, Register rs1, VRegister vs3, VSew vsew, 679 MaskType mask = NoMask); 680 681 void vsu(VRegister vd, Register rs1, VRegister vs3, VSew vsew, 682 MaskType mask = NoMask); 683 684 #define SegInstr(OP) \ 685 void OP##seg2(ARG); \ 686 void OP##seg3(ARG); \ 687 void OP##seg4(ARG); \ 688 void OP##seg5(ARG); \ 689 void OP##seg6(ARG); \ 690 void OP##seg7(ARG); \ 691 void OP##seg8(ARG); 692 693 #define ARG \ 694 VRegister vd, Register rs1, uint8_t lumop, VSew vsew, MaskType mask = NoMask 695 696 SegInstr(vl) SegInstr(vs) 697 #undef ARG 698 699 #define ARG \ 700 VRegister vd, Register rs1, Register rs2, VSew vsew, MaskType mask = NoMask 701 702 SegInstr(vls) SegInstr(vss) 703 #undef ARG 704 705 #define ARG \ 706 VRegister vd, Register rs1, VRegister rs2, VSew vsew, MaskType mask = NoMask 707 708 SegInstr(vsx) SegInstr(vlx) 709 #undef ARG 710 #undef SegInstr 711 712 // RVV Vector Arithmetic Instruction 713 714 void vmv_vv(VRegister vd, VRegister vs1); 715 void vmv_vx(VRegister vd, Register rs1); 716 void vmv_vi(VRegister vd, uint8_t simm5); 717 void vmv_xs(Register rd, VRegister vs2); 718 void vmv_sx(VRegister vd, Register rs1); 719 void vmerge_vv(VRegister vd, VRegister vs1, VRegister vs2); 720 void vmerge_vx(VRegister vd, Register rs1, VRegister vs2); 721 void vmerge_vi(VRegister vd, uint8_t imm5, VRegister vs2); 722 723 void vredmaxu_vs(VRegister vd, VRegister vs2, VRegister vs1, 724 MaskType mask = NoMask); 725 void vredmax_vs(VRegister vd, VRegister vs2, VRegister vs1, 726 MaskType mask = NoMask); 727 void vredmin_vs(VRegister vd, VRegister vs2, VRegister vs1, 728 MaskType mask = NoMask); 729 void vredminu_vs(VRegister vd, VRegister vs2, VRegister vs1, 730 MaskType mask = NoMask); 731 732 void vadc_vv(VRegister vd, VRegister vs1, VRegister vs2); 733 void vadc_vx(VRegister vd, Register rs1, VRegister vs2); 734 void vadc_vi(VRegister vd, uint8_t imm5, VRegister vs2); 735 736 void vmadc_vv(VRegister vd, VRegister vs1, VRegister vs2); 737 void vmadc_vx(VRegister vd, Register rs1, VRegister vs2); 738 void vmadc_vi(VRegister vd, uint8_t imm5, VRegister vs2); 739 740 void vfmv_vf(VRegister vd, FPURegister fs1, MaskType mask = NoMask); 741 void vfmv_fs(FPURegister fd, VRegister vs2); 742 void vfmv_sf(VRegister vd, FPURegister fs); 743 744 void vwaddu_wx(VRegister vd, VRegister vs2, Register rs1, 745 MaskType mask = NoMask); 746 void vid_v(VRegister vd, MaskType mask = Mask); 747 748 #define DEFINE_OPIVV(name, funct6) \ 749 void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \ 750 MaskType mask = NoMask); 751 752 #define DEFINE_OPIVX(name, funct6) \ 753 void name##_vx(VRegister vd, VRegister vs2, Register rs1, \ 754 MaskType mask = NoMask); 755 756 #define DEFINE_OPIVI(name, funct6) \ 757 void name##_vi(VRegister vd, VRegister vs2, int8_t imm5, \ 758 MaskType mask = NoMask); 759 760 #define DEFINE_OPMVV(name, funct6) \ 761 void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \ 762 MaskType mask = NoMask); 763 764 #define DEFINE_OPMVX(name, funct6) \ 765 void name##_vx(VRegister vd, VRegister vs2, Register rs1, \ 766 MaskType mask = NoMask); 767 768 #define DEFINE_OPFVV(name, funct6) \ 769 void name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \ 770 MaskType mask = NoMask); 771 772 #define DEFINE_OPFWV(name, funct6) \ 773 void name##_wv(VRegister vd, VRegister vs2, VRegister vs1, \ 774 MaskType mask = NoMask); 775 776 #define DEFINE_OPFRED(name, funct6) \ 777 void name##_vs(VRegister vd, VRegister vs2, VRegister vs1, \ 778 MaskType mask = NoMask); 779 780 #define DEFINE_OPFVF(name, funct6) \ 781 void name##_vf(VRegister vd, VRegister vs2, FPURegister fs1, \ 782 MaskType mask = NoMask); 783 784 #define DEFINE_OPFWF(name, funct6) \ 785 void name##_wf(VRegister vd, VRegister vs2, FPURegister fs1, \ 786 MaskType mask = NoMask); 787 788 #define DEFINE_OPFVV_FMA(name, funct6) \ 789 void name##_vv(VRegister vd, VRegister vs1, VRegister vs2, \ 790 MaskType mask = NoMask); 791 792 #define DEFINE_OPFVF_FMA(name, funct6) \ 793 void name##_vf(VRegister vd, FPURegister fs1, VRegister vs2, \ 794 MaskType mask = NoMask); 795 796 #define DEFINE_OPMVV_VIE(name) \ 797 void name(VRegister vd, VRegister vs2, MaskType mask = NoMask); 798 DEFINE_OPIVV(vadd,VADD_FUNCT6)799 DEFINE_OPIVV(vadd, VADD_FUNCT6) 800 DEFINE_OPIVX(vadd, VADD_FUNCT6) 801 DEFINE_OPIVI(vadd, VADD_FUNCT6) 802 DEFINE_OPIVV(vsub, VSUB_FUNCT6) 803 DEFINE_OPIVX(vsub, VSUB_FUNCT6) 804 DEFINE_OPMVX(vdiv, VDIV_FUNCT6) 805 DEFINE_OPMVX(vdivu, VDIVU_FUNCT6) 806 DEFINE_OPMVX(vmul, VMUL_FUNCT6) 807 DEFINE_OPMVX(vmulhu, VMULHU_FUNCT6) 808 DEFINE_OPMVX(vmulhsu, VMULHSU_FUNCT6) 809 DEFINE_OPMVX(vmulh, VMULH_FUNCT6) 810 DEFINE_OPMVV(vdiv, VDIV_FUNCT6) 811 DEFINE_OPMVV(vdivu, VDIVU_FUNCT6) 812 DEFINE_OPMVV(vmul, VMUL_FUNCT6) 813 DEFINE_OPMVV(vmulhu, VMULHU_FUNCT6) 814 DEFINE_OPMVV(vmulhsu, VMULHSU_FUNCT6) 815 DEFINE_OPMVV(vmulh, VMULH_FUNCT6) 816 DEFINE_OPMVV(vwmul, VWMUL_FUNCT6) 817 DEFINE_OPMVV(vwmulu, VWMULU_FUNCT6) 818 DEFINE_OPMVV(vwaddu, VWADDU_FUNCT6) 819 DEFINE_OPMVV(vwadd, VWADD_FUNCT6) 820 DEFINE_OPMVV(vcompress, VCOMPRESS_FUNCT6) 821 DEFINE_OPIVX(vsadd, VSADD_FUNCT6) 822 DEFINE_OPIVV(vsadd, VSADD_FUNCT6) 823 DEFINE_OPIVI(vsadd, VSADD_FUNCT6) 824 DEFINE_OPIVX(vsaddu, VSADD_FUNCT6) 825 DEFINE_OPIVV(vsaddu, VSADDU_FUNCT6) 826 DEFINE_OPIVI(vsaddu, VSADDU_FUNCT6) 827 DEFINE_OPIVX(vssub, VSSUB_FUNCT6) 828 DEFINE_OPIVV(vssub, VSSUB_FUNCT6) 829 DEFINE_OPIVX(vssubu, VSSUBU_FUNCT6) 830 DEFINE_OPIVV(vssubu, VSSUBU_FUNCT6) 831 DEFINE_OPIVX(vrsub, VRSUB_FUNCT6) 832 DEFINE_OPIVI(vrsub, VRSUB_FUNCT6) 833 DEFINE_OPIVV(vminu, VMINU_FUNCT6) 834 DEFINE_OPIVX(vminu, VMINU_FUNCT6) 835 DEFINE_OPIVV(vmin, VMIN_FUNCT6) 836 DEFINE_OPIVX(vmin, VMIN_FUNCT6) 837 DEFINE_OPIVV(vmaxu, VMAXU_FUNCT6) 838 DEFINE_OPIVX(vmaxu, VMAXU_FUNCT6) 839 DEFINE_OPIVV(vmax, VMAX_FUNCT6) 840 DEFINE_OPIVX(vmax, VMAX_FUNCT6) 841 DEFINE_OPIVV(vand, VAND_FUNCT6) 842 DEFINE_OPIVX(vand, VAND_FUNCT6) 843 DEFINE_OPIVI(vand, VAND_FUNCT6) 844 DEFINE_OPIVV(vor, VOR_FUNCT6) 845 DEFINE_OPIVX(vor, VOR_FUNCT6) 846 DEFINE_OPIVI(vor, VOR_FUNCT6) 847 DEFINE_OPIVV(vxor, VXOR_FUNCT6) 848 DEFINE_OPIVX(vxor, VXOR_FUNCT6) 849 DEFINE_OPIVI(vxor, VXOR_FUNCT6) 850 DEFINE_OPIVV(vrgather, VRGATHER_FUNCT6) 851 DEFINE_OPIVX(vrgather, VRGATHER_FUNCT6) 852 DEFINE_OPIVI(vrgather, VRGATHER_FUNCT6) 853 854 DEFINE_OPIVX(vslidedown, VSLIDEDOWN_FUNCT6) 855 DEFINE_OPIVI(vslidedown, VSLIDEDOWN_FUNCT6) 856 DEFINE_OPIVX(vslideup, VSLIDEUP_FUNCT6) 857 DEFINE_OPIVI(vslideup, VSLIDEUP_FUNCT6) 858 859 DEFINE_OPIVV(vmseq, VMSEQ_FUNCT6) 860 DEFINE_OPIVX(vmseq, VMSEQ_FUNCT6) 861 DEFINE_OPIVI(vmseq, VMSEQ_FUNCT6) 862 863 DEFINE_OPIVV(vmsne, VMSNE_FUNCT6) 864 DEFINE_OPIVX(vmsne, VMSNE_FUNCT6) 865 DEFINE_OPIVI(vmsne, VMSNE_FUNCT6) 866 867 DEFINE_OPIVV(vmsltu, VMSLTU_FUNCT6) 868 DEFINE_OPIVX(vmsltu, VMSLTU_FUNCT6) 869 870 DEFINE_OPIVV(vmslt, VMSLT_FUNCT6) 871 DEFINE_OPIVX(vmslt, VMSLT_FUNCT6) 872 873 DEFINE_OPIVV(vmsle, VMSLE_FUNCT6) 874 DEFINE_OPIVX(vmsle, VMSLE_FUNCT6) 875 DEFINE_OPIVI(vmsle, VMSLE_FUNCT6) 876 877 DEFINE_OPIVV(vmsleu, VMSLEU_FUNCT6) 878 DEFINE_OPIVX(vmsleu, VMSLEU_FUNCT6) 879 DEFINE_OPIVI(vmsleu, VMSLEU_FUNCT6) 880 881 DEFINE_OPIVI(vmsgt, VMSGT_FUNCT6) 882 DEFINE_OPIVX(vmsgt, VMSGT_FUNCT6) 883 884 DEFINE_OPIVI(vmsgtu, VMSGTU_FUNCT6) 885 DEFINE_OPIVX(vmsgtu, VMSGTU_FUNCT6) 886 887 DEFINE_OPIVV(vsrl, VSRL_FUNCT6) 888 DEFINE_OPIVX(vsrl, VSRL_FUNCT6) 889 DEFINE_OPIVI(vsrl, VSRL_FUNCT6) 890 891 DEFINE_OPIVV(vsra, VSRA_FUNCT6) 892 DEFINE_OPIVX(vsra, VSRA_FUNCT6) 893 DEFINE_OPIVI(vsra, VSRA_FUNCT6) 894 895 DEFINE_OPIVV(vsll, VSLL_FUNCT6) 896 DEFINE_OPIVX(vsll, VSLL_FUNCT6) 897 DEFINE_OPIVI(vsll, VSLL_FUNCT6) 898 899 DEFINE_OPIVV(vsmul, VSMUL_FUNCT6) 900 DEFINE_OPIVX(vsmul, VSMUL_FUNCT6) 901 902 DEFINE_OPFVV(vfadd, VFADD_FUNCT6) 903 DEFINE_OPFVF(vfadd, VFADD_FUNCT6) 904 DEFINE_OPFVV(vfsub, VFSUB_FUNCT6) 905 DEFINE_OPFVF(vfsub, VFSUB_FUNCT6) 906 DEFINE_OPFVV(vfdiv, VFDIV_FUNCT6) 907 DEFINE_OPFVF(vfdiv, VFDIV_FUNCT6) 908 DEFINE_OPFVV(vfmul, VFMUL_FUNCT6) 909 DEFINE_OPFVF(vfmul, VFMUL_FUNCT6) 910 911 // Vector Widening Floating-Point Add/Subtract Instructions 912 DEFINE_OPFVV(vfwadd, VFWADD_FUNCT6) 913 DEFINE_OPFVF(vfwadd, VFWADD_FUNCT6) 914 DEFINE_OPFVV(vfwsub, VFWSUB_FUNCT6) 915 DEFINE_OPFVF(vfwsub, VFWSUB_FUNCT6) 916 DEFINE_OPFWV(vfwadd, VFWADD_W_FUNCT6) 917 DEFINE_OPFWF(vfwadd, VFWADD_W_FUNCT6) 918 DEFINE_OPFWV(vfwsub, VFWSUB_W_FUNCT6) 919 DEFINE_OPFWF(vfwsub, VFWSUB_W_FUNCT6) 920 921 // Vector Widening Floating-Point Reduction Instructions 922 DEFINE_OPFVV(vfwredusum, VFWREDUSUM_FUNCT6) 923 DEFINE_OPFVV(vfwredosum, VFWREDOSUM_FUNCT6) 924 925 // Vector Widening Floating-Point Multiply 926 DEFINE_OPFVV(vfwmul, VFWMUL_FUNCT6) 927 DEFINE_OPFVF(vfwmul, VFWMUL_FUNCT6) 928 929 DEFINE_OPFVV(vmfeq, VMFEQ_FUNCT6) 930 DEFINE_OPFVV(vmfne, VMFNE_FUNCT6) 931 DEFINE_OPFVV(vmflt, VMFLT_FUNCT6) 932 DEFINE_OPFVV(vmfle, VMFLE_FUNCT6) 933 DEFINE_OPFVV(vfmax, VMFMAX_FUNCT6) 934 DEFINE_OPFVV(vfmin, VMFMIN_FUNCT6) 935 DEFINE_OPFRED(vfredmax, VFREDMAX_FUNCT6) 936 937 DEFINE_OPFVV(vfsngj, VFSGNJ_FUNCT6) 938 DEFINE_OPFVF(vfsngj, VFSGNJ_FUNCT6) 939 DEFINE_OPFVV(vfsngjn, VFSGNJN_FUNCT6) 940 DEFINE_OPFVF(vfsngjn, VFSGNJN_FUNCT6) 941 DEFINE_OPFVV(vfsngjx, VFSGNJX_FUNCT6) 942 DEFINE_OPFVF(vfsngjx, VFSGNJX_FUNCT6) 943 944 // Vector Single-Width Floating-Point Fused Multiply-Add Instructions 945 DEFINE_OPFVV_FMA(vfmadd, VFMADD_FUNCT6) 946 DEFINE_OPFVF_FMA(vfmadd, VFMADD_FUNCT6) 947 DEFINE_OPFVV_FMA(vfmsub, VFMSUB_FUNCT6) 948 DEFINE_OPFVF_FMA(vfmsub, VFMSUB_FUNCT6) 949 DEFINE_OPFVV_FMA(vfmacc, VFMACC_FUNCT6) 950 DEFINE_OPFVF_FMA(vfmacc, VFMACC_FUNCT6) 951 DEFINE_OPFVV_FMA(vfmsac, VFMSAC_FUNCT6) 952 DEFINE_OPFVF_FMA(vfmsac, VFMSAC_FUNCT6) 953 DEFINE_OPFVV_FMA(vfnmadd, VFNMADD_FUNCT6) 954 DEFINE_OPFVF_FMA(vfnmadd, VFNMADD_FUNCT6) 955 DEFINE_OPFVV_FMA(vfnmsub, VFNMSUB_FUNCT6) 956 DEFINE_OPFVF_FMA(vfnmsub, VFNMSUB_FUNCT6) 957 DEFINE_OPFVV_FMA(vfnmacc, VFNMACC_FUNCT6) 958 DEFINE_OPFVF_FMA(vfnmacc, VFNMACC_FUNCT6) 959 DEFINE_OPFVV_FMA(vfnmsac, VFNMSAC_FUNCT6) 960 DEFINE_OPFVF_FMA(vfnmsac, VFNMSAC_FUNCT6) 961 962 // Vector Widening Floating-Point Fused Multiply-Add Instructions 963 DEFINE_OPFVV_FMA(vfwmacc, VFWMACC_FUNCT6) 964 DEFINE_OPFVF_FMA(vfwmacc, VFWMACC_FUNCT6) 965 DEFINE_OPFVV_FMA(vfwnmacc, VFWNMACC_FUNCT6) 966 DEFINE_OPFVF_FMA(vfwnmacc, VFWNMACC_FUNCT6) 967 DEFINE_OPFVV_FMA(vfwmsac, VFWMSAC_FUNCT6) 968 DEFINE_OPFVF_FMA(vfwmsac, VFWMSAC_FUNCT6) 969 DEFINE_OPFVV_FMA(vfwnmsac, VFWNMSAC_FUNCT6) 970 DEFINE_OPFVF_FMA(vfwnmsac, VFWNMSAC_FUNCT6) 971 972 // Vector Narrowing Fixed-Point Clip Instructions 973 DEFINE_OPIVV(vnclip, VNCLIP_FUNCT6) 974 DEFINE_OPIVX(vnclip, VNCLIP_FUNCT6) 975 DEFINE_OPIVI(vnclip, VNCLIP_FUNCT6) 976 DEFINE_OPIVV(vnclipu, VNCLIPU_FUNCT6) 977 DEFINE_OPIVX(vnclipu, VNCLIPU_FUNCT6) 978 DEFINE_OPIVI(vnclipu, VNCLIPU_FUNCT6) 979 980 // Vector Integer Extension 981 DEFINE_OPMVV_VIE(vzext_vf8) 982 DEFINE_OPMVV_VIE(vsext_vf8) 983 DEFINE_OPMVV_VIE(vzext_vf4) 984 DEFINE_OPMVV_VIE(vsext_vf4) 985 DEFINE_OPMVV_VIE(vzext_vf2) 986 DEFINE_OPMVV_VIE(vsext_vf2) 987 988 #undef DEFINE_OPIVI 989 #undef DEFINE_OPIVV 990 #undef DEFINE_OPIVX 991 #undef DEFINE_OPMVV 992 #undef DEFINE_OPMVX 993 #undef DEFINE_OPFVV 994 #undef DEFINE_OPFWV 995 #undef DEFINE_OPFVF 996 #undef DEFINE_OPFWF 997 #undef DEFINE_OPFVV_FMA 998 #undef DEFINE_OPFVF_FMA 999 #undef DEFINE_OPMVV_VIE 1000 #undef DEFINE_OPFRED 1001 1002 #define DEFINE_VFUNARY(name, funct6, vs1) \ 1003 void name(VRegister vd, VRegister vs2, MaskType mask = NoMask) { \ 1004 GenInstrV(funct6, OP_FVV, vd, vs1, vs2, mask); \ 1005 } 1006 1007 DEFINE_VFUNARY(vfcvt_xu_f_v, VFUNARY0_FUNCT6, VFCVT_XU_F_V) 1008 DEFINE_VFUNARY(vfcvt_x_f_v, VFUNARY0_FUNCT6, VFCVT_X_F_V) 1009 DEFINE_VFUNARY(vfcvt_f_x_v, VFUNARY0_FUNCT6, VFCVT_F_X_V) 1010 DEFINE_VFUNARY(vfcvt_f_xu_v, VFUNARY0_FUNCT6, VFCVT_F_XU_V) 1011 DEFINE_VFUNARY(vfwcvt_xu_f_v, VFUNARY0_FUNCT6, VFWCVT_XU_F_V) 1012 DEFINE_VFUNARY(vfwcvt_x_f_v, VFUNARY0_FUNCT6, VFWCVT_X_F_V) 1013 DEFINE_VFUNARY(vfwcvt_f_x_v, VFUNARY0_FUNCT6, VFWCVT_F_X_V) 1014 DEFINE_VFUNARY(vfwcvt_f_xu_v, VFUNARY0_FUNCT6, VFWCVT_F_XU_V) 1015 DEFINE_VFUNARY(vfwcvt_f_f_v, VFUNARY0_FUNCT6, VFWCVT_F_F_V) 1016 1017 DEFINE_VFUNARY(vfncvt_f_f_w, VFUNARY0_FUNCT6, VFNCVT_F_F_W) 1018 DEFINE_VFUNARY(vfncvt_x_f_w, VFUNARY0_FUNCT6, VFNCVT_X_F_W) 1019 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 DEFINE_VFUNARY(vfrsqrt7_v, VFUNARY1_FUNCT6, VFRSQRT7_V) 1024 DEFINE_VFUNARY(vfrec7_v, VFUNARY1_FUNCT6, VFREC7_V) 1025 #undef DEFINE_VFUNARY 1026 1027 void vnot_vv(VRegister dst, VRegister src, MaskType mask = NoMask) { 1028 vxor_vi(dst, src, -1, mask); 1029 } 1030 1031 void vneg_vv(VRegister dst, VRegister src, MaskType mask = NoMask) { 1032 vrsub_vx(dst, src, zero_reg, mask); 1033 } 1034 1035 void vfneg_vv(VRegister dst, VRegister src, MaskType mask = NoMask) { 1036 vfsngjn_vv(dst, src, src, mask); 1037 } 1038 void vfabs_vv(VRegister dst, VRegister src, MaskType mask = NoMask) { 1039 vfsngjx_vv(dst, src, src, mask); 1040 } 1041 void vfirst_m(Register rd, VRegister vs2, MaskType mask = NoMask); 1042 1043 void vcpop_m(Register rd, VRegister vs2, MaskType mask = NoMask); 1044 1045 // Privileged 1046 void uret(); 1047 void sret(); 1048 void mret(); 1049 void wfi(); 1050 void sfence_vma(Register rs1, Register rs2); 1051 1052 // Assembler Pseudo Instructions (Tables 25.2, 25.3, RISC-V Unprivileged ISA) 1053 void nop(); 1054 void RV_li(Register rd, int64_t imm); 1055 // Returns the number of instructions required to load the immediate 1056 static int li_estimate(int64_t imm, bool is_get_temp_reg = false); 1057 // Loads an immediate, always using 8 instructions, regardless of the value, 1058 // so that it can be modified later. 1059 void li_constant(Register rd, int64_t imm); 1060 void li_ptr(Register rd, int64_t imm); 1061 mv(Register rd,Register rs)1062 void mv(Register rd, Register rs) { addi(rd, rs, 0); } not_(Register rd,Register rs)1063 void not_(Register rd, Register rs) { xori(rd, rs, -1); } neg(Register rd,Register rs)1064 void neg(Register rd, Register rs) { sub(rd, zero_reg, rs); } negw(Register rd,Register rs)1065 void negw(Register rd, Register rs) { subw(rd, zero_reg, rs); } sext_w(Register rd,Register rs)1066 void sext_w(Register rd, Register rs) { addiw(rd, rs, 0); } seqz(Register rd,Register rs)1067 void seqz(Register rd, Register rs) { sltiu(rd, rs, 1); } snez(Register rd,Register rs)1068 void snez(Register rd, Register rs) { sltu(rd, zero_reg, rs); } sltz(Register rd,Register rs)1069 void sltz(Register rd, Register rs) { slt(rd, rs, zero_reg); } sgtz(Register rd,Register rs)1070 void sgtz(Register rd, Register rs) { slt(rd, zero_reg, rs); } 1071 fmv_s(FPURegister rd,FPURegister rs)1072 void fmv_s(FPURegister rd, FPURegister rs) { fsgnj_s(rd, rs, rs); } fabs_s(FPURegister rd,FPURegister rs)1073 void fabs_s(FPURegister rd, FPURegister rs) { fsgnjx_s(rd, rs, rs); } fneg_s(FPURegister rd,FPURegister rs)1074 void fneg_s(FPURegister rd, FPURegister rs) { fsgnjn_s(rd, rs, rs); } fmv_d(FPURegister rd,FPURegister rs)1075 void fmv_d(FPURegister rd, FPURegister rs) { fsgnj_d(rd, rs, rs); } fabs_d(FPURegister rd,FPURegister rs)1076 void fabs_d(FPURegister rd, FPURegister rs) { fsgnjx_d(rd, rs, rs); } fneg_d(FPURegister rd,FPURegister rs)1077 void fneg_d(FPURegister rd, FPURegister rs) { fsgnjn_d(rd, rs, rs); } 1078 beqz(Register rs,int16_t imm13)1079 void beqz(Register rs, int16_t imm13) { beq(rs, zero_reg, imm13); } beqz(Register rs1,Label * L)1080 inline void beqz(Register rs1, Label* L) { beqz(rs1, branch_offset(L)); } bnez(Register rs,int16_t imm13)1081 void bnez(Register rs, int16_t imm13) { bne(rs, zero_reg, imm13); } bnez(Register rs1,Label * L)1082 inline void bnez(Register rs1, Label* L) { bnez(rs1, branch_offset(L)); } blez(Register rs,int16_t imm13)1083 void blez(Register rs, int16_t imm13) { bge(zero_reg, rs, imm13); } blez(Register rs1,Label * L)1084 inline void blez(Register rs1, Label* L) { blez(rs1, branch_offset(L)); } bgez(Register rs,int16_t imm13)1085 void bgez(Register rs, int16_t imm13) { bge(rs, zero_reg, imm13); } bgez(Register rs1,Label * L)1086 inline void bgez(Register rs1, Label* L) { bgez(rs1, branch_offset(L)); } bltz(Register rs,int16_t imm13)1087 void bltz(Register rs, int16_t imm13) { blt(rs, zero_reg, imm13); } bltz(Register rs1,Label * L)1088 inline void bltz(Register rs1, Label* L) { bltz(rs1, branch_offset(L)); } bgtz(Register rs,int16_t imm13)1089 void bgtz(Register rs, int16_t imm13) { blt(zero_reg, rs, imm13); } 1090 bgtz(Register rs1,Label * L)1091 inline void bgtz(Register rs1, Label* L) { bgtz(rs1, branch_offset(L)); } bgt(Register rs1,Register rs2,int16_t imm13)1092 void bgt(Register rs1, Register rs2, int16_t imm13) { blt(rs2, rs1, imm13); } bgt(Register rs1,Register rs2,Label * L)1093 inline void bgt(Register rs1, Register rs2, Label* L) { 1094 bgt(rs1, rs2, branch_offset(L)); 1095 } ble(Register rs1,Register rs2,int16_t imm13)1096 void ble(Register rs1, Register rs2, int16_t imm13) { bge(rs2, rs1, imm13); } ble(Register rs1,Register rs2,Label * L)1097 inline void ble(Register rs1, Register rs2, Label* L) { 1098 ble(rs1, rs2, branch_offset(L)); 1099 } bgtu(Register rs1,Register rs2,int16_t imm13)1100 void bgtu(Register rs1, Register rs2, int16_t imm13) { 1101 bltu(rs2, rs1, imm13); 1102 } bgtu(Register rs1,Register rs2,Label * L)1103 inline void bgtu(Register rs1, Register rs2, Label* L) { 1104 bgtu(rs1, rs2, branch_offset(L)); 1105 } bleu(Register rs1,Register rs2,int16_t imm13)1106 void bleu(Register rs1, Register rs2, int16_t imm13) { 1107 bgeu(rs2, rs1, imm13); 1108 } bleu(Register rs1,Register rs2,Label * L)1109 inline void bleu(Register rs1, Register rs2, Label* L) { 1110 bleu(rs1, rs2, branch_offset(L)); 1111 } 1112 j(int32_t imm21)1113 void j(int32_t imm21) { jal(zero_reg, imm21); } j(Label * L)1114 inline void j(Label* L) { j(jump_offset(L)); } b(Label * L)1115 inline void b(Label* L) { j(L); } jal(int32_t imm21)1116 void jal(int32_t imm21) { jal(ra, imm21); } jal(Label * L)1117 inline void jal(Label* L) { jal(jump_offset(L)); } jr(Register rs)1118 void jr(Register rs) { jalr(zero_reg, rs, 0); } jr(Register rs,int32_t imm12)1119 void jr(Register rs, int32_t imm12) { jalr(zero_reg, rs, imm12); } jalr(Register rs,int32_t imm12)1120 void jalr(Register rs, int32_t imm12) { jalr(ra, rs, imm12); } jalr(Register rs)1121 void jalr(Register rs) { jalr(ra, rs, 0); } ret()1122 void ret() { jalr(zero_reg, ra, 0); } call(int32_t offset)1123 void call(int32_t offset) { 1124 auipc(ra, (offset >> 12) + ((offset & 0x800) >> 11)); 1125 jalr(ra, ra, offset << 20 >> 20); 1126 } 1127 1128 // Read instructions-retired counter rdinstret(Register rd)1129 void rdinstret(Register rd) { csrrs(rd, csr_instret, zero_reg); } rdinstreth(Register rd)1130 void rdinstreth(Register rd) { csrrs(rd, csr_instreth, zero_reg); } rdcycle(Register rd)1131 void rdcycle(Register rd) { csrrs(rd, csr_cycle, zero_reg); } rdcycleh(Register rd)1132 void rdcycleh(Register rd) { csrrs(rd, csr_cycleh, zero_reg); } rdtime(Register rd)1133 void rdtime(Register rd) { csrrs(rd, csr_time, zero_reg); } rdtimeh(Register rd)1134 void rdtimeh(Register rd) { csrrs(rd, csr_timeh, zero_reg); } 1135 csrr(Register rd,ControlStatusReg csr)1136 void csrr(Register rd, ControlStatusReg csr) { csrrs(rd, csr, zero_reg); } csrw(ControlStatusReg csr,Register rs)1137 void csrw(ControlStatusReg csr, Register rs) { csrrw(zero_reg, csr, rs); } csrs(ControlStatusReg csr,Register rs)1138 void csrs(ControlStatusReg csr, Register rs) { csrrs(zero_reg, csr, rs); } csrc(ControlStatusReg csr,Register rs)1139 void csrc(ControlStatusReg csr, Register rs) { csrrc(zero_reg, csr, rs); } 1140 csrwi(ControlStatusReg csr,uint8_t imm)1141 void csrwi(ControlStatusReg csr, uint8_t imm) { csrrwi(zero_reg, csr, imm); } csrsi(ControlStatusReg csr,uint8_t imm)1142 void csrsi(ControlStatusReg csr, uint8_t imm) { csrrsi(zero_reg, csr, imm); } csrci(ControlStatusReg csr,uint8_t imm)1143 void csrci(ControlStatusReg csr, uint8_t imm) { csrrci(zero_reg, csr, imm); } 1144 frcsr(Register rd)1145 void frcsr(Register rd) { csrrs(rd, csr_fcsr, zero_reg); } fscsr(Register rd,Register rs)1146 void fscsr(Register rd, Register rs) { csrrw(rd, csr_fcsr, rs); } fscsr(Register rs)1147 void fscsr(Register rs) { csrrw(zero_reg, csr_fcsr, rs); } 1148 frrm(Register rd)1149 void frrm(Register rd) { csrrs(rd, csr_frm, zero_reg); } fsrm(Register rd,Register rs)1150 void fsrm(Register rd, Register rs) { csrrw(rd, csr_frm, rs); } fsrm(Register rs)1151 void fsrm(Register rs) { csrrw(zero_reg, csr_frm, rs); } 1152 frflags(Register rd)1153 void frflags(Register rd) { csrrs(rd, csr_fflags, zero_reg); } fsflags(Register rd,Register rs)1154 void fsflags(Register rd, Register rs) { csrrw(rd, csr_fflags, rs); } fsflags(Register rs)1155 void fsflags(Register rs) { csrrw(zero_reg, csr_fflags, rs); } 1156 1157 // Other pseudo instructions that are not part of RISCV pseudo assemly nor(Register rd,Register rs,Register rt)1158 void nor(Register rd, Register rs, Register rt) { 1159 or_(rd, rs, rt); 1160 not_(rd, rd); 1161 } 1162 sync()1163 void sync() { fence(0b1111, 0b1111); } 1164 void break_(uint32_t code, bool break_as_stop = false); 1165 void stop(uint32_t code = kMaxStopCode); 1166 1167 // Check the code size generated from label to here. SizeOfCodeGeneratedSince(Label * label)1168 int SizeOfCodeGeneratedSince(Label* label) { 1169 return pc_offset() - label->pos(); 1170 } 1171 1172 // Check the number of instructions generated from label to here. InstructionsGeneratedSince(Label * label)1173 int InstructionsGeneratedSince(Label* label) { 1174 return SizeOfCodeGeneratedSince(label) / kInstrSize; 1175 } 1176 1177 using BlockConstPoolScope = ConstantPool::BlockScope; 1178 // Class for scoping postponing the trampoline pool generation. 1179 class BlockTrampolinePoolScope { 1180 public: 1181 explicit BlockTrampolinePoolScope(Assembler* assem, int margin = 0) assem_(assem)1182 : assem_(assem) { 1183 assem_->StartBlockTrampolinePool(); 1184 } 1185 BlockTrampolinePoolScope(Assembler * assem,PoolEmissionCheck check)1186 explicit BlockTrampolinePoolScope(Assembler* assem, PoolEmissionCheck check) 1187 : assem_(assem) { 1188 assem_->StartBlockTrampolinePool(); 1189 } ~BlockTrampolinePoolScope()1190 ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); } 1191 1192 private: 1193 Assembler* assem_; 1194 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope); 1195 }; 1196 1197 // Class for postponing the assembly buffer growth. Typically used for 1198 // sequences of instructions that must be emitted as a unit, before 1199 // buffer growth (and relocation) can occur. 1200 // This blocking scope is not nestable. 1201 class BlockGrowBufferScope { 1202 public: BlockGrowBufferScope(Assembler * assem)1203 explicit BlockGrowBufferScope(Assembler* assem) : assem_(assem) { 1204 assem_->StartBlockGrowBuffer(); 1205 } ~BlockGrowBufferScope()1206 ~BlockGrowBufferScope() { assem_->EndBlockGrowBuffer(); } 1207 1208 private: 1209 Assembler* assem_; 1210 1211 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope); 1212 }; 1213 1214 // Record a deoptimization reason that can be used by a log or cpu profiler. 1215 // Use --trace-deopt to enable. 1216 void RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id, 1217 SourcePosition position, int id); 1218 1219 static int RelocateInternalReference(RelocInfo::Mode rmode, Address pc, 1220 intptr_t pc_delta); 1221 static void RelocateRelativeReference(RelocInfo::Mode rmode, Address pc, 1222 intptr_t pc_delta); 1223 1224 // Writes a single byte or word of data in the code stream. Used for 1225 // inline tables, e.g., jump-tables. 1226 void db(uint8_t data); 1227 void dd(uint32_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO); 1228 void dq(uint64_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO); 1229 void dp(uintptr_t data, RelocInfo::Mode rmode = RelocInfo::NO_INFO) { 1230 dq(data, rmode); 1231 } 1232 void dd(Label* label); 1233 pc()1234 Instruction* pc() const { return reinterpret_cast<Instruction*>(pc_); } 1235 1236 // Postpone the generation of the trampoline pool for the specified number of 1237 // instructions. 1238 void BlockTrampolinePoolFor(int instructions); 1239 1240 // Check if there is less than kGap bytes available in the buffer. 1241 // If this is the case, we need to grow the buffer before emitting 1242 // an instruction or relocation information. overflow()1243 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } 1244 1245 // Get the number of bytes available in the buffer. available_space()1246 inline intptr_t available_space() const { 1247 return reloc_info_writer.pos() - pc_; 1248 } 1249 1250 // Read/patch instructions. instr_at(Address pc)1251 static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); } instr_at_put(Address pc,Instr instr)1252 static void instr_at_put(Address pc, Instr instr) { 1253 *reinterpret_cast<Instr*>(pc) = instr; 1254 } instr_at(int pos)1255 Instr instr_at(int pos) { 1256 return *reinterpret_cast<Instr*>(buffer_start_ + pos); 1257 } instr_at_put(int pos,Instr instr)1258 void instr_at_put(int pos, Instr instr) { 1259 *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr; 1260 } 1261 instr_at_put(int pos,ShortInstr instr)1262 void instr_at_put(int pos, ShortInstr instr) { 1263 *reinterpret_cast<ShortInstr*>(buffer_start_ + pos) = instr; 1264 } 1265 toAddress(int pos)1266 Address toAddress(int pos) { 1267 return reinterpret_cast<Address>(buffer_start_ + pos); 1268 } 1269 1270 // Check if an instruction is a branch of some kind. 1271 static bool IsBranch(Instr instr); 1272 static bool IsCBranch(Instr instr); 1273 static bool IsNop(Instr instr); 1274 static bool IsJump(Instr instr); 1275 static bool IsJal(Instr instr); 1276 static bool IsCJal(Instr instr); 1277 static bool IsJalr(Instr instr); 1278 static bool IsLui(Instr instr); 1279 static bool IsAuipc(Instr instr); 1280 static bool IsAddiw(Instr instr); 1281 static bool IsAddi(Instr instr); 1282 static bool IsOri(Instr instr); 1283 static bool IsSlli(Instr instr); 1284 static bool IsLd(Instr instr); 1285 void CheckTrampolinePool(); 1286 1287 // Get the code target object for a pc-relative call or jump. 1288 V8_INLINE Handle<Code> relative_code_target_object_handle_at( 1289 Address pc_) const; 1290 UnboundLabelsCount()1291 inline int UnboundLabelsCount() { return unbound_labels_count_; } 1292 1293 using BlockPoolsScope = BlockTrampolinePoolScope; 1294 1295 void RecordConstPool(int size); 1296 ForceConstantPoolEmissionWithoutJump()1297 void ForceConstantPoolEmissionWithoutJump() { 1298 constpool_.Check(Emission::kForced, Jump::kOmitted); 1299 } ForceConstantPoolEmissionWithJump()1300 void ForceConstantPoolEmissionWithJump() { 1301 constpool_.Check(Emission::kForced, Jump::kRequired); 1302 } 1303 // Check if the const pool needs to be emitted while pretending that {margin} 1304 // more bytes of instructions have already been emitted. 1305 void EmitConstPoolWithJumpIfNeeded(size_t margin = 0) { 1306 constpool_.Check(Emission::kIfNeeded, Jump::kRequired, margin); 1307 } 1308 1309 void EmitConstPoolWithoutJumpIfNeeded(size_t margin = 0) { 1310 constpool_.Check(Emission::kIfNeeded, Jump::kOmitted, margin); 1311 } 1312 RecordEntry(uint32_t data,RelocInfo::Mode rmode)1313 void RecordEntry(uint32_t data, RelocInfo::Mode rmode) { 1314 constpool_.RecordEntry(data, rmode); 1315 } 1316 RecordEntry(uint64_t data,RelocInfo::Mode rmode)1317 void RecordEntry(uint64_t data, RelocInfo::Mode rmode) { 1318 constpool_.RecordEntry(data, rmode); 1319 } 1320 1321 friend class VectorUnit; 1322 class VectorUnit { 1323 public: sew()1324 inline int32_t sew() const { return 2 ^ (sew_ + 3); } 1325 vlmax()1326 inline int32_t vlmax() const { 1327 if ((lmul_ & 0b100) != 0) { 1328 return (kRvvVLEN / sew()) >> (lmul_ & 0b11); 1329 } else { 1330 return ((kRvvVLEN << lmul_) / sew()); 1331 } 1332 } 1333 VectorUnit(Assembler * assm)1334 explicit VectorUnit(Assembler* assm) : assm_(assm) {} 1335 set(Register rd,VSew sew,Vlmul lmul)1336 void set(Register rd, VSew sew, Vlmul lmul) { 1337 if (sew != sew_ || lmul != lmul_ || vl != vlmax()) { 1338 sew_ = sew; 1339 lmul_ = lmul; 1340 vl = vlmax(); 1341 assm_->vsetvlmax(rd, sew_, lmul_); 1342 } 1343 } 1344 set(Register rd,int8_t sew,int8_t lmul)1345 void set(Register rd, int8_t sew, int8_t lmul) { 1346 DCHECK_GE(sew, E8); 1347 DCHECK_LE(sew, E64); 1348 DCHECK_GE(lmul, m1); 1349 DCHECK_LE(lmul, mf2); 1350 set(rd, VSew(sew), Vlmul(lmul)); 1351 } 1352 set(RoundingMode mode)1353 void set(RoundingMode mode) { 1354 if (mode_ != mode) { 1355 assm_->addi(kScratchReg, zero_reg, mode << kFcsrFrmShift); 1356 assm_->fscsr(kScratchReg); 1357 mode_ = mode; 1358 } 1359 } set(Register rd,Register rs1,VSew sew,Vlmul lmul)1360 void set(Register rd, Register rs1, VSew sew, Vlmul lmul) { 1361 if (sew != sew_ || lmul != lmul_) { 1362 sew_ = sew; 1363 lmul_ = lmul; 1364 vl = 0; 1365 assm_->vsetvli(rd, rs1, sew_, lmul_); 1366 } 1367 } 1368 set(VSew sew,Vlmul lmul)1369 void set(VSew sew, Vlmul lmul) { 1370 if (sew != sew_ || lmul != lmul_) { 1371 sew_ = sew; 1372 lmul_ = lmul; 1373 assm_->vsetvl(sew_, lmul_); 1374 } 1375 } 1376 1377 private: 1378 VSew sew_ = E8; 1379 Vlmul lmul_ = m1; 1380 int32_t vl = 0; 1381 Assembler* assm_; 1382 RoundingMode mode_ = RNE; 1383 }; 1384 1385 VectorUnit VU; 1386 1387 void CheckTrampolinePoolQuick(int extra_instructions = 0) { 1388 DEBUG_PRINTF("\tpc_offset:%d %d\n", pc_offset(), 1389 next_buffer_check_ - extra_instructions * kInstrSize); 1390 if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) { 1391 CheckTrampolinePool(); 1392 } 1393 } 1394 1395 protected: 1396 // Readable constants for base and offset adjustment helper, these indicate if 1397 // aside from offset, another value like offset + 4 should fit into int16. 1398 enum class OffsetAccessType : bool { 1399 SINGLE_ACCESS = false, 1400 TWO_ACCESSES = true 1401 }; 1402 1403 // Determine whether need to adjust base and offset of memroy load/store 1404 bool NeedAdjustBaseAndOffset( 1405 const MemOperand& src, OffsetAccessType = OffsetAccessType::SINGLE_ACCESS, 1406 int second_Access_add_to_offset = 4); 1407 1408 // Helper function for memory load/store using base register and offset. 1409 void AdjustBaseAndOffset( 1410 MemOperand* src, Register scratch, 1411 OffsetAccessType access_type = OffsetAccessType::SINGLE_ACCESS, 1412 int second_access_add_to_offset = 4); 1413 1414 inline static void set_target_internal_reference_encoded_at(Address pc, 1415 Address target); 1416 buffer_space()1417 int64_t buffer_space() const { return reloc_info_writer.pos() - pc_; } 1418 1419 // Decode branch instruction at pos and return branch target pos. 1420 int target_at(int pos, bool is_internal); 1421 1422 // Patch branch instruction at pos to branch to given branch target pos. 1423 void target_at_put(int pos, int target_pos, bool is_internal, 1424 bool trampoline = false); 1425 1426 // Say if we need to relocate with this mode. 1427 bool MustUseReg(RelocInfo::Mode rmode); 1428 1429 // Record reloc info for current pc_. 1430 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); 1431 1432 // Block the emission of the trampoline pool before pc_offset. BlockTrampolinePoolBefore(int pc_offset)1433 void BlockTrampolinePoolBefore(int pc_offset) { 1434 if (no_trampoline_pool_before_ < pc_offset) 1435 no_trampoline_pool_before_ = pc_offset; 1436 } 1437 StartBlockTrampolinePool()1438 void StartBlockTrampolinePool() { 1439 DEBUG_PRINTF("\tStartBlockTrampolinePool\n"); 1440 trampoline_pool_blocked_nesting_++; 1441 } 1442 EndBlockTrampolinePool()1443 void EndBlockTrampolinePool() { 1444 trampoline_pool_blocked_nesting_--; 1445 DEBUG_PRINTF("\ttrampoline_pool_blocked_nesting:%d\n", 1446 trampoline_pool_blocked_nesting_); 1447 if (trampoline_pool_blocked_nesting_ == 0) { 1448 CheckTrampolinePoolQuick(1); 1449 } 1450 } 1451 is_trampoline_pool_blocked()1452 bool is_trampoline_pool_blocked() const { 1453 return trampoline_pool_blocked_nesting_ > 0; 1454 } 1455 has_exception()1456 bool has_exception() const { return internal_trampoline_exception_; } 1457 is_trampoline_emitted()1458 bool is_trampoline_emitted() const { return trampoline_emitted_; } 1459 1460 // Temporarily block automatic assembly buffer growth. StartBlockGrowBuffer()1461 void StartBlockGrowBuffer() { 1462 DCHECK(!block_buffer_growth_); 1463 block_buffer_growth_ = true; 1464 } 1465 EndBlockGrowBuffer()1466 void EndBlockGrowBuffer() { 1467 DCHECK(block_buffer_growth_); 1468 block_buffer_growth_ = false; 1469 } 1470 is_buffer_growth_blocked()1471 bool is_buffer_growth_blocked() const { return block_buffer_growth_; } 1472 1473 private: 1474 void vsetvli(Register rd, Register rs1, VSew vsew, Vlmul vlmul, 1475 TailAgnosticType tail = tu, MaskAgnosticType mask = mu); 1476 1477 void vsetivli(Register rd, uint8_t uimm, VSew vsew, Vlmul vlmul, 1478 TailAgnosticType tail = tu, MaskAgnosticType mask = mu); 1479 1480 inline void vsetvlmax(Register rd, VSew vsew, Vlmul vlmul, 1481 TailAgnosticType tail = tu, 1482 MaskAgnosticType mask = mu) { 1483 vsetvli(rd, zero_reg, vsew, vlmul, tu, mu); 1484 } 1485 1486 inline void vsetvl(VSew vsew, Vlmul vlmul, TailAgnosticType tail = tu, 1487 MaskAgnosticType mask = mu) { 1488 vsetvli(zero_reg, zero_reg, vsew, vlmul, tu, mu); 1489 } 1490 1491 void vsetvl(Register rd, Register rs1, Register rs2); 1492 1493 // Avoid overflows for displacements etc. 1494 static const int kMaximalBufferSize = 512 * MB; 1495 1496 // Buffer size and constant pool distance are checked together at regular 1497 // intervals of kBufferCheckInterval emitted bytes. 1498 static constexpr int kBufferCheckInterval = 1 * KB / 2; 1499 1500 // Code generation. 1501 // The relocation writer's position is at least kGap bytes below the end of 1502 // the generated instructions. This is so that multi-instruction sequences do 1503 // not have to check for overflow. The same is true for writes of large 1504 // relocation info entries. 1505 static constexpr int kGap = 64; 1506 STATIC_ASSERT(AssemblerBase::kMinimalBufferSize >= 2 * kGap); 1507 1508 // Repeated checking whether the trampoline pool should be emitted is rather 1509 // expensive. By default we only check again once a number of instructions 1510 // has been generated. 1511 static constexpr int kCheckConstIntervalInst = 32; 1512 static constexpr int kCheckConstInterval = 1513 kCheckConstIntervalInst * kInstrSize; 1514 1515 int next_buffer_check_; // pc offset of next buffer check. 1516 1517 // Emission of the trampoline pool may be blocked in some code sequences. 1518 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero. 1519 int no_trampoline_pool_before_; // Block emission before this pc offset. 1520 1521 // Keep track of the last emitted pool to guarantee a maximal distance. 1522 int last_trampoline_pool_end_; // pc offset of the end of the last pool. 1523 1524 // Automatic growth of the assembly buffer may be blocked for some sequences. 1525 bool block_buffer_growth_; // Block growth when true. 1526 1527 // Relocation information generation. 1528 // Each relocation is encoded as a variable size value. 1529 static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize; 1530 RelocInfoWriter reloc_info_writer; 1531 1532 // The bound position, before this we cannot do instruction elimination. 1533 int last_bound_pos_; 1534 1535 // Code emission. 1536 inline void CheckBuffer(); 1537 void GrowBuffer(); 1538 inline void emit(Instr x); 1539 inline void emit(ShortInstr x); 1540 inline void emit(uint64_t x); 1541 template <typename T> 1542 inline void EmitHelper(T x); 1543 1544 static void disassembleInstr(Instr instr); 1545 1546 // Instruction generation. 1547 1548 // ----- Top-level instruction formats match those in the ISA manual 1549 // (R, I, S, B, U, J). These match the formats defined in LLVM's 1550 // RISCVInstrFormats.td. 1551 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, 1552 Register rs1, Register rs2); 1553 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, 1554 FPURegister rs1, FPURegister rs2); 1555 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, 1556 FPURegister rs1, Register rs2); 1557 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, 1558 Register rs1, Register rs2); 1559 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, 1560 FPURegister rs1, Register rs2); 1561 void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, 1562 FPURegister rs1, FPURegister rs2); 1563 void GenInstrR4(uint8_t funct2, Opcode opcode, Register rd, Register rs1, 1564 Register rs2, Register rs3, RoundingMode frm); 1565 void GenInstrR4(uint8_t funct2, Opcode opcode, FPURegister rd, 1566 FPURegister rs1, FPURegister rs2, FPURegister rs3, 1567 RoundingMode frm); 1568 void GenInstrRAtomic(uint8_t funct5, bool aq, bool rl, uint8_t funct3, 1569 Register rd, Register rs1, Register rs2); 1570 void GenInstrRFrm(uint8_t funct7, Opcode opcode, Register rd, Register rs1, 1571 Register rs2, RoundingMode frm); 1572 void GenInstrI(uint8_t funct3, Opcode opcode, Register rd, Register rs1, 1573 int16_t imm12); 1574 void GenInstrI(uint8_t funct3, Opcode opcode, FPURegister rd, Register rs1, 1575 int16_t imm12); 1576 void GenInstrIShift(bool arithshift, uint8_t funct3, Opcode opcode, 1577 Register rd, Register rs1, uint8_t shamt); 1578 void GenInstrIShiftW(bool arithshift, uint8_t funct3, Opcode opcode, 1579 Register rd, Register rs1, uint8_t shamt); 1580 void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, Register rs2, 1581 int16_t imm12); 1582 void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, FPURegister rs2, 1583 int16_t imm12); 1584 void GenInstrB(uint8_t funct3, Opcode opcode, Register rs1, Register rs2, 1585 int16_t imm12); 1586 void GenInstrU(Opcode opcode, Register rd, int32_t imm20); 1587 void GenInstrJ(Opcode opcode, Register rd, int32_t imm20); 1588 void GenInstrCR(uint8_t funct4, Opcode opcode, Register rd, Register rs2); 1589 void GenInstrCA(uint8_t funct6, Opcode opcode, Register rd, uint8_t funct, 1590 Register rs2); 1591 void GenInstrCI(uint8_t funct3, Opcode opcode, Register rd, int8_t imm6); 1592 void GenInstrCIU(uint8_t funct3, Opcode opcode, Register rd, uint8_t uimm6); 1593 void GenInstrCIU(uint8_t funct3, Opcode opcode, FPURegister rd, 1594 uint8_t uimm6); 1595 void GenInstrCIW(uint8_t funct3, Opcode opcode, Register rd, uint8_t uimm8); 1596 void GenInstrCSS(uint8_t funct3, Opcode opcode, FPURegister rs2, 1597 uint8_t uimm6); 1598 void GenInstrCSS(uint8_t funct3, Opcode opcode, Register rs2, uint8_t uimm6); 1599 void GenInstrCL(uint8_t funct3, Opcode opcode, Register rd, Register rs1, 1600 uint8_t uimm5); 1601 void GenInstrCL(uint8_t funct3, Opcode opcode, FPURegister rd, Register rs1, 1602 uint8_t uimm5); 1603 void GenInstrCS(uint8_t funct3, Opcode opcode, Register rs2, Register rs1, 1604 uint8_t uimm5); 1605 void GenInstrCS(uint8_t funct3, Opcode opcode, FPURegister rs2, Register rs1, 1606 uint8_t uimm5); 1607 void GenInstrCJ(uint8_t funct3, Opcode opcode, uint16_t uint11); 1608 void GenInstrCB(uint8_t funct3, Opcode opcode, Register rs1, uint8_t uimm8); 1609 void GenInstrCBA(uint8_t funct3, uint8_t funct2, Opcode opcode, Register rs1, 1610 int8_t imm6); 1611 1612 // ----- Instruction class templates match those in LLVM's RISCVInstrInfo.td 1613 void GenInstrBranchCC_rri(uint8_t funct3, Register rs1, Register rs2, 1614 int16_t imm12); 1615 void GenInstrLoad_ri(uint8_t funct3, Register rd, Register rs1, 1616 int16_t imm12); 1617 void GenInstrStore_rri(uint8_t funct3, Register rs1, Register rs2, 1618 int16_t imm12); 1619 void GenInstrALU_ri(uint8_t funct3, Register rd, Register rs1, int16_t imm12); 1620 void GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd, 1621 Register rs1, uint8_t shamt); 1622 void GenInstrALU_rr(uint8_t funct7, uint8_t funct3, Register rd, Register rs1, 1623 Register rs2); 1624 void GenInstrCSR_ir(uint8_t funct3, Register rd, ControlStatusReg csr, 1625 Register rs1); 1626 void GenInstrCSR_ii(uint8_t funct3, Register rd, ControlStatusReg csr, 1627 uint8_t rs1); 1628 void GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd, 1629 Register rs1, uint8_t shamt); 1630 void GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, Register rd, 1631 Register rs1, Register rs2); 1632 void GenInstrPriv(uint8_t funct7, Register rs1, Register rs2); 1633 void GenInstrLoadFP_ri(uint8_t funct3, FPURegister rd, Register rs1, 1634 int16_t imm12); 1635 void GenInstrStoreFP_rri(uint8_t funct3, Register rs1, FPURegister rs2, 1636 int16_t imm12); 1637 void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, 1638 FPURegister rs1, FPURegister rs2); 1639 void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, 1640 Register rs1, Register rs2); 1641 void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, 1642 FPURegister rs1, Register rs2); 1643 void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, 1644 FPURegister rs1, Register rs2); 1645 void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, 1646 FPURegister rs1, FPURegister rs2); 1647 1648 // ----------------------------RVV------------------------------------------ 1649 // vsetvl 1650 void GenInstrV(Register rd, Register rs1, Register rs2); 1651 // vsetvli 1652 void GenInstrV(Register rd, Register rs1, uint32_t zimm); 1653 // OPIVV OPFVV OPMVV 1654 void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, VRegister vs1, 1655 VRegister vs2, MaskType mask = NoMask); 1656 void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, int8_t vs1, 1657 VRegister vs2, MaskType mask = NoMask); 1658 void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, VRegister vs2, 1659 MaskType mask = NoMask); 1660 // OPMVV OPFVV 1661 void GenInstrV(uint8_t funct6, Opcode opcode, Register rd, VRegister vs1, 1662 VRegister vs2, MaskType mask = NoMask); 1663 // OPFVV 1664 void GenInstrV(uint8_t funct6, Opcode opcode, FPURegister fd, VRegister vs1, 1665 VRegister vs2, MaskType mask = NoMask); 1666 1667 // OPIVX OPMVX 1668 void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, Register rs1, 1669 VRegister vs2, MaskType mask = NoMask); 1670 // OPFVF 1671 void GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd, FPURegister fs1, 1672 VRegister vs2, MaskType mask = NoMask); 1673 // OPMVX 1674 void GenInstrV(uint8_t funct6, Register rd, Register rs1, VRegister vs2, 1675 MaskType mask = NoMask); 1676 // OPIVI 1677 void GenInstrV(uint8_t funct6, VRegister vd, int8_t simm5, VRegister vs2, 1678 MaskType mask = NoMask); 1679 1680 // VL VS 1681 void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1, 1682 uint8_t umop, MaskType mask, uint8_t IsMop, bool IsMew, 1683 uint8_t Nf); 1684 1685 void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1, 1686 Register rs2, MaskType mask, uint8_t IsMop, bool IsMew, 1687 uint8_t Nf); 1688 // VL VS AMO 1689 void GenInstrV(Opcode opcode, uint8_t width, VRegister vd, Register rs1, 1690 VRegister vs2, MaskType mask, uint8_t IsMop, bool IsMew, 1691 uint8_t Nf); 1692 // vmv_xs vcpop_m vfirst_m 1693 void GenInstrV(uint8_t funct6, Opcode opcode, Register rd, uint8_t vs1, 1694 VRegister vs2, MaskType mask); 1695 // Labels. 1696 void print(const Label* L); 1697 void bind_to(Label* L, int pos); 1698 void next(Label* L, bool is_internal); 1699 1700 // One trampoline consists of: 1701 // - space for trampoline slots, 1702 // - space for labels. 1703 // 1704 // Space for trampoline slots is equal to slot_count * 2 * kInstrSize. 1705 // Space for trampoline slots precedes space for labels. Each label is of one 1706 // instruction size, so total amount for labels is equal to 1707 // label_count * kInstrSize. 1708 class Trampoline { 1709 public: Trampoline()1710 Trampoline() { 1711 start_ = 0; 1712 next_slot_ = 0; 1713 free_slot_count_ = 0; 1714 end_ = 0; 1715 } Trampoline(int start,int slot_count)1716 Trampoline(int start, int slot_count) { 1717 start_ = start; 1718 next_slot_ = start; 1719 free_slot_count_ = slot_count; 1720 end_ = start + slot_count * kTrampolineSlotsSize; 1721 } start()1722 int start() { return start_; } end()1723 int end() { return end_; } take_slot()1724 int take_slot() { 1725 int trampoline_slot = kInvalidSlotPos; 1726 if (free_slot_count_ <= 0) { 1727 // We have run out of space on trampolines. 1728 // Make sure we fail in debug mode, so we become aware of each case 1729 // when this happens. 1730 DCHECK(0); 1731 // Internal exception will be caught. 1732 } else { 1733 trampoline_slot = next_slot_; 1734 free_slot_count_--; 1735 next_slot_ += kTrampolineSlotsSize; 1736 } 1737 return trampoline_slot; 1738 } 1739 1740 private: 1741 int start_; 1742 int end_; 1743 int next_slot_; 1744 int free_slot_count_; 1745 }; 1746 1747 int32_t get_trampoline_entry(int32_t pos); 1748 int unbound_labels_count_; 1749 // After trampoline is emitted, long branches are used in generated code for 1750 // the forward branches whose target offsets could be beyond reach of branch 1751 // instruction. We use this information to trigger different mode of 1752 // branch instruction generation, where we use jump instructions rather 1753 // than regular branch instructions. 1754 bool trampoline_emitted_ = false; 1755 static constexpr int kInvalidSlotPos = -1; 1756 1757 // Internal reference positions, required for unbounded internal reference 1758 // labels. 1759 std::set<int64_t> internal_reference_positions_; is_internal_reference(Label * L)1760 bool is_internal_reference(Label* L) { 1761 return internal_reference_positions_.find(L->pos()) != 1762 internal_reference_positions_.end(); 1763 } 1764 1765 Trampoline trampoline_; 1766 bool internal_trampoline_exception_; 1767 1768 RegList scratch_register_list_; 1769 1770 private: 1771 ConstantPool constpool_; 1772 1773 void AllocateAndInstallRequestedHeapObjects(Isolate* isolate); 1774 1775 int WriteCodeComments(); 1776 1777 friend class RegExpMacroAssemblerRISCV; 1778 friend class RelocInfo; 1779 friend class BlockTrampolinePoolScope; 1780 friend class EnsureSpace; 1781 friend class ConstantPool; 1782 }; 1783 1784 class EnsureSpace { 1785 public: 1786 explicit inline EnsureSpace(Assembler* assembler); 1787 }; 1788 1789 class V8_EXPORT_PRIVATE UseScratchRegisterScope { 1790 public: 1791 explicit UseScratchRegisterScope(Assembler* assembler); 1792 ~UseScratchRegisterScope(); 1793 1794 Register Acquire(); 1795 bool hasAvailable() const; Include(const RegList & list)1796 void Include(const RegList& list) { *available_ |= list; } Exclude(const RegList & list)1797 void Exclude(const RegList& list) { 1798 *available_ &= RegList::FromBits(~list.bits()); 1799 } 1800 void Include(const Register& reg1, const Register& reg2 = no_reg) { 1801 RegList list({reg1, reg2}); 1802 Include(list); 1803 } 1804 void Exclude(const Register& reg1, const Register& reg2 = no_reg) { 1805 RegList list({reg1, reg2}); 1806 Exclude(list); 1807 } 1808 1809 private: 1810 RegList* available_; 1811 RegList old_available_; 1812 }; 1813 1814 class LoadStoreLaneParams { 1815 public: 1816 int sz; 1817 uint8_t laneidx; 1818 1819 LoadStoreLaneParams(MachineRepresentation rep, uint8_t laneidx); 1820 1821 private: LoadStoreLaneParams(uint8_t laneidx,int sz,int lanes)1822 LoadStoreLaneParams(uint8_t laneidx, int sz, int lanes) 1823 : sz(sz), laneidx(laneidx % lanes) {} 1824 }; 1825 1826 } // namespace internal 1827 } // namespace v8 1828 1829 #endif // V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_H_ 1830