tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 96837ab7824d38825845fa93dfaac2d6cae3d078
parent 319893b3df863f59e21aff56bc9714857a81a6b0
Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
Date:   Mon, 15 Dec 2025 01:23:03 +0000

Bug 2003218 - Support RISCV-V Zbb extension. r=spidermonkey-reviewers,csmantle,jandem

Tested on HiFive P550 and simulator.

Differential Revision: https://phabricator.services.mozilla.com/D274545

Diffstat:
Mjs/src/jit/JitContext.cpp | 4++++
Mjs/src/jit/moz.build | 1+
Mjs/src/jit/riscv64/Architecture-riscv64.cpp | 8+++-----
Mjs/src/jit/riscv64/Assembler-riscv64.cpp | 28++++++++++++++++++++++++++++
Mjs/src/jit/riscv64/Assembler-riscv64.h | 17+++++++++++++++++
Mjs/src/jit/riscv64/MacroAssembler-riscv64.cpp | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mjs/src/jit/riscv64/MacroAssembler-riscv64.h | 8++++++++
Mjs/src/jit/riscv64/Simulator-riscv64.cpp | 309++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mjs/src/jit/riscv64/constant/Base-constant-riscv.h | 19+++++++++++++------
Ajs/src/jit/riscv64/constant/Constant-riscv-b.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mjs/src/jit/riscv64/constant/Constant-riscv-i.h | 21+++++++++++++++------
Mjs/src/jit/riscv64/constant/Constant-riscv64.h | 1+
Mjs/src/jit/riscv64/disasm/Disasm-riscv64.cpp | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mjs/src/jit/riscv64/extension/base-assembler-riscv.cc | 14++++++++------
Mjs/src/jit/riscv64/extension/base-assembler-riscv.h | 4++--
Ajs/src/jit/riscv64/extension/extension-riscv-b.cc | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ajs/src/jit/riscv64/extension/extension-riscv-b.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17 files changed, 1003 insertions(+), 58 deletions(-)

