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 #if V8_TARGET_ARCH_RISCV64
36
37 #include "src/codegen/riscv64/assembler-riscv64.h"
38
39 #include "src/base/cpu.h"
40 #include "src/codegen/riscv64/assembler-riscv64-inl.h"
41 #include "src/codegen/safepoint-table.h"
42 #include "src/codegen/string-constants.h"
43 #include "src/deoptimizer/deoptimizer.h"
44 #include "src/diagnostics/disasm.h"
45 #include "src/diagnostics/disassembler.h"
46 #include "src/objects/heap-number-inl.h"
47
48 namespace v8 {
49 namespace internal {
50 // Get the CPU features enabled by the build. For cross compilation the
51 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
52 // can be defined to enable FPU instructions when building the
53 // snapshot.
CpuFeaturesImpliedByCompiler()54 static unsigned CpuFeaturesImpliedByCompiler() {
55 unsigned answer = 0;
56 #ifdef CAN_USE_FPU_INSTRUCTIONS
57 answer |= 1u << FPU;
58 #endif // def CAN_USE_FPU_INSTRUCTIONS
59
60 #ifdef CAN_USE_RVV_INSTRUCTIONS
61 answer |= 1u << RISCV_SIMD;
62 #endif // def CAN_USE_RVV_INSTRUCTIONS
63 return answer;
64 }
65
SupportsWasmSimd128()66 bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(RISCV_SIMD); }
67
ProbeImpl(bool cross_compile)68 void CpuFeatures::ProbeImpl(bool cross_compile) {
69 supported_ |= CpuFeaturesImpliedByCompiler();
70 // Only use statically determined features for cross compile (snapshot).
71 if (cross_compile) return;
72 // Probe for additional features at runtime.
73 base::CPU cpu;
74 if (cpu.has_fpu()) supported_ |= 1u << FPU;
75 // Set a static value on whether SIMD is supported.
76 // This variable is only used for certain archs to query SupportWasmSimd128()
77 // at runtime in builtins using an extern ref. Other callers should use
78 // CpuFeatures::SupportWasmSimd128().
79 CpuFeatures::supports_wasm_simd_128_ = CpuFeatures::SupportsWasmSimd128();
80 }
81
PrintTarget()82 void CpuFeatures::PrintTarget() {}
PrintFeatures()83 void CpuFeatures::PrintFeatures() {}
ToNumber(Register reg)84 int ToNumber(Register reg) {
85 DCHECK(reg.is_valid());
86 const int kNumbers[] = {
87 0, // zero_reg
88 1, // ra
89 2, // sp
90 3, // gp
91 4, // tp
92 5, // t0
93 6, // t1
94 7, // t2
95 8, // s0/fp
96 9, // s1
97 10, // a0
98 11, // a1
99 12, // a2
100 13, // a3
101 14, // a4
102 15, // a5
103 16, // a6
104 17, // a7
105 18, // s2
106 19, // s3
107 20, // s4
108 21, // s5
109 22, // s6
110 23, // s7
111 24, // s8
112 25, // s9
113 26, // s10
114 27, // s11
115 28, // t3
116 29, // t4
117 30, // t5
118 31, // t6
119 };
120 return kNumbers[reg.code()];
121 }
122
ToRegister(int num)123 Register ToRegister(int num) {
124 DCHECK(num >= 0 && num < kNumRegisters);
125 const Register kRegisters[] = {
126 zero_reg, ra, sp, gp, tp, t0, t1, t2, fp, s1, a0, a1, a2, a3, a4, a5,
127 a6, a7, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, t3, t4, t5, t6};
128 return kRegisters[num];
129 }
130
131 // -----------------------------------------------------------------------------
132 // Implementation of RelocInfo.
133
134 const int RelocInfo::kApplyMask =
135 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
136 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
137 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
138
IsCodedSpecially()139 bool RelocInfo::IsCodedSpecially() {
140 // The deserializer needs to know whether a pointer is specially coded. Being
141 // specially coded on RISC-V means that it is a lui/addi instruction, and that
142 // is always the case inside code objects.
143 return true;
144 }
145
IsInConstantPool()146 bool RelocInfo::IsInConstantPool() { return false; }
147
wasm_call_tag() const148 uint32_t RelocInfo::wasm_call_tag() const {
149 DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
150 return static_cast<uint32_t>(
151 Assembler::target_address_at(pc_, constant_pool_));
152 }
153
154 // -----------------------------------------------------------------------------
155 // Implementation of Operand and MemOperand.
156 // See assembler-riscv64-inl.h for inlined constructors.
157
Operand(Handle<HeapObject> handle)158 Operand::Operand(Handle<HeapObject> handle)
159 : rm_(no_reg), rmode_(RelocInfo::FULL_EMBEDDED_OBJECT) {
160 value_.immediate = static_cast<intptr_t>(handle.address());
161 }
162
EmbeddedNumber(double value)163 Operand Operand::EmbeddedNumber(double value) {
164 int32_t smi;
165 if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi));
166 Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
167 result.is_heap_object_request_ = true;
168 result.value_.heap_object_request = HeapObjectRequest(value);
169 return result;
170 }
171
EmbeddedStringConstant(const StringConstantBase * str)172 Operand Operand::EmbeddedStringConstant(const StringConstantBase* str) {
173 Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
174 result.is_heap_object_request_ = true;
175 result.value_.heap_object_request = HeapObjectRequest(str);
176 return result;
177 }
178
MemOperand(Register rm,int32_t offset)179 MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
180 offset_ = offset;
181 }
182
MemOperand(Register rm,int32_t unit,int32_t multiplier,OffsetAddend offset_addend)183 MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
184 OffsetAddend offset_addend)
185 : Operand(rm) {
186 offset_ = unit * multiplier + offset_addend;
187 }
188
AllocateAndInstallRequestedHeapObjects(Isolate * isolate)189 void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
190 DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
191 for (auto& request : heap_object_requests_) {
192 Handle<HeapObject> object;
193 switch (request.kind()) {
194 case HeapObjectRequest::kHeapNumber:
195 object = isolate->factory()->NewHeapNumber<AllocationType::kOld>(
196 request.heap_number());
197 break;
198 case HeapObjectRequest::kStringConstant:
199 const StringConstantBase* str = request.string();
200 CHECK_NOT_NULL(str);
201 object = str->AllocateStringConstant(isolate);
202 break;
203 }
204 Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
205 set_target_value_at(pc, reinterpret_cast<uint64_t>(object.location()));
206 }
207 }
208
209 // -----------------------------------------------------------------------------
210 // Specific instructions, constants, and masks.
211
Assembler(const AssemblerOptions & options,std::unique_ptr<AssemblerBuffer> buffer)212 Assembler::Assembler(const AssemblerOptions& options,
213 std::unique_ptr<AssemblerBuffer> buffer)
214 : AssemblerBase(options, std::move(buffer)),
215 VU(this),
216 scratch_register_list_(t3.bit() | t5.bit()),
217 constpool_(this) {
218 reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
219
220 last_trampoline_pool_end_ = 0;
221 no_trampoline_pool_before_ = 0;
222 trampoline_pool_blocked_nesting_ = 0;
223 // We leave space (16 * kTrampolineSlotsSize)
224 // for BlockTrampolinePoolScope buffer.
225 next_buffer_check_ = FLAG_force_long_branches
226 ? kMaxInt
227 : kMaxBranchOffset - kTrampolineSlotsSize * 16;
228 internal_trampoline_exception_ = false;
229 last_bound_pos_ = 0;
230
231 trampoline_emitted_ = FLAG_force_long_branches;
232 unbound_labels_count_ = 0;
233 block_buffer_growth_ = false;
234 }
235
AbortedCodeGeneration()236 void Assembler::AbortedCodeGeneration() { constpool_.Clear(); }
~Assembler()237 Assembler::~Assembler() { CHECK(constpool_.IsEmpty()); }
238
GetCode(Isolate * isolate,CodeDesc * desc,SafepointTableBuilder * safepoint_table_builder,int handler_table_offset)239 void Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
240 SafepointTableBuilder* safepoint_table_builder,
241 int handler_table_offset) {
242 // As a crutch to avoid having to add manual Align calls wherever we use a
243 // raw workflow to create Code objects (mostly in tests), add another Align
244 // call here. It does no harm - the end of the Code object is aligned to the
245 // (larger) kCodeAlignment anyways.
246 // TODO(jgruber): Consider moving responsibility for proper alignment to
247 // metadata table builders (safepoint, handler, constant pool, code
248 // comments).
249 DataAlign(Code::kMetadataAlignment);
250
251 ForceConstantPoolEmissionWithoutJump();
252
253 int code_comments_size = WriteCodeComments();
254
255 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
256
257 AllocateAndInstallRequestedHeapObjects(isolate);
258
259 // Set up code descriptor.
260 // TODO(jgruber): Reconsider how these offsets and sizes are maintained up to
261 // this point to make CodeDesc initialization less fiddly.
262
263 static constexpr int kConstantPoolSize = 0;
264 const int instruction_size = pc_offset();
265 const int code_comments_offset = instruction_size - code_comments_size;
266 const int constant_pool_offset = code_comments_offset - kConstantPoolSize;
267 const int handler_table_offset2 = (handler_table_offset == kNoHandlerTable)
268 ? constant_pool_offset
269 : handler_table_offset;
270 const int safepoint_table_offset =
271 (safepoint_table_builder == kNoSafepointTable)
272 ? handler_table_offset2
273 : safepoint_table_builder->GetCodeOffset();
274 const int reloc_info_offset =
275 static_cast<int>(reloc_info_writer.pos() - buffer_->start());
276 CodeDesc::Initialize(desc, this, safepoint_table_offset,
277 handler_table_offset2, constant_pool_offset,
278 code_comments_offset, reloc_info_offset);
279 }
280
Align(int m)281 void Assembler::Align(int m) {
282 DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
283 while ((pc_offset() & (m - 1)) != 0) {
284 NOP();
285 }
286 }
287
CodeTargetAlign()288 void Assembler::CodeTargetAlign() {
289 // No advantage to aligning branch/call targets to more than
290 // single instruction, that I am aware of.
291 Align(4);
292 }
293
294 // Labels refer to positions in the (to be) generated code.
295 // There are bound, linked, and unused labels.
296 //
297 // Bound labels refer to known positions in the already
298 // generated code. pos() is the position the label refers to.
299 //
300 // Linked labels refer to unknown positions in the code
301 // to be generated; pos() is the position of the last
302 // instruction using the label.
303
304 // The link chain is terminated by a value in the instruction of 0,
305 // which is an otherwise illegal value (branch 0 is inf loop). When this case
306 // is detected, return an position of -1, an otherwise illegal position.
307 const int kEndOfChain = -1;
308 const int kEndOfJumpChain = 0;
309
IsBranch(Instr instr)310 bool Assembler::IsBranch(Instr instr) {
311 return (instr & kBaseOpcodeMask) == BRANCH;
312 }
313
IsCBranch(Instr instr)314 bool Assembler::IsCBranch(Instr instr) {
315 int Op = instr & kRvcOpcodeMask;
316 return Op == RO_C_BNEZ || Op == RO_C_BEQZ;
317 }
IsJump(Instr instr)318 bool Assembler::IsJump(Instr instr) {
319 int Op = instr & kBaseOpcodeMask;
320 return Op == JAL || Op == JALR;
321 }
322
IsNop(Instr instr)323 bool Assembler::IsNop(Instr instr) { return instr == kNopByte; }
324
IsJal(Instr instr)325 bool Assembler::IsJal(Instr instr) { return (instr & kBaseOpcodeMask) == JAL; }
326
IsJalr(Instr instr)327 bool Assembler::IsJalr(Instr instr) {
328 return (instr & kBaseOpcodeMask) == JALR;
329 }
330
IsCJal(Instr instr)331 bool Assembler::IsCJal(Instr instr) {
332 return (instr & kRvcOpcodeMask) == RO_C_J;
333 }
334
IsLui(Instr instr)335 bool Assembler::IsLui(Instr instr) { return (instr & kBaseOpcodeMask) == LUI; }
IsAuipc(Instr instr)336 bool Assembler::IsAuipc(Instr instr) {
337 return (instr & kBaseOpcodeMask) == AUIPC;
338 }
IsAddiw(Instr instr)339 bool Assembler::IsAddiw(Instr instr) {
340 return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ADDIW;
341 }
IsAddi(Instr instr)342 bool Assembler::IsAddi(Instr instr) {
343 return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ADDI;
344 }
IsOri(Instr instr)345 bool Assembler::IsOri(Instr instr) {
346 return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ORI;
347 }
IsSlli(Instr instr)348 bool Assembler::IsSlli(Instr instr) {
349 return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_SLLI;
350 }
351
IsLd(Instr instr)352 bool Assembler::IsLd(Instr instr) {
353 return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_LD;
354 }
355
target_at(int pos,bool is_internal)356 int Assembler::target_at(int pos, bool is_internal) {
357 if (is_internal) {
358 int64_t* p = reinterpret_cast<int64_t*>(buffer_start_ + pos);
359 int64_t address = *p;
360 if (address == kEndOfJumpChain) {
361 return kEndOfChain;
362 } else {
363 int64_t instr_address = reinterpret_cast<int64_t>(p);
364 DCHECK(instr_address - address < INT_MAX);
365 int delta = static_cast<int>(instr_address - address);
366 DCHECK(pos > delta);
367 return pos - delta;
368 }
369 }
370 Instruction* instruction = Instruction::At(buffer_start_ + pos);
371 DEBUG_PRINTF("target_at: %p (%d)\n\t",
372 reinterpret_cast<Instr*>(buffer_start_ + pos), pos);
373 Instr instr = instruction->InstructionBits();
374 disassembleInstr(instruction->InstructionBits());
375
376 switch (instruction->InstructionOpcodeType()) {
377 case BRANCH: {
378 int32_t imm13 = BranchOffset(instr);
379 if (imm13 == kEndOfJumpChain) {
380 // EndOfChain sentinel is returned directly, not relative to pc or pos.
381 return kEndOfChain;
382 } else {
383 return pos + imm13;
384 }
385 }
386 case JAL: {
387 int32_t imm21 = JumpOffset(instr);
388 if (imm21 == kEndOfJumpChain) {
389 // EndOfChain sentinel is returned directly, not relative to pc or pos.
390 return kEndOfChain;
391 } else {
392 return pos + imm21;
393 }
394 }
395 case JALR: {
396 int32_t imm12 = instr >> 20;
397 if (imm12 == kEndOfJumpChain) {
398 // EndOfChain sentinel is returned directly, not relative to pc or pos.
399 return kEndOfChain;
400 } else {
401 return pos + imm12;
402 }
403 }
404 case LUI: {
405 Address pc = reinterpret_cast<Address>(buffer_start_ + pos);
406 pc = target_address_at(pc);
407 uint64_t instr_address = reinterpret_cast<uint64_t>(buffer_start_ + pos);
408 uint64_t imm = reinterpret_cast<uint64_t>(pc);
409 if (imm == kEndOfJumpChain) {
410 return kEndOfChain;
411 } else {
412 DCHECK(instr_address - imm < INT_MAX);
413 int32_t delta = static_cast<int32_t>(instr_address - imm);
414 DCHECK(pos > delta);
415 return pos - delta;
416 }
417 }
418 case AUIPC: {
419 Instr instr_auipc = instr;
420 Instr instr_I = instr_at(pos + 4);
421 DCHECK(IsJalr(instr_I) || IsAddi(instr_I));
422 int32_t offset = BrachlongOffset(instr_auipc, instr_I);
423 if (offset == kEndOfJumpChain) return kEndOfChain;
424 return offset + pos;
425 }
426 case RO_C_J: {
427 int32_t offset = instruction->RvcImm11CJValue();
428 if (offset == kEndOfJumpChain) return kEndOfChain;
429 return offset + pos;
430 }
431 case RO_C_BNEZ:
432 case RO_C_BEQZ: {
433 int32_t offset = instruction->RvcImm8BValue();
434 if (offset == kEndOfJumpChain) return kEndOfChain;
435 return pos + offset;
436 }
437 default: {
438 if (instr == kEndOfJumpChain) {
439 return kEndOfChain;
440 } else {
441 int32_t imm18 =
442 ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
443 return (imm18 + pos);
444 }
445 }
446 }
447 }
448
SetBranchOffset(int32_t pos,int32_t target_pos,Instr instr)449 static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
450 Instr instr) {
451 int32_t imm = target_pos - pos;
452 DCHECK_EQ(imm & 1, 0);
453 DCHECK(is_intn(imm, Assembler::kBranchOffsetBits));
454
455 instr &= ~kBImm12Mask;
456 int32_t imm12 = ((imm & 0x800) >> 4) | // bit 11
457 ((imm & 0x1e) << 7) | // bits 4-1
458 ((imm & 0x7e0) << 20) | // bits 10-5
459 ((imm & 0x1000) << 19); // bit 12
460
461 return instr | (imm12 & kBImm12Mask);
462 }
463
SetLdOffset(int32_t offset,Instr instr)464 static inline Instr SetLdOffset(int32_t offset, Instr instr) {
465 DCHECK(Assembler::IsLd(instr));
466 DCHECK(is_int12(offset));
467 instr &= ~kImm12Mask;
468 int32_t imm12 = offset << kImm12Shift;
469 return instr | (imm12 & kImm12Mask);
470 }
471
SetAuipcOffset(int32_t offset,Instr instr)472 static inline Instr SetAuipcOffset(int32_t offset, Instr instr) {
473 DCHECK(Assembler::IsAuipc(instr));
474 DCHECK(is_int20(offset));
475 instr = (instr & ~kImm31_12Mask) | ((offset & kImm19_0Mask) << 12);
476 return instr;
477 }
478
SetJalrOffset(int32_t offset,Instr instr)479 static inline Instr SetJalrOffset(int32_t offset, Instr instr) {
480 DCHECK(Assembler::IsJalr(instr));
481 DCHECK(is_int12(offset));
482 instr &= ~kImm12Mask;
483 int32_t imm12 = offset << kImm12Shift;
484 DCHECK(Assembler::IsJalr(instr | (imm12 & kImm12Mask)));
485 DCHECK_EQ(Assembler::JalrOffset(instr | (imm12 & kImm12Mask)), offset);
486 return instr | (imm12 & kImm12Mask);
487 }
488
SetJalOffset(int32_t pos,int32_t target_pos,Instr instr)489 static inline Instr SetJalOffset(int32_t pos, int32_t target_pos, Instr instr) {
490 DCHECK(Assembler::IsJal(instr));
491 int32_t imm = target_pos - pos;
492 DCHECK_EQ(imm & 1, 0);
493 DCHECK(is_intn(imm, Assembler::kJumpOffsetBits));
494
495 instr &= ~kImm20Mask;
496 int32_t imm20 = (imm & 0xff000) | // bits 19-12
497 ((imm & 0x800) << 9) | // bit 11
498 ((imm & 0x7fe) << 20) | // bits 10-1
499 ((imm & 0x100000) << 11); // bit 20
500
501 return instr | (imm20 & kImm20Mask);
502 }
503
SetCJalOffset(int32_t pos,int32_t target_pos,Instr instr)504 static inline ShortInstr SetCJalOffset(int32_t pos, int32_t target_pos,
505 Instr instr) {
506 DCHECK(Assembler::IsCJal(instr));
507 int32_t imm = target_pos - pos;
508 DCHECK_EQ(imm & 1, 0);
509 DCHECK(is_intn(imm, Assembler::kCJalOffsetBits));
510 instr &= ~kImm11Mask;
511 int16_t imm11 = ((imm & 0x800) >> 1) | ((imm & 0x400) >> 4) |
512 ((imm & 0x300) >> 1) | ((imm & 0x80) >> 3) |
513 ((imm & 0x40) >> 1) | ((imm & 0x20) >> 5) |
514 ((imm & 0x10) << 5) | (imm & 0xe);
515 imm11 = imm11 << kImm11Shift;
516 DCHECK(Assembler::IsCJal(instr | (imm11 & kImm11Mask)));
517 return instr | (imm11 & kImm11Mask);
518 }
SetCBranchOffset(int32_t pos,int32_t target_pos,Instr instr)519 static inline Instr SetCBranchOffset(int32_t pos, int32_t target_pos,
520 Instr instr) {
521 DCHECK(Assembler::IsCBranch(instr));
522 int32_t imm = target_pos - pos;
523 DCHECK_EQ(imm & 1, 0);
524 DCHECK(is_intn(imm, Assembler::kCBranchOffsetBits));
525
526 instr &= ~kRvcBImm8Mask;
527 int32_t imm8 = ((imm & 0x20) >> 5) | ((imm & 0x6)) | ((imm & 0xc0) >> 3) |
528 ((imm & 0x18) << 2) | ((imm & 0x100) >> 1);
529 imm8 = ((imm8 & 0x1f) << 2) | ((imm8 & 0xe0) << 5);
530 DCHECK(Assembler::IsCBranch(instr | imm8 & kRvcBImm8Mask));
531
532 return instr | (imm8 & kRvcBImm8Mask);
533 }
534
target_at_put(int pos,int target_pos,bool is_internal,bool trampoline)535 void Assembler::target_at_put(int pos, int target_pos, bool is_internal,
536 bool trampoline) {
537 if (is_internal) {
538 uint64_t imm = reinterpret_cast<uint64_t>(buffer_start_) + target_pos;
539 *reinterpret_cast<uint64_t*>(buffer_start_ + pos) = imm;
540 return;
541 }
542 DEBUG_PRINTF("target_at_put: %p (%d) to %p (%d)\n",
543 reinterpret_cast<Instr*>(buffer_start_ + pos), pos,
544 reinterpret_cast<Instr*>(buffer_start_ + target_pos),
545 target_pos);
546 Instruction* instruction = Instruction::At(buffer_start_ + pos);
547 Instr instr = instruction->InstructionBits();
548
549 switch (instruction->InstructionOpcodeType()) {
550 case BRANCH: {
551 instr = SetBranchOffset(pos, target_pos, instr);
552 instr_at_put(pos, instr);
553 } break;
554 case JAL: {
555 DCHECK(IsJal(instr));
556 instr = SetJalOffset(pos, target_pos, instr);
557 instr_at_put(pos, instr);
558 } break;
559 case LUI: {
560 Address pc = reinterpret_cast<Address>(buffer_start_ + pos);
561 set_target_value_at(
562 pc, reinterpret_cast<uint64_t>(buffer_start_ + target_pos));
563 } break;
564 case AUIPC: {
565 Instr instr_auipc = instr;
566 Instr instr_I = instr_at(pos + 4);
567 DCHECK(IsJalr(instr_I) || IsAddi(instr_I));
568
569 int64_t offset = target_pos - pos;
570 if (is_int21(offset) && IsJalr(instr_I) && trampoline) {
571 DCHECK(is_int21(offset) && ((offset & 1) == 0));
572 Instr instr = JAL;
573 instr = SetJalOffset(pos, target_pos, instr);
574 DCHECK(IsJal(instr));
575 DCHECK(JumpOffset(instr) == offset);
576 instr_at_put(pos, instr);
577 instr_at_put(pos + 4, kNopByte);
578 } else {
579 CHECK(is_int32(offset + 0x800));
580
581 int32_t Hi20 = (((int32_t)offset + 0x800) >> 12);
582 int32_t Lo12 = (int32_t)offset << 20 >> 20;
583
584 instr_auipc =
585 (instr_auipc & ~kImm31_12Mask) | ((Hi20 & kImm19_0Mask) << 12);
586 instr_at_put(pos, instr_auipc);
587
588 const int kImm31_20Mask = ((1 << 12) - 1) << 20;
589 const int kImm11_0Mask = ((1 << 12) - 1);
590 instr_I = (instr_I & ~kImm31_20Mask) | ((Lo12 & kImm11_0Mask) << 20);
591 instr_at_put(pos + 4, instr_I);
592 }
593 } break;
594 case RO_C_J: {
595 ShortInstr short_instr = SetCJalOffset(pos, target_pos, instr);
596 instr_at_put(pos, short_instr);
597 } break;
598 case RO_C_BNEZ:
599 case RO_C_BEQZ: {
600 instr = SetCBranchOffset(pos, target_pos, instr);
601 instr_at_put(pos, instr);
602 } break;
603 default: {
604 // Emitted label constant, not part of a branch.
605 // Make label relative to Code pointer of generated Code object.
606 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
607 } break;
608 }
609 disassembleInstr(instr);
610 }
611
print(const Label * L)612 void Assembler::print(const Label* L) {
613 if (L->is_unused()) {
614 PrintF("unused label\n");
615 } else if (L->is_bound()) {
616 PrintF("bound label to %d\n", L->pos());
617 } else if (L->is_linked()) {
618 Label l;
619 l.link_to(L->pos());
620 PrintF("unbound label");
621 while (l.is_linked()) {
622 PrintF("@ %d ", l.pos());
623 Instr instr = instr_at(l.pos());
624 if ((instr & ~kImm16Mask) == 0) {
625 PrintF("value\n");
626 } else {
627 PrintF("%d\n", instr);
628 }
629 next(&l, is_internal_reference(&l));
630 }
631 } else {
632 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
633 }
634 }
635
bind_to(Label * L,int pos)636 void Assembler::bind_to(Label* L, int pos) {
637 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
638 DEBUG_PRINTF("binding %d to label %p\n", pos, L);
639 int trampoline_pos = kInvalidSlotPos;
640 bool is_internal = false;
641 if (L->is_linked() && !trampoline_emitted_) {
642 unbound_labels_count_--;
643 if (!is_internal_reference(L)) {
644 next_buffer_check_ += kTrampolineSlotsSize;
645 }
646 }
647
648 while (L->is_linked()) {
649 int fixup_pos = L->pos();
650 int dist = pos - fixup_pos;
651 is_internal = is_internal_reference(L);
652 next(L, is_internal); // Call next before overwriting link with target
653 // at fixup_pos.
654 Instr instr = instr_at(fixup_pos);
655 DEBUG_PRINTF("\tfixup: %d to %d\n", fixup_pos, dist);
656 if (is_internal) {
657 target_at_put(fixup_pos, pos, is_internal);
658 } else {
659 if (IsBranch(instr)) {
660 if (dist > kMaxBranchOffset) {
661 if (trampoline_pos == kInvalidSlotPos) {
662 trampoline_pos = get_trampoline_entry(fixup_pos);
663 CHECK_NE(trampoline_pos, kInvalidSlotPos);
664 }
665 CHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
666 DEBUG_PRINTF("\t\ttrampolining: %d\n", trampoline_pos);
667 target_at_put(fixup_pos, trampoline_pos, false, true);
668 fixup_pos = trampoline_pos;
669 }
670 target_at_put(fixup_pos, pos, false);
671 } else if (IsJal(instr)) {
672 if (dist > kMaxJumpOffset) {
673 if (trampoline_pos == kInvalidSlotPos) {
674 trampoline_pos = get_trampoline_entry(fixup_pos);
675 CHECK_NE(trampoline_pos, kInvalidSlotPos);
676 }
677 CHECK((trampoline_pos - fixup_pos) <= kMaxJumpOffset);
678 DEBUG_PRINTF("\t\ttrampolining: %d\n", trampoline_pos);
679 target_at_put(fixup_pos, trampoline_pos, false, true);
680 fixup_pos = trampoline_pos;
681 }
682 target_at_put(fixup_pos, pos, false);
683 } else {
684 target_at_put(fixup_pos, pos, false);
685 }
686 }
687 }
688 L->bind_to(pos);
689
690 // Keep track of the last bound label so we don't eliminate any instructions
691 // before a bound label.
692 if (pos > last_bound_pos_) last_bound_pos_ = pos;
693 }
694
bind(Label * L)695 void Assembler::bind(Label* L) {
696 DCHECK(!L->is_bound()); // Label can only be bound once.
697 bind_to(L, pc_offset());
698 }
699
next(Label * L,bool is_internal)700 void Assembler::next(Label* L, bool is_internal) {
701 DCHECK(L->is_linked());
702 int link = target_at(L->pos(), is_internal);
703 if (link == kEndOfChain) {
704 L->Unuse();
705 } else {
706 DCHECK_GE(link, 0);
707 DEBUG_PRINTF("next: %p to %p (%d)\n", L,
708 reinterpret_cast<Instr*>(buffer_start_ + link), link);
709 L->link_to(link);
710 }
711 }
712
is_near(Label * L)713 bool Assembler::is_near(Label* L) {
714 DCHECK(L->is_bound());
715 return is_intn((pc_offset() - L->pos()), kJumpOffsetBits);
716 }
717
is_near(Label * L,OffsetSize bits)718 bool Assembler::is_near(Label* L, OffsetSize bits) {
719 if (L == nullptr || !L->is_bound()) return true;
720 return is_intn((pc_offset() - L->pos()), bits);
721 }
722
is_near_branch(Label * L)723 bool Assembler::is_near_branch(Label* L) {
724 DCHECK(L->is_bound());
725 return is_intn((pc_offset() - L->pos()), kBranchOffsetBits);
726 }
727
BranchOffset(Instr instr)728 int Assembler::BranchOffset(Instr instr) {
729 // | imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1|11] | opcode |
730 // 31 25 11 7
731 int32_t imm13 = ((instr & 0xf00) >> 7) | ((instr & 0x7e000000) >> 20) |
732 ((instr & 0x80) << 4) | ((instr & 0x80000000) >> 19);
733 imm13 = imm13 << 19 >> 19;
734 return imm13;
735 }
736
JumpOffset(Instr instr)737 int Assembler::JumpOffset(Instr instr) {
738 int32_t imm21 = ((instr & 0x7fe00000) >> 20) | ((instr & 0x100000) >> 9) |
739 (instr & 0xff000) | ((instr & 0x80000000) >> 11);
740 imm21 = imm21 << 11 >> 11;
741 return imm21;
742 }
743
CJumpOffset(Instr instr)744 int Assembler::CJumpOffset(Instr instr) {
745 int32_t imm12 = ((instr & 0x4) << 3) | ((instr & 0x38) >> 2) |
746 ((instr & 0x40) << 1) | ((instr & 0x80) >> 1) |
747 ((instr & 0x100) << 2) | ((instr & 0x600) >> 1) |
748 ((instr & 0x800) >> 7) | ((instr & 0x1000) >> 1);
749 imm12 = imm12 << 20 >> 20;
750 return imm12;
751 }
752
BrachlongOffset(Instr auipc,Instr instr_I)753 int Assembler::BrachlongOffset(Instr auipc, Instr instr_I) {
754 DCHECK(reinterpret_cast<Instruction*>(&instr_I)->InstructionType() ==
755 InstructionBase::kIType);
756 DCHECK(IsAuipc(auipc));
757 DCHECK_EQ((auipc & kRdFieldMask) >> kRdShift,
758 (instr_I & kRs1FieldMask) >> kRs1Shift);
759 int32_t imm_auipc = AuipcOffset(auipc);
760 int32_t imm12 = static_cast<int32_t>(instr_I & kImm12Mask) >> 20;
761 int32_t offset = imm12 + imm_auipc;
762 return offset;
763 }
764
PatchBranchlongOffset(Address pc,Instr instr_auipc,Instr instr_jalr,int32_t offset)765 int Assembler::PatchBranchlongOffset(Address pc, Instr instr_auipc,
766 Instr instr_jalr, int32_t offset) {
767 DCHECK(IsAuipc(instr_auipc));
768 DCHECK(IsJalr(instr_jalr));
769 CHECK(is_int32(offset + 0x800));
770 int32_t Hi20 = (((int32_t)offset + 0x800) >> 12);
771 int32_t Lo12 = (int32_t)offset << 20 >> 20;
772 instr_at_put(pc, SetAuipcOffset(Hi20, instr_auipc));
773 instr_at_put(pc + 4, SetJalrOffset(Lo12, instr_jalr));
774 DCHECK(offset ==
775 BrachlongOffset(Assembler::instr_at(pc), Assembler::instr_at(pc + 4)));
776 return 2;
777 }
778
LdOffset(Instr instr)779 int Assembler::LdOffset(Instr instr) {
780 DCHECK(IsLd(instr));
781 int32_t imm12 = static_cast<int32_t>(instr & kImm12Mask) >> 20;
782 return imm12;
783 }
784
JalrOffset(Instr instr)785 int Assembler::JalrOffset(Instr instr) {
786 DCHECK(IsJalr(instr));
787 int32_t imm12 = static_cast<int32_t>(instr & kImm12Mask) >> 20;
788 return imm12;
789 }
790
AuipcOffset(Instr instr)791 int Assembler::AuipcOffset(Instr instr) {
792 DCHECK(IsAuipc(instr));
793 int32_t imm20 = static_cast<int32_t>(instr & kImm20Mask);
794 return imm20;
795 }
796 // We have to use a temporary register for things that can be relocated even
797 // if they can be encoded in RISC-V's 12 bits of immediate-offset instruction
798 // space. There is no guarantee that the relocated location can be similarly
799 // encoded.
MustUseReg(RelocInfo::Mode rmode)800 bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
801 return !RelocInfo::IsNone(rmode);
802 }
803
disassembleInstr(Instr instr)804 void Assembler::disassembleInstr(Instr instr) {
805 if (!FLAG_riscv_debug) return;
806 disasm::NameConverter converter;
807 disasm::Disassembler disasm(converter);
808 base::EmbeddedVector<char, 128> disasm_buffer;
809
810 disasm.InstructionDecode(disasm_buffer, reinterpret_cast<byte*>(&instr));
811 DEBUG_PRINTF("%s\n", disasm_buffer.begin());
812 }
813
814 // ----- Top-level instruction formats match those in the ISA manual
815 // (R, I, S, B, U, J). These match the formats defined in the compiler
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,Register rd,Register rs1,Register rs2)816 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
817 Register rd, Register rs1, Register rs2) {
818 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
819 rs1.is_valid() && rs2.is_valid());
820 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
821 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
822 (funct7 << kFunct7Shift);
823 emit(instr);
824 }
825
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,FPURegister rd,FPURegister rs1,FPURegister rs2)826 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
827 FPURegister rd, FPURegister rs1, FPURegister rs2) {
828 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
829 rs1.is_valid() && rs2.is_valid());
830 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
831 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
832 (funct7 << kFunct7Shift);
833 emit(instr);
834 }
835
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,Register rd,FPURegister rs1,Register rs2)836 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
837 Register rd, FPURegister rs1, Register rs2) {
838 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
839 rs1.is_valid() && rs2.is_valid());
840 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
841 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
842 (funct7 << kFunct7Shift);
843 emit(instr);
844 }
845
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,FPURegister rd,Register rs1,Register rs2)846 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
847 FPURegister rd, Register rs1, Register rs2) {
848 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
849 rs1.is_valid() && rs2.is_valid());
850 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
851 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
852 (funct7 << kFunct7Shift);
853 emit(instr);
854 }
855
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,FPURegister rd,FPURegister rs1,Register rs2)856 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
857 FPURegister rd, FPURegister rs1, Register rs2) {
858 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
859 rs1.is_valid() && rs2.is_valid());
860 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
861 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
862 (funct7 << kFunct7Shift);
863 emit(instr);
864 }
865
GenInstrR(uint8_t funct7,uint8_t funct3,Opcode opcode,Register rd,FPURegister rs1,FPURegister rs2)866 void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode,
867 Register rd, FPURegister rs1, FPURegister rs2) {
868 DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() &&
869 rs1.is_valid() && rs2.is_valid());
870 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
871 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
872 (funct7 << kFunct7Shift);
873 emit(instr);
874 }
875
GenInstrR4(uint8_t funct2,Opcode opcode,Register rd,Register rs1,Register rs2,Register rs3,RoundingMode frm)876 void Assembler::GenInstrR4(uint8_t funct2, Opcode opcode, Register rd,
877 Register rs1, Register rs2, Register rs3,
878 RoundingMode frm) {
879 DCHECK(is_uint2(funct2) && rd.is_valid() && rs1.is_valid() &&
880 rs2.is_valid() && rs3.is_valid() && is_uint3(frm));
881 Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) |
882 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
883 (funct2 << kFunct2Shift) | (rs3.code() << kRs3Shift);
884 emit(instr);
885 }
886
GenInstrR4(uint8_t funct2,Opcode opcode,FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)887 void Assembler::GenInstrR4(uint8_t funct2, Opcode opcode, FPURegister rd,
888 FPURegister rs1, FPURegister rs2, FPURegister rs3,
889 RoundingMode frm) {
890 DCHECK(is_uint2(funct2) && rd.is_valid() && rs1.is_valid() &&
891 rs2.is_valid() && rs3.is_valid() && is_uint3(frm));
892 Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) |
893 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
894 (funct2 << kFunct2Shift) | (rs3.code() << kRs3Shift);
895 emit(instr);
896 }
897
GenInstrRAtomic(uint8_t funct5,bool aq,bool rl,uint8_t funct3,Register rd,Register rs1,Register rs2)898 void Assembler::GenInstrRAtomic(uint8_t funct5, bool aq, bool rl,
899 uint8_t funct3, Register rd, Register rs1,
900 Register rs2) {
901 DCHECK(is_uint5(funct5) && is_uint3(funct3) && rd.is_valid() &&
902 rs1.is_valid() && rs2.is_valid());
903 Instr instr = AMO | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
904 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
905 (rl << kRlShift) | (aq << kAqShift) | (funct5 << kFunct5Shift);
906 emit(instr);
907 }
908
GenInstrRFrm(uint8_t funct7,Opcode opcode,Register rd,Register rs1,Register rs2,RoundingMode frm)909 void Assembler::GenInstrRFrm(uint8_t funct7, Opcode opcode, Register rd,
910 Register rs1, Register rs2, RoundingMode frm) {
911 DCHECK(rd.is_valid() && rs1.is_valid() && rs2.is_valid() && is_uint3(frm));
912 Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) |
913 (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) |
914 (funct7 << kFunct7Shift);
915 emit(instr);
916 }
917
GenInstrI(uint8_t funct3,Opcode opcode,Register rd,Register rs1,int16_t imm12)918 void Assembler::GenInstrI(uint8_t funct3, Opcode opcode, Register rd,
919 Register rs1, int16_t imm12) {
920 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
921 (is_uint12(imm12) || is_int12(imm12)));
922 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
923 (rs1.code() << kRs1Shift) | (imm12 << kImm12Shift);
924 emit(instr);
925 }
926
GenInstrI(uint8_t funct3,Opcode opcode,FPURegister rd,Register rs1,int16_t imm12)927 void Assembler::GenInstrI(uint8_t funct3, Opcode opcode, FPURegister rd,
928 Register rs1, int16_t imm12) {
929 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
930 (is_uint12(imm12) || is_int12(imm12)));
931 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
932 (rs1.code() << kRs1Shift) | (imm12 << kImm12Shift);
933 emit(instr);
934 }
935
GenInstrIShift(bool arithshift,uint8_t funct3,Opcode opcode,Register rd,Register rs1,uint8_t shamt)936 void Assembler::GenInstrIShift(bool arithshift, uint8_t funct3, Opcode opcode,
937 Register rd, Register rs1, uint8_t shamt) {
938 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
939 is_uint6(shamt));
940 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
941 (rs1.code() << kRs1Shift) | (shamt << kShamtShift) |
942 (arithshift << kArithShiftShift);
943 emit(instr);
944 }
945
GenInstrIShiftW(bool arithshift,uint8_t funct3,Opcode opcode,Register rd,Register rs1,uint8_t shamt)946 void Assembler::GenInstrIShiftW(bool arithshift, uint8_t funct3, Opcode opcode,
947 Register rd, Register rs1, uint8_t shamt) {
948 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
949 is_uint5(shamt));
950 Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) |
951 (rs1.code() << kRs1Shift) | (shamt << kShamtWShift) |
952 (arithshift << kArithShiftShift);
953 emit(instr);
954 }
955
GenInstrS(uint8_t funct3,Opcode opcode,Register rs1,Register rs2,int16_t imm12)956 void Assembler::GenInstrS(uint8_t funct3, Opcode opcode, Register rs1,
957 Register rs2, int16_t imm12) {
958 DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() &&
959 is_int12(imm12));
960 Instr instr = opcode | ((imm12 & 0x1f) << 7) | // bits 4-0
961 (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) |
962 (rs2.code() << kRs2Shift) |
963 ((imm12 & 0xfe0) << 20); // bits 11-5
964 emit(instr);
965 }
966
GenInstrS(uint8_t funct3,Opcode opcode,Register rs1,FPURegister rs2,int16_t imm12)967 void Assembler::GenInstrS(uint8_t funct3, Opcode opcode, Register rs1,
968 FPURegister rs2, int16_t imm12) {
969 DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() &&
970 is_int12(imm12));
971 Instr instr = opcode | ((imm12 & 0x1f) << 7) | // bits 4-0
972 (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) |
973 (rs2.code() << kRs2Shift) |
974 ((imm12 & 0xfe0) << 20); // bits 11-5
975 emit(instr);
976 }
977
GenInstrB(uint8_t funct3,Opcode opcode,Register rs1,Register rs2,int16_t imm13)978 void Assembler::GenInstrB(uint8_t funct3, Opcode opcode, Register rs1,
979 Register rs2, int16_t imm13) {
980 DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() &&
981 is_int13(imm13) && ((imm13 & 1) == 0));
982 Instr instr = opcode | ((imm13 & 0x800) >> 4) | // bit 11
983 ((imm13 & 0x1e) << 7) | // bits 4-1
984 (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) |
985 (rs2.code() << kRs2Shift) |
986 ((imm13 & 0x7e0) << 20) | // bits 10-5
987 ((imm13 & 0x1000) << 19); // bit 12
988 emit(instr);
989 }
990
GenInstrU(Opcode opcode,Register rd,int32_t imm20)991 void Assembler::GenInstrU(Opcode opcode, Register rd, int32_t imm20) {
992 DCHECK(rd.is_valid() && (is_int20(imm20) || is_uint20(imm20)));
993 Instr instr = opcode | (rd.code() << kRdShift) | (imm20 << kImm20Shift);
994 emit(instr);
995 }
996
GenInstrJ(Opcode opcode,Register rd,int32_t imm21)997 void Assembler::GenInstrJ(Opcode opcode, Register rd, int32_t imm21) {
998 DCHECK(rd.is_valid() && is_int21(imm21) && ((imm21 & 1) == 0));
999 Instr instr = opcode | (rd.code() << kRdShift) |
1000 (imm21 & 0xff000) | // bits 19-12
1001 ((imm21 & 0x800) << 9) | // bit 11
1002 ((imm21 & 0x7fe) << 20) | // bits 10-1
1003 ((imm21 & 0x100000) << 11); // bit 20
1004 emit(instr);
1005 }
1006
GenInstrCR(uint8_t funct4,Opcode opcode,Register rd,Register rs2)1007 void Assembler::GenInstrCR(uint8_t funct4, Opcode opcode, Register rd,
1008 Register rs2) {
1009 DCHECK(is_uint4(funct4) && rd.is_valid() && rs2.is_valid());
1010 ShortInstr instr = opcode | (rs2.code() << kRvcRs2Shift) |
1011 (rd.code() << kRvcRdShift) | (funct4 << kRvcFunct4Shift);
1012 emit(instr);
1013 }
1014
GenInstrCA(uint8_t funct6,Opcode opcode,Register rd,uint8_t funct,Register rs2)1015 void Assembler::GenInstrCA(uint8_t funct6, Opcode opcode, Register rd,
1016 uint8_t funct, Register rs2) {
1017 DCHECK(is_uint6(funct6) && rd.is_valid() && rs2.is_valid() &&
1018 is_uint2(funct));
1019 ShortInstr instr = opcode | ((rs2.code() & 0x7) << kRvcRs2sShift) |
1020 ((rd.code() & 0x7) << kRvcRs1sShift) |
1021 (funct6 << kRvcFunct6Shift) | (funct << kRvcFunct2Shift);
1022 emit(instr);
1023 }
1024
GenInstrCI(uint8_t funct3,Opcode opcode,Register rd,int8_t imm6)1025 void Assembler::GenInstrCI(uint8_t funct3, Opcode opcode, Register rd,
1026 int8_t imm6) {
1027 DCHECK(is_uint3(funct3) && rd.is_valid() && is_int6(imm6));
1028 ShortInstr instr = opcode | ((imm6 & 0x1f) << 2) |
1029 (rd.code() << kRvcRdShift) | ((imm6 & 0x20) << 7) |
1030 (funct3 << kRvcFunct3Shift);
1031 emit(instr);
1032 }
1033
GenInstrCIU(uint8_t funct3,Opcode opcode,Register rd,uint8_t uimm6)1034 void Assembler::GenInstrCIU(uint8_t funct3, Opcode opcode, Register rd,
1035 uint8_t uimm6) {
1036 DCHECK(is_uint3(funct3) && rd.is_valid() && is_uint6(uimm6));
1037 ShortInstr instr = opcode | ((uimm6 & 0x1f) << 2) |
1038 (rd.code() << kRvcRdShift) | ((uimm6 & 0x20) << 7) |
1039 (funct3 << kRvcFunct3Shift);
1040 emit(instr);
1041 }
1042
GenInstrCIU(uint8_t funct3,Opcode opcode,FPURegister rd,uint8_t uimm6)1043 void Assembler::GenInstrCIU(uint8_t funct3, Opcode opcode, FPURegister rd,
1044 uint8_t uimm6) {
1045 DCHECK(is_uint3(funct3) && rd.is_valid() && is_uint6(uimm6));
1046 ShortInstr instr = opcode | ((uimm6 & 0x1f) << 2) |
1047 (rd.code() << kRvcRdShift) | ((uimm6 & 0x20) << 7) |
1048 (funct3 << kRvcFunct3Shift);
1049 emit(instr);
1050 }
1051
GenInstrCIW(uint8_t funct3,Opcode opcode,Register rd,uint8_t uimm8)1052 void Assembler::GenInstrCIW(uint8_t funct3, Opcode opcode, Register rd,
1053 uint8_t uimm8) {
1054 DCHECK(is_uint3(funct3) && rd.is_valid() && is_uint8(uimm8));
1055 ShortInstr instr = opcode | ((uimm8) << 5) |
1056 ((rd.code() & 0x7) << kRvcRs2sShift) |
1057 (funct3 << kRvcFunct3Shift);
1058 emit(instr);
1059 }
1060
GenInstrCSS(uint8_t funct3,Opcode opcode,Register rs2,uint8_t uimm6)1061 void Assembler::GenInstrCSS(uint8_t funct3, Opcode opcode, Register rs2,
1062 uint8_t uimm6) {
1063 DCHECK(is_uint3(funct3) && rs2.is_valid() && is_uint6(uimm6));
1064 ShortInstr instr = opcode | (uimm6 << 7) | (rs2.code() << kRvcRs2Shift) |
1065 (funct3 << kRvcFunct3Shift);
1066 emit(instr);
1067 }
1068
GenInstrCSS(uint8_t funct3,Opcode opcode,FPURegister rs2,uint8_t uimm6)1069 void Assembler::GenInstrCSS(uint8_t funct3, Opcode opcode, FPURegister rs2,
1070 uint8_t uimm6) {
1071 DCHECK(is_uint3(funct3) && rs2.is_valid() && is_uint6(uimm6));
1072 ShortInstr instr = opcode | (uimm6 << 7) | (rs2.code() << kRvcRs2Shift) |
1073 (funct3 << kRvcFunct3Shift);
1074 emit(instr);
1075 }
1076
GenInstrCL(uint8_t funct3,Opcode opcode,Register rd,Register rs1,uint8_t uimm5)1077 void Assembler::GenInstrCL(uint8_t funct3, Opcode opcode, Register rd,
1078 Register rs1, uint8_t uimm5) {
1079 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
1080 is_uint5(uimm5));
1081 ShortInstr instr = opcode | ((uimm5 & 0x3) << 5) |
1082 ((rd.code() & 0x7) << kRvcRs2sShift) |
1083 ((uimm5 & 0x1c) << 8) | (funct3 << kRvcFunct3Shift) |
1084 ((rs1.code() & 0x7) << kRvcRs1sShift);
1085 emit(instr);
1086 }
1087
GenInstrCL(uint8_t funct3,Opcode opcode,FPURegister rd,Register rs1,uint8_t uimm5)1088 void Assembler::GenInstrCL(uint8_t funct3, Opcode opcode, FPURegister rd,
1089 Register rs1, uint8_t uimm5) {
1090 DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() &&
1091 is_uint5(uimm5));
1092 ShortInstr instr = opcode | ((uimm5 & 0x3) << 5) |
1093 ((rd.code() & 0x7) << kRvcRs2sShift) |
1094 ((uimm5 & 0x1c) << 8) | (funct3 << kRvcFunct3Shift) |
1095 ((rs1.code() & 0x7) << kRvcRs1sShift);
1096 emit(instr);
1097 }
GenInstrCJ(uint8_t funct3,Opcode opcode,uint16_t uint11)1098 void Assembler::GenInstrCJ(uint8_t funct3, Opcode opcode, uint16_t uint11) {
1099 DCHECK(is_uint11(uint11));
1100 ShortInstr instr = opcode | (funct3 << kRvcFunct3Shift) | (uint11 << 2);
1101 emit(instr);
1102 }
1103
GenInstrCS(uint8_t funct3,Opcode opcode,Register rs2,Register rs1,uint8_t uimm5)1104 void Assembler::GenInstrCS(uint8_t funct3, Opcode opcode, Register rs2,
1105 Register rs1, uint8_t uimm5) {
1106 DCHECK(is_uint3(funct3) && rs2.is_valid() && rs1.is_valid() &&
1107 is_uint5(uimm5));
1108 ShortInstr instr = opcode | ((uimm5 & 0x3) << 5) |
1109 ((rs2.code() & 0x7) << kRvcRs2sShift) |
1110 ((uimm5 & 0x1c) << 8) | (funct3 << kRvcFunct3Shift) |
1111 ((rs1.code() & 0x7) << kRvcRs1sShift);
1112 emit(instr);
1113 }
1114
GenInstrCS(uint8_t funct3,Opcode opcode,FPURegister rs2,Register rs1,uint8_t uimm5)1115 void Assembler::GenInstrCS(uint8_t funct3, Opcode opcode, FPURegister rs2,
1116 Register rs1, uint8_t uimm5) {
1117 DCHECK(is_uint3(funct3) && rs2.is_valid() && rs1.is_valid() &&
1118 is_uint5(uimm5));
1119 ShortInstr instr = opcode | ((uimm5 & 0x3) << 5) |
1120 ((rs2.code() & 0x7) << kRvcRs2sShift) |
1121 ((uimm5 & 0x1c) << 8) | (funct3 << kRvcFunct3Shift) |
1122 ((rs1.code() & 0x7) << kRvcRs1sShift);
1123 emit(instr);
1124 }
1125
GenInstrCB(uint8_t funct3,Opcode opcode,Register rs1,uint8_t uimm8)1126 void Assembler::GenInstrCB(uint8_t funct3, Opcode opcode, Register rs1,
1127 uint8_t uimm8) {
1128 DCHECK(is_uint3(funct3) && is_uint8(uimm8));
1129 ShortInstr instr = opcode | ((uimm8 & 0x1f) << 2) | ((uimm8 & 0xe0) << 5) |
1130 ((rs1.code() & 0x7) << kRvcRs1sShift) |
1131 (funct3 << kRvcFunct3Shift);
1132 emit(instr);
1133 }
1134
GenInstrCBA(uint8_t funct3,uint8_t funct2,Opcode opcode,Register rs1,int8_t imm6)1135 void Assembler::GenInstrCBA(uint8_t funct3, uint8_t funct2, Opcode opcode,
1136 Register rs1, int8_t imm6) {
1137 DCHECK(is_uint3(funct3) && is_uint2(funct2) && is_int6(imm6));
1138 ShortInstr instr = opcode | ((imm6 & 0x1f) << 2) | ((imm6 & 0x20) << 7) |
1139 ((rs1.code() & 0x7) << kRvcRs1sShift) |
1140 (funct3 << kRvcFunct3Shift) | (funct2 << 10);
1141 emit(instr);
1142 }
1143
1144 // OPIVV OPFVV OPMVV
GenInstrV(uint8_t funct6,Opcode opcode,VRegister vd,VRegister vs1,VRegister vs2,MaskType mask)1145 void Assembler::GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd,
1146 VRegister vs1, VRegister vs2, MaskType mask) {
1147 DCHECK(opcode == OP_MVV || opcode == OP_FVV || opcode == OP_IVV);
1148 Instr instr = (funct6 << kRvvFunct6Shift) | opcode | (mask << kRvvVmShift) |
1149 ((vd.code() & 0x1F) << kRvvVdShift) |
1150 ((vs1.code() & 0x1F) << kRvvVs1Shift) |
1151 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1152 emit(instr);
1153 }
1154
GenInstrV(uint8_t funct6,Opcode opcode,VRegister vd,int8_t vs1,VRegister vs2,MaskType mask)1155 void Assembler::GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd,
1156 int8_t vs1, VRegister vs2, MaskType mask) {
1157 DCHECK(opcode == OP_MVV || opcode == OP_FVV || opcode == OP_IVV);
1158 Instr instr = (funct6 << kRvvFunct6Shift) | opcode | (mask << kRvvVmShift) |
1159 ((vd.code() & 0x1F) << kRvvVdShift) |
1160 ((vs1 & 0x1F) << kRvvVs1Shift) |
1161 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1162 emit(instr);
1163 }
1164 // OPMVV OPFVV
GenInstrV(uint8_t funct6,Opcode opcode,Register rd,VRegister vs1,VRegister vs2,MaskType mask)1165 void Assembler::GenInstrV(uint8_t funct6, Opcode opcode, Register rd,
1166 VRegister vs1, VRegister vs2, MaskType mask) {
1167 DCHECK(opcode == OP_MVV || opcode == OP_FVV);
1168 Instr instr = (funct6 << kRvvFunct6Shift) | opcode | (mask << kRvvVmShift) |
1169 ((rd.code() & 0x1F) << kRvvVdShift) |
1170 ((vs1.code() & 0x1F) << kRvvVs1Shift) |
1171 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1172 emit(instr);
1173 }
1174
1175 // OPIVX OPMVX
GenInstrV(uint8_t funct6,Opcode opcode,VRegister vd,Register rs1,VRegister vs2,MaskType mask)1176 void Assembler::GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd,
1177 Register rs1, VRegister vs2, MaskType mask) {
1178 DCHECK(opcode == OP_IVX || opcode == OP_MVX);
1179 Instr instr = (funct6 << kRvvFunct6Shift) | opcode | (mask << kRvvVmShift) |
1180 ((vd.code() & 0x1F) << kRvvVdShift) |
1181 ((rs1.code() & 0x1F) << kRvvRs1Shift) |
1182 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1183 emit(instr);
1184 }
1185
1186 // OPFVF
GenInstrV(uint8_t funct6,Opcode opcode,VRegister vd,FPURegister fs1,VRegister vs2,MaskType mask)1187 void Assembler::GenInstrV(uint8_t funct6, Opcode opcode, VRegister vd,
1188 FPURegister fs1, VRegister vs2, MaskType mask) {
1189 DCHECK(opcode == OP_FVF);
1190 Instr instr = (funct6 << kRvvFunct6Shift) | opcode | (mask << kRvvVmShift) |
1191 ((vd.code() & 0x1F) << kRvvVdShift) |
1192 ((fs1.code() & 0x1F) << kRvvRs1Shift) |
1193 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1194 emit(instr);
1195 }
1196
1197 // OPMVX
GenInstrV(uint8_t funct6,Register rd,Register rs1,VRegister vs2,MaskType mask)1198 void Assembler::GenInstrV(uint8_t funct6, Register rd, Register rs1,
1199 VRegister vs2, MaskType mask) {
1200 Instr instr = (funct6 << kRvvFunct6Shift) | OP_MVX | (mask << kRvvVmShift) |
1201 ((rd.code() & 0x1F) << kRvvVdShift) |
1202 ((rs1.code() & 0x1F) << kRvvRs1Shift) |
1203 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1204 emit(instr);
1205 }
1206 // OPIVI
GenInstrV(uint8_t funct6,VRegister vd,int8_t imm5,VRegister vs2,MaskType mask)1207 void Assembler::GenInstrV(uint8_t funct6, VRegister vd, int8_t imm5,
1208 VRegister vs2, MaskType mask) {
1209 DCHECK(is_uint5(imm5) || is_int5(imm5));
1210 Instr instr = (funct6 << kRvvFunct6Shift) | OP_IVI | (mask << kRvvVmShift) |
1211 ((vd.code() & 0x1F) << kRvvVdShift) |
1212 (((uint32_t)imm5 << kRvvImm5Shift) & kRvvImm5Mask) |
1213 ((vs2.code() & 0x1F) << kRvvVs2Shift);
1214 emit(instr);
1215 }
1216
1217 // VL VS
GenInstrV(Opcode opcode,uint8_t width,VRegister vd,Register rs1,uint8_t umop,MaskType mask,uint8_t IsMop,bool IsMew,uint8_t Nf)1218 void Assembler::GenInstrV(Opcode opcode, uint8_t width, VRegister vd,
1219 Register rs1, uint8_t umop, MaskType mask,
1220 uint8_t IsMop, bool IsMew, uint8_t Nf) {
1221 DCHECK(opcode == LOAD_FP || opcode == STORE_FP);
1222 Instr instr = opcode | ((vd.code() << kRvvVdShift) & kRvvVdMask) |
1223 ((width << kRvvWidthShift) & kRvvWidthMask) |
1224 ((rs1.code() << kRvvRs1Shift) & kRvvRs1Mask) |
1225 ((umop << kRvvRs2Shift) & kRvvRs2Mask) |
1226 ((mask << kRvvVmShift) & kRvvVmMask) |
1227 ((IsMop << kRvvMopShift) & kRvvMopMask) |
1228 ((IsMew << kRvvMewShift) & kRvvMewMask) |
1229 ((Nf << kRvvNfShift) & kRvvNfMask);
1230 emit(instr);
1231 }
GenInstrV(Opcode opcode,uint8_t width,VRegister vd,Register rs1,Register rs2,MaskType mask,uint8_t IsMop,bool IsMew,uint8_t Nf)1232 void Assembler::GenInstrV(Opcode opcode, uint8_t width, VRegister vd,
1233 Register rs1, Register rs2, MaskType mask,
1234 uint8_t IsMop, bool IsMew, uint8_t Nf) {
1235 DCHECK(opcode == LOAD_FP || opcode == STORE_FP);
1236 Instr instr = opcode | ((vd.code() << kRvvVdShift) & kRvvVdMask) |
1237 ((width << kRvvWidthShift) & kRvvWidthMask) |
1238 ((rs1.code() << kRvvRs1Shift) & kRvvRs1Mask) |
1239 ((rs2.code() << kRvvRs2Shift) & kRvvRs2Mask) |
1240 ((mask << kRvvVmShift) & kRvvVmMask) |
1241 ((IsMop << kRvvMopShift) & kRvvMopMask) |
1242 ((IsMew << kRvvMewShift) & kRvvMewMask) |
1243 ((Nf << kRvvNfShift) & kRvvNfMask);
1244 emit(instr);
1245 }
1246 // VL VS AMO
GenInstrV(Opcode opcode,uint8_t width,VRegister vd,Register rs1,VRegister vs2,MaskType mask,uint8_t IsMop,bool IsMew,uint8_t Nf)1247 void Assembler::GenInstrV(Opcode opcode, uint8_t width, VRegister vd,
1248 Register rs1, VRegister vs2, MaskType mask,
1249 uint8_t IsMop, bool IsMew, uint8_t Nf) {
1250 DCHECK(opcode == LOAD_FP || opcode == STORE_FP || opcode == AMO);
1251 Instr instr = opcode | ((vd.code() << kRvvVdShift) & kRvvVdMask) |
1252 ((width << kRvvWidthShift) & kRvvWidthMask) |
1253 ((rs1.code() << kRvvRs1Shift) & kRvvRs1Mask) |
1254 ((vs2.code() << kRvvRs2Shift) & kRvvRs2Mask) |
1255 ((mask << kRvvVmShift) & kRvvVmMask) |
1256 ((IsMop << kRvvMopShift) & kRvvMopMask) |
1257 ((IsMew << kRvvMewShift) & kRvvMewMask) |
1258 ((Nf << kRvvNfShift) & kRvvNfMask);
1259 emit(instr);
1260 }
1261 // ----- Instruction class templates match those in the compiler
1262
GenInstrBranchCC_rri(uint8_t funct3,Register rs1,Register rs2,int16_t imm13)1263 void Assembler::GenInstrBranchCC_rri(uint8_t funct3, Register rs1, Register rs2,
1264 int16_t imm13) {
1265 GenInstrB(funct3, BRANCH, rs1, rs2, imm13);
1266 }
1267
GenInstrLoad_ri(uint8_t funct3,Register rd,Register rs1,int16_t imm12)1268 void Assembler::GenInstrLoad_ri(uint8_t funct3, Register rd, Register rs1,
1269 int16_t imm12) {
1270 GenInstrI(funct3, LOAD, rd, rs1, imm12);
1271 }
1272
GenInstrStore_rri(uint8_t funct3,Register rs1,Register rs2,int16_t imm12)1273 void Assembler::GenInstrStore_rri(uint8_t funct3, Register rs1, Register rs2,
1274 int16_t imm12) {
1275 GenInstrS(funct3, STORE, rs1, rs2, imm12);
1276 }
1277
GenInstrALU_ri(uint8_t funct3,Register rd,Register rs1,int16_t imm12)1278 void Assembler::GenInstrALU_ri(uint8_t funct3, Register rd, Register rs1,
1279 int16_t imm12) {
1280 GenInstrI(funct3, OP_IMM, rd, rs1, imm12);
1281 }
1282
GenInstrShift_ri(bool arithshift,uint8_t funct3,Register rd,Register rs1,uint8_t shamt)1283 void Assembler::GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd,
1284 Register rs1, uint8_t shamt) {
1285 DCHECK(is_uint6(shamt));
1286 GenInstrI(funct3, OP_IMM, rd, rs1, (arithshift << 10) | shamt);
1287 }
1288
GenInstrALU_rr(uint8_t funct7,uint8_t funct3,Register rd,Register rs1,Register rs2)1289 void Assembler::GenInstrALU_rr(uint8_t funct7, uint8_t funct3, Register rd,
1290 Register rs1, Register rs2) {
1291 GenInstrR(funct7, funct3, OP, rd, rs1, rs2);
1292 }
1293
GenInstrCSR_ir(uint8_t funct3,Register rd,ControlStatusReg csr,Register rs1)1294 void Assembler::GenInstrCSR_ir(uint8_t funct3, Register rd,
1295 ControlStatusReg csr, Register rs1) {
1296 GenInstrI(funct3, SYSTEM, rd, rs1, csr);
1297 }
1298
GenInstrCSR_ii(uint8_t funct3,Register rd,ControlStatusReg csr,uint8_t imm5)1299 void Assembler::GenInstrCSR_ii(uint8_t funct3, Register rd,
1300 ControlStatusReg csr, uint8_t imm5) {
1301 GenInstrI(funct3, SYSTEM, rd, ToRegister(imm5), csr);
1302 }
1303
GenInstrShiftW_ri(bool arithshift,uint8_t funct3,Register rd,Register rs1,uint8_t shamt)1304 void Assembler::GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd,
1305 Register rs1, uint8_t shamt) {
1306 GenInstrIShiftW(arithshift, funct3, OP_IMM_32, rd, rs1, shamt);
1307 }
1308
GenInstrALUW_rr(uint8_t funct7,uint8_t funct3,Register rd,Register rs1,Register rs2)1309 void Assembler::GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, Register rd,
1310 Register rs1, Register rs2) {
1311 GenInstrR(funct7, funct3, OP_32, rd, rs1, rs2);
1312 }
1313
GenInstrPriv(uint8_t funct7,Register rs1,Register rs2)1314 void Assembler::GenInstrPriv(uint8_t funct7, Register rs1, Register rs2) {
1315 GenInstrR(funct7, 0b000, SYSTEM, ToRegister(0), rs1, rs2);
1316 }
1317
GenInstrLoadFP_ri(uint8_t funct3,FPURegister rd,Register rs1,int16_t imm12)1318 void Assembler::GenInstrLoadFP_ri(uint8_t funct3, FPURegister rd, Register rs1,
1319 int16_t imm12) {
1320 GenInstrI(funct3, LOAD_FP, rd, rs1, imm12);
1321 }
1322
GenInstrStoreFP_rri(uint8_t funct3,Register rs1,FPURegister rs2,int16_t imm12)1323 void Assembler::GenInstrStoreFP_rri(uint8_t funct3, Register rs1,
1324 FPURegister rs2, int16_t imm12) {
1325 GenInstrS(funct3, STORE_FP, rs1, rs2, imm12);
1326 }
1327
GenInstrALUFP_rr(uint8_t funct7,uint8_t funct3,FPURegister rd,FPURegister rs1,FPURegister rs2)1328 void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
1329 FPURegister rs1, FPURegister rs2) {
1330 GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2);
1331 }
1332
GenInstrALUFP_rr(uint8_t funct7,uint8_t funct3,FPURegister rd,Register rs1,Register rs2)1333 void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
1334 Register rs1, Register rs2) {
1335 GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2);
1336 }
1337
GenInstrALUFP_rr(uint8_t funct7,uint8_t funct3,FPURegister rd,FPURegister rs1,Register rs2)1338 void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd,
1339 FPURegister rs1, Register rs2) {
1340 GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2);
1341 }
1342
GenInstrALUFP_rr(uint8_t funct7,uint8_t funct3,Register rd,FPURegister rs1,Register rs2)1343 void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd,
1344 FPURegister rs1, Register rs2) {
1345 GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2);
1346 }
1347
GenInstrALUFP_rr(uint8_t funct7,uint8_t funct3,Register rd,FPURegister rs1,FPURegister rs2)1348 void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd,
1349 FPURegister rs1, FPURegister rs2) {
1350 GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2);
1351 }
1352
1353 // Returns the next free trampoline entry.
get_trampoline_entry(int32_t pos)1354 int32_t Assembler::get_trampoline_entry(int32_t pos) {
1355 int32_t trampoline_entry = kInvalidSlotPos;
1356 if (!internal_trampoline_exception_) {
1357 DEBUG_PRINTF("\tstart: %d,pos: %d\n", trampoline_.start(), pos);
1358 if (trampoline_.start() > pos) {
1359 trampoline_entry = trampoline_.take_slot();
1360 }
1361
1362 if (kInvalidSlotPos == trampoline_entry) {
1363 internal_trampoline_exception_ = true;
1364 }
1365 }
1366 return trampoline_entry;
1367 }
1368
jump_address(Label * L)1369 uint64_t Assembler::jump_address(Label* L) {
1370 int64_t target_pos;
1371 DEBUG_PRINTF("jump_address: %p to %p (%d)\n", L,
1372 reinterpret_cast<Instr*>(buffer_start_ + pc_offset()),
1373 pc_offset());
1374 if (L->is_bound()) {
1375 target_pos = L->pos();
1376 } else {
1377 if (L->is_linked()) {
1378 target_pos = L->pos(); // L's link.
1379 L->link_to(pc_offset());
1380 } else {
1381 L->link_to(pc_offset());
1382 if (!trampoline_emitted_) {
1383 unbound_labels_count_++;
1384 next_buffer_check_ -= kTrampolineSlotsSize;
1385 }
1386 DEBUG_PRINTF("\tstarted link\n");
1387 return kEndOfJumpChain;
1388 }
1389 }
1390 uint64_t imm = reinterpret_cast<uint64_t>(buffer_start_) + target_pos;
1391 if (FLAG_riscv_c_extension)
1392 DCHECK_EQ(imm & 1, 0);
1393 else
1394 DCHECK_EQ(imm & 3, 0);
1395
1396 return imm;
1397 }
1398
branch_long_offset(Label * L)1399 uint64_t Assembler::branch_long_offset(Label* L) {
1400 int64_t target_pos;
1401
1402 DEBUG_PRINTF("branch_long_offset: %p to %p (%d)\n", L,
1403 reinterpret_cast<Instr*>(buffer_start_ + pc_offset()),
1404 pc_offset());
1405 if (L->is_bound()) {
1406 target_pos = L->pos();
1407 } else {
1408 if (L->is_linked()) {
1409 target_pos = L->pos(); // L's link.
1410 L->link_to(pc_offset());
1411 } else {
1412 L->link_to(pc_offset());
1413 if (!trampoline_emitted_) {
1414 unbound_labels_count_++;
1415 next_buffer_check_ -= kTrampolineSlotsSize;
1416 }
1417 DEBUG_PRINTF("\tstarted link\n");
1418 return kEndOfJumpChain;
1419 }
1420 }
1421 int64_t offset = target_pos - pc_offset();
1422 if (FLAG_riscv_c_extension)
1423 DCHECK_EQ(offset & 1, 0);
1424 else
1425 DCHECK_EQ(offset & 3, 0);
1426
1427 return static_cast<uint64_t>(offset);
1428 }
1429
branch_offset_helper(Label * L,OffsetSize bits)1430 int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
1431 int32_t target_pos;
1432
1433 DEBUG_PRINTF("branch_offset_helper: %p to %p (%d)\n", L,
1434 reinterpret_cast<Instr*>(buffer_start_ + pc_offset()),
1435 pc_offset());
1436 if (L->is_bound()) {
1437 target_pos = L->pos();
1438 DEBUG_PRINTF("\tbound: %d", target_pos);
1439 } else {
1440 if (L->is_linked()) {
1441 target_pos = L->pos();
1442 L->link_to(pc_offset());
1443 DEBUG_PRINTF("\tadded to link: %d\n", target_pos);
1444 } else {
1445 L->link_to(pc_offset());
1446 if (!trampoline_emitted_) {
1447 unbound_labels_count_++;
1448 next_buffer_check_ -= kTrampolineSlotsSize;
1449 }
1450 DEBUG_PRINTF("\tstarted link\n");
1451 return kEndOfJumpChain;
1452 }
1453 }
1454
1455 int32_t offset = target_pos - pc_offset();
1456 DCHECK(is_intn(offset, bits));
1457 DCHECK_EQ(offset & 1, 0);
1458 DEBUG_PRINTF("\toffset = %d\n", offset);
1459 return offset;
1460 }
1461
label_at_put(Label * L,int at_offset)1462 void Assembler::label_at_put(Label* L, int at_offset) {
1463 int target_pos;
1464 DEBUG_PRINTF("label_at_put: %p @ %p (%d)\n", L,
1465 reinterpret_cast<Instr*>(buffer_start_ + at_offset), at_offset);
1466 if (L->is_bound()) {
1467 target_pos = L->pos();
1468 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1469 } else {
1470 if (L->is_linked()) {
1471 target_pos = L->pos(); // L's link.
1472 int32_t imm18 = target_pos - at_offset;
1473 DCHECK_EQ(imm18 & 3, 0);
1474 int32_t imm16 = imm18 >> 2;
1475 DCHECK(is_int16(imm16));
1476 instr_at_put(at_offset, (int32_t)(imm16 & kImm16Mask));
1477 } else {
1478 target_pos = kEndOfJumpChain;
1479 instr_at_put(at_offset, target_pos);
1480 if (!trampoline_emitted_) {
1481 unbound_labels_count_++;
1482 next_buffer_check_ -= kTrampolineSlotsSize;
1483 }
1484 }
1485 L->link_to(at_offset);
1486 }
1487 }
1488
1489 //===----------------------------------------------------------------------===//
1490 // Instructions
1491 //===----------------------------------------------------------------------===//
1492
lui(Register rd,int32_t imm20)1493 void Assembler::lui(Register rd, int32_t imm20) { GenInstrU(LUI, rd, imm20); }
1494
auipc(Register rd,int32_t imm20)1495 void Assembler::auipc(Register rd, int32_t imm20) {
1496 GenInstrU(AUIPC, rd, imm20);
1497 }
1498
1499 // Jumps
1500
jal(Register rd,int32_t imm21)1501 void Assembler::jal(Register rd, int32_t imm21) {
1502 GenInstrJ(JAL, rd, imm21);
1503 BlockTrampolinePoolFor(1);
1504 }
1505
jalr(Register rd,Register rs1,int16_t imm12)1506 void Assembler::jalr(Register rd, Register rs1, int16_t imm12) {
1507 GenInstrI(0b000, JALR, rd, rs1, imm12);
1508 BlockTrampolinePoolFor(1);
1509 }
1510
1511 // Branches
1512
beq(Register rs1,Register rs2,int16_t imm13)1513 void Assembler::beq(Register rs1, Register rs2, int16_t imm13) {
1514 GenInstrBranchCC_rri(0b000, rs1, rs2, imm13);
1515 }
1516
bne(Register rs1,Register rs2,int16_t imm13)1517 void Assembler::bne(Register rs1, Register rs2, int16_t imm13) {
1518 GenInstrBranchCC_rri(0b001, rs1, rs2, imm13);
1519 }
1520
blt(Register rs1,Register rs2,int16_t imm13)1521 void Assembler::blt(Register rs1, Register rs2, int16_t imm13) {
1522 GenInstrBranchCC_rri(0b100, rs1, rs2, imm13);
1523 }
1524
bge(Register rs1,Register rs2,int16_t imm13)1525 void Assembler::bge(Register rs1, Register rs2, int16_t imm13) {
1526 GenInstrBranchCC_rri(0b101, rs1, rs2, imm13);
1527 }
1528
bltu(Register rs1,Register rs2,int16_t imm13)1529 void Assembler::bltu(Register rs1, Register rs2, int16_t imm13) {
1530 GenInstrBranchCC_rri(0b110, rs1, rs2, imm13);
1531 }
1532
bgeu(Register rs1,Register rs2,int16_t imm13)1533 void Assembler::bgeu(Register rs1, Register rs2, int16_t imm13) {
1534 GenInstrBranchCC_rri(0b111, rs1, rs2, imm13);
1535 }
1536
1537 // Loads
1538
lb(Register rd,Register rs1,int16_t imm12)1539 void Assembler::lb(Register rd, Register rs1, int16_t imm12) {
1540 GenInstrLoad_ri(0b000, rd, rs1, imm12);
1541 }
1542
lh(Register rd,Register rs1,int16_t imm12)1543 void Assembler::lh(Register rd, Register rs1, int16_t imm12) {
1544 GenInstrLoad_ri(0b001, rd, rs1, imm12);
1545 }
1546
lw(Register rd,Register rs1,int16_t imm12)1547 void Assembler::lw(Register rd, Register rs1, int16_t imm12) {
1548 GenInstrLoad_ri(0b010, rd, rs1, imm12);
1549 }
1550
lbu(Register rd,Register rs1,int16_t imm12)1551 void Assembler::lbu(Register rd, Register rs1, int16_t imm12) {
1552 GenInstrLoad_ri(0b100, rd, rs1, imm12);
1553 }
1554
lhu(Register rd,Register rs1,int16_t imm12)1555 void Assembler::lhu(Register rd, Register rs1, int16_t imm12) {
1556 GenInstrLoad_ri(0b101, rd, rs1, imm12);
1557 }
1558
1559 // Stores
1560
sb(Register source,Register base,int16_t imm12)1561 void Assembler::sb(Register source, Register base, int16_t imm12) {
1562 GenInstrStore_rri(0b000, base, source, imm12);
1563 }
1564
sh(Register source,Register base,int16_t imm12)1565 void Assembler::sh(Register source, Register base, int16_t imm12) {
1566 GenInstrStore_rri(0b001, base, source, imm12);
1567 }
1568
sw(Register source,Register base,int16_t imm12)1569 void Assembler::sw(Register source, Register base, int16_t imm12) {
1570 GenInstrStore_rri(0b010, base, source, imm12);
1571 }
1572
1573 // Arithmetic with immediate
1574
addi(Register rd,Register rs1,int16_t imm12)1575 void Assembler::addi(Register rd, Register rs1, int16_t imm12) {
1576 GenInstrALU_ri(0b000, rd, rs1, imm12);
1577 }
1578
slti(Register rd,Register rs1,int16_t imm12)1579 void Assembler::slti(Register rd, Register rs1, int16_t imm12) {
1580 GenInstrALU_ri(0b010, rd, rs1, imm12);
1581 }
1582
sltiu(Register rd,Register rs1,int16_t imm12)1583 void Assembler::sltiu(Register rd, Register rs1, int16_t imm12) {
1584 GenInstrALU_ri(0b011, rd, rs1, imm12);
1585 }
1586
xori(Register rd,Register rs1,int16_t imm12)1587 void Assembler::xori(Register rd, Register rs1, int16_t imm12) {
1588 GenInstrALU_ri(0b100, rd, rs1, imm12);
1589 }
1590
ori(Register rd,Register rs1,int16_t imm12)1591 void Assembler::ori(Register rd, Register rs1, int16_t imm12) {
1592 GenInstrALU_ri(0b110, rd, rs1, imm12);
1593 }
1594
andi(Register rd,Register rs1,int16_t imm12)1595 void Assembler::andi(Register rd, Register rs1, int16_t imm12) {
1596 GenInstrALU_ri(0b111, rd, rs1, imm12);
1597 }
1598
slli(Register rd,Register rs1,uint8_t shamt)1599 void Assembler::slli(Register rd, Register rs1, uint8_t shamt) {
1600 GenInstrShift_ri(0, 0b001, rd, rs1, shamt & 0x3f);
1601 }
1602
srli(Register rd,Register rs1,uint8_t shamt)1603 void Assembler::srli(Register rd, Register rs1, uint8_t shamt) {
1604 GenInstrShift_ri(0, 0b101, rd, rs1, shamt & 0x3f);
1605 }
1606
srai(Register rd,Register rs1,uint8_t shamt)1607 void Assembler::srai(Register rd, Register rs1, uint8_t shamt) {
1608 GenInstrShift_ri(1, 0b101, rd, rs1, shamt & 0x3f);
1609 }
1610
1611 // Arithmetic
1612
add(Register rd,Register rs1,Register rs2)1613 void Assembler::add(Register rd, Register rs1, Register rs2) {
1614 GenInstrALU_rr(0b0000000, 0b000, rd, rs1, rs2);
1615 }
1616
sub(Register rd,Register rs1,Register rs2)1617 void Assembler::sub(Register rd, Register rs1, Register rs2) {
1618 GenInstrALU_rr(0b0100000, 0b000, rd, rs1, rs2);
1619 }
1620
sll(Register rd,Register rs1,Register rs2)1621 void Assembler::sll(Register rd, Register rs1, Register rs2) {
1622 GenInstrALU_rr(0b0000000, 0b001, rd, rs1, rs2);
1623 }
1624
slt(Register rd,Register rs1,Register rs2)1625 void Assembler::slt(Register rd, Register rs1, Register rs2) {
1626 GenInstrALU_rr(0b0000000, 0b010, rd, rs1, rs2);
1627 }
1628
sltu(Register rd,Register rs1,Register rs2)1629 void Assembler::sltu(Register rd, Register rs1, Register rs2) {
1630 GenInstrALU_rr(0b0000000, 0b011, rd, rs1, rs2);
1631 }
1632
xor_(Register rd,Register rs1,Register rs2)1633 void Assembler::xor_(Register rd, Register rs1, Register rs2) {
1634 GenInstrALU_rr(0b0000000, 0b100, rd, rs1, rs2);
1635 }
1636
srl(Register rd,Register rs1,Register rs2)1637 void Assembler::srl(Register rd, Register rs1, Register rs2) {
1638 GenInstrALU_rr(0b0000000, 0b101, rd, rs1, rs2);
1639 }
1640
sra(Register rd,Register rs1,Register rs2)1641 void Assembler::sra(Register rd, Register rs1, Register rs2) {
1642 GenInstrALU_rr(0b0100000, 0b101, rd, rs1, rs2);
1643 }
1644
or_(Register rd,Register rs1,Register rs2)1645 void Assembler::or_(Register rd, Register rs1, Register rs2) {
1646 GenInstrALU_rr(0b0000000, 0b110, rd, rs1, rs2);
1647 }
1648
and_(Register rd,Register rs1,Register rs2)1649 void Assembler::and_(Register rd, Register rs1, Register rs2) {
1650 GenInstrALU_rr(0b0000000, 0b111, rd, rs1, rs2);
1651 }
1652
1653 // Memory fences
1654
fence(uint8_t pred,uint8_t succ)1655 void Assembler::fence(uint8_t pred, uint8_t succ) {
1656 DCHECK(is_uint4(pred) && is_uint4(succ));
1657 uint16_t imm12 = succ | (pred << 4) | (0b0000 << 8);
1658 GenInstrI(0b000, MISC_MEM, ToRegister(0), ToRegister(0), imm12);
1659 }
1660
fence_tso()1661 void Assembler::fence_tso() {
1662 uint16_t imm12 = (0b0011) | (0b0011 << 4) | (0b1000 << 8);
1663 GenInstrI(0b000, MISC_MEM, ToRegister(0), ToRegister(0), imm12);
1664 }
1665
1666 // Environment call / break
1667
ecall()1668 void Assembler::ecall() {
1669 GenInstrI(0b000, SYSTEM, ToRegister(0), ToRegister(0), 0);
1670 }
1671
ebreak()1672 void Assembler::ebreak() {
1673 GenInstrI(0b000, SYSTEM, ToRegister(0), ToRegister(0), 1);
1674 }
1675
1676 // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
1677 // instruction (i.e., it should always trap, if your implementation has invalid
1678 // instruction traps).
unimp()1679 void Assembler::unimp() {
1680 GenInstrI(0b001, SYSTEM, ToRegister(0), ToRegister(0), 0b110000000000);
1681 }
1682
1683 // CSR
1684
csrrw(Register rd,ControlStatusReg csr,Register rs1)1685 void Assembler::csrrw(Register rd, ControlStatusReg csr, Register rs1) {
1686 GenInstrCSR_ir(0b001, rd, csr, rs1);
1687 }
1688
csrrs(Register rd,ControlStatusReg csr,Register rs1)1689 void Assembler::csrrs(Register rd, ControlStatusReg csr, Register rs1) {
1690 GenInstrCSR_ir(0b010, rd, csr, rs1);
1691 }
1692
csrrc(Register rd,ControlStatusReg csr,Register rs1)1693 void Assembler::csrrc(Register rd, ControlStatusReg csr, Register rs1) {
1694 GenInstrCSR_ir(0b011, rd, csr, rs1);
1695 }
1696
csrrwi(Register rd,ControlStatusReg csr,uint8_t imm5)1697 void Assembler::csrrwi(Register rd, ControlStatusReg csr, uint8_t imm5) {
1698 GenInstrCSR_ii(0b101, rd, csr, imm5);
1699 }
1700
csrrsi(Register rd,ControlStatusReg csr,uint8_t imm5)1701 void Assembler::csrrsi(Register rd, ControlStatusReg csr, uint8_t imm5) {
1702 GenInstrCSR_ii(0b110, rd, csr, imm5);
1703 }
1704
csrrci(Register rd,ControlStatusReg csr,uint8_t imm5)1705 void Assembler::csrrci(Register rd, ControlStatusReg csr, uint8_t imm5) {
1706 GenInstrCSR_ii(0b111, rd, csr, imm5);
1707 }
1708
1709 // RV64I
1710
lwu(Register rd,Register rs1,int16_t imm12)1711 void Assembler::lwu(Register rd, Register rs1, int16_t imm12) {
1712 GenInstrLoad_ri(0b110, rd, rs1, imm12);
1713 }
1714
ld(Register rd,Register rs1,int16_t imm12)1715 void Assembler::ld(Register rd, Register rs1, int16_t imm12) {
1716 GenInstrLoad_ri(0b011, rd, rs1, imm12);
1717 }
1718
sd(Register source,Register base,int16_t imm12)1719 void Assembler::sd(Register source, Register base, int16_t imm12) {
1720 GenInstrStore_rri(0b011, base, source, imm12);
1721 }
1722
addiw(Register rd,Register rs1,int16_t imm12)1723 void Assembler::addiw(Register rd, Register rs1, int16_t imm12) {
1724 GenInstrI(0b000, OP_IMM_32, rd, rs1, imm12);
1725 }
1726
slliw(Register rd,Register rs1,uint8_t shamt)1727 void Assembler::slliw(Register rd, Register rs1, uint8_t shamt) {
1728 GenInstrShiftW_ri(0, 0b001, rd, rs1, shamt & 0x1f);
1729 }
1730
srliw(Register rd,Register rs1,uint8_t shamt)1731 void Assembler::srliw(Register rd, Register rs1, uint8_t shamt) {
1732 GenInstrShiftW_ri(0, 0b101, rd, rs1, shamt & 0x1f);
1733 }
1734
sraiw(Register rd,Register rs1,uint8_t shamt)1735 void Assembler::sraiw(Register rd, Register rs1, uint8_t shamt) {
1736 GenInstrShiftW_ri(1, 0b101, rd, rs1, shamt & 0x1f);
1737 }
1738
addw(Register rd,Register rs1,Register rs2)1739 void Assembler::addw(Register rd, Register rs1, Register rs2) {
1740 GenInstrALUW_rr(0b0000000, 0b000, rd, rs1, rs2);
1741 }
1742
subw(Register rd,Register rs1,Register rs2)1743 void Assembler::subw(Register rd, Register rs1, Register rs2) {
1744 GenInstrALUW_rr(0b0100000, 0b000, rd, rs1, rs2);
1745 }
1746
sllw(Register rd,Register rs1,Register rs2)1747 void Assembler::sllw(Register rd, Register rs1, Register rs2) {
1748 GenInstrALUW_rr(0b0000000, 0b001, rd, rs1, rs2);
1749 }
1750
srlw(Register rd,Register rs1,Register rs2)1751 void Assembler::srlw(Register rd, Register rs1, Register rs2) {
1752 GenInstrALUW_rr(0b0000000, 0b101, rd, rs1, rs2);
1753 }
1754
sraw(Register rd,Register rs1,Register rs2)1755 void Assembler::sraw(Register rd, Register rs1, Register rs2) {
1756 GenInstrALUW_rr(0b0100000, 0b101, rd, rs1, rs2);
1757 }
1758
1759 // RV32M Standard Extension
1760
mul(Register rd,Register rs1,Register rs2)1761 void Assembler::mul(Register rd, Register rs1, Register rs2) {
1762 GenInstrALU_rr(0b0000001, 0b000, rd, rs1, rs2);
1763 }
1764
mulh(Register rd,Register rs1,Register rs2)1765 void Assembler::mulh(Register rd, Register rs1, Register rs2) {
1766 GenInstrALU_rr(0b0000001, 0b001, rd, rs1, rs2);
1767 }
1768
mulhsu(Register rd,Register rs1,Register rs2)1769 void Assembler::mulhsu(Register rd, Register rs1, Register rs2) {
1770 GenInstrALU_rr(0b0000001, 0b010, rd, rs1, rs2);
1771 }
1772
mulhu(Register rd,Register rs1,Register rs2)1773 void Assembler::mulhu(Register rd, Register rs1, Register rs2) {
1774 GenInstrALU_rr(0b0000001, 0b011, rd, rs1, rs2);
1775 }
1776
div(Register rd,Register rs1,Register rs2)1777 void Assembler::div(Register rd, Register rs1, Register rs2) {
1778 GenInstrALU_rr(0b0000001, 0b100, rd, rs1, rs2);
1779 }
1780
divu(Register rd,Register rs1,Register rs2)1781 void Assembler::divu(Register rd, Register rs1, Register rs2) {
1782 GenInstrALU_rr(0b0000001, 0b101, rd, rs1, rs2);
1783 }
1784
rem(Register rd,Register rs1,Register rs2)1785 void Assembler::rem(Register rd, Register rs1, Register rs2) {
1786 GenInstrALU_rr(0b0000001, 0b110, rd, rs1, rs2);
1787 }
1788
remu(Register rd,Register rs1,Register rs2)1789 void Assembler::remu(Register rd, Register rs1, Register rs2) {
1790 GenInstrALU_rr(0b0000001, 0b111, rd, rs1, rs2);
1791 }
1792
1793 // RV64M Standard Extension (in addition to RV32M)
1794
mulw(Register rd,Register rs1,Register rs2)1795 void Assembler::mulw(Register rd, Register rs1, Register rs2) {
1796 GenInstrALUW_rr(0b0000001, 0b000, rd, rs1, rs2);
1797 }
1798
divw(Register rd,Register rs1,Register rs2)1799 void Assembler::divw(Register rd, Register rs1, Register rs2) {
1800 GenInstrALUW_rr(0b0000001, 0b100, rd, rs1, rs2);
1801 }
1802
divuw(Register rd,Register rs1,Register rs2)1803 void Assembler::divuw(Register rd, Register rs1, Register rs2) {
1804 GenInstrALUW_rr(0b0000001, 0b101, rd, rs1, rs2);
1805 }
1806
remw(Register rd,Register rs1,Register rs2)1807 void Assembler::remw(Register rd, Register rs1, Register rs2) {
1808 GenInstrALUW_rr(0b0000001, 0b110, rd, rs1, rs2);
1809 }
1810
remuw(Register rd,Register rs1,Register rs2)1811 void Assembler::remuw(Register rd, Register rs1, Register rs2) {
1812 GenInstrALUW_rr(0b0000001, 0b111, rd, rs1, rs2);
1813 }
1814
1815 // RV32A Standard Extension
1816
lr_w(bool aq,bool rl,Register rd,Register rs1)1817 void Assembler::lr_w(bool aq, bool rl, Register rd, Register rs1) {
1818 GenInstrRAtomic(0b00010, aq, rl, 0b010, rd, rs1, zero_reg);
1819 }
1820
sc_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1821 void Assembler::sc_w(bool aq, bool rl, Register rd, Register rs1,
1822 Register rs2) {
1823 GenInstrRAtomic(0b00011, aq, rl, 0b010, rd, rs1, rs2);
1824 }
1825
amoswap_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1826 void Assembler::amoswap_w(bool aq, bool rl, Register rd, Register rs1,
1827 Register rs2) {
1828 GenInstrRAtomic(0b00001, aq, rl, 0b010, rd, rs1, rs2);
1829 }
1830
amoadd_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1831 void Assembler::amoadd_w(bool aq, bool rl, Register rd, Register rs1,
1832 Register rs2) {
1833 GenInstrRAtomic(0b00000, aq, rl, 0b010, rd, rs1, rs2);
1834 }
1835
amoxor_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1836 void Assembler::amoxor_w(bool aq, bool rl, Register rd, Register rs1,
1837 Register rs2) {
1838 GenInstrRAtomic(0b00100, aq, rl, 0b010, rd, rs1, rs2);
1839 }
1840
amoand_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1841 void Assembler::amoand_w(bool aq, bool rl, Register rd, Register rs1,
1842 Register rs2) {
1843 GenInstrRAtomic(0b01100, aq, rl, 0b010, rd, rs1, rs2);
1844 }
1845
amoor_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1846 void Assembler::amoor_w(bool aq, bool rl, Register rd, Register rs1,
1847 Register rs2) {
1848 GenInstrRAtomic(0b01000, aq, rl, 0b010, rd, rs1, rs2);
1849 }
1850
amomin_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1851 void Assembler::amomin_w(bool aq, bool rl, Register rd, Register rs1,
1852 Register rs2) {
1853 GenInstrRAtomic(0b10000, aq, rl, 0b010, rd, rs1, rs2);
1854 }
1855
amomax_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1856 void Assembler::amomax_w(bool aq, bool rl, Register rd, Register rs1,
1857 Register rs2) {
1858 GenInstrRAtomic(0b10100, aq, rl, 0b010, rd, rs1, rs2);
1859 }
1860
amominu_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1861 void Assembler::amominu_w(bool aq, bool rl, Register rd, Register rs1,
1862 Register rs2) {
1863 GenInstrRAtomic(0b11000, aq, rl, 0b010, rd, rs1, rs2);
1864 }
1865
amomaxu_w(bool aq,bool rl,Register rd,Register rs1,Register rs2)1866 void Assembler::amomaxu_w(bool aq, bool rl, Register rd, Register rs1,
1867 Register rs2) {
1868 GenInstrRAtomic(0b11100, aq, rl, 0b010, rd, rs1, rs2);
1869 }
1870
1871 // RV64A Standard Extension (in addition to RV32A)
1872
lr_d(bool aq,bool rl,Register rd,Register rs1)1873 void Assembler::lr_d(bool aq, bool rl, Register rd, Register rs1) {
1874 GenInstrRAtomic(0b00010, aq, rl, 0b011, rd, rs1, zero_reg);
1875 }
1876
sc_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1877 void Assembler::sc_d(bool aq, bool rl, Register rd, Register rs1,
1878 Register rs2) {
1879 GenInstrRAtomic(0b00011, aq, rl, 0b011, rd, rs1, rs2);
1880 }
1881
amoswap_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1882 void Assembler::amoswap_d(bool aq, bool rl, Register rd, Register rs1,
1883 Register rs2) {
1884 GenInstrRAtomic(0b00001, aq, rl, 0b011, rd, rs1, rs2);
1885 }
1886
amoadd_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1887 void Assembler::amoadd_d(bool aq, bool rl, Register rd, Register rs1,
1888 Register rs2) {
1889 GenInstrRAtomic(0b00000, aq, rl, 0b011, rd, rs1, rs2);
1890 }
1891
amoxor_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1892 void Assembler::amoxor_d(bool aq, bool rl, Register rd, Register rs1,
1893 Register rs2) {
1894 GenInstrRAtomic(0b00100, aq, rl, 0b011, rd, rs1, rs2);
1895 }
1896
amoand_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1897 void Assembler::amoand_d(bool aq, bool rl, Register rd, Register rs1,
1898 Register rs2) {
1899 GenInstrRAtomic(0b01100, aq, rl, 0b011, rd, rs1, rs2);
1900 }
1901
amoor_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1902 void Assembler::amoor_d(bool aq, bool rl, Register rd, Register rs1,
1903 Register rs2) {
1904 GenInstrRAtomic(0b01000, aq, rl, 0b011, rd, rs1, rs2);
1905 }
1906
amomin_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1907 void Assembler::amomin_d(bool aq, bool rl, Register rd, Register rs1,
1908 Register rs2) {
1909 GenInstrRAtomic(0b10000, aq, rl, 0b011, rd, rs1, rs2);
1910 }
1911
amomax_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1912 void Assembler::amomax_d(bool aq, bool rl, Register rd, Register rs1,
1913 Register rs2) {
1914 GenInstrRAtomic(0b10100, aq, rl, 0b011, rd, rs1, rs2);
1915 }
1916
amominu_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1917 void Assembler::amominu_d(bool aq, bool rl, Register rd, Register rs1,
1918 Register rs2) {
1919 GenInstrRAtomic(0b11000, aq, rl, 0b011, rd, rs1, rs2);
1920 }
1921
amomaxu_d(bool aq,bool rl,Register rd,Register rs1,Register rs2)1922 void Assembler::amomaxu_d(bool aq, bool rl, Register rd, Register rs1,
1923 Register rs2) {
1924 GenInstrRAtomic(0b11100, aq, rl, 0b011, rd, rs1, rs2);
1925 }
1926
1927 // RV32F Standard Extension
1928
flw(FPURegister rd,Register rs1,int16_t imm12)1929 void Assembler::flw(FPURegister rd, Register rs1, int16_t imm12) {
1930 GenInstrLoadFP_ri(0b010, rd, rs1, imm12);
1931 }
1932
fsw(FPURegister source,Register base,int16_t imm12)1933 void Assembler::fsw(FPURegister source, Register base, int16_t imm12) {
1934 GenInstrStoreFP_rri(0b010, base, source, imm12);
1935 }
1936
fmadd_s(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)1937 void Assembler::fmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1938 FPURegister rs3, RoundingMode frm) {
1939 GenInstrR4(0b00, MADD, rd, rs1, rs2, rs3, frm);
1940 }
1941
fmsub_s(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)1942 void Assembler::fmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1943 FPURegister rs3, RoundingMode frm) {
1944 GenInstrR4(0b00, MSUB, rd, rs1, rs2, rs3, frm);
1945 }
1946
fnmsub_s(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)1947 void Assembler::fnmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1948 FPURegister rs3, RoundingMode frm) {
1949 GenInstrR4(0b00, NMSUB, rd, rs1, rs2, rs3, frm);
1950 }
1951
fnmadd_s(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)1952 void Assembler::fnmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1953 FPURegister rs3, RoundingMode frm) {
1954 GenInstrR4(0b00, NMADD, rd, rs1, rs2, rs3, frm);
1955 }
1956
fadd_s(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)1957 void Assembler::fadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1958 RoundingMode frm) {
1959 GenInstrALUFP_rr(0b0000000, frm, rd, rs1, rs2);
1960 }
1961
fsub_s(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)1962 void Assembler::fsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1963 RoundingMode frm) {
1964 GenInstrALUFP_rr(0b0000100, frm, rd, rs1, rs2);
1965 }
1966
fmul_s(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)1967 void Assembler::fmul_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1968 RoundingMode frm) {
1969 GenInstrALUFP_rr(0b0001000, frm, rd, rs1, rs2);
1970 }
1971
fdiv_s(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)1972 void Assembler::fdiv_s(FPURegister rd, FPURegister rs1, FPURegister rs2,
1973 RoundingMode frm) {
1974 GenInstrALUFP_rr(0b0001100, frm, rd, rs1, rs2);
1975 }
1976
fsqrt_s(FPURegister rd,FPURegister rs1,RoundingMode frm)1977 void Assembler::fsqrt_s(FPURegister rd, FPURegister rs1, RoundingMode frm) {
1978 GenInstrALUFP_rr(0b0101100, frm, rd, rs1, zero_reg);
1979 }
1980
fsgnj_s(FPURegister rd,FPURegister rs1,FPURegister rs2)1981 void Assembler::fsgnj_s(FPURegister rd, FPURegister rs1, FPURegister rs2) {
1982 GenInstrALUFP_rr(0b0010000, 0b000, rd, rs1, rs2);
1983 }
1984
fsgnjn_s(FPURegister rd,FPURegister rs1,FPURegister rs2)1985 void Assembler::fsgnjn_s(FPURegister rd, FPURegister rs1, FPURegister rs2) {
1986 GenInstrALUFP_rr(0b0010000, 0b001, rd, rs1, rs2);
1987 }
1988
fsgnjx_s(FPURegister rd,FPURegister rs1,FPURegister rs2)1989 void Assembler::fsgnjx_s(FPURegister rd, FPURegister rs1, FPURegister rs2) {
1990 GenInstrALUFP_rr(0b0010000, 0b010, rd, rs1, rs2);
1991 }
1992
fmin_s(FPURegister rd,FPURegister rs1,FPURegister rs2)1993 void Assembler::fmin_s(FPURegister rd, FPURegister rs1, FPURegister rs2) {
1994 GenInstrALUFP_rr(0b0010100, 0b000, rd, rs1, rs2);
1995 }
1996
fmax_s(FPURegister rd,FPURegister rs1,FPURegister rs2)1997 void Assembler::fmax_s(FPURegister rd, FPURegister rs1, FPURegister rs2) {
1998 GenInstrALUFP_rr(0b0010100, 0b001, rd, rs1, rs2);
1999 }
2000
fcvt_w_s(Register rd,FPURegister rs1,RoundingMode frm)2001 void Assembler::fcvt_w_s(Register rd, FPURegister rs1, RoundingMode frm) {
2002 GenInstrALUFP_rr(0b1100000, frm, rd, rs1, zero_reg);
2003 }
2004
fcvt_wu_s(Register rd,FPURegister rs1,RoundingMode frm)2005 void Assembler::fcvt_wu_s(Register rd, FPURegister rs1, RoundingMode frm) {
2006 GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(1));
2007 }
2008
fmv_x_w(Register rd,FPURegister rs1)2009 void Assembler::fmv_x_w(Register rd, FPURegister rs1) {
2010 GenInstrALUFP_rr(0b1110000, 0b000, rd, rs1, zero_reg);
2011 }
2012
feq_s(Register rd,FPURegister rs1,FPURegister rs2)2013 void Assembler::feq_s(Register rd, FPURegister rs1, FPURegister rs2) {
2014 GenInstrALUFP_rr(0b1010000, 0b010, rd, rs1, rs2);
2015 }
2016
flt_s(Register rd,FPURegister rs1,FPURegister rs2)2017 void Assembler::flt_s(Register rd, FPURegister rs1, FPURegister rs2) {
2018 GenInstrALUFP_rr(0b1010000, 0b001, rd, rs1, rs2);
2019 }
2020
fle_s(Register rd,FPURegister rs1,FPURegister rs2)2021 void Assembler::fle_s(Register rd, FPURegister rs1, FPURegister rs2) {
2022 GenInstrALUFP_rr(0b1010000, 0b000, rd, rs1, rs2);
2023 }
2024
fclass_s(Register rd,FPURegister rs1)2025 void Assembler::fclass_s(Register rd, FPURegister rs1) {
2026 GenInstrALUFP_rr(0b1110000, 0b001, rd, rs1, zero_reg);
2027 }
2028
fcvt_s_w(FPURegister rd,Register rs1,RoundingMode frm)2029 void Assembler::fcvt_s_w(FPURegister rd, Register rs1, RoundingMode frm) {
2030 GenInstrALUFP_rr(0b1101000, frm, rd, rs1, zero_reg);
2031 }
2032
fcvt_s_wu(FPURegister rd,Register rs1,RoundingMode frm)2033 void Assembler::fcvt_s_wu(FPURegister rd, Register rs1, RoundingMode frm) {
2034 GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(1));
2035 }
2036
fmv_w_x(FPURegister rd,Register rs1)2037 void Assembler::fmv_w_x(FPURegister rd, Register rs1) {
2038 GenInstrALUFP_rr(0b1111000, 0b000, rd, rs1, zero_reg);
2039 }
2040
2041 // RV64F Standard Extension (in addition to RV32F)
2042
fcvt_l_s(Register rd,FPURegister rs1,RoundingMode frm)2043 void Assembler::fcvt_l_s(Register rd, FPURegister rs1, RoundingMode frm) {
2044 GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(2));
2045 }
2046
fcvt_lu_s(Register rd,FPURegister rs1,RoundingMode frm)2047 void Assembler::fcvt_lu_s(Register rd, FPURegister rs1, RoundingMode frm) {
2048 GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(3));
2049 }
2050
fcvt_s_l(FPURegister rd,Register rs1,RoundingMode frm)2051 void Assembler::fcvt_s_l(FPURegister rd, Register rs1, RoundingMode frm) {
2052 GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(2));
2053 }
2054
fcvt_s_lu(FPURegister rd,Register rs1,RoundingMode frm)2055 void Assembler::fcvt_s_lu(FPURegister rd, Register rs1, RoundingMode frm) {
2056 GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(3));
2057 }
2058
2059 // RV32D Standard Extension
2060
fld(FPURegister rd,Register rs1,int16_t imm12)2061 void Assembler::fld(FPURegister rd, Register rs1, int16_t imm12) {
2062 GenInstrLoadFP_ri(0b011, rd, rs1, imm12);
2063 }
2064
fsd(FPURegister source,Register base,int16_t imm12)2065 void Assembler::fsd(FPURegister source, Register base, int16_t imm12) {
2066 GenInstrStoreFP_rri(0b011, base, source, imm12);
2067 }
2068
fmadd_d(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)2069 void Assembler::fmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2070 FPURegister rs3, RoundingMode frm) {
2071 GenInstrR4(0b01, MADD, rd, rs1, rs2, rs3, frm);
2072 }
2073
fmsub_d(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)2074 void Assembler::fmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2075 FPURegister rs3, RoundingMode frm) {
2076 GenInstrR4(0b01, MSUB, rd, rs1, rs2, rs3, frm);
2077 }
2078
fnmsub_d(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)2079 void Assembler::fnmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2080 FPURegister rs3, RoundingMode frm) {
2081 GenInstrR4(0b01, NMSUB, rd, rs1, rs2, rs3, frm);
2082 }
2083
fnmadd_d(FPURegister rd,FPURegister rs1,FPURegister rs2,FPURegister rs3,RoundingMode frm)2084 void Assembler::fnmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2085 FPURegister rs3, RoundingMode frm) {
2086 GenInstrR4(0b01, NMADD, rd, rs1, rs2, rs3, frm);
2087 }
2088
fadd_d(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)2089 void Assembler::fadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2090 RoundingMode frm) {
2091 GenInstrALUFP_rr(0b0000001, frm, rd, rs1, rs2);
2092 }
2093
fsub_d(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)2094 void Assembler::fsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2095 RoundingMode frm) {
2096 GenInstrALUFP_rr(0b0000101, frm, rd, rs1, rs2);
2097 }
2098
fmul_d(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)2099 void Assembler::fmul_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2100 RoundingMode frm) {
2101 GenInstrALUFP_rr(0b0001001, frm, rd, rs1, rs2);
2102 }
2103
fdiv_d(FPURegister rd,FPURegister rs1,FPURegister rs2,RoundingMode frm)2104 void Assembler::fdiv_d(FPURegister rd, FPURegister rs1, FPURegister rs2,
2105 RoundingMode frm) {
2106 GenInstrALUFP_rr(0b0001101, frm, rd, rs1, rs2);
2107 }
2108
fsqrt_d(FPURegister rd,FPURegister rs1,RoundingMode frm)2109 void Assembler::fsqrt_d(FPURegister rd, FPURegister rs1, RoundingMode frm) {
2110 GenInstrALUFP_rr(0b0101101, frm, rd, rs1, zero_reg);
2111 }
2112
fsgnj_d(FPURegister rd,FPURegister rs1,FPURegister rs2)2113 void Assembler::fsgnj_d(FPURegister rd, FPURegister rs1, FPURegister rs2) {
2114 GenInstrALUFP_rr(0b0010001, 0b000, rd, rs1, rs2);
2115 }
2116
fsgnjn_d(FPURegister rd,FPURegister rs1,FPURegister rs2)2117 void Assembler::fsgnjn_d(FPURegister rd, FPURegister rs1, FPURegister rs2) {
2118 GenInstrALUFP_rr(0b0010001, 0b001, rd, rs1, rs2);
2119 }
2120
fsgnjx_d(FPURegister rd,FPURegister rs1,FPURegister rs2)2121 void Assembler::fsgnjx_d(FPURegister rd, FPURegister rs1, FPURegister rs2) {
2122 GenInstrALUFP_rr(0b0010001, 0b010, rd, rs1, rs2);
2123 }
2124
fmin_d(FPURegister rd,FPURegister rs1,FPURegister rs2)2125 void Assembler::fmin_d(FPURegister rd, FPURegister rs1, FPURegister rs2) {
2126 GenInstrALUFP_rr(0b0010101, 0b000, rd, rs1, rs2);
2127 }
2128
fmax_d(FPURegister rd,FPURegister rs1,FPURegister rs2)2129 void Assembler::fmax_d(FPURegister rd, FPURegister rs1, FPURegister rs2) {
2130 GenInstrALUFP_rr(0b0010101, 0b001, rd, rs1, rs2);
2131 }
2132
fcvt_s_d(FPURegister rd,FPURegister rs1,RoundingMode frm)2133 void Assembler::fcvt_s_d(FPURegister rd, FPURegister rs1, RoundingMode frm) {
2134 GenInstrALUFP_rr(0b0100000, frm, rd, rs1, ToRegister(1));
2135 }
2136
fcvt_d_s(FPURegister rd,FPURegister rs1,RoundingMode frm)2137 void Assembler::fcvt_d_s(FPURegister rd, FPURegister rs1, RoundingMode frm) {
2138 GenInstrALUFP_rr(0b0100001, frm, rd, rs1, zero_reg);
2139 }
2140
feq_d(Register rd,FPURegister rs1,FPURegister rs2)2141 void Assembler::feq_d(Register rd, FPURegister rs1, FPURegister rs2) {
2142 GenInstrALUFP_rr(0b1010001, 0b010, rd, rs1, rs2);
2143 }
2144
flt_d(Register rd,FPURegister rs1,FPURegister rs2)2145 void Assembler::flt_d(Register rd, FPURegister rs1, FPURegister rs2) {
2146 GenInstrALUFP_rr(0b1010001, 0b001, rd, rs1, rs2);
2147 }
2148
fle_d(Register rd,FPURegister rs1,FPURegister rs2)2149 void Assembler::fle_d(Register rd, FPURegister rs1, FPURegister rs2) {
2150 GenInstrALUFP_rr(0b1010001, 0b000, rd, rs1, rs2);
2151 }
2152
fclass_d(Register rd,FPURegister rs1)2153 void Assembler::fclass_d(Register rd, FPURegister rs1) {
2154 GenInstrALUFP_rr(0b1110001, 0b001, rd, rs1, zero_reg);
2155 }
2156
fcvt_w_d(Register rd,FPURegister rs1,RoundingMode frm)2157 void Assembler::fcvt_w_d(Register rd, FPURegister rs1, RoundingMode frm) {
2158 GenInstrALUFP_rr(0b1100001, frm, rd, rs1, zero_reg);
2159 }
2160
fcvt_wu_d(Register rd,FPURegister rs1,RoundingMode frm)2161 void Assembler::fcvt_wu_d(Register rd, FPURegister rs1, RoundingMode frm) {
2162 GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(1));
2163 }
2164
fcvt_d_w(FPURegister rd,Register rs1,RoundingMode frm)2165 void Assembler::fcvt_d_w(FPURegister rd, Register rs1, RoundingMode frm) {
2166 GenInstrALUFP_rr(0b1101001, frm, rd, rs1, zero_reg);
2167 }
2168
fcvt_d_wu(FPURegister rd,Register rs1,RoundingMode frm)2169 void Assembler::fcvt_d_wu(FPURegister rd, Register rs1, RoundingMode frm) {
2170 GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(1));
2171 }
2172
2173 // RV64D Standard Extension (in addition to RV32D)
2174
fcvt_l_d(Register rd,FPURegister rs1,RoundingMode frm)2175 void Assembler::fcvt_l_d(Register rd, FPURegister rs1, RoundingMode frm) {
2176 GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(2));
2177 }
2178
fcvt_lu_d(Register rd,FPURegister rs1,RoundingMode frm)2179 void Assembler::fcvt_lu_d(Register rd, FPURegister rs1, RoundingMode frm) {
2180 GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(3));
2181 }
2182
fmv_x_d(Register rd,FPURegister rs1)2183 void Assembler::fmv_x_d(Register rd, FPURegister rs1) {
2184 GenInstrALUFP_rr(0b1110001, 0b000, rd, rs1, zero_reg);
2185 }
2186
fcvt_d_l(FPURegister rd,Register rs1,RoundingMode frm)2187 void Assembler::fcvt_d_l(FPURegister rd, Register rs1, RoundingMode frm) {
2188 GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(2));
2189 }
2190
fcvt_d_lu(FPURegister rd,Register rs1,RoundingMode frm)2191 void Assembler::fcvt_d_lu(FPURegister rd, Register rs1, RoundingMode frm) {
2192 GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(3));
2193 }
2194
fmv_d_x(FPURegister rd,Register rs1)2195 void Assembler::fmv_d_x(FPURegister rd, Register rs1) {
2196 GenInstrALUFP_rr(0b1111001, 0b000, rd, rs1, zero_reg);
2197 }
2198
2199 // RV64C Standard Extension
c_nop()2200 void Assembler::c_nop() { GenInstrCI(0b000, C1, zero_reg, 0); }
2201
c_addi(Register rd,int8_t imm6)2202 void Assembler::c_addi(Register rd, int8_t imm6) {
2203 DCHECK(rd != zero_reg && imm6 != 0);
2204 GenInstrCI(0b000, C1, rd, imm6);
2205 }
2206
c_addiw(Register rd,int8_t imm6)2207 void Assembler::c_addiw(Register rd, int8_t imm6) {
2208 DCHECK(rd != zero_reg);
2209 GenInstrCI(0b001, C1, rd, imm6);
2210 }
2211
c_addi16sp(int16_t imm10)2212 void Assembler::c_addi16sp(int16_t imm10) {
2213 DCHECK(is_int10(imm10) && (imm10 & 0xf) == 0);
2214 uint8_t uimm6 = ((imm10 & 0x200) >> 4) | (imm10 & 0x10) |
2215 ((imm10 & 0x40) >> 3) | ((imm10 & 0x180) >> 6) |
2216 ((imm10 & 0x20) >> 5);
2217 GenInstrCIU(0b011, C1, sp, uimm6);
2218 }
2219
c_addi4spn(Register rd,int16_t uimm10)2220 void Assembler::c_addi4spn(Register rd, int16_t uimm10) {
2221 DCHECK(is_uint10(uimm10) && (uimm10 != 0));
2222 uint8_t uimm8 = ((uimm10 & 0x4) >> 1) | ((uimm10 & 0x8) >> 3) |
2223 ((uimm10 & 0x30) << 2) | ((uimm10 & 0x3c0) >> 4);
2224 GenInstrCIW(0b000, C0, rd, uimm8);
2225 }
2226
c_li(Register rd,int8_t imm6)2227 void Assembler::c_li(Register rd, int8_t imm6) {
2228 DCHECK(rd != zero_reg);
2229 GenInstrCI(0b010, C1, rd, imm6);
2230 }
2231
c_lui(Register rd,int8_t imm6)2232 void Assembler::c_lui(Register rd, int8_t imm6) {
2233 DCHECK(rd != zero_reg && rd != sp && imm6 != 0);
2234 GenInstrCI(0b011, C1, rd, imm6);
2235 }
2236
c_slli(Register rd,uint8_t shamt6)2237 void Assembler::c_slli(Register rd, uint8_t shamt6) {
2238 DCHECK(rd != zero_reg && shamt6 != 0);
2239 GenInstrCIU(0b000, C2, rd, shamt6);
2240 }
2241
c_fldsp(FPURegister rd,uint16_t uimm9)2242 void Assembler::c_fldsp(FPURegister rd, uint16_t uimm9) {
2243 DCHECK(is_uint9(uimm9) && (uimm9 & 0x7) == 0);
2244 uint8_t uimm6 = (uimm9 & 0x38) | ((uimm9 & 0x1c0) >> 6);
2245 GenInstrCIU(0b001, C2, rd, uimm6);
2246 }
2247
c_lwsp(Register rd,uint16_t uimm8)2248 void Assembler::c_lwsp(Register rd, uint16_t uimm8) {
2249 DCHECK(rd != zero_reg && is_uint8(uimm8) && (uimm8 & 0x3) == 0);
2250 uint8_t uimm6 = (uimm8 & 0x3c) | ((uimm8 & 0xc0) >> 6);
2251 GenInstrCIU(0b010, C2, rd, uimm6);
2252 }
2253
c_ldsp(Register rd,uint16_t uimm9)2254 void Assembler::c_ldsp(Register rd, uint16_t uimm9) {
2255 DCHECK(rd != zero_reg && is_uint9(uimm9) && (uimm9 & 0x7) == 0);
2256 uint8_t uimm6 = (uimm9 & 0x38) | ((uimm9 & 0x1c0) >> 6);
2257 GenInstrCIU(0b011, C2, rd, uimm6);
2258 }
2259
c_jr(Register rs1)2260 void Assembler::c_jr(Register rs1) {
2261 DCHECK(rs1 != zero_reg);
2262 GenInstrCR(0b1000, C2, rs1, zero_reg);
2263 BlockTrampolinePoolFor(1);
2264 }
2265
c_mv(Register rd,Register rs2)2266 void Assembler::c_mv(Register rd, Register rs2) {
2267 DCHECK(rd != zero_reg && rs2 != zero_reg);
2268 GenInstrCR(0b1000, C2, rd, rs2);
2269 }
2270
c_ebreak()2271 void Assembler::c_ebreak() { GenInstrCR(0b1001, C2, zero_reg, zero_reg); }
2272
c_jalr(Register rs1)2273 void Assembler::c_jalr(Register rs1) {
2274 DCHECK(rs1 != zero_reg);
2275 GenInstrCR(0b1001, C2, rs1, zero_reg);
2276 BlockTrampolinePoolFor(1);
2277 }
2278
c_add(Register rd,Register rs2)2279 void Assembler::c_add(Register rd, Register rs2) {
2280 DCHECK(rd != zero_reg && rs2 != zero_reg);
2281 GenInstrCR(0b1001, C2, rd, rs2);
2282 }
2283
2284 // CA Instructions
c_sub(Register rd,Register rs2)2285 void Assembler::c_sub(Register rd, Register rs2) {
2286 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2287 ((rs2.code() & 0b11000) == 0b01000));
2288 GenInstrCA(0b100011, C1, rd, 0b00, rs2);
2289 }
2290
c_xor(Register rd,Register rs2)2291 void Assembler::c_xor(Register rd, Register rs2) {
2292 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2293 ((rs2.code() & 0b11000) == 0b01000));
2294 GenInstrCA(0b100011, C1, rd, 0b01, rs2);
2295 }
2296
c_or(Register rd,Register rs2)2297 void Assembler::c_or(Register rd, Register rs2) {
2298 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2299 ((rs2.code() & 0b11000) == 0b01000));
2300 GenInstrCA(0b100011, C1, rd, 0b10, rs2);
2301 }
2302
c_and(Register rd,Register rs2)2303 void Assembler::c_and(Register rd, Register rs2) {
2304 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2305 ((rs2.code() & 0b11000) == 0b01000));
2306 GenInstrCA(0b100011, C1, rd, 0b11, rs2);
2307 }
2308
c_subw(Register rd,Register rs2)2309 void Assembler::c_subw(Register rd, Register rs2) {
2310 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2311 ((rs2.code() & 0b11000) == 0b01000));
2312 GenInstrCA(0b100111, C1, rd, 0b00, rs2);
2313 }
2314
c_addw(Register rd,Register rs2)2315 void Assembler::c_addw(Register rd, Register rs2) {
2316 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2317 ((rs2.code() & 0b11000) == 0b01000));
2318 GenInstrCA(0b100111, C1, rd, 0b01, rs2);
2319 }
2320
c_swsp(Register rs2,uint16_t uimm8)2321 void Assembler::c_swsp(Register rs2, uint16_t uimm8) {
2322 DCHECK(is_uint8(uimm8) && (uimm8 & 0x3) == 0);
2323 uint8_t uimm6 = (uimm8 & 0x3c) | ((uimm8 & 0xc0) >> 6);
2324 GenInstrCSS(0b110, C2, rs2, uimm6);
2325 }
2326
c_sdsp(Register rs2,uint16_t uimm9)2327 void Assembler::c_sdsp(Register rs2, uint16_t uimm9) {
2328 DCHECK(is_uint9(uimm9) && (uimm9 & 0x7) == 0);
2329 uint8_t uimm6 = (uimm9 & 0x38) | ((uimm9 & 0x1c0) >> 6);
2330 GenInstrCSS(0b111, C2, rs2, uimm6);
2331 }
2332
c_fsdsp(FPURegister rs2,uint16_t uimm9)2333 void Assembler::c_fsdsp(FPURegister rs2, uint16_t uimm9) {
2334 DCHECK(is_uint9(uimm9) && (uimm9 & 0x7) == 0);
2335 uint8_t uimm6 = (uimm9 & 0x38) | ((uimm9 & 0x1c0) >> 6);
2336 GenInstrCSS(0b101, C2, rs2, uimm6);
2337 }
2338
2339 // CL Instructions
2340
c_lw(Register rd,Register rs1,uint16_t uimm7)2341 void Assembler::c_lw(Register rd, Register rs1, uint16_t uimm7) {
2342 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2343 ((rs1.code() & 0b11000) == 0b01000) && is_uint7(uimm7) &&
2344 ((uimm7 & 0x3) == 0));
2345 uint8_t uimm5 =
2346 ((uimm7 & 0x4) >> 1) | ((uimm7 & 0x40) >> 6) | ((uimm7 & 0x38) >> 1);
2347 GenInstrCL(0b010, C0, rd, rs1, uimm5);
2348 }
2349
c_ld(Register rd,Register rs1,uint16_t uimm8)2350 void Assembler::c_ld(Register rd, Register rs1, uint16_t uimm8) {
2351 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2352 ((rs1.code() & 0b11000) == 0b01000) && is_uint8(uimm8) &&
2353 ((uimm8 & 0x7) == 0));
2354 uint8_t uimm5 = ((uimm8 & 0x38) >> 1) | ((uimm8 & 0xc0) >> 6);
2355 GenInstrCL(0b011, C0, rd, rs1, uimm5);
2356 }
2357
c_fld(FPURegister rd,Register rs1,uint16_t uimm8)2358 void Assembler::c_fld(FPURegister rd, Register rs1, uint16_t uimm8) {
2359 DCHECK(((rd.code() & 0b11000) == 0b01000) &&
2360 ((rs1.code() & 0b11000) == 0b01000) && is_uint8(uimm8) &&
2361 ((uimm8 & 0x7) == 0));
2362 uint8_t uimm5 = ((uimm8 & 0x38) >> 1) | ((uimm8 & 0xc0) >> 6);
2363 GenInstrCL(0b001, C0, rd, rs1, uimm5);
2364 }
2365
2366 // CS Instructions
2367
c_sw(Register rs2,Register rs1,uint16_t uimm7)2368 void Assembler::c_sw(Register rs2, Register rs1, uint16_t uimm7) {
2369 DCHECK(((rs2.code() & 0b11000) == 0b01000) &&
2370 ((rs1.code() & 0b11000) == 0b01000) && is_uint7(uimm7) &&
2371 ((uimm7 & 0x3) == 0));
2372 uint8_t uimm5 =
2373 ((uimm7 & 0x4) >> 1) | ((uimm7 & 0x40) >> 6) | ((uimm7 & 0x38) >> 1);
2374 GenInstrCS(0b110, C0, rs2, rs1, uimm5);
2375 }
2376
c_sd(Register rs2,Register rs1,uint16_t uimm8)2377 void Assembler::c_sd(Register rs2, Register rs1, uint16_t uimm8) {
2378 DCHECK(((rs2.code() & 0b11000) == 0b01000) &&
2379 ((rs1.code() & 0b11000) == 0b01000) && is_uint8(uimm8) &&
2380 ((uimm8 & 0x7) == 0));
2381 uint8_t uimm5 = ((uimm8 & 0x38) >> 1) | ((uimm8 & 0xc0) >> 6);
2382 GenInstrCS(0b111, C0, rs2, rs1, uimm5);
2383 }
2384
c_fsd(FPURegister rs2,Register rs1,uint16_t uimm8)2385 void Assembler::c_fsd(FPURegister rs2, Register rs1, uint16_t uimm8) {
2386 DCHECK(((rs2.code() & 0b11000) == 0b01000) &&
2387 ((rs1.code() & 0b11000) == 0b01000) && is_uint8(uimm8) &&
2388 ((uimm8 & 0x7) == 0));
2389 uint8_t uimm5 = ((uimm8 & 0x38) >> 1) | ((uimm8 & 0xc0) >> 6);
2390 GenInstrCS(0b101, C0, rs2, rs1, uimm5);
2391 }
2392
2393 // CJ Instructions
2394
c_j(int16_t imm12)2395 void Assembler::c_j(int16_t imm12) {
2396 DCHECK(is_int12(imm12));
2397 int16_t uimm11 = ((imm12 & 0x800) >> 1) | ((imm12 & 0x400) >> 4) |
2398 ((imm12 & 0x300) >> 1) | ((imm12 & 0x80) >> 3) |
2399 ((imm12 & 0x40) >> 1) | ((imm12 & 0x20) >> 5) |
2400 ((imm12 & 0x10) << 5) | (imm12 & 0xe);
2401 GenInstrCJ(0b101, C1, uimm11);
2402 BlockTrampolinePoolFor(1);
2403 }
2404
2405 // CB Instructions
2406
c_bnez(Register rs1,int16_t imm9)2407 void Assembler::c_bnez(Register rs1, int16_t imm9) {
2408 DCHECK(((rs1.code() & 0b11000) == 0b01000) && is_int9(imm9));
2409 uint8_t uimm8 = ((imm9 & 0x20) >> 5) | ((imm9 & 0x6)) | ((imm9 & 0xc0) >> 3) |
2410 ((imm9 & 0x18) << 2) | ((imm9 & 0x100) >> 1);
2411 GenInstrCB(0b111, C1, rs1, uimm8);
2412 }
2413
c_beqz(Register rs1,int16_t imm9)2414 void Assembler::c_beqz(Register rs1, int16_t imm9) {
2415 DCHECK(((rs1.code() & 0b11000) == 0b01000) && is_int9(imm9));
2416 uint8_t uimm8 = ((imm9 & 0x20) >> 5) | ((imm9 & 0x6)) | ((imm9 & 0xc0) >> 3) |
2417 ((imm9 & 0x18) << 2) | ((imm9 & 0x100) >> 1);
2418 GenInstrCB(0b110, C1, rs1, uimm8);
2419 }
2420
c_srli(Register rs1,int8_t shamt6)2421 void Assembler::c_srli(Register rs1, int8_t shamt6) {
2422 DCHECK(((rs1.code() & 0b11000) == 0b01000) && is_int6(shamt6));
2423 GenInstrCBA(0b100, 0b00, C1, rs1, shamt6);
2424 }
2425
c_srai(Register rs1,int8_t shamt6)2426 void Assembler::c_srai(Register rs1, int8_t shamt6) {
2427 DCHECK(((rs1.code() & 0b11000) == 0b01000) && is_int6(shamt6));
2428 GenInstrCBA(0b100, 0b01, C1, rs1, shamt6);
2429 }
2430
c_andi(Register rs1,int8_t imm6)2431 void Assembler::c_andi(Register rs1, int8_t imm6) {
2432 DCHECK(((rs1.code() & 0b11000) == 0b01000) && is_int6(imm6));
2433 GenInstrCBA(0b100, 0b10, C1, rs1, imm6);
2434 }
2435
2436 // Definitions for using compressed vs non compressed
2437
NOP()2438 void Assembler::NOP() {
2439 if (FLAG_riscv_c_extension)
2440 c_nop();
2441 else
2442 nop();
2443 }
2444
EBREAK()2445 void Assembler::EBREAK() {
2446 if (FLAG_riscv_c_extension)
2447 c_ebreak();
2448 else
2449 ebreak();
2450 }
2451
2452 // RVV
vmv_vv(VRegister vd,VRegister vs1)2453 void Assembler::vmv_vv(VRegister vd, VRegister vs1) {
2454 GenInstrV(VMV_FUNCT6, OP_IVV, vd, vs1, v0, NoMask);
2455 }
2456
vmv_vx(VRegister vd,Register rs1)2457 void Assembler::vmv_vx(VRegister vd, Register rs1) {
2458 GenInstrV(VMV_FUNCT6, OP_IVX, vd, rs1, v0, NoMask);
2459 }
2460
vmv_vi(VRegister vd,uint8_t simm5)2461 void Assembler::vmv_vi(VRegister vd, uint8_t simm5) {
2462 GenInstrV(VMV_FUNCT6, vd, simm5, v0, NoMask);
2463 }
2464
vmv_xs(Register rd,VRegister vs2)2465 void Assembler::vmv_xs(Register rd, VRegister vs2) {
2466 GenInstrV(VWXUNARY0_FUNCT6, OP_MVV, rd, v0, vs2, NoMask);
2467 }
2468
vmv_sx(VRegister vd,Register rs1)2469 void Assembler::vmv_sx(VRegister vd, Register rs1) {
2470 GenInstrV(VRXUNARY0_FUNCT6, OP_MVX, vd, rs1, v0, NoMask);
2471 }
2472
vmerge_vv(VRegister vd,VRegister vs1,VRegister vs2)2473 void Assembler::vmerge_vv(VRegister vd, VRegister vs1, VRegister vs2) {
2474 GenInstrV(VMV_FUNCT6, OP_IVV, vd, vs1, vs2, Mask);
2475 }
2476
vmerge_vx(VRegister vd,Register rs1,VRegister vs2)2477 void Assembler::vmerge_vx(VRegister vd, Register rs1, VRegister vs2) {
2478 GenInstrV(VMV_FUNCT6, OP_IVX, vd, rs1, vs2, Mask);
2479 }
2480
vmerge_vi(VRegister vd,uint8_t imm5,VRegister vs2)2481 void Assembler::vmerge_vi(VRegister vd, uint8_t imm5, VRegister vs2) {
2482 GenInstrV(VMV_FUNCT6, vd, imm5, vs2, Mask);
2483 }
2484
vadc_vv(VRegister vd,VRegister vs1,VRegister vs2)2485 void Assembler::vadc_vv(VRegister vd, VRegister vs1, VRegister vs2) {
2486 GenInstrV(VADC_FUNCT6, OP_IVV, vd, vs1, vs2, Mask);
2487 }
2488
vadc_vx(VRegister vd,Register rs1,VRegister vs2)2489 void Assembler::vadc_vx(VRegister vd, Register rs1, VRegister vs2) {
2490 GenInstrV(VADC_FUNCT6, OP_IVX, vd, rs1, vs2, Mask);
2491 }
2492
vadc_vi(VRegister vd,uint8_t imm5,VRegister vs2)2493 void Assembler::vadc_vi(VRegister vd, uint8_t imm5, VRegister vs2) {
2494 GenInstrV(VADC_FUNCT6, vd, imm5, vs2, Mask);
2495 }
2496
vmadc_vv(VRegister vd,VRegister vs1,VRegister vs2)2497 void Assembler::vmadc_vv(VRegister vd, VRegister vs1, VRegister vs2) {
2498 GenInstrV(VMADC_FUNCT6, OP_IVV, vd, vs1, vs2, Mask);
2499 }
2500
vmadc_vx(VRegister vd,Register rs1,VRegister vs2)2501 void Assembler::vmadc_vx(VRegister vd, Register rs1, VRegister vs2) {
2502 GenInstrV(VMADC_FUNCT6, OP_IVX, vd, rs1, vs2, Mask);
2503 }
2504
vmadc_vi(VRegister vd,uint8_t imm5,VRegister vs2)2505 void Assembler::vmadc_vi(VRegister vd, uint8_t imm5, VRegister vs2) {
2506 GenInstrV(VMADC_FUNCT6, vd, imm5, vs2, Mask);
2507 }
2508
vrgather_vv(VRegister vd,VRegister vs2,VRegister vs1,MaskType mask)2509 void Assembler::vrgather_vv(VRegister vd, VRegister vs2, VRegister vs1,
2510 MaskType mask) {
2511 DCHECK_NE(vd, vs1);
2512 DCHECK_NE(vd, vs2);
2513 GenInstrV(VRGATHER_FUNCT6, OP_IVV, vd, vs1, vs2, mask);
2514 }
2515
vrgather_vi(VRegister vd,VRegister vs2,int8_t imm5,MaskType mask)2516 void Assembler::vrgather_vi(VRegister vd, VRegister vs2, int8_t imm5,
2517 MaskType mask) {
2518 DCHECK_NE(vd, vs2);
2519 GenInstrV(VRGATHER_FUNCT6, vd, imm5, vs2, mask);
2520 }
2521
vrgather_vx(VRegister vd,VRegister vs2,Register rs1,MaskType mask)2522 void Assembler::vrgather_vx(VRegister vd, VRegister vs2, Register rs1,
2523 MaskType mask) {
2524 DCHECK_NE(vd, vs2);
2525 GenInstrV(VRGATHER_FUNCT6, OP_IVX, vd, rs1, vs2, mask);
2526 }
2527
2528 #define DEFINE_OPIVV(name, funct6) \
2529 void Assembler::name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \
2530 MaskType mask) { \
2531 GenInstrV(funct6, OP_IVV, vd, vs1, vs2, mask); \
2532 }
2533
2534 #define DEFINE_OPFVV(name, funct6) \
2535 void Assembler::name##_vv(VRegister vd, VRegister vs2, VRegister vs1, \
2536 MaskType mask) { \
2537 GenInstrV(funct6, OP_FVV, vd, vs1, vs2, mask); \
2538 }
2539
2540 #define DEFINE_OPIVX(name, funct6) \
2541 void Assembler::name##_vx(VRegister vd, VRegister vs2, Register rs1, \
2542 MaskType mask) { \
2543 GenInstrV(funct6, OP_IVX, vd, rs1, vs2, mask); \
2544 }
2545
2546 #define DEFINE_OPIVI(name, funct6) \
2547 void Assembler::name##_vi(VRegister vd, VRegister vs2, int8_t imm5, \
2548 MaskType mask) { \
2549 GenInstrV(funct6, vd, imm5, vs2, mask); \
2550 }
2551
2552 #define DEFINE_OPMVV(name, funct6) \
2553 void Assembler::name##_vs(VRegister vd, VRegister vs2, VRegister vs1, \
2554 MaskType mask) { \
2555 GenInstrV(funct6, OP_MVV, vd, vs1, vs2, mask); \
2556 }
2557
2558 #define DEFINE_OPFVF(name, funct6) \
2559 void Assembler::name##_vf(VRegister vd, VRegister vs2, FPURegister fs1, \
2560 MaskType mask) { \
2561 GenInstrV(funct6, OP_FVF, vd, fs1, vs2, mask); \
2562 }
2563
DEFINE_OPIVV(vadd,VADD_FUNCT6)2564 DEFINE_OPIVV(vadd, VADD_FUNCT6)
2565 DEFINE_OPIVX(vadd, VADD_FUNCT6)
2566 DEFINE_OPIVI(vadd, VADD_FUNCT6)
2567 DEFINE_OPIVV(vsub, VSUB_FUNCT6)
2568 DEFINE_OPIVX(vsub, VSUB_FUNCT6)
2569 DEFINE_OPIVX(vsadd, VSADD_FUNCT6)
2570 DEFINE_OPIVV(vsadd, VSADD_FUNCT6)
2571 DEFINE_OPIVI(vsadd, VSADD_FUNCT6)
2572 DEFINE_OPIVX(vsaddu, VSADDU_FUNCT6)
2573 DEFINE_OPIVV(vsaddu, VSADDU_FUNCT6)
2574 DEFINE_OPIVI(vsaddu, VSADDU_FUNCT6)
2575 DEFINE_OPIVX(vssub, VSSUB_FUNCT6)
2576 DEFINE_OPIVV(vssub, VSSUB_FUNCT6)
2577 DEFINE_OPIVX(vssubu, VSSUBU_FUNCT6)
2578 DEFINE_OPIVV(vssubu, VSSUBU_FUNCT6)
2579 DEFINE_OPIVX(vrsub, VRSUB_FUNCT6)
2580 DEFINE_OPIVI(vrsub, VRSUB_FUNCT6)
2581 DEFINE_OPIVV(vminu, VMINU_FUNCT6)
2582 DEFINE_OPIVX(vminu, VMINU_FUNCT6)
2583 DEFINE_OPIVV(vmin, VMIN_FUNCT6)
2584 DEFINE_OPIVX(vmin, VMIN_FUNCT6)
2585 DEFINE_OPIVV(vmaxu, VMAXU_FUNCT6)
2586 DEFINE_OPIVX(vmaxu, VMAXU_FUNCT6)
2587 DEFINE_OPIVV(vmax, VMAX_FUNCT6)
2588 DEFINE_OPIVX(vmax, VMAX_FUNCT6)
2589 DEFINE_OPIVV(vand, VAND_FUNCT6)
2590 DEFINE_OPIVX(vand, VAND_FUNCT6)
2591 DEFINE_OPIVI(vand, VAND_FUNCT6)
2592 DEFINE_OPIVV(vor, VOR_FUNCT6)
2593 DEFINE_OPIVX(vor, VOR_FUNCT6)
2594 DEFINE_OPIVI(vor, VOR_FUNCT6)
2595 DEFINE_OPIVV(vxor, VXOR_FUNCT6)
2596 DEFINE_OPIVX(vxor, VXOR_FUNCT6)
2597 DEFINE_OPIVI(vxor, VXOR_FUNCT6)
2598
2599 DEFINE_OPIVX(vslidedown, VSLIDEDOWN_FUNCT6)
2600 DEFINE_OPIVI(vslidedown, VSLIDEDOWN_FUNCT6)
2601 DEFINE_OPIVX(vslideup, VSLIDEUP_FUNCT6)
2602 DEFINE_OPIVI(vslideup, VSLIDEUP_FUNCT6)
2603
2604 DEFINE_OPIVV(vmseq, VMSEQ_FUNCT6)
2605 DEFINE_OPIVX(vmseq, VMSEQ_FUNCT6)
2606 DEFINE_OPIVI(vmseq, VMSEQ_FUNCT6)
2607
2608 DEFINE_OPIVV(vmsne, VMSNE_FUNCT6)
2609 DEFINE_OPIVX(vmsne, VMSNE_FUNCT6)
2610 DEFINE_OPIVI(vmsne, VMSNE_FUNCT6)
2611
2612 DEFINE_OPIVV(vmsltu, VMSLTU_FUNCT6)
2613 DEFINE_OPIVX(vmsltu, VMSLTU_FUNCT6)
2614
2615 DEFINE_OPIVV(vmslt, VMSLT_FUNCT6)
2616 DEFINE_OPIVX(vmslt, VMSLT_FUNCT6)
2617
2618 DEFINE_OPIVV(vmsle, VMSLE_FUNCT6)
2619 DEFINE_OPIVX(vmsle, VMSLE_FUNCT6)
2620 DEFINE_OPIVI(vmsle, VMSLE_FUNCT6)
2621
2622 DEFINE_OPIVV(vmsleu, VMSLEU_FUNCT6)
2623 DEFINE_OPIVX(vmsleu, VMSLEU_FUNCT6)
2624 DEFINE_OPIVI(vmsleu, VMSLEU_FUNCT6)
2625
2626 DEFINE_OPIVI(vmsgt, VMSGT_FUNCT6)
2627 DEFINE_OPIVX(vmsgt, VMSGT_FUNCT6)
2628
2629 DEFINE_OPIVI(vmsgtu, VMSGTU_FUNCT6)
2630 DEFINE_OPIVX(vmsgtu, VMSGTU_FUNCT6)
2631
2632 DEFINE_OPIVV(vsrl, VSRL_FUNCT6)
2633 DEFINE_OPIVX(vsrl, VSRL_FUNCT6)
2634 DEFINE_OPIVI(vsrl, VSRL_FUNCT6)
2635
2636 DEFINE_OPIVV(vsll, VSLL_FUNCT6)
2637 DEFINE_OPIVX(vsll, VSLL_FUNCT6)
2638 DEFINE_OPIVI(vsll, VSLL_FUNCT6)
2639
2640 DEFINE_OPMVV(vredmaxu, VREDMAXU_FUNCT6)
2641 DEFINE_OPMVV(vredmax, VREDMAX_FUNCT6)
2642 DEFINE_OPMVV(vredmin, VREDMIN_FUNCT6)
2643 DEFINE_OPMVV(vredminu, VREDMINU_FUNCT6)
2644
2645 DEFINE_OPFVV(vfadd, VFADD_FUNCT6)
2646 DEFINE_OPFVF(vfadd, VFADD_FUNCT6)
2647 DEFINE_OPFVV(vfsub, VFSUB_FUNCT6)
2648 DEFINE_OPFVF(vfsub, VFSUB_FUNCT6)
2649 DEFINE_OPFVV(vfdiv, VFDIV_FUNCT6)
2650 DEFINE_OPFVF(vfdiv, VFDIV_FUNCT6)
2651 DEFINE_OPFVV(vfmul, VFMUL_FUNCT6)
2652 DEFINE_OPFVF(vfmul, VFMUL_FUNCT6)
2653 DEFINE_OPFVV(vmfeq, VMFEQ_FUNCT6)
2654 DEFINE_OPFVV(vmfne, VMFNE_FUNCT6)
2655 DEFINE_OPFVV(vmflt, VMFLT_FUNCT6)
2656 DEFINE_OPFVV(vmfle, VMFLE_FUNCT6)
2657 DEFINE_OPFVV(vfmax, VFMAX_FUNCT6)
2658 DEFINE_OPFVV(vfmin, VFMIN_FUNCT6)
2659
2660 DEFINE_OPFVV(vfsngj, VFSGNJ_FUNCT6)
2661 DEFINE_OPFVF(vfsngj, VFSGNJ_FUNCT6)
2662 DEFINE_OPFVV(vfsngjn, VFSGNJN_FUNCT6)
2663 DEFINE_OPFVF(vfsngjn, VFSGNJN_FUNCT6)
2664 DEFINE_OPFVV(vfsngjx, VFSGNJX_FUNCT6)
2665 DEFINE_OPFVF(vfsngjx, VFSGNJX_FUNCT6)
2666 #undef DEFINE_OPIVI
2667 #undef DEFINE_OPIVV
2668 #undef DEFINE_OPIVX
2669 #undef DEFINE_OPFVV
2670 #undef DEFINE_OPFVF
2671
2672 void Assembler::vsetvli(Register rd, Register rs1, VSew vsew, Vlmul vlmul,
2673 TailAgnosticType tail, MaskAgnosticType mask) {
2674 int32_t zimm = GenZimm(vsew, vlmul, tail, mask);
2675 Instr instr = OP_V | ((rd.code() & 0x1F) << kRvvRdShift) | (0x7 << 12) |
2676 ((rs1.code() & 0x1F) << kRvvRs1Shift) |
2677 (((uint32_t)zimm << kRvvZimmShift) & kRvvZimmMask) | 0x0 << 31;
2678 emit(instr);
2679 }
2680
vsetivli(Register rd,uint8_t uimm,VSew vsew,Vlmul vlmul,TailAgnosticType tail,MaskAgnosticType mask)2681 void Assembler::vsetivli(Register rd, uint8_t uimm, VSew vsew, Vlmul vlmul,
2682 TailAgnosticType tail, MaskAgnosticType mask) {
2683 DCHECK(is_uint5(uimm));
2684 int32_t zimm = GenZimm(vsew, vlmul, tail, mask) & 0x3FF;
2685 Instr instr = OP_V | ((rd.code() & 0x1F) << kRvvRdShift) | (0x7 << 12) |
2686 ((uimm & 0x1F) << kRvvUimmShift) |
2687 (((uint32_t)zimm << kRvvZimmShift) & kRvvZimmMask) | 0x3 << 30;
2688 emit(instr);
2689 }
2690
vsetvl(Register rd,Register rs1,Register rs2)2691 void Assembler::vsetvl(Register rd, Register rs1, Register rs2) {
2692 Instr instr = OP_V | ((rd.code() & 0x1F) << kRvvRdShift) | (0x7 << 12) |
2693 ((rs1.code() & 0x1F) << kRvvRs1Shift) |
2694 ((rs2.code() & 0x1F) << kRvvRs2Shift) | 0x40 << 25;
2695 emit(instr);
2696 }
2697
vsew_switch(VSew vsew)2698 uint8_t vsew_switch(VSew vsew) {
2699 uint8_t width;
2700 switch (vsew) {
2701 case E8:
2702 width = 0b000;
2703 break;
2704 case E16:
2705 width = 0b101;
2706 break;
2707 case E32:
2708 width = 0b110;
2709 break;
2710 case E64:
2711 width = 0b111;
2712 break;
2713 case E128:
2714 width = 0b000;
2715 break;
2716 case E256:
2717 width = 0b101;
2718 break;
2719 case E512:
2720 width = 0b110;
2721 break;
2722 case E1024:
2723 width = 0b111;
2724 break;
2725 }
2726 return width;
2727 }
2728
vl(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2729 void Assembler::vl(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2730 MaskType mask) {
2731 bool IsMew = vsew >= E128 ? true : false;
2732 uint8_t width = vsew_switch(vsew);
2733 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b000);
2734 }
vls(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2735 void Assembler::vls(VRegister vd, Register rs1, Register rs2, VSew vsew,
2736 MaskType mask) {
2737 bool IsMew = vsew >= E128 ? true : false;
2738 uint8_t width = vsew_switch(vsew);
2739 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b000);
2740 }
vlx(VRegister vd,Register rs1,VRegister vs2,VSew vsew,MaskType mask)2741 void Assembler::vlx(VRegister vd, Register rs1, VRegister vs2, VSew vsew,
2742 MaskType mask) {
2743 bool IsMew = vsew >= E128 ? true : false;
2744 uint8_t width = vsew_switch(vsew);
2745 GenInstrV(LOAD_FP, width, vd, rs1, vs2, mask, 0b11, IsMew, 0);
2746 }
2747
vs(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2748 void Assembler::vs(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2749 MaskType mask) {
2750 bool IsMew = vsew >= E128 ? true : false;
2751 uint8_t width = vsew_switch(vsew);
2752 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b000);
2753 }
vss(VRegister vs3,Register rs1,Register rs2,VSew vsew,MaskType mask)2754 void Assembler::vss(VRegister vs3, Register rs1, Register rs2, VSew vsew,
2755 MaskType mask) {
2756 bool IsMew = vsew >= E128 ? true : false;
2757 uint8_t width = vsew_switch(vsew);
2758 GenInstrV(STORE_FP, width, vs3, rs1, rs2, mask, 0b10, IsMew, 0b000);
2759 }
2760
vsx(VRegister vd,Register rs1,VRegister vs2,VSew vsew,MaskType mask)2761 void Assembler::vsx(VRegister vd, Register rs1, VRegister vs2, VSew vsew,
2762 MaskType mask) {
2763 bool IsMew = vsew >= E128 ? true : false;
2764 uint8_t width = vsew_switch(vsew);
2765 GenInstrV(STORE_FP, width, vd, rs1, vs2, mask, 0b11, IsMew, 0b000);
2766 }
vsu(VRegister vd,Register rs1,VRegister vs2,VSew vsew,MaskType mask)2767 void Assembler::vsu(VRegister vd, Register rs1, VRegister vs2, VSew vsew,
2768 MaskType mask) {
2769 bool IsMew = vsew >= E128 ? true : false;
2770 uint8_t width = vsew_switch(vsew);
2771 GenInstrV(STORE_FP, width, vd, rs1, vs2, mask, 0b01, IsMew, 0b000);
2772 }
2773
vlseg2(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2774 void Assembler::vlseg2(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2775 MaskType mask) {
2776 bool IsMew = vsew >= E128 ? true : false;
2777 uint8_t width = vsew_switch(vsew);
2778 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b001);
2779 }
2780
vlseg3(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2781 void Assembler::vlseg3(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2782 MaskType mask) {
2783 bool IsMew = vsew >= E128 ? true : false;
2784 uint8_t width = vsew_switch(vsew);
2785 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b010);
2786 }
2787
vlseg4(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2788 void Assembler::vlseg4(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2789 MaskType mask) {
2790 bool IsMew = vsew >= E128 ? true : false;
2791 uint8_t width = vsew_switch(vsew);
2792 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b011);
2793 }
2794
vlseg5(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2795 void Assembler::vlseg5(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2796 MaskType mask) {
2797 bool IsMew = vsew >= E128 ? true : false;
2798 uint8_t width = vsew_switch(vsew);
2799 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b100);
2800 }
2801
vlseg6(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2802 void Assembler::vlseg6(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2803 MaskType mask) {
2804 bool IsMew = vsew >= E128 ? true : false;
2805 uint8_t width = vsew_switch(vsew);
2806 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b101);
2807 }
2808
vlseg7(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2809 void Assembler::vlseg7(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2810 MaskType mask) {
2811 bool IsMew = vsew >= E128 ? true : false;
2812 uint8_t width = vsew_switch(vsew);
2813 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b110);
2814 }
2815
vlseg8(VRegister vd,Register rs1,uint8_t lumop,VSew vsew,MaskType mask)2816 void Assembler::vlseg8(VRegister vd, Register rs1, uint8_t lumop, VSew vsew,
2817 MaskType mask) {
2818 bool IsMew = vsew >= E128 ? true : false;
2819 uint8_t width = vsew_switch(vsew);
2820 GenInstrV(LOAD_FP, width, vd, rs1, lumop, mask, 0b00, IsMew, 0b111);
2821 }
vsseg2(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2822 void Assembler::vsseg2(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2823 MaskType mask) {
2824 bool IsMew = vsew >= E128 ? true : false;
2825 uint8_t width = vsew_switch(vsew);
2826 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b001);
2827 }
vsseg3(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2828 void Assembler::vsseg3(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2829 MaskType mask) {
2830 bool IsMew = vsew >= E128 ? true : false;
2831 uint8_t width = vsew_switch(vsew);
2832 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b010);
2833 }
vsseg4(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2834 void Assembler::vsseg4(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2835 MaskType mask) {
2836 bool IsMew = vsew >= E128 ? true : false;
2837 uint8_t width = vsew_switch(vsew);
2838 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b011);
2839 }
vsseg5(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2840 void Assembler::vsseg5(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2841 MaskType mask) {
2842 bool IsMew = vsew >= E128 ? true : false;
2843 uint8_t width = vsew_switch(vsew);
2844 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b100);
2845 }
vsseg6(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2846 void Assembler::vsseg6(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2847 MaskType mask) {
2848 bool IsMew = vsew >= E128 ? true : false;
2849 uint8_t width = vsew_switch(vsew);
2850 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b101);
2851 }
vsseg7(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2852 void Assembler::vsseg7(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2853 MaskType mask) {
2854 bool IsMew = vsew >= E128 ? true : false;
2855 uint8_t width = vsew_switch(vsew);
2856 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b110);
2857 }
vsseg8(VRegister vd,Register rs1,uint8_t sumop,VSew vsew,MaskType mask)2858 void Assembler::vsseg8(VRegister vd, Register rs1, uint8_t sumop, VSew vsew,
2859 MaskType mask) {
2860 bool IsMew = vsew >= E128 ? true : false;
2861 uint8_t width = vsew_switch(vsew);
2862 GenInstrV(STORE_FP, width, vd, rs1, sumop, mask, 0b00, IsMew, 0b111);
2863 }
2864
vlsseg2(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2865 void Assembler::vlsseg2(VRegister vd, Register rs1, Register rs2, VSew vsew,
2866 MaskType mask) {
2867 bool IsMew = vsew >= E128 ? true : false;
2868 uint8_t width = vsew_switch(vsew);
2869 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b001);
2870 }
vlsseg3(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2871 void Assembler::vlsseg3(VRegister vd, Register rs1, Register rs2, VSew vsew,
2872 MaskType mask) {
2873 bool IsMew = vsew >= E128 ? true : false;
2874 uint8_t width = vsew_switch(vsew);
2875 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b010);
2876 }
vlsseg4(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2877 void Assembler::vlsseg4(VRegister vd, Register rs1, Register rs2, VSew vsew,
2878 MaskType mask) {
2879 bool IsMew = vsew >= E128 ? true : false;
2880 uint8_t width = vsew_switch(vsew);
2881 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b011);
2882 }
vlsseg5(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2883 void Assembler::vlsseg5(VRegister vd, Register rs1, Register rs2, VSew vsew,
2884 MaskType mask) {
2885 bool IsMew = vsew >= E128 ? true : false;
2886 uint8_t width = vsew_switch(vsew);
2887 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b100);
2888 }
vlsseg6(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2889 void Assembler::vlsseg6(VRegister vd, Register rs1, Register rs2, VSew vsew,
2890 MaskType mask) {
2891 bool IsMew = vsew >= E128 ? true : false;
2892 uint8_t width = vsew_switch(vsew);
2893 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b101);
2894 }
vlsseg7(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2895 void Assembler::vlsseg7(VRegister vd, Register rs1, Register rs2, VSew vsew,
2896 MaskType mask) {
2897 bool IsMew = vsew >= E128 ? true : false;
2898 uint8_t width = vsew_switch(vsew);
2899 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b110);
2900 }
vlsseg8(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2901 void Assembler::vlsseg8(VRegister vd, Register rs1, Register rs2, VSew vsew,
2902 MaskType mask) {
2903 bool IsMew = vsew >= E128 ? true : false;
2904 uint8_t width = vsew_switch(vsew);
2905 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b111);
2906 }
vssseg2(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2907 void Assembler::vssseg2(VRegister vd, Register rs1, Register rs2, VSew vsew,
2908 MaskType mask) {
2909 bool IsMew = vsew >= E128 ? true : false;
2910 uint8_t width = vsew_switch(vsew);
2911 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b001);
2912 }
vssseg3(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2913 void Assembler::vssseg3(VRegister vd, Register rs1, Register rs2, VSew vsew,
2914 MaskType mask) {
2915 bool IsMew = vsew >= E128 ? true : false;
2916 uint8_t width = vsew_switch(vsew);
2917 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b010);
2918 }
vssseg4(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2919 void Assembler::vssseg4(VRegister vd, Register rs1, Register rs2, VSew vsew,
2920 MaskType mask) {
2921 bool IsMew = vsew >= E128 ? true : false;
2922 uint8_t width = vsew_switch(vsew);
2923 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b011);
2924 }
vssseg5(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2925 void Assembler::vssseg5(VRegister vd, Register rs1, Register rs2, VSew vsew,
2926 MaskType mask) {
2927 bool IsMew = vsew >= E128 ? true : false;
2928 uint8_t width = vsew_switch(vsew);
2929 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b100);
2930 }
vssseg6(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2931 void Assembler::vssseg6(VRegister vd, Register rs1, Register rs2, VSew vsew,
2932 MaskType mask) {
2933 bool IsMew = vsew >= E128 ? true : false;
2934 uint8_t width = vsew_switch(vsew);
2935 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b101);
2936 }
vssseg7(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2937 void Assembler::vssseg7(VRegister vd, Register rs1, Register rs2, VSew vsew,
2938 MaskType mask) {
2939 bool IsMew = vsew >= E128 ? true : false;
2940 uint8_t width = vsew_switch(vsew);
2941 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b110);
2942 }
vssseg8(VRegister vd,Register rs1,Register rs2,VSew vsew,MaskType mask)2943 void Assembler::vssseg8(VRegister vd, Register rs1, Register rs2, VSew vsew,
2944 MaskType mask) {
2945 bool IsMew = vsew >= E128 ? true : false;
2946 uint8_t width = vsew_switch(vsew);
2947 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b10, IsMew, 0b111);
2948 }
2949
vlxseg2(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2950 void Assembler::vlxseg2(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2951 MaskType mask) {
2952 bool IsMew = vsew >= E128 ? true : false;
2953 uint8_t width = vsew_switch(vsew);
2954 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b001);
2955 }
vlxseg3(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2956 void Assembler::vlxseg3(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2957 MaskType mask) {
2958 bool IsMew = vsew >= E128 ? true : false;
2959 uint8_t width = vsew_switch(vsew);
2960 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b010);
2961 }
vlxseg4(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2962 void Assembler::vlxseg4(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2963 MaskType mask) {
2964 bool IsMew = vsew >= E128 ? true : false;
2965 uint8_t width = vsew_switch(vsew);
2966 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b011);
2967 }
vlxseg5(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2968 void Assembler::vlxseg5(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2969 MaskType mask) {
2970 bool IsMew = vsew >= E128 ? true : false;
2971 uint8_t width = vsew_switch(vsew);
2972 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b100);
2973 }
vlxseg6(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2974 void Assembler::vlxseg6(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2975 MaskType mask) {
2976 bool IsMew = vsew >= E128 ? true : false;
2977 uint8_t width = vsew_switch(vsew);
2978 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b101);
2979 }
vlxseg7(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2980 void Assembler::vlxseg7(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2981 MaskType mask) {
2982 bool IsMew = vsew >= E128 ? true : false;
2983 uint8_t width = vsew_switch(vsew);
2984 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b110);
2985 }
vlxseg8(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2986 void Assembler::vlxseg8(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2987 MaskType mask) {
2988 bool IsMew = vsew >= E128 ? true : false;
2989 uint8_t width = vsew_switch(vsew);
2990 GenInstrV(LOAD_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b111);
2991 }
vsxseg2(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2992 void Assembler::vsxseg2(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2993 MaskType mask) {
2994 bool IsMew = vsew >= E128 ? true : false;
2995 uint8_t width = vsew_switch(vsew);
2996 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b001);
2997 }
vsxseg3(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)2998 void Assembler::vsxseg3(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
2999 MaskType mask) {
3000 bool IsMew = vsew >= E128 ? true : false;
3001 uint8_t width = vsew_switch(vsew);
3002 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b010);
3003 }
vsxseg4(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)3004 void Assembler::vsxseg4(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
3005 MaskType mask) {
3006 bool IsMew = vsew >= E128 ? true : false;
3007 uint8_t width = vsew_switch(vsew);
3008 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b011);
3009 }
vsxseg5(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)3010 void Assembler::vsxseg5(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
3011 MaskType mask) {
3012 bool IsMew = vsew >= E128 ? true : false;
3013 uint8_t width = vsew_switch(vsew);
3014 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b100);
3015 }
vsxseg6(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)3016 void Assembler::vsxseg6(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
3017 MaskType mask) {
3018 bool IsMew = vsew >= E128 ? true : false;
3019 uint8_t width = vsew_switch(vsew);
3020 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b101);
3021 }
vsxseg7(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)3022 void Assembler::vsxseg7(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
3023 MaskType mask) {
3024 bool IsMew = vsew >= E128 ? true : false;
3025 uint8_t width = vsew_switch(vsew);
3026 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b110);
3027 }
vsxseg8(VRegister vd,Register rs1,VRegister rs2,VSew vsew,MaskType mask)3028 void Assembler::vsxseg8(VRegister vd, Register rs1, VRegister rs2, VSew vsew,
3029 MaskType mask) {
3030 bool IsMew = vsew >= E128 ? true : false;
3031 uint8_t width = vsew_switch(vsew);
3032 GenInstrV(STORE_FP, width, vd, rs1, rs2, mask, 0b11, IsMew, 0b111);
3033 }
3034
3035 // Privileged
uret()3036 void Assembler::uret() {
3037 GenInstrPriv(0b0000000, ToRegister(0), ToRegister(0b00010));
3038 }
3039
sret()3040 void Assembler::sret() {
3041 GenInstrPriv(0b0001000, ToRegister(0), ToRegister(0b00010));
3042 }
3043
mret()3044 void Assembler::mret() {
3045 GenInstrPriv(0b0011000, ToRegister(0), ToRegister(0b00010));
3046 }
3047
wfi()3048 void Assembler::wfi() {
3049 GenInstrPriv(0b0001000, ToRegister(0), ToRegister(0b00101));
3050 }
3051
sfence_vma(Register rs1,Register rs2)3052 void Assembler::sfence_vma(Register rs1, Register rs2) {
3053 GenInstrR(0b0001001, 0b000, SYSTEM, ToRegister(0), rs1, rs2);
3054 }
3055
3056 // Assembler Pseudo Instructions (Tables 25.2 and 25.3, RISC-V Unprivileged ISA)
3057
nop()3058 void Assembler::nop() { addi(ToRegister(0), ToRegister(0), 0); }
3059
RV_li(Register rd,int64_t imm)3060 void Assembler::RV_li(Register rd, int64_t imm) {
3061 // 64-bit imm is put in the register rd.
3062 // In most cases the imm is 32 bit and 2 instructions are generated. If a
3063 // temporary register is available, in the worst case, 6 instructions are
3064 // generated for a full 64-bit immediate. If temporay register is not
3065 // available the maximum will be 8 instructions. If imm is more than 32 bits
3066 // and a temp register is available, imm is divided into two 32-bit parts,
3067 // low_32 and up_32. Each part is built in a separate register. low_32 is
3068 // built before up_32. If low_32 is negative (upper 32 bits are 1), 0xffffffff
3069 // is subtracted from up_32 before up_32 is built. This compensates for 32
3070 // bits of 1's in the lower when the two registers are added. If no temp is
3071 // available, the upper 32 bit is built in rd, and the lower 32 bits are
3072 // devided to 3 parts (11, 11, and 10 bits). The parts are shifted and added
3073 // to the upper part built in rd.
3074 if (is_int32(imm + 0x800)) {
3075 // 32-bit case. Maximum of 2 instructions generated
3076 int64_t high_20 = ((imm + 0x800) >> 12);
3077 int64_t low_12 = imm << 52 >> 52;
3078 if (high_20) {
3079 lui(rd, (int32_t)high_20);
3080 if (low_12) {
3081 addi(rd, rd, low_12);
3082 }
3083 } else {
3084 addi(rd, zero_reg, low_12);
3085 }
3086 return;
3087 } else {
3088 // 64-bit case: divide imm into two 32-bit parts, upper and lower
3089 int64_t up_32 = imm >> 32;
3090 int64_t low_32 = imm & 0xffffffffull;
3091 Register temp_reg = rd;
3092 // Check if a temporary register is available
3093 if (up_32 == 0 || low_32 == 0) {
3094 // No temp register is needed
3095 } else {
3096 UseScratchRegisterScope temps(this);
3097 BlockTrampolinePoolScope block_trampoline_pool(this);
3098 temp_reg = temps.hasAvailable() ? temps.Acquire() : no_reg;
3099 }
3100 if (temp_reg != no_reg) {
3101 // keep track of hardware behavior for lower part in sim_low
3102 int64_t sim_low = 0;
3103 // Build lower part
3104 if (low_32 != 0) {
3105 int64_t high_20 = ((low_32 + 0x800) >> 12);
3106 int64_t low_12 = low_32 & 0xfff;
3107 if (high_20) {
3108 // Adjust to 20 bits for the case of overflow
3109 high_20 &= 0xfffff;
3110 sim_low = ((high_20 << 12) << 32) >> 32;
3111 lui(rd, (int32_t)high_20);
3112 if (low_12) {
3113 sim_low += (low_12 << 52 >> 52) | low_12;
3114 addi(rd, rd, low_12);
3115 }
3116 } else {
3117 sim_low = low_12;
3118 ori(rd, zero_reg, low_12);
3119 }
3120 }
3121 if (sim_low & 0x100000000) {
3122 // Bit 31 is 1. Either an overflow or a negative 64 bit
3123 if (up_32 == 0) {
3124 // Positive number, but overflow because of the add 0x800
3125 slli(rd, rd, 32);
3126 srli(rd, rd, 32);
3127 return;
3128 }
3129 // low_32 is a negative 64 bit after the build
3130 up_32 = (up_32 - 0xffffffff) & 0xffffffff;
3131 }
3132 if (up_32 == 0) {
3133 return;
3134 }
3135 // Build upper part in a temporary register
3136 if (low_32 == 0) {
3137 // Build upper part in rd
3138 temp_reg = rd;
3139 }
3140 int64_t high_20 = (up_32 + 0x800) >> 12;
3141 int64_t low_12 = up_32 & 0xfff;
3142 if (high_20) {
3143 // Adjust to 20 bits for the case of overflow
3144 high_20 &= 0xfffff;
3145 lui(temp_reg, (int32_t)high_20);
3146 if (low_12) {
3147 addi(temp_reg, temp_reg, low_12);
3148 }
3149 } else {
3150 ori(temp_reg, zero_reg, low_12);
3151 }
3152 // Put it at the bgining of register
3153 slli(temp_reg, temp_reg, 32);
3154 if (low_32 != 0) {
3155 add(rd, rd, temp_reg);
3156 }
3157 return;
3158 }
3159 // No temp register. Build imm in rd.
3160 // Build upper 32 bits first in rd. Divide lower 32 bits parts and add
3161 // parts to the upper part by doing shift and add.
3162 // First build upper part in rd.
3163 int64_t high_20 = (up_32 + 0x800) >> 12;
3164 int64_t low_12 = up_32 & 0xfff;
3165 if (high_20) {
3166 // Adjust to 20 bits for the case of overflow
3167 high_20 &= 0xfffff;
3168 lui(rd, (int32_t)high_20);
3169 if (low_12) {
3170 addi(rd, rd, low_12);
3171 }
3172 } else {
3173 ori(rd, zero_reg, low_12);
3174 }
3175 // upper part already in rd. Each part to be added to rd, has maximum of 11
3176 // bits, and always starts with a 1. rd is shifted by the size of the part
3177 // plus the number of zeros between the parts. Each part is added after the
3178 // left shift.
3179 uint32_t mask = 0x80000000;
3180 int32_t shift_val = 0;
3181 int32_t i;
3182 for (i = 0; i < 32; i++) {
3183 if ((low_32 & mask) == 0) {
3184 mask >>= 1;
3185 shift_val++;
3186 if (i == 31) {
3187 // rest is zero
3188 slli(rd, rd, shift_val);
3189 }
3190 continue;
3191 }
3192 // The first 1 seen
3193 int32_t part;
3194 if ((i + 11) < 32) {
3195 // Pick 11 bits
3196 part = ((uint32_t)(low_32 << i) >> i) >> (32 - (i + 11));
3197 slli(rd, rd, shift_val + 11);
3198 ori(rd, rd, part);
3199 i += 10;
3200 mask >>= 11;
3201 } else {
3202 part = (uint32_t)(low_32 << i) >> i;
3203 slli(rd, rd, shift_val + (32 - i));
3204 ori(rd, rd, part);
3205 break;
3206 }
3207 shift_val = 0;
3208 }
3209 }
3210 }
3211
li_estimate(int64_t imm,bool is_get_temp_reg)3212 int Assembler::li_estimate(int64_t imm, bool is_get_temp_reg) {
3213 int count = 0;
3214 // imitate Assembler::RV_li
3215 if (is_int32(imm + 0x800)) {
3216 // 32-bit case. Maximum of 2 instructions generated
3217 int64_t high_20 = ((imm + 0x800) >> 12);
3218 int64_t low_12 = imm << 52 >> 52;
3219 if (high_20) {
3220 count++;
3221 if (low_12) {
3222 count++;
3223 }
3224 } else {
3225 count++;
3226 }
3227 return count;
3228 } else {
3229 // 64-bit case: divide imm into two 32-bit parts, upper and lower
3230 int64_t up_32 = imm >> 32;
3231 int64_t low_32 = imm & 0xffffffffull;
3232 // Check if a temporary register is available
3233 if (is_get_temp_reg) {
3234 // keep track of hardware behavior for lower part in sim_low
3235 int64_t sim_low = 0;
3236 // Build lower part
3237 if (low_32 != 0) {
3238 int64_t high_20 = ((low_32 + 0x800) >> 12);
3239 int64_t low_12 = low_32 & 0xfff;
3240 if (high_20) {
3241 // Adjust to 20 bits for the case of overflow
3242 high_20 &= 0xfffff;
3243 sim_low = ((high_20 << 12) << 32) >> 32;
3244 count++;
3245 if (low_12) {
3246 sim_low += (low_12 << 52 >> 52) | low_12;
3247 count++;
3248 }
3249 } else {
3250 sim_low = low_12;
3251 count++;
3252 }
3253 }
3254 if (sim_low & 0x100000000) {
3255 // Bit 31 is 1. Either an overflow or a negative 64 bit
3256 if (up_32 == 0) {
3257 // Positive number, but overflow because of the add 0x800
3258 count++;
3259 count++;
3260 return count;
3261 }
3262 // low_32 is a negative 64 bit after the build
3263 up_32 = (up_32 - 0xffffffff) & 0xffffffff;
3264 }
3265 if (up_32 == 0) {
3266 return count;
3267 }
3268 int64_t high_20 = (up_32 + 0x800) >> 12;
3269 int64_t low_12 = up_32 & 0xfff;
3270 if (high_20) {
3271 // Adjust to 20 bits for the case of overflow
3272 high_20 &= 0xfffff;
3273 count++;
3274 if (low_12) {
3275 count++;
3276 }
3277 } else {
3278 count++;
3279 }
3280 // Put it at the bgining of register
3281 count++;
3282 if (low_32 != 0) {
3283 count++;
3284 }
3285 return count;
3286 }
3287 // No temp register. Build imm in rd.
3288 // Build upper 32 bits first in rd. Divide lower 32 bits parts and add
3289 // parts to the upper part by doing shift and add.
3290 // First build upper part in rd.
3291 int64_t high_20 = (up_32 + 0x800) >> 12;
3292 int64_t low_12 = up_32 & 0xfff;
3293 if (high_20) {
3294 // Adjust to 20 bits for the case of overflow
3295 high_20 &= 0xfffff;
3296 count++;
3297 if (low_12) {
3298 count++;
3299 }
3300 } else {
3301 count++;
3302 }
3303 // upper part already in rd. Each part to be added to rd, has maximum of 11
3304 // bits, and always starts with a 1. rd is shifted by the size of the part
3305 // plus the number of zeros between the parts. Each part is added after the
3306 // left shift.
3307 uint32_t mask = 0x80000000;
3308 int32_t shift_val = 0;
3309 int32_t i;
3310 for (i = 0; i < 32; i++) {
3311 if ((low_32 & mask) == 0) {
3312 mask >>= 1;
3313 shift_val++;
3314 if (i == 31) {
3315 // rest is zero
3316 count++;
3317 }
3318 continue;
3319 }
3320 // The first 1 seen
3321 int32_t part;
3322 if ((i + 11) < 32) {
3323 // Pick 11 bits
3324 part = ((uint32_t)(low_32 << i) >> i) >> (32 - (i + 11));
3325 count++;
3326 count++;
3327 i += 10;
3328 mask >>= 11;
3329 } else {
3330 part = (uint32_t)(low_32 << i) >> i;
3331 count++;
3332 count++;
3333 break;
3334 }
3335 shift_val = 0;
3336 }
3337 }
3338 return count;
3339 }
3340
li_ptr(Register rd,int64_t imm)3341 void Assembler::li_ptr(Register rd, int64_t imm) {
3342 // Initialize rd with an address
3343 // Pointers are 48 bits
3344 // 6 fixed instructions are generated
3345 DCHECK_EQ((imm & 0xfff0000000000000ll), 0);
3346 int64_t a6 = imm & 0x3f; // bits 0:5. 6 bits
3347 int64_t b11 = (imm >> 6) & 0x7ff; // bits 6:11. 11 bits
3348 int64_t high_31 = (imm >> 17) & 0x7fffffff; // 31 bits
3349 int64_t high_20 = ((high_31 + 0x800) >> 12); // 19 bits
3350 int64_t low_12 = high_31 & 0xfff; // 12 bits
3351 lui(rd, (int32_t)high_20);
3352 addi(rd, rd, low_12); // 31 bits in rd.
3353 slli(rd, rd, 11); // Space for next 11 bis
3354 ori(rd, rd, b11); // 11 bits are put in. 42 bit in rd
3355 slli(rd, rd, 6); // Space for next 6 bits
3356 ori(rd, rd, a6); // 6 bits are put in. 48 bis in rd
3357 }
3358
li_constant(Register rd,int64_t imm)3359 void Assembler::li_constant(Register rd, int64_t imm) {
3360 DEBUG_PRINTF("li_constant(%d, %lx <%ld>)\n", ToNumber(rd), imm, imm);
3361 lui(rd, (imm + (1LL << 47) + (1LL << 35) + (1LL << 23) + (1LL << 11)) >>
3362 48); // Bits 63:48
3363 addiw(rd, rd,
3364 (imm + (1LL << 35) + (1LL << 23) + (1LL << 11)) << 16 >>
3365 52); // Bits 47:36
3366 slli(rd, rd, 12);
3367 addi(rd, rd, (imm + (1LL << 23) + (1LL << 11)) << 28 >> 52); // Bits 35:24
3368 slli(rd, rd, 12);
3369 addi(rd, rd, (imm + (1LL << 11)) << 40 >> 52); // Bits 23:12
3370 slli(rd, rd, 12);
3371 addi(rd, rd, imm << 52 >> 52); // Bits 11:0
3372 }
3373
3374 // Break / Trap instructions.
break_(uint32_t code,bool break_as_stop)3375 void Assembler::break_(uint32_t code, bool break_as_stop) {
3376 // We need to invalidate breaks that could be stops as well because the
3377 // simulator expects a char pointer after the stop instruction.
3378 // See constants-mips.h for explanation.
3379 DCHECK(
3380 (break_as_stop && code <= kMaxStopCode && code > kMaxWatchpointCode) ||
3381 (!break_as_stop && (code > kMaxStopCode || code <= kMaxWatchpointCode)));
3382
3383 // since ebreak does not allow additional immediate field, we use the
3384 // immediate field of lui instruction immediately following the ebreak to
3385 // encode the "code" info
3386 ebreak();
3387 DCHECK(is_uint20(code));
3388 lui(zero_reg, code);
3389 }
3390
stop(uint32_t code)3391 void Assembler::stop(uint32_t code) {
3392 DCHECK_GT(code, kMaxWatchpointCode);
3393 DCHECK_LE(code, kMaxStopCode);
3394 #if defined(V8_HOST_ARCH_RISCV64)
3395 break_(0x54321);
3396 #else // V8_HOST_ARCH_RISCV64
3397 break_(code, true);
3398 #endif
3399 }
3400
3401 // Original MIPS Instructions
3402
3403 // ------------Memory-instructions-------------
3404
NeedAdjustBaseAndOffset(const MemOperand & src,OffsetAccessType access_type,int second_access_add_to_offset)3405 bool Assembler::NeedAdjustBaseAndOffset(const MemOperand& src,
3406 OffsetAccessType access_type,
3407 int second_access_add_to_offset) {
3408 bool two_accesses = static_cast<bool>(access_type);
3409 DCHECK_LE(second_access_add_to_offset, 7); // Must be <= 7.
3410
3411 // is_int12 must be passed a signed value, hence the static cast below.
3412 if (is_int12(src.offset()) &&
3413 (!two_accesses || is_int12(static_cast<int32_t>(
3414 src.offset() + second_access_add_to_offset)))) {
3415 // Nothing to do: 'offset' (and, if needed, 'offset + 4', or other specified
3416 // value) fits into int12.
3417 return false;
3418 }
3419 return true;
3420 }
3421
AdjustBaseAndOffset(MemOperand * src,Register scratch,OffsetAccessType access_type,int second_Access_add_to_offset)3422 void Assembler::AdjustBaseAndOffset(MemOperand* src, Register scratch,
3423 OffsetAccessType access_type,
3424 int second_Access_add_to_offset) {
3425 // This method is used to adjust the base register and offset pair
3426 // for a load/store when the offset doesn't fit into int12.
3427
3428 // Must not overwrite the register 'base' while loading 'offset'.
3429 constexpr int32_t kMinOffsetForSimpleAdjustment = 0x7F8;
3430 constexpr int32_t kMaxOffsetForSimpleAdjustment =
3431 2 * kMinOffsetForSimpleAdjustment;
3432 if (0 <= src->offset() && src->offset() <= kMaxOffsetForSimpleAdjustment) {
3433 addi(scratch, src->rm(), kMinOffsetForSimpleAdjustment);
3434 src->offset_ -= kMinOffsetForSimpleAdjustment;
3435 } else if (-kMaxOffsetForSimpleAdjustment <= src->offset() &&
3436 src->offset() < 0) {
3437 addi(scratch, src->rm(), -kMinOffsetForSimpleAdjustment);
3438 src->offset_ += kMinOffsetForSimpleAdjustment;
3439 } else if (access_type == OffsetAccessType::SINGLE_ACCESS) {
3440 RV_li(scratch, (static_cast<int64_t>(src->offset()) + 0x800) >> 12 << 12);
3441 add(scratch, scratch, src->rm());
3442 src->offset_ = src->offset() << 20 >> 20;
3443 } else {
3444 RV_li(scratch, src->offset());
3445 add(scratch, scratch, src->rm());
3446 src->offset_ = 0;
3447 }
3448 src->rm_ = scratch;
3449 }
3450
RelocateInternalReference(RelocInfo::Mode rmode,Address pc,intptr_t pc_delta)3451 int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, Address pc,
3452 intptr_t pc_delta) {
3453 if (RelocInfo::IsInternalReference(rmode)) {
3454 int64_t* p = reinterpret_cast<int64_t*>(pc);
3455 if (*p == kEndOfJumpChain) {
3456 return 0; // Number of instructions patched.
3457 }
3458 *p += pc_delta;
3459 return 2; // Number of instructions patched.
3460 }
3461 Instr instr = instr_at(pc);
3462 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
3463 if (IsLui(instr)) {
3464 uint64_t target_address = target_address_at(pc) + pc_delta;
3465 DEBUG_PRINTF("target_address 0x%lx\n", target_address);
3466 set_target_value_at(pc, target_address);
3467 return 8; // Number of instructions patched.
3468 } else {
3469 UNIMPLEMENTED();
3470 }
3471 }
3472
RelocateRelativeReference(RelocInfo::Mode rmode,Address pc,intptr_t pc_delta)3473 void Assembler::RelocateRelativeReference(RelocInfo::Mode rmode, Address pc,
3474 intptr_t pc_delta) {
3475 Instr instr = instr_at(pc);
3476 Instr instr1 = instr_at(pc + 1 * kInstrSize);
3477 DCHECK(RelocInfo::IsRelativeCodeTarget(rmode));
3478 if (IsAuipc(instr) && IsJalr(instr1)) {
3479 int32_t imm;
3480 imm = BrachlongOffset(instr, instr1);
3481 imm -= pc_delta;
3482 PatchBranchlongOffset(pc, instr, instr1, imm);
3483 return;
3484 } else {
3485 UNREACHABLE();
3486 }
3487 }
3488
FixOnHeapReferences(bool update_embedded_objects)3489 void Assembler::FixOnHeapReferences(bool update_embedded_objects) {
3490 if (!update_embedded_objects) return;
3491 for (auto p : saved_handles_for_raw_object_ptr_) {
3492 Address address = reinterpret_cast<Address>(buffer_->start() + p.first);
3493 Handle<HeapObject> object(reinterpret_cast<Address*>(p.second));
3494 set_target_value_at(address, object->ptr());
3495 }
3496 }
3497
FixOnHeapReferencesToHandles()3498 void Assembler::FixOnHeapReferencesToHandles() {
3499 for (auto p : saved_handles_for_raw_object_ptr_) {
3500 Address address = reinterpret_cast<Address>(buffer_->start() + p.first);
3501 set_target_value_at(address, p.second);
3502 }
3503 saved_handles_for_raw_object_ptr_.clear();
3504 }
3505
GrowBuffer()3506 void Assembler::GrowBuffer() {
3507 DEBUG_PRINTF("GrowBuffer: %p -> ", buffer_start_);
3508 bool previously_on_heap = buffer_->IsOnHeap();
3509 int previous_on_heap_gc_count = OnHeapGCCount();
3510
3511 // Compute new buffer size.
3512 int old_size = buffer_->size();
3513 int new_size = std::min(2 * old_size, old_size + 1 * MB);
3514
3515 // Some internal data structures overflow for very large buffers,
3516 // they must ensure that kMaximalBufferSize is not too large.
3517 if (new_size > kMaximalBufferSize) {
3518 V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
3519 }
3520
3521 // Set up new buffer.
3522 std::unique_ptr<AssemblerBuffer> new_buffer = buffer_->Grow(new_size);
3523 DCHECK_EQ(new_size, new_buffer->size());
3524 byte* new_start = new_buffer->start();
3525
3526 // Copy the data.
3527 intptr_t pc_delta = new_start - buffer_start_;
3528 intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size);
3529 size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos();
3530 MemMove(new_start, buffer_start_, pc_offset());
3531 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
3532 reloc_size);
3533
3534 // Switch buffers.
3535 buffer_ = std::move(new_buffer);
3536 buffer_start_ = new_start;
3537 DEBUG_PRINTF("%p\n", buffer_start_);
3538 pc_ += pc_delta;
3539 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3540 reloc_info_writer.last_pc() + pc_delta);
3541
3542 // Relocate runtime entries.
3543 base::Vector<byte> instructions{buffer_start_,
3544 static_cast<size_t>(pc_offset())};
3545 base::Vector<const byte> reloc_info{reloc_info_writer.pos(), reloc_size};
3546 for (RelocIterator it(instructions, reloc_info, 0); !it.done(); it.next()) {
3547 RelocInfo::Mode rmode = it.rinfo()->rmode();
3548 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
3549 RelocateInternalReference(rmode, it.rinfo()->pc(), pc_delta);
3550 }
3551 }
3552
3553 // Fix on-heap references.
3554 if (previously_on_heap) {
3555 if (buffer_->IsOnHeap()) {
3556 FixOnHeapReferences(previous_on_heap_gc_count != OnHeapGCCount());
3557 } else {
3558 FixOnHeapReferencesToHandles();
3559 }
3560 }
3561
3562 DCHECK(!overflow());
3563 }
3564
db(uint8_t data)3565 void Assembler::db(uint8_t data) {
3566 if (!is_buffer_growth_blocked()) CheckBuffer();
3567 DEBUG_PRINTF("%p: constant 0x%x\n", pc_, data);
3568 EmitHelper(data);
3569 }
3570
dd(uint32_t data,RelocInfo::Mode rmode)3571 void Assembler::dd(uint32_t data, RelocInfo::Mode rmode) {
3572 if (!RelocInfo::IsNone(rmode)) {
3573 DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) ||
3574 RelocInfo::IsLiteralConstant(rmode));
3575 RecordRelocInfo(rmode);
3576 }
3577 if (!is_buffer_growth_blocked()) CheckBuffer();
3578 DEBUG_PRINTF("%p: constant 0x%x\n", pc_, data);
3579 EmitHelper(data);
3580 }
3581
dq(uint64_t data,RelocInfo::Mode rmode)3582 void Assembler::dq(uint64_t data, RelocInfo::Mode rmode) {
3583 if (!RelocInfo::IsNone(rmode)) {
3584 DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) ||
3585 RelocInfo::IsLiteralConstant(rmode));
3586 RecordRelocInfo(rmode);
3587 }
3588 if (!is_buffer_growth_blocked()) CheckBuffer();
3589 DEBUG_PRINTF("%p: constant 0x%lx\n", pc_, data);
3590 EmitHelper(data);
3591 }
3592
dd(Label * label)3593 void Assembler::dd(Label* label) {
3594 uint64_t data;
3595 if (!is_buffer_growth_blocked()) CheckBuffer();
3596 if (label->is_bound()) {
3597 data = reinterpret_cast<uint64_t>(buffer_start_ + label->pos());
3598 } else {
3599 data = jump_address(label);
3600 internal_reference_positions_.insert(label->pos());
3601 }
3602 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3603 EmitHelper(data);
3604 }
3605
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)3606 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
3607 if (!ShouldRecordRelocInfo(rmode)) return;
3608 // We do not try to reuse pool constants.
3609 RelocInfo rinfo(reinterpret_cast<Address>(pc_), rmode, data, Code());
3610 DCHECK_GE(buffer_space(), kMaxRelocSize); // Too late to grow buffer here.
3611 reloc_info_writer.Write(&rinfo);
3612 }
3613
BlockTrampolinePoolFor(int instructions)3614 void Assembler::BlockTrampolinePoolFor(int instructions) {
3615 DEBUG_PRINTF("\tBlockTrampolinePoolFor %d", instructions);
3616 CheckTrampolinePoolQuick(instructions);
3617 DEBUG_PRINTF("\tpc_offset %d,BlockTrampolinePoolBefore %d\n", pc_offset(),
3618 pc_offset() + instructions * kInstrSize);
3619 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3620 }
3621
CheckTrampolinePool()3622 void Assembler::CheckTrampolinePool() {
3623 // Some small sequences of instructions must not be broken up by the
3624 // insertion of a trampoline pool; such sequences are protected by setting
3625 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3626 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3627 // are blocked by trampoline_pool_blocked_nesting_.
3628 DEBUG_PRINTF("\tpc_offset %d no_trampoline_pool_before:%d\n", pc_offset(),
3629 no_trampoline_pool_before_);
3630 DEBUG_PRINTF("\ttrampoline_pool_blocked_nesting:%d\n",
3631 trampoline_pool_blocked_nesting_);
3632 if ((trampoline_pool_blocked_nesting_ > 0) ||
3633 (pc_offset() < no_trampoline_pool_before_)) {
3634 // Emission is currently blocked; make sure we try again as soon as
3635 // possible.
3636 if (trampoline_pool_blocked_nesting_ > 0) {
3637 next_buffer_check_ = pc_offset() + kInstrSize;
3638 } else {
3639 next_buffer_check_ = no_trampoline_pool_before_;
3640 }
3641 return;
3642 }
3643
3644 DCHECK(!trampoline_emitted_);
3645 DCHECK_GE(unbound_labels_count_, 0);
3646 if (unbound_labels_count_ > 0) {
3647 // First we emit jump, then we emit trampoline pool.
3648 {
3649 DEBUG_PRINTF("inserting trampoline pool at %p (%d)\n",
3650 reinterpret_cast<Instr*>(buffer_start_ + pc_offset()),
3651 pc_offset());
3652 BlockTrampolinePoolScope block_trampoline_pool(this);
3653 Label after_pool;
3654 j(&after_pool);
3655
3656 int pool_start = pc_offset();
3657 for (int i = 0; i < unbound_labels_count_; i++) {
3658 int64_t imm64;
3659 imm64 = branch_long_offset(&after_pool);
3660 CHECK(is_int32(imm64 + 0x800));
3661 int32_t Hi20 = (((int32_t)imm64 + 0x800) >> 12);
3662 int32_t Lo12 = (int32_t)imm64 << 20 >> 20;
3663 auipc(t6, Hi20); // Read PC + Hi20 into t6
3664 jr(t6, Lo12); // jump PC + Hi20 + Lo12
3665 }
3666 // If unbound_labels_count_ is big enough, label after_pool will
3667 // need a trampoline too, so we must create the trampoline before
3668 // the bind operation to make sure function 'bind' can get this
3669 // information.
3670 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3671 bind(&after_pool);
3672
3673 trampoline_emitted_ = true;
3674 // As we are only going to emit trampoline once, we need to prevent any
3675 // further emission.
3676 next_buffer_check_ = kMaxInt;
3677 }
3678 } else {
3679 // Number of branches to unbound label at this point is zero, so we can
3680 // move next buffer check to maximum.
3681 next_buffer_check_ =
3682 pc_offset() + kMaxBranchOffset - kTrampolineSlotsSize * 16;
3683 }
3684 return;
3685 }
3686
set_target_address_at(Address pc,Address constant_pool,Address target,ICacheFlushMode icache_flush_mode)3687 void Assembler::set_target_address_at(Address pc, Address constant_pool,
3688 Address target,
3689 ICacheFlushMode icache_flush_mode) {
3690 Instr* instr = reinterpret_cast<Instr*>(pc);
3691 if (IsAuipc(*instr)) {
3692 if (IsLd(*reinterpret_cast<Instr*>(pc + 4))) {
3693 int32_t Hi20 = AuipcOffset(*instr);
3694 int32_t Lo12 = LdOffset(*reinterpret_cast<Instr*>(pc + 4));
3695 Memory<Address>(pc + Hi20 + Lo12) = target;
3696 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
3697 FlushInstructionCache(pc + Hi20 + Lo12, 2 * kInstrSize);
3698 }
3699 } else {
3700 DCHECK(IsJalr(*reinterpret_cast<Instr*>(pc + 4)));
3701 int64_t imm = (int64_t)target - (int64_t)pc;
3702 Instr instr = instr_at(pc);
3703 Instr instr1 = instr_at(pc + 1 * kInstrSize);
3704 DCHECK(is_int32(imm + 0x800));
3705 int num = PatchBranchlongOffset(pc, instr, instr1, (int32_t)imm);
3706 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
3707 FlushInstructionCache(pc, num * kInstrSize);
3708 }
3709 }
3710 } else {
3711 set_target_address_at(pc, target, icache_flush_mode);
3712 }
3713 }
3714
target_address_at(Address pc,Address constant_pool)3715 Address Assembler::target_address_at(Address pc, Address constant_pool) {
3716 Instr* instr = reinterpret_cast<Instr*>(pc);
3717 if (IsAuipc(*instr)) {
3718 if (IsLd(*reinterpret_cast<Instr*>(pc + 4))) {
3719 int32_t Hi20 = AuipcOffset(*instr);
3720 int32_t Lo12 = LdOffset(*reinterpret_cast<Instr*>(pc + 4));
3721 return Memory<Address>(pc + Hi20 + Lo12);
3722 } else {
3723 DCHECK(IsJalr(*reinterpret_cast<Instr*>(pc + 4)));
3724 int32_t Hi20 = AuipcOffset(*instr);
3725 int32_t Lo12 = JalrOffset(*reinterpret_cast<Instr*>(pc + 4));
3726 return pc + Hi20 + Lo12;
3727 }
3728
3729 } else {
3730 return target_address_at(pc);
3731 }
3732 }
target_address_at(Address pc)3733 Address Assembler::target_address_at(Address pc) {
3734 DEBUG_PRINTF("target_address_at: pc: %lx\t", pc);
3735 Instruction* instr0 = Instruction::At((unsigned char*)pc);
3736 Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize));
3737 Instruction* instr2 = Instruction::At((unsigned char*)(pc + 2 * kInstrSize));
3738 Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize));
3739 Instruction* instr4 = Instruction::At((unsigned char*)(pc + 4 * kInstrSize));
3740 Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize));
3741
3742 // Interpret instructions for address generated by li: See listing in
3743 // Assembler::set_target_address_at() just below.
3744 if (IsLui(*reinterpret_cast<Instr*>(instr0)) &&
3745 IsAddi(*reinterpret_cast<Instr*>(instr1)) &&
3746 IsSlli(*reinterpret_cast<Instr*>(instr2)) &&
3747 IsOri(*reinterpret_cast<Instr*>(instr3)) &&
3748 IsSlli(*reinterpret_cast<Instr*>(instr4)) &&
3749 IsOri(*reinterpret_cast<Instr*>(instr5))) {
3750 // Assemble the 64 bit value.
3751 int64_t addr = (int64_t)(instr0->Imm20UValue() << kImm20Shift) +
3752 (int64_t)instr1->Imm12Value();
3753 addr <<= 11;
3754 addr |= (int64_t)instr3->Imm12Value();
3755 addr <<= 6;
3756 addr |= (int64_t)instr5->Imm12Value();
3757
3758 DEBUG_PRINTF("addr: %lx\n", addr);
3759 return static_cast<Address>(addr);
3760 }
3761 // We should never get here, force a bad address if we do.
3762 UNREACHABLE();
3763 }
3764 // On RISC-V, a 48-bit target address is stored in an 6-instruction sequence:
3765 // lui(reg, (int32_t)high_20); // 19 high bits
3766 // addi(reg, reg, low_12); // 12 following bits. total is 31 high bits in reg.
3767 // slli(reg, reg, 11); // Space for next 11 bits
3768 // ori(reg, reg, b11); // 11 bits are put in. 42 bit in reg
3769 // slli(reg, reg, 6); // Space for next 6 bits
3770 // ori(reg, reg, a6); // 6 bits are put in. all 48 bis in reg
3771 //
3772 // Patching the address must replace all instructions, and flush the i-cache.
3773 // Note that this assumes the use of SV48, the 48-bit virtual memory system.
set_target_value_at(Address pc,uint64_t target,ICacheFlushMode icache_flush_mode)3774 void Assembler::set_target_value_at(Address pc, uint64_t target,
3775 ICacheFlushMode icache_flush_mode) {
3776 DEBUG_PRINTF("set_target_value_at: pc: %lx\ttarget: %lx\n", pc, target);
3777 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3778 DCHECK_EQ((target & 0xffff000000000000ll), 0);
3779 #ifdef DEBUG
3780 // Check we have the result from a li macro-instruction.
3781 Instruction* instr0 = Instruction::At((unsigned char*)pc);
3782 Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize));
3783 Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize));
3784 Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize));
3785 DCHECK(IsLui(*reinterpret_cast<Instr*>(instr0)) &&
3786 IsAddi(*reinterpret_cast<Instr*>(instr1)) &&
3787 IsOri(*reinterpret_cast<Instr*>(instr3)) &&
3788 IsOri(*reinterpret_cast<Instr*>(instr5)));
3789 #endif
3790 int64_t a6 = target & 0x3f; // bits 0:6. 6 bits
3791 int64_t b11 = (target >> 6) & 0x7ff; // bits 6:11. 11 bits
3792 int64_t high_31 = (target >> 17) & 0x7fffffff; // 31 bits
3793 int64_t high_20 = ((high_31 + 0x800) >> 12); // 19 bits
3794 int64_t low_12 = high_31 & 0xfff; // 12 bits
3795 *p = *p & 0xfff;
3796 *p = *p | ((int32_t)high_20 << 12);
3797 *(p + 1) = *(p + 1) & 0xfffff;
3798 *(p + 1) = *(p + 1) | ((int32_t)low_12 << 20);
3799 *(p + 2) = *(p + 2) & 0xfffff;
3800 *(p + 2) = *(p + 2) | (11 << 20);
3801 *(p + 3) = *(p + 3) & 0xfffff;
3802 *(p + 3) = *(p + 3) | ((int32_t)b11 << 20);
3803 *(p + 4) = *(p + 4) & 0xfffff;
3804 *(p + 4) = *(p + 4) | (6 << 20);
3805 *(p + 5) = *(p + 5) & 0xfffff;
3806 *(p + 5) = *(p + 5) | ((int32_t)a6 << 20);
3807 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
3808 FlushInstructionCache(pc, 8 * kInstrSize);
3809 }
3810 DCHECK_EQ(target_address_at(pc), target);
3811 }
UseScratchRegisterScope(Assembler * assembler)3812 UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)
3813 : available_(assembler->GetScratchRegisterList()),
3814 old_available_(*available_) {}
3815
~UseScratchRegisterScope()3816 UseScratchRegisterScope::~UseScratchRegisterScope() {
3817 *available_ = old_available_;
3818 }
3819
Acquire()3820 Register UseScratchRegisterScope::Acquire() {
3821 DCHECK_NOT_NULL(available_);
3822 DCHECK_NE(*available_, 0);
3823 int index = static_cast<int>(base::bits::CountTrailingZeros32(*available_));
3824 *available_ &= ~(1UL << index);
3825
3826 return Register::from_code(index);
3827 }
3828
hasAvailable() const3829 bool UseScratchRegisterScope::hasAvailable() const { return *available_ != 0; }
3830
IsConstantPoolAt(Instruction * instr)3831 bool Assembler::IsConstantPoolAt(Instruction* instr) {
3832 // The constant pool marker is made of two instructions. These instructions
3833 // will never be emitted by the JIT, so checking for the first one is enough:
3834 // 0: ld x0, x0, #offset
3835 Instr instr_value = *reinterpret_cast<Instr*>(instr);
3836 bool result = IsLd(instr_value) && (instr->Rs1Value() == kRegCode_zero_reg) &&
3837 (instr->RdValue() == kRegCode_zero_reg);
3838 #ifdef DEBUG
3839 // It is still worth asserting the marker is complete.
3840 // 1: j 0x0
3841 Instruction* instr_following = instr + kInstrSize;
3842 DCHECK(!result || (IsJal(*reinterpret_cast<Instr*>(instr_following)) &&
3843 instr_following->Imm20JValue() == 0 &&
3844 instr_following->RdValue() == kRegCode_zero_reg));
3845 #endif
3846 return result;
3847 }
3848
ConstantPoolSizeAt(Instruction * instr)3849 int Assembler::ConstantPoolSizeAt(Instruction* instr) {
3850 if (IsConstantPoolAt(instr)) {
3851 return instr->Imm12Value();
3852 } else {
3853 return -1;
3854 }
3855 }
3856
RecordConstPool(int size)3857 void Assembler::RecordConstPool(int size) {
3858 // We only need this for debugger support, to correctly compute offsets in the
3859 // code.
3860 Assembler::BlockPoolsScope block_pools(this);
3861 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3862 }
3863
EmitPoolGuard()3864 void Assembler::EmitPoolGuard() {
3865 // We must generate only one instruction as this is used in scopes that
3866 // control the size of the code generated.
3867 j(0);
3868 }
3869
3870 // Constant Pool
3871
EmitPrologue(Alignment require_alignment)3872 void ConstantPool::EmitPrologue(Alignment require_alignment) {
3873 // Recorded constant pool size is expressed in number of 32-bits words,
3874 // and includes prologue and alignment, but not the jump around the pool
3875 // and the size of the marker itself.
3876 const int marker_size = 1;
3877 int word_count =
3878 ComputeSize(Jump::kOmitted, require_alignment) / kInt32Size - marker_size;
3879 assm_->ld(zero_reg, zero_reg, word_count);
3880 assm_->EmitPoolGuard();
3881 }
3882
PrologueSize(Jump require_jump) const3883 int ConstantPool::PrologueSize(Jump require_jump) const {
3884 // Prologue is:
3885 // j over ;; if require_jump
3886 // ld x0, x0, #pool_size
3887 // j 0x0
3888 int prologue_size = require_jump == Jump::kRequired ? kInstrSize : 0;
3889 prologue_size += 2 * kInstrSize;
3890 return prologue_size;
3891 }
3892
SetLoadOffsetToConstPoolEntry(int load_offset,Instruction * entry_offset,const ConstantPoolKey & key)3893 void ConstantPool::SetLoadOffsetToConstPoolEntry(int load_offset,
3894 Instruction* entry_offset,
3895 const ConstantPoolKey& key) {
3896 Instr instr_auipc = assm_->instr_at(load_offset);
3897 Instr instr_ld = assm_->instr_at(load_offset + 4);
3898 // Instruction to patch must be 'ld rd, offset(rd)' with 'offset == 0'.
3899 DCHECK(assm_->IsAuipc(instr_auipc));
3900 DCHECK(assm_->IsLd(instr_ld));
3901 DCHECK_EQ(assm_->LdOffset(instr_ld), 0);
3902 DCHECK_EQ(assm_->AuipcOffset(instr_auipc), 0);
3903 int32_t distance = static_cast<int32_t>(
3904 reinterpret_cast<Address>(entry_offset) -
3905 reinterpret_cast<Address>(assm_->toAddress(load_offset)));
3906 CHECK(is_int32(distance + 0x800));
3907 int32_t Hi20 = (((int32_t)distance + 0x800) >> 12);
3908 int32_t Lo12 = (int32_t)distance << 20 >> 20;
3909 assm_->instr_at_put(load_offset, SetAuipcOffset(Hi20, instr_auipc));
3910 assm_->instr_at_put(load_offset + 4, SetLdOffset(Lo12, instr_ld));
3911 }
3912
Check(Emission force_emit,Jump require_jump,size_t margin)3913 void ConstantPool::Check(Emission force_emit, Jump require_jump,
3914 size_t margin) {
3915 // Some short sequence of instruction must not be broken up by constant pool
3916 // emission, such sequences are protected by a ConstPool::BlockScope.
3917 if (IsBlocked()) {
3918 // Something is wrong if emission is forced and blocked at the same time.
3919 DCHECK_EQ(force_emit, Emission::kIfNeeded);
3920 return;
3921 }
3922
3923 // We emit a constant pool only if :
3924 // * it is not empty
3925 // * emission is forced by parameter force_emit (e.g. at function end).
3926 // * emission is mandatory or opportune according to {ShouldEmitNow}.
3927 if (!IsEmpty() && (force_emit == Emission::kForced ||
3928 ShouldEmitNow(require_jump, margin))) {
3929 // Emit veneers for branches that would go out of range during emission of
3930 // the constant pool.
3931 int worst_case_size = ComputeSize(Jump::kRequired, Alignment::kRequired);
3932
3933 // Check that the code buffer is large enough before emitting the constant
3934 // pool (this includes the gap to the relocation information).
3935 int needed_space = worst_case_size + assm_->kGap;
3936 while (assm_->buffer_space() <= needed_space) {
3937 assm_->GrowBuffer();
3938 }
3939
3940 EmitAndClear(require_jump);
3941 }
3942 // Since a constant pool is (now) empty, move the check offset forward by
3943 // the standard interval.
3944 SetNextCheckIn(ConstantPool::kCheckInterval);
3945 }
3946
3947 // Pool entries are accessed with pc relative load therefore this cannot be more
3948 // than 1 * MB. Since constant pool emission checks are interval based, and we
3949 // want to keep entries close to the code, we try to emit every 64KB.
3950 const size_t ConstantPool::kMaxDistToPool32 = 1 * MB;
3951 const size_t ConstantPool::kMaxDistToPool64 = 1 * MB;
3952 const size_t ConstantPool::kCheckInterval = 128 * kInstrSize;
3953 const size_t ConstantPool::kApproxDistToPool32 = 64 * KB;
3954 const size_t ConstantPool::kApproxDistToPool64 = kApproxDistToPool32;
3955
3956 const size_t ConstantPool::kOpportunityDistToPool32 = 64 * KB;
3957 const size_t ConstantPool::kOpportunityDistToPool64 = 64 * KB;
3958 const size_t ConstantPool::kApproxMaxEntryCount = 512;
3959
3960 } // namespace internal
3961 } // namespace v8
3962
3963 #endif // V8_TARGET_ARCH_RISCV64
3964