PPCRec: Implement MFCR and MTCRF

This commit is contained in:
Exzap
2023-03-13 05:10:44 +01:00
parent 97e39e37fc
commit 3590ad9099
12 changed files with 60 additions and 921 deletions
@@ -680,31 +680,6 @@ bool PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction,
cemu_assert_debug((imlInstruction->op_r_immS32.immS32 & 0x80) == 0);
x64Gen_rol_reg64Low32_imm8(x64GenContext, regR, (uint8)imlInstruction->op_r_immS32.immS32);
}
else if( imlInstruction->operation == PPCREC_IML_OP_MFCR )
{
DEBUG_BREAK;
//uint32 destRegister = imlInstruction->op_r_immS32.registerIndex;
//x64Gen_xor_reg64Low32_reg64Low32(x64GenContext, destRegister, destRegister);
//for(sint32 f=0; f<32; f++)
//{
// x64Gen_bt_mem8(x64GenContext, X86_REG_RSP, offsetof(PPCInterpreter_t, cr)+f, 0);
// x64Gen_adc_reg64Low32_reg64Low32(x64GenContext, destRegister, destRegister);
//}
}
else if (imlInstruction->operation == PPCREC_IML_OP_MTCRF)
{
DEBUG_BREAK;
//uint32 srcRegister = imlInstruction->op_r_immS32.registerIndex;
//uint32 crBitMask = ppc_MTCRFMaskToCRBitMask((uint32)imlInstruction->op_r_immS32.immS32);
//for (sint32 f = 0; f < 32; f++)
//{
// if(((crBitMask >> f) & 1) == 0)
// continue;
// x64Gen_mov_mem8Reg64_imm8(x64GenContext, X86_REG_ESP, offsetof(PPCInterpreter_t, cr) + sizeof(uint8) * (f), 0);
// x64Gen_test_reg64Low32_imm32(x64GenContext, srcRegister, 0x80000000>>f);
// x64Gen_setcc_mem8(x64GenContext, X86_CONDITION_NOT_EQUAL, X86_REG_ESP, offsetof(PPCInterpreter_t, cr) + sizeof(uint8) * (f));
//}
}
else
{
debug_printf("PPCRecompilerX64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\n", imlInstruction->operation);
@@ -1582,14 +1557,6 @@ bool PPCRecompiler_generateX64Code(PPCRecFunction_t* PPCRecFunction, ppcImlGenCo
{
// no op
}
else if( imlInstruction->type == PPCREC_IML_TYPE_FPR_R_NAME )
{
PPCRecompilerX64Gen_imlInstruction_fpr_r_name(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);
}
else if( imlInstruction->type == PPCREC_IML_TYPE_FPR_NAME_R )
{
PPCRecompilerX64Gen_imlInstruction_fpr_name_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);
}
else if( imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD )
{
if( PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, false) == false )
@@ -34,42 +34,6 @@ static x86Assembler64::GPR8_REX _reg8_from_reg32(x86Assembler64::GPR32 regId)
return (x86Assembler64::GPR8_REX)regId;
}
void PPCRecompilerX64Gen_imlInstruction_fpr_r_name(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)
{
uint32 name = imlInstruction->op_r_name.name;
uint32 fprReg = _regF64(imlInstruction->op_r_name.regR);
if( name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0+32) )
{
x64Gen_movupd_xmmReg_memReg128(x64GenContext, fprReg, X86_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, fprReg, X86_REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
}
else
{
cemu_assert_debug(false);
}
}
void PPCRecompilerX64Gen_imlInstruction_fpr_name_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)
{
uint32 name = imlInstruction->op_r_name.name;
uint32 fprReg = _regF64(imlInstruction->op_r_name.regR);
if( name >= PPCREC_NAME_FPR0 && name < (PPCREC_NAME_FPR0+32) )
{
x64Gen_movupd_memReg128_xmmReg(x64GenContext, fprReg, X86_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, fprReg, X86_REG_ESP, offsetof(PPCInterpreter_t, temporaryFPR)+sizeof(FPR_t)*(name-PPCREC_NAME_TEMPORARY_FPR0));
}
else
{
cemu_assert_debug(false);
}
}
void PPCRecompilerX64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, sint32 registerXMM, bool isLoad, bool scalePS1, IMLReg registerGQR)
{
// load GQR
+3 -14
View File
@@ -4,24 +4,13 @@
#include "IMLSegment.h"
// analyzer
struct PPCRecCRTracking_t
{
uint32 readCRBits;
uint32 writtenCRBits;
};
bool IMLAnalyzer_IsTightFiniteLoop(IMLSegment* imlSegment);
bool IMLAnalyzer_CanTypeWriteCR(IMLInstruction* imlInstruction);
// optimizer passes
// todo - rename
//bool PPCRecompiler_reduceNumberOfFPRRegisters(struct ppcImlGenContext_t* ppcImlGenContext);
//bool PPCRecompiler_manageFPRRegisters(struct ppcImlGenContext_t* ppcImlGenContext);
void PPCRecompiler_optimizeDirectFloatCopies(struct ppcImlGenContext_t* ppcImlGenContext);
void PPCRecompiler_optimizeDirectIntegerCopies(struct ppcImlGenContext_t* ppcImlGenContext);
void IMLOptimizer_OptimizeDirectFloatCopies(struct ppcImlGenContext_t* ppcImlGenContext);
void IMLOptimizer_OptimizeDirectIntegerCopies(struct ppcImlGenContext_t* ppcImlGenContext);
void PPCRecompiler_optimizePSQLoadAndStore(struct ppcImlGenContext_t* ppcImlGenContext);
void PPCRecompiler_reorderConditionModifyInstructions(struct ppcImlGenContext_t* ppcImlGenContext);
// debug
void IMLDebug_DumpSegment(struct ppcImlGenContext_t* ctx, struct IMLSegment* imlSegment, sint32 segmentIndex, bool printLivenessRangeInfo = false);
void IMLDebug_DumpSegment(struct ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool printLivenessRangeInfo = false);
void IMLDebug_Dump(struct ppcImlGenContext_t* ppcImlGenContext, bool printLivenessRangeInfo = false);
@@ -52,40 +52,4 @@ bool IMLAnalyzer_IsTightFiniteLoop(IMLSegment* imlSegment)
}
}
return false;
}
/*
* Returns true if the instruction can overwrite CR (depending on value of ->crRegister)
*/
bool IMLAnalyzer_CanTypeWriteCR(IMLInstruction* imlInstruction)
{
if (imlInstruction->type == PPCREC_IML_TYPE_R_R)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_R_S32)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R_R)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R)
return true;
// new instructions
if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE || imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R_CARRY)
return true;
if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32_CARRY)
return true;
return false;
}
}
@@ -60,7 +60,7 @@ std::string IMLDebug_GetRegName(IMLReg r)
regName.append("r");
break;
default:
__debugbreak();
DEBUG_BREAK;
}
regName.append(fmt::format("{}", regId));
return regName;
@@ -417,36 +417,6 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
strOutput.addFmt("MACRO ukn operation {}", inst.operation);
}
}
else if (inst.type == PPCREC_IML_TYPE_FPR_R_NAME)
{
strOutput.addFmt("fpr_t{} = name_{} (", inst.op_r_name.regR.GetRegID(), inst.op_r_name.name);
if (inst.op_r_name.name >= PPCREC_NAME_FPR0 && inst.op_r_name.name < (PPCREC_NAME_FPR0 + 999))
{
strOutput.addFmt("fpr{}", inst.op_r_name.name - PPCREC_NAME_FPR0);
}
else if (inst.op_r_name.name >= PPCREC_NAME_TEMPORARY_FPR0 && inst.op_r_name.name < (PPCREC_NAME_TEMPORARY_FPR0 + 999))
{
strOutput.addFmt("tempFpr{}", inst.op_r_name.name - PPCREC_NAME_TEMPORARY_FPR0);
}
else
strOutput.add("ukn");
strOutput.add(")");
}
else if (inst.type == PPCREC_IML_TYPE_FPR_NAME_R)
{
strOutput.addFmt("name_{} (", inst.op_r_name.name);
if (inst.op_r_name.name >= PPCREC_NAME_FPR0 && inst.op_r_name.name < (PPCREC_NAME_FPR0 + 999))
{
strOutput.addFmt("fpr{}", inst.op_r_name.name - PPCREC_NAME_FPR0);
}
else if (inst.op_r_name.name >= PPCREC_NAME_TEMPORARY_FPR0 && inst.op_r_name.name < (PPCREC_NAME_TEMPORARY_FPR0 + 999))
{
strOutput.addFmt("tempFpr{}", inst.op_r_name.name - PPCREC_NAME_TEMPORARY_FPR0);
}
else
strOutput.add("ukn");
strOutput.addFmt(") = {}", IMLDebug_GetRegName(inst.op_r_name.regR));
}
else if (inst.type == PPCREC_IML_TYPE_FPR_LOAD)
{
strOutput.addFmt("{} = ", IMLDebug_GetRegName(inst.op_storeLoad.registerData));
@@ -56,12 +56,7 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
operation != PPCREC_IML_OP_OR &&
operation != PPCREC_IML_OP_XOR); // deprecated, use r_r_s32 for these
if (operation == PPCREC_IML_OP_MTCRF)
{
// operand register is read only
registersUsed->readGPR1 = op_r_immS32.regR;
}
else if (operation == PPCREC_IML_OP_LEFT_ROTATE)
if (operation == PPCREC_IML_OP_LEFT_ROTATE)
{
// operand register is read and write
registersUsed->readGPR1 = op_r_immS32.regR;
@@ -221,16 +216,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
registersUsed->readGPR3 = op_atomic_compare_store.regWriteValue;
registersUsed->writtenGPR1 = op_atomic_compare_store.regBoolOut;
}
else if (type == PPCREC_IML_TYPE_FPR_R_NAME)
{
// fpr operation
registersUsed->writtenFPR1 = op_r_name.regR;
}
else if (type == PPCREC_IML_TYPE_FPR_NAME_R)
{
// fpr operation
registersUsed->readFPR1 = op_r_name.regR;
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
// fpr load operation
@@ -636,14 +621,6 @@ void IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& tr
op_atomic_compare_store.regWriteValue = replaceRegisterIdMultiple(op_atomic_compare_store.regWriteValue, translationTable);
op_atomic_compare_store.regBoolOut = replaceRegisterIdMultiple(op_atomic_compare_store.regBoolOut, translationTable);
}
else if (type == PPCREC_IML_TYPE_FPR_R_NAME)
{
op_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, translationTable);
}
else if (type == PPCREC_IML_TYPE_FPR_NAME_R)
{
op_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, translationTable);
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);
@@ -766,14 +743,6 @@ void IMLInstruction::ReplaceFPRs(IMLReg fprRegisterSearched[4], IMLReg fprRegist
{
;
}
else if (type == PPCREC_IML_TYPE_FPR_R_NAME)
{
op_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_NAME_R)
{
op_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
op_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
@@ -885,14 +854,6 @@ void IMLInstruction::ReplaceFPR(IMLRegID fprRegisterSearched, IMLRegID fprRegist
{
;
}
else if (type == PPCREC_IML_TYPE_FPR_R_NAME)
{
op_r_name.regR = replaceRegisterId(op_r_name.regR, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_NAME_R)
{
op_r_name.regR = replaceRegisterId(op_r_name.regR, fprRegisterSearched, fprRegisterReplaced);
}
else if (type == PPCREC_IML_TYPE_FPR_LOAD)
{
op_storeLoad.registerData = replaceRegisterId(op_storeLoad.registerData, fprRegisterSearched, fprRegisterReplaced);
@@ -125,8 +125,6 @@ enum
PPCREC_IML_OP_SRW, // SRW (shift based on register by up to 63 bits)
PPCREC_IML_OP_CNTLZW,
PPCREC_IML_OP_DCBZ, // clear 32 bytes aligned to 0x20
PPCREC_IML_OP_MFCR, // copy cr to gpr
PPCREC_IML_OP_MTCRF, // copy gpr to cr (with mask)
// FPU
PPCREC_IML_OP_FPR_ADD_BOTTOM,
PPCREC_IML_OP_FPR_ADD_PAIR,
@@ -253,8 +251,6 @@ enum
PPCREC_IML_TYPE_CONDITIONAL_R_S32,
// FPR
PPCREC_IML_TYPE_FPR_R_NAME, // name = f*
PPCREC_IML_TYPE_FPR_NAME_R, // f* = name
PPCREC_IML_TYPE_FPR_LOAD, // r* = (bitdepth) [r*+s32*] (single or paired single mode)
PPCREC_IML_TYPE_FPR_LOAD_INDEXED, // r* = (bitdepth) [r*+r*] (single or paired single mode)
PPCREC_IML_TYPE_FPR_STORE, // (bitdepth) [r*+s32*] = r* (single or paired single mode)
@@ -412,20 +408,6 @@ struct IMLUsedRegisters
F(writtenFPR1, true);
}
//bool HasSameBaseFPRRegId(IMLRegID regId) const
//{
// if (readFPR1.IsValid() && readFPR1.GetRegID() == regId)
// return true;
// if (readFPR2.IsValid() && readFPR2.GetRegID() == regId)
// return true;
// if (readFPR3.IsValid() && readFPR3.GetRegID() == regId)
// return true;
// if (readFPR4.IsValid() && readFPR4.GetRegID() == regId)
// return true;
// if (writtenFPR1.IsValid() && writtenFPR1.GetRegID() == regId)
// return true;
// return false;
//}
};
struct IMLInstruction
File diff suppressed because it is too large Load Diff
@@ -423,3 +423,4 @@ sint32 PPCRecRARange_estimateAdditionalCostAfterSplit(raLivenessSubrange_t* subr
return cost;
}
@@ -71,34 +71,21 @@ struct PPCSegmentRegisterAllocatorInfo_t
struct IMLSegment
{
sint32 momentaryIndex{}; // index in segment list, generally not kept up to date except if needed (necessary for loop detection)
sint32 startOffset{}; // offset to first instruction in iml instruction list
sint32 count{}; // number of instructions in segment
sint32 loopDepth{};
uint32 ppcAddress{}; // ppc address (0xFFFFFFFF if not associated with an address)
uint32 x64Offset{}; // x64 code offset of segment start
uint32 cycleCount{}; // number of PPC cycles required to execute this segment (roughly)
// list of intermediate instructions in this segment
std::vector<IMLInstruction> imlList;
// segment link
IMLSegment* nextSegmentBranchNotTaken{}; // this is also the default for segments where there is no branch
IMLSegment* nextSegmentBranchTaken{};
bool nextSegmentIsUncertain{};
sint32 loopDepth{};
std::vector<IMLSegment*> list_prevSegments{};
// PPC range of segment
uint32 ppcAddrMin{};
uint32 ppcAddrMax{};
// enterable segments
bool isEnterable{}; // this segment can be entered from outside the recompiler (no preloaded registers necessary)
uint32 enterPPCAddress{}; // used if isEnterable is true
// PPC FPR use mask
//bool ppcFPRUsed[32]{}; // same as ppcGPRUsed, but for FPR
// CR use mask
uint32 crBitsInput{}; // bits that are expected to be set from the previous segment (read in this segment but not overwritten)
uint32 crBitsRead{}; // all bits that are read in this segment
uint32 crBitsWritten{}; // bits that are written in this segment
// register allocator info
PPCSegmentRegisterAllocatorInfo_t raInfo{};
// segment state API
void SetEnterable(uint32 enterAddress);
void SetLinkBranchNotTaken(IMLSegment* imlSegmentDst);
@@ -245,63 +245,13 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
return ppcRecFunc;
}
bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
void PPCRecompiler_NativeRegisterAllocatorPass(ppcImlGenContext_t& ppcImlGenContext)
{
// isolate entry points from function flow (enterable segments must not be the target of any other segment)
// this simplifies logic during register allocation
PPCRecompilerIML_isolateEnterableSegments(&ppcImlGenContext);
// if GQRs can be predicted, optimize PSQ load/stores
PPCRecompiler_optimizePSQLoadAndStore(&ppcImlGenContext);
// insert name store instructions at the end of each segment but before branch instructions
//for (IMLSegment* segIt : ppcImlGenContext.segmentList2)
//{
// if (segIt->imlList.size() == 0)
// continue; // ignore empty segments
// // analyze segment for register usage
// IMLUsedRegisters registersUsed;
// for (sint32 i = 0; i < segIt->imlList.size(); i++)
// {
// segIt->imlList[i].CheckRegisterUsage(&registersUsed);
// IMLReg accessedTempReg[5];
// // intermediate FPRs
// accessedTempReg[0] = registersUsed.readFPR1;
// accessedTempReg[1] = registersUsed.readFPR2;
// accessedTempReg[2] = registersUsed.readFPR3;
// accessedTempReg[3] = registersUsed.readFPR4;
// accessedTempReg[4] = registersUsed.writtenFPR1;
// for (sint32 f = 0; f < 5; f++)
// {
// if (accessedTempReg[f].IsInvalid())
// continue;
// uint32 regName = ppcImlGenContext.mappedFPRRegister[accessedTempReg[f].GetRegID()];
// if (regName >= PPCREC_NAME_FPR0 && regName < PPCREC_NAME_FPR0 + 32)
// {
// segIt->ppcFPRUsed[regName - PPCREC_NAME_FPR0] = true;
// }
// }
// }
//}
// merge certain float load+store patterns (must happen before FPR register remapping)
PPCRecompiler_optimizeDirectFloatCopies(&ppcImlGenContext);
// delay byte swapping for certain load+store patterns
PPCRecompiler_optimizeDirectIntegerCopies(&ppcImlGenContext);
//if (numLoadedFPRRegisters > 0)
//{
// if (PPCRecompiler_manageFPRRegisters(&ppcImlGenContext) == false)
// {
// return false;
// }
//}
IMLRegisterAllocatorParameters raParam;
for (auto& it : ppcImlGenContext.mappedRegs)
raParam.regIdToName.try_emplace(it.second.GetRegID(), it.first);
auto& gprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::I64);
gprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RAX);
gprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RDX);
@@ -335,6 +285,23 @@ bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
fprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 14);
IMLRegisterAllocator_AllocateRegisters(&ppcImlGenContext, raParam);
}
bool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)
{
// isolate entry points from function flow (enterable segments must not be the target of any other segment)
// this simplifies logic during register allocation
PPCRecompilerIML_isolateEnterableSegments(&ppcImlGenContext);
// if GQRs can be predicted, optimize PSQ load/stores
PPCRecompiler_optimizePSQLoadAndStore(&ppcImlGenContext);
// merge certain float load+store patterns (must happen before FPR register remapping)
IMLOptimizer_OptimizeDirectFloatCopies(&ppcImlGenContext);
// delay byte swapping for certain load+store patterns
IMLOptimizer_OptimizeDirectIntegerCopies(&ppcImlGenContext);
PPCRecompiler_NativeRegisterAllocatorPass(ppcImlGenContext);
//PPCRecompiler_reorderConditionModifyInstructions(&ppcImlGenContext);
//PPCRecompiler_removeRedundantCRUpdates(&ppcImlGenContext);
@@ -355,7 +322,7 @@ bool PPCRecompiler_makeRecompiledFunctionActive(uint32 initialEntryPoint, PPCFun
return false;
}
// check if the current range got invalidated in the time it took to recompile it
// check if the current range got invalidated during the time it took to recompile it
bool isInvalidated = false;
for (auto& invRange : PPCRecompilerState.invalidationRanges)
{
@@ -168,7 +168,7 @@ IMLName PPCRecompilerImlGen_GetRegName(ppcImlGenContext_t* ppcImlGenContext, IML
uint32 PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)
{
__debugbreak();
DEBUG_BREAK;
//if( mappedName == PPCREC_NAME_NONE )
//{
// debug_printf("PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(): Invalid mappedName parameter\n");
@@ -187,7 +187,7 @@ uint32 PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(ppcImlGenContext_t* ppcIml
uint32 PPCRecompilerImlGen_findFPRRegisterByMappedName(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)
{
__debugbreak();
DEBUG_BREAK;
//for(uint32 i=0; i<255; i++)
//{
// if( ppcImlGenContext->mappedFPRRegister[i] == mappedName )
@@ -242,14 +242,6 @@ IMLReg _GetRegTemporaryS8(ppcImlGenContext_t* ppcImlGenContext, uint32 index)
*/
IMLReg PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName, bool loadNew)
{
//if( loadNew == false )
//{
// uint32 loadedRegisterIndex = PPCRecompilerImlGen_findFPRRegisterByMappedName(ppcImlGenContext, mappedName);
// if( loadedRegisterIndex != PPC_REC_INVALID_REGISTER )
// return IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, loadedRegisterIndex);
//}
//uint32 registerIndex = PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(ppcImlGenContext, mappedName);
//return IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, registerIndex);
return PPCRecompilerImlGen_LookupReg(ppcImlGenContext, mappedName, IMLRegFormat::F64);
}
@@ -259,11 +251,6 @@ IMLReg PPCRecompilerImlGen_loadFPRRegister(ppcImlGenContext_t* ppcImlGenContext,
*/
IMLReg PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)
{
//uint32 loadedRegisterIndex = PPCRecompilerImlGen_findFPRRegisterByMappedName(ppcImlGenContext, mappedName);
//if( loadedRegisterIndex != PPC_REC_INVALID_REGISTER )
// return IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, loadedRegisterIndex);
//uint32 registerIndex = PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(ppcImlGenContext, mappedName);
//return IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, registerIndex);
return PPCRecompilerImlGen_LookupReg(ppcImlGenContext, mappedName, IMLRegFormat::F64);
}
@@ -434,27 +421,38 @@ bool PPCRecompilerImlGen_MFTB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
bool PPCRecompilerImlGen_MFCR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
printf("MFCR: Not implemented\n");
return false;
//sint32 rD, rA, rB;
//PPC_OPC_TEMPL_X(opcode, rD, rA, rB);
//uint32 gprReg = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_R0 + rD);
//ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_MFCR, gprReg, 0);
//return true;
sint32 rD, rA, rB;
PPC_OPC_TEMPL_X(opcode, rD, rA, rB);
IMLReg regD = _GetRegGPR(ppcImlGenContext, rD);
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regD, 0);
for (sint32 i = 0; i < 32; i++)
{
IMLReg regCrBit = _GetRegCR(ppcImlGenContext, i);
cemu_assert_debug(regCrBit.GetRegFormat() == IMLRegFormat::I32); // addition is only allowed between same-format regs
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, regD, regD, 1);
ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regD, regD, regCrBit);
}
return true;
}
bool PPCRecompilerImlGen_MTCRF(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
printf("MTCRF: Not implemented\n");
return false;
//uint32 rS;
//uint32 crMask;
//PPC_OPC_TEMPL_XFX(opcode, rS, crMask);
//uint32 gprReg = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_R0 + rS);
//ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_MTCRF, gprReg, crMask);
//return true;
uint32 rS;
uint32 crMask;
PPC_OPC_TEMPL_XFX(opcode, rS, crMask);
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
IMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);
uint32 crBitMask = ppc_MTCRFMaskToCRBitMask(crMask);
for (sint32 f = 0; f < 32; f++)
{
if(((crBitMask >> f) & 1) == 0)
continue;
IMLReg regCrBit = _GetRegCR(ppcImlGenContext, f);
cemu_assert_debug(regCrBit.GetRegFormat() == IMLRegFormat::I32);
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, regTmp, regS, (31-f));
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regCrBit, regTmp, 1);
}
return true;
}
void PPCRecompilerImlGen_CMP(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isUnsigned)