riscv: Add jit for some initial instructions.

This commit is contained in:
Unknown W. Brackets 2023-07-20 21:09:59 -07:00
parent 4c1cc2dfdc
commit bf7a6eb2cd
11 changed files with 474 additions and 1 deletions

View file

@ -1610,6 +1610,12 @@ list(APPEND CoreExtra
list(APPEND CoreExtra
Core/MIPS/RiscV/RiscVAsm.cpp
Core/MIPS/RiscV/RiscVCompALU.cpp
Core/MIPS/RiscV/RiscVCompBranch.cpp
Core/MIPS/RiscV/RiscVCompFPU.cpp
Core/MIPS/RiscV/RiscVCompLoadStore.cpp
Core/MIPS/RiscV/RiscVCompSystem.cpp
Core/MIPS/RiscV/RiscVCompVec.cpp
Core/MIPS/RiscV/RiscVJit.cpp
Core/MIPS/RiscV/RiscVJit.h
Core/MIPS/RiscV/RiscVRegCache.cpp

View file

@ -594,6 +594,12 @@
<ClCompile Include="MIPS\IR\IRRegCache.cpp" />
<ClCompile Include="MIPS\MIPSVFPUFallbacks.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVAsm.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompALU.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompBranch.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompSystem.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompFPU.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompLoadStore.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVCompVec.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVJit.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVRegCache.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVRegCacheFPU.cpp" />

View file

@ -1219,6 +1219,24 @@
<ClCompile Include="MIPS\RiscV\RiscVRegCacheFPU.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompFPU.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompLoadStore.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompVec.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompALU.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompBranch.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVCompSystem.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">

View file

@ -0,0 +1,137 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for integer / arithmetic / logic related instructions.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
void RiscVJit::CompIR_Arith(IRInst inst) {
CONDITIONAL_DISABLE;
bool allowPtrMath = true;
#ifndef MASKED_PSP_MEMORY
// Since we modify it, we can't safely.
allowPtrMath = false;
#endif
// RISC-V only adds signed immediates, so rewrite a small enough subtract to an add.
// We use -2047 and 2048 here because the range swaps.
if (inst.op == IROp::SubConst && (int32_t)inst.constant >= -2047 && (int32_t)inst.constant <= 2048) {
inst.op = IROp::AddConst;
inst.constant = (uint32_t)-(int32_t)inst.constant;
}
switch (inst.op) {
case IROp::Add:
gpr.MapDirtyInIn(inst.dest, inst.src1, inst.src2);
ADDW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2));
break;
case IROp::Sub:
gpr.MapDirtyInIn(inst.dest, inst.src1, inst.src2);
SUBW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2));
break;
case IROp::AddConst:
if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {
// Typical of stack pointer updates.
if (gpr.IsMappedAsPointer(inst.src1) && inst.dest == inst.src1 && allowPtrMath) {
gpr.MarkDirty(gpr.RPtr(inst.dest));
ADDI(gpr.RPtr(inst.dest), gpr.RPtr(inst.dest), inst.constant);
} else {
gpr.MapDirtyIn(inst.dest, inst.src1);
ADDIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.constant);
}
} else {
gpr.MapDirtyIn(inst.dest, inst.src1);
LI(SCRATCH1, (s32)inst.constant, SCRATCH2);
ADDW(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1);
}
break;
case IROp::SubConst:
gpr.MapDirtyIn(inst.dest, inst.src1);
LI(SCRATCH1, (s32)inst.constant, SCRATCH2);
SUBW(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1);
break;
case IROp::Neg:
gpr.MapDirtyIn(inst.dest, inst.src1);
SUBW(gpr.R(inst.dest), R_ZERO, gpr.R(inst.src1));
break;
default:
INVALIDOP;
break;
}
}
void RiscVJit::CompIR_Logic(IRInst inst) {
CONDITIONAL_DISABLE;
switch (inst.op) {
case IROp::And:
case IROp::Or:
case IROp::Xor:
case IROp::AndConst:
case IROp::OrConst:
case IROp::XorConst:
case IROp::Not:
CompIR_Generic(inst);
break;
default:
INVALIDOP;
break;
}
}
void RiscVJit::CompIR_Assign(IRInst inst) {
CONDITIONAL_DISABLE;
switch (inst.op) {
case IROp::Mov:
case IROp::Ext8to32:
case IROp::Ext16to32:
case IROp::ReverseBits:
case IROp::BSwap16:
case IROp::BSwap32:
CompIR_Generic(inst);
break;
default:
INVALIDOP;
break;
}
}
} // namespace MIPSComp

View file

