Merge pull request #17815 from unknownbrackets/riscv-jit

riscv: Spill registers more intelligently
This commit is contained in:
Unknown W. Brackets 2023-07-30 14:49:37 -07:00 committed by GitHub
commit b03398a46c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 339 additions and 82 deletions

View file

@ -1539,6 +1539,8 @@ set(CoreExtra)
set(CoreExtraLibs)
set(CoreExtra ${CoreExtra}
Core/MIPS/IR/IRAnalysis.cpp
Core/MIPS/IR/IRAnalysis.h
Core/MIPS/IR/IRCompALU.cpp
Core/MIPS/IR/IRCompBranch.cpp
Core/MIPS/IR/IRCompFPU.cpp

View file

@ -580,6 +580,7 @@
<ClCompile Include="KeyMapDefaults.cpp" />
<ClCompile Include="MemFault.cpp" />
<ClCompile Include="MIPS\fake\FakeJit.cpp" />
<ClCompile Include="MIPS\IR\IRAnalysis.cpp" />
<ClCompile Include="MIPS\IR\IRAsm.cpp" />
<ClCompile Include="MIPS\IR\IRCompALU.cpp" />
<ClCompile Include="MIPS\IR\IRCompBranch.cpp" />
@ -1164,6 +1165,7 @@
<ClInclude Include="KeyMapDefaults.h" />
<ClInclude Include="MemFault.h" />
<ClInclude Include="MIPS\fake\FakeJit.h" />
<ClInclude Include="MIPS\IR\IRAnalysis.h" />
<ClInclude Include="MIPS\IR\IRFrontend.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />
<ClInclude Include="MIPS\IR\IRInterpreter.h" />

View file

@ -1237,6 +1237,9 @@
<ClCompile Include="MIPS\RiscV\RiscVCompSystem.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\IR\IRAnalysis.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1992,6 +1995,9 @@
<ClInclude Include="MIPS\RiscV\RiscVRegCacheFPU.h">
<Filter>MIPS\RiscV</Filter>
</ClInclude>
<ClInclude Include="MIPS\IR\IRAnalysis.h">
<Filter>MIPS\IR</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE.TXT" />

135
Core/MIPS/IR/IRAnalysis.cpp Normal file
View file

@ -0,0 +1,135 @@
// Copyright (c) 2016- 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/MIPS/IR/IRAnalysis.h"
static bool IRReadsFrom(const IRInst &inst, int reg, char type, bool directly = false) {
const IRMeta *m = GetIRMeta(inst.op);
if (m->types[1] == type && inst.src1 == reg) {
return true;
}
if (m->types[2] == type && inst.src2 == reg) {
return true;
}
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type && inst.src3 == reg) {
return true;
}
if (!directly) {
if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
return true;
if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)
return true;
}
return false;
}
bool IRReadsFromFPR(const IRInst &inst, int reg, bool directly) {
if (IRReadsFrom(inst, reg, 'F', directly))
return true;
const IRMeta *m = GetIRMeta(inst.op);
// We also need to check V and 2. Indirect reads already checked, don't check again.
if (m->types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)
return true;
if (m->types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)
return true;
if (m->types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)
return true;
if (m->types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)
return true;
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (m->types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)
return true;
if (m->types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)
return true;
}
return false;
}
bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly) {
return IRReadsFrom(inst, reg, 'G', directly);
}
int IRDestGPR(const IRInst &inst) {
const IRMeta *m = GetIRMeta(inst.op);
if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') {
return inst.dest;
}
return -1;
}
bool IRWritesToGPR(const IRInst &inst, int reg) {
return IRDestGPR(inst) == reg;
}
bool IRWritesToFPR(const IRInst &inst, int reg) {
const IRMeta *m = GetIRMeta(inst.op);
// Doesn't write to anything.
if ((m->flags & IRFLAG_SRC3) != 0)
return false;
if (m->types[0] == 'F' && reg == inst.dest)
return true;
if (m->types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)
return true;
if (m->types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)
return true;
return false;
}
IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) {
// Exclude any "special" regs from this logic for now.
if (gpr >= 32)
return IRUsage::UNKNOWN;
int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInst inst = info.instructions[info.currentIndex + i];
if (IRReadsFromGPR(inst, gpr))
return IRUsage::READ;
// We say WRITE when the current instruction writes. It's not useful for spilling.
if (IRDestGPR(inst) == gpr)
return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
}
return IRUsage::UNUSED;
}
IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) {
// Let's only pay attention to standard FP regs and temps.
// See MIPS.h for these offsets.
if (fpr < 0 || (fpr >= 160 && fpr < 192) || fpr >= 208)
return IRUsage::UNKNOWN;
int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInst inst = info.instructions[info.currentIndex + i];
if (IRReadsFromFPR(inst, fpr))
return IRUsage::READ;
// We say WRITE when the current instruction writes. It's not useful for spilling.
if (IRWritesToFPR(inst, fpr)) {
return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
}
}
return IRUsage::UNUSED;
}

