mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
riscv: Emit mul/div instructions.
This commit is contained in:
parent
00280ab2ad
commit
c66d02d4db
2 changed files with 124 additions and 0 deletions
|
@ -30,6 +30,11 @@ static inline uint8_t BitsSupported() {
|
|||
return 64;
|
||||
}
|
||||
|
||||
static inline bool SupportsMulDiv() {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class Opcode32 {
|
||||
// Note: invalid, just used for FixupBranch.
|
||||
ZERO = 0b0000000,
|
||||
|
@ -55,6 +60,7 @@ enum class Funct3 {
|
|||
PRIV = 0b000,
|
||||
|
||||
FENCE = 0b000,
|
||||
FENCE_I = 0b001,
|
||||
|
||||
BEQ = 0b000,
|
||||
BNE = 0b001,
|
||||
|
@ -79,6 +85,15 @@ enum class Funct3 {
|
|||
SRL = 0b101,
|
||||
OR = 0b110,
|
||||
AND = 0b111,
|
||||
|
||||
MUL = 0b000,
|
||||
MULH = 0b001,
|
||||
MULHSU = 0b010,
|
||||
MULHU = 0b011,
|
||||
DIV = 0b100,
|
||||
DIVU = 0b101,
|
||||
REM = 0b110,
|
||||
REMU = 0b111,
|
||||
};
|
||||
|
||||
enum class Funct2 {
|
||||
|
@ -90,6 +105,8 @@ enum class Funct7 {
|
|||
|
||||
SUB = 0b0100000,
|
||||
SRA = 0b0100000,
|
||||
|
||||
MULDIV = 0b0000001,
|
||||
};
|
||||
|
||||
enum class Funct12 {
|
||||
|
@ -635,4 +652,95 @@ void RiscVEmitter::SRAW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
|||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::SRL, rs1, rs2, Funct7::SRA));
|
||||
}
|
||||
|
||||
void RiscVEmitter::MUL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::MUL, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::MULH(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::MULH, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::MULHSU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::MULHSU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::MULHU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::MULHU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::DIV(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::DIV, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::DIVU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::DIVU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::REM(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::REM, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::REMU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsMulDiv(), "%s is only valid with R32M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::REMU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::MULW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(BitsSupported() >= 64 && SupportsMulDiv(), "%s is only valid with R64M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::MUL, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::DIVW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(BitsSupported() >= 64 && SupportsMulDiv(), "%s is only valid with R64M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::DIV, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::DIVUW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(BitsSupported() >= 64 && SupportsMulDiv(), "%s is only valid with R64M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::DIVU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::REMW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(BitsSupported() >= 64 && SupportsMulDiv(), "%s is only valid with R64M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::REM, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
void RiscVEmitter::REMUW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
||||
_assert_msg_(BitsSupported() >= 64 && SupportsMulDiv(), "%s is only valid with R64M", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::REMU, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -188,6 +188,22 @@ public:
|
|||
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);
|
||||
|
||||
private:
|
||||
void SetJumpTarget(const FixupBranch &branch, const void *dst);
|
||||
bool BInRange(const void *src, const void *dst) const;
|
||||
|
|
Loading…
Add table
Reference in a new issue