Source code

Revision control

Copy as Markdown

Other Tools

// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef jit_riscv64_extension_Base_riscv_i_h_
#define jit_riscv64_extension_Base_riscv_i_h_
#include "mozilla/Assertions.h"
#include <stdint.h>
#include "jit/riscv64/constant/Constant-riscv64.h"
#include "jit/riscv64/extension/base-assembler-riscv.h"
namespace js {
namespace jit {
class AssemblerRISCVI : public AssemblerRiscvBase {
public:
void lui(Register rd, int32_t imm20);
void auipc(Register rd, int32_t imm20);
// Jumps
void jal(Register rd, int32_t imm20);
void jalr(Register rd, Register rs1, int16_t imm12);
// Branches
void beq(Register rs1, Register rs2, int16_t imm12);
void bne(Register rs1, Register rs2, int16_t imm12);
void blt(Register rs1, Register rs2, int16_t imm12);
void bge(Register rs1, Register rs2, int16_t imm12);
void bltu(Register rs1, Register rs2, int16_t imm12);
void bgeu(Register rs1, Register rs2, int16_t imm12);
// Loads
void lb(Register rd, Register rs1, int16_t imm12);
void lh(Register rd, Register rs1, int16_t imm12);
void lw(Register rd, Register rs1, int16_t imm12);
void lbu(Register rd, Register rs1, int16_t imm12);
void lhu(Register rd, Register rs1, int16_t imm12);
// Stores
void sb(Register source, Register base, int16_t imm12);
void sh(Register source, Register base, int16_t imm12);
void sw(Register source, Register base, int16_t imm12);
// Arithmetic with immediate
void addi(Register rd, Register rs1, int16_t imm12);
void slti(Register rd, Register rs1, int16_t imm12);
void sltiu(Register rd, Register rs1, int16_t imm12);
void xori(Register rd, Register rs1, int16_t imm12);
void ori(Register rd, Register rs1, int16_t imm12);
void andi(Register rd, Register rs1, int16_t imm12);
void slli(Register rd, Register rs1, uint8_t shamt);
void srli(Register rd, Register rs1, uint8_t shamt);
void srai(Register rd, Register rs1, uint8_t shamt);
// Arithmetic
void add(Register rd, Register rs1, Register rs2);
void sub(Register rd, Register rs1, Register rs2);
void sll(Register rd, Register rs1, Register rs2);
void slt(Register rd, Register rs1, Register rs2);
void sltu(Register rd, Register rs1, Register rs2);
void xor_(Register rd, Register rs1, Register rs2);
void srl(Register rd, Register rs1, Register rs2);
void sra(Register rd, Register rs1, Register rs2);
void or_(Register rd, Register rs1, Register rs2);
void and_(Register rd, Register rs1, Register rs2);
// Other pseudo instructions that are not part of RISCV pseudo assemly
void nor(Register rd, Register rs, Register rt) {
or_(rd, rs, rt);
not_(rd, rd);
}
// Memory fences
void fence(uint8_t pred, uint8_t succ);
void fence_tso();
// Environment call / break
void ecall();
void ebreak();
void sync() { fence(0b1111, 0b1111); }
// This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
// instruction (i.e., it should always trap, if your implementation has
// invalid instruction traps).
void unimp();
static int JumpOffset(Instr instr);
static int AuipcOffset(Instr instr);
static int JalrOffset(Instr instr);
static int LoadOffset(Instr instr);
static int BranchOffset(Instr instr);
static int BrachlongOffset(Instr auipc, Instr instr_I);
static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
Instr instr) {
int32_t imm = target_pos - pos;
MOZ_ASSERT((imm & 1) == 0);
MOZ_ASSERT(is_intn(imm, kBranchOffsetBits));
instr &= ~kBImm12Mask;
int32_t imm12 = ((imm & 0x800) >> 4) | // bit 11
((imm & 0x1e) << 7) | // bits 4-1
((imm & 0x7e0) << 20) | // bits 10-5
((imm & 0x1000) << 19); // bit 12
return instr | (imm12 & kBImm12Mask);
}
static inline Instr SetJalOffset(int32_t pos, int32_t target_pos,
Instr instr) {
MOZ_ASSERT(IsJal(instr));
int32_t imm = target_pos - pos;
MOZ_ASSERT((imm & 1) == 0);
MOZ_ASSERT(is_intn(imm, kJumpOffsetBits));
instr &= ~kImm20Mask;
int32_t imm20 = (imm & 0xff000) | // bits 19-12
((imm & 0x800) << 9) | // bit 11
((imm & 0x7fe) << 20) | // bits 10-1
((imm & 0x100000) << 11); // bit 20
return instr | (imm20 & kImm20Mask);
}
static inline Instr SetJalrOffset(int32_t offset, Instr instr) {
MOZ_ASSERT(IsJalr(instr));
MOZ_ASSERT(is_int12(offset));
instr &= ~kImm12Mask;
int32_t imm12 = offset << kImm12Shift;
MOZ_ASSERT(IsJalr(instr | (imm12 & kImm12Mask)));
MOZ_ASSERT(JalrOffset(instr | (imm12 & kImm12Mask)) == offset);
return instr | (imm12 & kImm12Mask);
}
static inline Instr SetLoadOffset(int32_t offset, Instr instr) {
#if JS_CODEGEN_RISCV64
MOZ_ASSERT(IsLd(instr));
#elif JS_CODEGEN_RISCV32
MOZ_ASSERT(IsLw(instr));
#endif
MOZ_ASSERT(is_int12(offset));
instr &= ~kImm12Mask;
int32_t imm12 = offset << kImm12Shift;
return instr | (imm12 & kImm12Mask);
}
static inline Instr SetAuipcOffset(int32_t offset, Instr instr) {
MOZ_ASSERT(IsAuipc(instr));
MOZ_ASSERT(is_int20(offset));
instr = (instr & ~kImm31_12Mask) | ((offset & kImm19_0Mask) << 12);
return instr;
}
// Check if an instruction is a branch of some kind.
static bool IsBranch(Instr instr);
static bool IsNop(Instr instr);
static bool IsJump(Instr instr);
static bool IsJal(Instr instr);
static bool IsJalr(Instr instr);
static bool IsLui(Instr instr);
static bool IsAuipc(Instr instr);
static bool IsAddi(Instr instr);
static bool IsOri(Instr instr);
static bool IsSlli(Instr instr);
static bool IsLw(Instr instr);
inline int32_t branch_offset(Label* L) {
return branch_offset_helper(L, OffsetSize::kOffset13);
}
inline int32_t jump_offset(Label* L) {
return branch_offset_helper(L, OffsetSize::kOffset21);
}
// Branches
void beq(Register rs1, Register rs2, Label* L) {
beq(rs1, rs2, branch_offset(L));
}
void bne(Register rs1, Register rs2, Label* L) {
bne(rs1, rs2, branch_offset(L));
}
void blt(Register rs1, Register rs2, Label* L) {
blt(rs1, rs2, branch_offset(L));
}
void bge(Register rs1, Register rs2, Label* L) {
bge(rs1, rs2, branch_offset(L));
}
void bltu(Register rs1, Register rs2, Label* L) {
bltu(rs1, rs2, branch_offset(L));
}
void bgeu(Register rs1, Register rs2, Label* L) {
bgeu(rs1, rs2, branch_offset(L));
}
void beqz(Register rs, int16_t imm13) { beq(rs, zero_reg, imm13); }
void beqz(Register rs1, Label* L) { beqz(rs1, branch_offset(L)); }
void bnez(Register rs, int16_t imm13) { bne(rs, zero_reg, imm13); }
void bnez(Register rs1, Label* L) { bnez(rs1, branch_offset(L)); }
void blez(Register rs, int16_t imm13) { bge(zero_reg, rs, imm13); }
void blez(Register rs1, Label* L) { blez(rs1, branch_offset(L)); }
void bgez(Register rs, int16_t imm13) { bge(rs, zero_reg, imm13); }
void bgez(Register rs1, Label* L) { bgez(rs1, branch_offset(L)); }
void bltz(Register rs, int16_t imm13) { blt(rs, zero_reg, imm13); }
void bltz(Register rs1, Label* L) { bltz(rs1, branch_offset(L)); }
void bgtz(Register rs, int16_t imm13) { blt(zero_reg, rs, imm13); }
void bgtz(Register rs1, Label* L) { bgtz(rs1, branch_offset(L)); }
void bgt(Register rs1, Register rs2, int16_t imm13) { blt(rs2, rs1, imm13); }
void bgt(Register rs1, Register rs2, Label* L) {
bgt(rs1, rs2, branch_offset(L));
}
void ble(Register rs1, Register rs2, int16_t imm13) { bge(rs2, rs1, imm13); }
void ble(Register rs1, Register rs2, Label* L) {
ble(rs1, rs2, branch_offset(L));
}
void bgtu(Register rs1, Register rs2, int16_t imm13) {
bltu(rs2, rs1, imm13);
}
void bgtu(Register rs1, Register rs2, Label* L) {
bgtu(rs1, rs2, branch_offset(L));
}
void bleu(Register rs1, Register rs2, int16_t imm13) {
bgeu(rs2, rs1, imm13);
}
void bleu(Register rs1, Register rs2, Label* L) {
bleu(rs1, rs2, branch_offset(L));
}
void j(int32_t imm21) { jal(zero_reg, imm21); }
void j(Label* L) { j(jump_offset(L)); }
void b(Label* L) { j(L); }
void jal(int32_t imm21) { jal(ra, imm21); }
void jal(Label* L) { jal(jump_offset(L)); }
void jr(Register rs) { jalr(zero_reg, rs, 0); }
void jr(Register rs, int32_t imm12) { jalr(zero_reg, rs, imm12); }
void jalr(Register rs, int32_t imm12) { jalr(ra, rs, imm12); }
void jalr(Register rs) { jalr(ra, rs, 0); }
void call(int32_t offset) {
auipc(ra, (offset >> 12) + ((offset & 0x800) >> 11));
jalr(ra, ra, offset << 20 >> 20);
}
void mv(Register rd, Register rs) { addi(rd, rs, 0); }
void not_(Register rd, Register rs) { xori(rd, rs, -1); }
void neg(Register rd, Register rs) { sub(rd, zero_reg, rs); }
void seqz(Register rd, Register rs) { sltiu(rd, rs, 1); }
void snez(Register rd, Register rs) { sltu(rd, zero_reg, rs); }
void sltz(Register rd, Register rs) { slt(rd, rs, zero_reg); }
void sgtz(Register rd, Register rs) { slt(rd, zero_reg, rs); }
#if JS_CODEGEN_RISCV64
void lwu(Register rd, Register rs1, int16_t imm12);
void ld(Register rd, Register rs1, int16_t imm12);
void sd(Register source, Register base, int16_t imm12);
void addiw(Register rd, Register rs1, int16_t imm12);
void slliw(Register rd, Register rs1, uint8_t shamt);
void srliw(Register rd, Register rs1, uint8_t shamt);
void sraiw(Register rd, Register rs1, uint8_t shamt);
void addw(Register rd, Register rs1, Register rs2);
void subw(Register rd, Register rs1, Register rs2);
void sllw(Register rd, Register rs1, Register rs2);
void srlw(Register rd, Register rs1, Register rs2);
void sraw(Register rd, Register rs1, Register rs2);
void negw(Register rd, Register rs) { subw(rd, zero_reg, rs); }
void sext_w(Register rd, Register rs) { addiw(rd, rs, 0); }
static bool IsAddiw(Instr instr);
static bool IsLd(Instr instr);
#endif
};
} // namespace jit
} // namespace js
#endif // jit_riscv64_extension_Base_riscv_I_h_