44
Core/MIPS/IR/IRAnalysis.h Normal file
View file

@ -0,0 +1,44 @@
// Copyright (c) 2016- 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 "Core/MIPS/IR/IRInst.h"
bool IRReadsFromFPR(const IRInst &inst, int reg, bool directly = false);
bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly = false);
bool IRWritesToGPR(const IRInst &inst, int reg);
bool IRWritesToFPR(const IRInst &inst, int reg);
int IRDestGPR(const IRInst &inst);
struct IRSituation {
int lookaheadCount;
int currentIndex;
const IRInst *instructions;
int numInstructions;
};
enum class IRUsage {
UNKNOWN,
UNUSED,
READ,
WRITE,
CLOBBERED,
};
IRUsage IRNextGPRUsage(int gpr, const IRSituation &info);
IRUsage IRNextFPRUsage(int fpr, const IRSituation &info);

View file

@ -1,6 +1,5 @@
#include "Common/CommonFuncs.h"
#include "Core/MIPS/IR/IRInst.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/MIPSDebugInterface.h"
// Legend

View file

@ -36,7 +36,6 @@
#include "Core/MIPS/MIPSTables.h"
#include "Core/MIPS/IR/IRRegCache.h"
#include "Core/MIPS/IR/IRJit.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/IR/IRInterpreter.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/Reporting.h"

View file

