mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
PPCRec: Make register pool for RA configurable
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,9 @@
|
||||
|
||||
struct x64RelocEntry_t
|
||||
{
|
||||
x64RelocEntry_t(uint32 offset, uint8 type, void* extraInfo) : offset(offset), type(type), extraInfo(extraInfo) {};
|
||||
x64RelocEntry_t(uint32 offset, void* extraInfo) : offset(offset), extraInfo(extraInfo) {};
|
||||
|
||||
uint32 offset;
|
||||
uint8 type;
|
||||
void* extraInfo;
|
||||
};
|
||||
|
||||
@@ -97,10 +96,6 @@ struct x64GenContext_t
|
||||
#define REG_RESV_FPR_TEMP (15)
|
||||
|
||||
|
||||
extern sint32 x64Gen_registerMap[12];
|
||||
|
||||
#define tempToRealRegister(__x) (x64Gen_registerMap[__x])
|
||||
#define tempToRealFPRRegister(__x) (__x)
|
||||
#define reg32ToReg16(__x) (__x)
|
||||
|
||||
enum
|
||||
@@ -128,9 +123,6 @@ enum
|
||||
#define PPCREC_CR_STATE_TYPE_SIGNED_ARITHMETIC (1) // for unsigned arithmetic operations (ADD, CMPI)
|
||||
#define PPCREC_CR_STATE_TYPE_LOGICAL (2) // for unsigned operations (CMPLI)
|
||||
|
||||
#define X64_RELOC_LINK_TO_PPC (1) // translate from ppc address to x86 offset
|
||||
#define X64_RELOC_LINK_TO_SEGMENT (2) // link to beginning of segment
|
||||
|
||||
#define PPC_X64_GPR_USABLE_REGISTERS (16-4)
|
||||
#define PPC_X64_FPR_USABLE_REGISTERS (16-1) // Use XMM0 - XMM14, XMM15 is the temp register
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ void PPCRecompilerX64Gen_imlInstruction_fpr_r_name(PPCRecFunction_t* PPCRecFunct
|
||||
uint32 name = imlInstruction->op_r_name.name;
|
||||
if( name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0+32) )
|
||||
{
|
||||
x64Gen_movupd_xmmReg_memReg128(x64GenContext, tempToRealFPRRegister(imlInstruction->op_r_name.registerIndex), REG_ESP, offsetof(PPCInterpreter_t, fpr)+sizeof(FPR_t)*(name-PPCREC_NAME_FPR0));
|
||||
x64Gen_movupd_xmmReg_memReg128(x64GenContext, imlInstruction->op_r_name.registerIndex, REG_ESP, offsetof(PPCInterpreter_t, fpr)+sizeof(FPR_t)*(name-PPCREC_NAME_FPR0));
|
||||
}
|
||||
else if( name >= PPCREC_NAME_TEMPORARY_FPR0 || name < (PPCREC_NAME_TEMPORARY_FPR0+8) )
|
||||
{
|
||||
x64Gen_movupd_xmmReg_memReg128(x64GenContext, tempToRealFPRRegister(imlInstruction->op_r_name.registerIndex), REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
|
||||
x64Gen_movupd_xmmReg_memReg128(x64GenContext, imlInstruction->op_r_name.registerIndex, REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -27,11 +27,11 @@ void PPCRecompilerX64Gen_imlInstruction_fpr_name_r(PPCRecFunction_t* PPCRecFunct
|
||||
uint32 name = imlInstruction->op_r_name.name;
|
||||
if( name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0+32) )
|
||||
{
|
||||
x64Gen_movupd_memReg128_xmmReg(x64GenContext, tempToRealFPRRegister(imlInstruction->op_r_name.registerIndex), REG_ESP, offsetof(PPCInterpreter_t, fpr)+sizeof(FPR_t)*(name-PPCREC_NAME_FPR0));
|
||||
x64Gen_movupd_memReg128_xmmReg(x64GenContext, imlInstruction->op_r_name.registerIndex, REG_ESP, offsetof(PPCInterpreter_t, fpr)+sizeof(FPR_t)*(name-PPCREC_NAME_FPR0));
|
||||
}
|
||||
else if( name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0+8) )
|
||||
{
|
||||
x64Gen_movupd_memReg128_xmmReg(x64GenContext, tempToRealFPRRegister(imlInstruction->op_r_name.registerIndex), REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
|
||||
x64Gen_movupd_memReg128_xmmReg(x64GenContext, imlInstruction->op_r_name.registerIndex, REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -268,11 +268,11 @@ void PPCRecompilerX64Gen_imlInstr_psq_load_generic(ppcImlGenContext_t* ppcImlGen
|
||||
bool PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)
|
||||
{
|
||||
PPCRecompilerX64Gen_crConditionFlags_forget(PPCRecFunction, ppcImlGenContext, x64GenContext);
|
||||
sint32 realRegisterXMM = tempToRealFPRRegister(imlInstruction->op_storeLoad.registerData);
|
||||
sint32 realRegisterMem = tempToRealRegister(imlInstruction->op_storeLoad.registerMem);
|
||||
sint32 realRegisterXMM = imlInstruction->op_storeLoad.registerData;
|
||||
sint32 realRegisterMem = imlInstruction->op_storeLoad.registerMem;
|
||||
sint32 realRegisterMem2 = PPC_REC_INVALID_REGISTER;
|
||||
if( indexed )
|
||||
realRegisterMem2 = tempToRealRegister(imlInstruction->op_storeLoad.registerMem2);
|
||||
realRegisterMem2 = imlInstruction->op_storeLoad.registerMem2;
|
||||
uint8 mode = imlInstruction->op_storeLoad.mode;
|
||||
|
||||
if( mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1 )
|
||||
@@ -384,7 +384,7 @@ bool PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction_t* PPCRecFunctio
|
||||
else if (mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1 ||
|
||||
mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0)
|
||||
{
|
||||
PPCRecompilerX64Gen_imlInstr_psq_load_generic(ppcImlGenContext, x64GenContext, mode, realRegisterXMM, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed, tempToRealRegister(imlInstruction->op_storeLoad.registerGQR));
|
||||
PPCRecompilerX64Gen_imlInstr_psq_load_generic(ppcImlGenContext, x64GenContext, mode, realRegisterXMM, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed, imlInstruction->op_storeLoad.registerGQR);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -579,11 +579,11 @@ void PPCRecompilerX64Gen_imlInstr_psq_store_generic(ppcImlGenContext_t* ppcImlGe
|
||||
bool PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)
|
||||
{
|
||||
PPCRecompilerX64Gen_crConditionFlags_forget(PPCRecFunction, ppcImlGenContext, x64GenContext);
|
||||
sint32 realRegisterXMM = tempToRealFPRRegister(imlInstruction->op_storeLoad.registerData);
|
||||
sint32 realRegisterMem = tempToRealRegister(imlInstruction->op_storeLoad.registerMem);
|
||||
sint32 realRegisterXMM = imlInstruction->op_storeLoad.registerData;
|
||||
sint32 realRegisterMem = imlInstruction->op_storeLoad.registerMem;
|
||||
sint32 realRegisterMem2 = PPC_REC_INVALID_REGISTER;
|
||||
if( indexed )
|
||||
realRegisterMem2 = tempToRealRegister(imlInstruction->op_storeLoad.registerMem2);
|
||||
realRegisterMem2 = imlInstruction->op_storeLoad.registerMem2;
|
||||
uint8 mode = imlInstruction->op_storeLoad.mode;
|
||||
if( mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0 )
|
||||
{
|
||||
@@ -670,7 +670,7 @@ bool PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction_t* PPCRecFuncti
|
||||
else if (mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1 ||
|
||||
mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0)
|
||||
{
|
||||
PPCRecompilerX64Gen_imlInstr_psq_store_generic(ppcImlGenContext, x64GenContext, mode, realRegisterXMM, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed, tempToRealRegister(imlInstruction->op_storeLoad.registerGQR));
|
||||
PPCRecompilerX64Gen_imlInstr_psq_store_generic(ppcImlGenContext, x64GenContext, mode, realRegisterXMM, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed, imlInstruction->op_storeLoad.registerGQR);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -24,9 +24,6 @@ void PPCRecompiler_optimizeDirectIntegerCopies(struct ppcImlGenContext_t* ppcIml
|
||||
void PPCRecompiler_optimizePSQLoadAndStore(struct ppcImlGenContext_t* ppcImlGenContext);
|
||||
void PPCRecompiler_reorderConditionModifyInstructions(struct ppcImlGenContext_t* ppcImlGenContext);
|
||||
|
||||
// register allocator
|
||||
void IMLRegisterAllocator_AllocateRegisters(struct ppcImlGenContext_t* ppcImlGenContext);
|
||||
|
||||
// debug
|
||||
void IMLDebug_DumpSegment(struct ppcImlGenContext_t* ctx, struct IMLSegment* imlSegment, sint32 segmentIndex, bool printLivenessRangeInfo = false);
|
||||
void IMLDebug_Dump(struct ppcImlGenContext_t* ppcImlGenContext);
|
||||
|
||||
@@ -6,104 +6,6 @@
|
||||
#include "../PPCRecompilerIml.h"
|
||||
#include "../BackendX64/BackendX64.h"
|
||||
|
||||
struct replacedRegisterTracker_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
sint32 instructionIndex;
|
||||
sint32 registerPreviousName;
|
||||
sint32 registerNewName;
|
||||
sint32 index; // new index
|
||||
sint32 previousIndex; // previous index (always out of range)
|
||||
bool nameMustBeMaintained; // must be stored before replacement and loaded after replacement ends
|
||||
}replacedRegisterEntry[PPC_X64_GPR_USABLE_REGISTERS];
|
||||
sint32 count;
|
||||
};
|
||||
|
||||
bool PPCRecompiler_findAvailableRegisterDepr(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexStart, replacedRegisterTracker_t* replacedRegisterTracker, sint32* registerIndex, sint32* registerName, bool* isUsed)
|
||||
{
|
||||
IMLUsedRegisters registersUsed;
|
||||
imlSegment->imlList[imlIndexStart].CheckRegisterUsage(®istersUsed);
|
||||
// mask all registers used by this instruction
|
||||
uint32 instructionReservedRegisterMask = 0;
|
||||
if( registersUsed.readNamedReg1 != -1 )
|
||||
instructionReservedRegisterMask |= (1<<(registersUsed.readNamedReg1));
|
||||
if( registersUsed.readNamedReg2 != -1 )
|
||||
instructionReservedRegisterMask |= (1<<(registersUsed.readNamedReg2));
|
||||
if( registersUsed.readNamedReg3 != -1 )
|
||||
instructionReservedRegisterMask |= (1<<(registersUsed.readNamedReg3));
|
||||
if( registersUsed.writtenNamedReg1 != -1 )
|
||||
instructionReservedRegisterMask |= (1<<(registersUsed.writtenNamedReg1));
|
||||
// mask all registers that are reserved for other replacements
|
||||
uint32 replacementReservedRegisterMask = 0;
|
||||
for(sint32 i=0; i<replacedRegisterTracker->count; i++)
|
||||
{
|
||||
replacementReservedRegisterMask |= (1<<replacedRegisterTracker->replacedRegisterEntry[i].index);
|
||||
}
|
||||
|
||||
// potential improvement: Scan ahead a few instructions and look for registers that are the least used (or ideally never used)
|
||||
|
||||
// pick available register
|
||||
const uint32 allRegisterMask = (1<<(PPC_X64_GPR_USABLE_REGISTERS+1))-1; // mask with set bit for every register
|
||||
uint32 reservedRegisterMask = instructionReservedRegisterMask | replacementReservedRegisterMask;
|
||||
cemu_assert(instructionReservedRegisterMask != allRegisterMask); // no usable register! (Need to store a register from the replacedRegisterTracker)
|
||||
sint32 usedRegisterIndex = -1;
|
||||
for(sint32 i=0; i<PPC_X64_GPR_USABLE_REGISTERS; i++)
|
||||
{
|
||||
if( (reservedRegisterMask&(1<<i)) == 0 )
|
||||
{
|
||||
if( (instructionReservedRegisterMask&(1<<i)) == 0 && ppcImlGenContext->mappedRegister[i] != -1 )
|
||||
{
|
||||
// register is reserved by segment -> In use
|
||||
*isUsed = true;
|
||||
*registerName = ppcImlGenContext->mappedRegister[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
*isUsed = false;
|
||||
*registerName = -1;
|
||||
}
|
||||
*registerIndex = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void PPCRecompiler_storeReplacedRegister(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, replacedRegisterTracker_t* replacedRegisterTracker, sint32 registerTrackerIndex, sint32* imlIndex)
|
||||
{
|
||||
// store register
|
||||
sint32 imlIndexEdit = *imlIndex;
|
||||
PPCRecompiler_pushBackIMLInstructions(imlSegment, imlIndexEdit, 1);
|
||||
// name_unusedRegister = unusedRegister
|
||||
IMLInstruction& imlInstructionItr = imlSegment->imlList[imlIndexEdit + 0];
|
||||
memset(&imlInstructionItr, 0x00, sizeof(IMLInstruction));
|
||||
imlInstructionItr.type = PPCREC_IML_TYPE_NAME_R;
|
||||
imlInstructionItr.crRegister = PPC_REC_INVALID_REGISTER;
|
||||
imlInstructionItr.operation = PPCREC_IML_OP_ASSIGN;
|
||||
imlInstructionItr.op_r_name.registerIndex = replacedRegisterTracker->replacedRegisterEntry[registerTrackerIndex].index;
|
||||
imlInstructionItr.op_r_name.name = replacedRegisterTracker->replacedRegisterEntry[registerTrackerIndex].registerNewName;
|
||||
imlIndexEdit++;
|
||||
// load new register if required
|
||||
if( replacedRegisterTracker->replacedRegisterEntry[registerTrackerIndex].nameMustBeMaintained )
|
||||
{
|
||||
PPCRecompiler_pushBackIMLInstructions(imlSegment, imlIndexEdit, 1);
|
||||
IMLInstruction& imlInstructionItr = imlSegment->imlList[imlIndexEdit];
|
||||
memset(&imlInstructionItr, 0x00, sizeof(IMLInstruction));
|
||||
imlInstructionItr.type = PPCREC_IML_TYPE_R_NAME;
|
||||
imlInstructionItr.crRegister = PPC_REC_INVALID_REGISTER;
|
||||
imlInstructionItr.operation = PPCREC_IML_OP_ASSIGN;
|
||||
imlInstructionItr.op_r_name.registerIndex = replacedRegisterTracker->replacedRegisterEntry[registerTrackerIndex].index;
|
||||
imlInstructionItr.op_r_name.name = replacedRegisterTracker->replacedRegisterEntry[registerTrackerIndex].registerPreviousName;//ppcImlGenContext->mappedRegister[replacedRegisterTracker.replacedRegisterEntry[i].index];
|
||||
imlIndexEdit += 1;
|
||||
}
|
||||
// move last entry to current one
|
||||
memcpy(replacedRegisterTracker->replacedRegisterEntry+registerTrackerIndex, replacedRegisterTracker->replacedRegisterEntry+replacedRegisterTracker->count-1, sizeof(replacedRegisterTracker->replacedRegisterEntry[0]));
|
||||
replacedRegisterTracker->count--;
|
||||
*imlIndex = imlIndexEdit;
|
||||
}
|
||||
|
||||
bool PPCRecompiler_reduceNumberOfFPRRegisters(ppcImlGenContext_t* ppcImlGenContext)
|
||||
{
|
||||
// only xmm0 to xmm14 may be used, xmm15 is reserved
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
#include "../PPCRecompiler.h"
|
||||
#include "../PPCRecompilerIml.h"
|
||||
#include "IMLRegisterAllocator.h"
|
||||
#include "IMLRegisterAllocatorRanges.h"
|
||||
|
||||
#include "../BackendX64/BackendX64.h"
|
||||
|
||||
struct IMLRegisterAllocatorContext
|
||||
{
|
||||
IMLRegisterAllocatorParameters* raParam;
|
||||
};
|
||||
|
||||
uint32 recRACurrentIterationIndex = 0;
|
||||
|
||||
uint32 PPCRecRA_getNextIterationIndex()
|
||||
@@ -212,10 +218,10 @@ typedef struct
|
||||
sint32 liveRangesCount;
|
||||
}raLiveRangeInfo_t;
|
||||
|
||||
// return a bitmask that contains only registers that are not used by any colliding range
|
||||
uint32 PPCRecRA_getAllowedRegisterMaskForFullRange(raLivenessRange_t* range)
|
||||
// mark occupied registers by any overlapping range as unavailable in physRegSet
|
||||
void PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange_t* range, IMLPhysRegisterSet& physRegSet)
|
||||
{
|
||||
uint32 physRegisterMask = (1 << PPC_X64_GPR_USABLE_REGISTERS) - 1;
|
||||
//uint32 physRegisterMask = (1 << PPC_X64_GPR_USABLE_REGISTERS) - 1;
|
||||
for (auto& subrange : range->list_subranges)
|
||||
{
|
||||
IMLSegment* imlSegment = subrange->imlSegment;
|
||||
@@ -233,14 +239,13 @@ uint32 PPCRecRA_getAllowedRegisterMaskForFullRange(raLivenessRange_t* range)
|
||||
(subrange->start.index == RA_INTER_RANGE_START && subrange->start.index == subrangeItr->start.index) ||
|
||||
(subrange->end.index == RA_INTER_RANGE_END && subrange->end.index == subrangeItr->end.index) )
|
||||
{
|
||||
if(subrangeItr->range->physicalRegister >= 0)
|
||||
physRegisterMask &= ~(1<<(subrangeItr->range->physicalRegister));
|
||||
if (subrangeItr->range->physicalRegister >= 0)
|
||||
physRegSet.SetReserved(subrangeItr->range->physicalRegister);
|
||||
}
|
||||
// next
|
||||
subrangeItr = subrangeItr->link_segmentSubrangesGPR.next;
|
||||
}
|
||||
}
|
||||
return physRegisterMask;
|
||||
}
|
||||
|
||||
bool _livenessRangeStartCompare(raLivenessSubrange_t* lhs, raLivenessSubrange_t* rhs) { return lhs->start.index < rhs->start.index; }
|
||||
@@ -326,7 +331,7 @@ void PPCRecRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegm
|
||||
// todo
|
||||
}
|
||||
|
||||
bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)
|
||||
bool PPCRecRA_assignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)
|
||||
{
|
||||
// sort subranges ascending by start index
|
||||
_sortSegmentAllSubrangesLinkedList(imlSegment);
|
||||
@@ -380,24 +385,22 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSe
|
||||
continue;
|
||||
}
|
||||
// find free register for this segment
|
||||
uint32 physRegisterMask = (1<<PPC_X64_GPR_USABLE_REGISTERS)-1;
|
||||
IMLPhysRegisterSet physRegSet = ctx.raParam->physicalRegisterPool;
|
||||
|
||||
for (sint32 f = 0; f < liveInfo.liveRangesCount; f++)
|
||||
{
|
||||
raLivenessSubrange_t* liverange = liveInfo.liveRangeList[f];
|
||||
if (liverange->range->physicalRegister < 0)
|
||||
assert_dbg();
|
||||
physRegisterMask &= ~(1<<liverange->range->physicalRegister);
|
||||
cemu_assert_debug(liverange->range->physicalRegister >= 0);
|
||||
physRegSet.SetReserved(liverange->range->physicalRegister);
|
||||
}
|
||||
// check intersections with other ranges and determine allowed registers
|
||||
uint32 allowedPhysRegisterMask = 0;
|
||||
uint32 unusedRegisterMask = physRegisterMask; // mask of registers that are currently not used (does not include range checks)
|
||||
if (physRegisterMask != 0)
|
||||
IMLPhysRegisterSet localAvailableRegsMask = physRegSet; // mask of registers that are currently not used (does not include range checks in other segments)
|
||||
if(physRegSet.HasAnyAvailable())
|
||||
{
|
||||
// check globally
|
||||
allowedPhysRegisterMask = PPCRecRA_getAllowedRegisterMaskForFullRange(subrangeItr->range);
|
||||
physRegisterMask &= allowedPhysRegisterMask;
|
||||
// check globally in all segments
|
||||
PPCRecRA_MaskOverlappingPhysRegForGlobalRange(subrangeItr->range, physRegSet);
|
||||
}
|
||||
if (physRegisterMask == 0)
|
||||
if (!physRegSet.HasAnyAvailable())
|
||||
{
|
||||
struct
|
||||
{
|
||||
@@ -480,14 +483,16 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSe
|
||||
spillStrategies.availableRegisterHole.physRegister = -1;
|
||||
if (currentIndex >= 0)
|
||||
{
|
||||
if (unusedRegisterMask != 0)
|
||||
if (localAvailableRegsMask.HasAnyAvailable())
|
||||
{
|
||||
for (sint32 t = 0; t < PPC_X64_GPR_USABLE_REGISTERS; t++)
|
||||
sint32 physRegItr = -1;
|
||||
while (true)
|
||||
{
|
||||
if ((unusedRegisterMask&(1 << t)) == 0)
|
||||
continue;
|
||||
physRegItr = localAvailableRegsMask.GetNextAvailableReg(physRegItr + 1);
|
||||
if (physRegItr < 0)
|
||||
break;
|
||||
// get size of potential hole for this register
|
||||
sint32 distance = PPCRecRA_countInstructionsUntilNextLocalPhysRegisterUse(imlSegment, currentIndex, t);
|
||||
sint32 distance = PPCRecRA_countInstructionsUntilNextLocalPhysRegisterUse(imlSegment, currentIndex, physRegItr);
|
||||
if (distance < 2)
|
||||
continue; // not worth consideration
|
||||
// calculate additional cost due to split
|
||||
@@ -500,7 +505,7 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSe
|
||||
{
|
||||
spillStrategies.availableRegisterHole.cost = cost;
|
||||
spillStrategies.availableRegisterHole.distance = distance;
|
||||
spillStrategies.availableRegisterHole.physRegister = t;
|
||||
spillStrategies.availableRegisterHole.physRegister = physRegItr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -611,16 +616,7 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSe
|
||||
return false;
|
||||
}
|
||||
// assign register to range
|
||||
sint32 registerIndex = -1;
|
||||
for (sint32 f = 0; f < PPC_X64_GPR_USABLE_REGISTERS; f++)
|
||||
{
|
||||
if ((physRegisterMask&(1 << f)) != 0)
|
||||
{
|
||||
registerIndex = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
subrangeItr->range->physicalRegister = registerIndex;
|
||||
subrangeItr->range->physicalRegister = physRegSet.GetFirstAvailableReg();
|
||||
// add to live ranges
|
||||
liveInfo.liveRangeList[liveInfo.liveRangesCount] = subrangeItr;
|
||||
liveInfo.liveRangesCount++;
|
||||
@@ -630,7 +626,7 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSe
|
||||
return true;
|
||||
}
|
||||
|
||||
void PPCRecRA_assignRegisters(ppcImlGenContext_t* ppcImlGenContext)
|
||||
void PPCRecRA_assignRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenContext_t* ppcImlGenContext)
|
||||
{
|
||||
// start with frequently executed segments first
|
||||
sint32 maxLoopDepth = 0;
|
||||
@@ -647,7 +643,7 @@ void PPCRecRA_assignRegisters(ppcImlGenContext_t* ppcImlGenContext)
|
||||
{
|
||||
if (segIt->loopDepth != d)
|
||||
continue;
|
||||
done = PPCRecRA_assignSegmentRegisters(ppcImlGenContext, segIt);
|
||||
done = PPCRecRA_assignSegmentRegisters(ctx, ppcImlGenContext, segIt);
|
||||
if (done == false)
|
||||
break;
|
||||
}
|
||||
@@ -997,8 +993,11 @@ void PPCRecompilerImm_reshapeForRegisterAllocation(ppcImlGenContext_t* ppcImlGen
|
||||
}
|
||||
}
|
||||
|
||||
void IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext)
|
||||
void IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLRegisterAllocatorParameters& raParam)
|
||||
{
|
||||
IMLRegisterAllocatorContext ctx;
|
||||
ctx.raParam = &raParam;
|
||||
|
||||
PPCRecompilerImm_reshapeForRegisterAllocation(ppcImlGenContext);
|
||||
|
||||
ppcImlGenContext->raInfo.list_ranges = std::vector<raLivenessRange_t*>();
|
||||
@@ -1006,7 +1005,7 @@ void IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext
|
||||
PPCRecRA_calculateLivenessRangesV2(ppcImlGenContext);
|
||||
PPCRecRA_processFlowAndCalculateLivenessRangesV2(ppcImlGenContext);
|
||||
|
||||
PPCRecRA_assignRegisters(ppcImlGenContext);
|
||||
PPCRecRA_assignRegisters(ctx, ppcImlGenContext);
|
||||
|
||||
PPCRecRA_analyzeRangeDataFlowV2(ppcImlGenContext);
|
||||
PPCRecRA_generateMoveInstructions(ppcImlGenContext);
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
// container for storing a set of register indices
|
||||
// specifically optimized towards storing physical register indices (expected to be below 64)
|
||||
class IMLPhysRegisterSet
|
||||
{
|
||||
public:
|
||||
void SetAvailable(uint32 index)
|
||||
{
|
||||
cemu_assert_debug(index < 64);
|
||||
m_regBitmask |= ((uint64)1 << index);
|
||||
}
|
||||
|
||||
void SetReserved(uint32 index)
|
||||
{
|
||||
cemu_assert_debug(index < 64);
|
||||
m_regBitmask &= ~((uint64)1 << index);
|
||||
}
|
||||
|
||||
bool IsAvailable(uint32 index) const
|
||||
{
|
||||
return (m_regBitmask & (1 << index)) != 0;
|
||||
}
|
||||
|
||||
IMLPhysRegisterSet& operator&=(const IMLPhysRegisterSet& other)
|
||||
{
|
||||
this->m_regBitmask &= other.m_regBitmask;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IMLPhysRegisterSet& operator=(const IMLPhysRegisterSet& other)
|
||||
{
|
||||
this->m_regBitmask = other.m_regBitmask;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HasAnyAvailable() const
|
||||
{
|
||||
return m_regBitmask != 0;
|
||||
}
|
||||
|
||||
// returns index of first available register. Do not call when HasAnyAvailable() == false
|
||||
uint32 GetFirstAvailableReg()
|
||||
{
|
||||
cemu_assert_debug(m_regBitmask != 0);
|
||||
uint32 regIndex = 0;
|
||||
auto tmp = m_regBitmask;
|
||||
while ((tmp & 0xFF) == 0)
|
||||
{
|
||||
regIndex += 8;
|
||||
tmp >>= 8;
|
||||
}
|
||||
while ((tmp & 0x1) == 0)
|
||||
{
|
||||
regIndex++;
|
||||
tmp >>= 1;
|
||||
}
|
||||
return regIndex;
|
||||
}
|
||||
|
||||
// returns index of next available register (search includes any register index >= startIndex)
|
||||
// returns -1 if there is no more register
|
||||
sint32 GetNextAvailableReg(sint32 startIndex)
|
||||
{
|
||||
if (startIndex >= 64)
|
||||
return -1;
|
||||
uint32 regIndex = startIndex;
|
||||
auto tmp = m_regBitmask;
|
||||
tmp >>= regIndex;
|
||||
if (!tmp)
|
||||
return -1;
|
||||
while ((tmp & 0xFF) == 0)
|
||||
{
|
||||
regIndex += 8;
|
||||
tmp >>= 8;
|
||||
}
|
||||
while ((tmp & 0x1) == 0)
|
||||
{
|
||||
regIndex++;
|
||||
tmp >>= 1;
|
||||
}
|
||||
return regIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 m_regBitmask{ 0 };
|
||||
};
|
||||
|
||||
|
||||
struct IMLRegisterAllocatorParameters
|
||||
{
|
||||
IMLPhysRegisterSet physicalRegisterPool;
|
||||
};
|
||||
|
||||
void IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLRegisterAllocatorParameters& raParam);
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "util/MemMapper/MemMapper.h"
|
||||
|
||||
#include "IML/IML.h"
|
||||
#include "IML/IMLRegisterAllocator.h"
|
||||
#include "BackendX64/BackendX64.h"
|
||||
|
||||
struct PPCInvalidationRange
|
||||
@@ -272,7 +273,21 @@ bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
|
||||
}
|
||||
}
|
||||
|
||||
IMLRegisterAllocator_AllocateRegisters(&ppcImlGenContext);
|
||||
IMLRegisterAllocatorParameters raParam;
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RAX);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RDX);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RBX);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RBP);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RSI);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RDI);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_R8);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_R9);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_R10);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_R11);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_R12);
|
||||
raParam.physicalRegisterPool.SetAvailable(REG_RCX);
|
||||
|
||||
IMLRegisterAllocator_AllocateRegisters(&ppcImlGenContext, raParam);
|
||||
|
||||
// remove redundant name load and store instructions
|
||||
PPCRecompiler_reorderConditionModifyInstructions(&ppcImlGenContext);
|
||||
|
||||
Reference in New Issue
Block a user