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(); 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) bool PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)
{ {
if (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG) 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)); x64Gen_jmp_memReg64(x64GenContext, X86_REG_RAX, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));
return true; 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 else
{ {
debug_printf("Unknown recompiler macro operation %d\n", imlInstruction->operation); 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; raLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;
while (subrangeItr) 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("."); currentLineText.add(".");
else else
currentLineText.add("|"); currentLineText.add("|");
currentLineText.addFmt("{:<4}", subrangeItr->GetVirtualRegister()); 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("* "); currentLineText.add("* ");
else else
currentLineText.add("| "); currentLineText.add("| ");
} }
else if (subrangeItr->interval2.ContainsInstructionIndexEx(offset)) else if (subrangeItr->interval.ContainsInstructionIndexEx(offset))
{ {
currentLineText.add("| "); 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); 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) else if (inst.operation == PPCREC_IML_MACRO_COUNT_CYCLES)
{ {
strOutput.addFmt("MACRO COUNT_CYCLES cycles: {}", inst.op_macro.param); strOutput.addFmt("MACRO COUNT_CYCLES cycles: {}", inst.op_macro.param);

View File

@ -4,6 +4,7 @@
#include "../PPCRecompiler.h" #include "../PPCRecompiler.h"
#include "../PPCRecompilerIml.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 IMLInstruction::HasSideEffects() const
{ {
bool hasSideEffects = true; bool hasSideEffects = true;
@ -160,7 +161,7 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
} }
else if (type == PPCREC_IML_TYPE_MACRO) 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 // 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) IMLReg replaceRegisterIdMultiple(IMLReg reg, const std::unordered_map<IMLRegID, IMLRegID>& translationTable)
{ {
if (reg.IsInvalid()) if (reg.IsInvalid())
@ -502,26 +494,6 @@ IMLReg replaceRegisterIdMultiple(IMLReg reg, const std::unordered_map<IMLRegID,
return alteredReg; 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) void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable)
{ {
if (type == PPCREC_IML_TYPE_R_NAME) 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) 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 // no effect on registers
} }
@ -717,228 +689,3 @@ void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& tr
cemu_assert_unimplemented(); 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_B_FAR, // branch to different function
PPCREC_IML_MACRO_COUNT_CYCLES, // decrease current remaining thread cycles by a certain amount PPCREC_IML_MACRO_COUNT_CYCLES, // decrease current remaining thread cycles by a certain amount
PPCREC_IML_MACRO_HLE, // HLE function call 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 PPCREC_IML_MACRO_LEAVE, // leaves recompiler and switches to interpeter
// debugging // debugging
PPCREC_IML_MACRO_DEBUGBREAK, // throws a debugbreak PPCREC_IML_MACRO_DEBUGBREAK, // throws a debugbreak
@ -335,19 +334,6 @@ struct IMLUsedRegisters
{ {
IMLUsedRegisters() {}; IMLUsedRegisters() {};
union
{
struct
{
IMLReg readGPR1;
IMLReg readGPR2;
IMLReg readGPR3;
IMLReg readGPR4;
IMLReg writtenGPR1;
IMLReg writtenGPR2;
};
};
bool IsWrittenByRegId(IMLRegID regId) const bool IsWrittenByRegId(IMLRegID regId) const
{ {
if (writtenGPR1.IsValid() && writtenGPR1.GetRegID() == regId) if (writtenGPR1.IsValid() && writtenGPR1.GetRegID() == regId)
@ -404,6 +390,12 @@ struct IMLUsedRegisters
F(writtenGPR2, true); F(writtenGPR2, true);
} }
IMLReg readGPR1;
IMLReg readGPR2;
IMLReg readGPR3;
IMLReg readGPR4;
IMLReg writtenGPR1;
IMLReg writtenGPR2;
}; };
struct IMLInstruction 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_B_TO_REG ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_LEAVE || 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_HLE ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_MFTB ||
type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK || type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK ||
type == PPCREC_IML_TYPE_JUMP || type == PPCREC_IML_TYPE_JUMP ||
type == PPCREC_IML_TYPE_CONDITIONAL_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 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 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 // architecture specific constants

View File

@ -192,7 +192,7 @@ static void GetInstructionFixedRegisters(IMLInstruction* instruction, IMLFixedRe
} }
#endif #endif
uint32 PPCRecRA_getNextIterationIndex() uint32 IMLRA_GetNextIterationIndex()
{ {
static uint32 recRACurrentIterationIndex = 0; static uint32 recRACurrentIterationIndex = 0;
recRACurrentIterationIndex++; recRACurrentIterationIndex++;
@ -231,9 +231,9 @@ bool _detectLoop(IMLSegment* currentSegment, sint32 depth, uint32 iterationIndex
return currentSegment->raInfo.isPartOfProcessedLoop; 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; imlSegmentLoopBase->raInfo.lastIterationIndex = iterationIndex;
if (_detectLoop(imlSegmentLoopBase->nextSegmentBranchTaken, 0, iterationIndex, imlSegmentLoopBase)) 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) if (imlSegment->nextSegmentIsUncertain)
return; 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) // check if this segment has a branch that goes backwards (potential complex loop)
if (imlSegment->nextSegmentBranchTaken && imlSegment->nextSegmentBranchTaken->momentaryIndex < imlSegment->momentaryIndex) if (imlSegment->nextSegmentBranchTaken && imlSegment->nextSegmentBranchTaken->momentaryIndex < imlSegment->momentaryIndex)
{ {
PPCRecRA_detectLoop(ppcImlGenContext, imlSegment); IMLRA_DetectLoop(ppcImlGenContext, imlSegment);
} }
} }
#define SUBRANGE_LIST_SIZE (128) #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++) 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(); return fixedReqEntry.pos.GetRaw() - startPosition.GetRaw();
} }
} }
cemu_assert_debug(range->interval2.end.IsInstructionIndex()); cemu_assert_debug(range->interval.end.IsInstructionIndex());
return range->interval2.end.GetRaw() - startPosition.GetRaw(); return range->interval.end.GetRaw() - startPosition.GetRaw();
} }
sint32 IMLRA_CountDistanceUntilFixedRegUsage(IMLSegment* imlSegment, raInstructionEdge startPosition, sint32 maxDistance, IMLRegID ourRegId, sint32 physRegister) 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; subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue; continue;
} }
if (subrangeItr->interval2.ContainsEdge(startPosition)) if (subrangeItr->interval.ContainsEdge(startPosition))
return 0; return 0;
if (subrangeItr->interval2.end < startPosition) if (subrangeItr->interval.end < startPosition)
{ {
subrangeItr = subrangeItr->link_allSegmentRanges.next; subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue; continue;
} }
cemu_assert_debug(startPosition <= subrangeItr->interval2.start); cemu_assert_debug(startPosition <= subrangeItr->interval.start);
sint32 currentDist = subrangeItr->interval2.start.GetRaw() - startPosition.GetRaw(); sint32 currentDist = subrangeItr->interval.start.GetRaw() - startPosition.GetRaw();
minDistance = std::min(minDistance, currentDist); minDistance = std::min(minDistance, currentDist);
subrangeItr = subrangeItr->link_allSegmentRanges.next; subrangeItr = subrangeItr->link_allSegmentRanges.next;
} }
@ -377,7 +377,7 @@ struct IMLRALivenessTimeline
for (size_t f = 0; f < count; f++) for (size_t f = 0; f < count; f++)
{ {
raLivenessRange* liverange = activeRanges[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 #ifdef CEMU_DEBUG_ASSERT
if (!expireUpTo.ConnectsToNextSegment() && (liverange->subrangeBranchTaken || liverange->subrangeBranchNotTaken)) if (!expireUpTo.ConnectsToNextSegment() && (liverange->subrangeBranchTaken || liverange->subrangeBranchNotTaken))
@ -443,7 +443,7 @@ void PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange* range2, IMLP
subrangeItr = subrangeItr->link_allSegmentRanges.next; subrangeItr = subrangeItr->link_allSegmentRanges.next;
continue; continue;
} }
if (subrange->interval2.IsOverlapping(subrangeItr->interval2)) if (subrange->interval.IsOverlapping(subrangeItr->interval))
{ {
if (subrangeItr->GetPhysicalRegister() >= 0) if (subrangeItr->GetPhysicalRegister() >= 0)
physRegSet.SetReserved(subrangeItr->GetPhysicalRegister()); physRegSet.SetReserved(subrangeItr->GetPhysicalRegister());
@ -456,7 +456,7 @@ void PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange* range2, IMLP
bool _livenessRangeStartCompare(raLivenessRange* lhs, raLivenessRange* rhs) bool _livenessRangeStartCompare(raLivenessRange* lhs, raLivenessRange* rhs)
{ {
return lhs->interval2.start < rhs->interval2.start; return lhs->interval.start < rhs->interval.start;
} }
void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment) void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)
@ -467,8 +467,7 @@ void _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)
raLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges; raLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;
while (subrangeItr) while (subrangeItr)
{ {
if (count >= 4096) cemu_assert(count < 4096);
assert_dbg();
subrangeList[count] = subrangeItr; subrangeList[count] = subrangeItr;
count++; count++;
// next // next
@ -526,6 +525,9 @@ raLivenessRange* IMLRA_GetSubrange(IMLSegment* imlSegment, IMLRegID regId)
struct raFixedRegRequirementWithVGPR struct raFixedRegRequirementWithVGPR
{ {
raFixedRegRequirementWithVGPR(raInstructionEdge pos, IMLPhysRegisterSet allowedReg, IMLRegID regId)
: pos(pos), allowedReg(allowedReg), regId(regId) {}
raInstructionEdge pos; raInstructionEdge pos;
IMLPhysRegisterSet allowedReg; IMLPhysRegisterSet allowedReg;
IMLRegID regId; IMLRegID regId;
@ -560,7 +562,7 @@ boost::container::small_vector<raLivenessRange*, 8> IMLRA_GetRangeWithFixedRegRe
boost::container::small_vector<raLivenessRange*, 8> rangeList; boost::container::small_vector<raLivenessRange*, 8> rangeList;
for (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next) for (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)
{ {
if (!currentRange->interval2.ContainsEdge(pos)) if (!currentRange->interval.ContainsEdge(pos))
continue; continue;
IMLPhysRegisterSet allowedRegs; IMLPhysRegisterSet allowedRegs;
if (!currentRange->GetAllowedRegistersEx(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) 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 // 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;) for (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange;)
{ {
IMLPhysRegisterSet allowedRegs; IMLPhysRegisterSet allowedRegs;
@ -588,10 +590,10 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment
currentRange = currentRange->link_allSegmentRanges.next; currentRange = currentRange->link_allSegmentRanges.next;
continue; continue;
} }
if (currentRange->interval2.ExtendsPreviousSegment() || currentRange->interval2.ExtendsIntoNextSegment()) if (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())
{ {
raLivenessRange* nextRange = currentRange->link_allSegmentRanges.next; raLivenessRange* nextRange = currentRange->link_allSegmentRanges.next;
PPCRecRA_explodeRange(ppcImlGenContext, currentRange); IMLRA_ExplodeRangeCluster(ppcImlGenContext, currentRange);
currentRange = nextRange; currentRange = nextRange;
continue; continue;
} }
@ -638,9 +640,9 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment
for (auto& range : overlappingRanges) 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(); distance = endPos.GetRaw() - startPos.GetRaw();
} }
void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx); static void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx);
class RASpillStrategy class RASpillStrategy
{ {
@ -737,8 +739,8 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
void Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs) void Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)
{ {
raInstructionEdge currentRangeStart = currentRange->interval2.start; raInstructionEdge currentRangeStart = currentRange->interval.start;
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance(); sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
cemu_assert_debug(localRangeHoleCutting.distance == -1); cemu_assert_debug(localRangeHoleCutting.distance == -1);
cemu_assert_debug(strategyCost == INT_MAX); cemu_assert_debug(strategyCost == INT_MAX);
if (!currentRangeStart.ConnectsToPreviousSegment()) if (!currentRangeStart.ConnectsToPreviousSegment())
@ -746,7 +748,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
cemu_assert_debug(currentRangeStart.GetRaw() >= 0); cemu_assert_debug(currentRangeStart.GetRaw() >= 0);
for (auto candidate : timeline.activeRanges) for (auto candidate : timeline.activeRanges)
{ {
if (candidate->interval2.ExtendsIntoNextSegment()) if (candidate->interval.ExtendsIntoNextSegment())
continue; continue;
// new checks (Oct 2024): // new checks (Oct 2024):
if (candidate == currentRange) if (candidate == currentRange)
@ -756,7 +758,7 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister())) if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))
continue; continue;
sint32 distance2 = PPCRecRA_countDistanceUntilNextUse2(candidate, currentRangeStart); sint32 distance2 = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);
IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance2); IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance2);
if (distance2 < 2) if (distance2 < 2)
continue; continue;
@ -785,18 +787,18 @@ class RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{ {
cemu_assert_debug(strategyCost != INT_MAX); cemu_assert_debug(strategyCost != INT_MAX);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance(); sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
raInstructionEdge currentRangeStart = currentRange->interval2.start; raInstructionEdge currentRangeStart = currentRange->interval.start;
raInstructionEdge holeStartPosition = currentRangeStart; raInstructionEdge holeStartPosition = currentRangeStart;
raInstructionEdge holeEndPosition = currentRangeStart + localRangeHoleCutting.distance; raInstructionEdge holeEndPosition = currentRangeStart + localRangeHoleCutting.distance;
raLivenessRange* collisionRange = localRangeHoleCutting.largestHoleSubrange; raLivenessRange* collisionRange = localRangeHoleCutting.largestHoleSubrange;
if (collisionRange->interval2.start < holeStartPosition) if (collisionRange->interval.start < holeStartPosition)
{ {
collisionRange = PPCRecRA_splitLocalSubrange2(nullptr, collisionRange, holeStartPosition, true); collisionRange = IMLRA_SplitRange(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->interval.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 cemu_assert_debug(!collisionRange || collisionRange->interval.start >= holeEndPosition); // also verify that the trimmed hole is actually big enough
} }
else 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 // we may also have to cut the current range to fit partially into the hole
if (requiredSize2 > localRangeHoleCutting.distance) 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) if (tailRange)
{ {
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers 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 // verify that the hole is large enough
if (collisionRange) 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) 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); cemu_assert_debug(strategyCost == INT_MAX);
availableRegisterHole.distance = -1; availableRegisterHole.distance = -1;
availableRegisterHole.physRegister = -1; availableRegisterHole.physRegister = -1;
@ -888,9 +890,9 @@ class RASpillStrategy_AvailableRegisterHole : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{ {
cemu_assert_debug(strategyCost != INT_MAX); cemu_assert_debug(strategyCost != INT_MAX);
raInstructionEdge currentRangeStart = currentRange->interval2.start; raInstructionEdge currentRangeStart = currentRange->interval.start;
// use available register // 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) if (tailRange)
{ {
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers 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) 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()) if (currentRangeStart.ConnectsToPreviousSegment())
currentRangeStart.Set(0, true); currentRangeStart.Set(0, true);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance(); sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
cemu_assert_debug(strategyCost == INT_MAX); cemu_assert_debug(strategyCost == INT_MAX);
explodeRange.range = nullptr; explodeRange.range = nullptr;
explodeRange.distance = -1; explodeRange.distance = -1;
for (auto candidate : timeline.activeRanges) for (auto candidate : timeline.activeRanges)
{ {
if (!candidate->interval2.ExtendsIntoNextSegment()) if (!candidate->interval.ExtendsIntoNextSegment())
continue; continue;
// new checks (Oct 2024): // new checks (Oct 2024):
if (candidate == currentRange) if (candidate == currentRange)
@ -937,7 +939,7 @@ class RASpillStrategy_ExplodeRange : public RASpillStrategy
if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister())) if (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))
continue; continue;
sint32 distance = PPCRecRA_countDistanceUntilNextUse2(candidate, currentRangeStart); sint32 distance = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);
IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance); IMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance);
if (distance < 2) if (distance < 2)
continue; continue;
@ -961,16 +963,16 @@ class RASpillStrategy_ExplodeRange : public RASpillStrategy
void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{ {
raInstructionEdge currentRangeStart = currentRange->interval2.start; raInstructionEdge currentRangeStart = currentRange->interval.start;
if (currentRangeStart.ConnectsToPreviousSegment()) if (currentRangeStart.ConnectsToPreviousSegment())
currentRangeStart.Set(0, true); currentRangeStart.Set(0, true);
sint32 requiredSize2 = currentRange->interval2.GetPreciseDistance(); sint32 requiredSize2 = currentRange->interval.GetPreciseDistance();
// explode range // explode range
PPCRecRA_explodeRange(nullptr, explodeRange.range); IMLRA_ExplodeRangeCluster(nullptr, explodeRange.range);
// split current subrange if necessary // split current subrange if necessary
if (requiredSize2 > explodeRange.distance) 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) if (tailRange)
{ {
cemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers 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); cemu_assert_debug(explodeRange.range == nullptr && explodeRange.distance == -1);
for (auto candidate : timeline.activeRanges) for (auto candidate : timeline.activeRanges)
{ {
if (!candidate->interval2.ExtendsIntoNextSegment()) if (!candidate->interval.ExtendsIntoNextSegment())
continue; continue;
// only select candidates that clash with current subrange // only select candidates that clash with current subrange
if (candidate->GetPhysicalRegister() < 0 && candidate != currentRange) 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 void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override
{ {
cemu_assert_debug(strategyCost != INT_MAX); cemu_assert_debug(strategyCost != INT_MAX);
PPCRecRA_explodeRange(ctx, explodeRange.range); IMLRA_ExplodeRangeCluster(ctx, explodeRange.range);
} }
private: private:
@ -1056,16 +1058,16 @@ void IMLRA_FilterReservedFixedRegisterRequirementsForSegment(IMLRegisterAllocato
if (seg->imlList.empty()) if (seg->imlList.empty())
return; // there can be no fixed register requirements if there are no instructions return; // there can be no fixed register requirements if there are no instructions
raInstructionEdge firstPos = currentRange->interval2.start; raInstructionEdge firstPos = currentRange->interval.start;
if (currentRange->interval2.start.ConnectsToPreviousSegment()) if (currentRange->interval.start.ConnectsToPreviousSegment())
firstPos.SetRaw(0); firstPos.SetRaw(0);
else if (currentRange->interval2.start.ConnectsToNextSegment()) else if (currentRange->interval.start.ConnectsToNextSegment())
firstPos.Set(seg->imlList.size() - 1, false); firstPos.Set(seg->imlList.size() - 1, false);
raInstructionEdge lastPos = currentRange->interval2.end; raInstructionEdge lastPos = currentRange->interval.end;
if (currentRange->interval2.end.ConnectsToPreviousSegment()) if (currentRange->interval.end.ConnectsToPreviousSegment())
lastPos.SetRaw(0); lastPos.SetRaw(0);
else if (currentRange->interval2.end.ConnectsToNextSegment()) else if (currentRange->interval.end.ConnectsToNextSegment())
lastPos.Set(seg->imlList.size() - 1, false); lastPos.Set(seg->imlList.size() - 1, false);
cemu_assert_debug(firstPos <= lastPos); cemu_assert_debug(firstPos <= lastPos);
@ -1093,7 +1095,7 @@ void IMLRA_FilterReservedFixedRegisterRequirementsForSegment(IMLRegisterAllocato
void IMLRA_FilterReservedFixedRegisterRequirementsForCluster(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, raLivenessRange* currentRange, IMLPhysRegisterSet& candidatePhysRegSet) void IMLRA_FilterReservedFixedRegisterRequirementsForCluster(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, raLivenessRange* currentRange, IMLPhysRegisterSet& candidatePhysRegSet)
{ {
cemu_assert_debug(currentRange->imlSegment == imlSegment); cemu_assert_debug(currentRange->imlSegment == imlSegment);
if (currentRange->interval2.ExtendsPreviousSegment() || currentRange->interval2.ExtendsIntoNextSegment()) if (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())
{ {
auto clusterRanges = currentRange->GetAllSubrangesInCluster(); auto clusterRanges = currentRange->GetAllSubrangesInCluster();
for (auto& rangeIt : clusterRanges) for (auto& rangeIt : clusterRanges)
@ -1128,7 +1130,7 @@ bool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenCon
while (subrangeItr) 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); PPCRecRA_debugValidateSubrange(subrangeItr);
livenessTimeline.ExpireRanges((currentRangeStart > lastInstructionEdge) ? lastInstructionEdge : currentRangeStart); // expire up to currentIndex (inclusive), but exclude infinite ranges 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; selectedStrategy = &newStrategy;
}; };
if (!subrangeItr->interval2.ExtendsIntoNextSegment()) if (!subrangeItr->interval.ExtendsIntoNextSegment())
{ {
// range ends in current segment, use local strategies // range ends in current segment, use local strategies
// evaluate strategy: Cut hole into local subrange // evaluate strategy: Cut hole into local subrange
@ -1232,9 +1234,9 @@ bool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenCon
else 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 // 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 // alternative strategy if we have no other choice: explode current range
PPCRecRA_explodeRange(ppcImlGenContext, subrangeItr); IMLRA_ExplodeRangeCluster(ppcImlGenContext, subrangeItr);
} }
return false; return false;
} }
@ -1336,7 +1338,7 @@ void IMLRA_ReshapeForRegisterAllocation(ppcImlGenContext_t* ppcImlGenContext)
for (size_t s = 0; s < ppcImlGenContext->segmentList2.size(); s++) for (size_t s = 0; s < ppcImlGenContext->segmentList2.size(); s++)
{ {
IMLSegment* imlSegment = ppcImlGenContext->segmentList2[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 inclusiveEnd--; // subtract one, because usageEnd is exclusive, but the end value of the interval passed to createSubrange is inclusive
raInterval interval; raInterval interval;
interval.SetInterval(abstractRange->usageStart, true, inclusiveEnd, true); 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 // traverse forward
if (abstractRange->usageEnd == RA_INTER_RANGE_END) 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 = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchTaken, vGPR, name);
subrange->subrangeBranchTaken->previousRanges.push_back(subrange); subrange->subrangeBranchTaken->previousRanges.push_back(subrange);
cemu_assert_debug(subrange->subrangeBranchTaken->interval2.ExtendsPreviousSegment()); cemu_assert_debug(subrange->subrangeBranchTaken->interval.ExtendsPreviousSegment());
} }
} }
if (imlSegment->nextSegmentBranchNotTaken) if (imlSegment->nextSegmentBranchNotTaken)
@ -1432,7 +1434,7 @@ raLivenessRange* PPCRecRA_convertToMappedRanges(IMLRegisterAllocatorContext& ctx
{ {
subrange->subrangeBranchNotTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchNotTaken, vGPR, name); subrange->subrangeBranchNotTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchNotTaken, vGPR, name);
subrange->subrangeBranchNotTaken->previousRanges.push_back(subrange); 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->_noLoad = isOverwritten;
subrange->hasStore = isWritten; subrange->hasStore = isWritten;
if (subrange->interval2.ExtendsPreviousSegment()) if (subrange->interval.ExtendsPreviousSegment())
subrange->_noLoad = true; subrange->_noLoad = true;
} }
@ -1796,7 +1798,7 @@ void _findSubrangeWriteEndings(raLivenessRange* subrange, uint32 iterationIndex,
if (subrange->hasStoreDelayed) if (subrange->hasStoreDelayed)
return; // no need to traverse this subrange return; // no need to traverse this subrange
IMLSegment* imlSegment = subrange->imlSegment; IMLSegment* imlSegment = subrange->imlSegment;
if (!subrange->interval2.ExtendsIntoNextSegment()) if (!subrange->interval.ExtendsIntoNextSegment())
{ {
// ending segment // ending segment
if (info->subrangeCount >= SUBRANGE_LIST_SIZE) if (info->subrangeCount >= SUBRANGE_LIST_SIZE)
@ -1839,7 +1841,7 @@ void _findSubrangeWriteEndings(raLivenessRange* subrange, uint32 iterationIndex,
static void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange) static void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange)
{ {
if (!subrange->interval2.ExtendsIntoNextSegment()) if (!subrange->interval.ExtendsIntoNextSegment())
return; return;
// analyze data flow across segments (if this segment has writes) // analyze data flow across segments (if this segment has writes)
if (subrange->hasStore) if (subrange->hasStore)
@ -1847,7 +1849,7 @@ static void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange)
subrangeEndingInfo_t writeEndingInfo; subrangeEndingInfo_t writeEndingInfo;
writeEndingInfo.subrangeCount = 0; writeEndingInfo.subrangeCount = 0;
writeEndingInfo.hasUndefinedEndings = false; writeEndingInfo.hasUndefinedEndings = false;
_findSubrangeWriteEndings(subrange, PPCRecRA_getNextIterationIndex(), 0, &writeEndingInfo); _findSubrangeWriteEndings(subrange, IMLRA_GetNextIterationIndex(), 0, &writeEndingInfo);
if (writeEndingInfo.hasUndefinedEndings == false) if (writeEndingInfo.hasUndefinedEndings == false)
{ {
// get cost of delaying store into endings // 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 currentEdge.Set(i, false); // set to instruction index on output edge
// activate ranges which begin before or during this instruction // 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 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(); auto it = activeRanges.begin();
while (it != activeRanges.end()) while (it != activeRanges.end())
{ {
if ((*it)->interval2.end <= currentEdge) if ((*it)->interval.end <= currentEdge)
{ {
virtId2PhysReg.erase((*it)->GetVirtualRegister()); virtId2PhysReg.erase((*it)->GetVirtualRegister());
it = activeRanges.erase(it); it = activeRanges.erase(it);
@ -1981,7 +1983,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
{ {
if (!currentRange->_noLoad) 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()); rebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());
} }
currentRange = currentRange->link_allSegmentRanges.next; currentRange = currentRange->link_allSegmentRanges.next;
@ -2001,9 +2003,9 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
while (currentRange) 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; currentRange = currentRange->link_allSegmentRanges.next;
} }
@ -2025,9 +2027,8 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
boost::container::small_vector<raLivenessRange*, 64> activeRanges; 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 // 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; raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;
// make all ranges active that start on RA_INTER_RANGE_START // 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); activeRanges.push_back(currentRange);
currentRange = currentRange->link_allSegmentRanges.next; currentRange = currentRange->link_allSegmentRanges.next;
@ -2038,7 +2039,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
firstOutputEdge.Set(0, false); firstOutputEdge.Set(0, false);
while (it != activeRanges.end()) while (it != activeRanges.end())
{ {
if ((*it)->interval2.end < firstOutputEdge) if ((*it)->interval.end < firstOutputEdge)
{ {
raLivenessRange* storedRange = *it; raLivenessRange* storedRange = *it;
if (storedRange->hasStore) if (storedRange->hasStore)
@ -2055,7 +2056,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
raInstructionEdge curEdge; raInstructionEdge curEdge;
// input edge // input edge
curEdge.SetRaw(i * 2 + 1); // +1 to include ranges that start at the output of the instruction 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) if (!currentRange->_noLoad)
{ {
@ -2072,11 +2073,9 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
auto it = activeRanges.begin(); auto it = activeRanges.begin();
while (it != activeRanges.end()) while (it != activeRanges.end())
{ {
if ((*it)->interval2.end <= curEdge) if ((*it)->interval.end <= curEdge)
{ {
// range expires // 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 // todo - check hasStore
raLivenessRange* storedRange = *it; raLivenessRange* storedRange = *it;
if (storedRange->hasStore) if (storedRange->hasStore)
@ -2084,7 +2083,6 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
cemu_assert_debug(i != numInstructionsWithoutSuffix); // not allowed to emit after suffix 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())); rebuiltInstructions.emplace_back().make_name_r(storedRange->GetName(), _MakeNativeReg(ctx.regIdToBaseFormat[storedRange->GetVirtualRegister()], storedRange->GetPhysicalRegister()));
} }
it = activeRanges.erase(it); it = activeRanges.erase(it);
continue; continue;
} }
@ -2109,7 +2107,7 @@ void IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IM
} }
while (currentRange) while (currentRange)
{ {
cemu_assert_debug(currentRange->interval2.IsNextSegmentOnly()); cemu_assert_debug(currentRange->interval.IsNextSegmentOnly());
cemu_assert_debug(!currentRange->_noLoad); cemu_assert_debug(!currentRange->_noLoad);
rebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName()); rebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());
currentRange = currentRange->link_allSegmentRanges.next; currentRange = currentRange->link_allSegmentRanges.next;

View File

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

View File

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

View File

@ -302,7 +302,7 @@ struct raFixedRegRequirement
struct raLivenessRange struct raLivenessRange
{ {
IMLSegment* imlSegment; IMLSegment* imlSegment;
raInterval interval2; raInterval interval;
// dirty state tracking // dirty state tracking
bool _noLoad; bool _noLoad;
@ -327,7 +327,7 @@ struct raLivenessRange
IMLRegID virtualRegister; IMLRegID virtualRegister;
IMLName name; IMLName name;
// register allocator result // register allocator result
sint32 physicalRegister; IMLPhysReg physicalRegister;
boost::container::small_vector<raLivenessRange*, 128> GetAllSubrangesInCluster(); 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 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; sint32 GetPhysicalRegister() const;
bool HasPhysicalRegister() const { return physicalRegister >= 0; } bool HasPhysicalRegister() const { return physicalRegister >= 0; }
IMLName GetName() const; IMLName GetName() const;
void SetPhysicalRegister(sint32 physicalRegister); void SetPhysicalRegister(IMLPhysReg physicalRegister);
void SetPhysicalRegisterForCluster(sint32 physicalRegister); void SetPhysicalRegisterForCluster(IMLPhysReg physicalRegister);
void UnsetPhysicalRegister() { physicalRegister = -1; } void UnsetPhysicalRegister() { physicalRegister = -1; }
private: private:
void GetAllowedRegistersExRecursive(raLivenessRange* range, uint32 iterationIndex, IMLPhysRegisterSet& allowedRegs); void GetAllowedRegistersExRecursive(raLivenessRange* range, uint32 iterationIndex, IMLPhysRegisterSet& allowedRegs);
}; };
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);
void PPCRecRA_deleteSubrange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange); void IMLRA_DeleteRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange);
void IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext); 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); void PPCRecRA_debugValidateSubrange(raLivenessRange* subrange);

View File

@ -19,6 +19,7 @@
#include "util/highresolutiontimer/HighResolutionTimer.h" #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_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 struct PPCInvalidationRange
{ {
@ -185,8 +186,10 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
ppcRecFunc->ppcAddress = range.startAddress; ppcRecFunc->ppcAddress = range.startAddress;
ppcRecFunc->ppcSize = range.length; ppcRecFunc->ppcSize = range.length;
#if PPCREC_LOG_RECOMPILATION_RESULTS
BenchmarkTimer bt; BenchmarkTimer bt;
bt.Start(); bt.Start();
#endif
// generate intermediate code // generate intermediate code
ppcImlGenContext_t ppcImlGenContext = { 0 }; ppcImlGenContext_t ppcImlGenContext = { 0 };
@ -217,18 +220,6 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
return nullptr; 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 // emit x64 code
bool x64GenerationSuccess = PPCRecompiler_generateX64Code(ppcRecFunc, &ppcImlGenContext); bool x64GenerationSuccess = PPCRecompiler_generateX64Code(ppcRecFunc, &ppcImlGenContext);
if (x64GenerationSuccess == false) if (x64GenerationSuccess == false)
@ -258,18 +249,16 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
entryPointsOut.emplace_back(ppcEnterOffset, x64Offset); entryPointsOut.emplace_back(ppcEnterOffset, x64Offset);
} }
#if PPCREC_LOG_RECOMPILATION_RESULTS
bt.Stop(); 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; uint32 codeHash = 0;
for (uint32 i = 0; i < ppcRecFunc->x86Size; i++) for (uint32 i = 0; i < ppcRecFunc->x86Size; i++)
{ {
codeHash = _rotr(codeHash, 3); codeHash = _rotr(codeHash, 3);
codeHash += ((uint8*)ppcRecFunc->x86Code)[i]; 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); 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; return ppcRecFunc;
} }

View File

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