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