@ -0,0 +1,60 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for exits, syscalls, and related.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
void RiscVJit::CompIR_Exit(IRInst inst) {
CONDITIONAL_DISABLE;
// Will probably always want this?
FlushAll();
switch (inst.op) {
case IROp::ExitToConst:
case IROp::ExitToReg:
case IROp::ExitToConstIfEq:
case IROp::ExitToConstIfNeq:
case IROp::ExitToConstIfGeZ:
case IROp::ExitToConstIfLtZ:
case IROp::ExitToConstIfLeZ:
case IROp::ExitToPC:
CompIR_Generic(inst);
break;
default:
INVALIDOP;
break;
}
}
} // namespace MIPSComp

View file

@ -0,0 +1,37 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for floating point related instructions.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
} // namespace MIPSComp

View file

@ -0,0 +1,37 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for load/store instructions.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
} // namespace MIPSComp

View file

@ -0,0 +1,70 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for basic PC/downcount accounting, debug funcs, etc.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
void RiscVJit::CompIR_Basic(IRInst inst) {
CONDITIONAL_DISABLE;
switch (inst.op) {
case IROp::SetConst:
gpr.SetImm(inst.dest, inst.constant);
break;
case IROp::Downcount:
if (inst.constant <= 2048) {
ADDI(DOWNCOUNTREG, DOWNCOUNTREG, -(s32)inst.constant);
} else {
LI(SCRATCH1, inst.constant, SCRATCH2);
SUB(DOWNCOUNTREG, DOWNCOUNTREG, SCRATCH1);
}
break;
case IROp::SetPC:
gpr.MapIn(inst.src1);
MovToPC(gpr.R(inst.src1));
break;
case IROp::SetPCConst:
LI(SCRATCH1, inst.constant, SCRATCH2);
MovToPC(SCRATCH1);
break;
default:
INVALIDOP;
break;
}
}
} // namespace MIPSComp

View file

@ -0,0 +1,37 @@
// Copyright (c) 2023- 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 "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
// This file contains compilation for vector instructions.
//
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
// Currently known non working ones should have DISABLE. No flags because that's in IR already.
// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }
#define CONDITIONAL_DISABLE {}
#define DISABLE { CompIR_Generic(inst); return; }
#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
} // namespace MIPSComp

View file

@ -65,7 +65,8 @@ bool RiscVJit::CompileBlock(u32 em_address, std::vector<IRInst> &instructions, u
// TODO: Block linking, checked entries and such.
int block_num = blocks_.GetBlockNumberFromStartAddress(em_address);
_assert_msg_(blockStartAddrs_[block_num] == nullptr, "Block reused before clear");
_assert_msg_(block_num >= 0 && block_num < MAX_ALLOWED_JIT_BLOCKS, "Bad block num");
_assert_msg_(blockStartAddrs_[block_num] == nullptr, "Block %d reused before clear", block_num);
blockStartAddrs_[block_num] = GetCodePointer();
gpr.Start();
@ -106,7 +107,64 @@ static u32 DoIRInst(uint64_t value) {
}
void RiscVJit::CompileIRInst(IRInst inst) {
switch (inst.op) {
case IROp::Nop:
break;
case IROp::SetConst:
case IROp::Downcount:
case IROp::SetPC:
case IROp::SetPCConst:
CompIR_Basic(inst);
break;
case IROp::Add:
case IROp::Sub:
case IROp::AddConst:
case IROp::SubConst:
case IROp::Neg:
CompIR_Arith(inst);
break;
case IROp::And:
case IROp::Or:
case IROp::Xor:
case IROp::AndConst:
case IROp::OrConst:
case IROp::XorConst:
case IROp::Not:
CompIR_Logic(inst);
break;
case IROp::Mov:
case IROp::Ext8to32:
case IROp::Ext16to32:
case IROp::ReverseBits:
case IROp::BSwap16:
case IROp::BSwap32:
CompIR_Assign(inst);
break;
case IROp::ExitToConst:
case IROp::ExitToReg:
case IROp::ExitToConstIfEq:
case IROp::ExitToConstIfNeq:
case IROp::ExitToConstIfGeZ:
case IROp::ExitToConstIfLtZ:
case IROp::ExitToConstIfLeZ:
case IROp::ExitToPC:
CompIR_Exit(inst);
break;
default:
CompIR_Generic(inst);
break;
}
}
void RiscVJit::CompIR_Generic(IRInst inst) {
// For now, we're gonna do it the slow and ugly way.
// Maybe there's a smarter way to fallback?
uint64_t value;
memcpy(&value, &inst, sizeof(inst));

View file

@ -63,6 +63,13 @@ private:
void FlushAll();
void CompIR_Generic(IRInst inst);
void CompIR_Basic(IRInst inst);
void CompIR_Arith(IRInst inst);
void CompIR_Logic(IRInst inst);
void CompIR_Assign(IRInst inst);
void CompIR_Exit(IRInst inst);
RiscVRegCache gpr;
const u8 *enterDispatcher_ = nullptr;