PPCRec: Code cleanup

This commit is contained in:
Exzap 2024-10-27 14:49:24 +01:00
parent 126a682143
commit f309d5d8a8
10 changed files with 188 additions and 523 deletions

View File

@ -172,18 +172,6 @@ void* ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t* hCPU, uint32 hleFun
return PPCInterpreter_getCurrentInstance();
}
void ATTR_MS_ABI PPCRecompiler_getTBL(PPCInterpreter_t* hCPU, uint32 gprIndex)
{
uint64 coreTime = coreinit::coreinit_getTimerTick();
hCPU->gpr[gprIndex] = (uint32)(coreTime&0xFFFFFFFF);
}
void ATTR_MS_ABI PPCRecompiler_getTBU(PPCInterpreter_t* hCPU, uint32 gprIndex)
{
uint64 coreTime = coreinit::coreinit_getTimerTick();
hCPU->gpr[gprIndex] = (uint32)((coreTime>>32)&0xFFFFFFFF);
}
bool PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)
{
if (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG)
@ -340,43 +328,6 @@ bool PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction,
x64Gen_jmp_memReg64(x64GenContext, X86_REG_RAX, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));
return true;
}
else if( imlInstruction->operation == PPCREC_IML_MACRO_MFTB )
{
// according to MS ABI the caller needs to save:
// RAX, RCX, RDX, R8, R9, R10, R11
uint32 ppcAddress = imlInstruction->op_macro.param;
uint32 sprId = imlInstruction->op_macro.param2&0xFFFF;
uint32 gprIndex = (imlInstruction->op_macro.param2>>16)&0x1F;
// update instruction pointer
x64Gen_mov_mem32Reg64_imm32(x64GenContext, X86_REG_RSP, offsetof(PPCInterpreter_t, instructionPointer), ppcAddress);
// set parameters
x64Gen_mov_reg64_reg64(x64GenContext, X86_REG_RCX, X86_REG_RSP);
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RDX, gprIndex);
// restore stackpointer to original RSP
x64Emit_mov_reg64_mem64(x64GenContext, X86_REG_RSP, REG_RESV_HCPU, offsetof(PPCInterpreter_t, rspTemp));
// push hCPU on stack
x64Gen_push_reg64(x64GenContext, X86_REG_RCX);
// reserve space on stack for call parameters
x64Gen_sub_reg64_imm32(x64GenContext, X86_REG_RSP, 8*11 + 8);
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RBP, 0);
// call function
if( sprId == SPR_TBL )
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RAX, (uint64)PPCRecompiler_getTBL);
else if( sprId == SPR_TBU )
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RAX, (uint64)PPCRecompiler_getTBU);
else
assert_dbg();
x64Gen_call_reg64(x64GenContext, X86_REG_RAX);
// restore hCPU from stack
x64Gen_add_reg64_imm32(x64GenContext, X86_REG_RSP, 8 * 11 + 8);
x64Gen_pop_reg64(x64GenContext, X86_REG_RSP);
// MOV R15, ppcRecompilerInstanceData
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_R15, (uint64)ppcRecompilerInstanceData);
// MOV R13, memory_base
x64Gen_mov_reg64_imm64(x64GenContext, X86_REG_R13, (uint64)memory_base);
return true;
}
else
{
debug_printf("Unknown recompiler macro operation %d\n", imlInstruction->operation);

View File

@ -97,23 +97,23 @@ void IMLDebug_PrintLivenessRangeInfo(StringBuf& currentLineText, IMLSegment* iml
raLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;
while (subrangeItr)
{
if (subrangeItr->interval2.start.GetInstructionIndexEx() == offset)
if (subrangeItr->interval.start.GetInstructionIndexEx() == offset)
{
if(subrangeItr->interval2.start.IsInstructionIndex() && !subrangeItr->interval2.start.IsOnInputEdge())
if(subrangeItr->interval.start.IsInstructionIndex() && !subrangeItr->interval.start.IsOnInputEdge())
currentLineText.add(".");
else
currentLineText.add("|");
currentLineText.addFmt("{:<4}", subrangeItr->GetVirtualRegister());
}
else if (subrangeItr->interval2.end.GetInstructionIndexEx() == offset)
else if (subrangeItr->interval.end.GetInstructionIndexEx() == offset)
{
if(subrangeItr->interval2.end.IsInstructionIndex() && !subrangeItr->interval2.end.IsOnOutputEdge())
if(subrangeItr->interval.end.IsInstructionIndex() && !subrangeItr->interval.end.IsOnOutputEdge())
currentLineText.add("* ");
else
currentLineText.add("| ");
}
else if (subrangeItr->interval2.ContainsInstructionIndexEx(offset))
else if (subrangeItr->interval.ContainsInstructionIndexEx(offset))
{
currentLineText.add("| ");
}
@ -374,10 +374,6 @@ void IMLDebug_DisassembleInstruction(const IMLInstruction& inst, std::string& di
{
strOutput.addFmt("MACRO HLE ppcAddr: 0x{:08x} funcId: 0x{:08x}", inst.op_macro.param, inst.op_macro.param2);
}
else if (inst.operation == PPCREC_IML_MACRO_MFTB)
{
strOutput.addFmt("MACRO MFTB ppcAddr: 0x{:08x} sprId: 0x{:08x}", inst.op_macro.param, inst.op_macro.param2);
}
else if (inst.operation == PPCREC_IML_MACRO_COUNT_CYCLES)
{
strOutput.addFmt("MACRO COUNT_CYCLES cycles: {}", inst.op_macro.param);

View File

@ -4,6 +4,7 @@
#include "../PPCRecompiler.h"
#include "../PPCRecompilerIml.h"
// return true if an instruction has side effects on top of just reading and writing registers
bool IMLInstruction::HasSideEffects() const
{
bool hasSideEffects = true;
@ -160,7 +161,7 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_COUNT_CYCLES || operation == PPCREC_IML_MACRO_HLE || operation == PPCREC_IML_MACRO_MFTB)
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_COUNT_CYCLES || operation == PPCREC_IML_MACRO_HLE)
{
// no effect on registers
}
@ -482,15 +483,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
}
}
//#define replaceRegister(__x,__r,__n) (((__x)==(__r))?(__n):(__x))
IMLReg replaceRegisterId(IMLReg reg, IMLRegID oldId, IMLRegID newId)
{
if (reg.GetRegID() != oldId)
return reg;
reg.SetRegID(newId);
return reg;
}
IMLReg replaceRegisterIdMultiple(IMLReg reg, const std::unordered_map<IMLRegID, IMLRegID>& translationTable)
{
if (reg.IsInvalid())
@ -502,26 +494,6 @@ IMLReg replaceRegisterIdMultiple(IMLReg reg, const std::unordered_map<IMLRegID,
return alteredReg;
}
IMLReg replaceRegisterIdMultiple(IMLReg reg, IMLReg match[4], IMLReg replaced[4])
{
// deprecated but still used for FPRs
for (sint32 i = 0; i < 4; i++)
{
if (match[i].IsInvalid())
continue;
if (reg.GetRegID() == match[i].GetRegID())
{
cemu_assert_debug(reg.GetBaseFormat() == match[i].GetBaseFormat());
cemu_assert_debug(reg.GetRegFormat() == match[i].GetRegFormat());
cemu_assert_debug(reg.GetBaseFormat() == replaced[i].GetBaseFormat());
cemu_assert_debug(reg.GetRegFormat() == replaced[i].GetRegFormat());
return replaced[i];
}
}
return reg;
}
void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable)
{
if (type == PPCREC_IML_TYPE_R_NAME)
@ -594,7 +566,7 @@ void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& tr
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_HLE || operation == PPCREC_IML_MACRO_MFTB || operation == PPCREC_IML_MACRO_COUNT_CYCLES)
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_HLE || operation == PPCREC_IML_MACRO_COUNT_CYCLES)
{
// no effect on registers
}
@ -717,228 +689,3 @@ void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& tr
cemu_assert_unimplemented();
}
}
void IMLInstruction::ReplaceFPRs(IMLReg fprRegisterSearched[4], IMLReg fprRegisterReplaced[4])
{
if (type == PPCREC_IML_TYPE_R_NAME)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_NAME_R)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_S32)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R_S32)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R_R)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_COMPARE || type == PPCREC_IML_TYPE_COMPARE_S32 || type == PPCREC_IML_TYPE_CONDITIONAL_JUMP || type == PPCREC_IML_TYPE_JUMP)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_NO_OP)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_LOAD)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_LOAD_INDEXED)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_STORE)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_STORE_INDEXED)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)
{
;
}
else if (type == PPCREC_IML_TYPE_CALL_IMM)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_STORE)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R)
{
op_fpr_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R_R)
{
op_fpr_r_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r.regB = replaceRegisterIdMultiple(op_fpr_r_r_r.regB, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R_R_R)
{
op_fpr_r_r_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regB = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regB, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regC = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regC, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R)
{
op_fpr_r.regR = replaceRegisterIdMultiple(op_fpr_r.regR, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_COMPARE)
{
op_fpr_compare.regA = replaceRegisterIdMultiple(op_fpr_compare.regA, fprRegisterSearched, fprRegisterReplaced);
op_fpr_compare.regB = replaceRegisterIdMultiple(op_fpr_compare.regB, fprRegisterSearched, fprRegisterReplaced);
}
else
{
cemu_assert_unimplemented();
}
}
void IMLInstruction::ReplaceFPR(IMLRegID fprRegisterSearched, IMLRegID fprRegisterReplaced)
{
if (type == PPCREC_IML_TYPE_R_NAME)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_NAME_R)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_S32)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R_S32 || type == PPCREC_IML_TYPE_R_R_S32_CARRY)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_R_R_R || type == PPCREC_IML_TYPE_R_R_R_CARRY)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_COMPARE || type == PPCREC_IML_TYPE_COMPARE_S32 || type == PPCREC_IML_TYPE_CONDITIONAL_JUMP || type == PPCREC_IML_TYPE_JUMP)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_NO_OP)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_LOAD)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_LOAD_INDEXED)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_STORE)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_STORE_INDEXED)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_CALL_IMM)
{
// not affected
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
op_storeLoad.registerData = replaceRegisterId(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)
{
op_storeLoad.registerData = replaceRegisterId(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_STORE)
{
op_storeLoad.registerData = replaceRegisterId(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)
{
op_storeLoad.registerData = replaceRegisterId(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R)
{
op_fpr_r_r.regR = replaceRegisterId(op_fpr_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r.regA = replaceRegisterId(op_fpr_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R_R)
{
op_fpr_r_r_r.regR = replaceRegisterId(op_fpr_r_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r.regA = replaceRegisterId(op_fpr_r_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r.regB = replaceRegisterId(op_fpr_r_r_r.regB, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R_R_R_R)
{
op_fpr_r_r_r_r.regR = replaceRegisterId(op_fpr_r_r_r_r.regR, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regA = replaceRegisterId(op_fpr_r_r_r_r.regA, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regB = replaceRegisterId(op_fpr_r_r_r_r.regB, fprRegisterSearched, fprRegisterReplaced);
op_fpr_r_r_r_r.regC = replaceRegisterId(op_fpr_r_r_r_r.regC, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_R)
{
op_fpr_r.regR = replaceRegisterId(op_fpr_r.regR, fprRegisterSearched, fprRegisterReplaced);
}
else
{
cemu_assert_unimplemented();
}
}

View File

@ -197,7 +197,6 @@ enum
PPCREC_IML_MACRO_B_FAR, // branch to different function
PPCREC_IML_MACRO_COUNT_CYCLES, // decrease current remaining thread cycles by a certain amount
PPCREC_IML_MACRO_HLE, // HLE function call
PPCREC_IML_MACRO_MFTB, // get TB register value (low or high)
PPCREC_IML_MACRO_LEAVE, // leaves recompiler and switches to interpeter
// debugging
PPCREC_IML_MACRO_DEBUGBREAK, // throws a debugbreak
@ -335,19 +334,6 @@ struct IMLUsedRegisters
{
IMLUsedRegisters() {};
union
{
struct
{
IMLReg readGPR1;
IMLReg readGPR2;
IMLReg readGPR3;
IMLReg readGPR4;
IMLReg writtenGPR1;
IMLReg writtenGPR2;
};
};
bool IsWrittenByRegId(IMLRegID regId) const
{
if (writtenGPR1.IsValid() && writtenGPR1.GetRegID() == regId)
@ -404,6 +390,12 @@ struct IMLUsedRegisters
F(writtenGPR2, true);
}
IMLReg readGPR1;
IMLReg readGPR2;
IMLReg readGPR3;
IMLReg readGPR4;
IMLReg writtenGPR1;
IMLReg writtenGPR2;
};
struct IMLInstruction
@ -575,7 +567,6 @@ struct IMLInstruction
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_B_TO_REG ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_LEAVE ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_HLE ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_MFTB ||
type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK ||
type == PPCREC_IML_TYPE_JUMP ||
type == PPCREC_IML_TYPE_CONDITIONAL_JUMP ||
@ -788,9 +779,6 @@ struct IMLInstruction
bool HasSideEffects() const; // returns true if the instruction has side effects beyond just reading and writing registers. Dead code elimination uses this to know if an instruction can be dropped when the regular register outputs are not used
void RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable);
void ReplaceFPRs(IMLReg fprRegisterSearched[4], IMLReg fprRegisterReplaced[4]);
void ReplaceFPR(IMLRegID fprRegisterSearched, IMLRegID fprRegisterReplaced);
};
// architecture specific constants

View File

@ -192,7 +192,7 @@ static void GetInstructionFixedRegisters(IMLInstruction* instruction, IMLFixedRe
}
#endif
uint32 PPCRecRA_getNextIterationIndex()
uint32 IMLRA_GetNextIterationIndex()
{
static uint32 recRACurrentIterationIndex = 0;
recRACurrentIterationIndex++;
@ -231,9 +231,9 @@ bool _detectLoop(IMLSegment* currentSegment, sint32 depth, uint32 iterationIndex
return currentSegment->raInfo.isPartOfProcessedLoop;
}
void PPCRecRA_detectLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegmentLoopBase)
void IMLRA_DetectLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegmentLoopBase)
{
uint32 iterationIndex = PPCRecRA_getNextIterationIndex();
uint32 iterationIndex = IMLRA_GetNextIterationIndex();
imlSegmentLoopBase->raInfo.lastIterationIndex = iterationIndex;
if (_detectLoop(imlSegmentLoopBase->nextSegmentBranchTaken, 0, iterationIndex, imlSegmentLoopBase))
{
@ -241,7 +241,7 @@ void PPCRecRA_detectLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSe
}
}
void PPCRecRA_identifyLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)
void IMLRA_IdentifyLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)
{
if (imlSegment->nextSegmentIsUncertain)
return;
@ -255,13 +255,13 @@ void PPCRecRA_identifyLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* iml
// check if this segment has a branch that goes backwards (potential complex loop)
if (imlSegment->nextSegmentBranchTaken && imlSegment->nextSegmentBranchTaken->momentaryIndex < imlSegment->momentaryIndex)
{
PPCRecRA_detectLoop(ppcImlGenContext, imlSegment);
IMLRA_DetectLoop(ppcImlGenContext, imlSegment);
}
}
#define SUBRANGE_LIST_SIZE (128)
sint32 PPCRecRA_countDistanceUntilNextUse2(raLivenessRange* subrange, raInstructionEdge startPosition)
sint32 IMLRA_CountDistanceUntilNextUse(raLivenessRange* subrange, raInstructionEdge startPosition)
{
for (sint32 i = 0; i < subrange->list_accessLocations.size(); i++)
{
@ -292,8 +292,8 @@ sint32 IMLRA_CountDistanceUntilFixedRegUsageInRange(IMLSegment* imlSegment, raLi
return fixedReqEntry.pos.GetRaw() - startPosition.GetRaw();
}
}
cemu_assert_debug(range->interval2.end.IsInstructionIndex());
return range->interval2.end.GetRaw() - startPosition.GetRaw();
cemu_assert_debug(range->interval.end.IsInstructionIndex());
return range->interval.end.GetRaw() - startPosition.GetRaw();
}
sint32 IMLRA_CountDistanceUntilFixedRegUsage(IMLSegment* imlSegment, raInstructionEdge startPosition, sint32 maxDistance, IMLRegID ourRegId, sint32 physRegister)
@ -343,15 +343,15 @@ sint32 PPCRecRA_countDistanceUntilNextLocalPhysRegisterUse(IMLSegment* imlSegmen
subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue;
}
if (subrangeItr->interval2.ContainsEdge(startPosition))
if (subrangeItr->interval.ContainsEdge(startPosition))
return 0;
if (subrangeItr->interval2.end < startPosition)
if (subrangeItr->interval.end < startPosition)
{
subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue;
}
cemu_assert_debug(startPosition <= subrangeItr->interval2.start);
sint32 currentDist = subrangeItr->interval2.start.GetRaw() - startPosition.GetRaw();
cemu_assert_debug(startPosition <= subrangeItr->interval.start);
sint32 currentDist = subrangeItr->interval.start.GetRaw() - startPosition.GetRaw();
minDistance = std::min(minDistance, currentDist);
subrangeItr = subrangeItr->link_allSegmentRanges.next;
}
@ -377,7 +377,7 @@ struct IMLRALivenessTimeline
for (size_t f = 0; f < count; f++)
{
raLivenessRange* liverange = activeRanges[f];
if (liverange->interval2.end < expireUpTo) // this was <= but since end is not inclusive we need to use <
if (liverange->interval.end < expireUpTo) // this was <= but since end is not inclusive we need to use <
{
#ifdef CEMU_DEBUG_ASSERT
if (!expireUpTo.ConnectsToNextSegment() && (liverange->subrangeBranchTaken || liverange->subrangeBranchNotTaken))
@ -443,7 +443,7 @@ void PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange* range2, IMLP
subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue;
}
if (subrange->interval2.IsOverlapping(subrangeItr->interval2))
if (subrange->interval.IsOverlapping(subrangeItr->interval))
{
if (subrangeItr->GetPhysicalRegister() >= 0)
physRegSet.SetReserved(subrangeItr->GetPhysicalRegister());
@ -456,7 +456,7 @@ void PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange* range2, IMLP
bool _livenessRangeStartCompare(raLivenessRange* lhs, raLivenessRange* rhs)
{
return lhs->interval2.start < rhs->interval2.start;
return lhs->interval.start < rhs->interval.start;
}
void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)
@ -467,8 +467,7 @@ void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)
raLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;
while (subrangeItr)
{
if (count >= 4096)
assert_dbg();
cemu_assert(count < 4096);
subrangeList[count] = subrangeItr;
count++;
// next
@ -526,6 +525,9 @@ raLivenessRange* IMLRA_GetSubrange(IMLSegment* imlSegment, IMLRegID regId)
struct raFixedRegRequirementWithVGPR
{
raFixedRegRequirementWithVGPR(raInstructionEdge pos, IMLPhysRegisterSet allowedReg, IMLRegID regId)
: pos(pos), allowedReg(allowedReg), regId(regId) {}
raInstructionEdge pos;
IMLPhysRegisterSet allowedReg;
IMLRegID regId;
@ -560,7 +562,7 @@ boost::container::small_vector<raLivenessRange*, 8> IMLRA_GetRangeWithFixedRegRe
boost::container::small_vector<raLivenessRange*, 8> rangeList;
for (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)
{
if (!currentRange->interval2.ContainsEdge(pos))
if (!currentRange->interval.ContainsEdge(pos))
continue;
IMLPhysRegisterSet allowedRegs;
if (!currentRange->GetAllowedRegistersEx(allowedRegs))
@ -574,7 +576,7 @@ boost::container::small_vector<raLivenessRange*, 8> IMLRA_GetRangeWithFixedRegRe
void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)
{
// first pass - iterate over all ranges with fixed register requirements and split them if they cross the segment border
// todo - this pass currently creates suboptimal results by splitting all ranges that cross the segment border if they have any fixed register requirement. This isn't always necessary
// todo - this pass currently creates suboptimal results by splitting all ranges that cross the segment border if they have any fixed register requirement. This can be avoided in some cases
for (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange;)
{
IMLPhysRegisterSet allowedRegs;
@ -588,10 +590,10 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment
currentRange = currentRange->link_allSegmentRanges.next;
continue;
}
if (currentRange->interval2.ExtendsPreviousSegment() || currentRange->interval2.ExtendsIntoNextSegment())
if (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())
{
raLivenessRange* nextRange = currentRange->link_allSegmentRanges.next;
PPCRecRA_explodeRange(ppcImlGenContext, currentRange);
IMLRA_ExplodeRangeCluster(ppcImlGenContext, currentRange);
currentRange = nextRange;
continue;
}
@ -638,9 +640,9 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment
for (auto& range : overlappingRanges)
{
if (range->interval2.start < entry.pos)
if (range->interval.start < entry.pos)
{
PPCRecRA_splitLocalSubrange2(ppcImlGenContext, range, entry.pos, true);
IMLRA_SplitRange(ppcImlGenContext, range, entry.pos, true);
}
}
}
@ -704,7 +706,7 @@ void IMLRA_MakeSafeSplitDistance(IMLSegment* imlSegment, raInstructionEdge start
distance = endPos.GetRaw() - startPos.GetRaw();
}
void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx);
static void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx);
class RASpillStrategy
{
@ -737,8 +739,8 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
void Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)
{
raInstructionEdge currentRangeStart = currentRange->interval2.start;
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance();
raInstructionEdge currentRangeStart = currentRange->interval.start;
sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
cemu_assert_debug(localRangeHoleCutting.distance == -1);
cemu_assert_debug(strategyCost == INT_MAX);
if (!currentRangeStart.ConnectsToPreviousSegment())
@ -746,7 +748,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
cemu_assert_debug(currentRangeStart.GetRaw() >= 0);
for (auto candidate : timeline.activeRanges)
{
if (candidate->interval2.ExtendsIntoNextSegment())
if (candidate->interval.ExtendsIntoNextSegment())
continue;
// new checks (Oct 2024):
if (candidate == currentRange)
@ -756,7 +758,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))
continue;
sint32 distance2 = PPCRecRA_countDistanceUntilNextUse2(candidate, currentRangeStart);
sint32 distance2 = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);
IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance2);
if (distance2 < 2)
continue;
@ -785,18 +787,18 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{
cemu_assert_debug(strategyCost != INT_MAX);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance();
raInstructionEdge currentRangeStart = currentRange->interval2.start;
sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
raInstructionEdge currentRangeStart = currentRange->interval.start;
raInstructionEdge holeStartPosition = currentRangeStart;
raInstructionEdge holeEndPosition = currentRangeStart + localRangeHoleCutting.distance;
raLivenessRange* collisionRange = localRangeHoleCutting.largestHoleSubrange;
if (collisionRange->interval2.start < holeStartPosition)
if (collisionRange->interval.start < holeStartPosition)
{
collisionRange = PPCRecRA_splitLocalSubrange2(nullptr, collisionRange, holeStartPosition, true);
cemu_assert_debug(!collisionRange || collisionRange->interval2.start >= holeStartPosition); // verify if splitting worked at all, tail must be on or after the split point
cemu_assert_debug(!collisionRange || collisionRange->interval2.start >= holeEndPosition); // also verify that the trimmed hole is actually big enough
collisionRange = IMLRA_SplitRange(nullptr, collisionRange, holeStartPosition, true);
cemu_assert_debug(!collisionRange || collisionRange->interval.start >= holeStartPosition); // verify if splitting worked at all, tail must be on or after the split point
cemu_assert_debug(!collisionRange || collisionRange->interval.start >= holeEndPosition); // also verify that the trimmed hole is actually big enough
}
else
{
@ -805,7 +807,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
// we may also have to cut the current range to fit partially into the hole
if (requiredSize2 > localRangeHoleCutting.distance)
{
raLivenessRange* tailRange = PPCRecRA_splitLocalSubrange2(nullptr, currentRange, currentRangeStart + localRangeHoleCutting.distance, true);
raLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + localRangeHoleCutting.distance, true);
if (tailRange)
{
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers
@ -815,7 +817,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
// verify that the hole is large enough
if (collisionRange)
{
cemu_assert_debug(!collisionRange->interval2.IsOverlapping(currentRange->interval2));
cemu_assert_debug(!collisionRange->interval.IsOverlapping(currentRange->interval));
}
}
@ -840,9 +842,9 @@ class RASpillStrategy_AvailableRegisterHole : public RASpillStrategy
void Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& localAvailableRegsMask, const IMLPhysRegisterSet& allowedRegs)
{
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance();
sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
raInstructionEdge currentRangeStart = currentRange->interval2.start;
raInstructionEdge currentRangeStart = currentRange->interval.start;
cemu_assert_debug(strategyCost == INT_MAX);
availableRegisterHole.distance = -1;
availableRegisterHole.physRegister = -1;
@ -888,9 +890,9 @@ class RASpillStrategy_AvailableRegisterHole : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{
cemu_assert_debug(strategyCost != INT_MAX);
raInstructionEdge currentRangeStart = currentRange->interval2.start;
raInstructionEdge currentRangeStart = currentRange->interval.start;
// use available register
raLivenessRange* tailRange = PPCRecRA_splitLocalSubrange2(nullptr, currentRange, currentRangeStart + availableRegisterHole.distance, true);
raLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + availableRegisterHole.distance, true);
if (tailRange)
{
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers
@ -918,16 +920,16 @@ class RASpillStrategy_ExplodeRange : public RASpillStrategy
void Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)
{
raInstructionEdge currentRangeStart = currentRange->interval2.start;
raInstructionEdge currentRangeStart = currentRange->interval.start;
if (currentRangeStart.ConnectsToPreviousSegment())
currentRangeStart.Set(0, true);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance();
sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
cemu_assert_debug(strategyCost == INT_MAX);
explodeRange.range = nullptr;
explodeRange.distance = -1;
for (auto candidate : timeline.activeRanges)
{
if (!candidate->interval2.ExtendsIntoNextSegment())
if (!candidate->interval.ExtendsIntoNextSegment())
continue;
// new checks (Oct 2024):
if (candidate == currentRange)
@ -937,7 +939,7 @@ class RASpillStrategy_ExplodeRange : public RASpillStrategy
if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))
continue;
sint32 distance = PPCRecRA_countDistanceUntilNextUse2(candidate, currentRangeStart);
sint32 distance = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);
IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance);
if (distance < 2)
continue;
@ -961,16 +963,16 @@ class RASpillStrategy_ExplodeRange : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{
raInstructionEdge currentRangeStart = currentRange->interval2.start;
raInstructionEdge currentRangeStart = currentRange->interval.start;
if (currentRangeStart.ConnectsToPreviousSegment())
currentRangeStart.Set(0, true);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance();
sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
// explode range
PPCRecRA_explodeRange(nullptr, explodeRange.range);
IMLRA_ExplodeRangeCluster(nullptr, explodeRange.range);
// split current subrange if necessary
if (requiredSize2 > explodeRange.distance)
{
raLivenessRange* tailRange = PPCRecRA_splitLocalSubrange2(nullptr, currentRange, currentRangeStart + explodeRange.distance, true);
raLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + explodeRange.distance, true);
if (tailRange)
{
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers
@ -1005,7 +1007,7 @@ class RASpillStrategy_ExplodeRangeInter : public RASpillStrategy
cemu_assert_debug(explodeRange.range == nullptr && explodeRange.distance == -1);
for (auto candidate : timeline.activeRanges)
{
if (!candidate->interval2.ExtendsIntoNextSegment())
if (!candidate->interval.ExtendsIntoNextSegment())
continue;
// only select candidates that clash with current subrange
if (candidate->GetPhysicalRegister() < 0 && candidate != currentRange)
@ -1037,7 +1039,7 @@ class RASpillStrategy_ExplodeRangeInter : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{
cemu_assert_debug(strategyCost != INT_MAX);
PPCRecRA_explodeRange(ctx, explodeRange.range);
IMLRA_ExplodeRangeCluster(ctx, explodeRange.range);
}
private:
@ -1056,16 +1058,16 @@ void IMLRA_FilterReservedFixedRegisterRequirementsForSegment(IMLRegisterAllocato
if (seg->imlList.empty())
return; // there can be no fixed register requirements if there are no instructions
raInstructionEdge firstPos = currentRange->interval2.start;
if (currentRange->interval2.start.ConnectsToPreviousSegment())
raInstructionEdge firstPos = currentRange->interval.start;
if (currentRange->interval.start.ConnectsToPreviousSegment())
firstPos.SetRaw(0);
else if (currentRange->interval2.start.ConnectsToNextSegment())
else if (currentRange->interval.start.ConnectsToNextSegment())
firstPos.Set(seg->imlList.size() - 1, false);
raInstructionEdge lastPos = currentRange->interval2.end;
if (currentRange->interval2.end.ConnectsToPreviousSegment())
raInstructionEdge lastPos = currentRange->interval.end;
if (currentRange->interval.end.ConnectsToPreviousSegment())
lastPos.SetRaw(0);
else if (currentRange->interval2.end.ConnectsToNextSegment())
else if (currentRange->interval.end.ConnectsToNextSegment())
lastPos.Set(seg->imlList.size() - 1, false);
cemu_assert_debug(firstPos <= lastPos);
@ -1093,7 +1095,7 @@ void IMLRA_FilterReservedFixedRegisterRequirementsForSegment(IMLRegisterAllocato
void IMLRA_FilterReservedFixedRegisterRequirementsForCluster(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, raLivenessRange* currentRange, IMLPhysRegisterSet& candidatePhysRegSet)
{
cemu_assert_debug(currentRange->imlSegment == imlSegment);
if (currentRange->interval2.ExtendsPreviousSegment() || currentRange->interval2.ExtendsIntoNextSegment())
if (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())
{
auto clusterRanges = currentRange->GetAllSubrangesInCluster();
for (auto& rangeIt : clusterRanges)
@ -1128,7 +1130,7 @@ bool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenCon
while (subrangeItr)
{
raInstructionEdge currentRangeStart = subrangeItr->interval2.start; // used to be currentIndex before refactor
raInstructionEdge currentRangeStart = subrangeItr->interval.start; // used to be currentIndex before refactor
PPCRecRA_debugValidateSubrange(subrangeItr);
livenessTimeline.ExpireRanges((currentRangeStart > lastInstructionEdge) ? lastInstructionEdge : currentRangeStart); // expire up to currentIndex (inclusive), but exclude infinite ranges
@ -1204,7 +1206,7 @@ bool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenCon
selectedStrategy = &newStrategy;
};
if (!subrangeItr->interval2.ExtendsIntoNextSegment())
if (!subrangeItr->interval.ExtendsIntoNextSegment())
{
// range ends in current segment, use local strategies
// evaluate strategy: Cut hole into local subrange
@ -1232,9 +1234,9 @@ bool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenCon
else
{
// none of the evulated strategies can be applied, this should only happen if the segment extends into the next segment(s) for which we have no good strategy
cemu_assert_debug(subrangeItr->interval2.ExtendsPreviousSegment());
cemu_assert_debug(subrangeItr->interval.ExtendsPreviousSegment());
// alternative strategy if we have no other choice: explode current range
PPCRecRA_explodeRange(ppcImlGenContext, subrangeItr);
IMLRA_ExplodeRangeCluster(ppcImlGenContext, subrangeItr);
}
return false;
}
@ -1336,7 +1338,7 @@ void IMLRA_ReshapeForRegisterAllocation(ppcImlGenContext_t* ppcImlGenContext)
for (size_t s = 0; s < ppcImlGenContext->segmentList2.size(); s++)
{
IMLSegment* imlSegment = ppcImlGenContext->segmentList2[s];
PPCRecRA_identifyLoop(ppcImlGenContext, imlSegment);
IMLRA_IdentifyLoop(ppcImlGenContext, imlSegment);
}
}
@ -1411,7 +1413,7 @@ raLivenessRange* PPCRecRA_convertToMappedRanges(IMLRegisterAllocatorContext& ctx
inclusiveEnd--; // subtract one, because usageEnd is exclusive, but the end value of the interval passed to createSubrange is inclusive
raInterval interval;
interval.SetInterval(abstractRange->usageStart, true, inclusiveEnd, true);
raLivenessRange* subrange = PPCRecRA_createSubrange2(ctx.deprGenContext, imlSegment, vGPR, name, interval.start, interval.end);
raLivenessRange* subrange = IMLRA_CreateRange(ctx.deprGenContext, imlSegment, vGPR, name, interval.start, interval.end);
// traverse forward
if (abstractRange->usageEnd == RA_INTER_RANGE_END)
{
@ -1422,7 +1424,7 @@ raLivenessRange* PPCRecRA_convertToMappedRanges(IMLRegisterAllocatorContext& ctx
{
subrange->subrangeBranchTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchTaken, vGPR, name);
subrange->subrangeBranchTaken->previousRanges.push_back(subrange);
cemu_assert_debug(subrange->subrangeBranchTaken->interval2.ExtendsPreviousSegment());
cemu_assert_debug(subrange->subrangeBranchTaken->interval.ExtendsPreviousSegment());
}
}
if (imlSegment->nextSegmentBranchNotTaken)
@ -1432,7 +1434,7 @@ raLivenessRange* PPCRecRA_convertToMappedRanges(IMLRegisterAllocatorContext& ctx
{
subrange->subrangeBranchNotTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchNotTaken, vGPR, name);
subrange->subrangeBranchNotTaken->previousRanges.push_back(subrange);
cemu_assert_debug(subrange->subrangeBranchNotTaken->interval2.ExtendsPreviousSegment());
cemu_assert_debug(subrange->subrangeBranchNotTaken->interval.ExtendsPreviousSegment());
}
}
}
@ -1771,7 +1773,7 @@ void IMLRA_AnalyzeSubrangeDataDependency(raLivenessRange* subrange)
subrange->_noLoad = isOverwritten;
subrange->hasStore = isWritten;
if (subrange->interval2.ExtendsPreviousSegment())
if (subrange->interval.ExtendsPreviousSegment())
subrange->_noLoad = true;
}
@ -1796,7 +1798,7 @@ void _findSubrangeWriteEndings(raLivenessRange* subrange, uint32 iterationIndex,
if (subrange->hasStoreDelayed)
return; // no need to traverse this subrange
IMLSegment* imlSegment = subrange->imlSegment;
if (!subrange->interval2.ExtendsIntoNextSegment())
if (!subrange->interval.ExtendsIntoNextSegment())
{
// ending segment
if (info->subrangeCount >= SUBRANGE_LIST_SIZE)
@ -1839,7 +1841,7 @@ void _findSubrangeWriteEndings(raLivenessRange* subrange, uint32 iterationIndex,
static void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange)
{
if (!subrange->interval2.ExtendsIntoNextSegment())
if (!subrange->interval.ExtendsIntoNextSegment())
return;
// analyze data flow across segments (if this segment has writes)
if (subrange->hasStore)
@ -1847,7 +1849,7 @@ static void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange)
subrangeEndingInfo_t writeEndingInfo;
writeEndingInfo.subrangeCount = 0;
writeEndingInfo.hasUndefinedEndings = false;
_findSubrangeWriteEndings(subrange, PPCRecRA_getNextIterationIndex(), 0, &writeEndingInfo);
_findSubrangeWriteEndings(subrange, IMLRA_GetNextIterationIndex(), 0, &writeEndingInfo);
if (writeEndingInfo.hasUndefinedEndings == false)
{
// get cost of delaying store into endings
@ -1924,7 +1926,7 @@ void IMLRA_RewriteRegisters(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSeg
{
currentEdge.Set(i, false); // set to instruction index on output edge
// activate ranges which begin before or during this instruction
while (currentRange && currentRange->interval2.start <= currentEdge)
while (currentRange && currentRange->interval.start <= currentEdge)
{
cemu_assert_debug(virtId2PhysReg.find(currentRange->GetVirtualRegister()) == virtId2PhysReg.end() || virtId2PhysReg[currentRange->GetVirtualRegister()] == currentRange->GetPhysicalRegister()); // check for register conflict
@ -1938,7 +1940,7 @@ void IMLRA_RewriteRegisters(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSeg
auto it = activeRanges.begin();
while (it != activeRanges.end())
{
if ((*it)->interval2.end <= currentEdge)
if ((*it)->interval.end <= currentEdge)
{
virtId2PhysReg.erase((*it)->GetVirtualRegister());
it = activeRanges.erase(it);
@ -1981,7 +1983,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
{
if (!currentRange->_noLoad)
{
cemu_assert_debug(currentRange->interval2.ExtendsIntoNextSegment());
cemu_assert_debug(currentRange->interval.ExtendsIntoNextSegment());
rebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());
}
currentRange = currentRange->link_allSegmentRanges.next;
@ -2001,9 +2003,9 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
while (currentRange)
{
if (!currentRange->interval2.IsNextSegmentOnly() && currentRange->interval2.end > edge)
if (!currentRange->interval.IsNextSegmentOnly() && currentRange->interval.end > edge)
{
currentRange->interval2.SetEnd(edge);
currentRange->interval.SetEnd(edge);
}
currentRange = currentRange->link_allSegmentRanges.next;
}
@ -2025,9 +2027,8 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
boost::container::small_vector<raLivenessRange*, 64> activeRanges;
// first we add all the ranges that extend from the previous segment, some of these will end immediately at the first instruction so we might need to store them early
raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;
// make all ranges active that start on RA_INTER_RANGE_START
while (currentRange && currentRange->interval2.start.ConnectsToPreviousSegment())
while (currentRange && currentRange->interval.start.ConnectsToPreviousSegment())
{
activeRanges.push_back(currentRange);
currentRange = currentRange->link_allSegmentRanges.next;
@ -2038,7 +2039,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
firstOutputEdge.Set(0, false);
while (it != activeRanges.end())
{
if ((*it)->interval2.end < firstOutputEdge)
if ((*it)->interval.end < firstOutputEdge)
{
raLivenessRange* storedRange = *it;
if (storedRange->hasStore)
@ -2055,7 +2056,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
raInstructionEdge curEdge;
// input edge
curEdge.SetRaw(i * 2 + 1); // +1 to include ranges that start at the output of the instruction
while (currentRange && currentRange->interval2.start <= curEdge)
while (currentRange && currentRange->interval.start <= curEdge)
{
if (!currentRange->_noLoad)
{
@ -2072,11 +2073,9 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
auto it = activeRanges.begin();
while (it != activeRanges.end())
{
if ((*it)->interval2.end <= curEdge)
if ((*it)->interval.end <= curEdge)
{
// range expires
// we cant erase it from virtId2PhysReg right away because a store might happen before the last use (the +1 thing above)
// todo - check hasStore
raLivenessRange* storedRange = *it;
if (storedRange->hasStore)
@ -2084,7 +2083,6 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
cemu_assert_debug(i != numInstructionsWithoutSuffix); // not allowed to emit after suffix
rebuiltInstructions.emplace_back().make_name_r(storedRange->GetName(), _MakeNativeReg(ctx.regIdToBaseFormat[storedRange->GetVirtualRegister()], storedRange->GetPhysicalRegister()));
}
it = activeRanges.erase(it);
continue;
}
@ -2109,7 +2107,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
}
while (currentRange)
{
cemu_assert_debug(currentRange->interval2.IsNextSegmentOnly());
cemu_assert_debug(currentRange->interval.IsNextSegmentOnly());
cemu_assert_debug(!currentRange->_noLoad);
rebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());
currentRange = currentRange->link_allSegmentRanges.next;

View File

@ -60,10 +60,10 @@ public:
}
// returns index of first available register. Do not call when HasAnyAvailable() == false
uint32 GetFirstAvailableReg()
IMLPhysReg GetFirstAvailableReg()
{
cemu_assert_debug(m_regBitmask != 0);
uint32 regIndex = 0;
sint32 regIndex = 0;
auto tmp = m_regBitmask;
while ((tmp & 0xFF) == 0)
{
@ -80,7 +80,7 @@ public:
// returns index of next available register (search includes any register index >= startIndex)
// returns -1 if there is no more register
sint32 GetNextAvailableReg(sint32 startIndex) const
IMLPhysReg GetNextAvailableReg(sint32 startIndex) const
{
if (startIndex >= 64)
return -1;
@ -111,7 +111,6 @@ private:
uint64 m_regBitmask{ 0 };
};
struct IMLRegisterAllocatorParameters
{
inline IMLPhysRegisterSet& GetPhysRegPool(IMLRegFormat regFormat)

View File

@ -3,7 +3,7 @@
#include "IMLRegisterAllocatorRanges.h"
#include "util/helpers/MemoryPool.h"
uint32 PPCRecRA_getNextIterationIndex();
uint32 IMLRA_GetNextIterationIndex();
IMLRegID raLivenessRange::GetVirtualRegister() const
{
@ -20,12 +20,12 @@ IMLName raLivenessRange::GetName() const
return name;
}
void raLivenessRange::SetPhysicalRegister(sint32 physicalRegister)
void raLivenessRange::SetPhysicalRegister(IMLPhysReg physicalRegister)
{
this->physicalRegister = physicalRegister;
}
void raLivenessRange::SetPhysicalRegisterForCluster(sint32 physicalRegister)
void raLivenessRange::SetPhysicalRegisterForCluster(IMLPhysReg physicalRegister)
{
auto clusterRanges = GetAllSubrangesInCluster();
for(auto& range : clusterRanges)
@ -34,7 +34,7 @@ void raLivenessRange::SetPhysicalRegisterForCluster(sint32 physicalRegister)
boost::container::small_vector<raLivenessRange*, 128> raLivenessRange::GetAllSubrangesInCluster()
{
uint32 iterationIndex = PPCRecRA_getNextIterationIndex();
uint32 iterationIndex = IMLRA_GetNextIterationIndex();
boost::container::small_vector<raLivenessRange*, 128> subranges;
subranges.push_back(this);
this->lastIterationIndex = iterationIndex;
@ -87,7 +87,7 @@ void raLivenessRange::GetAllowedRegistersExRecursive(raLivenessRange* range, uin
bool raLivenessRange::GetAllowedRegistersEx(IMLPhysRegisterSet& allowedRegisters)
{
uint32 iterationIndex = PPCRecRA_getNextIterationIndex();
uint32 iterationIndex = IMLRA_GetNextIterationIndex();
allowedRegisters.SetAllAvailable();
GetAllowedRegistersExRecursive(this, iterationIndex, allowedRegisters);
return !allowedRegisters.HasAllAvailable();
@ -96,7 +96,7 @@ bool raLivenessRange::GetAllowedRegistersEx(IMLPhysRegisterSet& allowedRegisters
IMLPhysRegisterSet raLivenessRange::GetAllowedRegisters(IMLPhysRegisterSet regPool)
{
IMLPhysRegisterSet fixedRegRequirements = regPool;
if(interval2.ExtendsPreviousSegment() || interval2.ExtendsIntoNextSegment())
if(interval.ExtendsPreviousSegment() || interval.ExtendsIntoNextSegment())
{
auto clusterRanges = GetAllSubrangesInCluster();
for(auto& subrange : clusterRanges)
@ -203,7 +203,7 @@ void PPCRecRARange_removeLink_allSegmentRanges(raLivenessRange** root, raLivenes
MemoryPoolPermanentObjects<raLivenessRange> memPool_livenessSubrange(4096);
// startPosition and endPosition are inclusive
raLivenessRange* PPCRecRA_createSubrange2(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition)
raLivenessRange* IMLRA_CreateRange(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition)
{
raLivenessRange* range = memPool_livenessSubrange.acquireObj();
range->previousRanges.clear();
@ -212,8 +212,8 @@ raLivenessRange* PPCRecRA_createSubrange2(ppcImlGenContext_t* ppcImlGenContext,
range->imlSegment = imlSegment;
cemu_assert_debug(startPosition <= endPosition);
range->interval2.start = startPosition;
range->interval2.end = endPosition;
range->interval.start = startPosition;
range->interval.end = endPosition;
// register mapping
range->virtualRegister = virtualRegister;
@ -233,42 +233,42 @@ raLivenessRange* PPCRecRA_createSubrange2(ppcImlGenContext_t* ppcImlGenContext,
return range;
}
void _unlinkSubrange(raLivenessRange* subrange)
void _unlinkSubrange(raLivenessRange* range)
{
IMLSegment* imlSegment = subrange->imlSegment;
PPCRecRARange_removeLink_perVirtualGPR(imlSegment->raInfo.linkedList_perVirtualRegister, subrange);
PPCRecRARange_removeLink_allSegmentRanges(&imlSegment->raInfo.linkedList_allSubranges, subrange);
IMLSegment* imlSegment = range->imlSegment;
PPCRecRARange_removeLink_perVirtualGPR(imlSegment->raInfo.linkedList_perVirtualRegister, range);
PPCRecRARange_removeLink_allSegmentRanges(&imlSegment->raInfo.linkedList_allSubranges, range);
// unlink reverse references
if(subrange->subrangeBranchTaken)
subrange->subrangeBranchTaken->previousRanges.erase(std::find(subrange->subrangeBranchTaken->previousRanges.begin(), subrange->subrangeBranchTaken->previousRanges.end(), subrange));
if(subrange->subrangeBranchNotTaken)
subrange->subrangeBranchNotTaken->previousRanges.erase(std::find(subrange->subrangeBranchNotTaken->previousRanges.begin(), subrange->subrangeBranchNotTaken->previousRanges.end(), subrange));
subrange->subrangeBranchTaken = (raLivenessRange*)(uintptr_t)-1;
subrange->subrangeBranchNotTaken = (raLivenessRange*)(uintptr_t)-1;
if(range->subrangeBranchTaken)
range->subrangeBranchTaken->previousRanges.erase(std::find(range->subrangeBranchTaken->previousRanges.begin(), range->subrangeBranchTaken->previousRanges.end(), range));
if(range->subrangeBranchNotTaken)
range->subrangeBranchNotTaken->previousRanges.erase(std::find(range->subrangeBranchNotTaken->previousRanges.begin(), range->subrangeBranchNotTaken->previousRanges.end(), range));
range->subrangeBranchTaken = (raLivenessRange*)(uintptr_t)-1;
range->subrangeBranchNotTaken = (raLivenessRange*)(uintptr_t)-1;
// remove forward references
for(auto& prev : subrange->previousRanges)
for(auto& prev : range->previousRanges)
{
if(prev->subrangeBranchTaken == subrange)
if(prev->subrangeBranchTaken == range)
prev->subrangeBranchTaken = nullptr;
if(prev->subrangeBranchNotTaken == subrange)
if(prev->subrangeBranchNotTaken == range)
prev->subrangeBranchNotTaken = nullptr;
}
subrange->previousRanges.clear();
range->previousRanges.clear();
}
void PPCRecRA_deleteSubrange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange)
void IMLRA_DeleteRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* range)
{
_unlinkSubrange(subrange);
subrange->list_accessLocations.clear();
subrange->list_fixedRegRequirements.clear();
memPool_livenessSubrange.releaseObj(subrange);
_unlinkSubrange(range);
range->list_accessLocations.clear();
range->list_fixedRegRequirements.clear();
memPool_livenessSubrange.releaseObj(range);
}
void PPCRecRA_deleteSubrangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange)
void IMLRA_DeleteRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* range)
{
auto clusterRanges = subrange->GetAllSubrangesInCluster();
auto clusterRanges = range->GetAllSubrangesInCluster();
for (auto& subrange : clusterRanges)
PPCRecRA_deleteSubrange(ppcImlGenContext, subrange);
IMLRA_DeleteRange(ppcImlGenContext, subrange);
}
void IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext)
@ -277,13 +277,13 @@ void IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext)
{
raLivenessRange* cur;
while(cur = seg->raInfo.linkedList_allSubranges)
PPCRecRA_deleteSubrange(ppcImlGenContext, cur);
IMLRA_DeleteRange(ppcImlGenContext, cur);
seg->raInfo.linkedList_allSubranges = nullptr;
seg->raInfo.linkedList_perVirtualRegister.clear();
}
}
void PPCRecRA_mergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange)
void IMLRA_MergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange)
{
#ifdef CEMU_DEBUG_ASSERT
PPCRecRA_debugValidateSubrange(subrange);
@ -322,17 +322,17 @@ void PPCRecRA_mergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRan
subrange->list_fixedRegRequirements.push_back(fixedReg);
absorbedSubrange->list_fixedRegRequirements.clear();
subrange->interval2.end = absorbedSubrange->interval2.end;
subrange->interval.end = absorbedSubrange->interval.end;
PPCRecRA_debugValidateSubrange(subrange);
PPCRecRA_deleteSubrange(ppcImlGenContext, absorbedSubrange);
IMLRA_DeleteRange(ppcImlGenContext, absorbedSubrange);
}
// remove all inter-segment connections from the range cluster and split it into local ranges (also removes empty ranges)
void PPCRecRA_explodeRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange)
// remove all inter-segment connections from the range cluster and split it into local ranges. Ranges are trimmed and if they have no access location they will be removed
void IMLRA_ExplodeRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange)
{
cemu_assert_debug(originRange->interval2.ExtendsPreviousSegment() || originRange->interval2.ExtendsIntoNextSegment()); // only call this on ranges that span multiple segments
cemu_assert_debug(originRange->interval.ExtendsPreviousSegment() || originRange->interval.ExtendsIntoNextSegment()); // only call this on ranges that span multiple segments
auto clusterRanges = originRange->GetAllSubrangesInCluster();
for (auto& subrange : clusterRanges)
{
@ -340,7 +340,7 @@ void PPCRecRA_explodeRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange
continue;
raInterval interval;
interval.SetInterval(subrange->list_accessLocations.front().pos, subrange->list_accessLocations.back().pos);
raLivenessRange* newSubrange = PPCRecRA_createSubrange2(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), interval.start, interval.end);
raLivenessRange* newSubrange = IMLRA_CreateRange(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), interval.start, interval.end);
// copy locations and fixed reg indices
newSubrange->list_accessLocations = subrange->list_accessLocations;
newSubrange->list_fixedRegRequirements = subrange->list_fixedRegRequirements;
@ -351,17 +351,17 @@ void PPCRecRA_explodeRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange
// validate
if(!newSubrange->list_accessLocations.empty())
{
cemu_assert_debug(newSubrange->list_accessLocations.front().pos >= newSubrange->interval2.start);
cemu_assert_debug(newSubrange->list_accessLocations.back().pos <= newSubrange->interval2.end);
cemu_assert_debug(newSubrange->list_accessLocations.front().pos >= newSubrange->interval.start);
cemu_assert_debug(newSubrange->list_accessLocations.back().pos <= newSubrange->interval.end);
}
if(!newSubrange->list_fixedRegRequirements.empty())
{
cemu_assert_debug(newSubrange->list_fixedRegRequirements.front().pos >= newSubrange->interval2.start); // fixed register requirements outside of the actual access range probably means there is a mistake in GetInstructionFixedRegisters()
cemu_assert_debug(newSubrange->list_fixedRegRequirements.back().pos <= newSubrange->interval2.end);
cemu_assert_debug(newSubrange->list_fixedRegRequirements.front().pos >= newSubrange->interval.start); // fixed register requirements outside of the actual access range probably means there is a mistake in GetInstructionFixedRegisters()
cemu_assert_debug(newSubrange->list_fixedRegRequirements.back().pos <= newSubrange->interval.end);
}
}
// remove subranges
PPCRecRA_deleteSubrangeCluster(ppcImlGenContext, originRange);
// delete the original range cluster
IMLRA_DeleteRangeCluster(ppcImlGenContext, originRange);
}
#ifdef CEMU_DEBUG_ASSERT
@ -408,19 +408,19 @@ void IMLRA_TrimRangeToUse(raLivenessRange* range)
if(range->list_accessLocations.empty())
{
// special case where we trim ranges extending from other segments to a single instruction edge
cemu_assert_debug(!range->interval2.start.IsInstructionIndex() || !range->interval2.end.IsInstructionIndex());
if(range->interval2.start.IsInstructionIndex())
range->interval2.start = range->interval2.end;
if(range->interval2.end.IsInstructionIndex())
range->interval2.end = range->interval2.start;
cemu_assert_debug(!range->interval.start.IsInstructionIndex() || !range->interval.end.IsInstructionIndex());
if(range->interval.start.IsInstructionIndex())
range->interval.start = range->interval.end;
if(range->interval.end.IsInstructionIndex())
range->interval.end = range->interval.start;
return;
}
// trim start and end
raInterval prevInterval = range->interval2;
if(range->interval2.start.IsInstructionIndex())
range->interval2.start = range->list_accessLocations.front().pos;
if(range->interval2.end.IsInstructionIndex())
range->interval2.end = range->list_accessLocations.back().pos;
raInterval prevInterval = range->interval;
if(range->interval.start.IsInstructionIndex())
range->interval.start = range->list_accessLocations.front().pos;
if(range->interval.end.IsInstructionIndex())
range->interval.end = range->list_accessLocations.back().pos;
// extra checks
#ifdef CEMU_DEBUG_ASSERT
cemu_assert_debug(range->interval2.start <= range->interval2.end);
@ -438,22 +438,20 @@ void IMLRA_TrimRangeToUse(raLivenessRange* range)
// tail -> a new subrange that ranges from splitIndex (inclusive) to the end of the original subrange
// if head has a physical register assigned it will not carry over to tail
// The return value is the tail range
// If trimToHole is true, the end of the head subrange and the start of the tail subrange will be shrunk to fit the read/write locations within them
// the range after the split point does not inherit the physical register
// if trimToHole is true and any of the halfes is empty, it will be deleted
raLivenessRange* PPCRecRA_splitLocalSubrange2(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToHole)
// If trimToUsage is true, the end of the head subrange and the start of the tail subrange will be shrunk to fit the read/write locations within. If there are no locations then the range will be deleted
raLivenessRange* IMLRA_SplitRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToUsage)
{
cemu_assert_debug(splitPosition.IsInstructionIndex());
cemu_assert_debug(!subrange->interval2.IsNextSegmentOnly() && !subrange->interval2.IsPreviousSegmentOnly());
cemu_assert_debug(subrange->interval2.ContainsEdge(splitPosition));
cemu_assert_debug(!subrange->interval.IsNextSegmentOnly() && !subrange->interval.IsPreviousSegmentOnly());
cemu_assert_debug(subrange->interval.ContainsEdge(splitPosition));
// determine new intervals
raInterval headInterval, tailInterval;
headInterval.SetInterval(subrange->interval2.start, splitPosition-1);
tailInterval.SetInterval(splitPosition, subrange->interval2.end);
headInterval.SetInterval(subrange->interval.start, splitPosition-1);
tailInterval.SetInterval(splitPosition, subrange->interval.end);
cemu_assert_debug(headInterval.start <= headInterval.end);
cemu_assert_debug(tailInterval.start <= tailInterval.end);
// create tail
raLivenessRange* tailSubrange = PPCRecRA_createSubrange2(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), tailInterval.start, tailInterval.end);
raLivenessRange* tailSubrange = IMLRA_CreateRange(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), tailInterval.start, tailInterval.end);
tailSubrange->SetPhysicalRegister(subrange->GetPhysicalRegister());
// carry over branch targets and update reverse references
tailSubrange->subrangeBranchTaken = subrange->subrangeBranchTaken;
@ -505,23 +503,23 @@ raLivenessRange* PPCRecRA_splitLocalSubrange2(ppcImlGenContext_t* ppcImlGenConte
}
}
// adjust intervals
subrange->interval2 = headInterval;
tailSubrange->interval2 = tailInterval;
subrange->interval = headInterval;
tailSubrange->interval = tailInterval;
// trim to hole
if(trimToHole)
if(trimToUsage)
{
if(subrange->list_accessLocations.empty() && (subrange->interval2.start.IsInstructionIndex() && subrange->interval2.end.IsInstructionIndex()))
if(subrange->list_accessLocations.empty() && (subrange->interval.start.IsInstructionIndex() && subrange->interval.end.IsInstructionIndex()))
{
PPCRecRA_deleteSubrange(ppcImlGenContext, subrange);
IMLRA_DeleteRange(ppcImlGenContext, subrange);
subrange = nullptr;
}
else
{
IMLRA_TrimRangeToUse(subrange);
}
if(tailSubrange->list_accessLocations.empty() && (tailSubrange->interval2.start.IsInstructionIndex() && tailSubrange->interval2.end.IsInstructionIndex()))
if(tailSubrange->list_accessLocations.empty() && (tailSubrange->interval.start.IsInstructionIndex() && tailSubrange->interval.end.IsInstructionIndex()))
{
PPCRecRA_deleteSubrange(ppcImlGenContext, tailSubrange);
IMLRA_DeleteRange(ppcImlGenContext, tailSubrange);
tailSubrange = nullptr;
}
else
@ -530,11 +528,11 @@ raLivenessRange* PPCRecRA_splitLocalSubrange2(ppcImlGenContext_t* ppcImlGenConte
}
}
// validation
cemu_assert_debug(!subrange || subrange->interval2.start <= subrange->interval2.end);
cemu_assert_debug(!tailSubrange || tailSubrange->interval2.start <= tailSubrange->interval2.end);
cemu_assert_debug(!tailSubrange || tailSubrange->interval2.start >= splitPosition);
if (!trimToHole)
cemu_assert_debug(!tailSubrange || tailSubrange->interval2.start == splitPosition);
cemu_assert_debug(!subrange || subrange->interval.start <= subrange->interval.end);
cemu_assert_debug(!tailSubrange || tailSubrange->interval.start <= tailSubrange->interval.end);
cemu_assert_debug(!tailSubrange || tailSubrange->interval.start >= splitPosition);
if (!trimToUsage)
cemu_assert_debug(!tailSubrange || tailSubrange->interval.start == splitPosition);
if(subrange)
PPCRecRA_debugValidateSubrange(subrange);
@ -560,8 +558,8 @@ sint32 IMLRA_CalculateAdditionalCostOfRangeExplode(raLivenessRange* subrange)
if (subrange->list_accessLocations.empty())
continue; // this range would be deleted and thus has no cost
sint32 segmentLoadStoreCost = IMLRA_GetSegmentReadWriteCost(subrange->imlSegment);
bool hasAdditionalLoad = subrange->interval2.ExtendsPreviousSegment();
bool hasAdditionalStore = subrange->interval2.ExtendsIntoNextSegment();
bool hasAdditionalLoad = subrange->interval.ExtendsPreviousSegment();
bool hasAdditionalStore = subrange->interval.ExtendsIntoNextSegment();
if(hasAdditionalLoad && subrange->list_accessLocations.front().IsWrite()) // if written before read then a load isn't necessary
{
cemu_assert_debug(!subrange->list_accessLocations.front().IsRead());

View File

@ -302,7 +302,7 @@ struct raFixedRegRequirement
struct raLivenessRange
{
IMLSegment* imlSegment;
raInterval interval2;
raInterval interval;
// dirty state tracking
bool _noLoad;
@ -327,7 +327,7 @@ struct raLivenessRange
IMLRegID virtualRegister;
IMLName name;
// register allocator result
sint32 physicalRegister;
IMLPhysReg physicalRegister;
boost::container::small_vector<raLivenessRange*, 128> GetAllSubrangesInCluster();
bool GetAllowedRegistersEx(IMLPhysRegisterSet& allowedRegisters); // if the cluster has fixed register requirements in any instruction this returns the combined register mask. Otherwise returns false in which case allowedRegisters is left undefined
@ -337,23 +337,23 @@ struct raLivenessRange
sint32 GetPhysicalRegister() const;
bool HasPhysicalRegister() const { return physicalRegister >= 0; }
IMLName GetName() const;
void SetPhysicalRegister(sint32 physicalRegister);
void SetPhysicalRegisterForCluster(sint32 physicalRegister);
void SetPhysicalRegister(IMLPhysReg physicalRegister);
void SetPhysicalRegisterForCluster(IMLPhysReg physicalRegister);
void UnsetPhysicalRegister() { physicalRegister = -1; }
private:
void GetAllowedRegistersExRecursive(raLivenessRange* range, uint32 iterationIndex, IMLPhysRegisterSet& allowedRegs);
};
raLivenessRange* PPCRecRA_createSubrange2(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition);
void PPCRecRA_deleteSubrange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange);
raLivenessRange* IMLRA_CreateRange(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition);
void IMLRA_DeleteRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange);
void IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext);
void PPCRecRA_explodeRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange);
void IMLRA_ExplodeRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange);
void PPCRecRA_mergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange);
void IMLRA_MergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange);
raLivenessRange* PPCRecRA_splitLocalSubrange2(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToHole = false);
raLivenessRange* IMLRA_SplitRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToUsage = false);
void PPCRecRA_debugValidateSubrange(raLivenessRange* subrange);

View File

@ -19,6 +19,7 @@
#include "util/highresolutiontimer/HighResolutionTimer.h"
#define PPCREC_FORCE_SYNCHRONOUS_COMPILATION 0 // if 1, then function recompilation will block and execute on the thread that called PPCRecompiler_visitAddressNoBlock
#define PPCREC_LOG_RECOMPILATION_RESULTS 0
struct PPCInvalidationRange
{
@ -185,8 +186,10 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
ppcRecFunc->ppcAddress = range.startAddress;
ppcRecFunc->ppcSize = range.length;
#if PPCREC_LOG_RECOMPILATION_RESULTS
BenchmarkTimer bt;
bt.Start();
#endif
// generate intermediate code
ppcImlGenContext_t ppcImlGenContext = { 0 };
@ -217,18 +220,6 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
return nullptr;
}
// if (ppcRecFunc->ppcAddress == 0x2BDA9F4)
// {
// IMLDebug_Dump(&ppcImlGenContext);
// __debugbreak();
// }
// Functions for testing (botw):
// 3B4049C (large with switch case)
// 30BF118 (has a bndz copy loop + some float instructions at the end)
// emit x64 code
bool x64GenerationSuccess = PPCRecompiler_generateX64Code(ppcRecFunc, &ppcImlGenContext);
if (x64GenerationSuccess == false)
@ -258,18 +249,16 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
entryPointsOut.emplace_back(ppcEnterOffset, x64Offset);
}
#if PPCREC_LOG_RECOMPILATION_RESULTS
bt.Stop();
//cemuLog_log(LogType::Force, "[Recompiler] Successfully compiled {:08x} - {:08x} Segments: {} Entrypoints: {}", ppcRecFunc->ppcAddress, ppcRecFunc->ppcAddress + ppcRecFunc->ppcSize, ppcImlGenContext.segmentList2.size(), entryPointsOut.size());
uint32 codeHash = 0;
for (uint32 i = 0; i < ppcRecFunc->x86Size; i++)
{
codeHash = _rotr(codeHash, 3);
codeHash += ((uint8*)ppcRecFunc->x86Code)[i];
}
cemuLog_log(LogType::Force, "[Recompiler] PPC 0x{:08x} -> x64: 0x{:x} Took {:.4}ms | Size {:04x} CodeHash {:08x}", (uint32)ppcRecFunc->ppcAddress, (uint64)(uintptr_t)ppcRecFunc->x86Code, bt.GetElapsedMilliseconds(), ppcRecFunc->x86Size, codeHash);
#endif
return ppcRecFunc;
}

View File

@ -3008,7 +3008,6 @@ void PPCRecompiler_SetSegmentsUncertainFlow(ppcImlGenContext_t& ppcImlGenContext
break;
case PPCREC_IML_MACRO_DEBUGBREAK:
case PPCREC_IML_MACRO_COUNT_CYCLES:
case PPCREC_IML_MACRO_MFTB:
break;
default:
cemu_assert_unimplemented();