v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-generator-riscv.cc
Go to the documentation of this file.
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
15#include "src/compiler/osr.h"
17
18#if V8_ENABLE_WEBASSEMBLY
21#endif // V8_ENABLE_WEBASSEMBLY
22
23namespace v8 {
24namespace internal {
25namespace compiler {
26
27#define __ masm()->
28
29#define TRACE(...) PrintF(__VA_ARGS__)
30
31// Adds RISC-V-specific methods to convert InstructionOperands.
33 public:
36
38 return ToSingleRegister(instr_->OutputAt(index));
39 }
40
42 return ToSingleRegister(instr_->InputAt(index));
43 }
44
46 // Single (Float) and Double register namespace is same on RISC-V,
47 // both are typedefs of FPURegister.
48 return ToDoubleRegister(op);
49 }
50
52 if (instr_->InputAt(index)->IsImmediate()) {
53 Constant constant = ToConstant(instr_->InputAt(index));
54 switch (constant.type()) {
57 DCHECK_EQ(0, InputInt32(index));
58 break;
61 break;
64 break;
65 default:
67 }
68 return zero_reg;
69 }
70 return InputRegister(index);
71 }
72
74 if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
75
76 return InputDoubleRegister(index);
77 }
78
80 if (instr_->InputAt(index)->IsImmediate()) return kSingleRegZero;
81
82 return InputSingleRegister(index);
83 }
84
85 Operand InputImmediate(size_t index) {
86 Constant constant = ToConstant(instr_->InputAt(index));
87 switch (constant.type()) {
89 return Operand(constant.ToInt32());
91 return Operand(constant.ToInt64());
93 return Operand::EmbeddedNumber(constant.ToFloat32());
95 return Operand::EmbeddedNumber(constant.ToFloat64().value());
97 RootIndex root_index;
98 if (gen_->isolate()->roots_table().IsRootHandle(constant.ToHeapObject(),
99 &root_index)) {
102 Tagged_t ptr =
104 return Operand(ptr);
105 }
106 return Operand(constant.ToHeapObject());
107 }
110 // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
111 // maybe not done on arm due to const pool ??
112 break;
114 UNREACHABLE(); // TODO(titzer): RPO immediates
115 }
116 UNREACHABLE();
117 }
118
119 Operand InputOperand(size_t index) {
120 InstructionOperand* op = instr_->InputAt(index);
121 if (op->IsRegister()) {
122 return Operand(ToRegister(op));
123 }
124 return InputImmediate(index);
125 }
126
127 MemOperand MemoryOperand(size_t* first_index) {
128 const size_t index = *first_index;
130 case kMode_None:
131 break;
132 case kMode_MRI:
133 *first_index += 2;
134 return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
135 case kMode_Root:
136 return MemOperand(kRootRegister, InputInt32(index));
137 case kMode_MRR:
138 // TODO(plind): r6 address mode, to be implemented ...
139 UNREACHABLE();
140 }
141 UNREACHABLE();
142 }
143
144 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
145
151
152 MemOperand SlotToMemOperand(int slot) const {
154 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
155 }
156};
157
158static inline bool HasRegisterInput(Instruction* instr, size_t index) {
159 return instr->InputAt(index)->IsRegister();
160}
161namespace {
162
163class OutOfLineRecordWrite final : public OutOfLineCode {
164 public:
165 OutOfLineRecordWrite(
166 CodeGenerator* gen, Register object, Operand offset, Register value,
167 RecordWriteMode mode, StubCallMode stub_mode,
168 IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag)
169 : OutOfLineCode(gen),
170 object_(object),
172 value_(value),
173 mode_(mode),
174#if V8_ENABLE_WEBASSEMBLY
175 stub_mode_(stub_mode),
176#endif // V8_ENABLE_WEBASSEMBLY
177 must_save_lr_(!gen->frame_access_state()->has_frame()),
178 zone_(gen->zone()),
179 indirect_pointer_tag_(indirect_pointer_tag) {
180 }
181
182 void Generate() final {
183#ifdef V8_TARGET_ARCH_RISCV64
184 // When storing an indirect pointer, the value will always be a
185 // full/decompressed pointer.
188 __ DecompressTagged(value_, value_);
189 }
190#endif
192 exit());
193
194 SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
197 if (must_save_lr_) {
198 // We need to save and restore ra if the frame was elided.
199 __ Push(ra);
200 }
202 __ CallEphemeronKeyBarrier(object_, offset_, save_fp_mode);
203 } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) {
205 __ CallIndirectPointerBarrier(object_, offset_, save_fp_mode,
207#if V8_ENABLE_WEBASSEMBLY
208 } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
209 // A direct call to a wasm runtime stub defined in this module.
210 // Just encode the stub index. This will be patched when the code
211 // is added to the native module and copied into wasm code space.
212 __ CallRecordWriteStubSaveRegisters(object_, offset_, save_fp_mode,
213 StubCallMode::kCallWasmRuntimeStub);
214#endif // V8_ENABLE_WEBASSEMBLY
215 } else {
216 __ CallRecordWriteStubSaveRegisters(object_, offset_, save_fp_mode);
217 }
218 if (must_save_lr_) {
219 __ Pop(ra);
220 }
221 }
222
223 private:
224 Register const object_;
225 Operand const offset_;
226 Register const value_;
228#if V8_ENABLE_WEBASSEMBLY
229 StubCallMode const stub_mode_;
230#endif // V8_ENABLE_WEBASSEMBLY
234};
235
236Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
237 switch (condition) {
238 case kEqual:
239 return eq;
240 case kNotEqual:
241 return ne;
242 case kSignedLessThan:
243 return lt;
245 return ge;
247 return le;
249 return gt;
251 return Uless;
253 return Ugreater_equal;
255 return Uless_equal;
257 return Ugreater;
258 case kUnorderedEqual:
260 break;
261 default:
262 break;
263 }
264 UNREACHABLE();
265}
266
267Condition FlagsConditionToConditionTst(FlagsCondition condition) {
268 switch (condition) {
269 case kNotEqual:
270 return ne;
271 case kEqual:
272 return eq;
273 default:
274 break;
275 }
276 UNREACHABLE();
277}
278#if V8_TARGET_ARCH_RISCV64
279Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
280 switch (condition) {
281 case kOverflow:
282 return ne;
283 case kNotOverflow:
284 return eq;
285 default:
286 break;
287 }
288 UNREACHABLE();
289}
290#endif
291
292FPUCondition FlagsConditionToConditionCmpFPU(bool* predicate,
294 switch (condition) {
295 case kEqual:
296 *predicate = true;
297 return EQ;
298 case kNotEqual:
299 *predicate = false;
300 return EQ;
302 case kFloatLessThan:
303 *predicate = true;
304 return LT;
306 *predicate = false;
307 return LT;
310 *predicate = true;
311 return LE;
313 *predicate = false;
314 return LE;
315 case kUnorderedEqual:
317 *predicate = true;
318 break;
320 *predicate = true;
321 return GT;
323 *predicate = true;
324 return GE;
326 *predicate = true;
327 return LT;
329 *predicate = false;
330 return LE;
332 *predicate = false;
333 return LT;
335 *predicate = true;
336 return LE;
337 default:
338 *predicate = true;
339 break;
340 }
341 UNREACHABLE();
342}
343
344#if V8_ENABLE_WEBASSEMBLY
345class WasmOutOfLineTrap : public OutOfLineCode {
346 public:
347 WasmOutOfLineTrap(CodeGenerator* gen, Instruction* instr)
348 : OutOfLineCode(gen), gen_(gen), instr_(instr) {}
349 void Generate() override {
350 RiscvOperandConverter i(gen_, instr_);
351 TrapId trap_id =
352 static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
353 GenerateCallToTrap(trap_id);
354 }
355
356 protected:
357 CodeGenerator* gen_;
358
359 void GenerateWithTrapId(TrapId trap_id) { GenerateCallToTrap(trap_id); }
360
361 private:
362 void GenerateCallToTrap(TrapId trap_id) {
363 gen_->AssembleSourcePosition(instr_);
364 // A direct call to a wasm runtime stub defined in this module.
365 // Just encode the stub index. This will be patched when the code
366 // is added to the native module and copied into wasm code space.
367 __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
368 ReferenceMap* reference_map = gen_->zone()->New<ReferenceMap>(gen_->zone());
369 gen_->RecordSafepoint(reference_map);
370 __ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap);
371 }
372
373 Instruction* instr_;
374};
375
376void RecordTrapInfoIfNeeded(Zone* zone, CodeGenerator* codegen,
377 InstructionCode opcode, Instruction* instr,
378 int pc) {
379 const MemoryAccessMode access_mode = AccessModeField::decode(opcode);
380 if (access_mode == kMemoryAccessProtectedMemOutOfBounds ||
382 codegen->RecordProtectedInstruction(pc);
383 }
384}
385#else
386void RecordTrapInfoIfNeeded(Zone* zone, CodeGenerator* codegen,
387 InstructionCode opcode, Instruction* instr,
388 int pc) {
390}
391#endif // V8_ENABLE_WEBASSEMBLY
392} // namespace
393
394#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \
395 do { \
396 __ asm_instr(i.OutputRegister(), i.MemoryOperand(), trapper); \
397 __ sync(); \
398 } while (0)
399
400#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
401 do { \
402 __ sync(); \
403 __ asm_instr(i.InputOrZeroRegister(0), i.MemoryOperand(1), trapper); \
404 __ sync(); \
405 } while (0)
406
407#define ASSEMBLE_ATOMIC_BINOP(load_linked, store_conditional, bin_instr) \
408 do { \
409 Label binop; \
410 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
411 __ sync(); \
412 __ bind(&binop); \
413 __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0), \
414 trapper); \
415 __ bin_instr(i.TempRegister(1), i.OutputRegister(0), \
416 Operand(i.InputRegister(2))); \
417 __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
418 __ BranchShort(&binop, ne, i.TempRegister(1), Operand(zero_reg)); \
419 __ sync(); \
420 } while (0)
421
422#define ASSEMBLE_ATOMIC64_LOGIC_BINOP(bin_instr, external) \
423 do { \
424 FrameScope scope(masm(), StackFrame::MANUAL); \
425 __ AddWord(a0, i.InputRegister(0), i.InputRegister(1)); \
426 __ PushCallerSaved(SaveFPRegsMode::kIgnore, a0, a1); \
427 __ PrepareCallCFunction(3, 0, kScratchReg); \
428 __ CallCFunction(ExternalReference::external(), 3, 0); \
429 __ PopCallerSaved(SaveFPRegsMode::kIgnore, a0, a1); \
430 } while (0)
431
432#define ASSEMBLE_ATOMIC64_ARITH_BINOP(bin_instr, external) \
433 do { \
434 FrameScope scope(masm(), StackFrame::MANUAL); \
435 __ AddWord(a0, i.InputRegister(0), i.InputRegister(1)); \
436 __ PushCallerSaved(SaveFPRegsMode::kIgnore, a0, a1); \
437 __ PrepareCallCFunction(3, 0, kScratchReg); \
438 __ CallCFunction(ExternalReference::external(), 3, 0); \
439 __ PopCallerSaved(SaveFPRegsMode::kIgnore, a0, a1); \
440 } while (0)
441
442#define ASSEMBLE_ATOMIC_BINOP_EXT(load_linked, store_conditional, sign_extend, \
443 size, bin_instr, representation) \
444 do { \
445 Label binop; \
446 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
447 if (representation == 32) { \
448 __ And(i.TempRegister(3), i.TempRegister(0), 0x3); \
449 } else { \
450 DCHECK_EQ(representation, 64); \
451 __ And(i.TempRegister(3), i.TempRegister(0), 0x7); \
452 } \
453 __ SubWord(i.TempRegister(0), i.TempRegister(0), \
454 Operand(i.TempRegister(3))); \
455 __ Sll32(i.TempRegister(3), i.TempRegister(3), 3); \
456 __ sync(); \
457 __ bind(&binop); \
458 __ load_linked(i.TempRegister(1), MemOperand(i.TempRegister(0), 0), \
459 trapper); \
460 __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3), \
461 size, sign_extend); \
462 __ bin_instr(i.TempRegister(2), i.OutputRegister(0), \
463 Operand(i.InputRegister(2))); \
464 __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3), \
465 size); \
466 __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
467 __ BranchShort(&binop, ne, i.TempRegister(1), Operand(zero_reg)); \
468 __ sync(); \
469 } while (0)
470
471#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_linked, store_conditional) \
472 do { \
473 Label exchange; \
474 __ sync(); \
475 __ bind(&exchange); \
476 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
477 __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0), \
478 trapper); \
479 __ Move(i.TempRegister(1), i.InputRegister(2)); \
480 __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
481 __ BranchShort(&exchange, ne, i.TempRegister(1), Operand(zero_reg)); \
482 __ sync(); \
483 } while (0)
484
485#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT( \
486 load_linked, store_conditional, sign_extend, size, representation) \
487 do { \
488 Label exchange; \
489 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
490 if (representation == 32) { \
491 __ And(i.TempRegister(1), i.TempRegister(0), 0x3); \
492 } else { \
493 DCHECK_EQ(representation, 64); \
494 __ And(i.TempRegister(1), i.TempRegister(0), 0x7); \
495 } \
496 __ SubWord(i.TempRegister(0), i.TempRegister(0), \
497 Operand(i.TempRegister(1))); \
498 __ Sll32(i.TempRegister(1), i.TempRegister(1), 3); \
499 __ sync(); \
500 __ bind(&exchange); \
501 __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0), \
502 trapper); \
503 __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \
504 size, sign_extend); \
505 __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1), \
506 size); \
507 __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
508 __ BranchShort(&exchange, ne, i.TempRegister(2), Operand(zero_reg)); \
509 __ sync(); \
510 } while (0)
511
512#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_linked, \
513 store_conditional) \
514 do { \
515 Label compareExchange; \
516 Label exit; \
517 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
518 __ sync(); \
519 __ bind(&compareExchange); \
520 __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0), \
521 trapper); \
522 __ BranchShort(&exit, ne, i.InputRegister(2), \
523 Operand(i.OutputRegister(0))); \
524 __ Move(i.TempRegister(2), i.InputRegister(3)); \
525 __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
526 __ BranchShort(&compareExchange, ne, i.TempRegister(2), \
527 Operand(zero_reg)); \
528 __ bind(&exit); \
529 __ sync(); \
530 } while (0)
531
532#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT( \
533 load_linked, store_conditional, sign_extend, size, representation) \
534 do { \
535 Label compareExchange; \
536 Label exit; \
537 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
538 if (representation == 32) { \
539 __ And(i.TempRegister(1), i.TempRegister(0), 0x3); \
540 } else { \
541 DCHECK_EQ(representation, 64); \
542 __ And(i.TempRegister(1), i.TempRegister(0), 0x7); \
543 } \
544 __ SubWord(i.TempRegister(0), i.TempRegister(0), \
545 Operand(i.TempRegister(1))); \
546 __ Sll32(i.TempRegister(1), i.TempRegister(1), 3); \
547 __ sync(); \
548 __ bind(&compareExchange); \
549 __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0), \
550 trapper); \
551 __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \
552 size, sign_extend); \
553 __ ExtractBits(i.InputRegister(2), i.InputRegister(2), 0, size, \
554 sign_extend); \
555 __ BranchShort(&exit, ne, i.InputRegister(2), \
556 Operand(i.OutputRegister(0))); \
557 __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1), \
558 size); \
559 __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
560 __ BranchShort(&compareExchange, ne, i.TempRegister(2), \
561 Operand(zero_reg)); \
562 __ bind(&exit); \
563 __ sync(); \
564 } while (0)
565
566#define ASSEMBLE_IEEE754_BINOP(name) \
567 do { \
568 FrameScope scope(masm(), StackFrame::MANUAL); \
569 __ PrepareCallCFunction(0, 2, kScratchReg); \
570 __ MovToFloatParameters(i.InputDoubleRegister(0), \
571 i.InputDoubleRegister(1)); \
572 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
573 /* Move the result in the double result register. */ \
574 __ MovFromFloatResult(i.OutputDoubleRegister()); \
575 } while (0)
576
577#define ASSEMBLE_IEEE754_UNOP(name) \
578 do { \
579 FrameScope scope(masm(), StackFrame::MANUAL); \
580 __ PrepareCallCFunction(0, 1, kScratchReg); \
581 __ MovToFloatParameter(i.InputDoubleRegister(0)); \
582 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
583 /* Move the result in the double result register. */ \
584 __ MovFromFloatResult(i.OutputDoubleRegister()); \
585 } while (0)
586
587#define ASSEMBLE_F64X2_ARITHMETIC_BINOP(op) \
588 do { \
589 __ op(i.OutputSimd128Register(), i.InputSimd128Register(0), \
590 i.InputSimd128Register(1)); \
591 } while (0)
592
593#define ASSEMBLE_RVV_BINOP_INTEGER(instr, OP) \
594 case kRiscvI8x16##instr: { \
595 __ VU.set(kScratchReg, E8, m1); \
596 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0), \
597 i.InputSimd128Register(1)); \
598 break; \
599 } \
600 case kRiscvI16x8##instr: { \
601 __ VU.set(kScratchReg, E16, m1); \
602 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0), \
603 i.InputSimd128Register(1)); \
604 break; \
605 } \
606 case kRiscvI32x4##instr: { \
607 __ VU.set(kScratchReg, E32, m1); \
608 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0), \
609 i.InputSimd128Register(1)); \
610 break; \
611 }
612
613#define ASSEMBLE_RVV_UNOP_INTEGER_VR(instr, OP) \
614 case kRiscvI8x16##instr: { \
615 __ VU.set(kScratchReg, E8, m1); \
616 __ OP(i.OutputSimd128Register(), i.InputRegister(0)); \
617 break; \
618 } \
619 case kRiscvI16x8##instr: { \
620 __ VU.set(kScratchReg, E16, m1); \
621 __ OP(i.OutputSimd128Register(), i.InputRegister(0)); \
622 break; \
623 } \
624 case kRiscvI32x4##instr: { \
625 __ VU.set(kScratchReg, E32, m1); \
626 __ OP(i.OutputSimd128Register(), i.InputRegister(0)); \
627 break; \
628 }
629
630#define ASSEMBLE_RVV_UNOP_INTEGER_VV(instr, OP) \
631 case kRiscvI8x16##instr: { \
632 __ VU.set(kScratchReg, E8, m1); \
633 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0)); \
634 break; \
635 } \
636 case kRiscvI16x8##instr: { \
637 __ VU.set(kScratchReg, E16, m1); \
638 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0)); \
639 break; \
640 } \
641 case kRiscvI32x4##instr: { \
642 __ VU.set(kScratchReg, E32, m1); \
643 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0)); \
644 break; \
645 } \
646 case kRiscvI64x2##instr: { \
647 __ VU.set(kScratchReg, E64, m1); \
648 __ OP(i.OutputSimd128Register(), i.InputSimd128Register(0)); \
649 break; \
650 }
651
653 __ Move(sp, fp);
654 __ Pop(ra, fp);
655}
656
658 if (frame_access_state()->has_frame()) {
661 }
663}
664
668}
669
670namespace {
671
672void AdjustStackPointerForTailCall(MacroAssembler* masm,
673 FrameAccessState* state,
674 int new_slot_above_sp,
675 bool allow_shrinkage = true) {
676 int current_sp_offset = state->GetSPToFPSlotCount() +
678 int stack_slot_delta = new_slot_above_sp - current_sp_offset;
679 if (stack_slot_delta > 0) {
680 masm->SubWord(sp, sp, stack_slot_delta * kSystemPointerSize);
681 state->IncreaseSPDelta(stack_slot_delta);
682 } else if (allow_shrinkage && stack_slot_delta < 0) {
683 masm->AddWord(sp, sp, -stack_slot_delta * kSystemPointerSize);
684 state->IncreaseSPDelta(stack_slot_delta);
685 }
686}
687
688} // namespace
689
691 int first_unused_slot_offset) {
692 AdjustStackPointerForTailCall(masm(), frame_access_state(),
693 first_unused_slot_offset, false);
694}
695
697 int first_unused_slot_offset) {
698 AdjustStackPointerForTailCall(masm(), frame_access_state(),
699 first_unused_slot_offset);
700}
701
702// Check that {kJavaScriptCallCodeStartRegister} is correct.
704 __ ComputeCodeStartAddress(kScratchReg);
705 __ Assert(eq, AbortReason::kWrongFunctionCodeStart,
707}
708
709#ifdef V8_ENABLE_LEAPTIERING
710// Check that {kJavaScriptCallDispatchHandleRegister} is correct.
711void CodeGenerator::AssembleDispatchHandleRegisterCheck() {
712#ifdef V8_TARGET_ARCH_RISCV32
714#else
715 DCHECK(linkage()->GetIncomingDescriptor()->IsJSFunctionCall());
716
718
719 // We currently don't check this for JS builtins as those are sometimes
720 // called directly (e.g. from other builtins) and not through the dispatch
721 // table. This is fine as builtin functions don't use the dispatch handle,
722 // but we could enable this check in the future if we make sure to pass the
723 // kInvalidDispatchHandle whenever we do a direct call to a JS builtin.
725 return;
726 }
727
728 // For now, we only ensure that the register references a valid dispatch
729 // entry with the correct parameter count. In the future, we may also be able
730 // to check that the entry points back to this code.
731 UseScratchRegisterScope temps(masm());
732 Register actual_parameter_count = temps.Acquire();
733 {
734 UseScratchRegisterScope temps(masm());
735 Register scratch = temps.Acquire();
736 __ LoadParameterCountFromJSDispatchTable(
737 actual_parameter_count, kJavaScriptCallDispatchHandleRegister, scratch);
738 }
739 __ Assert(eq, AbortReason::kWrongFunctionDispatchHandle,
740 actual_parameter_count, Operand(parameter_count_));
741#endif
742}
743#endif // V8_ENABLE_LEAPTIERING
744
745// Check if the code object is marked for deoptimization. If it is, then it
746// jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
747// to:
748// 1. read from memory the word that contains that bit, which can be found in
749// the flags in the referenced {Code} object;
750// 2. test kMarkedForDeoptimizationBit in those flags; and
751// 3. if it is not zero then it jumps to the builtin.
753
754// Assembles an instruction after register allocation, producing machine code.
756 Instruction* instr) {
757 RiscvOperandConverter i(this, instr);
758 InstructionCode opcode = instr->opcode();
759 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
760 auto trapper = [this, opcode, instr](int offset) {
761 RecordTrapInfoIfNeeded(zone(), this, opcode, instr, offset);
762 };
763 switch (arch_opcode) {
764 case kArchCallCodeObject: {
765 if (instr->InputAt(0)->IsImmediate()) {
766 __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
767 } else {
768 Register reg = i.InputRegister(0);
770 i.InputCodeEntrypointTag(instr->CodeEnrypointTagInputIndex());
772 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
774 __ CallCodeObject(reg, tag);
775 }
778 break;
779 }
780 case kArchCallBuiltinPointer: {
781 DCHECK(!instr->InputAt(0)->IsImmediate());
782 Register builtin_index = i.InputRegister(0);
783 Register target =
784 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister)
786 : builtin_index;
787 __ CallBuiltinByIndex(builtin_index, target);
790 break;
791 }
792 case kArchCallWasmFunction:
793 case kArchCallWasmFunctionIndirect: {
794 if (instr->InputAt(0)->IsImmediate()) {
795 DCHECK_EQ(arch_opcode, kArchCallWasmFunction);
796 Constant constant = i.ToConstant(instr->InputAt(0));
797 Address wasm_code = static_cast<Address>(constant.ToInt64());
798 __ Call(wasm_code, constant.rmode());
799 } else if (arch_opcode == kArchCallWasmFunctionIndirect) {
800 __ CallWasmCodePointer(
801 i.InputRegister(0),
802 i.InputInt64(instr->WasmSignatureHashInputIndex()));
803 } else {
804 __ Call(i.InputRegister(0));
805 }
808 break;
809 }
810 case kArchTailCallCodeObject: {
811 if (instr->InputAt(0)->IsImmediate()) {
812 __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
813 } else {
814 Register reg = i.InputOrZeroRegister(0);
816 i.InputCodeEntrypointTag(instr->CodeEnrypointTagInputIndex());
818 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
820 __ JumpCodeObject(reg, tag);
821 }
824 break;
825 }
826 case kArchTailCallWasm:
827 case kArchTailCallWasmIndirect: {
828 if (instr->InputAt(0)->IsImmediate()) {
829 DCHECK_EQ(arch_opcode, kArchTailCallWasm);
830 Constant constant = i.ToConstant(instr->InputAt(0));
831 Address wasm_code = static_cast<Address>(constant.ToInt64());
832 __ Jump(wasm_code, constant.rmode());
833 } else {
834 __ AddWord(kScratchReg, i.InputOrZeroRegister(0), 0);
835 if (arch_opcode == kArchTailCallWasmIndirect) {
836 __ CallWasmCodePointer(
837 i.InputRegister(0),
838 i.InputInt64(instr->WasmSignatureHashInputIndex()),
840 } else {
841 __ Jump(kScratchReg);
842 }
843 }
846 break;
847 }
848 case kArchTailCallAddress: {
849 CHECK(!instr->InputAt(0)->IsImmediate());
850 Register reg = i.InputOrZeroRegister(0);
852 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
854 __ Jump(reg);
857 break;
858 }
859 case kArchCallJSFunction: {
860 Register func = i.InputOrZeroRegister(0);
861 if (v8_flags.debug_code) {
862 // Check the function's context matches the context argument.
863 __ LoadTaggedField(kScratchReg,
864 FieldMemOperand(func, JSFunction::kContextOffset));
865 __ Assert(eq, AbortReason::kWrongFunctionContext, cp,
866 Operand(kScratchReg));
867 }
868 uint32_t num_arguments =
869 i.InputUint32(instr->JSCallArgumentCountInputIndex());
870 __ CallJSFunction(func, num_arguments);
873 break;
874 }
875 case kArchPrepareCallCFunction: {
876#ifdef V8_TARGET_ARCH_RISCV64
877 int const num_gp_parameters = ParamField::decode(instr->opcode());
878 int const num_fp_parameters = FPParamField::decode(instr->opcode());
879 __ PrepareCallCFunction(num_gp_parameters, num_fp_parameters,
881#else
882 int const num_parameters = MiscField::decode(instr->opcode());
883 __ PrepareCallCFunction(num_parameters, kScratchReg);
884#endif
885 // Frame alignment requires using FP-relative frame addressing.
887 break;
888 }
889 case kArchSaveCallerRegisters: {
890 fp_mode_ =
891 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
894 // kReturnRegister0 should have been saved before entering the stub.
895 int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
897 DCHECK_EQ(0, frame_access_state()->sp_delta());
901 break;
902 }
903 case kArchRestoreCallerRegisters: {
905 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
908 // Don't overwrite the returned value.
909 int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
911 DCHECK_EQ(0, frame_access_state()->sp_delta());
914 break;
915 }
916 case kArchPrepareTailCall:
918 break;
919 case kArchCallCFunctionWithFrameState:
920 case kArchCallCFunction: {
921 int const num_gp_parameters = ParamField::decode(instr->opcode());
922 int const num_fp_parameters = FPParamField::decode(instr->opcode());
923 Label return_location;
924 SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes;
925#if V8_ENABLE_WEBASSEMBLY
926 bool isWasmCapiFunction =
927 linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
928 if (isWasmCapiFunction) {
929 // Put the return address in a stack slot.
930 __ LoadAddress(kScratchReg, &return_location,
932 __ StoreWord(kScratchReg,
933 MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
934 set_isolate_data_slots = SetIsolateDataSlots::kNo;
935 }
936#endif // V8_ENABLE_WEBASSEMBLY
937 int pc_offset;
938 if (instr->InputAt(0)->IsImmediate()) {
939 ExternalReference ref = i.InputExternalReference(0);
940 pc_offset = __ CallCFunction(ref, num_gp_parameters, num_fp_parameters,
941 set_isolate_data_slots, &return_location);
942 } else {
943 Register func = i.InputRegister(0);
944 pc_offset = __ CallCFunction(func, num_gp_parameters, num_fp_parameters,
945 set_isolate_data_slots, &return_location);
946 }
947 RecordSafepoint(instr->reference_map(), pc_offset);
948
949 bool const needs_frame_state =
950 (arch_opcode == kArchCallCFunctionWithFrameState);
951 if (needs_frame_state) {
953 }
954
956 // Ideally, we should decrement SP delta to match the change of stack
957 // pointer in CallCFunction. However, for certain architectures (e.g.
958 // ARM), there may be more strict alignment requirement, causing old SP
959 // to be saved on the stack. In those cases, we can not calculate the SP
960 // delta statically.
963 // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
964 // Here, we assume the sequence to be:
965 // kArchSaveCallerRegisters;
966 // kArchCallCFunction;
967 // kArchRestoreCallerRegisters;
968 int bytes =
969 __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
971 }
972 break;
973 }
974 case kArchJmp:
975 AssembleArchJump(i.InputRpo(0));
976 break;
977 case kArchBinarySearchSwitch:
979 break;
980 case kArchTableSwitch:
982 break;
983 case kArchAbortCSADcheck:
984 DCHECK(i.InputRegister(0) == a0);
985 {
986 // We don't actually want to generate a pile of code for this, so just
987 // claim there is a stack frame, without generating one.
988 FrameScope scope(masm(), StackFrame::NO_FRAME_TYPE);
989 __ CallBuiltin(Builtin::kAbortCSADcheck);
990 }
991 __ stop();
992 break;
993 case kArchDebugBreak:
994 __ DebugBreak();
995 break;
996 case kArchComment:
997 __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)),
999 break;
1000 case kArchNop:
1001 case kArchThrowTerminator:
1002 // don't emit code for nops.
1003 break;
1004 case kArchDeoptimize: {
1005 DeoptimizationExit* exit =
1007 __ Branch(exit->label());
1008 break;
1009 }
1010 case kArchRet:
1011 AssembleReturn(instr->InputAt(0));
1012 break;
1013#if V8_ENABLE_WEBASSEMBLY
1014 case kArchStackPointer:
1015 // The register allocator expects an allocatable register for the output,
1016 // we cannot use sp directly.
1017 __ Move(i.OutputRegister(), sp);
1018 break;
1019 case kArchSetStackPointer: {
1020 DCHECK(instr->InputAt(0)->IsRegister());
1021 if (masm()->options().enable_simulator_code) {
1022 __ RecordComment("-- Set simulator stack limit --");
1023 __ LoadStackLimit(kSimulatorBreakArgument,
1026 }
1027 __ Move(sp, i.InputRegister(0));
1028 break;
1029 }
1030#endif // V8_ENABLE_WEBASSEMBLY
1031 case kArchStackPointerGreaterThan:
1032 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1033 break;
1034 case kArchStackCheckOffset:
1035 __ Move(i.OutputRegister(), Smi::FromInt(GetStackCheckOffset()));
1036 break;
1037 case kArchFramePointer:
1038 __ Move(i.OutputRegister(), fp);
1039 break;
1040 case kArchParentFramePointer:
1041 if (frame_access_state()->has_frame()) {
1042 __ LoadWord(i.OutputRegister(), MemOperand(fp, 0));
1043 } else {
1044 __ Move(i.OutputRegister(), fp);
1045 }
1046 break;
1047 case kArchTruncateDoubleToI:
1048 __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
1049 i.InputDoubleRegister(0), DetermineStubCallMode());
1050 break;
1051 case kArchStoreWithWriteBarrier: {
1053 // Indirect pointer writes must use a different opcode.
1055 Register object = i.InputRegister(0);
1056 Register offset = i.InputRegister(1);
1057 Register value = i.InputRegister(2);
1058 __ AddWord(kScratchReg, object, offset);
1059 auto ool = zone()->New<OutOfLineRecordWrite>(
1060 this, object, Operand(offset), value, mode, DetermineStubCallMode());
1061 __ StoreTaggedField(value, MemOperand(kScratchReg, 0), trapper);
1063 __ JumpIfSmi(value, ool->exit());
1064 }
1066 ne, ool->entry());
1067 __ bind(ool->exit());
1068 break;
1069 }
1070 case kArchAtomicStoreWithWriteBarrier: {
1071#ifdef V8_TARGET_ARCH_RISCV64
1073 // Indirect pointer writes must use a different opcode.
1075 Register object = i.InputRegister(0);
1076 Register offset = i.InputRegister(1);
1077 Register value = i.InputRegister(2);
1078
1079 auto ool = zone()->New<OutOfLineRecordWrite>(
1080 this, object, Operand(offset), value, mode, DetermineStubCallMode());
1081 __ AddWord(kScratchReg, object, offset);
1082 __ AtomicStoreTaggedField(value, MemOperand(kScratchReg, 0));
1083 // Skip the write barrier if the value is a Smi. However, this is only
1084 // valid if the value isn't an indirect pointer. Otherwise the value will
1085 // be a pointer table index, which will always look like a Smi (but
1086 // actually reference a pointer in the pointer table).
1088 __ JumpIfSmi(value, ool->exit());
1089 }
1091 ne, ool->entry());
1092 __ bind(ool->exit());
1093 break;
1094#else
1095 UNREACHABLE();
1096#endif
1097 }
1098 case kArchStoreIndirectWithWriteBarrier: {
1099#ifdef V8_TARGET_ARCH_RISCV64
1102 IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3));
1104 Register object = i.InputRegister(0);
1105 Register offset = i.InputRegister(1);
1106 Register value = i.InputRegister(2);
1107 __ AddWord(kScratchReg, object, offset);
1108 auto ool = zone()->New<OutOfLineRecordWrite>(
1109 this, object, Operand(offset), value, mode, DetermineStubCallMode(),
1110 tag);
1111 __ StoreIndirectPointerField(value, MemOperand(kScratchReg, 0), trapper);
1113 ne, ool->entry());
1114 __ bind(ool->exit());
1115 break;
1116#else
1117 UNREACHABLE();
1118#endif
1119 }
1120 case kArchStackSlot: {
1121 FrameOffset offset =
1122 frame_access_state()->GetFrameOffset(i.InputInt32(0));
1123 Register base_reg = offset.from_stack_pointer() ? sp : fp;
1124 __ AddWord(i.OutputRegister(), base_reg, Operand(offset.offset()));
1125 break;
1126 }
1127 case kIeee754Float64Acos:
1129 break;
1130 case kIeee754Float64Acosh:
1131 ASSEMBLE_IEEE754_UNOP(acosh);
1132 break;
1133 case kIeee754Float64Asin:
1135 break;
1136 case kIeee754Float64Asinh:
1137 ASSEMBLE_IEEE754_UNOP(asinh);
1138 break;
1139 case kIeee754Float64Atan:
1141 break;
1142 case kIeee754Float64Atanh:
1143 ASSEMBLE_IEEE754_UNOP(atanh);
1144 break;
1145 case kIeee754Float64Atan2:
1147 break;
1148 case kIeee754Float64Cos:
1150 break;
1151 case kIeee754Float64Cosh:
1153 break;
1154 case kIeee754Float64Cbrt:
1156 break;
1157 case kIeee754Float64Exp:
1159 break;
1160 case kIeee754Float64Expm1:
1161 ASSEMBLE_IEEE754_UNOP(expm1);
1162 break;
1163 case kIeee754Float64Log:
1165 break;
1166 case kIeee754Float64Log1p:
1167 ASSEMBLE_IEEE754_UNOP(log1p);
1168 break;
1169 case kIeee754Float64Log2:
1171 break;
1172 case kIeee754Float64Log10:
1173 ASSEMBLE_IEEE754_UNOP(log10);
1174 break;
1175 case kIeee754Float64Pow:
1177 break;
1178 case kIeee754Float64Sin:
1180 break;
1181 case kIeee754Float64Sinh:
1183 break;
1184 case kIeee754Float64Tan:
1186 break;
1187 case kIeee754Float64Tanh:
1189 break;
1190 case kRiscvAdd32:
1191 __ Add32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1192 break;
1193 case kRiscvSub32:
1194 __ Sub32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1195 break;
1196 case kRiscvMul32:
1197 __ Mul32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1198 break;
1199 case kRiscvMulOvf32:
1200 __ MulOverflow32(i.OutputRegister(), i.InputOrZeroRegister(0),
1201 i.InputOperand(1), kScratchReg);
1202 break;
1203#if V8_TARGET_ARCH_RISCV64
1204 case kRiscvAdd64:
1205 __ AddWord(i.OutputRegister(), i.InputOrZeroRegister(0),
1206 i.InputOperand(1));
1207 break;
1208 case kRiscvAddOvf64:
1209 __ AddOverflow64(i.OutputRegister(), i.InputOrZeroRegister(0),
1210 i.InputOperand(1), kScratchReg);
1211 break;
1212 case kRiscvSub64:
1213 __ Sub64(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1214 break;
1215 case kRiscvSubOvf64:
1216 __ SubOverflow64(i.OutputRegister(), i.InputOrZeroRegister(0),
1217 i.InputOperand(1), kScratchReg);
1218 break;
1219 case kRiscvMulHigh32:
1220 __ Mulh32(i.OutputRegister(), i.InputOrZeroRegister(0),
1221 i.InputOperand(1));
1222 break;
1223 case kRiscvMulHighU32:
1224 __ Mulhu32(i.OutputRegister(), i.InputOrZeroRegister(0),
1225 i.InputOperand(1), kScratchReg, kScratchReg2);
1226 break;
1227 case kRiscvMulHigh64:
1228 __ Mulh64(i.OutputRegister(), i.InputOrZeroRegister(0),
1229 i.InputOperand(1));
1230 break;
1231 case kRiscvMulHighU64:
1232 __ Mulhu64(i.OutputRegister(), i.InputOrZeroRegister(0),
1233 i.InputOperand(1));
1234 break;
1235 case kRiscvMulOvf64:
1236 __ MulOverflow64(i.OutputRegister(), i.InputOrZeroRegister(0),
1237 i.InputOperand(1), kScratchReg);
1238 break;
1239 case kRiscvDiv32: {
1240 DCHECK_NE(i.OutputRegister(), i.InputRegister(1));
1241 __ Div32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1242 // Set ouput to zero if divisor == 0
1243 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1244 break;
1245 }
1246 case kRiscvDivU32: {
1247 DCHECK_NE(i.OutputRegister(), i.InputRegister(1));
1248 __ Divu32(i.OutputRegister(), i.InputOrZeroRegister(0),
1249 i.InputOperand(1));
1250 // Set ouput to zero if divisor == 0
1251 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1252 break;
1253 }
1254 case kRiscvMod32:
1255 __ Mod32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1256 break;
1257 case kRiscvModU32:
1258 __ Modu32(i.OutputRegister(), i.InputOrZeroRegister(0),
1259 i.InputOperand(1));
1260 break;
1261 case kRiscvMul64:
1262 __ Mul64(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1263 break;
1264 case kRiscvDiv64: {
1265 DCHECK_NE(i.OutputRegister(), i.InputRegister(1));
1266 __ Div64(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1267 // Set ouput to zero if divisor == 0
1268 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1269 break;
1270 }
1271 case kRiscvDivU64: {
1272 DCHECK_NE(i.OutputRegister(), i.InputRegister(1));
1273 __ Divu64(i.OutputRegister(), i.InputOrZeroRegister(0),
1274 i.InputOperand(1));
1275 // Set ouput to zero if divisor == 0
1276 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1277 break;
1278 }
1279 case kRiscvMod64:
1280 __ Mod64(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1281 break;
1282 case kRiscvModU64:
1283 __ Modu64(i.OutputRegister(), i.InputOrZeroRegister(0),
1284 i.InputOperand(1));
1285 break;
1286#elif V8_TARGET_ARCH_RISCV32
1287 case kRiscvAddOvf:
1288 __ AddOverflow(i.OutputRegister(), i.InputOrZeroRegister(0),
1289 i.InputOperand(1), kScratchReg);
1290 break;
1291 case kRiscvSubOvf:
1292 __ SubOverflow(i.OutputRegister(), i.InputOrZeroRegister(0),
1293 i.InputOperand(1), kScratchReg);
1294 break;
1295 case kRiscvMulHigh32:
1296 __ Mulh(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1297 break;
1298 case kRiscvMulHighU32:
1299 __ Mulhu(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1),
1301 break;
1302 case kRiscvDiv32: {
1303 __ Div(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1304 // Set ouput to zero if divisor == 0
1305 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1306 break;
1307 }
1308 case kRiscvDivU32: {
1309 __ Divu(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1310 // Set ouput to zero if divisor == 0
1311 __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1));
1312 break;
1313 }
1314 case kRiscvMod32:
1315 __ Mod(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1316 break;
1317 case kRiscvModU32:
1318 __ Modu(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1319 break;
1320#endif
1321 case kRiscvAnd:
1322 __ And(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1323 break;
1324 case kRiscvAnd32:
1325 __ And(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1326 __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0);
1327 break;
1328 case kRiscvOr:
1329 __ Or(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1330 break;
1331 case kRiscvOr32:
1332 __ Or(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1333 __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0);
1334 break;
1335 case kRiscvXor:
1336 __ Xor(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1337 break;
1338 case kRiscvXor32:
1339 __ Xor(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
1340 __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0);
1341 break;
1342 case kRiscvClz32:
1343 __ Clz32(i.OutputRegister(), i.InputOrZeroRegister(0));
1344 break;
1345#if V8_TARGET_ARCH_RISCV64
1346 case kRiscvClz64:
1347 __ Clz64(i.OutputRegister(), i.InputOrZeroRegister(0));
1348 break;
1349#endif
1350 case kRiscvShl32:
1351 if (instr->InputAt(1)->IsRegister()) {
1352 __ Sll32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1353 } else {
1354 int64_t imm = i.InputOperand(1).immediate();
1355 __ Sll32(i.OutputRegister(), i.InputRegister(0),
1356 static_cast<uint16_t>(imm));
1357 }
1358 break;
1359 case kRiscvShr32:
1360 if (instr->InputAt(1)->IsRegister()) {
1361 __ Srl32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1362 } else {
1363 int64_t imm = i.InputOperand(1).immediate();
1364 __ Srl32(i.OutputRegister(), i.InputRegister(0),
1365 static_cast<uint16_t>(imm));
1366 }
1367 break;
1368 case kRiscvSar32:
1369 if (instr->InputAt(1)->IsRegister()) {
1370 __ Sra32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1371 } else {
1372 int64_t imm = i.InputOperand(1).immediate();
1373 __ Sra32(i.OutputRegister(), i.InputRegister(0),
1374 static_cast<uint16_t>(imm));
1375 }
1376 break;
1377#if V8_TARGET_ARCH_RISCV64
1378 case kRiscvZeroExtendWord: {
1379 __ ZeroExtendWord(i.OutputRegister(), i.InputRegister(0));
1380 break;
1381 }
1382 case kRiscvSignExtendWord: {
1383 __ SignExtendWord(i.OutputRegister(), i.InputRegister(0));
1384 break;
1385 }
1386 case kRiscvShl64:
1387 __ Sll64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1388 break;
1389 case kRiscvShr64:
1390 __ Srl64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1391 break;
1392 case kRiscvSar64:
1393 __ Sra64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1394 break;
1395 case kRiscvRor64:
1396 __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1397 break;
1398 case kRiscvTst64:
1399 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1400 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1401 break;
1402#endif
1403 case kRiscvRev8:
1404 __ rev8(i.OutputRegister(), i.InputRegister(0));
1405 break;
1406 case kRiscvAndn:
1407 __ andn(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1408 break;
1409 case kRiscvOrn:
1410 __ orn(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1411 break;
1412 case kRiscvXnor:
1413 __ xnor(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1414 break;
1415 case kRiscvClz:
1416 __ clz(i.OutputRegister(), i.InputRegister(0));
1417 break;
1418 case kRiscvCtz:
1419 __ ctz(i.OutputRegister(), i.InputRegister(0));
1420 break;
1421 case kRiscvCpop:
1422 __ cpop(i.OutputRegister(), i.InputRegister(0));
1423 break;
1424#if V8_TARGET_ARCH_RISCV64
1425 case kRiscvClzw:
1426 __ clzw(i.OutputRegister(), i.InputRegister(0));
1427 break;
1428 case kRiscvCtzw:
1429 __ ctzw(i.OutputRegister(), i.InputRegister(0));
1430 break;
1431 case kRiscvCpopw:
1432 __ cpopw(i.OutputRegister(), i.InputRegister(0));
1433 break;
1434#endif
1435 case kRiscvMax:
1436 __ max(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1437 break;
1438 case kRiscvMaxu:
1439 __ maxu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1440 break;
1441 case kRiscvMin:
1442 __ min(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1443 break;
1444 case kRiscvMinu:
1445 __ minu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1446 break;
1447 case kRiscvSextb:
1448 __ sextb(i.OutputRegister(), i.InputRegister(0));
1449 break;
1450 case kRiscvSexth:
1451 __ sexth(i.OutputRegister(), i.InputRegister(0));
1452 break;
1453 case kRiscvZexth:
1454 __ zexth(i.OutputRegister(), i.InputRegister(0));
1455 break;
1456 case kRiscvTst32:
1457 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
1458 __ Sll32(kScratchReg, kScratchReg, 0x0);
1459 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1460 break;
1461 case kRiscvRor32:
1462 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1463 break;
1464 case kRiscvCmp:
1465#ifdef V8_TARGET_ARCH_RISCV64
1466 case kRiscvCmp32:
1467 case kRiscvCmpZero32:
1468#endif
1469 // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1470 break;
1471 case kRiscvCmpZero:
1472 // Pseudo-instruction used for cmpzero/branch. No opcode emitted here.
1473 break;
1474 case kRiscvMov:
1475 // TODO(plind): Should we combine mov/li like this, or use separate instr?
1476 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1477 if (HasRegisterInput(instr, 0)) {
1478 __ Move(i.OutputRegister(), i.InputRegister(0));
1479 } else {
1480 __ li(i.OutputRegister(), i.InputOperand(0));
1481 }
1482 break;
1483
1484 case kRiscvCmpS: {
1485 FPURegister left = i.InputOrZeroSingleRegister(0);
1486 FPURegister right = i.InputOrZeroSingleRegister(1);
1487 bool predicate;
1489 FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1490
1491 if ((left == kSingleRegZero || right == kSingleRegZero) &&
1492 !__ IsSingleZeroRegSet()) {
1493 __ LoadFPRImmediate(kSingleRegZero, 0.0f);
1494 }
1495 // compare result set to kScratchReg
1496 __ CompareF32(kScratchReg, cc, left, right);
1497 } break;
1498 case kRiscvAddS:
1499 // TODO(plind): add special case: combine mult & add.
1500 __ fadd_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1501 i.InputDoubleRegister(1));
1502 break;
1503 case kRiscvSubS:
1504 __ fsub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1505 i.InputDoubleRegister(1));
1506 break;
1507 case kRiscvMulS:
1508 // TODO(plind): add special case: right op is -1.0, see arm port.
1509 __ fmul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1510 i.InputDoubleRegister(1));
1511 break;
1512 case kRiscvDivS:
1513 __ fdiv_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1514 i.InputDoubleRegister(1));
1515 break;
1516 case kRiscvModS: {
1517 // TODO(bmeurer): We should really get rid of this special instruction,
1518 // and generate a CallAddress instruction instead.
1519 FrameScope scope(masm(), StackFrame::MANUAL);
1520 __ PrepareCallCFunction(0, 2, kScratchReg);
1521 __ MovToFloatParameters(i.InputDoubleRegister(0),
1522 i.InputDoubleRegister(1));
1523 // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate())
1524 __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1525 // Move the result in the double result register.
1526 __ MovFromFloatResult(i.OutputSingleRegister());
1527 break;
1528 }
1529 case kRiscvAbsS:
1530 __ fabs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1531 break;
1532 case kRiscvNegS:
1533 __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1534 break;
1535 case kRiscvSqrtS: {
1536 __ fsqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1537 break;
1538 }
1539 case kRiscvMaxS:
1540 __ fmax_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1541 i.InputDoubleRegister(1));
1542 break;
1543 case kRiscvMinS:
1544 __ fmin_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1545 i.InputDoubleRegister(1));
1546 break;
1547 case kRiscvCmpD: {
1548 FPURegister left = i.InputOrZeroDoubleRegister(0);
1549 FPURegister right = i.InputOrZeroDoubleRegister(1);
1550 bool predicate;
1552 FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1553 if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1554 !__ IsDoubleZeroRegSet()) {
1555 __ LoadFPRImmediate(kDoubleRegZero, 0.0);
1556 }
1557 // compare result set to kScratchReg
1558 __ CompareF64(kScratchReg, cc, left, right);
1559 } break;
1560#if V8_TARGET_ARCH_RISCV32
1561 case kRiscvAddPair:
1562 __ AddPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1563 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1565 break;
1566 case kRiscvSubPair:
1567 __ SubPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1568 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1570 break;
1571 case kRiscvAndPair:
1572 __ AndPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1573 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3));
1574 break;
1575 case kRiscvOrPair:
1576 __ OrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1577 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3));
1578 break;
1579 case kRiscvXorPair:
1580 __ XorPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1581 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3));
1582 break;
1583 case kRiscvMulPair:
1584 __ MulPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
1585 i.InputRegister(1), i.InputRegister(2), i.InputRegister(3),
1587 break;
1588 case kRiscvShlPair: {
1589 Register second_output =
1590 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1591 if (instr->InputAt(2)->IsRegister()) {
1592 __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1593 i.InputRegister(1), i.InputRegister(2), kScratchReg,
1594 kScratchReg2);
1595 } else {
1596 uint32_t imm = i.InputOperand(2).immediate();
1597 __ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1598 i.InputRegister(1), imm, kScratchReg, kScratchReg2);
1599 }
1600 } break;
1601 case kRiscvShrPair: {
1602 Register second_output =
1603 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1604 if (instr->InputAt(2)->IsRegister()) {
1605 __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1606 i.InputRegister(1), i.InputRegister(2), kScratchReg,
1607 kScratchReg2);
1608 } else {
1609 uint32_t imm = i.InputOperand(2).immediate();
1610 __ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1611 i.InputRegister(1), imm, kScratchReg, kScratchReg2);
1612 }
1613 } break;
1614 case kRiscvSarPair: {
1615 Register second_output =
1616 instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1617 if (instr->InputAt(2)->IsRegister()) {
1618 __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1619 i.InputRegister(1), i.InputRegister(2), kScratchReg,
1620 kScratchReg2);
1621 } else {
1622 uint32_t imm = i.InputOperand(2).immediate();
1623 __ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1624 i.InputRegister(1), imm, kScratchReg, kScratchReg2);
1625 }
1626 } break;
1627#endif
1628 case kRiscvAddD:
1629 // TODO(plind): add special case: combine mult & add.
1630 __ fadd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1631 i.InputDoubleRegister(1));
1632 break;
1633 case kRiscvSubD:
1634 __ fsub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1635 i.InputDoubleRegister(1));
1636 break;
1637 case kRiscvMulD:
1638 // TODO(plind): add special case: right op is -1.0, see arm port.
1639 __ fmul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1640 i.InputDoubleRegister(1));
1641 break;
1642 case kRiscvDivD:
1643 __ fdiv_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1644 i.InputDoubleRegister(1));
1645 break;
1646 case kRiscvModD: {
1647 // TODO(bmeurer): We should really get rid of this special instruction,
1648 // and generate a CallAddress instruction instead.
1649 FrameScope scope(masm(), StackFrame::MANUAL);
1650 __ PrepareCallCFunction(0, 2, kScratchReg);
1651 __ MovToFloatParameters(i.InputDoubleRegister(0),
1652 i.InputDoubleRegister(1));
1653 __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1654 // Move the result in the double result register.
1655 __ MovFromFloatResult(i.OutputDoubleRegister());
1656 break;
1657 }
1658 case kRiscvAbsD:
1659 __ fabs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1660 break;
1661 case kRiscvNegD:
1662 __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1663 break;
1664 case kRiscvSqrtD: {
1665 __ fsqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1666 break;
1667 }
1668 case kRiscvMaxD:
1669 __ fmax_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1670 i.InputDoubleRegister(1));
1671 break;
1672 case kRiscvMinD:
1673 __ fmin_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1674 i.InputDoubleRegister(1));
1675 break;
1676#if V8_TARGET_ARCH_RISCV64
1677 case kRiscvFloat64RoundDown: {
1678 __ Floor_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1680 break;
1681 }
1682 case kRiscvFloat64RoundTruncate: {
1683 __ Trunc_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1685 break;
1686 }
1687 case kRiscvFloat64RoundUp: {
1688 __ Ceil_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1690 break;
1691 }
1692 case kRiscvFloat64RoundTiesEven: {
1693 __ Round_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1695 break;
1696 }
1697#endif
1698 case kRiscvFloat32RoundDown: {
1699 __ Floor_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0),
1701 break;
1702 }
1703 case kRiscvFloat32RoundTruncate: {
1704 __ Trunc_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0),
1706 break;
1707 }
1708 case kRiscvFloat32RoundUp: {
1709 __ Ceil_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0),
1711 break;
1712 }
1713 case kRiscvFloat32RoundTiesEven: {
1714 __ Round_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0),
1716 break;
1717 }
1718 case kRiscvFloat32Max: {
1719 __ Float32Max(i.OutputSingleRegister(), i.InputSingleRegister(0),
1720 i.InputSingleRegister(1));
1721 break;
1722 }
1723 case kRiscvFloat64Max: {
1724 __ Float64Max(i.OutputSingleRegister(), i.InputSingleRegister(0),
1725 i.InputSingleRegister(1));
1726 break;
1727 }
1728 case kRiscvFloat32Min: {
1729 __ Float32Min(i.OutputSingleRegister(), i.InputSingleRegister(0),
1730 i.InputSingleRegister(1));
1731 break;
1732 }
1733 case kRiscvFloat64Min: {
1734 __ Float64Min(i.OutputSingleRegister(), i.InputSingleRegister(0),
1735 i.InputSingleRegister(1));
1736 break;
1737 }
1738 case kRiscvFloat64SilenceNaN:
1739 __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1740 break;
1741 case kRiscvCvtSD: {
1742 Label done;
1743 __ feq_d(kScratchReg, i.InputDoubleRegister(0), i.InputDoubleRegister(0));
1744#if V8_TARGET_ARCH_RISCV64
1745 __ fmv_x_d(kScratchReg2, i.InputDoubleRegister(0));
1746#elif V8_TARGET_ARCH_RISCV32
1747 __ StoreDouble(i.InputDoubleRegister(0),
1748 MemOperand(sp, -kDoubleSize)); // store whole 64 bit
1749#endif
1750 __ fcvt_s_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1751 __ Branch(&done, ne, kScratchReg, Operand(zero_reg));
1752#if V8_TARGET_ARCH_RISCV64
1753 __ And(kScratchReg2, kScratchReg2, Operand(0x8000000000000000));
1754 __ srai(kScratchReg2, kScratchReg2, 32);
1756#elif V8_TARGET_ARCH_RISCV32
1757 __ Lw(kScratchReg2,
1758 MemOperand(sp,
1759 -kDoubleSize /
1760 2)); // only load the high half to get the sign bit
1762#endif
1763 __ fsgnj_s(i.OutputDoubleRegister(), i.OutputDoubleRegister(),
1765 __ bind(&done);
1766 break;
1767 }
1768 case kRiscvCvtDS: {
1769 Label done;
1770 __ feq_s(kScratchReg, i.InputDoubleRegister(0), i.InputDoubleRegister(0));
1771#if V8_TARGET_ARCH_RISCV64
1772 __ fmv_x_d(kScratchReg2, i.InputDoubleRegister(0));
1773#elif V8_TARGET_ARCH_RISCV32
1774 __ StoreFloat(i.InputDoubleRegister(0), MemOperand(sp, -kFloatSize));
1775#endif
1776 __ fcvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1777 __ Branch(&done, ne, kScratchReg, Operand(zero_reg));
1778#if V8_TARGET_ARCH_RISCV64
1779 __ And(kScratchReg2, kScratchReg2, Operand(0x80000000));
1780 __ slli(kScratchReg2, kScratchReg2, 32);
1782#elif V8_TARGET_ARCH_RISCV32
1785#endif
1786 __ fsgnj_d(i.OutputDoubleRegister(), i.OutputDoubleRegister(),
1788 __ bind(&done);
1789 break;
1790 }
1791 case kRiscvCvtDW: {
1792 __ fcvt_d_w(i.OutputDoubleRegister(), i.InputRegister(0));
1793 break;
1794 }
1795 case kRiscvCvtSW: {
1796 __ fcvt_s_w(i.OutputDoubleRegister(), i.InputRegister(0));
1797 break;
1798 }
1799 case kRiscvCvtSUw: {
1800 __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1801 break;
1802 }
1803#if V8_TARGET_ARCH_RISCV64
1804 case kRiscvCvtSL: {
1805 __ fcvt_s_l(i.OutputDoubleRegister(), i.InputRegister(0));
1806 break;
1807 }
1808 case kRiscvCvtDL: {
1809 __ fcvt_d_l(i.OutputDoubleRegister(), i.InputRegister(0));
1810 break;
1811 }
1812 case kRiscvCvtDUl: {
1813 __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1814 break;
1815 }
1816 case kRiscvCvtSUl: {
1817 __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1818 break;
1819 }
1820#endif
1821 case kRiscvCvtDUw: {
1822 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1823 break;
1824 }
1825 case kRiscvFloorWD: {
1826 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1827 __ Floor_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1828 break;
1829 }
1830 case kRiscvCeilWD: {
1831 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1832 __ Ceil_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1833 break;
1834 }
1835 case kRiscvRoundWD: {
1836 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1837 __ Round_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1838 break;
1839 }
1840 case kRiscvTruncWD: {
1841 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1842 __ Trunc_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1843 break;
1844 }
1845 case kRiscvFloorWS: {
1846 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1847 __ Floor_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1848 break;
1849 }
1850 case kRiscvCeilWS: {
1851 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1852 __ Ceil_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1853 break;
1854 }
1855 case kRiscvRoundWS: {
1856 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1857 __ Round_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1858 break;
1859 }
1860 case kRiscvTruncWS: {
1861 Label done;
1862 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1863 bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1864 __ Trunc_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1865
1866 // On RISCV, if the input value exceeds INT32_MAX, the result of fcvt
1867 // is INT32_MAX. Note that, since INT32_MAX means the lower 31-bits are
1868 // all 1s, INT32_MAX cannot be represented precisely as a float, so an
1869 // fcvt result of INT32_MAX always indicate overflow.
1870 //
1871 // In wasm_compiler, to detect overflow in converting a FP value, fval, to
1872 // integer, V8 checks whether I2F(F2I(fval)) equals fval. However, if fval
1873 // == INT32_MAX+1, the value of I2F(F2I(fval)) happens to be fval. So,
1874 // INT32_MAX is not a good value to indicate overflow. Instead, we will
1875 // use INT32_MIN as the converted result of an out-of-range FP value,
1876 // exploiting the fact that INT32_MAX+1 is INT32_MIN.
1877 //
1878 // If the result of conversion overflow, the result will be set to
1879 // INT32_MIN. Here we detect overflow by testing whether output + 1 <
1880 // output (i.e., kScratchReg < output)
1881 if (set_overflow_to_min_i32) {
1882 __ Add32(kScratchReg, i.OutputRegister(), 1);
1883 __ BranchShort(&done, lt, i.OutputRegister(), Operand(kScratchReg));
1884 __ Move(i.OutputRegister(), kScratchReg);
1885 __ bind(&done);
1886 }
1887 break;
1888 }
1889#if V8_TARGET_ARCH_RISCV64
1890 case kRiscvTruncLS: {
1891 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1892 __ Trunc_l_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1893 break;
1894 }
1895 case kRiscvTruncLD: {
1896 Label done;
1897 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1898 bool set_overflow_to_min_i64 = MiscField::decode(instr->opcode());
1899 __ Trunc_l_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1900 if (set_overflow_to_min_i64) {
1901 __ AddWord(kScratchReg, i.OutputRegister(), 1);
1902 __ BranchShort(&done, lt, i.OutputRegister(), Operand(kScratchReg));
1903 __ Move(i.OutputRegister(), kScratchReg);
1904 __ bind(&done);
1905 }
1906 break;
1907 }
1908#endif
1909 case kRiscvTruncUwD: {
1910 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1911 __ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), result);
1912 break;
1913 }
1914 case kRiscvTruncUwS: {
1915 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1916 bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
1917 __ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1918
1919 // On RISCV, if the input value exceeds UINT32_MAX, the result of fcvt
1920 // is UINT32_MAX. Note that, since UINT32_MAX means all 32-bits are 1s,
1921 // UINT32_MAX cannot be represented precisely as float, so an fcvt result
1922 // of UINT32_MAX always indicates overflow.
1923 //
1924 // In wasm_compiler.cc, to detect overflow in converting a FP value, fval,
1925 // to integer, V8 checks whether I2F(F2I(fval)) equals fval. However, if
1926 // fval == UINT32_MAX+1, the value of I2F(F2I(fval)) happens to be fval.
1927 // So, UINT32_MAX is not a good value to indicate overflow. Instead, we
1928 // will use 0 as the converted result of an out-of-range FP value,
1929 // exploiting the fact that UINT32_MAX+1 is 0.
1930 if (set_overflow_to_min_u32) {
1931 __ Add32(kScratchReg, i.OutputRegister(), 1);
1932 // Set ouput to zero if result overflows (i.e., UINT32_MAX)
1933 __ LoadZeroIfConditionZero(i.OutputRegister(), kScratchReg);
1934 }
1935 break;
1936 }
1937#if V8_TARGET_ARCH_RISCV64
1938 case kRiscvTruncUlS: {
1939 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1940 __ Trunc_ul_s(i.OutputRegister(), i.InputDoubleRegister(0), result);
1941 break;
1942 }
1943 case kRiscvTruncUlD: {
1944 Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1945 __ Trunc_ul_d(i.OutputRegister(0), i.InputDoubleRegister(0), result);
1946 break;
1947 }
1948 case kRiscvBitcastDL:
1949 __ fmv_x_d(i.OutputRegister(), i.InputDoubleRegister(0));
1950 break;
1951 case kRiscvBitcastLD:
1952 __ fmv_d_x(i.OutputDoubleRegister(), i.InputRegister(0));
1953 break;
1954#endif
1955 case kRiscvBitcastInt32ToFloat32:
1956 __ fmv_w_x(i.OutputDoubleRegister(), i.InputRegister(0));
1957 break;
1958 case kRiscvBitcastFloat32ToInt32:
1959 __ fmv_x_w(i.OutputRegister(), i.InputDoubleRegister(0));
1960 break;
1961 case kRiscvFloat64ExtractLowWord32:
1962 __ ExtractLowWordFromF64(i.OutputRegister(), i.InputDoubleRegister(0));
1963 break;
1964 case kRiscvFloat64ExtractHighWord32:
1965 __ ExtractHighWordFromF64(i.OutputRegister(), i.InputDoubleRegister(0));
1966 break;
1967 case kRiscvFloat64InsertLowWord32:
1968 __ InsertLowWordF64(i.OutputDoubleRegister(), i.InputRegister(1));
1969 break;
1970 case kRiscvFloat64InsertHighWord32:
1971 __ InsertHighWordF64(i.OutputDoubleRegister(), i.InputRegister(1));
1972 break;
1973 // ... more basic instructions ...
1974
1975 case kRiscvSignExtendByte:
1976 __ SignExtendByte(i.OutputRegister(), i.InputRegister(0));
1977 break;
1978 case kRiscvSignExtendShort:
1979 __ SignExtendShort(i.OutputRegister(), i.InputRegister(0));
1980 break;
1981 case kRiscvLbu:
1982 __ Lbu(i.OutputRegister(), i.MemoryOperand(), trapper);
1983 break;
1984 case kRiscvLb:
1985 __ Lb(i.OutputRegister(), i.MemoryOperand(), trapper);
1986 break;
1987 case kRiscvSb:
1988 __ Sb(i.InputOrZeroRegister(0), i.MemoryOperand(1), trapper);
1989 break;
1990 case kRiscvLhu:
1991 __ Lhu(i.OutputRegister(), i.MemoryOperand(), trapper);
1992 break;
1993 case kRiscvUlhu:
1994 __ Ulhu(i.OutputRegister(), i.MemoryOperand());
1995 break;
1996 case kRiscvLh:
1997 __ Lh(i.OutputRegister(), i.MemoryOperand(), trapper);
1998 break;
1999 case kRiscvUlh:
2000 __ Ulh(i.OutputRegister(), i.MemoryOperand());
2001 break;
2002 case kRiscvSh:
2003 __ Sh(i.InputOrZeroRegister(0), i.MemoryOperand(1), trapper);
2004 break;
2005 case kRiscvUsh:
2006 __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand());
2007 break;
2008 case kRiscvLw:
2009 __ Lw(i.OutputRegister(), i.MemoryOperand(), trapper);
2010 break;
2011 case kRiscvUlw:
2012 __ Ulw(i.OutputRegister(), i.MemoryOperand());
2013 break;
2014#if V8_TARGET_ARCH_RISCV64
2015 case kRiscvLwu:
2016 __ Lwu(i.OutputRegister(), i.MemoryOperand(), trapper);
2017 break;
2018 case kRiscvUlwu:
2019 __ Ulwu(i.OutputRegister(), i.MemoryOperand());
2020 break;
2021 case kRiscvLd:
2022 __ Ld(i.OutputRegister(), i.MemoryOperand(), trapper);
2023 break;
2024 case kRiscvUld:
2025 __ Uld(i.OutputRegister(), i.MemoryOperand());
2026 break;
2027 case kRiscvSd:
2028 __ Sd(i.InputOrZeroRegister(0), i.MemoryOperand(1), trapper);
2029 break;
2030 case kRiscvUsd:
2031 __ Usd(i.InputOrZeroRegister(2), i.MemoryOperand());
2032 break;
2033#endif
2034 case kRiscvSw:
2035 __ Sw(i.InputOrZeroRegister(0), i.MemoryOperand(1), trapper);
2036 break;
2037 case kRiscvUsw:
2038 __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand());
2039 break;
2040 case kRiscvLoadFloat: {
2041 __ LoadFloat(i.OutputSingleRegister(), i.MemoryOperand(), trapper);
2042 break;
2043 }
2044 case kRiscvULoadFloat: {
2045 __ ULoadFloat(i.OutputSingleRegister(), i.MemoryOperand());
2046 break;
2047 }
2048 case kRiscvStoreFloat: {
2049 MemOperand operand = i.MemoryOperand(1);
2050 FPURegister ft = i.InputOrZeroSingleRegister(0);
2051 if (ft == kSingleRegZero && !__ IsSingleZeroRegSet()) {
2052 __ LoadFPRImmediate(kSingleRegZero, 0.0f);
2053 }
2054 __ StoreFloat(ft, operand, trapper);
2055 break;
2056 }
2057 case kRiscvUStoreFloat: {
2058 size_t index = 0;
2059 MemOperand operand = i.MemoryOperand(&index);
2060 FPURegister ft = i.InputOrZeroSingleRegister(index);
2061 if (ft == kSingleRegZero && !__ IsSingleZeroRegSet()) {
2062 __ LoadFPRImmediate(kSingleRegZero, 0.0f);
2063 }
2064 __ UStoreFloat(ft, operand);
2065 break;
2066 }
2067 case kRiscvLoadDouble:
2068 __ LoadDouble(i.OutputDoubleRegister(), i.MemoryOperand(), trapper);
2069 break;
2070 case kRiscvULoadDouble: {
2071 __ ULoadDouble(i.OutputDoubleRegister(), i.MemoryOperand());
2072 break;
2073 }
2074 case kRiscvStoreDouble: {
2075 FPURegister ft = i.InputOrZeroDoubleRegister(0);
2076 if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
2077 __ LoadFPRImmediate(kDoubleRegZero, 0.0);
2078 }
2079 __ StoreDouble(ft, i.MemoryOperand(1), trapper);
2080 break;
2081 }
2082 case kRiscvUStoreDouble: {
2083 FPURegister ft = i.InputOrZeroDoubleRegister(2);
2084 if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
2085 __ LoadFPRImmediate(kDoubleRegZero, 0.0);
2086 }
2087 __ UStoreDouble(ft, i.MemoryOperand());
2088 break;
2089 }
2090 case kRiscvSync: {
2091 __ sync();
2092 break;
2093 }
2094 case kRiscvPush:
2095 if (instr->InputAt(0)->IsFPRegister()) {
2096 __ StoreDouble(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
2097 __ Sub32(sp, sp, Operand(kDoubleSize));
2099 } else {
2100 __ Push(i.InputOrZeroRegister(0));
2102 }
2103 break;
2104 case kRiscvPeek: {
2105 int reverse_slot = i.InputInt32(0);
2106 int offset =
2107 FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
2108 if (instr->OutputAt(0)->IsFPRegister()) {
2109 LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
2110 if (op->representation() == MachineRepresentation::kFloat64) {
2111 __ LoadDouble(i.OutputDoubleRegister(), MemOperand(fp, offset));
2112 } else {
2113 DCHECK_EQ(op->representation(), MachineRepresentation::kFloat32);
2114 __ LoadFloat(
2115 i.OutputSingleRegister(0),
2116 MemOperand(fp, offset + kLessSignificantWordInDoublewordOffset));
2117 }
2118 } else {
2119 __ LoadWord(i.OutputRegister(0), MemOperand(fp, offset));
2120 }
2121 break;
2122 }
2123 case kRiscvStackClaim: {
2124 __ SubWord(sp, sp, Operand(i.InputInt32(0)));
2125 frame_access_state()->IncreaseSPDelta(i.InputInt32(0) /
2127 break;
2128 }
2129 case kRiscvStoreToStackSlot: {
2130 if (instr->InputAt(0)->IsFPRegister()) {
2131 if (instr->InputAt(0)->IsSimd128Register()) {
2132 Register dst = sp;
2133 if (i.InputInt32(1) != 0) {
2134 dst = kScratchReg2;
2135 __ AddWord(kScratchReg2, sp, Operand(i.InputInt32(1)));
2136 }
2137 __ VU.set(kScratchReg, E8, m1);
2138 __ vs(i.InputSimd128Register(0), dst, 0, E8);
2139 } else {
2140#if V8_TARGET_ARCH_RISCV64
2141 __ StoreDouble(i.InputDoubleRegister(0),
2142 MemOperand(sp, i.InputInt32(1)));
2143#elif V8_TARGET_ARCH_RISCV32
2144 if (instr->InputAt(0)->IsDoubleRegister()) {
2145 __ StoreDouble(i.InputDoubleRegister(0),
2146 MemOperand(sp, i.InputInt32(1)));
2147 } else if (instr->InputAt(0)->IsFloatRegister()) {
2148 __ StoreFloat(i.InputSingleRegister(0),
2149 MemOperand(sp, i.InputInt32(1)));
2150 }
2151#endif
2152 }
2153 } else {
2154 __ StoreWord(i.InputOrZeroRegister(0), MemOperand(sp, i.InputInt32(1)));
2155 }
2156 break;
2157 }
2158#if V8_TARGET_ARCH_RISCV64
2159 case kRiscvByteSwap64: {
2160 __ ByteSwap(i.OutputRegister(0), i.InputRegister(0), 8, kScratchReg);
2161 break;
2162 }
2163#endif
2164 case kRiscvByteSwap32: {
2165 __ ByteSwap(i.OutputRegister(0), i.InputRegister(0), 4, kScratchReg);
2166 break;
2167 }
2168 case kAtomicLoadInt8:
2169#if V8_TARGET_ARCH_RISCV64
2171#endif
2173 break;
2174 case kAtomicLoadUint8:
2176 break;
2177 case kAtomicLoadInt16:
2178#if V8_TARGET_ARCH_RISCV64
2180#endif
2182 break;
2183 case kAtomicLoadUint16:
2185 break;
2186 case kAtomicLoadWord32:
2187#if V8_TARGET_ARCH_RISCV64
2190 break;
2191 }
2192#endif // V8_TARGET_ARCH_RISCV64
2194 break;
2195#if V8_TARGET_ARCH_RISCV64
2196 case kRiscvWord64AtomicLoadUint64:
2198 break;
2199 case kRiscvWord64AtomicStoreWord64:
2201 break;
2202#endif
2203 case kAtomicStoreWord8:
2205 break;
2206 case kAtomicStoreWord16:
2208 break;
2209 case kAtomicStoreWord32:
2211 break;
2212#if V8_TARGET_ARCH_RISCV32
2213 case kRiscvWord32AtomicPairLoad: {
2214 FrameScope scope(masm(), StackFrame::MANUAL);
2215 __ AddWord(a0, i.InputRegister(0), i.InputRegister(1));
2216 __ PushCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2217 __ PrepareCallCFunction(1, 0, kScratchReg);
2218 __ CallCFunction(ExternalReference::atomic_pair_load_function(), 1, 0);
2219 __ PopCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2220 break;
2221 }
2222 case kRiscvWord32AtomicPairStore: {
2223 FrameScope scope(masm(), StackFrame::MANUAL);
2224 __ AddWord(a0, i.InputRegister(0), i.InputRegister(1));
2225 __ PushCallerSaved(SaveFPRegsMode::kIgnore);
2226 __ PrepareCallCFunction(3, 0, kScratchReg);
2227 __ CallCFunction(ExternalReference::atomic_pair_store_function(), 3, 0);
2228 __ PopCallerSaved(SaveFPRegsMode::kIgnore);
2229 break;
2230 }
2231#define ATOMIC64_BINOP_ARITH_CASE(op, instr, external) \
2232 case kRiscvWord32AtomicPair##op: \
2233 ASSEMBLE_ATOMIC64_ARITH_BINOP(instr, external); \
2234 break;
2235 ATOMIC64_BINOP_ARITH_CASE(Add, AddPair, atomic_pair_add_function)
2236 ATOMIC64_BINOP_ARITH_CASE(Sub, SubPair, atomic_pair_sub_function)
2237#undef ATOMIC64_BINOP_ARITH_CASE
2238#define ATOMIC64_BINOP_LOGIC_CASE(op, instr, external) \
2239 case kRiscvWord32AtomicPair##op: \
2240 ASSEMBLE_ATOMIC64_LOGIC_BINOP(instr, external); \
2241 break;
2242 ATOMIC64_BINOP_LOGIC_CASE(And, AndPair, atomic_pair_and_function)
2243 ATOMIC64_BINOP_LOGIC_CASE(Or, OrPair, atomic_pair_or_function)
2244 ATOMIC64_BINOP_LOGIC_CASE(Xor, XorPair, atomic_pair_xor_function)
2245 case kRiscvWord32AtomicPairExchange: {
2246 FrameScope scope(masm(), StackFrame::MANUAL);
2247 __ PushCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2248 __ PrepareCallCFunction(3, 0, kScratchReg);
2249 __ AddWord(a0, i.InputRegister(0), i.InputRegister(1));
2250 __ CallCFunction(ExternalReference::atomic_pair_exchange_function(), 3,
2251 0);
2252 __ PopCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2253 break;
2254 }
2255 case kRiscvWord32AtomicPairCompareExchange: {
2256 FrameScope scope(masm(), StackFrame::MANUAL);
2257 __ PushCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2258 __ PrepareCallCFunction(5, 0, kScratchReg);
2259 __ add(a0, i.InputRegister(0), i.InputRegister(1));
2260 __ CallCFunction(
2261 ExternalReference::atomic_pair_compare_exchange_function(), 5, 0);
2262 __ PopCallerSaved(SaveFPRegsMode::kIgnore, a0, a1);
2263 break;
2264 }
2265#endif
2266 case kAtomicExchangeInt8:
2268 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 8, 32);
2269 break;
2270 case kAtomicExchangeUint8:
2271 switch (AtomicWidthField::decode(opcode)) {
2273 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 8, 32);
2274 break;
2276#if V8_TARGET_ARCH_RISCV64
2277 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 8, 64);
2278 break;
2279#endif
2280 default:
2281 UNREACHABLE();
2282 }
2283 break;
2284 case kAtomicExchangeInt16:
2286 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 16, 32);
2287 break;
2288 case kAtomicExchangeUint16:
2289 switch (AtomicWidthField::decode(opcode)) {
2291 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 16, 32);
2292 break;
2293#if V8_TARGET_ARCH_RISCV64
2295 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 16, 64);
2296 break;
2297#endif
2298 default:
2299 UNREACHABLE();
2300 }
2301 break;
2302 case kAtomicExchangeWord32:
2303 switch (AtomicWidthField::decode(opcode)) {
2306 break;
2307#if V8_TARGET_ARCH_RISCV64
2309 ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 32, 64);
2310 break;
2311#endif
2312 default:
2313 UNREACHABLE();
2314 }
2315 break;
2316#if V8_TARGET_ARCH_RISCV64
2317 case kRiscvWord64AtomicExchangeUint64:
2319 break;
2320#endif
2321 case kAtomicCompareExchangeInt8:
2324 break;
2325 case kAtomicCompareExchangeUint8:
2326 switch (AtomicWidthField::decode(opcode)) {
2329 break;
2330#if V8_TARGET_ARCH_RISCV64
2332 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 8, 64);
2333 break;
2334#endif
2335 default:
2336 UNREACHABLE();
2337 }
2338 break;
2339 case kAtomicCompareExchangeInt16:
2342 break;
2343 case kAtomicCompareExchangeUint16:
2344 switch (AtomicWidthField::decode(opcode)) {
2346 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 16, 32);
2347 break;
2348#if V8_TARGET_ARCH_RISCV64
2350 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 16, 64);
2351 break;
2352#endif
2353 default:
2354 UNREACHABLE();
2355 }
2356 break;
2357 case kAtomicCompareExchangeWord32:
2358 switch (AtomicWidthField::decode(opcode)) {
2360 __ Sll32(i.InputRegister(2), i.InputRegister(2), 0);
2362 break;
2363#if V8_TARGET_ARCH_RISCV64
2365 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 32, 64);
2366 break;
2367#endif
2368 default:
2369 UNREACHABLE();
2370 }
2371 break;
2372#if V8_TARGET_ARCH_RISCV64
2373 case kRiscvWord64AtomicCompareExchangeUint64:
2375 break;
2376#define ATOMIC_BINOP_CASE(op, inst32, inst64) \
2377 case kAtomic##op##Int8: \
2378 DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); \
2379 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 8, inst32, 32); \
2380 break; \
2381 case kAtomic##op##Uint8: \
2382 switch (AtomicWidthField::decode(opcode)) { \
2383 case AtomicWidth::kWord32: \
2384 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 8, inst32, 32); \
2385 break; \
2386 case AtomicWidth::kWord64: \
2387 ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 8, inst64, 64); \
2388 break; \
2389 } \
2390 break; \
2391 case kAtomic##op##Int16: \
2392 DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); \
2393 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 16, inst32, 32); \
2394 break; \
2395 case kAtomic##op##Uint16: \
2396 switch (AtomicWidthField::decode(opcode)) { \
2397 case AtomicWidth::kWord32: \
2398 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 16, inst32, 32); \
2399 break; \
2400 case AtomicWidth::kWord64: \
2401 ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 16, inst64, 64); \
2402 break; \
2403 } \
2404 break; \
2405 case kAtomic##op##Word32: \
2406 switch (AtomicWidthField::decode(opcode)) { \
2407 case AtomicWidth::kWord32: \
2408 ASSEMBLE_ATOMIC_BINOP(Ll, Sc, inst32); \
2409 break; \
2410 case AtomicWidth::kWord64: \
2411 ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 32, inst64, 64); \
2412 break; \
2413 } \
2414 break; \
2415 case kRiscvWord64Atomic##op##Uint64: \
2416 ASSEMBLE_ATOMIC_BINOP(Lld, Scd, inst64); \
2417 break;
2418 ATOMIC_BINOP_CASE(Add, Add32, AddWord)
2419 ATOMIC_BINOP_CASE(Sub, Sub32, Sub64)
2420 ATOMIC_BINOP_CASE(And, And, And)
2421 ATOMIC_BINOP_CASE(Or, Or, Or)
2422 ATOMIC_BINOP_CASE(Xor, Xor, Xor)
2423#undef ATOMIC_BINOP_CASE
2424#elif V8_TARGET_ARCH_RISCV32
2425#define ATOMIC_BINOP_CASE(op, inst32, inst64, amoinst32) \
2426 case kAtomic##op##Int8: \
2427 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 8, inst32, 32); \
2428 break; \
2429 case kAtomic##op##Uint8: \
2430 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 8, inst32, 32); \
2431 break; \
2432 case kAtomic##op##Int16: \
2433 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 16, inst32, 32); \
2434 break; \
2435 case kAtomic##op##Uint16: \
2436 ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 16, inst32, 32); \
2437 break; \
2438 case kAtomic##op##Word32: \
2439 __ AddWord(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
2440 __ amoinst32(true, true, i.OutputRegister(0), i.TempRegister(0), \
2441 i.InputRegister(2)); \
2442 break;
2443 ATOMIC_BINOP_CASE(Add, Add32, Add64, amoadd_w) // todo: delete 64
2444 ATOMIC_BINOP_CASE(Sub, Sub32, Sub64, Amosub_w) // todo: delete 64
2445 ATOMIC_BINOP_CASE(And, And, And, amoand_w)
2446 ATOMIC_BINOP_CASE(Or, Or, Or, amoor_w)
2447 ATOMIC_BINOP_CASE(Xor, Xor, Xor, amoxor_w)
2448#undef ATOMIC_BINOP_CASE
2449#endif
2450 case kRiscvAssertEqual:
2451 __ Assert(eq, static_cast<AbortReason>(i.InputOperand(2).immediate()),
2452 i.InputRegister(0), Operand(i.InputRegister(1)));
2453 break;
2454#if V8_TARGET_ARCH_RISCV64
2455 case kRiscvStoreCompressTagged: {
2456 MemOperand mem = i.MemoryOperand(1);
2457 __ StoreTaggedField(i.InputOrZeroRegister(0), mem, trapper);
2458 break;
2459 }
2460 case kRiscvLoadDecompressTaggedSigned: {
2461 CHECK(instr->HasOutput());
2462 Register result = i.OutputRegister();
2463 MemOperand operand = i.MemoryOperand();
2464 __ DecompressTaggedSigned(result, operand, trapper);
2465 break;
2466 }
2467 case kRiscvLoadDecompressTagged: {
2468 CHECK(instr->HasOutput());
2469 Register result = i.OutputRegister();
2470 MemOperand operand = i.MemoryOperand();
2471 __ DecompressTagged(result, operand, trapper);
2472 break;
2473 }
2474 case kRiscvLoadDecodeSandboxedPointer: {
2475 __ LoadSandboxedPointerField(i.OutputRegister(), i.MemoryOperand(),
2476 trapper);
2477 break;
2478 }
2479 case kRiscvStoreEncodeSandboxedPointer: {
2480 MemOperand mem = i.MemoryOperand(1);
2481 __ StoreSandboxedPointerField(i.InputOrZeroRegister(0), mem, trapper);
2482 break;
2483 }
2484 case kRiscvStoreIndirectPointer: {
2485 MemOperand mem = i.MemoryOperand(1);
2486 __ StoreIndirectPointerField(i.InputOrZeroRegister(0), mem, trapper);
2487 break;
2488 }
2489 case kRiscvAtomicLoadDecompressTaggedSigned:
2490 __ AtomicDecompressTaggedSigned(i.OutputRegister(), i.MemoryOperand(),
2491 trapper);
2492 break;
2493 case kRiscvAtomicLoadDecompressTagged:
2494 __ AtomicDecompressTagged(i.OutputRegister(), i.MemoryOperand(), trapper);
2495 break;
2496 case kRiscvAtomicStoreCompressTagged: {
2497 size_t index = 0;
2498 MemOperand mem = i.MemoryOperand(&index);
2499 __ AtomicStoreTaggedField(i.InputOrZeroRegister(index), mem, trapper);
2500 break;
2501 }
2502 case kRiscvLoadDecompressProtected: {
2503 __ DecompressProtected(i.OutputRegister(), i.MemoryOperand(), trapper);
2504 break;
2505 }
2506#endif
2507 case kRiscvRvvSt: {
2508 (__ VU).set(kScratchReg, VSew::E8, Vlmul::m1);
2509 auto memOperand = i.MemoryOperand(1);
2510 Register dst = memOperand.offset() == 0 ? memOperand.rm() : kScratchReg;
2511 if (memOperand.offset() != 0) {
2512 __ AddWord(dst, memOperand.rm(), memOperand.offset());
2513 }
2514 trapper(__ pc_offset());
2515 __ vs(i.InputSimd128Register(0), dst, 0, VSew::E8);
2516 break;
2517 }
2518 case kRiscvRvvLd: {
2519 (__ VU).set(kScratchReg, VSew::E8, Vlmul::m1);
2520 Register src = i.MemoryOperand().offset() == 0 ? i.MemoryOperand().rm()
2521 : kScratchReg;
2522 if (i.MemoryOperand().offset() != 0) {
2523 __ AddWord(src, i.MemoryOperand().rm(), i.MemoryOperand().offset());
2524 }
2525 trapper(__ pc_offset());
2526 __ vl(i.OutputSimd128Register(), src, 0, VSew::E8);
2527 break;
2528 }
2529 case kRiscvS128Zero: {
2530 Simd128Register dst = i.OutputSimd128Register();
2531 __ VU.set(kScratchReg, E8, m1);
2532 __ vmv_vx(dst, zero_reg);
2533 break;
2534 }
2535 case kRiscvS128Load32Zero: {
2536 Simd128Register dst = i.OutputSimd128Register();
2537 __ VU.set(kScratchReg, E32, m1);
2538 __ Load32U(kScratchReg, i.MemoryOperand(), trapper);
2539 __ vmv_sx(dst, kScratchReg);
2540 break;
2541 }
2542 case kRiscvS128Load64Zero: {
2543 Simd128Register dst = i.OutputSimd128Register();
2544 __ VU.set(kScratchReg, E64, m1);
2545#if V8_TARGET_ARCH_RISCV64
2546 __ LoadWord(kScratchReg, i.MemoryOperand(), trapper);
2547 __ vmv_sx(dst, kScratchReg);
2548#elif V8_TARGET_ARCH_RISCV32
2549 __ LoadDouble(kScratchDoubleReg, i.MemoryOperand(), trapper);
2550 __ vfmv_sf(dst, kScratchDoubleReg);
2551#endif
2552 break;
2553 }
2554 case kRiscvS128LoadLane: {
2555 Simd128Register dst = i.OutputSimd128Register();
2556 DCHECK_EQ(dst, i.InputSimd128Register(0));
2557 auto sz = LaneSizeField::decode(opcode);
2558 __ LoadLane(sz, dst, i.InputUint8(1), i.MemoryOperand(2), trapper);
2559 break;
2560 }
2561 case kRiscvS128StoreLane: {
2562 Simd128Register src = i.InputSimd128Register(0);
2563 DCHECK_EQ(src, i.InputSimd128Register(0));
2564 auto sz = LaneSizeField::decode(opcode);
2565 __ StoreLane(sz, src, i.InputUint8(1), i.MemoryOperand(2), trapper);
2566 break;
2567 }
2568 case kRiscvS128Load64ExtendS: {
2569 __ VU.set(kScratchReg, E64, m1);
2570#if V8_TARGET_ARCH_RISCV64
2571 __ LoadWord(kScratchReg, i.MemoryOperand(), trapper);
2573#elif V8_TARGET_ARCH_RISCV32
2574 __ LoadDouble(kScratchDoubleReg, i.MemoryOperand(), trapper);
2576#endif
2577 __ VU.set(kScratchReg, i.InputInt8(2), m1);
2578 __ vsext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
2579 break;
2580 }
2581 case kRiscvS128Load64ExtendU: {
2582 __ VU.set(kScratchReg, E64, m1);
2583#if V8_TARGET_ARCH_RISCV64
2584 __ LoadWord(kScratchReg, i.MemoryOperand(), trapper);
2586#elif V8_TARGET_ARCH_RISCV32
2587 __ LoadDouble(kScratchDoubleReg, i.MemoryOperand(), trapper);
2589#endif
2590 __ VU.set(kScratchReg, i.InputInt8(2), m1);
2591 __ vzext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
2592 break;
2593 }
2594 case kRiscvS128LoadSplat: {
2595 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
2596 switch (i.InputInt8(2)) {
2597 case E8:
2598 __ Lb(kScratchReg, i.MemoryOperand(), trapper);
2599 __ vmv_vx(i.OutputSimd128Register(), kScratchReg);
2600 break;
2601 case E16:
2602 __ Lh(kScratchReg, i.MemoryOperand(), trapper);
2603 __ vmv_vx(i.OutputSimd128Register(), kScratchReg);
2604 break;
2605 case E32:
2606 __ Lw(kScratchReg, i.MemoryOperand(), trapper);
2607 __ vmv_vx(i.OutputSimd128Register(), kScratchReg);
2608 break;
2609 case E64:
2610#if V8_TARGET_ARCH_RISCV64
2611 __ LoadWord(kScratchReg, i.MemoryOperand(), trapper);
2612 __ vmv_vx(i.OutputSimd128Register(), kScratchReg);
2613#elif V8_TARGET_ARCH_RISCV32
2614 __ LoadDouble(kScratchDoubleReg, i.MemoryOperand(), trapper);
2615 __ vfmv_vf(i.OutputSimd128Register(), kScratchDoubleReg);
2616#endif
2617 break;
2618 default:
2619 UNREACHABLE();
2620 }
2621 break;
2622 }
2623 case kRiscvS128AllOnes: {
2624 __ VU.set(kScratchReg, E8, m1);
2625 __ vmv_vx(i.OutputSimd128Register(), zero_reg);
2626 __ vnot_vv(i.OutputSimd128Register(), i.OutputSimd128Register());
2627 break;
2628 }
2629 case kRiscvS128Select: {
2630 __ VU.set(kScratchReg, E8, m1);
2631 __ vand_vv(kSimd128ScratchReg, i.InputSimd128Register(1),
2632 i.InputSimd128Register(0));
2633 __ vnot_vv(kSimd128ScratchReg2, i.InputSimd128Register(0));
2634 __ vand_vv(kSimd128ScratchReg2, i.InputSimd128Register(2),
2636 __ vor_vv(i.OutputSimd128Register(), kSimd128ScratchReg,
2638 break;
2639 }
2640 case kRiscvVnot: {
2641 (__ VU).set(kScratchReg, VSew::E8, Vlmul::m1);
2642 __ vnot_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
2643 break;
2644 }
2645 case kRiscvS128Const: {
2646 Simd128Register dst = i.OutputSimd128Register();
2647 uint8_t imm[16];
2648 *reinterpret_cast<uint64_t*>(imm) =
2649 make_uint64(i.InputUint32(1), i.InputUint32(0));
2650 *(reinterpret_cast<uint64_t*>(imm) + 1) =
2651 make_uint64(i.InputUint32(3), i.InputUint32(2));
2652 __ WasmRvvS128const(dst, imm);
2653 break;
2654 }
2655 case kRiscvVrgather: {
2656 Simd128Register index = i.InputSimd128Register(0);
2657 if (!(instr->InputAt(1)->IsImmediate())) {
2658 index = i.InputSimd128Register(1);
2659 } else {
2660#if V8_TARGET_ARCH_RISCV64
2661 __ VU.set(kScratchReg, E64, m1);
2662 __ li(kScratchReg, i.InputInt64(1));
2663 __ vmv_vi(kSimd128ScratchReg3, -1);
2665 index = kSimd128ScratchReg3;
2666#elif V8_TARGET_ARCH_RISCV32
2667 int64_t intput_int64 = i.InputInt64(1);
2668 int32_t input_int32[2];
2669 memcpy(input_int32, &intput_int64, sizeof(intput_int64));
2670 __ VU.set(kScratchReg, E32, m1);
2671 __ li(kScratchReg, input_int32[1]);
2673 __ li(kScratchReg, input_int32[0]);
2675 index = kSimd128ScratchReg3;
2676#endif
2677 }
2678 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
2679 if (i.OutputSimd128Register() == i.InputSimd128Register(0)) {
2680 __ vrgather_vv(kSimd128ScratchReg, i.InputSimd128Register(0), index);
2681 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg);
2682 } else {
2683 __ vrgather_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
2684 index);
2685 }
2686 break;
2687 }
2688 case kRiscvVslidedown: {
2689 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
2690 if (instr->InputAt(1)->IsImmediate()) {
2691 DCHECK(is_uint5(i.InputInt32(1)));
2692 __ vslidedown_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2693 i.InputInt5(1));
2694 } else {
2695 __ vslidedown_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2696 i.InputRegister(1));
2697 }
2698 break;
2699 }
2700 case kRiscvI8x16ExtractLaneU: {
2701 __ VU.set(kScratchReg, E8, m1);
2702 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2703 i.InputInt8(1));
2704 __ vmv_xs(i.OutputRegister(), kSimd128ScratchReg);
2705 __ slli(i.OutputRegister(), i.OutputRegister(), sizeof(void*) * 8 - 8);
2706 __ srli(i.OutputRegister(), i.OutputRegister(), sizeof(void*) * 8 - 8);
2707 break;
2708 }
2709 case kRiscvI8x16ExtractLaneS: {
2710 __ VU.set(kScratchReg, E8, m1);
2711 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2712 i.InputInt8(1));
2713 __ vmv_xs(i.OutputRegister(), kSimd128ScratchReg);
2714 break;
2715 }
2716 case kRiscvI16x8ExtractLaneU: {
2717 __ VU.set(kScratchReg, E16, m1);
2718 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2719 i.InputInt8(1));
2720 __ vmv_xs(i.OutputRegister(), kSimd128ScratchReg);
2721 __ slli(i.OutputRegister(), i.OutputRegister(), sizeof(void*) * 8 - 16);
2722 __ srli(i.OutputRegister(), i.OutputRegister(), sizeof(void*) * 8 - 16);
2723 break;
2724 }
2725 case kRiscvI16x8ExtractLaneS: {
2726 __ VU.set(kScratchReg, E16, m1);
2727 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2728 i.InputInt8(1));
2729 __ vmv_xs(i.OutputRegister(), kSimd128ScratchReg);
2730 break;
2731 }
2732 case kRiscvI8x16ShrU: {
2733 __ VU.set(kScratchReg, E8, m1);
2734 if (instr->InputAt(1)->IsRegister()) {
2735 __ andi(i.InputRegister(1), i.InputRegister(1), 8 - 1);
2736 __ vsrl_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2737 i.InputRegister(1));
2738 } else {
2739 __ vsrl_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2740 i.InputInt5(1) % 8);
2741 }
2742 break;
2743 }
2744 case kRiscvI16x8ShrU: {
2745 __ VU.set(kScratchReg, E16, m1);
2746 if (instr->InputAt(1)->IsRegister()) {
2747 __ andi(i.InputRegister(1), i.InputRegister(1), 16 - 1);
2748 __ vsrl_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2749 i.InputRegister(1));
2750 } else {
2751 __ vsrl_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2752 i.InputInt5(1) % 16);
2753 }
2754 break;
2755 }
2756 case kRiscvI32x4TruncSatF64x2SZero: {
2757 __ VU.set(kScratchReg, E64, m1);
2758 __ vmv_vx(kSimd128ScratchReg, zero_reg);
2759 __ vmfeq_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(0));
2760 __ vmv_vv(kSimd128ScratchReg3, i.InputSimd128Register(0));
2761 __ VU.set(kScratchReg, E32, m1);
2762 __ VU.set(FPURoundingMode::RTZ);
2764 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg);
2765 break;
2766 }
2767 case kRiscvI32x4TruncSatF64x2UZero: {
2768 __ VU.set(kScratchReg, E64, m1);
2769 __ vmv_vx(kSimd128ScratchReg, zero_reg);
2770 __ vmfeq_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(0));
2771 __ vmv_vv(kSimd128ScratchReg3, i.InputSimd128Register(0));
2772 __ VU.set(kScratchReg, E32, m1);
2773 __ VU.set(FPURoundingMode::RTZ);
2775 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg);
2776 break;
2777 }
2778 case kRiscvI32x4ShrU: {
2779 __ VU.set(kScratchReg, E32, m1);
2780 if (instr->InputAt(1)->IsRegister()) {
2781 __ vsrl_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2782 i.InputRegister(1));
2783 } else {
2784 __ vsrl_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2785 i.InputInt5(1) % 32);
2786 }
2787 break;
2788 }
2789 case kRiscvI64x2ShrU: {
2790 __ VU.set(kScratchReg, E64, m1);
2791 if (instr->InputAt(1)->IsRegister()) {
2792 __ vsrl_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2793 i.InputRegister(1));
2794 } else {
2795 if (is_uint5(i.InputInt6(1) % 64)) {
2796 __ vsrl_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2797 i.InputInt6(1) % 64);
2798 } else {
2799 __ li(kScratchReg, i.InputInt6(1) % 64);
2800 __ vsrl_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2801 kScratchReg);
2802 }
2803 }
2804 break;
2805 }
2806 case kRiscvI8x16ShrS: {
2807 __ VU.set(kScratchReg, E8, m1);
2808 if (instr->InputAt(1)->IsRegister()) {
2809 __ vsra_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2810 i.InputRegister(1));
2811 } else {
2812 __ vsra_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2813 i.InputInt5(1) % 8);
2814 }
2815 break;
2816 }
2817 case kRiscvI16x8ShrS: {
2818 __ VU.set(kScratchReg, E16, m1);
2819 if (instr->InputAt(1)->IsRegister()) {
2820 __ vsra_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2821 i.InputRegister(1));
2822 } else {
2823 __ vsra_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2824 i.InputInt5(1) % 16);
2825 }
2826 break;
2827 }
2828 case kRiscvI32x4ShrS: {
2829 __ VU.set(kScratchReg, E32, m1);
2830 if (instr->InputAt(1)->IsRegister()) {
2831 __ vsra_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2832 i.InputRegister(1));
2833 } else {
2834 __ vsra_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2835 i.InputInt5(1) % 32);
2836 }
2837 break;
2838 }
2839 case kRiscvI64x2ShrS: {
2840 __ VU.set(kScratchReg, E64, m1);
2841 if (instr->InputAt(1)->IsRegister()) {
2842 __ vsra_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2843 i.InputRegister(1));
2844 } else {
2845 if (is_uint5(i.InputInt6(1) % 64)) {
2846 __ vsra_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2847 i.InputInt6(1) % 64);
2848 } else {
2849 __ li(kScratchReg, i.InputInt6(1) % 64);
2850 __ vsra_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2851 kScratchReg);
2852 }
2853 }
2854 break;
2855 }
2856 case kRiscvI32x4ExtractLane: {
2857 __ WasmRvvExtractLane(i.OutputRegister(), i.InputSimd128Register(0),
2858 i.InputInt8(1), E32, m1);
2859 break;
2860 }
2861 case kRiscvVAbs: {
2862 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
2863 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
2864 __ vmslt_vx(v0, i.InputSimd128Register(0), zero_reg);
2865 __ vneg_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
2867 break;
2868 }
2869#if V8_TARGET_ARCH_RISCV64
2870 case kRiscvI64x2ExtractLane: {
2871 __ WasmRvvExtractLane(i.OutputRegister(), i.InputSimd128Register(0),
2872 i.InputInt8(1), E64, m1);
2873 break;
2874 }
2875#elif V8_TARGET_ARCH_RISCV32
2876 case kRiscvI64x2ExtractLane: {
2877 uint8_t imm_lane_idx = i.InputInt8(1);
2878 __ VU.set(kScratchReg, E32, m1);
2879 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2880 (imm_lane_idx << 0x1) + 1);
2881 __ vmv_xs(i.OutputRegister(1), kSimd128ScratchReg);
2882 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
2883 (imm_lane_idx << 0x1));
2884 __ vmv_xs(i.OutputRegister(0), kSimd128ScratchReg);
2885 break;
2886 }
2887#endif
2888 case kRiscvI8x16Shl: {
2889 __ VU.set(kScratchReg, E8, m1);
2890 if (instr->InputAt(1)->IsRegister()) {
2891 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2892 i.InputRegister(1));
2893 } else {
2894 __ vsll_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2895 i.InputInt5(1) % 8);
2896 }
2897 break;
2898 }
2899 case kRiscvI16x8Shl: {
2900 __ VU.set(kScratchReg, E16, m1);
2901 if (instr->InputAt(1)->IsRegister()) {
2902 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2903 i.InputRegister(1));
2904 } else {
2905 __ vsll_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2906 i.InputInt5(1) % 16);
2907 }
2908 break;
2909 }
2910 case kRiscvI32x4Shl: {
2911 __ VU.set(kScratchReg, E32, m1);
2912 if (instr->InputAt(1)->IsRegister()) {
2913 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2914 i.InputRegister(1));
2915 } else {
2916 __ vsll_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2917 i.InputInt5(1) % 32);
2918 }
2919 break;
2920 }
2921 case kRiscvI64x2Shl: {
2922 __ VU.set(kScratchReg, E64, m1);
2923 if (instr->InputAt(1)->IsRegister()) {
2924 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2925 i.InputRegister(1));
2926 } else {
2927 if (is_int5(i.InputInt6(1) % 64)) {
2928 __ vsll_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
2929 i.InputInt6(1) % 64);
2930 } else {
2931 __ li(kScratchReg, i.InputInt6(1) % 64);
2932 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
2933 kScratchReg);
2934 }
2935 }
2936 break;
2937 }
2938 case kRiscvI8x16ReplaceLane: {
2939 Simd128Register src = i.InputSimd128Register(0);
2940 Simd128Register dst = i.OutputSimd128Register();
2941 __ VU.set(kScratchReg, E64, m1);
2942 __ li(kScratchReg, 0x1 << i.InputInt8(1));
2943 __ vmv_sx(v0, kScratchReg);
2944 __ VU.set(kScratchReg, E8, m1);
2945 __ vmerge_vx(dst, i.InputRegister(2), src);
2946 break;
2947 }
2948 case kRiscvI16x8ReplaceLane: {
2949 Simd128Register src = i.InputSimd128Register(0);
2950 Simd128Register dst = i.OutputSimd128Register();
2951 __ VU.set(kScratchReg, E16, m1);
2952 __ li(kScratchReg, 0x1 << i.InputInt8(1));
2953 __ vmv_sx(v0, kScratchReg);
2954 __ vmerge_vx(dst, i.InputRegister(2), src);
2955 break;
2956 }
2957#if V8_TARGET_ARCH_RISCV64
2958 case kRiscvI64x2ReplaceLane: {
2959 Simd128Register src = i.InputSimd128Register(0);
2960 Simd128Register dst = i.OutputSimd128Register();
2961 __ VU.set(kScratchReg, E64, m1);
2962 __ li(kScratchReg, 0x1 << i.InputInt8(1));
2963 __ vmv_sx(v0, kScratchReg);
2964 __ vmerge_vx(dst, i.InputRegister(2), src);
2965 break;
2966 }
2967#elif V8_TARGET_ARCH_RISCV32
2968 case kRiscvI64x2ReplaceLaneI32Pair: {
2969 Simd128Register src = i.InputSimd128Register(0);
2970 Simd128Register dst = i.OutputSimd128Register();
2971 Register int64_low = i.InputRegister(2);
2972 Register int64_high = i.InputRegister(3);
2973 __ VU.set(kScratchReg, E32, m1);
2974 __ vmv_vx(kSimd128ScratchReg, int64_high);
2975 __ vmv_sx(kSimd128ScratchReg, int64_low);
2976 __ VU.set(kScratchReg, E64, m1);
2977 __ li(kScratchReg, 0x1 << i.InputInt8(1));
2978 __ vmv_sx(v0, kScratchReg);
2980 __ vfmerge_vf(dst, kScratchDoubleReg, src);
2981 break;
2982 }
2983#endif
2984 case kRiscvI32x4ReplaceLane: {
2985 Simd128Register src = i.InputSimd128Register(0);
2986 Simd128Register dst = i.OutputSimd128Register();
2987 __ VU.set(kScratchReg, E32, m1);
2988 __ li(kScratchReg, 0x1 << i.InputInt8(1));
2989 __ vmv_sx(v0, kScratchReg);
2990 __ vmerge_vx(dst, i.InputRegister(2), src);
2991 break;
2992 }
2993 case kRiscvV128AnyTrue: {
2994 __ VU.set(kScratchReg, E8, m1);
2995 Register dst = i.OutputRegister();
2996 Label t;
2997 __ vmv_sx(kSimd128ScratchReg, zero_reg);
2998 __ vredmaxu_vs(kSimd128ScratchReg, i.InputSimd128Register(0),
3000 __ vmv_xs(dst, kSimd128ScratchReg);
3001 __ beq(dst, zero_reg, &t);
3002 __ li(dst, 1);
3003 __ bind(&t);
3004 break;
3005 }
3006 case kRiscvVAllTrue: {
3007 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3008 Register dst = i.OutputRegister();
3009 Label notalltrue;
3010 __ vmv_vi(kSimd128ScratchReg, -1);
3011 __ vredminu_vs(kSimd128ScratchReg, i.InputSimd128Register(0),
3013 __ vmv_xs(dst, kSimd128ScratchReg);
3014 __ beqz(dst, &notalltrue);
3015 __ li(dst, 1);
3016 __ bind(&notalltrue);
3017 break;
3018 }
3019 case kRiscvI8x16Shuffle: {
3020 VRegister dst = i.OutputSimd128Register(),
3021 src0 = i.InputSimd128Register(0),
3022 src1 = i.InputSimd128Register(1);
3023
3024#if V8_TARGET_ARCH_RISCV64
3025 int64_t imm1 = make_uint64(i.InputInt32(3), i.InputInt32(2));
3026 int64_t imm2 = make_uint64(i.InputInt32(5), i.InputInt32(4));
3027 __ VU.set(kScratchReg, VSew::E64, Vlmul::m1);
3028 __ li(kScratchReg, imm2);
3030 __ vslideup_vi(kSimd128ScratchReg, kSimd128ScratchReg2, 1);
3031 __ li(kScratchReg, imm1);
3033#elif V8_TARGET_ARCH_RISCV32
3034 __ VU.set(kScratchReg, VSew::E32, Vlmul::m1);
3035 __ li(kScratchReg, i.InputInt32(5));
3037 __ li(kScratchReg, i.InputInt32(4));
3039 __ li(kScratchReg, i.InputInt32(3));
3041 __ li(kScratchReg, i.InputInt32(2));
3043 __ vslideup_vi(kSimd128ScratchReg, kSimd128ScratchReg2, 2);
3044#endif
3045
3046 __ VU.set(kScratchReg, E8, m1);
3047 if (dst == src0) {
3048 __ vmv_vv(kSimd128ScratchReg2, src0);
3049 src0 = kSimd128ScratchReg2;
3050 } else if (dst == src1) {
3051 __ vmv_vv(kSimd128ScratchReg2, src1);
3052 src1 = kSimd128ScratchReg2;
3053 }
3054 __ vrgather_vv(dst, src0, kSimd128ScratchReg);
3056 __ vrgather_vv(kSimd128ScratchReg3, src1, kSimd128ScratchReg);
3057 __ vor_vv(dst, dst, kSimd128ScratchReg3);
3058 break;
3059 }
3060 case kRiscvI8x16Popcnt: {
3061 VRegister dst = i.OutputSimd128Register(),
3062 src = i.InputSimd128Register(0);
3063 Label t;
3064
3065 __ VU.set(kScratchReg, E8, m1);
3066 __ vmv_vv(kSimd128ScratchReg, src);
3067 __ vmv_vv(dst, kSimd128RegZero);
3068
3069 __ bind(&t);
3070 __ vmsne_vv(v0, kSimd128ScratchReg, kSimd128RegZero);
3071 __ vadd_vi(dst, dst, 1, Mask);
3074 // kScratchReg = -1 if kSimd128ScratchReg == 0 i.e. no active element
3076 __ bgez(kScratchReg, &t);
3077 break;
3078 }
3079 case kRiscvF64x2NearestInt: {
3080 __ Round_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
3082 break;
3083 }
3084 case kRiscvF64x2Trunc: {
3085 __ Trunc_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
3087 break;
3088 }
3089 case kRiscvF64x2Sqrt: {
3090 __ VU.set(kScratchReg, E64, m1);
3091 __ vfsqrt_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3092 break;
3093 }
3094 case kRiscvF64x2Abs: {
3095 __ VU.set(kScratchReg, VSew::E64, Vlmul::m1);
3096 __ vfabs_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3097 break;
3098 }
3099 case kRiscvF64x2Ceil: {
3100 __ Ceil_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
3102 break;
3103 }
3104 case kRiscvF64x2Floor: {
3105 __ Floor_d(i.OutputSimd128Register(), i.InputSimd128Register(0),
3107 break;
3108 }
3109 case kRiscvF64x2ReplaceLane: {
3110 __ VU.set(kScratchReg, E64, m1);
3111 __ li(kScratchReg, 0x1 << i.InputInt8(1));
3112 __ vmv_sx(v0, kScratchReg);
3113 __ vfmerge_vf(i.OutputSimd128Register(), i.InputSingleRegister(2),
3114 i.InputSimd128Register(0));
3115 break;
3116 }
3117 case kRiscvF64x2Pmax: {
3118 __ VU.set(kScratchReg, E64, m1);
3119 __ vmflt_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(1));
3120 __ vmerge_vv(i.OutputSimd128Register(), i.InputSimd128Register(1),
3121 i.InputSimd128Register(0));
3122 break;
3123 }
3124 case kRiscvF64x2Pmin: {
3125 __ VU.set(kScratchReg, E64, m1);
3126 __ vmflt_vv(v0, i.InputSimd128Register(1), i.InputSimd128Register(0));
3127 __ vmerge_vv(i.OutputSimd128Register(), i.InputSimd128Register(1),
3128 i.InputSimd128Register(0));
3129 break;
3130 }
3131 case kRiscvF64x2ExtractLane: {
3132 __ VU.set(kScratchReg, E64, m1);
3133 if (is_uint5(i.InputInt8(1))) {
3134 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
3135 i.InputInt8(1));
3136 } else {
3137 __ li(kScratchReg, i.InputInt8(1));
3138 __ vslidedown_vx(kSimd128ScratchReg, i.InputSimd128Register(0),
3139 kScratchReg);
3140 }
3141 __ vfmv_fs(i.OutputDoubleRegister(), kSimd128ScratchReg);
3142 break;
3143 }
3144 case kRiscvF64x2PromoteLowF32x4: {
3145 __ VU.set(kScratchReg, E32, mf2);
3146 if (i.OutputSimd128Register() != i.InputSimd128Register(0)) {
3147 __ vfwcvt_f_f_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3148 } else {
3149 __ vfwcvt_f_f_v(kSimd128ScratchReg3, i.InputSimd128Register(0));
3150 __ VU.set(kScratchReg, E64, m1);
3151 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg3);
3152 }
3153 break;
3154 }
3155 case kRiscvF64x2ConvertLowI32x4S: {
3156 __ VU.set(kScratchReg, E32, mf2);
3157 if (i.OutputSimd128Register() != i.InputSimd128Register(0)) {
3158 __ vfwcvt_f_x_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3159 } else {
3160 __ vfwcvt_f_x_v(kSimd128ScratchReg3, i.InputSimd128Register(0));
3161 __ VU.set(kScratchReg, E64, m1);
3162 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg3);
3163 }
3164 break;
3165 }
3166 case kRiscvF64x2ConvertLowI32x4U: {
3167 __ VU.set(kScratchReg, E32, mf2);
3168 if (i.OutputSimd128Register() != i.InputSimd128Register(0)) {
3169 __ vfwcvt_f_xu_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3170 } else {
3171 __ vfwcvt_f_xu_v(kSimd128ScratchReg3, i.InputSimd128Register(0));
3172 __ VU.set(kScratchReg, E64, m1);
3173 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg3);
3174 }
3175 break;
3176 }
3177 case kRiscvF64x2Qfma: {
3178 __ VU.set(kScratchReg, E64, m1);
3179 __ vfmadd_vv(i.InputSimd128Register(0), i.InputSimd128Register(1),
3180 i.InputSimd128Register(2));
3181 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3182 break;
3183 }
3184 case kRiscvF64x2Qfms: {
3185 __ VU.set(kScratchReg, E64, m1);
3186 __ vfnmsub_vv(i.InputSimd128Register(0), i.InputSimd128Register(1),
3187 i.InputSimd128Register(2));
3188 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3189 break;
3190 }
3191 case kRiscvF32x4ExtractLane: {
3192 __ VU.set(kScratchReg, E32, m1);
3193 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0),
3194 i.InputInt8(1));
3195 __ vfmv_fs(i.OutputDoubleRegister(), kSimd128ScratchReg);
3196 break;
3197 }
3198 case kRiscvF32x4Trunc: {
3199 __ Trunc_f(i.OutputSimd128Register(), i.InputSimd128Register(0),
3201 break;
3202 }
3203 case kRiscvF32x4NearestInt: {
3204 __ Round_f(i.OutputSimd128Register(), i.InputSimd128Register(0),
3206 break;
3207 }
3208 case kRiscvF32x4DemoteF64x2Zero: {
3209 __ VU.set(kScratchReg, E32, mf2);
3210 __ vfncvt_f_f_w(i.OutputSimd128Register(), i.InputSimd128Register(0));
3211 __ VU.set(kScratchReg, E32, m1);
3212 __ vmv_vi(v0, 12);
3213 __ vmerge_vx(i.OutputSimd128Register(), zero_reg,
3214 i.OutputSimd128Register());
3215 break;
3216 }
3217 case kRiscvF32x4Abs: {
3218 __ VU.set(kScratchReg, VSew::E32, Vlmul::m1);
3219 __ vfabs_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3220 break;
3221 }
3222 case kRiscvF32x4Ceil: {
3223 __ Ceil_f(i.OutputSimd128Register(), i.InputSimd128Register(0),
3225 break;
3226 }
3227 case kRiscvF32x4Floor: {
3228 __ Floor_f(i.OutputSimd128Register(), i.InputSimd128Register(0),
3230 break;
3231 }
3232 case kRiscvF32x4UConvertI32x4: {
3233 __ VU.set(kScratchReg, E32, m1);
3234 __ VU.set(FPURoundingMode::RTZ);
3235 __ vfcvt_f_xu_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3236 break;
3237 }
3238 case kRiscvF32x4SConvertI32x4: {
3239 __ VU.set(kScratchReg, E32, m1);
3240 __ VU.set(FPURoundingMode::RTZ);
3241 __ vfcvt_f_x_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3242 break;
3243 }
3244 case kRiscvF32x4ReplaceLane: {
3245 __ VU.set(kScratchReg, E32, m1);
3246 __ li(kScratchReg, 0x1 << i.InputInt8(1));
3247 __ vmv_sx(v0, kScratchReg);
3248 __ fmv_x_w(kScratchReg, i.InputSingleRegister(2));
3249 __ vmerge_vx(i.OutputSimd128Register(), kScratchReg,
3250 i.InputSimd128Register(0));
3251 break;
3252 }
3253 case kRiscvF32x4Pmax: {
3254 __ VU.set(kScratchReg, E32, m1);
3255 __ vmflt_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(1));
3256 __ vmerge_vv(i.OutputSimd128Register(), i.InputSimd128Register(1),
3257 i.InputSimd128Register(0));
3258 break;
3259 }
3260 case kRiscvF32x4Pmin: {
3261 __ VU.set(kScratchReg, E32, m1);
3262 __ vmflt_vv(v0, i.InputSimd128Register(1), i.InputSimd128Register(0));
3263 __ vmerge_vv(i.OutputSimd128Register(), i.InputSimd128Register(1),
3264 i.InputSimd128Register(0));
3265 break;
3266 }
3267 case kRiscvF32x4Sqrt: {
3268 __ VU.set(kScratchReg, E32, m1);
3269 __ vfsqrt_v(i.OutputSimd128Register(), i.InputSimd128Register(0));
3270 break;
3271 }
3272 case kRiscvF32x4Qfma: {
3273 __ VU.set(kScratchReg, E32, m1);
3274 __ vfmadd_vv(i.InputSimd128Register(0), i.InputSimd128Register(1),
3275 i.InputSimd128Register(2));
3276 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3277 break;
3278 }
3279 case kRiscvF32x4Qfms: {
3280 __ VU.set(kScratchReg, E32, m1);
3281 __ vfnmsub_vv(i.InputSimd128Register(0), i.InputSimd128Register(1),
3282 i.InputSimd128Register(2));
3283 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3284 break;
3285 }
3286 case kRiscvI64x2SConvertI32x4Low: {
3287 __ VU.set(kScratchReg, E64, m1);
3288 __ vmv_vv(kSimd128ScratchReg, i.InputSimd128Register(0));
3289 __ vsext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
3290
3291 break;
3292 }
3293 case kRiscvI64x2SConvertI32x4High: {
3294 __ VU.set(kScratchReg, E32, m1);
3295 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0), 2);
3296 __ VU.set(kScratchReg, E64, m1);
3297 __ vsext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
3298 break;
3299 }
3300 case kRiscvI64x2UConvertI32x4Low: {
3301 __ VU.set(kScratchReg, E64, m1);
3302 __ vmv_vv(kSimd128ScratchReg, i.InputSimd128Register(0));
3303 __ vzext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
3304 break;
3305 }
3306 case kRiscvI64x2UConvertI32x4High: {
3307 __ VU.set(kScratchReg, E32, m1);
3308 __ vslidedown_vi(kSimd128ScratchReg, i.InputSimd128Register(0), 2);
3309 __ VU.set(kScratchReg, E64, m1);
3310 __ vzext_vf2(i.OutputSimd128Register(), kSimd128ScratchReg);
3311 break;
3312 }
3313 case kRiscvI32x4SConvertF32x4: {
3314 __ VU.set(kScratchReg, E32, m1);
3315 __ VU.set(FPURoundingMode::RTZ);
3316 __ vmfeq_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(0));
3317 if (i.OutputSimd128Register() != i.InputSimd128Register(0)) {
3318 __ vmv_vx(i.OutputSimd128Register(), zero_reg);
3319 __ vfcvt_x_f_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3320 Mask);
3321 } else {
3322 __ vmv_vx(kSimd128ScratchReg, zero_reg);
3323 __ vfcvt_x_f_v(kSimd128ScratchReg, i.InputSimd128Register(0), Mask);
3324 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg);
3325 }
3326 break;
3327 }
3328 case kRiscvI32x4UConvertF32x4: {
3329 __ VU.set(kScratchReg, E32, m1);
3330 __ VU.set(FPURoundingMode::RTZ);
3331 __ vmfeq_vv(v0, i.InputSimd128Register(0), i.InputSimd128Register(0));
3332 if (i.OutputSimd128Register() != i.InputSimd128Register(0)) {
3333 __ vmv_vx(i.OutputSimd128Register(), zero_reg);
3334 __ vfcvt_xu_f_v(i.OutputSimd128Register(), i.InputSimd128Register(0),
3335 Mask);
3336 } else {
3337 __ vmv_vx(kSimd128ScratchReg, zero_reg);
3338 __ vfcvt_xu_f_v(kSimd128ScratchReg, i.InputSimd128Register(0), Mask);
3339 __ vmv_vv(i.OutputSimd128Register(), kSimd128ScratchReg);
3340 }
3341 break;
3342 }
3343#if V8_TARGET_ARCH_RISCV32
3344 case kRiscvI64x2SplatI32Pair: {
3345 __ VU.set(kScratchReg, E32, m1);
3346 __ vmv_vi(v0, 0b0101);
3347 __ vmv_vx(kSimd128ScratchReg, i.InputRegister(1));
3348 __ vmerge_vx(i.OutputSimd128Register(), i.InputRegister(0),
3350 break;
3351 }
3352#endif
3353 case kRiscvVwaddVv: {
3354 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3355 __ vwadd_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3356 i.InputSimd128Register(1));
3357 break;
3358 }
3359 case kRiscvVwadduVv: {
3360 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3361 __ vwaddu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3362 i.InputSimd128Register(1));
3363 break;
3364 }
3365 case kRiscvVwadduWx: {
3366 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3367 if (instr->InputAt(1)->IsRegister()) {
3368 __ vwaddu_wx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3369 i.InputRegister(1));
3370 } else {
3371 __ li(kScratchReg, i.InputInt64(1));
3372 __ vwaddu_wx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3373 kScratchReg);
3374 }
3375 break;
3376 }
3377 case kRiscvVdivu: {
3378 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3379 if (instr->InputAt(1)->IsSimd128Register()) {
3380 __ vdivu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3381 i.InputSimd128Register(1));
3382 } else if ((instr->InputAt(1)->IsRegister())) {
3383 __ vdivu_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3384 i.InputRegister(1));
3385 } else {
3386 __ li(kScratchReg, i.InputInt64(1));
3387 __ vdivu_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3388 kScratchReg);
3389 }
3390 break;
3391 }
3392 case kRiscvVnclipu: {
3393 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3394 __ VU.set(FPURoundingMode(i.InputInt8(4)));
3395 if (instr->InputAt(1)->IsSimd128Register()) {
3396 __ vnclipu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3397 i.InputSimd128Register(1));
3398 } else if (instr->InputAt(1)->IsRegister()) {
3399 __ vnclipu_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3400 i.InputRegister(1));
3401 } else {
3402 DCHECK(instr->InputAt(1)->IsImmediate());
3403 __ vnclipu_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
3404 i.InputInt8(1));
3405 }
3406 break;
3407 }
3408 case kRiscvVnclip: {
3409 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3410 __ VU.set(FPURoundingMode(i.InputInt8(4)));
3411 if (instr->InputAt(1)->IsSimd128Register()) {
3412 __ vnclip_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3413 i.InputSimd128Register(1));
3414 } else if (instr->InputAt(1)->IsRegister()) {
3415 __ vnclip_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3416 i.InputRegister(1));
3417 } else {
3418 DCHECK(instr->InputAt(1)->IsImmediate());
3419 __ vnclip_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
3420 i.InputInt8(1));
3421 }
3422 break;
3423 }
3424 case kRiscvVwmul: {
3425 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3426 __ vwmul_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3427 i.InputSimd128Register(1));
3428 break;
3429 }
3430 case kRiscvVwmulu: {
3431 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3432 __ vwmulu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3433 i.InputSimd128Register(1));
3434 break;
3435 }
3436 case kRiscvVmvSx: {
3437 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3438 if (instr->InputAt(0)->IsRegister()) {
3439 __ vmv_sx(i.OutputSimd128Register(), i.InputRegister(0));
3440 } else {
3441 DCHECK(instr->InputAt(0)->IsImmediate());
3442 __ li(kScratchReg, i.InputInt64(0));
3443 __ vmv_sx(i.OutputSimd128Register(), kScratchReg);
3444 }
3445 break;
3446 }
3447 case kRiscvVmvXs: {
3448 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3449 __ vmv_xs(i.OutputRegister(), i.InputSimd128Register(0));
3450 break;
3451 }
3452 case kRiscvVcompress: {
3453 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3454 if (instr->InputAt(1)->IsSimd128Register()) {
3455 __ vcompress_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3456 i.InputSimd128Register(1));
3457 } else {
3458 DCHECK(instr->InputAt(1)->IsImmediate());
3459 __ li(kScratchReg, i.InputInt64(1));
3460 __ vmv_sx(v0, kScratchReg);
3461 __ vcompress_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3462 v0);
3463 }
3464 break;
3465 }
3466 case kRiscvVsll: {
3467 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3468 if (instr->InputAt(1)->IsRegister()) {
3469 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3470 i.InputRegister(1));
3471 } else if (instr->InputAt(1)->IsSimd128Register()) {
3472 __ vsll_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3473 i.InputSimd128Register(1));
3474 } else {
3475 DCHECK(instr->InputAt(1)->IsImmediate());
3476 if (is_int5(i.InputInt64(1))) {
3477 __ vsll_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
3478 i.InputInt8(1));
3479 } else {
3480 __ li(kScratchReg, i.InputInt64(1));
3481 __ vsll_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3482 kScratchReg);
3483 }
3484 }
3485 break;
3486 }
3487 case kRiscvVmslt: {
3488 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3489 if (i.InputInt8(4)) {
3490 DCHECK(i.OutputSimd128Register() != i.InputSimd128Register(0));
3491 __ vmv_vx(i.OutputSimd128Register(), zero_reg);
3492 }
3493 if (instr->InputAt(1)->IsRegister()) {
3494 __ vmslt_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3495 i.InputRegister(1));
3496 } else if (instr->InputAt(1)->IsSimd128Register()) {
3497 __ vmslt_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3498 i.InputSimd128Register(1));
3499 } else {
3500 DCHECK(instr->InputAt(1)->IsImmediate());
3501 if (is_int5(i.InputInt64(1))) {
3502 __ vmslt_vi(i.OutputSimd128Register(), i.InputSimd128Register(0),
3503 i.InputInt8(1));
3504 } else {
3505 __ li(kScratchReg, i.InputInt64(1));
3506 __ vmslt_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3507 kScratchReg);
3508 }
3509 }
3510 break;
3511 }
3512 case kRiscvVaddVv: {
3513 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3514 __ vadd_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3515 i.InputSimd128Register(1));
3516 break;
3517 }
3518 case kRiscvVsubVv: {
3519 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3520 __ vsub_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3521 i.InputSimd128Register(1));
3522 break;
3523 }
3524 case kRiscvVmv: {
3525 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3526 if (instr->InputAt(0)->IsSimd128Register()) {
3527 __ vmv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3528 } else if (instr->InputAt(0)->IsRegister()) {
3529 __ vmv_vx(i.OutputSimd128Register(), i.InputRegister(0));
3530 } else {
3531 if (i.ToConstant(instr->InputAt(0)).FitsInInt32() &&
3532 is_int8(i.InputInt32(0))) {
3533 __ vmv_vi(i.OutputSimd128Register(), i.InputInt8(0));
3534 } else {
3535 __ li(kScratchReg, i.InputInt64(0));
3536 __ vmv_vx(i.OutputSimd128Register(), kScratchReg);
3537 }
3538 }
3539 break;
3540 }
3541 case kRiscvVfmvVf: {
3542 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3543 __ vfmv_vf(i.OutputSimd128Register(), i.InputDoubleRegister(0));
3544 break;
3545 }
3546 case kRiscvVnegVv: {
3547 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3548 __ vneg_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3549 break;
3550 }
3551 case kRiscvVfnegVv: {
3552 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3553 __ vfneg_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3554 break;
3555 }
3556 case kRiscvVmaxuVv: {
3557 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3558 __ vmaxu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3559 i.InputSimd128Register(1));
3560 break;
3561 }
3562 case kRiscvVmax: {
3563 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3564 if (instr->InputAt(1)->IsSimd128Register()) {
3565 __ vmax_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3566 i.InputSimd128Register(1));
3567 } else if (instr->InputAt(1)->IsRegister()) {
3568 __ vmax_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3569 i.InputRegister(1));
3570
3571 } else {
3572 DCHECK(instr->InputAt(1)->IsImmediate());
3573 __ li(kScratchReg, i.InputInt64(1));
3574 __ vmax_vx(i.OutputSimd128Register(), i.InputSimd128Register(0),
3575 kScratchReg);
3576 }
3577 break;
3578 }
3579 case kRiscvVminuVv: {
3580 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3581 __ vminu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3582 i.InputSimd128Register(1));
3583 break;
3584 }
3585 case kRiscvVminsVv: {
3586 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3587 __ vmin_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3588 i.InputSimd128Register(1));
3589 break;
3590 }
3591 case kRiscvVmulVv: {
3592 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3593 __ vmul_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3594 i.InputSimd128Register(1));
3595 break;
3596 }
3597 case kRiscvVgtsVv: {
3598 __ WasmRvvGtS(i.OutputSimd128Register(), i.InputSimd128Register(0),
3599 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3600 Vlmul(i.InputInt8(3)));
3601 break;
3602 }
3603 case kRiscvVgesVv: {
3604 __ WasmRvvGeS(i.OutputSimd128Register(), i.InputSimd128Register(0),
3605 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3606 Vlmul(i.InputInt8(3)));
3607 break;
3608 }
3609 case kRiscvVgeuVv: {
3610 __ WasmRvvGeU(i.OutputSimd128Register(), i.InputSimd128Register(0),
3611 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3612 Vlmul(i.InputInt8(3)));
3613 break;
3614 }
3615 case kRiscvVgtuVv: {
3616 __ WasmRvvGtU(i.OutputSimd128Register(), i.InputSimd128Register(0),
3617 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3618 Vlmul(i.InputInt8(3)));
3619 break;
3620 }
3621 case kRiscvVeqVv: {
3622 __ WasmRvvEq(i.OutputSimd128Register(), i.InputSimd128Register(0),
3623 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3624 Vlmul(i.InputInt8(3)));
3625 break;
3626 }
3627 case kRiscvVneVv: {
3628 __ WasmRvvNe(i.OutputSimd128Register(), i.InputSimd128Register(0),
3629 i.InputSimd128Register(1), VSew(i.InputInt8(2)),
3630 Vlmul(i.InputInt8(3)));
3631 break;
3632 }
3633 case kRiscvVaddSatSVv: {
3634 (__ VU).set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3635 __ vsadd_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3636 i.InputSimd128Register(1));
3637 break;
3638 }
3639 case kRiscvVaddSatUVv: {
3640 (__ VU).set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3641 __ vsaddu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3642 i.InputSimd128Register(1));
3643 break;
3644 }
3645 case kRiscvVsubSatSVv: {
3646 (__ VU).set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3647 __ vssub_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3648 i.InputSimd128Register(1));
3649 break;
3650 }
3651 case kRiscvVsubSatUVv: {
3652 (__ VU).set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3653 __ vssubu_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3654 i.InputSimd128Register(1));
3655 break;
3656 }
3657 case kRiscvVfaddVv: {
3658 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3659 __ vfadd_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3660 i.InputSimd128Register(1));
3661 break;
3662 }
3663 case kRiscvVfsubVv: {
3664 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3665 __ vfsub_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3666 i.InputSimd128Register(1));
3667 break;
3668 }
3669 case kRiscvVfmulVv: {
3670 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3671 __ vfmul_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3672 i.InputSimd128Register(1));
3673 break;
3674 }
3675 case kRiscvVfdivVv: {
3676 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3677 __ vfdiv_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3678 i.InputSimd128Register(1));
3679 break;
3680 }
3681 case kRiscvVmfeqVv: {
3682 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3683 __ vmfeq_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3684 i.InputSimd128Register(1));
3685 break;
3686 }
3687 case kRiscvVmfneVv: {
3688 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3689 __ vmfne_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3690 i.InputSimd128Register(1));
3691 break;
3692 }
3693 case kRiscvVmfltVv: {
3694 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3695 __ vmflt_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3696 i.InputSimd128Register(1));
3697 break;
3698 }
3699 case kRiscvVmfleVv: {
3700 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3701 __ vmfle_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3702 i.InputSimd128Register(1));
3703 break;
3704 }
3705 case kRiscvVfminVv: {
3706 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3707 __ vfmin_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3708 i.InputSimd128Register(1), MaskType(i.InputInt8(4)));
3709 break;
3710 }
3711 case kRiscvVfmaxVv: {
3712 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3713 __ vfmax_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3714 i.InputSimd128Register(1), MaskType(i.InputInt8(4)));
3715 break;
3716 }
3717 case kRiscvVandVv: {
3718 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3719 __ vand_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3720 i.InputSimd128Register(1));
3721 break;
3722 }
3723 case kRiscvVorVv: {
3724 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3725 __ vor_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3726 i.InputSimd128Register(1));
3727 break;
3728 }
3729 case kRiscvVxorVv: {
3730 (__ VU).set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3731 __ vxor_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3732 i.InputSimd128Register(1));
3733 break;
3734 }
3735 case kRiscvVnotVv: {
3736 (__ VU).set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3737 __ vnot_vv(i.OutputSimd128Register(), i.InputSimd128Register(0));
3738 break;
3739 }
3740 case kRiscvVmergeVx: {
3741 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3742 if (instr->InputAt(0)->IsRegister()) {
3743 __ vmerge_vx(i.OutputSimd128Register(), i.InputRegister(0),
3744 i.InputSimd128Register(1));
3745 } else {
3746 DCHECK(is_int5(i.InputInt32(0)));
3747 __ vmerge_vi(i.OutputSimd128Register(), i.InputInt8(0),
3748 i.InputSimd128Register(1));
3749 }
3750 break;
3751 }
3752 case kRiscvVsmulVv: {
3753 __ VU.set(kScratchReg, i.InputInt8(2), i.InputInt8(3));
3754 __ vsmul_vv(i.OutputSimd128Register(), i.InputSimd128Register(0),
3755 i.InputSimd128Register(1));
3756 break;
3757 }
3758 case kRiscvVredminuVs: {
3759 __ vredminu_vs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3760 i.InputSimd128Register(1));
3761 break;
3762 }
3763 case kRiscvVzextVf2: {
3764 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3765 __ vzext_vf2(i.OutputSimd128Register(), i.InputSimd128Register(0));
3766 break;
3767 }
3768 case kRiscvVsextVf2: {
3769 __ VU.set(kScratchReg, i.InputInt8(1), i.InputInt8(2));
3770 __ vsext_vf2(i.OutputSimd128Register(), i.InputSimd128Register(0));
3771 break;
3772 }
3773 case kRiscvEnableDebugTrace: {
3774#ifdef USE_SIMULATOR
3775 __ Debug(TRACE_ENABLE | LOG_TRACE | LOG_REGS);
3776 break;
3777#else
3778 UNREACHABLE();
3779#endif
3780 }
3781 case kRiscvDisableDebugTrace: {
3782#ifdef USE_SIMULATOR
3784 break;
3785#else
3786 UNREACHABLE();
3787#endif
3788 }
3789 default:
3790#ifdef DEBUG
3791 switch (arch_opcode) {
3792#define Print(name) \
3793 case k##name: \
3794 printf("k%s", #name); \
3795 break;
3796 ARCH_OPCODE_LIST(Print);
3797#undef Print
3798 default:
3799 break;
3800 }
3801#endif
3802 UNIMPLEMENTED();
3803 }
3804 return kSuccess;
3805}
3806
3807#define UNSUPPORTED_COND(opcode, condition) \
3808 StdoutStream{} << "Unsupported " << #opcode << " condition: \"" << condition \
3809 << "\""; \
3810 UNIMPLEMENTED();
3811
3813 switch (cc) {
3814 case equal:
3815 case greater_equal:
3816 case less_equal:
3817 case Uless_equal:
3818 case Ugreater_equal:
3819 return true;
3820 default:
3821 return false;
3822 }
3823}
3824
3825void AssembleBranchToLabels(CodeGenerator* gen, MacroAssembler* masm,
3827 Label* tlabel, Label* flabel, bool fallthru) {
3828#undef __
3829#define __ masm->
3830 RiscvOperandConverter i(gen, instr);
3831
3832 // RISC-V does not have condition code flags, so compare and branch are
3833 // implemented differently than on the other arch's. The compare operations
3834 // emit riscv64 pseudo-instructions, which are handled here by branch
3835 // instructions that do the actual comparison. Essential that the input
3836 // registers to compare pseudo-op are not modified before this branch op, as
3837 // they are tested here.
3838#if V8_TARGET_ARCH_RISCV64
3839 if (instr->arch_opcode() == kRiscvTst64 ||
3840 instr->arch_opcode() == kRiscvTst32) {
3841#elif V8_TARGET_ARCH_RISCV32
3842 if (instr->arch_opcode() == kRiscvTst32) {
3843#endif
3844 Condition cc = FlagsConditionToConditionTst(condition);
3845 __ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
3846#if V8_TARGET_ARCH_RISCV64
3847 } else if (instr->arch_opcode() == kRiscvAdd64 ||
3848 instr->arch_opcode() == kRiscvSub64) {
3849 Condition cc = FlagsConditionToConditionOvf(condition);
3850 __ Sra64(kScratchReg, i.OutputRegister(), 32);
3851 __ Sra32(kScratchReg2, i.OutputRegister(), 31);
3852 __ Branch(tlabel, cc, kScratchReg2, Operand(kScratchReg));
3853 } else if (instr->arch_opcode() == kRiscvAddOvf64 ||
3854 instr->arch_opcode() == kRiscvSubOvf64) {
3855#elif V8_TARGET_ARCH_RISCV32
3856 } else if (instr->arch_opcode() == kRiscvAddOvf ||
3857 instr->arch_opcode() == kRiscvSubOvf) {
3858#endif
3859 switch (condition) {
3860 // Overflow occurs if overflow register is negative
3861 case kOverflow:
3862 __ Branch(tlabel, lt, kScratchReg, Operand(zero_reg));
3863 break;
3864 case kNotOverflow:
3865 __ Branch(tlabel, ge, kScratchReg, Operand(zero_reg));
3866 break;
3867 default:
3869 }
3870#if V8_TARGET_ARCH_RISCV64
3871 // kRiscvMulOvf64 is only for RISCV64
3872 } else if (instr->arch_opcode() == kRiscvMulOvf32 ||
3873 instr->arch_opcode() == kRiscvMulOvf64) {
3874#elif V8_TARGET_ARCH_RISCV32
3875 } else if (instr->arch_opcode() == kRiscvMulOvf32) {
3876#endif
3877 // Overflow occurs if overflow register is not zero
3878 switch (condition) {
3879 case kOverflow:
3880 __ Branch(tlabel, ne, kScratchReg, Operand(zero_reg));
3881 break;
3882 case kNotOverflow:
3883 __ Branch(tlabel, eq, kScratchReg, Operand(zero_reg));
3884 break;
3885 default:
3887 }
3888#if V8_TARGET_ARCH_RISCV64
3889 } else if (instr->arch_opcode() == kRiscvCmp ||
3890 instr->arch_opcode() == kRiscvCmp32) {
3891#elif V8_TARGET_ARCH_RISCV32
3892 } else if (instr->arch_opcode() == kRiscvCmp) {
3893#endif
3894 Condition cc = FlagsConditionToConditionCmp(condition);
3895 Register left = i.InputRegister(0);
3896 Operand right = i.InputOperand(1);
3897 // Word32Compare has two temp registers.
3898#if V8_TARGET_ARCH_RISCV64
3899 if (COMPRESS_POINTERS_BOOL && (instr->arch_opcode() == kRiscvCmp32)) {
3900 Register temp0 = i.TempRegister(0);
3901 Register temp1 = right.is_reg() ? i.TempRegister(1) : no_reg;
3902 __ slliw(temp0, left, 0);
3903 left = temp0;
3904 if (temp1 != no_reg) {
3905 __ slliw(temp1, right.rm(), 0);
3906 right = Operand(temp1);
3907 }
3908 }
3909#endif
3910 __ Branch(tlabel, cc, left, right);
3911 } else if (instr->arch_opcode() == kRiscvCmpZero) {
3912 Condition cc = FlagsConditionToConditionCmp(condition);
3913 if (i.InputOrZeroRegister(0) == zero_reg && IsInludeEqual(cc)) {
3914 __ Branch(tlabel);
3915 } else if (i.InputOrZeroRegister(0) != zero_reg) {
3916 __ Branch(tlabel, cc, i.InputRegister(0), Operand(zero_reg));
3917 }
3918#ifdef V8_TARGET_ARCH_RISCV64
3919 } else if (instr->arch_opcode() == kRiscvCmpZero32) {
3920 Condition cc = FlagsConditionToConditionCmp(condition);
3921 if (i.InputOrZeroRegister(0) == zero_reg && IsInludeEqual(cc)) {
3922 __ Branch(tlabel);
3923 } else if (i.InputOrZeroRegister(0) != zero_reg) {
3924 Register temp0 = i.TempRegister(0);
3925 __ slliw(temp0, i.InputRegister(0), 0);
3926 __ Branch(tlabel, cc, temp0, Operand(zero_reg));
3927 }
3928#endif
3929 } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
3930 Condition cc = FlagsConditionToConditionCmp(condition);
3931 Register lhs_register = sp;
3932 uint32_t offset;
3933 if (gen->ShouldApplyOffsetToStackCheck(instr, &offset)) {
3934 lhs_register = i.TempRegister(0);
3935 __ SubWord(lhs_register, sp, offset);
3936 }
3937 __ Branch(tlabel, cc, lhs_register, Operand(i.InputRegister(0)));
3938 } else if (instr->arch_opcode() == kRiscvCmpS ||
3939 instr->arch_opcode() == kRiscvCmpD) {
3940 bool predicate;
3941 FlagsConditionToConditionCmpFPU(&predicate, condition);
3942 // floating-point compare result is set in kScratchReg
3943 if (predicate) {
3944 __ BranchTrueF(kScratchReg, tlabel);
3945 } else {
3946 __ BranchFalseF(kScratchReg, tlabel);
3947 }
3948 } else {
3949 std::cout << "AssembleArchBranch Unimplemented arch_opcode:"
3950 << instr->arch_opcode() << " " << condition << std::endl;
3952 }
3953 if (!fallthru) __ Branch(flabel); // no fallthru to flabel.
3954#undef __
3955#define __ masm()->
3956}
3957
3958// Assembles branches after an instruction.
3959void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
3960 Label* tlabel = branch->true_label;
3961 Label* flabel = branch->false_label;
3962
3963 AssembleBranchToLabels(this, masm(), instr, branch->condition, tlabel, flabel,
3964 branch->fallthru);
3965}
3966
3967#undef UNSUPPORTED_COND
3968
3970 BranchInfo* branch) {
3971 AssembleArchBranch(instr, branch);
3972}
3973
3975 RpoNumber target) {
3976 __ Branch(GetLabel(target));
3977}
3978
3979#if V8_ENABLE_WEBASSEMBLY
3980void CodeGenerator::AssembleArchTrap(Instruction* instr,
3982 class OutOfLineTrap final : public OutOfLineCode {
3983 public:
3984 OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
3985 : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
3986 void Generate() override {
3987 RiscvOperandConverter i(gen_, instr_);
3988 TrapId trap_id =
3989 static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
3990 GenerateCallToTrap(trap_id);
3991 }
3992
3993 private:
3994 void GenerateCallToTrap(TrapId trap_id) {
3995 gen_->AssembleSourcePosition(instr_);
3996 // A direct call to a wasm runtime stub defined in this module.
3997 // Just encode the stub index. This will be patched when the code
3998 // is added to the native module and copied into wasm code space.
3999 __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
4000 ReferenceMap* reference_map =
4001 gen_->zone()->New<ReferenceMap>(gen_->zone());
4002 gen_->RecordSafepoint(reference_map);
4003 if (v8_flags.debug_code) {
4004 __ stop();
4005 }
4006 }
4007 Instruction* instr_;
4008 CodeGenerator* gen_;
4009 };
4010 auto ool = zone()->New<OutOfLineTrap>(this, instr);
4011 Label* tlabel = ool->entry();
4012 AssembleBranchToLabels(this, masm(), instr, condition, tlabel, nullptr, true);
4013}
4014#endif // V8_ENABLE_WEBASSEMBLY
4015
4016// Assembles boolean materializations after an instruction.
4019 RiscvOperandConverter i(this, instr);
4020
4021 // Materialize a full 32-bit 1 or 0 value. The result register is always the
4022 // last output of the instruction.
4023 DCHECK_NE(0u, instr->OutputCount());
4024 Register result = i.OutputRegister(instr->OutputCount() - 1);
4025 // RISC-V does not have condition code flags, so compare and branch are
4026 // implemented differently than on the other arch's. The compare operations
4027 // emit riscv64 pseudo-instructions, which are checked and handled here.
4028
4029#if V8_TARGET_ARCH_RISCV64
4030 if (instr->arch_opcode() == kRiscvTst64 ||
4031 instr->arch_opcode() == kRiscvTst32) {
4032#elif V8_TARGET_ARCH_RISCV32
4033 if (instr->arch_opcode() == kRiscvTst32) {
4034#endif
4035 Condition cc = FlagsConditionToConditionTst(condition);
4036 if (cc == eq) {
4037 __ Sltu(result, kScratchReg, 1);
4038 } else {
4039 __ Sltu(result, zero_reg, kScratchReg);
4040 }
4041 return;
4042#if V8_TARGET_ARCH_RISCV64
4043 } else if (instr->arch_opcode() == kRiscvAdd64 ||
4044 instr->arch_opcode() == kRiscvSub64) {
4045 Condition cc = FlagsConditionToConditionOvf(condition);
4046 // Check for overflow creates 1 or 0 for result.
4047 __ Srl64(kScratchReg, i.OutputRegister(), 63);
4048 __ Srl32(kScratchReg2, i.OutputRegister(), 31);
4050 if (cc == eq) // Toggle result for not overflow.
4051 __ Xor(result, result, 1);
4052 return;
4053 } else if (instr->arch_opcode() == kRiscvAddOvf64 ||
4054 instr->arch_opcode() == kRiscvSubOvf64) {
4055#elif V8_TARGET_ARCH_RISCV32
4056 } else if (instr->arch_opcode() == kRiscvAddOvf ||
4057 instr->arch_opcode() == kRiscvSubOvf) {
4058#endif
4059 // Overflow occurs if overflow register is negative
4060 __ Slt(result, kScratchReg, zero_reg);
4061#if V8_TARGET_ARCH_RISCV64
4062 // kRiscvMulOvf64 is only for RISCV64
4063 } else if (instr->arch_opcode() == kRiscvMulOvf32 ||
4064 instr->arch_opcode() == kRiscvMulOvf64) {
4065#elif V8_TARGET_ARCH_RISCV32
4066 } else if (instr->arch_opcode() == kRiscvMulOvf32) {
4067#endif
4068 // Overflow occurs if overflow register is not zero
4069 __ Sgtu(result, kScratchReg, zero_reg);
4070#if V8_TARGET_ARCH_RISCV64
4071 } else if (instr->arch_opcode() == kRiscvCmp ||
4072 instr->arch_opcode() == kRiscvCmp32) {
4073#elif V8_TARGET_ARCH_RISCV32
4074 } else if (instr->arch_opcode() == kRiscvCmp) {
4075#endif
4076 Condition cc = FlagsConditionToConditionCmp(condition);
4077 Register left = i.InputRegister(0);
4078 Operand right = i.InputOperand(1);
4079#if V8_TARGET_ARCH_RISCV64
4080 if (COMPRESS_POINTERS_BOOL && (instr->arch_opcode() == kRiscvCmp32)) {
4081 Register temp0 = i.TempRegister(0);
4082 Register temp1 = right.is_reg() ? i.TempRegister(1) : no_reg;
4083 __ slliw(temp0, left, 0);
4084 left = temp0;
4085 if (temp1 != no_reg) {
4086 __ slliw(temp1, right.rm(), 0);
4087 right = Operand(temp1);
4088 }
4089 }
4090#endif
4091 switch (cc) {
4092 case eq:
4093 case ne: {
4094 if (instr->InputAt(1)->IsImmediate()) {
4095 if (is_int12(-right.immediate())) {
4096 if (right.immediate() == 0) {
4097 if (cc == eq) {
4098 __ Sltu(result, left, 1);
4099 } else {
4100 __ Sltu(result, zero_reg, left);
4101 }
4102 } else {
4103 __ AddWord(result, left, Operand(-right.immediate()));
4104 if (cc == eq) {
4105 __ Sltu(result, result, 1);
4106 } else {
4107 __ Sltu(result, zero_reg, result);
4108 }
4109 }
4110 } else {
4111 if (is_uint12(right.immediate())) {
4112 __ Xor(result, left, right);
4113 } else {
4114 __ li(kScratchReg, right);
4115 __ Xor(result, left, kScratchReg);
4116 }
4117 if (cc == eq) {
4118 __ Sltu(result, result, 1);
4119 } else {
4120 __ Sltu(result, zero_reg, result);
4121 }
4122 }
4123 } else {
4124 __ Xor(result, left, right);
4125 if (cc == eq) {
4126 __ Sltu(result, result, 1);
4127 } else {
4128 __ Sltu(result, zero_reg, result);
4129 }
4130 }
4131 } break;
4132 case lt:
4133 case ge: {
4134 Register left = i.InputOrZeroRegister(0);
4135 Operand right = i.InputOperand(1);
4136 __ Slt(result, left, right);
4137 if (cc == ge) {
4138 __ Xor(result, result, 1);
4139 }
4140 } break;
4141 case gt:
4142 case le: {
4143 Register left = i.InputOrZeroRegister(1);
4144 Operand right = i.InputOperand(0);
4145 __ Slt(result, left, right);
4146 if (cc == le) {
4147 __ Xor(result, result, 1);
4148 }
4149 } break;
4150 case Uless:
4151 case Ugreater_equal: {
4152 Register left = i.InputOrZeroRegister(0);
4153 Operand right = i.InputOperand(1);
4154 __ Sltu(result, left, right);
4155 if (cc == Ugreater_equal) {
4156 __ Xor(result, result, 1);
4157 }
4158 } break;
4159 case Ugreater:
4160 case Uless_equal: {
4161 Register left = i.InputRegister(1);
4162 Operand right = i.InputOperand(0);
4163 __ Sltu(result, left, right);
4164 if (cc == Uless_equal) {
4165 __ Xor(result, result, 1);
4166 }
4167 } break;
4168 default:
4169 UNREACHABLE();
4170 }
4171 return;
4172 } else if (instr->arch_opcode() == kRiscvCmpZero) {
4173 Condition cc = FlagsConditionToConditionCmp(condition);
4174 switch (cc) {
4175 case eq: {
4176 Register left = i.InputOrZeroRegister(0);
4177 __ Sltu(result, left, 1);
4178 break;
4179 }
4180 case ne: {
4181 Register left = i.InputOrZeroRegister(0);
4182 __ Sltu(result, zero_reg, left);
4183 break;
4184 }
4185 case lt:
4186 case ge: {
4187 Register left = i.InputOrZeroRegister(0);
4188 Operand right = Operand(zero_reg);
4189 __ Slt(result, left, right);
4190 if (cc == ge) {
4191 __ Xor(result, result, 1);
4192 }
4193 } break;
4194 case gt:
4195 case le: {
4196 Operand left = i.InputOperand(0);
4197 __ Slt(result, zero_reg, left);
4198 if (cc == le) {
4199 __ Xor(result, result, 1);
4200 }
4201 } break;
4202 case Uless:
4203 case Ugreater_equal: {
4204 Register left = i.InputOrZeroRegister(0);
4205 Operand right = Operand(zero_reg);
4206 __ Sltu(result, left, right);
4207 if (cc == Ugreater_equal) {
4208 __ Xor(result, result, 1);
4209 }
4210 } break;
4211 case Ugreater:
4212 case Uless_equal: {
4213 Register left = zero_reg;
4214 Operand right = i.InputOperand(0);
4215 __ Sltu(result, left, right);
4216 if (cc == Uless_equal) {
4217 __ Xor(result, result, 1);
4218 }
4219 } break;
4220 default:
4221 UNREACHABLE();
4222 }
4223 return;
4224#ifdef V8_TARGET_ARCH_RISCV64
4225 } else if (instr->arch_opcode() == kRiscvCmpZero32) {
4226 auto trim_reg = [&](Register in) -> Register {
4227 Register temp = i.TempRegister(0);
4228 __ slliw(temp, in, 0);
4229 return temp;
4230 };
4231 auto trim_op = [&](Operand in) -> Register {
4232 Register temp = i.TempRegister(0);
4233 if (in.is_reg()) {
4234 __ slliw(temp, in.rm(), 0);
4235 } else {
4236 __ Li(temp, in.immediate());
4237 __ slliw(temp, temp, 0);
4238 }
4239 return temp;
4240 };
4241 Condition cc = FlagsConditionToConditionCmp(condition);
4242 switch (cc) {
4243 case eq: {
4244 auto left = trim_reg(i.InputOrZeroRegister(0));
4245 __ Sltu(result, left, 1);
4246 break;
4247 }
4248 case ne: {
4249 auto left = trim_reg(i.InputOrZeroRegister(0));
4250 __ Sltu(result, zero_reg, left);
4251 break;
4252 }
4253 case lt:
4254 case ge: {
4255 auto left = trim_reg(i.InputOrZeroRegister(0));
4256 __ Slt(result, left, zero_reg);
4257 if (cc == ge) {
4258 __ Xor(result, result, 1);
4259 }
4260 } break;
4261 case gt:
4262 case le: {
4263 auto left = trim_op(i.InputOperand(0));
4264 __ Slt(result, zero_reg, left);
4265 if (cc == le) {
4266 __ Xor(result, result, 1);
4267 }
4268 } break;
4269 case Uless:
4270 case Ugreater_equal: {
4271 auto left = trim_reg(i.InputOrZeroRegister(0));
4272 __ Sltu(result, left, zero_reg);
4273 if (cc == Ugreater_equal) {
4274 __ Xor(result, result, 1);
4275 }
4276 } break;
4277 case Ugreater:
4278 case Uless_equal: {
4279 auto right = trim_op(i.InputOperand(0));
4280 __ Sltu(result, zero_reg, right);
4281 if (cc == Uless_equal) {
4282 __ Xor(result, result, 1);
4283 }
4284 } break;
4285 default:
4286 UNREACHABLE();
4287 }
4288 return;
4289#endif
4290 } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
4291 Register lhs_register = sp;
4292 uint32_t offset;
4294 lhs_register = i.TempRegister(0);
4295 __ SubWord(lhs_register, sp, offset);
4296 }
4297 __ Sgtu(result, lhs_register, Operand(i.InputRegister(0)));
4298 return;
4299 } else if (instr->arch_opcode() == kRiscvCmpD ||
4300 instr->arch_opcode() == kRiscvCmpS) {
4301 if (instr->arch_opcode() == kRiscvCmpD) {
4302 FPURegister left = i.InputOrZeroDoubleRegister(0);
4303 FPURegister right = i.InputOrZeroDoubleRegister(1);
4304 if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
4305 !__ IsDoubleZeroRegSet()) {
4306 __ LoadFPRImmediate(kDoubleRegZero, 0.0);
4307 }
4308 } else {
4309 FPURegister left = i.InputOrZeroSingleRegister(0);
4310 FPURegister right = i.InputOrZeroSingleRegister(1);
4311 if ((left == kSingleRegZero || right == kSingleRegZero) &&
4312 !__ IsSingleZeroRegSet()) {
4313 __ LoadFPRImmediate(kSingleRegZero, 0.0f);
4314 }
4315 }
4316 bool predicate;
4317 FlagsConditionToConditionCmpFPU(&predicate, condition);
4318 // RISCV compare returns 0 or 1, do nothing when predicate; otherwise
4319 // toggle kScratchReg (i.e., 0 -> 1, 1 -> 0)
4320 if (predicate) {
4321 __ Move(result, kScratchReg);
4322 } else {
4323 __ Xor(result, kScratchReg, 1);
4324 }
4325 return;
4326 } else {
4327 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
4328 instr->arch_opcode());
4329 TRACE("UNIMPLEMENTED code_generator_riscv64: %s at line %d\n", __FUNCTION__,
4330 __LINE__);
4332 }
4333}
4334
4336 UNREACHABLE();
4337}
4338
4340 BranchInfo* branch) {
4341 UNREACHABLE();
4342}
4343
4345 RiscvOperandConverter i(this, instr);
4346 Register input = i.InputRegister(0);
4347 std::vector<std::pair<int32_t, Label*>> cases;
4348 for (size_t index = 2; index < instr->InputCount(); index += 2) {
4349 cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
4350 }
4351 AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
4352 cases.data() + cases.size());
4353}
4354
4356 RiscvOperandConverter i(this, instr);
4357 Register input = i.InputRegister(0);
4358 size_t const case_count = instr->InputCount() - 2;
4359
4360 __ Branch(GetLabel(i.InputRpo(1)), Ugreater_equal, input,
4361 Operand(case_count));
4362 __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
4363 return GetLabel(i.InputRpo(index + 2));
4364 });
4365}
4366
4367void CodeGenerator::FinishFrame(Frame* frame) {
4368 auto call_descriptor = linkage()->GetIncomingDescriptor();
4369
4370 const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
4371 if (!saves_fpu.is_empty()) {
4372 int count = saves_fpu.Count();
4374 frame->AllocateSavedCalleeRegisterSlots(count *
4376 }
4377
4378 const RegList saves = call_descriptor->CalleeSavedRegisters();
4379 if (!saves.is_empty()) {
4380 int count = saves.Count();
4381 frame->AllocateSavedCalleeRegisterSlots(count);
4382 }
4383}
4384
4386 auto call_descriptor = linkage()->GetIncomingDescriptor();
4387
4388 if (frame_access_state()->has_frame()) {
4389 if (call_descriptor->IsCFunctionCall()) {
4390 if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) {
4391 __ StubPrologue(StackFrame::C_WASM_ENTRY);
4392 // Reserve stack space for saving the c_entry_fp later.
4393 __ SubWord(sp, sp, Operand(kSystemPointerSize));
4394 } else {
4395 __ Push(ra, fp);
4396 __ Move(fp, sp);
4397 }
4398 } else if (call_descriptor->IsJSFunctionCall()) {
4399 __ Prologue();
4400 } else {
4401 __ StubPrologue(info()->GetOutputStackFrameType());
4402 if (call_descriptor->IsAnyWasmFunctionCall() ||
4403 call_descriptor->IsWasmImportWrapper() ||
4404 call_descriptor->IsWasmCapiFunction()) {
4406 }
4407 if (call_descriptor->IsWasmCapiFunction()) {
4408 // Reserve space for saving the PC later.
4409 __ SubWord(sp, sp, Operand(kSystemPointerSize));
4410 }
4411 }
4412 }
4413
4414 int required_slots =
4415 frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount();
4416
4417 if (info()->is_osr()) {
4418 // TurboFan OSR-compiled functions cannot be entered directly.
4419 __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
4420
4421 // Unoptimized code jumps directly to this entrypoint while the unoptimized
4422 // frame is still on the stack. Optimized code uses OSR values directly from
4423 // the unoptimized frame. Thus, all that needs to be done is to allocate the
4424 // remaining stack slots.
4425 __ RecordComment("-- OSR entrypoint --");
4427#ifdef V8_ENABLE_SANDBOX_BOOL
4428 UseScratchRegisterScope temps(masm());
4429 uint32_t expected_frame_size =
4430 static_cast<uint32_t>(osr_helper()->UnoptimizedFrameSlots()) *
4433 Register scratch = temps.Acquire();
4434 __ AddWord(scratch, sp, expected_frame_size);
4435 __ SbxCheck(eq, AbortReason::kOsrUnexpectedStackSize, scratch, Operand(fp));
4436#endif // V8_ENABLE_SANDBOX_BOOL
4437 required_slots -= osr_helper()->UnoptimizedFrameSlots();
4438 }
4439
4440 const RegList saves = call_descriptor->CalleeSavedRegisters();
4441 const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
4442
4443 if (required_slots > 0) {
4444 DCHECK(frame_access_state()->has_frame());
4445 if (info()->IsWasm() && required_slots > 128) {
4446 // For WebAssembly functions with big frames we have to do the stack
4447 // overflow check before we construct the frame. Otherwise we may not
4448 // have enough space on the stack to call the runtime for the stack
4449 // overflow.
4450 Label done;
4451
4452 // If the frame is bigger than the stack, we throw the stack overflow
4453 // exception unconditionally. Thereby we can avoid the integer overflow
4454 // check in the condition code.
4455 if ((required_slots * kSystemPointerSize) <
4456 (v8_flags.stack_size * KB)) {
4457 UseScratchRegisterScope temps(masm());
4458 Register stack_limit = temps.Acquire();
4459 __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit);
4460 __ AddWord(stack_limit, stack_limit,
4461 Operand(required_slots * kSystemPointerSize));
4462 __ Branch(&done, uge, sp, Operand(stack_limit));
4463 }
4464
4465 if (v8_flags.experimental_wasm_growable_stacks) {
4468 regs_to_save.set(
4469 WasmHandleStackOverflowDescriptor::FrameBaseRegister());
4470 for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg);
4471 __ MultiPush(regs_to_save);
4472 DoubleRegList fp_regs_to_save;
4473 for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg);
4474 __ MultiPushFPU(fp_regs_to_save);
4476 required_slots * kSystemPointerSize);
4477 __ AddWord(
4478 WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp,
4479 Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize +
4481 __ CallBuiltin(Builtin::kWasmHandleStackOverflow);
4482 __ MultiPopFPU(fp_regs_to_save);
4483 __ MultiPop(regs_to_save);
4484 } else {
4485 __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow),
4487 // We come from WebAssembly, there are no references for the GC.
4488 ReferenceMap* reference_map = zone()->New<ReferenceMap>(zone());
4489 RecordSafepoint(reference_map);
4490 if (v8_flags.debug_code) {
4491 __ stop();
4492 }
4493 }
4494 __ bind(&done);
4495 }
4496 }
4497
4498 const int returns = frame()->GetReturnSlotCount();
4499
4500 // Skip callee-saved and return slots, which are pushed below.
4501 required_slots -= saves.Count();
4502 required_slots -= saves_fpu.Count() * (kDoubleSize / kSystemPointerSize);
4503 required_slots -= returns;
4504 if (required_slots > 0) {
4505 __ SubWord(sp, sp, Operand(required_slots * kSystemPointerSize));
4506 }
4507
4508 if (!saves_fpu.is_empty()) {
4509 // Save callee-saved FPU registers.
4510 __ MultiPushFPU(saves_fpu);
4511 DCHECK_EQ(kNumCalleeSavedFPU, saves_fpu.Count());
4512 }
4513
4514 if (!saves.is_empty()) {
4515 // Save callee-saved registers.
4516 __ MultiPush(saves);
4517 }
4518
4519 if (returns != 0) {
4520 // Create space for returns.
4521 __ SubWord(sp, sp, Operand(returns * kSystemPointerSize));
4522 }
4523
4524 for (int spill_slot : frame()->tagged_slots()) {
4525 FrameOffset offset = frame_access_state()->GetFrameOffset(spill_slot);
4526 DCHECK(offset.from_frame_pointer());
4527 __ StoreWord(zero_reg, MemOperand(fp, offset.offset()));
4528 }
4529}
4530
4531void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
4532 auto call_descriptor = linkage()->GetIncomingDescriptor();
4533
4534 const int returns = frame()->GetReturnSlotCount();
4535 if (returns != 0) {
4536 __ AddWord(sp, sp, Operand(returns * kSystemPointerSize));
4537 }
4538
4539 // Restore GP registers.
4540 const RegList saves = call_descriptor->CalleeSavedRegisters();
4541 if (!saves.is_empty()) {
4542 __ MultiPop(saves);
4543 }
4544
4545 // Restore FPU registers.
4546 const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
4547 if (!saves_fpu.is_empty()) {
4548 __ MultiPopFPU(saves_fpu);
4549 }
4550
4551 RiscvOperandConverter g(this, nullptr);
4552
4553 const int parameter_slots =
4554 static_cast<int>(call_descriptor->ParameterSlotCount());
4555
4556 // {aditional_pop_count} is only greater than zero if {parameter_slots = 0}.
4557 // Check RawMachineAssembler::PopAndReturn.
4558 if (parameter_slots != 0) {
4559 if (additional_pop_count->IsImmediate()) {
4560 DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
4561 } else if (v8_flags.debug_code) {
4562 __ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue,
4563 g.ToRegister(additional_pop_count),
4564 Operand(static_cast<intptr_t>(0)));
4565 }
4566 }
4567
4568#if V8_ENABLE_WEBASSEMBLY
4569 if (call_descriptor->IsAnyWasmFunctionCall() &&
4570 v8_flags.experimental_wasm_growable_stacks) {
4571 Label done;
4572 {
4573 UseScratchRegisterScope temps{masm()};
4574 Register scratch = temps.Acquire();
4575 __ LoadWord(scratch,
4577 __ BranchShort(
4578 &done, ne, scratch,
4579 Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)));
4580 }
4583 __ MultiPush(regs_to_save);
4585 {
4586 UseScratchRegisterScope temps{masm()};
4587 Register scratch = temps.Acquire();
4588 __ PrepareCallCFunction(1, scratch);
4589 }
4590 __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1);
4591 __ mv(fp, kReturnRegister0);
4592 __ MultiPop(regs_to_save);
4593 __ bind(&done);
4594 }
4595#endif // V8_ENABLE_WEBASSEMBLY
4596
4597 // Functions with JS linkage have at least one parameter (the receiver).
4598 // If {parameter_slots} == 0, it means it is a builtin with
4599 // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
4600 // itself.
4601 const bool drop_jsargs = frame_access_state()->has_frame() &&
4602 call_descriptor->IsJSFunctionCall() &&
4603 parameter_slots != 0;
4604
4605 if (call_descriptor->IsCFunctionCall()) {
4607 } else if (frame_access_state()->has_frame()) {
4608 // Canonicalize JSFunction return sites for now unless they have an variable
4609 // number of stack slot pops.
4610 if (additional_pop_count->IsImmediate() &&
4611 g.ToConstant(additional_pop_count).ToInt32() == 0) {
4612 if (return_label_.is_bound()) {
4613 __ Branch(&return_label_);
4614 return;
4615 } else {
4616 __ bind(&return_label_);
4617 }
4618 }
4619 if (drop_jsargs) {
4620 // Get the actual argument count
4622 }
4624 }
4625 if (drop_jsargs) {
4626 // We must pop all arguments from the stack (including the receiver). This
4627 // number of arguments is given by max(1 + argc_reg, parameter_slots).
4628 if (parameter_slots > 1) {
4629 Label done;
4630 __ li(kScratchReg, parameter_slots);
4631 __ BranchShort(&done, ge, t0, Operand(kScratchReg));
4632 __ Move(t0, kScratchReg);
4633 __ bind(&done);
4634 }
4635 __ SllWord(t0, t0, kSystemPointerSizeLog2);
4636 __ AddWord(sp, sp, t0);
4637 } else if (additional_pop_count->IsImmediate()) {
4638 // it should be a kInt32 or a kInt64
4639 DCHECK_LE(g.ToConstant(additional_pop_count).type(), Constant::kInt64);
4640 int additional_count = g.ToConstant(additional_pop_count).ToInt32();
4641 __ Drop(parameter_slots + additional_count);
4642 } else {
4643 Register pop_reg = g.ToRegister(additional_pop_count);
4644 __ Drop(parameter_slots);
4645 __ SllWord(pop_reg, pop_reg, kSystemPointerSizeLog2);
4646 __ AddWord(sp, sp, pop_reg);
4647 }
4648 __ Ret();
4649}
4650
4651void CodeGenerator::FinishCode() { __ ForceConstantPoolEmissionWithoutJump(); }
4652
4654 ZoneDeque<DeoptimizationExit*>* exits) {
4655 __ ForceConstantPoolEmissionWithoutJump();
4656 int total_size = 0;
4657 for (DeoptimizationExit* exit : deoptimization_exits_) {
4658 total_size += (exit->kind() == DeoptimizeKind::kLazy)
4661 }
4662
4663 __ CheckTrampolinePoolQuick(total_size);
4664}
4665
4666void CodeGenerator::MoveToTempLocation(InstructionOperand* source,
4668 // Must be kept in sync with {MoveTempLocationTo}.
4669 DCHECK(!source->IsImmediate());
4670 move_cycle_.temps.emplace(masm());
4671 auto& temps = *move_cycle_.temps;
4672 // Temporarily exclude the reserved scratch registers while we pick one to
4673 // resolve the move cycle. Re-include them immediately afterwards as they
4674 // might be needed for the move to the temp location.
4675 temps.Exclude(move_cycle_.scratch_regs);
4676 if (!IsFloatingPoint(rep)) {
4677 if (temps.CanAcquire()) {
4678 Register scratch = move_cycle_.temps->Acquire();
4679 move_cycle_.scratch_reg.emplace(scratch);
4680 }
4681 }
4682
4683 temps.Include(move_cycle_.scratch_regs);
4684
4685 if (move_cycle_.scratch_reg.has_value()) {
4686 // A scratch register is available for this rep.
4687 // auto& scratch_reg = *move_cycle_.scratch_reg;
4688 AllocatedOperand scratch(LocationOperand::REGISTER, rep,
4689 move_cycle_.scratch_reg->code());
4690 AssembleMove(source, &scratch);
4691 } else {
4692 // The scratch registers are blocked by pending moves. Use the stack
4693 // instead.
4694 Push(source);
4695 }
4696}
4697
4698void CodeGenerator::MoveTempLocationTo(InstructionOperand* dest,
4700 if (move_cycle_.scratch_reg.has_value()) {
4701 // auto& scratch_reg = *move_cycle_.scratch_reg;
4702 AllocatedOperand scratch(LocationOperand::REGISTER, rep,
4703 move_cycle_.scratch_reg->code());
4704 AssembleMove(&scratch, dest);
4705 } else {
4706 Pop(dest, rep);
4707 }
4708 // Restore the default state to release the {UseScratchRegisterScope} and to
4709 // prepare for the next cycle.
4710 move_cycle_ = MoveCycleState();
4711}
4712
4713void CodeGenerator::SetPendingMove(MoveOperands* move) {
4714 InstructionOperand* src = &move->source();
4715 InstructionOperand* dst = &move->destination();
4716 UseScratchRegisterScope temps(masm());
4717 if (src->IsConstant() && dst->IsFPLocationOperand()) {
4718 Register temp = temps.Acquire();
4720 } else if (src->IsAnyStackSlot() || dst->IsAnyStackSlot()) {
4721 RiscvOperandConverter g(this, nullptr);
4722 bool src_need_scratch = false;
4723 bool dst_need_scratch = false;
4724 if (src->IsAnyStackSlot()) {
4725 MemOperand src_mem = g.ToMemOperand(src);
4726 src_need_scratch =
4727 (!is_int16(src_mem.offset())) || (((src_mem.offset() & 0b111) != 0) &&
4728 !is_int16(src_mem.offset() + 4));
4729 }
4730 if (dst->IsAnyStackSlot()) {
4731 MemOperand dst_mem = g.ToMemOperand(dst);
4732 dst_need_scratch =
4733 (!is_int16(dst_mem.offset())) || (((dst_mem.offset() & 0b111) != 0) &&
4734 !is_int16(dst_mem.offset() + 4));
4735 }
4736 if (src_need_scratch || dst_need_scratch) {
4737 Register temp = temps.Acquire();
4739 }
4740 }
4741}
4742
4743void CodeGenerator::AssembleMove(InstructionOperand* source,
4744 InstructionOperand* destination) {
4745 RiscvOperandConverter g(this, nullptr);
4746 // Dispatch on the source and destination operand kinds. Not all
4747 // combinations are possible.
4748 if (source->IsRegister()) {
4749 DCHECK(destination->IsRegister() || destination->IsStackSlot());
4750 Register src = g.ToRegister(source);
4751 if (destination->IsRegister()) {
4752 __ Move(g.ToRegister(destination), src);
4753 } else {
4754 __ StoreWord(src, g.ToMemOperand(destination));
4755 }
4756 } else if (source->IsStackSlot()) {
4757 DCHECK(destination->IsRegister() || destination->IsStackSlot());
4758 MemOperand src = g.ToMemOperand(source);
4759 if (destination->IsRegister()) {
4760 __ LoadWord(g.ToRegister(destination), src);
4761 } else {
4762 Register temp = kScratchReg;
4763 __ LoadWord(temp, src);
4764 __ StoreWord(temp, g.ToMemOperand(destination));
4765 }
4766 } else if (source->IsConstant()) {
4767 Constant src = g.ToConstant(source);
4768 if (destination->IsRegister() || destination->IsStackSlot()) {
4769 Register dst =
4770 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
4771 switch (src.type()) {
4772 case Constant::kInt32:
4773 if (src.ToInt32() == 0 && destination->IsStackSlot() &&
4774 RelocInfo::IsNoInfo(src.rmode())) {
4775 dst = zero_reg;
4776 } else {
4777 __ li(dst, Operand(src.ToInt32(), src.rmode()));
4778 }
4779 break;
4780 case Constant::kFloat32:
4781 __ li(dst, Operand::EmbeddedNumber(src.ToFloat32()));
4782 break;
4783 case Constant::kInt64:
4784 if (src.ToInt64() == 0 && destination->IsStackSlot() &&
4785 RelocInfo::IsNoInfo(src.rmode())) {
4786 dst = zero_reg;
4787 } else {
4788 __ li(dst, Operand(src.ToInt64(), src.rmode()));
4789 }
4790 break;
4791 case Constant::kFloat64:
4792 __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
4793 break;
4795 __ li(dst, src.ToExternalReference());
4796 break;
4797 case Constant::kHeapObject: {
4798 Handle<HeapObject> src_object = src.ToHeapObject();
4800 if (IsMaterializableFromRoot(src_object, &index)) {
4801 __ LoadRoot(dst, index);
4802 } else {
4803 __ li(dst, src_object);
4804 }
4805 break;
4806 }
4808 Handle<HeapObject> src_object = src.ToHeapObject();
4810 if (IsMaterializableFromRoot(src_object, &index)) {
4811 __ LoadCompressedTaggedRoot(dst, index);
4812 } else {
4813 __ li(dst, src_object, RelocInfo::COMPRESSED_EMBEDDED_OBJECT);
4814 }
4815 break;
4816 }
4818 UNREACHABLE(); // TODO(titzer): loading RPO numbers
4819 }
4820 if (destination->IsStackSlot()) {
4821 __ StoreWord(dst, g.ToMemOperand(destination));
4822 }
4823 } else if (src.type() == Constant::kFloat32) {
4824 if (destination->IsFPStackSlot()) {
4825 MemOperand dst = g.ToMemOperand(destination);
4826 if (base::bit_cast<int32_t>(src.ToFloat32()) == 0) {
4827 __ Sw(zero_reg, dst);
4828 } else {
4829 __ li(kScratchReg, Operand(base::bit_cast<int32_t>(src.ToFloat32())));
4830 __ Sw(kScratchReg, dst);
4831 }
4832 } else {
4833 DCHECK(destination->IsFPRegister());
4834 FloatRegister dst = g.ToSingleRegister(destination);
4835 __ LoadFPRImmediate(dst, src.ToFloat32());
4836 }
4837 } else {
4838 DCHECK_EQ(Constant::kFloat64, src.type());
4839 DoubleRegister dst = destination->IsFPRegister()
4840 ? g.ToDoubleRegister(destination)
4842 __ LoadFPRImmediate(dst, src.ToFloat64().value());
4843 if (destination->IsFPStackSlot()) {
4844 __ StoreDouble(dst, g.ToMemOperand(destination));
4845 }
4846 }
4847 } else if (source->IsFPRegister()) {
4850 VRegister src = g.ToSimd128Register(source);
4851 if (destination->IsSimd128Register()) {
4852 VRegister dst = g.ToSimd128Register(destination);
4853 __ VU.set(kScratchReg, E8, m1);
4854 __ vmv_vv(dst, src);
4855 } else {
4856 DCHECK(destination->IsSimd128StackSlot());
4857 __ VU.set(kScratchReg, E8, m1);
4858 MemOperand dst = g.ToMemOperand(destination);
4859 Register dst_r = dst.rm();
4860 if (dst.offset() != 0) {
4861 dst_r = kScratchReg;
4862 __ AddWord(dst_r, dst.rm(), dst.offset());
4863 }
4864 __ vs(src, dst_r, 0, E8);
4865 }
4866 } else {
4867 FPURegister src = g.ToDoubleRegister(source);
4868 if (destination->IsFPRegister()) {
4869 FPURegister dst = g.ToDoubleRegister(destination);
4871 // In src/builtins/wasm-to-js.tq:193
4872 //*toRef =
4873 //Convert<intptr>(Bitcast<uint32>(WasmTaggedToFloat32(retVal))); so
4874 // high 32 of src is 0. fmv.s can't NaNBox src.
4875 __ fmv_x_w(kScratchReg, src);
4876 __ fmv_w_x(dst, kScratchReg);
4877 } else {
4878 __ MoveDouble(dst, src);
4879 }
4880 } else {
4881 DCHECK(destination->IsFPStackSlot());
4883 __ StoreFloat(src, g.ToMemOperand(destination));
4884 } else {
4886 __ StoreDouble(src, g.ToMemOperand(destination));
4887 }
4888 }
4889 }
4890 } else if (source->IsFPStackSlot()) {
4891 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
4892 MemOperand src = g.ToMemOperand(source);
4895 __ VU.set(kScratchReg, E8, m1);
4896 Register src_r = src.rm();
4897 if (src.offset() != 0) {
4898 src_r = kScratchReg;
4899 __ AddWord(src_r, src.rm(), src.offset());
4900 }
4901 if (destination->IsSimd128Register()) {
4902 __ vl(g.ToSimd128Register(destination), src_r, 0, E8);
4903 } else {
4904 DCHECK(destination->IsSimd128StackSlot());
4905 VRegister temp = kSimd128ScratchReg;
4906 MemOperand dst = g.ToMemOperand(destination);
4907 Register dst_r = dst.rm();
4908 if (dst.offset() != 0) {
4909 dst_r = kScratchReg2;
4910 __ AddWord(dst_r, dst.rm(), dst.offset());
4911 }
4912 __ vl(temp, src_r, 0, E8);
4913 __ vs(temp, dst_r, 0, E8);
4914 }
4915 } else {
4916 if (destination->IsFPRegister()) {
4918 __ LoadFloat(g.ToDoubleRegister(destination), src);
4919 } else {
4921 __ LoadDouble(g.ToDoubleRegister(destination), src);
4922 }
4923 } else {
4924 DCHECK(destination->IsFPStackSlot());
4925 FPURegister temp = kScratchDoubleReg;
4927 __ LoadFloat(temp, src);
4928 __ StoreFloat(temp, g.ToMemOperand(destination));
4929 } else {
4931 __ LoadDouble(temp, src);
4932 __ StoreDouble(temp, g.ToMemOperand(destination));
4933 }
4934 }
4935 }
4936 } else {
4937 UNREACHABLE();
4938 }
4939}
4940
4941void CodeGenerator::AssembleSwap(InstructionOperand* source,
4942 InstructionOperand* destination) {
4943 RiscvOperandConverter g(this, nullptr);
4944 switch (MoveType::InferSwap(source, destination)) {
4946 if (source->IsRegister()) {
4947 Register temp = kScratchReg;
4948 Register src = g.ToRegister(source);
4949 Register dst = g.ToRegister(destination);
4950 __ Move(temp, src);
4951 __ Move(src, dst);
4952 __ Move(dst, temp);
4953 } else {
4954 if (source->IsFloatRegister() || source->IsDoubleRegister()) {
4955 FPURegister temp = kScratchDoubleReg;
4956 FPURegister src = g.ToDoubleRegister(source);
4957 FPURegister dst = g.ToDoubleRegister(destination);
4958 __ Move(temp, src);
4959 __ Move(src, dst);
4960 __ Move(dst, temp);
4961 } else {
4962 DCHECK(source->IsSimd128Register());
4963 VRegister src = g.ToDoubleRegister(source).toV();
4964 VRegister dst = g.ToDoubleRegister(destination).toV();
4965 VRegister temp = kSimd128ScratchReg;
4966 __ VU.set(kScratchReg, E8, m1);
4967 __ vmv_vv(temp, src);
4968 __ vmv_vv(src, dst);
4969 __ vmv_vv(dst, temp);
4970 }
4971 }
4972 break;
4974 MemOperand dst = g.ToMemOperand(destination);
4975 if (source->IsRegister()) {
4976 Register temp = kScratchReg;
4977 Register src = g.ToRegister(source);
4978 __ mv(temp, src);
4979 __ LoadWord(src, dst);
4980 __ StoreWord(temp, dst);
4981 } else {
4982 MemOperand dst = g.ToMemOperand(destination);
4983 if (source->IsFloatRegister()) {
4984 DoubleRegister src = g.ToDoubleRegister(source);
4986 __ fmv_s(temp, src);
4987 __ LoadFloat(src, dst);
4988 __ StoreFloat(temp, dst);
4989 } else if (source->IsDoubleRegister()) {
4990 DoubleRegister src = g.ToDoubleRegister(source);
4992 __ fmv_d(temp, src);
4993 __ LoadDouble(src, dst);
4994 __ StoreDouble(temp, dst);
4995 } else {
4996 DCHECK(source->IsSimd128Register());
4997 VRegister src = g.ToDoubleRegister(source).toV();
4998 VRegister temp = kSimd128ScratchReg;
4999 __ VU.set(kScratchReg, E8, m1);
5000 __ vmv_vv(temp, src);
5001 Register dst_v = dst.rm();
5002 if (dst.offset() != 0) {
5003 dst_v = kScratchReg2;
5004 __ AddWord(dst_v, dst.rm(), Operand(dst.offset()));
5005 }
5006 __ vl(src, dst_v, 0, E8);
5007 __ vs(temp, dst_v, 0, E8);
5008 }
5009 }
5010 } break;
5012 MemOperand src = g.ToMemOperand(source);
5013 MemOperand dst = g.ToMemOperand(destination);
5014 if (source->IsSimd128StackSlot()) {
5015 __ VU.set(kScratchReg, E8, m1);
5016 Register src_v = src.rm();
5017 Register dst_v = dst.rm();
5018 if (src.offset() != 0) {
5019 src_v = kScratchReg;
5020 __ AddWord(src_v, src.rm(), Operand(src.offset()));
5021 }
5022 if (dst.offset() != 0) {
5023 dst_v = kScratchReg2;
5024 __ AddWord(dst_v, dst.rm(), Operand(dst.offset()));
5025 }
5026 __ vl(kSimd128ScratchReg, src_v, 0, E8);
5027 __ vl(kSimd128ScratchReg2, dst_v, 0, E8);
5028 __ vs(kSimd128ScratchReg, dst_v, 0, E8);
5029 __ vs(kSimd128ScratchReg2, src_v, 0, E8);
5030 } else {
5031#if V8_TARGET_ARCH_RISCV32
5032 if (source->IsFPStackSlot()) {
5033 DCHECK(destination->IsFPStackSlot());
5037 FPURegister temp_double = kScratchDoubleReg;
5038 Register temp_word32 = kScratchReg;
5039 MemOperand src_hi(src.rm(), src.offset() + kSystemPointerSize);
5040 MemOperand dst_hi(dst.rm(), dst.offset() + kSystemPointerSize);
5041 __ LoadDouble(temp_double, src);
5042 __ Lw(temp_word32, dst);
5043 __ Sw(temp_word32, src);
5044 __ Lw(temp_word32, dst_hi);
5045 __ Sw(temp_word32, src_hi);
5046 __ StoreDouble(temp_double, dst);
5047 break;
5048 }
5049 }
5050#endif
5051 UseScratchRegisterScope scope(masm());
5052 Register temp_0 = kScratchReg;
5053 Register temp_1 = kScratchReg2;
5054 __ LoadWord(temp_0, src);
5055 __ LoadWord(temp_1, dst);
5056 __ StoreWord(temp_0, dst);
5057 __ StoreWord(temp_1, src);
5058 }
5059 } break;
5060 default:
5061 UNREACHABLE();
5062 }
5063}
5064
5065AllocatedOperand CodeGenerator::Push(InstructionOperand* source) {
5066 auto rep = LocationOperand::cast(source)->representation();
5067 int new_slots = ElementSizeInPointers(rep);
5068 RiscvOperandConverter g(this, nullptr);
5069 int last_frame_slot_id =
5070 frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
5071 int sp_delta = frame_access_state_->sp_delta();
5072 int slot_id = last_frame_slot_id + sp_delta + new_slots;
5073 AllocatedOperand stack_slot(LocationOperand::STACK_SLOT, rep, slot_id);
5074 if (source->IsRegister()) {
5075 __ Push(g.ToRegister(source));
5076 frame_access_state()->IncreaseSPDelta(new_slots);
5077 } else if (source->IsStackSlot()) {
5078 UseScratchRegisterScope temps(masm());
5079 Register scratch = temps.Acquire();
5080 __ LoadWord(scratch, g.ToMemOperand(source));
5081 __ Push(scratch);
5082 frame_access_state()->IncreaseSPDelta(new_slots);
5083 } else {
5084 // No push instruction for this operand type. Bump the stack pointer and
5085 // assemble the move.
5086 __ SubWord(sp, sp, Operand(new_slots * kSystemPointerSize));
5087 frame_access_state()->IncreaseSPDelta(new_slots);
5088 AssembleMove(source, &stack_slot);
5089 }
5090 temp_slots_ += new_slots;
5091 return stack_slot;
5092}
5093
5094void CodeGenerator::Pop(InstructionOperand* dest, MachineRepresentation rep) {
5095 int dropped_slots = ElementSizeInPointers(rep);
5096 RiscvOperandConverter g(this, nullptr);
5097 if (dest->IsRegister()) {
5098 frame_access_state()->IncreaseSPDelta(-dropped_slots);
5099 __ Pop(g.ToRegister(dest));
5100 } else if (dest->IsStackSlot()) {
5101 frame_access_state()->IncreaseSPDelta(-dropped_slots);
5102 UseScratchRegisterScope temps(masm());
5103 Register scratch = temps.Acquire();
5104 __ Pop(scratch);
5105 __ StoreWord(scratch, g.ToMemOperand(dest));
5106 } else {
5107 int last_frame_slot_id =
5108 frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
5109 int sp_delta = frame_access_state_->sp_delta();
5110 int slot_id = last_frame_slot_id + sp_delta;
5111 AllocatedOperand stack_slot(LocationOperand::STACK_SLOT, rep, slot_id);
5112 AssembleMove(&stack_slot, dest);
5113 frame_access_state()->IncreaseSPDelta(-dropped_slots);
5114 __ AddWord(sp, sp, Operand(dropped_slots * kSystemPointerSize));
5115 }
5116 temp_slots_ -= dropped_slots;
5117}
5118
5120 if (temp_slots_ > 0) {
5122 __ AddWord(sp, sp, Operand(temp_slots_ * kSystemPointerSize));
5123 temp_slots_ = 0;
5124 }
5125}
5126
5127void CodeGenerator::AssembleJumpTable(base::Vector<Label*> targets) {
5128 // On 64-bit RISC-V we emit the jump tables inline.
5129 UNREACHABLE();
5130}
5131
5132#undef ASSEMBLE_ATOMIC_LOAD_INTEGER
5133#undef ASSEMBLE_ATOMIC_STORE_INTEGER
5134#undef ASSEMBLE_ATOMIC_BINOP
5135#undef ASSEMBLE_ATOMIC_BINOP_EXT
5136#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
5137#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT
5138#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER
5139#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT
5140#undef ASSEMBLE_IEEE754_BINOP
5141#undef ASSEMBLE_IEEE754_UNOP
5142
5143#undef TRACE
5144#undef __
5145
5146} // namespace compiler
5147} // namespace internal
5148} // namespace v8
friend Zone
Definition asm-types.cc:195
#define Assert(condition)
static constexpr T decode(U value)
Definition bit-field.h:66
static constexpr bool IsBuiltinId(Builtin builtin)
Definition builtins.h:128
static constexpr int kFixedSlotCountAboveFp
static constexpr int kFixedFrameSizeAboveFp
static V8_EXPORT_PRIVATE const int kEagerDeoptExitSize
static V8_EXPORT_PRIVATE const int kLazyDeoptExitSize
static V8_EXPORT_PRIVATE ExternalReference isolate_address()
Bootstrapper * bootstrapper()
Definition isolate.h:1178
RootsTable & roots_table()
Definition isolate.h:1250
Tagged_t ReadOnlyRootPtr(RootIndex index)
static constexpr MainThreadFlags kPointersToHereAreInterestingMask
static constexpr MainThreadFlags kPointersFromHereAreInterestingMask
static Operand EmbeddedNumber(double number)
constexpr void set(RegisterT reg)
static constexpr bool IsNoInfo(Mode mode)
Definition reloc-info.h:257
bool IsRootHandle(IndirectHandle< T > handle, RootIndex *index) const
Definition roots-inl.h:65
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr int32_t TypeToMarker(Type type)
Definition frames.h:196
static constexpr int kFrameTypeOffset
T * New(Args &&... args)
Definition zone.h:114
static Type InferSwap(InstructionOperand *source, InstructionOperand *destination)
void MoveToTempLocation(InstructionOperand *src, MachineRepresentation rep) final
void AssembleTailCallAfterGap(Instruction *instr, int first_unused_stack_slot)
void AssembleReturn(InstructionOperand *pop)
void AssembleTailCallBeforeGap(Instruction *instr, int first_unused_stack_slot)
FrameAccessState * frame_access_state() const
CodeGenResult AssembleArchInstruction(Instruction *instr)
DeoptimizationExit * BuildTranslation(Instruction *instr, int pc_offset, size_t frame_state_offset, size_t immediate_args_count, OutputFrameStateCombine state_combine)
void AssembleArchBinarySearchSwitch(Instruction *instr)
void AssembleArchJumpRegardlessOfAssemblyOrder(RpoNumber target)
void AssembleArchBoolean(Instruction *instr, FlagsCondition condition)
void AssembleJumpTable(base::Vector< Label * > targets)
void AssembleArchBranch(Instruction *instr, BranchInfo *branch)
void AssembleMove(InstructionOperand *source, InstructionOperand *destination) final
void SetPendingMove(MoveOperands *move) final
bool ShouldApplyOffsetToStackCheck(Instruction *instr, uint32_t *offset)
void RecordSafepoint(ReferenceMap *references, int pc_offset=0)
void AssembleArchBinarySearchSwitchRange(Register input, RpoNumber def_block, std::pair< int32_t, Label * > *begin, std::pair< int32_t, Label * > *end)
void PrepareForDeoptimizationExits(ZoneDeque< DeoptimizationExit * > *exits)
void AssembleArchTableSwitch(Instruction *instr)
bool IsMaterializableFromRoot(Handle< HeapObject > object, RootIndex *index_return)
ZoneDeque< DeoptimizationExit * > deoptimization_exits_
void AssembleArchConditionalBranch(Instruction *instr, BranchInfo *branch)
AllocatedOperand Push(InstructionOperand *src) final
void MoveTempLocationTo(InstructionOperand *dst, MachineRepresentation rep) final
void AssembleArchDeoptBranch(Instruction *instr, BranchInfo *branch)
void RecordCallPosition(Instruction *instr)
void AssembleSwap(InstructionOperand *source, InstructionOperand *destination) final
void AssembleArchConditionalBoolean(Instruction *instr)
void RecordDeoptInfo(Instruction *instr, int pc_offset)
OptimizedCompilationInfo * info() const
void AssembleArchSelect(Instruction *instr, FlagsCondition condition)
void Pop(InstructionOperand *src, MachineRepresentation rep) final
FrameOffset GetFrameOffset(int spill_slot) const
Definition frame.cc:61
DoubleRegister ToDoubleRegister(InstructionOperand *op)
Constant ToConstant(InstructionOperand *op) const
Register ToRegister(InstructionOperand *op) const
const InstructionOperand * OutputAt(size_t i) const
InstructionCode opcode() const
const InstructionOperand * InputAt(size_t i) const
CallDescriptor * GetIncomingDescriptor() const
Definition linkage.h:405
MachineRepresentation representation() const
static LocationOperand * cast(InstructionOperand *op)
static OutputFrameStateCombine Ignore()
FloatRegister ToSingleRegister(InstructionOperand *op)
RiscvOperandConverter(CodeGenerator *gen, Instruction *instr)
MemOperand ToMemOperand(InstructionOperand *op) const
IndirectPointerTag indirect_pointer_tag_
#define ATOMIC_BINOP_CASE(op, inst)
#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)
bool must_save_lr_
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr, cmp_reg)
Zone * zone_
#define ASSEMBLE_IEEE754_UNOP(name)
Register const object_
Operand const offset_
#define ASSEMBLE_IEEE754_BINOP(name)
#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr)
Register const value_
#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr, order)
RecordWriteMode const mode_
#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT( load_linked, store_conditional, sign_extend, size, representation)
#define UNSUPPORTED_COND(opcode, condition)
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT( load_linked, store_conditional, sign_extend, size, representation)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
Definition globals.h:161
#define ARCH_OPCODE_LIST(V)
int32_t offset
DirectHandle< JSReceiver > options
Instruction * instr
ZoneVector< RpoNumber > & result
#define TRACE(...)
Builtin builtin
LiftoffRegister reg
int pc_offset
LiftoffRegList regs_to_save
SetIsolateDataSlots
InstructionOperand destination
v8::SourceLocation SourceLocation
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
constexpr T ByteSwap(T value)
uintptr_t Address
Definition memory.h:13
static bool HasRegisterInput(Instruction *instr, size_t index)
void AssembleBranchToLabels(CodeGenerator *gen, MacroAssembler *masm, Instruction *instr, FlagsCondition condition, Label *tlabel, Label *flabel, bool fallthru)
void Or(LiftoffAssembler *lasm, Register dst, Register lhs, Register rhs)
void Xor(LiftoffAssembler *lasm, Register dst, Register lhs, Register rhs)
void And(LiftoffAssembler *lasm, Register dst, Register lhs, Register rhs)
constexpr Register kGpParamRegisters[]
constexpr DoubleRegister kFpParamRegisters[]
constexpr Register kGpReturnRegisters[]
constexpr Register no_reg
constexpr Register kRootRegister
RegListBase< DoubleRegister > DoubleRegList
Definition reglist-arm.h:15
const uint32_t kExceptionIsSwitchStackLimit
V8_EXPORT_PRIVATE constexpr int ElementSizeInPointers(MachineRepresentation rep)
DwVfpRegister DoubleRegister
void PrintF(const char *format,...)
Definition utils.cc:39
constexpr Simd128Register kSimd128RegZero
constexpr DoubleRegister kScratchDoubleReg
RegListBase< Register > RegList
Definition reglist-arm.h:14
constexpr int kFloatSize
Definition globals.h:406
V8_INLINE constexpr bool IsValidIndirectPointerTag(IndirectPointerTag tag)
Address Tagged_t
Definition globals.h:547
constexpr Register kScratchReg2
constexpr int kSystemPointerSizeLog2
Definition globals.h:494
constexpr VRegister kSimd128ScratchReg2
constexpr Register kScratchReg
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
constexpr Register kSimulatorBreakArgument
QwNeonRegister Simd128Register
MemOperand FieldMemOperand(Register object, int offset)
constexpr DoubleRegister kSingleRegZero
constexpr int kSystemPointerSize
Definition globals.h:410
constexpr bool IsFloatingPoint(MachineRepresentation rep)
constexpr Simd128Register kSimd128ScratchReg
constexpr Register kReturnRegister0
constexpr Register kWasmImplicitArgRegister
constexpr VRegister kSimd128ScratchReg3
constexpr LowDwVfpRegister kDoubleRegZero
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr Register kJavaScriptCallCodeStartRegister
return value
Definition map-inl.h:893
constexpr Register cp
const int kNumCalleeSavedFPU
constexpr Register kCArgRegs[]
constexpr int kDoubleSize
Definition globals.h:407
constexpr Register kJavaScriptCallDispatchHandleRegister
static int FrameSlotToFPOffset(int slot)
SwVfpRegister FloatRegister
BodyGen *const gen_
BodyGen * gen
ro::BitSet tagged_slots
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
uint64_t make_uint64(uint32_t high, uint32_t low)
Definition macros.h:365
std::optional< CPURegister > scratch_reg
std::optional< UseScratchRegisterScope > temps
#define V8_STATIC_ROOTS_BOOL
Definition v8config.h:1001