@ -6,6 +6,7 @@
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Log.h"
#include "Core/Config.h"
#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/IR/IRInterpreter.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/IR/IRRegCache.h"
@ -805,27 +806,6 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
return logBlocks;
}
bool IRReadsFromGPR(const IRInst &inst, int reg, bool directly = false) {
const IRMeta *m = GetIRMeta(inst.op);
if (m->types[1] == 'G' && inst.src1 == reg) {
return true;
}
if (m->types[2] == 'G' && inst.src2 == reg) {
return true;
}
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == 'G' && inst.src3 == reg) {
return true;
}
if (!directly) {
if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
return true;
if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)
return true;
}
return false;
}
IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) {
IRInst newInst = inst;
const IRMeta *m = GetIRMeta(inst.op);
@ -842,15 +822,6 @@ IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) {
return newInst;
}
int IRDestGPR(const IRInst &inst) {
const IRMeta *m = GetIRMeta(inst.op);
if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') {
return inst.dest;
}
return -1;
}
IRInst IRReplaceDestGPR(const IRInst &inst, int fromReg, int toReg) {
IRInst newInst = inst;
const IRMeta *m = GetIRMeta(inst.op);

View file

@ -813,7 +813,7 @@ namespace MIPSAnalyst {
break;
}
if (reg > 32) {
if (reg >= 32) {
return USAGE_UNKNOWN;
}

View file

@ -277,10 +277,55 @@ void RiscVJit::CompIR_FCvt(IRInst inst) {
void RiscVJit::CompIR_FSat(IRInst inst) {
CONDITIONAL_DISABLE;
RiscVReg tempReg = INVALID_REG;
FixupBranch skipLower;
FixupBranch finishLower;
FixupBranch skipHigher;
switch (inst.op) {
case IROp::FSat0_1:
tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1);
if (inst.dest != inst.src1)
FMV(32, fpr.R(inst.dest), fpr.R(inst.src1));
// First, set SCRATCH1 = clamp to zero, SCRATCH2 = clamp to one.
FCVT(FConv::S, FConv::W, tempReg, R_ZERO);
// FLE here is intentional to convert -0.0 to +0.0.
FLE(32, SCRATCH1, fpr.R(inst.src1), tempReg);
LI(SCRATCH2, 1.0f);
FMV(FMv::W, FMv::X, tempReg, SCRATCH2);
FLT(32, SCRATCH2, tempReg, fpr.R(inst.src1));
skipLower = BEQ(SCRATCH1, R_ZERO);
FCVT(FConv::S, FConv::W, fpr.R(inst.dest), R_ZERO);
finishLower = J();
SetJumpTarget(skipLower);
skipHigher = BEQ(SCRATCH2, R_ZERO);
// Still has 1.0 in it.
FMV(32, fpr.R(inst.dest), tempReg);
SetJumpTarget(finishLower);
SetJumpTarget(skipHigher);
break;
case IROp::FSatMinus1_1:
CompIR_Generic(inst);
tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1);
if (inst.dest != inst.src1)
FMV(32, fpr.R(inst.dest), fpr.R(inst.src1));
// First, set SCRATCH1 = clamp to negative, SCRATCH2 = clamp to positive.
LI(SCRATCH2, -1.0f);
FMV(FMv::W, FMv::X, tempReg, SCRATCH2);
FLT(32, SCRATCH1, fpr.R(inst.src1), tempReg);
FNEG(32, tempReg, tempReg);
FLT(32, SCRATCH2, tempReg, fpr.R(inst.src1));
// But we can actually do one branch, using sign-injection to keep the original sign.
OR(SCRATCH1, SCRATCH1, SCRATCH2);
skipLower = BEQ(SCRATCH1, R_ZERO);
FSGNJ(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest));
SetJumpTarget(skipLower);
break;
default:
@ -551,6 +596,7 @@ void RiscVJit::CompIR_FSpecial(IRInst inst) {
}
};
RiscVReg tempReg = INVALID_REG;
switch (inst.op) {
case IROp::FSin:
callFuncF_F(&vfpu_sin);
@ -561,30 +607,25 @@ void RiscVJit::CompIR_FSpecial(IRInst inst) {
break;
case IROp::FRSqrt:
fpr.MapDirtyIn(inst.dest, inst.src1);
tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1);
FSQRT(32, fpr.R(inst.dest), fpr.R(inst.src1));
// Ugh, we can't really avoid a temp here. Probably not worth a permanent one.
LI(SCRATCH1, 1.0f);
{
// TODO: Smarter allocation of a temp reg?
RiscVReg tempReg = fpr.R(inst.dest) == F31 ? F30 : F31;
fpr.FlushRiscVReg(tempReg);
FMV(FMv::W, FMv::X, tempReg, SCRATCH1);
FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest));
}
FMV(FMv::W, FMv::X, tempReg, SCRATCH1);
FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest));
break;
case IROp::FRecip:
fpr.MapDirtyIn(inst.dest, inst.src1);
LI(SCRATCH1, 1.0f);
if (inst.dest != inst.src1) {
// This is the easy case.
fpr.MapDirtyIn(inst.dest, inst.src1);
LI(SCRATCH1, 1.0f);
FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1);
FDIV(32, fpr.R(inst.dest), fpr.R(inst.dest), fpr.R(inst.src1));
} else {
RiscVReg tempReg = fpr.R(inst.dest) == F31 ? F30 : F31;
fpr.FlushRiscVReg(tempReg);
tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1);
LI(SCRATCH1, 1.0f);
FMV(FMv::W, FMv::X, tempReg, SCRATCH1);
FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.src1));
}

View file

