mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-21 10:19:04 +02:00
c.lbu and c.sb keep the offset's bit 0 in bit 6 and bit 1 in bit 5, so offsets 1 and 2 were swapped, and the JIT loaded and stored the wrong byte. FLI's only NaN is the canonical one, but CanFLI took any NaN for it: the pattern went through a float to double conversion that quieted it, which on RISC-V also drops the sign and payload. vfim of a NaN lost its sign. Neither is detected on real hardware yet (we never set Zcb or Zfa), and the CPU fuzzer found both with the extensions forced on under qemu. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1137 lines
52 KiB
C++
1137 lines
52 KiB
C++
// Copyright (c) 2022- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <type_traits>
|
|
#include "Common/CodeBlock.h"
|
|
#include "Common/Common.h"
|
|
|
|
namespace RiscVGen {
|
|
|
|
enum RiscVReg {
|
|
X0 = 0, X1, X2, X3, X4, X5, X6, X7,
|
|
X8, X9, X10, X11, X12, X13, X14, X15,
|
|
X16, X17, X18, X19, X20, X21, X22, X23,
|
|
X24, X25, X26, X27, X28, X29, X30, X31,
|
|
|
|
R_ZERO = 0,
|
|
R_RA = 1,
|
|
R_SP = 2,
|
|
R_GP = 3,
|
|
R_TP = 4,
|
|
R_FP = 8,
|
|
|
|
F0 = 0x20, F1, F2, F3, F4, F5, F6, F7,
|
|
F8, F9, F10, F11, F12, F13, F14, F15,
|
|
F16, F17, F18, F19, F20, F21, F22, F23,
|
|
F24, F25, F26, F27, F28, F29, F30, F31,
|
|
|
|
V0 = 0x40, V1, V2, V3, V4, V5, V6, V7,
|
|
V8, V9, V10, V11, V12, V13, V14, V15,
|
|
V16, V17, V18, V19, V20, V21, V22, V23,
|
|
V24, V25, V26, V27, V28, V29, V30, V31,
|
|
|
|
INVALID_REG = 0xFFFFFFFF,
|
|
};
|
|
|
|
enum class FixupBranchType {
|
|
B,
|
|
J,
|
|
CB,
|
|
CJ,
|
|
};
|
|
|
|
enum class Fence {
|
|
I = 0b1000,
|
|
O = 0b0100,
|
|
R = 0b0010,
|
|
W = 0b0001,
|
|
RW = R | W,
|
|
IO = I | O,
|
|
};
|
|
ENUM_CLASS_BITOPS(Fence);
|
|
|
|
enum class Atomic {
|
|
NONE = 0b00,
|
|
ACQUIRE = 0b10,
|
|
RELEASE = 0b01,
|
|
SEQUENTIAL = 0b11,
|
|
};
|
|
|
|
enum class Round {
|
|
NEAREST_EVEN = 0b000,
|
|
TOZERO = 0b001,
|
|
DOWN = 0b010,
|
|
UP = 0b011,
|
|
NEAREST_MAX = 0b100,
|
|
DYNAMIC = 0b111,
|
|
};
|
|
|
|
enum class FConv {
|
|
W = 0x0000,
|
|
WU = 0x0001,
|
|
L = 0x0002,
|
|
LU = 0x0003,
|
|
|
|
S = 0x1000,
|
|
D = 0x1001,
|
|
H = 0x1002,
|
|
Q = 0x1003,
|
|
};
|
|
|
|
enum class FMv {
|
|
X,
|
|
H,
|
|
W,
|
|
D,
|
|
};
|
|
|
|
enum class Csr {
|
|
FFlags = 0x001,
|
|
FRm = 0x002,
|
|
FCsr = 0x003,
|
|
|
|
VStart = 0x008,
|
|
VXSat = 0x009,
|
|
VXRm = 0x00A,
|
|
VCsr = 0x00F,
|
|
VL = 0xC20,
|
|
VType = 0xC21,
|
|
VLenB = 0xC22,
|
|
|
|
Cycle = 0xC00,
|
|
Time = 0xC01,
|
|
InstRet = 0xC02,
|
|
CycleH = 0xC80,
|
|
TimeH = 0xC81,
|
|
InstRetH = 0xC82,
|
|
};
|
|
|
|
enum class VLMul {
|
|
M1 = 0b000,
|
|
M2 = 0b001,
|
|
M4 = 0b010,
|
|
M8 = 0b011,
|
|
MF8 = 0b101,
|
|
MF4 = 0b110,
|
|
MF2 = 0b111,
|
|
};
|
|
|
|
enum class VSew {
|
|
E8 = 0b000,
|
|
E16 = 0b001,
|
|
E32 = 0b010,
|
|
E64 = 0b011,
|
|
};
|
|
|
|
enum class VTail {
|
|
U = 0,
|
|
A = 1,
|
|
};
|
|
|
|
enum class VMask {
|
|
U = 0,
|
|
A = 1,
|
|
};
|
|
|
|
struct VType {
|
|
constexpr VType(VSew sew, VTail vt, VMask vm)
|
|
: value(((uint32_t)sew << 3) | ((uint32_t)vt << 6) | ((uint32_t)vm << 7)) {
|
|
}
|
|
constexpr VType(VSew sew, VLMul lmul, VTail vt, VMask vm)
|
|
: value((uint32_t)lmul | ((uint32_t)sew << 3) | ((uint32_t)vt << 6) | ((uint32_t)vm << 7)) {
|
|
}
|
|
|
|
VType(int bits, VLMul lmul, VTail vt, VMask vm) {
|
|
VSew sew = VSew::E8;
|
|
switch (bits) {
|
|
case 8: sew = VSew::E8; break;
|
|
case 16: sew = VSew::E16; break;
|
|
case 32: sew = VSew::E32; break;
|
|
case 64: sew = VSew::E64; break;
|
|
default: _assert_msg_(false, "Invalid vtype width"); break;
|
|
}
|
|
value = (uint32_t)lmul | ((uint32_t)sew << 3) | ((uint32_t)vt << 6) | ((uint32_t)vm << 7);
|
|
}
|
|
|
|
uint32_t value;
|
|
};
|
|
|
|
enum class VUseMask {
|
|
V0_T = 0,
|
|
NONE = 1,
|
|
};
|
|
|
|
struct FixupBranch {
|
|
FixupBranch() {}
|
|
FixupBranch(const u8 *p, FixupBranchType t) : ptr(p), type(t) {}
|
|
FixupBranch(FixupBranch &&other);
|
|
FixupBranch(const FixupBranch &) = delete;
|
|
~FixupBranch();
|
|
|
|
FixupBranch &operator =(FixupBranch &&other);
|
|
FixupBranch &operator =(const FixupBranch &other) = delete;
|
|
|
|
const u8 *ptr = nullptr;
|
|
FixupBranchType type = FixupBranchType::B;
|
|
};
|
|
|
|
class RiscVEmitter {
|
|
public:
|
|
RiscVEmitter() {}
|
|
RiscVEmitter(const u8 *codePtr, u8 *writablePtr);
|
|
virtual ~RiscVEmitter() {}
|
|
|
|
void SetCodePointer(const u8 *ptr, u8 *writePtr);
|
|
const u8 *GetCodePointer() const;
|
|
u8 *GetWritableCodePtr();
|
|
|
|
void ReserveCodeSpace(u32 bytes);
|
|
const u8 *AlignCode16();
|
|
const u8 *AlignCodePage();
|
|
void FlushIcache();
|
|
void FlushIcacheSection(const u8 *start, const u8 *end);
|
|
|
|
void SetJumpTarget(FixupBranch &branch);
|
|
bool BInRange(const void *func) const;
|
|
bool JInRange(const void *func) const;
|
|
|
|
void QuickJAL(RiscVReg scratchreg, RiscVReg rd, const u8 *dst);
|
|
void QuickJ(RiscVReg scratchreg, const u8 *dst) {
|
|
QuickJAL(scratchreg, R_ZERO, dst);
|
|
}
|
|
void QuickCallFunction(const u8 *func, RiscVReg scratchreg = R_RA) {
|
|
QuickJAL(scratchreg, R_RA, func);
|
|
}
|
|
template <typename T>
|
|
void QuickCallFunction(T *func, RiscVReg scratchreg = R_RA) {
|
|
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
|
|
QuickCallFunction((const u8 *)func, scratchreg);
|
|
}
|
|
|
|
void QuickCallFunctionR(const u8 *func, RiscVReg arg, RiscVReg scratchreg = R_RA) {
|
|
if (arg != RiscVReg::X10) { // A0
|
|
MV(RiscVReg::X10, arg);
|
|
}
|
|
QuickJAL(scratchreg, R_RA, func);
|
|
}
|
|
template <typename T>
|
|
void QuickCallFunctionR(T *func, RiscVReg arg, RiscVReg scratchreg = R_RA) {
|
|
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
|
|
QuickCallFunctionR((const u8 *)func, arg, scratchreg);
|
|
}
|
|
void LUI(RiscVReg rd, s32 simm32);
|
|
void AUIPC(RiscVReg rd, s32 simm32);
|
|
|
|
void JAL(RiscVReg rd, const void *dst);
|
|
void JALR(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
FixupBranch JAL(RiscVReg rd);
|
|
|
|
// Psuedo-instructions for convenience/clarity.
|
|
void J(const void *dst) {
|
|
JAL(R_ZERO, dst);
|
|
}
|
|
void JR(RiscVReg rs1, u32 simm12 = 0) {
|
|
JALR(R_ZERO, rs1, simm12);
|
|
}
|
|
void RET() {
|
|
JR(R_RA);
|
|
}
|
|
FixupBranch J() {
|
|
return JAL(R_ZERO);
|
|
}
|
|
|
|
void BEQ(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
void BNE(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
void BLT(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
void BGE(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
void BLTU(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
void BGEU(RiscVReg rs1, RiscVReg rs2, const void *dst);
|
|
FixupBranch BEQ(RiscVReg rs1, RiscVReg rs2);
|
|
FixupBranch BNE(RiscVReg rs1, RiscVReg rs2);
|
|
FixupBranch BLT(RiscVReg rs1, RiscVReg rs2);
|
|
FixupBranch BGE(RiscVReg rs1, RiscVReg rs2);
|
|
FixupBranch BLTU(RiscVReg rs1, RiscVReg rs2);
|
|
FixupBranch BGEU(RiscVReg rs1, RiscVReg rs2);
|
|
|
|
void LB(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void LH(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void LW(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void LBU(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void LHU(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
|
|
void SB(RiscVReg rs2, RiscVReg addr, s32 simm12);
|
|
void SH(RiscVReg rs2, RiscVReg addr, s32 simm12);
|
|
void SW(RiscVReg rs2, RiscVReg addr, s32 simm12);
|
|
|
|
void ADDI(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void SLTI(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void SLTIU(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void XORI(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void ORI(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void ANDI(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
|
|
void NOP() {
|
|
ADDI(R_ZERO, R_ZERO, 0);
|
|
}
|
|
void MV(RiscVReg rd, RiscVReg rs1) {
|
|
ADDI(rd, rs1, 0);
|
|
}
|
|
void NOT(RiscVReg rd, RiscVReg rs1) {
|
|
XORI(rd, rs1, -1);
|
|
}
|
|
|
|
// The temp reg is only possibly used for 64-bit values.
|
|
template <typename T>
|
|
void LI(RiscVReg rd, const T &v, RiscVReg temp = R_ZERO) {
|
|
_assert_msg_(rd != R_ZERO, "LI to X0");
|
|
_assert_msg_(rd < F0 && temp < F0, "LI to non-GPR");
|
|
|
|
uint64_t value = AsImmediate<T, std::is_signed<T>::value>(v);
|
|
SetRegToImmediate(rd, value, temp);
|
|
}
|
|
|
|
void SLLI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void SRLI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void SRAI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
|
|
void ADD(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SUB(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SLL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SLT(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SLTU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void XOR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SRL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SRA(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void OR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void AND(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
void NEG(RiscVReg rd, RiscVReg rs) {
|
|
SUB(rd, R_ZERO, rs);
|
|
}
|
|
void SNEZ(RiscVReg rd, RiscVReg rs) {
|
|
SLTU(rd, R_ZERO, rs);
|
|
}
|
|
void SEQZ(RiscVReg rd, RiscVReg rs) {
|
|
SLTIU(rd, rs, 1);
|
|
}
|
|
|
|
void FENCE(Fence predecessor, Fence successor);
|
|
void FENCE_TSO();
|
|
|
|
void ECALL();
|
|
void EBREAK();
|
|
|
|
// 64-bit instructions - ones ending in W sign extend result to 32 bits.
|
|
void LWU(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void LD(RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void SD(RiscVReg rs2, RiscVReg addr, s32 simm12);
|
|
void ADDIW(RiscVReg rd, RiscVReg rs1, s32 simm12);
|
|
void SLLIW(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void SRLIW(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void SRAIW(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void ADDW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SUBW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SLLW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SRLW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SRAW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
void NEGW(RiscVReg rd, RiscVReg rs) {
|
|
SUBW(rd, R_ZERO, rs);
|
|
}
|
|
|
|
// Integer multiplication and division.
|
|
void MUL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MULH(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MULHSU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MULHU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void DIV(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void DIVU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void REM(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void REMU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
// 64-bit only multiply and divide.
|
|
void MULW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void DIVW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void DIVUW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void REMW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void REMUW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
// Atomic memory operations.
|
|
void LR(int bits, RiscVReg rd, RiscVReg addr, Atomic ordering);
|
|
void SC(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOSWAP(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOADD(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOAND(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOOR(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOXOR(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOMIN(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOMAX(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOMINU(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
void AMOMAXU(int bits, RiscVReg rd, RiscVReg rs2, RiscVReg addr, Atomic ordering);
|
|
|
|
// Floating point (same funcs for single/double/quad, if supported.)
|
|
void FL(int bits, RiscVReg rd, RiscVReg addr, s32 simm12);
|
|
void FS(int bits, RiscVReg rs2, RiscVReg addr, s32 simm12);
|
|
void FLW(RiscVReg rd, RiscVReg addr, s32 simm12) {
|
|
FL(32, rd, addr, simm12);
|
|
}
|
|
void FSW(RiscVReg rs2, RiscVReg addr, s32 simm12) {
|
|
FS(32, rs2, addr, simm12);
|
|
}
|
|
|
|
void FMADD(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, RiscVReg rs3, Round rm = Round::DYNAMIC);
|
|
void FMSUB(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, RiscVReg rs3, Round rm = Round::DYNAMIC);
|
|
void FNMSUB(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, RiscVReg rs3, Round rm = Round::DYNAMIC);
|
|
void FNMADD(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, RiscVReg rs3, Round rm = Round::DYNAMIC);
|
|
|
|
void FADD(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, Round rm = Round::DYNAMIC);
|
|
void FSUB(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, Round rm = Round::DYNAMIC);
|
|
void FMUL(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, Round rm = Round::DYNAMIC);
|
|
void FDIV(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2, Round rm = Round::DYNAMIC);
|
|
void FSQRT(int bits, RiscVReg rd, RiscVReg rs1, Round rm = Round::DYNAMIC);
|
|
|
|
void FSGNJ(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FSGNJN(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FSGNJX(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
void FMV(int bits, RiscVReg rd, RiscVReg rs) {
|
|
FSGNJ(bits, rd, rs, rs);
|
|
}
|
|
void FNEG(int bits, RiscVReg rd, RiscVReg rs) {
|
|
FSGNJN(bits, rd, rs, rs);
|
|
}
|
|
void FABS(int bits, RiscVReg rd, RiscVReg rs) {
|
|
FSGNJX(bits, rd, rs, rs);
|
|
}
|
|
|
|
void FMIN(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FMAX(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
void FCVT(FConv to, FConv from, RiscVReg rd, RiscVReg rs1, Round rm = Round::DYNAMIC);
|
|
void FMV(FMv to, FMv from, RiscVReg rd, RiscVReg rs1);
|
|
|
|
void FEQ(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FLT(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FLE(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FCLASS(int bits, RiscVReg rd, RiscVReg rs1);
|
|
|
|
// Additional floating point (Zfa.)
|
|
bool CanFLI(int bits, double v) const;
|
|
bool CanFLI(int bits, uint32_t pattern) const;
|
|
bool CanFLI(int bits, float v) const;
|
|
void FLI(int bits, RiscVReg rd, double v);
|
|
void FLI(int bits, RiscVReg rd, uint32_t pattern);
|
|
void FLI(int bits, RiscVReg rd, float v) {
|
|
FLI(bits, rd, (double)v);
|
|
}
|
|
void FMINM(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FMAXM(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void FROUND(int bits, RiscVReg rd, RiscVReg rs1, Round rm = Round::DYNAMIC);
|
|
|
|
// Convenience helper for FLI support.
|
|
void QuickFLI(int bits, RiscVReg rd, double v, RiscVReg scratchReg);
|
|
void QuickFLI(int bits, RiscVReg rd, uint32_t pattern, RiscVReg scratchReg);
|
|
void QuickFLI(int bits, RiscVReg rd, float v, RiscVReg scratchReg);
|
|
|
|
// Control state register manipulation.
|
|
void CSRRW(RiscVReg rd, Csr csr, RiscVReg rs1);
|
|
void CSRRS(RiscVReg rd, Csr csr, RiscVReg rs1);
|
|
void CSRRC(RiscVReg rd, Csr csr, RiscVReg rs1);
|
|
void CSRRWI(RiscVReg rd, Csr csr, u8 uimm5);
|
|
void CSRRSI(RiscVReg rd, Csr csr, u8 uimm5);
|
|
void CSRRCI(RiscVReg rd, Csr csr, u8 uimm5);
|
|
|
|
void FRRM(RiscVReg rd) {
|
|
CSRRS(rd, Csr::FRm, R_ZERO);
|
|
}
|
|
void FSRM(RiscVReg rs) {
|
|
CSRRW(R_ZERO, Csr::FRm, rs);
|
|
}
|
|
void FSRMI(RiscVReg rd, Round rm) {
|
|
_assert_msg_(rm != Round::DYNAMIC, "Cannot set FRm to DYNAMIC");
|
|
CSRRWI(rd, Csr::FRm, (uint8_t)rm);
|
|
}
|
|
void FSRMI(Round rm) {
|
|
FSRMI(R_ZERO, rm);
|
|
}
|
|
|
|
// Vector instructions.
|
|
void VSETVLI(RiscVReg rd, RiscVReg rs1, VType vtype);
|
|
void VSETIVLI(RiscVReg rd, u8 uimm5, VType vtype);
|
|
void VSETVL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
// Load contiguous registers, unordered.
|
|
void VLE_V(int dataBits, RiscVReg vd, RiscVReg rs1, VUseMask vm = VUseMask::NONE) {
|
|
VLSEGE_V(1, dataBits, vd, rs1, vm);
|
|
}
|
|
// Load registers with stride (note: rs2/stride can be X0/zero to broadcast.)
|
|
void VLSE_V(int dataBits, RiscVReg vd, RiscVReg rs1, RiscVReg rs2, VUseMask vm = VUseMask::NONE) {
|
|
VLSSEGE_V(1, dataBits, vd, rs1, rs2, vm);
|
|
}
|
|
// Load indexed registers (gather), unordered.
|
|
void VLUXEI_V(int indexBits, RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VLUXSEGEI_V(1, indexBits, vd, rs1, vs2, vm);
|
|
}
|
|
// Load indexed registers (gather), ordered.
|
|
void VLOXEI_V(int indexBits, RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VLOXSEGEI_V(1, indexBits, vd, rs1, vs2, vm);
|
|
}
|
|
// Load mask (force 8 bit, EMUL=1, TA)
|
|
void VLM_V(RiscVReg vd, RiscVReg rs1);
|
|
// Load but ignore faults after first element.
|
|
void VLEFF_V(int dataBits, RiscVReg vd, RiscVReg rs1, VUseMask vm = VUseMask::NONE) {
|
|
VLSEGEFF_V(1, dataBits, vd, rs1, vm);
|
|
}
|
|
// Load fields into subsequent registers (destructure.)
|
|
void VLSEGE_V(int fields, int dataBits, RiscVReg vd, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VLSSEGE_V(int fields, int dataBits, RiscVReg vd, RiscVReg rs1, RiscVReg rs2, VUseMask vm = VUseMask::NONE);
|
|
void VLUXSEGEI_V(int fields, int indexBits, RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VLOXSEGEI_V(int fields, int indexBits, RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VLSEGEFF_V(int fields, int dataBits, RiscVReg vd, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
// Load entire registers (implementation dependent size.)
|
|
void VLR_V(int regs, int hintBits, RiscVReg vd, RiscVReg rs1);
|
|
|
|
void VSE_V(int dataBits, RiscVReg vs3, RiscVReg rs1, VUseMask vm = VUseMask::NONE) {
|
|
VSSEGE_V(1, dataBits, vs3, rs1, vm);
|
|
}
|
|
void VSSE_V(int dataBits, RiscVReg vs3, RiscVReg rs1, RiscVReg rs2, VUseMask vm = VUseMask::NONE) {
|
|
VSSSEGE_V(1, dataBits, vs3, rs1, rs2, vm);
|
|
}
|
|
void VSUXEI_V(int indexBits, RiscVReg vs3, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VSUXSEGEI_V(1, indexBits, vs3, rs1, vs2, vm);
|
|
}
|
|
void VSOXEI_V(int indexBits, RiscVReg vs3, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VSOXSEGEI_V(1, indexBits, vs3, rs1, vs2, vm);
|
|
}
|
|
void VSM_V(RiscVReg vs3, RiscVReg rs1);
|
|
void VSSEGE_V(int fields, int dataBits, RiscVReg vs3, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSSEGE_V(int fields, int dataBits, RiscVReg vs3, RiscVReg rs1, RiscVReg rs2, VUseMask vm = VUseMask::NONE);
|
|
void VSUXSEGEI_V(int fields, int indexBits, RiscVReg vs3, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VSOXSEGEI_V(int fields, int indexBits, RiscVReg vs3, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VSR_V(int regs, RiscVReg vs3, RiscVReg rs1);
|
|
|
|
void VADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VADD_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VADD_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VSUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSUB_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VRSUB_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VRSUB_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VNEG_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VRSUB_VX(vd, vs2, X0, vm);
|
|
}
|
|
|
|
void VWADDU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADDU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUBU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUBU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADD_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUB_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADDU_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADDU_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUBU_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUBU_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADD_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWADD_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUB_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSUB_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VZEXT_V(int frac, RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VSEXT_V(int frac, RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
// vmask must be V0, provided for clarity/reminder.
|
|
void VADC_VVM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, RiscVReg vmask);
|
|
void VADC_VXM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
void VADC_VIM(RiscVReg vd, RiscVReg vs2, s8 simm5, RiscVReg vmask);
|
|
void VMADC_VVM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, RiscVReg vmask);
|
|
void VMADC_VXM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
void VMADC_VIM(RiscVReg vd, RiscVReg vs2, s8 simm5, RiscVReg vmask);
|
|
void VMADC_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMADC_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1);
|
|
void VMADC_VI(RiscVReg vd, RiscVReg vs2, s8 simm5);
|
|
void VSBC_VVM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, RiscVReg vmask);
|
|
void VSBC_VXM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
void VMSBC_VVM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, RiscVReg vmask);
|
|
void VMSBC_VXM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
void VMSBC_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMSBC_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1);
|
|
|
|
void VAND_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VAND_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VAND_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VOR_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VOR_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VOR_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VXOR_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VXOR_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VXOR_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VNOT_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE) {
|
|
VXOR_VI(vd, vs2, -1, vm);
|
|
}
|
|
|
|
void VSLL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSLL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSLL_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VSRL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSRL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSRL_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VSRA_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSRA_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSRA_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VNSRL_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VNSRL_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VNSRL_WI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VNSRA_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VNSRA_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VNSRA_WI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Using a mask creates an AND condition, assuming vtype has MU not MA.
|
|
// Note: VV and VI don't have all comparison ops, VX does (there's no GE/GEU at all, though.)
|
|
void VMSEQ_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSNE_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLTU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLT_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLEU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLE_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSEQ_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSNE_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLTU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLT_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLEU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSLE_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSGTU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSGT_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMSEQ_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VMSNE_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VMSLEU_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VMSLE_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VMSGTU_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VMSGT_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VMINU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMINU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMIN_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMIN_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMAXU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMAXU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMAX_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMAX_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VMUL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMUL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMULH_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMULH_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMULHU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMULHU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
// Takes vs2 as signed, vs1 as unsigned.
|
|
void VMULHSU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMULHSU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VDIVU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VDIVU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VDIV_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VDIV_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VREMU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREMU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VREM_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREM_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VWMUL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWMUL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWMULU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWMULU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWMULSU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWMULSU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Multiply and add - vd += vs1 * vs2.
|
|
void VMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VMACC_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Multiply and sub - vd -= vs1 * vs2.
|
|
void VNMSAC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VNMSAC_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Multiply and add - vd = vd * vs1 + vs2.
|
|
void VMADD_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VMADD_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Multiply and sub - vd = -(vd * vs1) + vs2.
|
|
void VNMSUB_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VNMSUB_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Widening multiply and add - vd(wide) += vs1 * vs2.
|
|
void VWMACCU_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VWMACCU_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Widening multiply and add - vd(wide) += vs1 * vs2.
|
|
void VWMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VWMACC_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Widening multiply and add - vd(wide) += S(vs1) * U(vs2).
|
|
void VWMACCSU_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VWMACCSU_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Widening multiply and add - vd(wide) += U(rs1) * S(vs2).
|
|
void VWMACCUS_VX(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Masked bits (1) take vs1/rs1/simm5, vmask must be V0.
|
|
void VMERGE_VVM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, RiscVReg vmask);
|
|
void VMERGE_VXM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
void VMERGE_VIM(RiscVReg vd, RiscVReg vs2, s8 simm5, RiscVReg vmask);
|
|
|
|
// Simple register copy, can be used as a hint to internally prepare size if vd == vs1.
|
|
void VMV_VV(RiscVReg vd, RiscVReg vs1);
|
|
// These broadcast a value to all lanes of vd.
|
|
void VMV_VX(RiscVReg vd, RiscVReg rs1);
|
|
void VMV_VI(RiscVReg vd, s8 simm5);
|
|
|
|
void VSADDU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSADDU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSADDU_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VSADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSADD_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSADD_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VSSUBU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSUBU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSUB_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VAADDU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VAADDU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VAADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VAADD_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VASUBU_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VASUBU_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VASUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VASUB_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Fixed-point multiply, sra's product by SEW-1 before writing result.
|
|
void VSMUL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSMUL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VSSRL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSRL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSRL_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VSSRA_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSRA_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSSRA_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VNCLIPU_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VNCLIPU_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VNCLIPU_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
void VNCLIP_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VNCLIP_WX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VNCLIP_VI(RiscVReg vd, RiscVReg vs2, s8 simm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFADD_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSUB_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFRSUB_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFWADD_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWADD_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWSUB_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWSUB_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWADD_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWADD_WF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWSUB_WV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWSUB_WF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFMUL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFMUL_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFDIV_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFDIV_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFRDIV_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFWMUL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWMUL_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Fused multiply and accumulate: vd = +vd + vs1 * vs2.
|
|
void VFMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFMACC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and accumulate, negated: vd = -vd - vs1 * vs2.
|
|
void VFNMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNMACC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and subtract accumuluator: vd = -vd + vs1 * vs2.
|
|
void VFMSAC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFMSAC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and subtract accumuluator, negated: vd = +vd - vs1 * vs2.
|
|
void VFNMSAC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNMSAC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and add: vd = +(vs1 * vd) + vs2.
|
|
void VFMADD_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFMADD_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and add, negated: vd = -(vs1 * vd) - vs2.
|
|
void VFNMADD_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNMADD_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and subtract: vd = +(vs1 * vd) - vs2.
|
|
void VFMSUB_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFMSUB_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused multiply and subtract, negated: vd = -(vs1 * vd) + vs2.
|
|
void VFNMSUB_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNMSUB_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Fused widening multiply and accumulate: vd(wide) = +vd + vs1 * vs2.
|
|
void VFWMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWMACC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused widening multiply and accumulate, negated: vd(wide) = -vd - vs1 * vs2.
|
|
void VFWNMACC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWNMACC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused widening multiply and subtract accumulator: vd(wide) = -vd + vs1 * vs2.
|
|
void VFWMSAC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWMSAC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
// Fused widening multiply and subtract accumulator, negated: vd(wide) = +vd - vs1 * vs2.
|
|
void VFWNMSAC_VV(RiscVReg vd, RiscVReg vs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWNMSAC_VF(RiscVReg vd, RiscVReg rs1, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFSQRT_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFRSQRT7_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFREC7_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFMIN_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFMIN_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFMAX_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFMAX_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFSGNJ_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSGNJ_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSGNJN_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSGNJN_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSGNJX_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSGNJX_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VMFEQ_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFEQ_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFNE_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFNE_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFLT_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFLT_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFLE_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFLE_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFGT_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VMFGE_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFCLASS_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
// vmask must be V0, takes rs1 where mask bits are set (1).
|
|
void VFMERGE_VFM(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, RiscVReg vmask);
|
|
// Broadcast/splat.
|
|
void VFMV_VF(RiscVReg vd, RiscVReg rs1);
|
|
|
|
void VFCVT_XU_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFCVT_X_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFCVT_RTZ_XU_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFCVT_RTZ_X_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFCVT_F_XU_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFCVT_F_X_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFWCVT_XU_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_X_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_RTZ_XU_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_RTZ_X_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_F_XU_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_F_X_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFWCVT_F_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFNCVT_XU_F_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_X_F_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_RTZ_XU_F_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_RTZ_X_F_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_F_XU_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_F_X_W(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_F_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFNCVT_ROD_F_F_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VREDSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDMAXU_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDMAX_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDMINU_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDMIN_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDAND_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDOR_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VREDXOR_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWREDSUMU_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWREDSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VFREDOSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFREDUSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFREDMAX_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFREDMIN_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWREDOSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VFWREDUSUM_VS(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VMAND_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMNAND_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMANDN_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMXOR_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMOR_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMNOR_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMORN_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMXNOR_MM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMMV_M(RiscVReg vd, RiscVReg vs1) {
|
|
VMAND_MM(vd, vs1, vs1);
|
|
}
|
|
void VMCLR_M(RiscVReg vd, RiscVReg vs1) {
|
|
VMXOR_MM(vd, vs1, vs1);
|
|
}
|
|
void VMSET_M(RiscVReg vd, RiscVReg vs1) {
|
|
VMXNOR_MM(vd, vs1, vs1);
|
|
}
|
|
void VMNOT_M(RiscVReg vd, RiscVReg vs1) {
|
|
VMNAND_MM(vd, vs1, vs1);
|
|
}
|
|
|
|
void VCPOP_M(RiscVReg rd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VFIRST_M(RiscVReg rd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VMSBF_M(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VMSIF_M(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VMSOF_M(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VIOTA_M(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VID_M(RiscVReg vd, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VMV_X_S(RiscVReg rd, RiscVReg vs2);
|
|
void VMV_S_X(RiscVReg vd, RiscVReg rs1);
|
|
void VFMV_F_S(RiscVReg rd, RiscVReg vs2);
|
|
void VFMV_S_F(RiscVReg vd, RiscVReg rs1);
|
|
|
|
void VSLIDEUP_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSLIDEUP_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VSLIDEDOWN_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSLIDEDOWN_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
void VSLIDE1UP_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSLIDE1UP_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VSLIDE1DOWN_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VFSLIDE1DOWN_VF(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VRGATHER_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VRGATHEREI16_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VRGATHER_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VRGATHER_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
void VCOMPRESS_VM(RiscVReg vd, RiscVReg vs2, RiscVReg vs1);
|
|
void VMVR_V(int regs, RiscVReg vd, RiscVReg vs2);
|
|
|
|
void VANDN_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VANDN_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VBREV_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VBREV8_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VREV8_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VCLZ_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VCTZ_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VCPOP_V(RiscVReg vd, RiscVReg vs2, VUseMask vm = VUseMask::NONE);
|
|
void VROL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VROL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VROR_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VROR_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VROR_VI(RiscVReg vd, RiscVReg vs2, u8 uimm6, VUseMask vm = VUseMask::NONE);
|
|
void VWSLL_VV(RiscVReg vd, RiscVReg vs2, RiscVReg vs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSLL_VX(RiscVReg vd, RiscVReg vs2, RiscVReg rs1, VUseMask vm = VUseMask::NONE);
|
|
void VWSLL_VI(RiscVReg vd, RiscVReg vs2, u8 uimm5, VUseMask vm = VUseMask::NONE);
|
|
|
|
// Bitmanip instructions.
|
|
void ADD_UW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SH_ADD(int shift, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SH_ADD_UW(int shift, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SLLI_UW(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void ANDN(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void ORN(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void XNOR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void CLZ(RiscVReg rd, RiscVReg rs);
|
|
void CLZW(RiscVReg rd, RiscVReg rs);
|
|
void CTZ(RiscVReg rd, RiscVReg rs);
|
|
void CTZW(RiscVReg rd, RiscVReg rs);
|
|
void CPOP(RiscVReg rd, RiscVReg rs);
|
|
void CPOPW(RiscVReg rd, RiscVReg rs);
|
|
void MAX(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MAXU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MIN(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void MINU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void SEXT_B(RiscVReg rd, RiscVReg rs);
|
|
void SEXT_H(RiscVReg rd, RiscVReg rs);
|
|
void SEXT_W(RiscVReg rd, RiscVReg rs) {
|
|
ADDIW(rd, rs, 0);
|
|
}
|
|
void ZEXT_B(RiscVReg rd, RiscVReg rs) {
|
|
ANDI(rd, rs, 0xFF);
|
|
}
|
|
void ZEXT_H(RiscVReg rd, RiscVReg rs);
|
|
void ZEXT_W(RiscVReg rd, RiscVReg rs) {
|
|
ADD_UW(rd, rs, R_ZERO);
|
|
}
|
|
void ROL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void ROLW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void ROR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void RORW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void RORI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void RORIW(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void ORC_B(RiscVReg rd, RiscVReg rs);
|
|
void REV8(RiscVReg rd, RiscVReg rs);
|
|
void CLMUL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void CLMULH(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void CLMULR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void BCLR(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void BCLRI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void BEXT(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void BEXTI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void BINV(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void BINVI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
void BSET(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void BSETI(RiscVReg rd, RiscVReg rs1, u32 shamt);
|
|
|
|
void CZERO_EQZ(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
void CZERO_NEZ(RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
|
|
|
|
// Compressed instructions.
|
|
void C_ADDI4SPN(RiscVReg rd, u32 nzuimm10);
|
|
void C_FLD(RiscVReg rd, RiscVReg addr, u8 uimm8);
|
|
void C_LW(RiscVReg rd, RiscVReg addr, u8 uimm7);
|
|
void C_FLW(RiscVReg rd, RiscVReg addr, u8 uimm7);
|
|
void C_LD(RiscVReg rd, RiscVReg addr, u8 uimm8);
|
|
void C_FSD(RiscVReg rs2, RiscVReg addr, u8 uimm8);
|
|
void C_SW(RiscVReg rs2, RiscVReg addr, u8 uimm7);
|
|
void C_FSW(RiscVReg rs2, RiscVReg addr, u8 uimm7);
|
|
void C_SD(RiscVReg rs2, RiscVReg addr, u8 uimm8);
|
|
|
|
void C_NOP();
|
|
void C_ADDI(RiscVReg rd, s8 nzsimm6);
|
|
void C_JAL(const void *dst);
|
|
FixupBranch C_JAL();
|
|
void C_ADDIW(RiscVReg rd, s8 simm6);
|
|
void C_LI(RiscVReg rd, s8 simm6);
|
|
void C_ADDI16SP(s32 nzsimm10);
|
|
void C_LUI(RiscVReg rd, s32 nzsimm18);
|
|
void C_SRLI(RiscVReg rd, u8 nzuimm6);
|
|
void C_SRAI(RiscVReg rd, u8 nzuimm6);
|
|
void C_ANDI(RiscVReg rd, s8 simm6);
|
|
void C_SUB(RiscVReg rd, RiscVReg rs2);
|
|
void C_XOR(RiscVReg rd, RiscVReg rs2);
|
|
void C_OR(RiscVReg rd, RiscVReg rs2);
|
|
void C_AND(RiscVReg rd, RiscVReg rs2);
|
|
void C_SUBW(RiscVReg rd, RiscVReg rs2);
|
|
void C_ADDW(RiscVReg rd, RiscVReg rs2);
|
|
void C_J(const void *dst);
|
|
void C_BEQZ(RiscVReg rs1, const void *dst);
|
|
void C_BNEZ(RiscVReg rs1, const void *dst);
|
|
FixupBranch C_J();
|
|
FixupBranch C_BEQZ(RiscVReg rs1);
|
|
FixupBranch C_BNEZ(RiscVReg rs1);
|
|
|
|
void C_SLLI(RiscVReg rd, u8 nzuimm6);
|
|
void C_FLDSP(RiscVReg rd, u32 uimm9);
|
|
void C_LWSP(RiscVReg rd, u8 uimm8);
|
|
void C_FLWSP(RiscVReg rd, u8 uimm8);
|
|
void C_LDSP(RiscVReg rd, u32 uimm9);
|
|
void C_JR(RiscVReg rs1);
|
|
void C_MV(RiscVReg rd, RiscVReg rs2);
|
|
void C_EBREAK();
|
|
void C_JALR(RiscVReg rs1);
|
|
void C_ADD(RiscVReg rd, RiscVReg rs2);
|
|
void C_FSDSP(RiscVReg rs2, u32 uimm9);
|
|
void C_SWSP(RiscVReg rs2, u8 uimm8);
|
|
void C_FSWSP(RiscVReg rs2, u8 uimm8);
|
|
void C_SDSP(RiscVReg rs2, u32 uimm9);
|
|
|
|
void C_LBU(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
|
void C_LHU(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
|
void C_LH(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
|
void C_SB(RiscVReg rs2, RiscVReg rs1, u8 uimm2);
|
|
void C_SH(RiscVReg rs2, RiscVReg rs1, u8 uimm2);
|
|
void C_ZEXT_B(RiscVReg rd);
|
|
void C_SEXT_B(RiscVReg rd);
|
|
void C_ZEXT_H(RiscVReg rd);
|
|
void C_SEXT_H(RiscVReg rd);
|
|
void C_ZEXT_W(RiscVReg rd);
|
|
void C_SEXT_W(RiscVReg rd) {
|
|
C_ADDIW(rd, 0);
|
|
}
|
|
void C_NOT(RiscVReg rd);
|
|
void C_MUL(RiscVReg rd, RiscVReg rs2);
|
|
|
|
bool CBInRange(const void *func) const;
|
|
bool CJInRange(const void *func) const;
|
|
|
|
bool SetAutoCompress(bool flag) {
|
|
bool prev = autoCompress_;
|
|
autoCompress_ = flag;
|
|
return prev;
|
|
}
|
|
bool AutoCompress() const;
|
|
|
|
private:
|
|
void SetJumpTarget(FixupBranch &branch, const void *dst);
|
|
bool BInRange(const void *src, const void *dst) const;
|
|
bool JInRange(const void *src, const void *dst) const;
|
|
bool CBInRange(const void *src, const void *dst) const;
|
|
bool CJInRange(const void *src, const void *dst) const;
|
|
|
|
void SetRegToImmediate(RiscVReg rd, uint64_t value, RiscVReg temp);
|
|
|
|
template <typename T, bool extend>
|
|
uint64_t AsImmediate(const T &v) {
|
|
static_assert(std::is_trivial<T>::value, "Immediate argument must be a simple type");
|
|
static_assert(sizeof(T) <= 8, "Immediate argument size should be 8, 16, 32, or 64 bits");
|
|
|
|
// Copy the type to allow floats and avoid endian issues.
|
|
if (sizeof(T) == 8) {
|
|
uint64_t value;
|
|
memcpy(&value, &v, sizeof(value));
|
|
return value;
|
|
} else if (sizeof(T) == 4) {
|
|
uint32_t value;
|
|
memcpy(&value, &v, sizeof(value));
|
|
if (extend)
|
|
return (int64_t)(int32_t)value;
|
|
return value;
|
|
} else if (sizeof(T) == 2) {
|
|
uint16_t value;
|
|
memcpy(&value, &v, sizeof(value));
|
|
if (extend)
|
|
return (int64_t)(int16_t)value;
|
|
return value;
|
|
} else if (sizeof(T) == 1) {
|
|
uint8_t value;
|
|
memcpy(&value, &v, sizeof(value));
|
|
if (extend)
|
|
return (int64_t)(int8_t)value;
|
|
return value;
|
|
}
|
|
return (uint64_t)v;
|
|
}
|
|
|
|
inline void Write32(u32 value) {
|
|
Write16(value & 0x0000FFFF);
|
|
Write16(value >> 16);
|
|
}
|
|
inline void Write16(u16 value) {
|
|
*(u16 *)writable_ = value;
|
|
code_ += 2;
|
|
writable_ += 2;
|
|
}
|
|
|
|
protected:
|
|
const u8 *code_ = nullptr;
|
|
u8 *writable_ = nullptr;
|
|
const u8 *lastCacheFlushEnd_ = nullptr;
|
|
bool autoCompress_ = false;
|
|
};
|
|
|
|
class RiscVCodeBlock : public CodeBlock<RiscVEmitter> {
|
|
private:
|
|
void PoisonMemory(int offset) override;
|
|
};
|
|
|
|
};
|