diff --git a/js/src/jit/JitContext.cpp b/js/src/jit/JitContext.cpp @@ -119,6 +119,10 @@ bool jit::InitializeJit() { MIPSFlags::Init(); #endif +#ifdef JS_CODEGEN_RISCV64 + RVFlags::Init(); +#endif + #ifndef JS_CODEGEN_NONE MOZ_ASSERT(js::jit::CPUFlagsHaveBeenComputed()); #endif diff --git a/js/src/jit/moz.build b/js/src/jit/moz.build @@ -236,6 +236,7 @@ elif CONFIG["JS_CODEGEN_RISCV64"]: "riscv64/extension/base-assembler-riscv.cc", "riscv64/extension/base-riscv-i.cc", "riscv64/extension/extension-riscv-a.cc", + "riscv64/extension/extension-riscv-b.cc", "riscv64/extension/extension-riscv-c.cc", "riscv64/extension/extension-riscv-d.cc", "riscv64/extension/extension-riscv-f.cc", diff --git a/js/src/jit/riscv64/Architecture-riscv64.cpp b/js/src/jit/riscv64/Architecture-riscv64.cpp @@ -8,7 +8,9 @@ #include "jit/FlushICache.h" // js::jit::FlushICache #include "jit/RegisterSets.h" +#include "jit/riscv64/MacroAssembler-riscv64.h" #include "jit/Simulator.h" + namespace js { namespace jit { Registers::Code Registers::FromName(const char* name) { @@ -90,11 +92,7 @@ void FlushICache(void* code, size_t size) { #endif } -bool CPUFlagsHaveBeenComputed() { - // TODO Add CPU flags support - // Flags were computed above. - return true; -} +bool CPUFlagsHaveBeenComputed() { return RVFlags::FlagsHaveBeenComputed(); } } // namespace jit } // namespace js diff --git a/js/src/jit/riscv64/Assembler-riscv64.cpp b/js/src/jit/riscv64/Assembler-riscv64.cpp @@ -49,10 +49,38 @@ #include "vm/Realm.h" #include "wasm/WasmFrame.h" +#if defined(__linux__) && !defined(JS_SIMULATOR_RISCV64) +# include <sys/syscall.h> +# if __has_include(<asm/hwprobe.h>) +# include <asm/hwprobe.h> +# endif +#endif + using mozilla::DebugOnly; namespace js { namespace jit { +// static +void RVFlags::Init() { + MOZ_ASSERT(!sComputed); +#if defined(__linux__) && !defined(JS_SIMULATOR_RISCV64) && \ + __has_include(<asm/hwprobe.h>) + riscv_hwprobe probe[1] = {{RISCV_HWPROBE_KEY_IMA_EXT_0, 0}}; + if (syscall(__NR_riscv_hwprobe, probe, 1, 0, nullptr, 0) == 0) { + if (probe[0].value & RISCV_HWPROBE_EXT_ZBB) { + sZbbExtension = true; + } + } +#else + if (getenv("RISCV_EXT_ZBB")) { + // Force on Zbb extension for testing purposes or on non-linux platforms. + sZbbExtension = true; + } +#endif + + sComputed = true; +} + #define UNIMPLEMENTED_RISCV() MOZ_CRASH("RISC_V not implemented"); bool Assembler::FLAG_riscv_debug = false; diff --git a/js/src/jit/riscv64/Assembler-riscv64.h b/js/src/jit/riscv64/Assembler-riscv64.h @@ -56,6 +56,7 @@ #include "jit/riscv64/extension/base-assembler-riscv.h" #include "jit/riscv64/extension/base-riscv-i.h" #include "jit/riscv64/extension/extension-riscv-a.h" +#include "jit/riscv64/extension/extension-riscv-b.h" #include "jit/riscv64/extension/extension-riscv-c.h" #include "jit/riscv64/extension/extension-riscv-d.h" #include "jit/riscv64/extension/extension-riscv-f.h" @@ -72,6 +73,19 @@ namespace js { namespace jit { +class RVFlags final { + public: + static void Init(); + + static bool FlagsHaveBeenComputed() { return sComputed; } + + static bool HasZbbExtension() { return sZbbExtension; } + + private: + static inline bool sZbbExtension = false; + static inline bool sComputed = false; +}; + struct ScratchFloat32Scope : public AutoFloatRegisterScope { explicit ScratchFloat32Scope(MacroAssembler& masm) : AutoFloatRegisterScope(masm, ScratchFloat32Reg) {} @@ -119,6 +133,7 @@ typedef js::jit::AssemblerBufferWithConstantPools< class Assembler : public AssemblerShared, public AssemblerRISCVI, public AssemblerRISCVA, + public AssemblerRISCVB, public AssemblerRISCVF, public AssemblerRISCVD, public AssemblerRISCVM, @@ -490,6 +505,8 @@ class Assembler : public AssemblerShared, MOZ_CRASH("unexpected mode"); } + static bool HasZbbExtension() { return RVFlags::HasZbbExtension(); } + void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, const Disassembler::HeapAccess& heapAccess) { MOZ_CRASH(); diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64.cpp b/js/src/jit/riscv64/MacroAssembler-riscv64.cpp @@ -6248,6 +6248,15 @@ void MacroAssemblerRiscv64::BranchFloat64(DoubleCondition cc, } void MacroAssemblerRiscv64::Clz32(Register rd, Register xx) { + if (HasZbbExtension()) { +#if JS_CODEGEN_RISCV64 + clzw(rd, xx); +#else + clz(rd, xx); +#endif + return; + } + // 32 bit unsigned in lower word: count number of leading zeros. // int n = 32; // unsigned y; @@ -6377,6 +6386,15 @@ void MacroAssemblerRiscv64::Clz64(Register rd, Register xx) { } #endif void MacroAssemblerRiscv64::Ctz32(Register rd, Register rs) { + if (HasZbbExtension()) { +#if JS_CODEGEN_RISCV64 + ctzw(rd, rs); +#else + ctz(rd, rs); +#endif + return; + } + // Convert trailing zeroes to trailing ones, and bits to their left // to zeroes. @@ -6400,6 +6418,11 @@ void MacroAssemblerRiscv64::Ctz32(Register rd, Register rs) { } #if JS_CODEGEN_RISCV64 void MacroAssemblerRiscv64::Ctz64(Register rd, Register rs) { + if (HasZbbExtension()) { + ctz(rd, rs); + return; + } + // Convert trailing zeroes to trailing ones, and bits to their left // to zeroes. { @@ -6423,6 +6446,15 @@ void MacroAssemblerRiscv64::Ctz64(Register rd, Register rs) { #endif void MacroAssemblerRiscv64::Popcnt32(Register rd, Register rs, Register scratch) { + if (HasZbbExtension()) { +#if JS_CODEGEN_RISCV64 + cpopw(rd, rs); +#else + cpop(rd, rs); +#endif + return; + } + MOZ_ASSERT(scratch != rs); MOZ_ASSERT(scratch != rd); // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel @@ -6474,6 +6506,11 @@ void MacroAssemblerRiscv64::Popcnt32(Register rd, Register rs, #if JS_CODEGEN_RISCV64 void MacroAssemblerRiscv64::Popcnt64(Register rd, Register rs, Register scratch) { + if (HasZbbExtension()) { + cpop(rd, rs); + return; + } + MOZ_ASSERT(scratch != rs); MOZ_ASSERT(scratch != rd); // uint64_t B0 = 0x5555555555555555l; // (T)~(T)0/3 @@ -6598,9 +6635,19 @@ void MacroAssemblerRiscv64::ma_fmovz(FloatFormat fmt, FloatRegister fd, void MacroAssemblerRiscv64::ByteSwap(Register rd, Register rs, int operand_size, Register scratch) { + MOZ_ASSERT(operand_size == 4 || operand_size == 8); +#if JS_CODEGEN_RISCV64 + if (HasZbbExtension()) { + rev8(rd, rs); + if (operand_size == 4) { + srai(rd, rd, 32); + } + return; + } +#endif + MOZ_ASSERT(scratch != rs); MOZ_ASSERT(scratch != rd); - MOZ_ASSERT(operand_size == 4 || operand_size == 8); if (operand_size == 4) { // Uint32_t x1 = 0x00FF00FF; // x0 = (x0 << 16 | x0 >> 16); @@ -6749,6 +6796,18 @@ void MacroAssemblerRiscv64::Rol(Register rd, Register rs, const Operand& rt) { } void MacroAssemblerRiscv64::Ror(Register rd, Register rs, const Operand& rt) { + if (HasZbbExtension()) { + if (rt.is_reg()) { + rorw(rd, rs, rt.rm()); + } else { + int64_t ror_value = rt.immediate() % 32; + if (ror_value < 0) { + ror_value += 32; + } + roriw(rd, rs, ror_value); + } + return; + } UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); if (rt.is_reg()) { @@ -6785,6 +6844,18 @@ void MacroAssemblerRiscv64::Drol(Register rd, Register rs, const Operand& rt) { } void MacroAssemblerRiscv64::Dror(Register rd, Register rs, const Operand& rt) { + if (HasZbbExtension()) { + if (rt.is_reg()) { + ror(rd, rs, rt.rm()); + } else { + int64_t dror_value = rt.immediate() % 64; + if (dror_value < 0) { + dror_value += 64; + } + rori(rd, rs, dror_value); + } + return; + } UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); if (rt.is_reg()) { diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64.h b/js/src/jit/riscv64/MacroAssembler-riscv64.h @@ -1071,11 +1071,19 @@ class MacroAssemblerRiscv64Compat : public MacroAssemblerRiscv64 { FaultingCodeOffset load16ZeroExtend(const BaseIndex& src, Register dest); void SignExtendByte(Register rd, Register rs) { + if (HasZbbExtension()) { + sextb(rd, rs); + return; + } slli(rd, rs, xlen - 8); srai(rd, rd, xlen - 8); } void SignExtendShort(Register rd, Register rs) { + if (HasZbbExtension()) { + sexth(rd, rs); + return; + } slli(rd, rs, xlen - 16); srai(rd, rd, xlen - 16); } diff --git a/js/src/jit/riscv64/Simulator-riscv64.cpp b/js/src/jit/riscv64/Simulator-riscv64.cpp @@ -1989,11 +1989,23 @@ void Simulator::DecodeRVRType() { set_rd(rs1() & rs2()); break; } + case RO_ANDN: + set_rd(rs1() & ~rs2()); + break; + case RO_ORN: + set_rd(rs1() | (~rs2())); + break; + case RO_XNOR: + set_rd((~rs1()) ^ (~rs2())); + break; # ifdef JS_CODEGEN_RISCV64 case RO_ADDW: { set_rd(sext32(rs1() + rs2())); break; } + case RO_ADDUW: + set_rd(zext32(rs1()) + rs2()); + break; case RO_SUBW: { set_rd(sext32(rs1() - rs2())); break; @@ -2010,6 +2022,30 @@ void Simulator::DecodeRVRType() { set_rd(sext32(int32_t(rs1()) >> (rs2() & 0x1F))); break; } + case RO_SH1ADDUW: { + set_rd(rs2() + (zext32(rs1()) << 1)); + break; + } + case RO_SH2ADDUW: { + set_rd(rs2() + (zext32(rs1()) << 2)); + break; + } + case RO_SH3ADDUW: { + set_rd(rs2() + (zext32(rs1()) << 3)); + break; + } + case RO_ROLW: { + reg_t extz_rs1 = zext32(rs1()); + sreg_t shamt = rs2() & 31; + set_rd(sext32((extz_rs1 << shamt) | (extz_rs1 >> (32 - shamt)))); + break; + } + case RO_RORW: { + reg_t extz_rs1 = zext32(rs1()); + sreg_t shamt = rs2() & 31; + set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt)))); + break; + } # endif /* JS_CODEGEN_RISCV64 */ // TODO(riscv): Add RISCV M extension macro case RO_MUL: { @@ -2122,6 +2158,64 @@ void Simulator::DecodeRVRType() { break; } # endif /*JS_CODEGEN_RISCV64*/ + case RO_SH1ADD: + set_rd(rs2() + (rs1() << 1)); + break; + case RO_SH2ADD: + set_rd(rs2() + (rs1() << 2)); + break; + case RO_SH3ADD: + set_rd(rs2() + (rs1() << 3)); + break; + case RO_MAX: + set_rd(rs1() < rs2() ? rs2() : rs1()); + break; + case RO_MAXU: + set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs2() + : rs1()); + break; + case RO_MIN: + set_rd(rs1() < rs2() ? rs1() : rs2()); + break; + case RO_MINU: + set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs1() + : rs2()); + break; + case RO_ZEXTH: + set_rd(zext_xlen(uint16_t(rs1()))); + break; + case RO_ROL: { + sreg_t shamt = rs2() & (xlen - 1); + set_rd((static_cast<reg_t>(rs1()) << shamt) | + (static_cast<reg_t>(rs1()) >> (xlen - shamt))); + break; + } + case RO_ROR: { + sreg_t shamt = rs2() & (xlen - 1); + set_rd((static_cast<reg_t>(rs1()) >> shamt) | + (static_cast<reg_t>(rs1()) << (xlen - shamt))); + break; + } + case RO_BCLR: { + sreg_t index = rs2() & (xlen - 1); + set_rd(rs1() & ~(1l << index)); + break; + } + case RO_BEXT: { + sreg_t index = rs2() & (xlen - 1); + set_rd((rs1() >> index) & 1); + break; + } + case RO_BINV: { + sreg_t index = rs2() & (xlen - 1); + set_rd(rs1() ^ (1 << index)); + break; + } + case RO_BSET: { + sreg_t index = rs2() & (xlen - 1); + set_rd(rs1() | (1 << index)); + break; + } // TODO(riscv): End Add RISCV M extension macro default: { switch (instr_.BaseOpcode()) { @@ -3488,18 +3582,137 @@ void Simulator::DecodeRVIType() { set_rd(imm12() & rs1()); break; } - case RO_SLLI: { - require(shamt6() < xlen); - set_rd(sext_xlen(rs1() << shamt6())); + case OP_SHL: { + switch (instr_.Funct6FieldRaw() | OP_SHL) { + case RO_SLLI: + require(shamt6() < xlen); + set_rd(sext_xlen(rs1() << shamt6())); + break; + case RO_BCLRI: { + require(shamt6() < xlen); + sreg_t index = shamt6() & (xlen - 1); + set_rd(rs1() & ~(1l << index)); + break; + } + case RO_BINVI: { + require(shamt6() < xlen); + sreg_t index = shamt6() & (xlen - 1); + set_rd(rs1() ^ (1l << index)); + break; + } + case RO_BSETI: { + require(shamt6() < xlen); + sreg_t index = shamt6() & (xlen - 1); + set_rd(rs1() | (1l << index)); + break; + } + case OP_COUNT: + switch (instr_.Shamt()) { + case 0: { // clz + sreg_t x = rs1(); + int highest_setbit = -1; + for (auto i = xlen - 1; i >= 0; i--) { + if ((x & (1l << i))) { + highest_setbit = i; + break; + } + } + set_rd(xlen - 1 - highest_setbit); + break; + } + case 1: { // ctz + sreg_t x = rs1(); + int lowest_setbit = xlen; + for (auto i = 0; i < xlen; i++) { + if ((x & (1l << i))) { + lowest_setbit = i; + break; + } + } + set_rd(lowest_setbit); + break; + } + case 2: { // cpop + int i = 0; + sreg_t n = rs1(); + while (n) { + n &= (n - 1); + i++; + } + set_rd(i); + break; + } + case 4: + set_rd(static_cast<int8_t>(rs1())); + break; + case 5: + set_rd(static_cast<int16_t>(rs1())); + break; + default: + UNSUPPORTED(); + } + break; + default: + UNSUPPORTED(); + } break; } - case RO_SRLI: { // RO_SRAI - if (!instr_.IsArithShift()) { - require(shamt6() < xlen); - set_rd(sext_xlen(zext_xlen(rs1()) >> shamt6())); - } else { - require(shamt6() < xlen); - set_rd(sext_xlen(sext_xlen(rs1()) >> shamt6())); + case OP_SHR: { // RO_SRAI + switch (instr_.Funct6FieldRaw() | OP_SHR) { + case RO_SRLI: + require(shamt6() < xlen); + set_rd(sext_xlen(zext_xlen(rs1()) >> shamt6())); + break; + case RO_SRAI: + require(shamt6() < xlen); + set_rd(sext_xlen(sext_xlen(rs1()) >> shamt6())); + break; + case RO_BEXTI: { + require(shamt6() < xlen); + sreg_t index = shamt6() & (xlen - 1); + set_rd((rs1() >> index) & 1); + break; + } + case RO_ORCB&(kFunct6Mask | OP_SHR): { + reg_t rs1_val = rs1(); + reg_t result = 0; + reg_t mask = 0xFF; + reg_t step = 8; + for (reg_t i = 0; i < xlen; i += step) { + if ((rs1_val & mask) != 0) { + result |= mask; + } + mask <<= step; + } + set_rd(result); + break; + } + case RO_RORI: { +# ifdef JS_CODEGEN_RISCV64 + int16_t shamt = shamt6(); +# else + int16_t shamt = shamt5(); +# endif + set_rd((static_cast<reg_t>(rs1()) >> shamt) | + (static_cast<reg_t>(rs1()) << (xlen - shamt))); + break; + } + case RO_REV8: { + if (imm12() == RO_REV8_IMM12) { + reg_t input = rs1(); + reg_t output = 0; + reg_t j = xlen - 1; + for (int i = 0; i < xlen; i += 8) { + output |= ((input >> (j - 7)) & 0xff) << i; + j -= 8; + } + set_rd(output); + break; + } + UNSUPPORTED(); + } + default: + UNSUPPORTED(); } break; } @@ -3508,15 +3721,75 @@ void Simulator::DecodeRVIType() { set_rd(sext32(rs1() + imm12())); break; } - case RO_SLLIW: { - set_rd(sext32(rs1() << shamt5())); + case OP_SHLW: + switch (instr_.Funct7FieldRaw() | OP_SHLW) { + case RO_SLLIW: + set_rd(sext32(rs1() << shamt5())); + break; + case RO_SLLIUW: + set_rd(zext32(rs1()) << shamt6()); + break; + case OP_COUNTW: { + switch (instr_.Shamt()) { + case 0: { // clzw + sreg_t x = rs1(); + int highest_setbit = -1; + for (auto i = 31; i >= 0; i--) { + if ((x & (1l << i))) { + highest_setbit = i; + break; + } + } + set_rd(31 - highest_setbit); + break; + } + case 1: { // ctzw + sreg_t x = rs1(); + int lowest_setbit = 32; + for (auto i = 0; i < 32; i++) { + if ((x & (1l << i))) { + lowest_setbit = i; + break; + } + } + set_rd(lowest_setbit); + break; + } + case 2: { // cpopw + int i = 0; + int32_t n = static_cast<int32_t>(rs1()); + while (n) { + n &= (n - 1); + i++; + } + set_rd(i); + break; + } + default: + UNSUPPORTED(); + } + break; + } + default: + UNSUPPORTED(); + } break; - } - case RO_SRLIW: { // RO_SRAIW - if (!instr_.IsArithShift()) { - set_rd(sext32(uint32_t(rs1()) >> shamt5())); - } else { - set_rd(sext32(int32_t(rs1()) >> shamt5())); + case OP_SHRW: { // RO_SRAI + switch (instr_.Funct7FieldRaw() | OP_SHRW) { + case RO_SRLIW: + set_rd(sext32(uint32_t(rs1()) >> shamt5())); + break; + case RO_SRAIW: + set_rd(sext32(int32_t(rs1()) >> shamt5())); + break; + case RO_RORIW: { + reg_t extz_rs1 = zext32(rs1()); + int16_t shamt = shamt5(); + set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt)))); + break; + } + default: + UNSUPPORTED(); } break; } diff --git a/js/src/jit/riscv64/constant/Base-constant-riscv.h b/js/src/jit/riscv64/constant/Base-constant-riscv.h @@ -52,6 +52,8 @@ typedef unsigned char byte; // RISCV constants const int kBaseOpcodeShift = 0; const int kBaseOpcodeBits = 7; +const int kFunct6Shift = 26; +const int kFunct6Bits = 6; const int kFunct7Shift = 25; const int kFunct7Bits = 7; const int kFunct5Shift = 27; @@ -82,6 +84,7 @@ const int kImm11Shift = 2; const int kImm11Bits = 11; const int kShamtShift = 20; const int kShamtBits = 5; +const uint32_t kShamtMask = (((1 << kShamtBits) - 1) << kShamtShift); const int kShamtWShift = 20; // FIXME: remove this once we have a proper way to handle the wide shift amount const int kShamtWBits = 6; @@ -137,6 +140,7 @@ const uint32_t kBaseOpcodeMask = ((1 << kBaseOpcodeBits) - 1) << kBaseOpcodeShift; const uint32_t kFunct3Mask = ((1 << kFunct3Bits) - 1) << kFunct3Shift; const uint32_t kFunct5Mask = ((1 << kFunct5Bits) - 1) << kFunct5Shift; +const uint32_t kFunct6Mask = ((1 << kFunct6Bits) - 1) << kFunct6Shift; const uint32_t kFunct7Mask = ((1 << kFunct7Bits) - 1) << kFunct7Shift; const uint32_t kFunct2Mask = 0b11 << kFunct7Shift; const uint32_t kRTypeMask = kBaseOpcodeMask | kFunct3Mask | kFunct7Mask; @@ -255,11 +259,10 @@ const uint32_t kRvvNfMask = (((1 << kRvvNfBits) - 1) << kRvvNfShift); const int kNopByte = 0x00000013; enum BaseOpcode : uint32_t { - LOAD = 0b0000011, // I form: LB LH LW LBU LHU - LOAD_FP = 0b0000111, // I form: FLW FLD FLQ - MISC_MEM = 0b0001111, // I special form: FENCE FENCE.I - OP_IMM = 0b0010011, // I form: ADDI SLTI SLTIU XORI ORI ANDI SLLI SRLI SRAI - // Note: SLLI/SRLI/SRAI I form first, then func3 001/101 => R type + LOAD = 0b0000011, // I form: LB LH LW LBU LHU + LOAD_FP = 0b0000111, // I form: FLW FLD FLQ + MISC_MEM = 0b0001111, // I special form: FENCE FENCE.I + OP_IMM = 0b0010011, // I form: ADDI SLTI SLTIU XORI ORI ANDI AUIPC = 0b0010111, // U form: AUIPC OP_IMM_32 = 0b0011011, // I form: ADDIW SLLIW SRLIW SRAIW // Note: SRLIW SRAIW I form first, then func3 101 special shift encoding @@ -557,6 +560,9 @@ class InstructionBase { // Safe to call within R-type instructions inline int Funct7FieldRaw() const { return InstructionBits() & kFunct7Mask; } + // Safe to call within R-type instructions + inline int Funct6FieldRaw() const { return InstructionBits() & kFunct6Mask; } + // Safe to call within R-, I-, S-, or B-type instructions inline int Funct3FieldRaw() const { return InstructionBits() & kFunct3Mask; } @@ -787,7 +793,8 @@ class InstructionGetters : public T { inline int Shamt() const { // Valid only for shift instructions (SLLI, SRLI, SRAI) - MOZ_ASSERT((this->InstructionBits() & kBaseOpcodeMask) == OP_IMM && + MOZ_ASSERT(((this->InstructionBits() & kBaseOpcodeMask) == OP_IMM || + (this->InstructionBits() & kBaseOpcodeMask) == OP_IMM_32) && (this->Funct3Value() == 0b001 || this->Funct3Value() == 0b101)); // | 0A0000 | shamt | rs1 | funct3 | rd | opcode | // 31 25 20 diff --git a/js/src/jit/riscv64/constant/Constant-riscv-b.h b/js/src/jit/riscv64/constant/Constant-riscv-b.h @@ -0,0 +1,95 @@ +// Copyright 2023 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_constant_Constant_riscv64_b_h_ +#define jit_riscv64_constant_Constant_riscv64_b_h_ + +#include "jit/riscv64/constant/Base-constant-riscv.h" + +namespace js { +namespace jit { + +enum OpcodeRISCVB : uint32_t { +#ifdef JS_CODEGEN_RISCV64 + RO_ADDUW = OP_32 | (0b000 << kFunct3Shift) | (0b0000100 << kFunct7Shift), + RO_SH1ADDUW = OP_32 | (0b010 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + RO_SH2ADDUW = OP_32 | (0b100 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + RO_SH3ADDUW = OP_32 | (0b110 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + RO_SLLIUW = OP_IMM_32 | (0b001 << kFunct3Shift) | (0b000010 << kFunct6Shift), +#endif + RO_SH1ADD = OP | (0b010 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + RO_SH2ADD = OP | (0b100 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + RO_SH3ADD = OP | (0b110 << kFunct3Shift) | (0b0010000 << kFunct7Shift), + + // Zbb + RO_ANDN = OP | (0b111 << kFunct3Shift) | (0b0100000 << kFunct7Shift), + RO_ORN = OP | (0b110 << kFunct3Shift) | (0b0100000 << kFunct7Shift), + RO_XNOR = OP | (0b100 << kFunct3Shift) | (0b0100000 << kFunct7Shift), + OP_COUNT = OP_IMM | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_CLZ = OP_COUNT | (0b00000 << kShamtShift), + RO_CTZ = OP_COUNT | (0b00001 << kShamtShift), + RO_CPOP = OP_COUNT | (0b00010 << kShamtShift), +#ifdef JS_CODEGEN_RISCV64 + OP_COUNTW = OP_IMM_32 | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_CLZW = OP_COUNTW | (0b00000 << kShamtShift), + RO_CTZW = OP_COUNTW | (0b00001 << kShamtShift), + RO_CPOPW = OP_COUNTW | (0b00010 << kShamtShift), +#endif + RO_MAX = OP | (0b110 << kFunct3Shift) | (0b0000101 << kFunct7Shift), + RO_MAXU = OP | (0b111 << kFunct3Shift) | (0b0000101 << kFunct7Shift), + RO_MIN = OP | (0b100 << kFunct3Shift) | (0b0000101 << kFunct7Shift), + RO_MINU = OP | (0b101 << kFunct3Shift) | (0b0000101 << kFunct7Shift), + RO_SEXTB = OP_IMM | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift) | + (0b00100 << kShamtShift), + RO_SEXTH = OP_IMM | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift) | + (0b00101 << kShamtShift), +#ifdef JS_CODEGEN_RISCV64 + RO_ZEXTH = OP_32 | (0b100 << kFunct3Shift) | (0b0000100 << kFunct7Shift) | + (0b00000 << kShamtShift), +#else + RO_ZEXTH = OP | (0b100 << kFunct3Shift) | (0b0000100 << kFunct7Shift) | + (0b00000 << kShamtShift), +#endif + + // Zbb: bitwise rotation + RO_ROL = OP | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_ROR = OP | (0b101 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_ORCB = OP_IMM | (0b101 << kFunct3Shift) | (0b001010000111 << kImm12Shift), +#ifdef JS_CODEGEN_RISCV64 + RO_RORI = OP_IMM | (0b101 << kFunct3Shift) | (0b011000 << kFunct6Shift), +#else + RO_RORI = OP_IMM | (0b101 << kFunct3Shift) | (0b0110000 << kFunct7Shift), +#endif + +#ifdef JS_CODEGEN_RISCV64 + RO_ROLW = OP_32 | (0b001 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_RORIW = OP_IMM_32 | (0b101 << kFunct3Shift) | (0b0110000 << kFunct7Shift), + RO_RORW = OP_32 | (0b101 << kFunct3Shift) | (0b0110000 << kFunct7Shift), +#endif + + RO_REV8 = OP_IMM | (0b101 << kFunct3Shift) | (0b011010 << kFunct6Shift), +#ifdef JS_CODEGEN_RISCV64 + RO_REV8_IMM12 = 0b011010111000, +#else + RO_REV8_IMM12 = 0b011010011000, +#endif + + // Zbs + RO_BCLR = OP | (0b001 << kFunct3Shift) | (0b0100100 << kFunct7Shift), + RO_BCLRI = OP_IMM | (0b001 << kFunct3Shift) | (0b010010 << kFunct6Shift), + + RO_BEXT = OP | (0b101 << kFunct3Shift) | (0b0100100 << kFunct7Shift), + RO_BEXTI = OP_IMM | (0b101 << kFunct3Shift) | (0b010010 << kFunct6Shift), + + RO_BINV = OP | (0b001 << kFunct3Shift) | (0b0110100 << kFunct7Shift), + RO_BINVI = OP_IMM | (0b001 << kFunct3Shift) | (0b011010 << kFunct6Shift), + + RO_BSET = OP | (0b001 << kFunct3Shift) | (0b0010100 << kFunct7Shift), + RO_BSETI = OP_IMM | (0b001 << kFunct3Shift) | (0b0010100 << kFunct7Shift), +}; + +} // namespace jit +} // namespace js + +#endif diff --git a/js/src/jit/riscv64/constant/Constant-riscv-i.h b/js/src/jit/riscv64/constant/Constant-riscv-i.h @@ -34,9 +34,14 @@ enum OpcodeRISCV32I : uint32_t { RO_XORI = OP_IMM | (0b100 << kFunct3Shift), RO_ORI = OP_IMM | (0b110 << kFunct3Shift), RO_ANDI = OP_IMM | (0b111 << kFunct3Shift), - RO_SLLI = OP_IMM | (0b001 << kFunct3Shift), - RO_SRLI = OP_IMM | (0b101 << kFunct3Shift), - // RO_SRAI = OP_IMM | (0b101 << kFunct3Shift), // Same as SRLI, use func7 + + OP_SHL = 0b0010011 | (0b001 << kFunct3Shift), + RO_SLLI = OP_SHL | (0b000000 << kFunct6Shift), + + OP_SHR = 0b0010011 | (0b101 << kFunct3Shift), + RO_SRLI = OP_SHR | (0b000000 << kFunct6Shift), + RO_SRAI = OP_SHR | (0b010000 << kFunct6Shift), + RO_ADD = OP | (0b000 << kFunct3Shift) | (0b0000000 << kFunct7Shift), RO_SUB = OP | (0b000 << kFunct3Shift) | (0b0100000 << kFunct7Shift), RO_SLL = OP | (0b001 << kFunct3Shift) | (0b0000000 << kFunct7Shift), @@ -57,9 +62,13 @@ enum OpcodeRISCV32I : uint32_t { RO_LD = LOAD | (0b011 << kFunct3Shift), RO_SD = STORE | (0b011 << kFunct3Shift), RO_ADDIW = OP_IMM_32 | (0b000 << kFunct3Shift), - RO_SLLIW = OP_IMM_32 | (0b001 << kFunct3Shift), - RO_SRLIW = OP_IMM_32 | (0b101 << kFunct3Shift), - // RO_SRAIW = OP_IMM_32 | (0b101 << kFunct3Shift), // Same as SRLIW, use func7 + + OP_SHLW = OP_IMM_32 | (0b001 << kFunct3Shift), + RO_SLLIW = OP_SHLW | (0b0000000 << kFunct7Shift), + OP_SHRW = OP_IMM_32 | (0b101 << kFunct3Shift), + RO_SRLIW = OP_SHRW | (0b0000000 << kFunct7Shift), + RO_SRAIW = OP_SHRW | (0b0100000 << kFunct7Shift), + RO_ADDW = OP_32 | (0b000 << kFunct3Shift) | (0b0000000 << kFunct7Shift), RO_SUBW = OP_32 | (0b000 << kFunct3Shift) | (0b0100000 << kFunct7Shift), RO_SLLW = OP_32 | (0b001 << kFunct3Shift) | (0b0000000 << kFunct7Shift), diff --git a/js/src/jit/riscv64/constant/Constant-riscv64.h b/js/src/jit/riscv64/constant/Constant-riscv64.h @@ -11,6 +11,7 @@ #include "jit/riscv64/constant/Base-constant-riscv.h" #include "jit/riscv64/constant/Constant-riscv-a.h" +#include "jit/riscv64/constant/Constant-riscv-b.h" #include "jit/riscv64/constant/Constant-riscv-c.h" #include "jit/riscv64/constant/Constant-riscv-d.h" #include "jit/riscv64/constant/Constant-riscv-f.h" diff --git a/js/src/jit/riscv64/disasm/Disasm-riscv64.cpp b/js/src/jit/riscv64/disasm/Disasm-riscv64.cpp @@ -973,10 +973,26 @@ void Decoder::DecodeRType(Instruction* instr) { case RO_AND: Format(instr, "and 'rd, 'rs1, 'rs2"); break; + case RO_ANDN: + Format(instr, "andn 'rd, 'rs1, 'rs2"); + break; + case RO_ORN: + Format(instr, "orn 'rd, 'rs1, 'rs2"); + break; + case RO_XNOR: + Format(instr, "xnor 'rd, 'rs1, 'rs2"); + break; #ifdef JS_CODEGEN_RISCV64 case RO_ADDW: Format(instr, "addw 'rd, 'rs1, 'rs2"); break; + case RO_ADDUW: + if (instr->Rs2Value() == zero_reg.code()) { + Format(instr, "zext.w 'rd, 'rs1"); + } else { + Format(instr, "add.uw 'rd, 'rs1, 'rs2"); + } + break; case RO_SUBW: if (instr->Rs1Value() == zero.code()) Format(instr, "negw 'rd, 'rs2"); @@ -1034,7 +1050,64 @@ void Decoder::DecodeRType(Instruction* instr) { case RO_REMUW: Format(instr, "remuw 'rd, 'rs1, 'rs2"); break; + case RO_SH1ADDUW: + Format(instr, "sh1add.uw 'rd, 'rs1, 'rs2"); + break; + case RO_SH2ADDUW: + Format(instr, "sh2add.uw 'rd, 'rs1, 'rs2"); + break; + case RO_SH3ADDUW: + Format(instr, "sh3add.uw 'rd, 'rs1, 'rs2"); + break; + case RO_ROLW: + Format(instr, "rolw 'rd, 'rs1, 'rs2"); + break; + case RO_RORW: + Format(instr, "rorw 'rd, 'rs1, 'rs2"); + break; #endif /*JS_CODEGEN_RISCV64*/ + case RO_SH1ADD: + Format(instr, "sh1add 'rd, 'rs1, 'rs2"); + break; + case RO_SH2ADD: + Format(instr, "sh2add 'rd, 'rs1, 'rs2"); + break; + case RO_SH3ADD: + Format(instr, "sh3add 'rd, 'rs1, 'rs2"); + break; + case RO_MAX: + Format(instr, "max 'rd, 'rs1, 'rs2"); + break; + case RO_MAXU: + Format(instr, "maxu 'rd, 'rs1, 'rs2"); + break; + case RO_MIN: + Format(instr, "min 'rd, 'rs1, 'rs2"); + break; + case RO_MINU: + Format(instr, "minu 'rd, 'rs1, 'rs2"); + break; + case RO_ZEXTH: + Format(instr, "zext.h 'rd, 'rs1"); + break; + case RO_ROL: + Format(instr, "rol 'rd, 'rs1, 'rs2"); + break; + case RO_ROR: + Format(instr, "ror 'rd, 'rs1, 'rs2"); + break; + case RO_BCLR: + Format(instr, "bclr 'rd, 'rs1, 'rs2"); + break; + case RO_BEXT: + Format(instr, "bext 'rd, 'rs1, 'rs2"); + break; + case RO_BINV: + Format(instr, "binv 'rd, 'rs1, 'rs2"); + break; + case RO_BSET: + Format(instr, "bset 'rd, 'rs1, 'rs2"); + break; // TODO(riscv): End Add RISCV M extension macro default: { switch (instr->BaseOpcode()) { @@ -1544,14 +1617,77 @@ void Decoder::DecodeIType(Instruction* instr) { case RO_ANDI: Format(instr, "andi 'rd, 'rs1, 'imm12x"); break; - case RO_SLLI: - Format(instr, "slli 'rd, 'rs1, 's64"); + case OP_SHL: + switch (instr->Funct6FieldRaw() | OP_SHL) { + case RO_SLLI: + Format(instr, "slli 'rd, 'rs1, 's64"); + break; + case RO_BCLRI: + Format(instr, "bclri 'rd, 'rs1, 's64"); + break; + case RO_BINVI: + Format(instr, "binvi 'rd, 'rs1, 's64"); + break; + case RO_BSETI: + Format(instr, "bseti 'rd, 'rs1, 's64"); + break; + case OP_COUNT: + switch (instr->Shamt()) { + case 0: + Format(instr, "clz 'rd, 'rs1"); + break; + case 1: + Format(instr, "ctz 'rd, 'rs1"); + break; + case 2: + Format(instr, "cpop 'rd, 'rs1"); + break; + case 4: + Format(instr, "sext.b 'rd, 'rs1"); + break; + case 5: + Format(instr, "sext.h 'rd, 'rs1"); + break; + default: + UNSUPPORTED_RISCV(); + } + break; + default: + UNSUPPORTED_RISCV(); + } break; - case RO_SRLI: { // RO_SRAI - if (!instr->IsArithShift()) { - Format(instr, "srli 'rd, 'rs1, 's64"); - } else { - Format(instr, "srai 'rd, 'rs1, 's64"); + case OP_SHR: { // RO_SRAI + switch (instr->Funct6FieldRaw() | OP_SHR) { + case RO_SRLI: + Format(instr, "srli 'rd, 'rs1, 's64"); + break; + case RO_SRAI: + Format(instr, "srai 'rd, 'rs1, 's64"); + break; + case RO_BEXTI: + Format(instr, "bexti 'rd, 'rs1, 's64"); + break; + case RO_ORCB&(kFunct6Mask | OP_SHR): + Format(instr, "orc.b 'rd, 'rs1"); + break; + case RO_RORI: +#ifdef JS_CODEGEN_RISCV64 + Format(instr, "rori 'rd, 'rs1, 's64"); + break; +#else + Format(instr, "rori 'rd, 'rs1, 's32"); + break; +#endif + case RO_REV8: { + if (instr->Imm12Value() == RO_REV8_IMM12) { + Format(instr, "rev8 'rd, 'rs1"); + break; + } + UNSUPPORTED_RISCV(); + break; + } + default: + UNSUPPORTED_RISCV(); } break; } @@ -1562,14 +1698,47 @@ void Decoder::DecodeIType(Instruction* instr) { else Format(instr, "addiw 'rd, 'rs1, 'imm12"); break; - case RO_SLLIW: - Format(instr, "slliw 'rd, 'rs1, 's32"); + case OP_SHLW: + switch (instr->Funct7FieldRaw() | OP_SHLW) { + case RO_SLLIW: + Format(instr, "slliw 'rd, 'rs1, 's32"); + break; + case RO_SLLIUW: + Format(instr, "slli.uw 'rd, 'rs1, 's32"); + break; + case OP_COUNTW: { + switch (instr->Shamt()) { + case 0: + Format(instr, "clzw 'rd, 'rs1"); + break; + case 1: + Format(instr, "ctzw 'rd, 'rs1"); + break; + case 2: + Format(instr, "cpopw 'rd, 'rs1"); + break; + default: + UNSUPPORTED_RISCV(); + } + break; + } + default: + UNSUPPORTED_RISCV(); + } break; - case RO_SRLIW: { // RO_SRAIW - if (!instr->IsArithShift()) { - Format(instr, "srliw 'rd, 'rs1, 's32"); - } else { - Format(instr, "sraiw 'rd, 'rs1, 's32"); + case OP_SHRW: { // RO_SRAI + switch (instr->Funct7FieldRaw() | OP_SHRW) { + case RO_SRLIW: + Format(instr, "srliw 'rd, 'rs1, 's32"); + break; + case RO_SRAIW: + Format(instr, "sraiw 'rd, 'rs1, 's32"); + break; + case RO_RORIW: + Format(instr, "roriw 'rd, 'rs1, 's32"); + break; + default: + UNSUPPORTED_RISCV(); } break; } diff --git a/js/src/jit/riscv64/extension/base-assembler-riscv.cc b/js/src/jit/riscv64/extension/base-assembler-riscv.cc @@ -207,23 +207,23 @@ BufferOffset AssemblerRiscvBase::GenInstrI(uint8_t funct3, BaseOpcode opcode, return emit(instr); } -void AssemblerRiscvBase::GenInstrIShift(bool arithshift, uint8_t funct3, +void AssemblerRiscvBase::GenInstrIShift(uint8_t funct6, uint8_t funct3, BaseOpcode opcode, Register rd, Register rs1, uint8_t shamt) { MOZ_ASSERT(is_uint3(funct3) && is_uint6(shamt)); Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) | (shamt << kShamtShift) | - (arithshift << kArithShiftShift); + (funct6 << kFunct6Shift); emit(instr); } -void AssemblerRiscvBase::GenInstrIShiftW(bool arithshift, uint8_t funct3, +void AssemblerRiscvBase::GenInstrIShiftW(uint8_t funct7, uint8_t funct3, BaseOpcode opcode, Register rd, Register rs1, uint8_t shamt) { MOZ_ASSERT(is_uint3(funct3) && is_uint5(shamt)); Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) | (shamt << kShamtWShift) | - (arithshift << kArithShiftShift); + (funct7 << kFunct7Shift); emit(instr); } @@ -439,7 +439,8 @@ void AssemblerRiscvBase::GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd, Register rs1, uint8_t shamt) { MOZ_ASSERT(is_uint6(shamt)); - GenInstrI(funct3, OP_IMM, rd, rs1, (arithshift << 10) | shamt); + GenInstrIShift(arithshift << (kArithShiftShift - kFunct6Shift), funct3, + OP_IMM, rd, rs1, shamt); } void AssemblerRiscvBase::GenInstrALU_rr(uint8_t funct7, uint8_t funct3, @@ -461,7 +462,8 @@ void AssemblerRiscvBase::GenInstrCSR_ii(uint8_t funct3, Register rd, void AssemblerRiscvBase::GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd, Register rs1, uint8_t shamt) { - GenInstrIShiftW(arithshift, funct3, OP_IMM_32, rd, rs1, shamt); + GenInstrIShiftW(arithshift << (kArithShiftShift - kFunct7Shift), funct3, + OP_IMM_32, rd, rs1, shamt); } void AssemblerRiscvBase::GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, diff --git a/js/src/jit/riscv64/extension/base-assembler-riscv.h b/js/src/jit/riscv64/extension/base-assembler-riscv.h @@ -143,9 +143,9 @@ class AssemblerRiscvBase { Register rs1, int16_t imm12); BufferOffset GenInstrI(uint8_t funct3, BaseOpcode opcode, FPURegister rd, Register rs1, int16_t imm12); - void GenInstrIShift(bool arithshift, uint8_t funct3, BaseOpcode opcode, + void GenInstrIShift(uint8_t funct7, uint8_t funct3, BaseOpcode opcode, Register rd, Register rs1, uint8_t shamt); - void GenInstrIShiftW(bool arithshift, uint8_t funct3, BaseOpcode opcode, + void GenInstrIShiftW(uint8_t funct7, uint8_t funct3, BaseOpcode opcode, Register rd, Register rs1, uint8_t shamt); void GenInstrS(uint8_t funct3, BaseOpcode opcode, Register rs1, Register rs2, int16_t imm12); diff --git a/js/src/jit/riscv64/extension/extension-riscv-b.cc b/js/src/jit/riscv64/extension/extension-riscv-b.cc @@ -0,0 +1,184 @@ +// 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. + +#include "jit/riscv64/extension/extension-riscv-b.h" +#include "jit/riscv64/Assembler-riscv64.h" +#include "jit/riscv64/constant/Constant-riscv64.h" +#include "jit/riscv64/Architecture-riscv64.h" + +namespace js { +namespace jit { + +// RV32B Standard Extension +void AssemblerRISCVB::sh1add(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0010000, 0b010, rd, rs1, rs2); +} +void AssemblerRISCVB::sh2add(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0010000, 0b100, rd, rs1, rs2); +} +void AssemblerRISCVB::sh3add(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0010000, 0b110, rd, rs1, rs2); +} +#ifdef JS_CODEGEN_RISCV64 +void AssemblerRISCVB::adduw(Register rd, Register rs1, Register rs2) { + GenInstrALUW_rr(0b0000100, 0b000, rd, rs1, rs2); +} +void AssemblerRISCVB::sh1adduw(Register rd, Register rs1, Register rs2) { + GenInstrALUW_rr(0b0010000, 0b010, rd, rs1, rs2); +} +void AssemblerRISCVB::sh2adduw(Register rd, Register rs1, Register rs2) { + GenInstrALUW_rr(0b0010000, 0b100, rd, rs1, rs2); +} +void AssemblerRISCVB::sh3adduw(Register rd, Register rs1, Register rs2) { + GenInstrALUW_rr(0b0010000, 0b110, rd, rs1, rs2); +} +void AssemblerRISCVB::slliuw(Register rd, Register rs1, uint8_t shamt) { + GenInstrIShift(0b000010, 0b001, OP_IMM_32, rd, rs1, shamt); +} +#endif // JS_CODEGEN_RISCV64 + +void AssemblerRISCVB::andn(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0100000, 0b111, rd, rs1, rs2); +} +void AssemblerRISCVB::orn(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0100000, 0b110, rd, rs1, rs2); +} +void AssemblerRISCVB::xnor(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0100000, 0b100, rd, rs1, rs2); +} + +void AssemblerRISCVB::clz(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM, rd, rs, 0); +} +void AssemblerRISCVB::ctz(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM, rd, rs, 1); +} +void AssemblerRISCVB::cpop(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM, rd, rs, 2); +} +#ifdef JS_CODEGEN_RISCV64 +void AssemblerRISCVB::clzw(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM_32, rd, rs, 0); +} +void AssemblerRISCVB::ctzw(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM_32, rd, rs, 1); +} +void AssemblerRISCVB::cpopw(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM_32, rd, rs, 2); +} +#endif + +void AssemblerRISCVB::max(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0000101, 0b110, rd, rs1, rs2); +} +void AssemblerRISCVB::maxu(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0000101, 0b111, rd, rs1, rs2); +} +void AssemblerRISCVB::min(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0000101, 0b100, rd, rs1, rs2); +} +void AssemblerRISCVB::minu(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0000101, 0b101, rd, rs1, rs2); +} + +void AssemblerRISCVB::sextb(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM, rd, rs, 0b100); +} +void AssemblerRISCVB::sexth(Register rd, Register rs) { + GenInstrIShiftW(0b0110000, 0b001, OP_IMM, rd, rs, 0b101); +} +void AssemblerRISCVB::zexth(Register rd, Register rs) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrALUW_rr(0b0000100, 0b100, rd, rs, zero_reg); +#else + GenInstrALU_rr(0b0000100, 0b100, rd, rs, zero_reg); +#endif +} + +void AssemblerRISCVB::rol(Register rd, Register rs1, Register rs2) { + GenInstrR(0b0110000, 0b001, OP, rd, rs1, rs2); +} + +void AssemblerRISCVB::ror(Register rd, Register rs1, Register rs2) { + GenInstrR(0b0110000, 0b101, OP, rd, rs1, rs2); +} + +void AssemblerRISCVB::orcb(Register rd, Register rs) { + GenInstrI(0b101, OP_IMM, rd, rs, 0b001010000111); +} + +void AssemblerRISCVB::rori(Register rd, Register rs1, uint8_t shamt) { +#ifdef JS_CODEGEN_RISCV64 + MOZ_ASSERT(is_uint6(shamt)); + GenInstrI(0b101, OP_IMM, rd, rs1, 0b011000000000 | shamt); +#else + DCHECK(is_uint5(shamt)); + GenInstrI(0b101, OP_IMM, rd, rs1, 0b011000000000 | shamt); +#endif +} + +#ifdef JS_CODEGEN_RISCV64 +void AssemblerRISCVB::rolw(Register rd, Register rs1, Register rs2) { + GenInstrR(0b0110000, 0b001, OP_32, rd, rs1, rs2); +} +void AssemblerRISCVB::roriw(Register rd, Register rs1, uint8_t shamt) { + MOZ_ASSERT(is_uint5(shamt)); + GenInstrI(0b101, OP_IMM_32, rd, rs1, 0b011000000000 | shamt); +} +void AssemblerRISCVB::rorw(Register rd, Register rs1, Register rs2) { + GenInstrR(0b0110000, 0b101, OP_32, rd, rs1, rs2); +} +#endif + +void AssemblerRISCVB::rev8(Register rd, Register rs) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrI(0b101, OP_IMM, rd, rs, 0b011010111000); +#else + GenInstrI(0b101, OP_IMM, rd, rs, 0b011010011000); +#endif +} + +void AssemblerRISCVB::bclr(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0100100, 0b001, rd, rs1, rs2); +} + +void AssemblerRISCVB::bclri(Register rd, Register rs, uint8_t shamt) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrIShift(0b010010, 0b001, OP_IMM, rd, rs, shamt); +#else + GenInstrIShiftW(0b0100100, 0b001, OP_IMM, rd, rs, shamt); +#endif +} +void AssemblerRISCVB::bext(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0100100, 0b101, rd, rs1, rs2); +} +void AssemblerRISCVB::bexti(Register rd, Register rs1, uint8_t shamt) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrIShift(0b010010, 0b101, OP_IMM, rd, rs1, shamt); +#else + GenInstrIShiftW(0b0100100, 0b101, OP_IMM, rd, rs1, shamt); +#endif +} +void AssemblerRISCVB::binv(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0110100, 0b001, rd, rs1, rs2); +} +void AssemblerRISCVB::binvi(Register rd, Register rs1, uint8_t shamt) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrIShift(0b011010, 0b001, OP_IMM, rd, rs1, shamt); +#else + GenInstrIShiftW(0b0110100, 0b001, OP_IMM, rd, rs1, shamt); +#endif +} +void AssemblerRISCVB::bset(Register rd, Register rs1, Register rs2) { + GenInstrALU_rr(0b0010100, 0b001, rd, rs1, rs2); +} +void AssemblerRISCVB::bseti(Register rd, Register rs1, uint8_t shamt) { +#ifdef JS_CODEGEN_RISCV64 + GenInstrIShift(0b001010, 0b001, OP_IMM, rd, rs1, shamt); +#else + GenInstrIShiftW(0b0010100, 0b001, OP_IMM, rd, rs1, shamt); +#endif +} +} // namespace jit +} // namespace js diff --git a/js/src/jit/riscv64/extension/extension-riscv-b.h b/js/src/jit/riscv64/extension/extension-riscv-b.h @@ -0,0 +1,78 @@ +// 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_Extension_riscv_b_h_ +#define jit_riscv64_extension_Extension_riscv_b_h_ + +#include <stdint.h> + +#include "jit/riscv64/extension/base-assembler-riscv.h" +#include "jit/riscv64/Register-riscv64.h" + +namespace js { +namespace jit { +class AssemblerRISCVB : public AssemblerRiscvBase { + // RV32B Extension + public: + // Zba Extension + void sh1add(Register rd, Register rs1, Register rs2); + void sh2add(Register rd, Register rs1, Register rs2); + void sh3add(Register rd, Register rs1, Register rs2); +#ifdef JS_CODEGEN_RISCV64 + void adduw(Register rd, Register rs1, Register rs2); + void zextw(Register rd, Register rs1) { adduw(rd, rs1, zero_reg); } + void sh1adduw(Register rd, Register rs1, Register rs2); + void sh2adduw(Register rd, Register rs1, Register rs2); + void sh3adduw(Register rd, Register rs1, Register rs2); + void slliuw(Register rd, Register rs1, uint8_t shamt); +#endif + + // Zbb Extension + void andn(Register rd, Register rs1, Register rs2); + void orn(Register rd, Register rs1, Register rs2); + void xnor(Register rd, Register rs1, Register rs2); + + void clz(Register rd, Register rs); + void ctz(Register rd, Register rs); + void cpop(Register rd, Register rs); +#ifdef JS_CODEGEN_RISCV64 + void clzw(Register rd, Register rs); + void ctzw(Register rd, Register rs); + void cpopw(Register rd, Register rs); +#endif + + void max(Register rd, Register rs1, Register rs2); + void maxu(Register rd, Register rs1, Register rs2); + void min(Register rd, Register rs1, Register rs2); + void minu(Register rd, Register rs1, Register rs2); + + void sextb(Register rd, Register rs); + void sexth(Register rd, Register rs); + void zexth(Register rd, Register rs); + + // Zbb: bitwise rotation + void rol(Register rd, Register rs1, Register rs2); + void ror(Register rd, Register rs1, Register rs2); + void rori(Register rd, Register rs1, uint8_t shamt); + void orcb(Register rd, Register rs); + void rev8(Register rd, Register rs); +#ifdef JS_CODEGEN_RISCV64 + void rolw(Register rd, Register rs1, Register rs2); + void roriw(Register rd, Register rs1, uint8_t shamt); + void rorw(Register rd, Register rs1, Register rs2); +#endif + + // Zbs + void bclr(Register rd, Register rs1, Register rs2); + void bclri(Register rd, Register rs1, uint8_t shamt); + void bext(Register rd, Register rs1, Register rs2); + void bexti(Register rd, Register rs1, uint8_t shamt); + void binv(Register rd, Register rs1, Register rs2); + void binvi(Register rd, Register rs1, uint8_t shamt); + void bset(Register rd, Register rs1, Register rs2); + void bseti(Register rd, Register rs1, uint8_t shamt); +}; +} // namespace jit +} // namespace js +#endif