mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #15910 from unknownbrackets/riscv-emitter
Add LI and compressed instructions for RISC-V
This commit is contained in:
commit
5247ffa0af
8 changed files with 1181 additions and 44 deletions
|
@ -2348,6 +2348,7 @@ if(UNITTEST)
|
|||
unittest/TestIRPassSimplify.cpp
|
||||
unittest/TestX64Emitter.cpp
|
||||
unittest/TestVertexJit.cpp
|
||||
unittest/TestRiscVEmitter.cpp
|
||||
unittest/TestSoftwareGPUJit.cpp
|
||||
unittest/TestThreadManager.cpp
|
||||
unittest/JitHarness.cpp
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include "Common/CodeBlock.h"
|
||||
#include "Common/Common.h"
|
||||
|
||||
|
@ -45,6 +47,8 @@ enum RiscVReg {
|
|||
enum class FixupBranchType {
|
||||
B,
|
||||
J,
|
||||
CB,
|
||||
CJ,
|
||||
};
|
||||
|
||||
enum class Fence {
|
||||
|
@ -104,6 +108,7 @@ enum class Csr {
|
|||
};
|
||||
|
||||
struct FixupBranch {
|
||||
FixupBranch() {}
|
||||
FixupBranch(const u8 *p, FixupBranchType t) : ptr(p), type(t) {}
|
||||
~FixupBranch();
|
||||
|
||||
|
@ -192,6 +197,16 @@ public:
|
|||
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);
|
||||
|
@ -319,28 +334,123 @@ public:
|
|||
void CSRRCI(RiscVReg rd, Csr csr, u8 uimm5);
|
||||
|
||||
void FRRM(RiscVReg rd) {
|
||||
CSRRS(rd, Csr::FRm, X0);
|
||||
CSRRS(rd, Csr::FRm, R_ZERO);
|
||||
}
|
||||
void FSRM(RiscVReg rs) {
|
||||
CSRRW(X0, Csr::FRm, 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(X0, rm);
|
||||
FSRMI(R_ZERO, rm);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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) {
|
||||
*(u32 *)writable_ = value;
|
||||
code_ += 4;
|
||||
writable_ += 4;
|
||||
Write16(value & 0x0000FFFF);
|
||||
Write16(value >> 16);
|
||||
}
|
||||
inline void Write16(u16 value) {
|
||||
*(u16 *)writable_ = value;
|
||||
|
@ -351,6 +461,7 @@ private:
|
|||
const u8 *code_ = nullptr;
|
||||
u8 *writable_ = nullptr;
|
||||
const u8 *lastCacheFlushEnd_ = nullptr;
|
||||
bool autoCompress_ = false;
|
||||
};
|
||||
|
||||
class MIPSCodeBlock : public CodeBlock<RiscVEmitter> {
|
||||
|
|
|
@ -721,11 +721,13 @@ ifeq ($(UNITTEST),1)
|
|||
TESTARMEMITTER_FILE = \
|
||||
$(SRC)/Common/ArmEmitter.cpp \
|
||||
$(SRC)/Common/Arm64Emitter.cpp \
|
||||
$(SRC)/Common/RiscVEmitter.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \
|
||||
$(SRC)/Core/Util/DisArm64.cpp \
|
||||
$(SRC)/ext/disarm.cpp \
|
||||
$(SRC)/unittest/TestArmEmitter.cpp \
|
||||
$(SRC)/unittest/TestArm64Emitter.cpp \
|
||||
$(SRC)/unittest/TestRiscVEmitter.cpp \
|
||||
$(SRC)/unittest/TestX64Emitter.cpp
|
||||
endif
|
||||
|
||||
|
|
69
unittest/TestRiscVEmitter.cpp
Normal file
69
unittest/TestRiscVEmitter.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
// 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/.
|
||||
|
||||
#include <cstdio>
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/RiscVEmitter.h"
|
||||
#include "UnitTest.h"
|
||||
|
||||
bool TestRiscVEmitter() {
|
||||
using namespace RiscVGen;
|
||||
|
||||
// TODO: Set cpu_info flags.
|
||||
|
||||
u32 code[1024];
|
||||
RiscVEmitter emitter((u8 *)code, (u8 *)code);
|
||||
|
||||
emitter.SetAutoCompress(false);
|
||||
emitter.LUI(X1, 0xFFFFF000);
|
||||
emitter.AUIPC(X2, 0x70051000);
|
||||
emitter.JAL(X3, code);
|
||||
emitter.JALR(X1, X2, -12);
|
||||
FixupBranch b1 = emitter.JAL(X4);
|
||||
emitter.SetJumpTarget(b1);
|
||||
emitter.BEQ(X5, X6, code);
|
||||
emitter.LB(X7, X8, 42);
|
||||
emitter.SB(X9, X10, 1337);
|
||||
emitter.ADDI(X11, X12, 42);
|
||||
emitter.SLLI(X13, X14, 3);
|
||||
emitter.ADD(X15, X16, X17);
|
||||
emitter.FENCE(Fence::RW, Fence::RW);
|
||||
|
||||
static constexpr uint32_t expected[] = {
|
||||
0xfffff0b7,
|
||||
0x70051117,
|
||||
0xff9ff1ef,
|
||||
0xff4100e7,
|
||||
0x0040026f,
|
||||
0xfe6286e3,
|
||||
0x02a40383,
|
||||
0x52950ca3,
|
||||
0x02a60593,
|
||||
0x00371693,
|
||||
0x011807b3,
|
||||
0x0330000f,
|
||||
};
|
||||
|
||||
ptrdiff_t len = (u32 *)emitter.GetWritableCodePtr() - code;
|
||||
EXPECT_EQ_INT(len, ARRAY_SIZE(expected));
|
||||
|
||||
for (ptrdiff_t i = 0; i < len; ++i) {
|
||||
EXPECT_EQ_HEX(code[i], expected[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -754,6 +754,7 @@ struct TestItem {
|
|||
bool TestArmEmitter();
|
||||
bool TestArm64Emitter();
|
||||
bool TestX64Emitter();
|
||||
bool TestRiscVEmitter();
|
||||
bool TestShaderGenerators();
|
||||
bool TestSoftwareGPUJit();
|
||||
bool TestIRPassSimplify();
|
||||
|
@ -768,6 +769,9 @@ TestItem availableTests[] = {
|
|||
#endif
|
||||
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
|
||||
TEST_ITEM(X64Emitter),
|
||||
#endif
|
||||
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) || PPSSPP_ARCH(RISCV64)
|
||||
TEST_ITEM(RiscVEmitter),
|
||||
#endif
|
||||
TEST_ITEM(VertexJit),
|
||||
TEST_ITEM(Asin),
|
||||
|
|
|
@ -383,6 +383,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestIRPassSimplify.cpp" />
|
||||
<ClCompile Include="TestRiscVEmitter.cpp" />
|
||||
<ClCompile Include="TestShaderGenerators.cpp" />
|
||||
<ClCompile Include="TestSoftwareGPUJit.cpp" />
|
||||
<ClCompile Include="TestThreadManager.cpp" />
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<ClCompile Include="TestThreadManager.cpp" />
|
||||
<ClCompile Include="TestSoftwareGPUJit.cpp" />
|
||||
<ClCompile Include="TestIRPassSimplify.cpp" />
|
||||
<ClCompile Include="TestRiscVEmitter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="JitHarness.h" />
|
||||
|
|
Loading…
Add table
Reference in a new issue