@ -116,19 +116,20 @@ bool RiscVJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) {
// TODO: Block linking, checked entries and such.
gpr.Start();
fpr.Start();
gpr.Start(block);
fpr.Start(block);
for (int i = 0; i < block->GetNumInstructions(); ++i) {
const IRInst &inst = block->GetInstructions()[i];
gpr.SetIRIndex(i);
fpr.SetIRIndex(i);
CompileIRInst(inst);
if (jo.Disabled(JitDisable::REGALLOC_GPR)) {
if (jo.Disabled(JitDisable::REGALLOC_GPR))
gpr.FlushAll();
}
if (jo.Disabled(JitDisable::REGALLOC_FPR)) {
if (jo.Disabled(JitDisable::REGALLOC_FPR))
fpr.FlushAll();
}
// Safety check, in case we get a bunch of really large jit ops without a lot of branching.
if (GetSpaceLeft() < 0x800) {

View file

@ -21,6 +21,7 @@
#include "Common/CPUDetect.h"
#include "Core/MIPS/IR/IRInst.h"
#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/Reporting.h"
@ -36,7 +37,7 @@ void RiscVRegCache::Init(RiscVEmitter *emitter) {
emit_ = emitter;
}
void RiscVRegCache::Start() {
void RiscVRegCache::Start(MIPSComp::IRBlock *irBlock) {
if (!initialReady_) {
SetupInitialRegs();
initialReady_ = true;
@ -56,6 +57,9 @@ void RiscVRegCache::Start() {
mr[statics[i].mr].isStatic = true;
mr[statics[i].mr].spillLock = true;
}
irBlock_ = irBlock;
irIndex_ = 0;
}
void RiscVRegCache::SetupInitialRegs() {
@ -362,8 +366,6 @@ allocate:
}
// Still nothing. Let's spill a reg and goto 10.
// TODO: Use age or something to choose which register to spill?
// TODO: Spill dirty regs first? or opposite?
bool clobbered;
RiscVReg bestToSpill = FindBestToSpill(true, &clobbered);
if (bestToSpill == INVALID_REG) {
@ -392,6 +394,12 @@ RiscVReg RiscVRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
static const int UNUSED_LOOKAHEAD_OPS = 30;
IRSituation info;
info.lookaheadCount = UNUSED_LOOKAHEAD_OPS;
info.currentIndex = irIndex_;
info.instructions = irBlock_->GetInstructions();
info.numInstructions = irBlock_->GetNumInstructions();
*clobbered = false;
for (int i = 0; i < allocCount; i++) {
RiscVReg reg = allocOrder[i];
@ -401,16 +409,24 @@ RiscVReg RiscVRegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
continue;
// As it's in alloc-order, we know it's not static so we don't need to check for that.
IRUsage usage = IRNextGPRUsage(ar[reg].mipsReg, info);
// TODO: Look for clobbering in the IRInst array with index?
// Not awesome. A used reg. Let's try to avoid spilling.
// TODO: Actually check if we'd be spilling.
if (unusedOnly) {
continue;
// Awesome, a clobbered reg. Let's use it.
if (usage == IRUsage::CLOBBERED) {
// TODO: Check HI/LO clobber together if we combine.
bool canClobber = true;
if (canClobber) {
*clobbered = true;
return reg;
}
}
return reg;
// Not awesome. A used reg. Let's try to avoid spilling.
if (!unusedOnly || usage == IRUsage::UNUSED) {
// TODO: Use age or something to choose which register to spill?
// TODO: Spill dirty regs first? or opposite?
return reg;
}
}
return INVALID_REG;

View file

@ -19,6 +19,7 @@
#include "Common/RiscVEmitter.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/IR/IRJit.h"
namespace RiscVJitConstants {
@ -101,8 +102,10 @@ public:
~RiscVRegCache() {}
void Init(RiscVGen::RiscVEmitter *emitter);
// TODO: Maybe pass in IR block and start PC for logging/debugging?
void Start();
void Start(MIPSComp::IRBlock *irBlock);
void SetIRIndex(int index) {
irIndex_ = index;
}
// Protect the arm register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
@ -176,6 +179,8 @@ private:
MIPSState *mips_;
RiscVGen::RiscVEmitter *emit_ = nullptr;
MIPSComp::JitOptions *jo_;
MIPSComp::IRBlock *irBlock_ = nullptr;
int irIndex_ = 0;
enum {
NUM_RVREG = 32, // 31 actual registers, plus the zero/sp register which is not mappable.

View file

@ -20,6 +20,8 @@
#endif
#include "Common/CPUDetect.h"
#include "Core/MIPS/IR/IRInst.h"
#include "Core/MIPS/IR/IRAnalysis.h"
#include "Core/MIPS/RiscV/RiscVRegCacheFPU.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/Reporting.h"
@ -34,7 +36,7 @@ void RiscVRegCacheFPU::Init(RiscVEmitter *emitter) {
emit_ = emitter;
}
void RiscVRegCacheFPU::Start() {
void RiscVRegCacheFPU::Start(MIPSComp::IRBlock *irBlock) {
if (!initialReady_) {
SetupInitialRegs();
initialReady_ = true;
@ -43,6 +45,9 @@ void RiscVRegCacheFPU::Start() {
memcpy(ar, arInitial_, sizeof(ar));
memcpy(mr, mrInitial_, sizeof(mr));
pendingFlush_ = false;
irBlock_ = irBlock;
irIndex_ = 0;
}
void RiscVRegCacheFPU::SetupInitialRegs() {
@ -130,8 +135,6 @@ allocate:
}
// Still nothing. Let's spill a reg and goto 10.
// TODO: Use age or something to choose which register to spill?
// TODO: Spill dirty regs first? or opposite?
bool clobbered;
RiscVReg bestToSpill = FindBestToSpill(true, &clobbered);
if (bestToSpill == INVALID_REG) {
@ -160,21 +163,33 @@ RiscVReg RiscVRegCacheFPU::FindBestToSpill(bool unusedOnly, bool *clobbered) {
static const int UNUSED_LOOKAHEAD_OPS = 30;
IRSituation info;
info.lookaheadCount = UNUSED_LOOKAHEAD_OPS;
info.currentIndex = irIndex_;
info.instructions = irBlock_->GetInstructions();
info.numInstructions = irBlock_->GetNumInstructions();
*clobbered = false;
for (int i = 0; i < allocCount; i++) {
RiscVReg reg = allocOrder[i];
if (ar[reg - F0].mipsReg != IRREG_INVALID && mr[ar[reg - F0].mipsReg].spillLock)
continue;
// TODO: Look for clobbering in the IRInst array with index?
// As it's in alloc-order, we know it's not static so we don't need to check for that.
IRUsage usage = IRNextFPRUsage(ar[reg - F0].mipsReg, info);
// Not awesome. A used reg. Let's try to avoid spilling.
// TODO: Actually check if we'd be spilling.
if (unusedOnly) {
continue;
// Awesome, a clobbered reg. Let's use it.
if (usage == IRUsage::CLOBBERED) {
*clobbered = true;
return reg;
}
return reg;
// Not awesome. A used reg. Let's try to avoid spilling.
if (!unusedOnly || usage == IRUsage::UNUSED) {
// TODO: Use age or something to choose which register to spill?
// TODO: Spill dirty regs first? or opposite?
return reg;
}
}
return INVALID_REG;
@ -184,8 +199,7 @@ void RiscVRegCacheFPU::MapInIn(IRRegIndex rd, IRRegIndex rs) {
SpillLock(rd, rs);
MapReg(rd);
MapReg(rs);
ReleaseSpillLock(rd);
ReleaseSpillLock(rs);
ReleaseSpillLock(rd, rs);
}
void RiscVRegCacheFPU::MapDirtyIn(IRRegIndex rd, IRRegIndex rs, bool avoidLoad) {
@ -193,8 +207,7 @@ void RiscVRegCacheFPU::MapDirtyIn(IRRegIndex rd, IRRegIndex rs, bool avoidLoad)
bool load = !avoidLoad || rd == rs;
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
MapReg(rs);
ReleaseSpillLock(rd);
ReleaseSpillLock(rs);
ReleaseSpillLock(rd, rs);
}
void RiscVRegCacheFPU::MapDirtyInIn(IRRegIndex rd, IRRegIndex rs, IRRegIndex rt, bool avoidLoad) {
@ -203,9 +216,17 @@ void RiscVRegCacheFPU::MapDirtyInIn(IRRegIndex rd, IRRegIndex rs, IRRegIndex rt,
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
MapReg(rt);
MapReg(rs);
ReleaseSpillLock(rd);
ReleaseSpillLock(rs);
ReleaseSpillLock(rt);
ReleaseSpillLock(rd, rs, rt);
}
RiscVReg RiscVRegCacheFPU::MapDirtyInTemp(IRRegIndex rd, IRRegIndex rs, bool avoidLoad) {
SpillLock(rd, rs);
bool load = !avoidLoad || rd == rs;
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
MapReg(rs);
RiscVReg temp = AllocateReg();
ReleaseSpillLock(rd, rs);
return temp;
}
void RiscVRegCacheFPU::Map4DirtyIn(IRRegIndex rdbase, IRRegIndex rsbase, bool avoidLoad) {

View file

@ -46,8 +46,10 @@ public:
~RiscVRegCacheFPU() {}
void Init(RiscVGen::RiscVEmitter *emitter);
// TODO: Maybe pass in IR block and start PC for logging/debugging?
void Start();
void Start(MIPSComp::IRBlock *irBlock);
void SetIRIndex(int index) {
irIndex_ = index;
}
// Protect the RISC-V register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
@ -64,6 +66,7 @@ public:
void MapInIn(IRRegIndex rd, IRRegIndex rs);
void MapDirtyIn(IRRegIndex rd, IRRegIndex rs, bool avoidLoad = true);
void MapDirtyInIn(IRRegIndex rd, IRRegIndex rs, IRRegIndex rt, bool avoidLoad = true);
RiscVGen::RiscVReg MapDirtyInTemp(IRRegIndex rd, IRRegIndex rs, bool avoidLoad = true);
void Map4DirtyIn(IRRegIndex rdbase, IRRegIndex rsbase, bool avoidLoad = true);
void Map4DirtyInIn(IRRegIndex rdbase, IRRegIndex rsbase, IRRegIndex rtbase, bool avoidLoad = true);
void FlushBeforeCall();
@ -88,6 +91,8 @@ private:
MIPSState *mips_;
RiscVGen::RiscVEmitter *emit_ = nullptr;
MIPSComp::JitOptions *jo_;
MIPSComp::IRBlock *irBlock_ = nullptr;
int irIndex_ = 0;
enum {
// On RiscV, each of the 32 registers are full 128-bit. No sharing of components!

View file

@ -302,6 +302,7 @@
<ClInclude Include="..\..\Core\MIPS\IR\IRInst.h" />
<ClInclude Include="..\..\Core\MIPS\IR\IRInterpreter.h" />
<ClInclude Include="..\..\Core\MIPS\IR\IRJit.h" />
<ClInclude Include="..\..\Core\MIPS\IR\IRAnalysis.h" />
<ClInclude Include="..\..\Core\MIPS\IR\IRPassSimplify.h" />
<ClInclude Include="..\..\Core\MIPS\IR\IRRegCache.h" />
<ClInclude Include="..\..\Core\MIPS\JitCommon\JitBlockCache.h" />
@ -561,6 +562,7 @@
<ClCompile Include="..\..\Core\MIPS\IR\IRInst.cpp" />
<ClCompile Include="..\..\Core\MIPS\IR\IRInterpreter.cpp" />
<ClCompile Include="..\..\Core\MIPS\IR\IRJit.cpp" />
<ClCompile Include="..\..\Core\MIPS\IR\IRAnalysis.cpp" />
<ClCompile Include="..\..\Core\MIPS\IR\IRPassSimplify.cpp" />
<ClCompile Include="..\..\Core\MIPS\IR\IRRegCache.cpp" />
<ClCompile Include="..\..\Core\MIPS\JitCommon\JitBlockCache.cpp" />

View file

@ -645,6 +645,9 @@
<ClCompile Include="..\..\Core\MIPS\IR\IRJit.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\MIPS\IR\IRAnalysis.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\MIPS\IR\IRPassSimplify.cpp">
<Filter>MIPS\IR</Filter>
</ClCompile>
@ -1667,6 +1670,9 @@
<ClInclude Include="..\..\Core\MIPS\IR\IRJit.h">
<Filter>MIPS\IR</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\MIPS\IR\IRAnalysis.h">
<Filter>MIPS\IR</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\MIPS\IR\IRPassSimplify.h">
<Filter>MIPS\IR</Filter>
</ClInclude>

View file

@ -390,6 +390,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/MIPS/MIPSVFPUFallbacks.cpp.arm \
$(SRC)/Core/MIPS/MIPSCodeUtils.cpp.arm \
$(SRC)/Core/MIPS/MIPSDebugInterface.cpp \
$(SRC)/Core/MIPS/IR/IRAnalysis.cpp \
$(SRC)/Core/MIPS/IR/IRFrontend.cpp \
$(SRC)/Core/MIPS/IR/IRJit.cpp \
$(SRC)/Core/MIPS/IR/IRCompALU.cpp \

View file

@ -671,6 +671,7 @@ SOURCES_CXX += \
$(COREDIR)/MIPS/JitCommon/JitCommon.cpp \
$(COREDIR)/MIPS/JitCommon/JitState.cpp \
$(COREDIR)/MIPS/JitCommon/JitBlockCache.cpp \
$(COREDIR)/MIPS/IR/IRAnalysis.cpp \
$(COREDIR)/MIPS/IR/IRCompALU.cpp \
$(COREDIR)/MIPS/IR/IRCompBranch.cpp \
$(COREDIR)/MIPS/IR/IRCompFPU.cpp \