PPCRec: Unify BCCTR and BCLR code

Instead of having fixed macros for BCCTR/BCCTRL/BCLR/BCLRL we now have only one single macro instruction that takes the jump destination as a register parameter.
This also allows us to reuse an already loaded LR register (by something like MTLR) instead of loading it again from memory.

As a necessary requirement for this: The register allocator now has support for read operations in suffix instructions
This commit is contained in:
Exzap 2022-12-12 14:13:46 +01:00
parent a5f6faac8a
commit 8d972d2500
6 changed files with 95 additions and 271 deletions

View File

@ -119,30 +119,12 @@ void ATTR_MS_ABI PPCRecompiler_getTBU(PPCInterpreter_t* hCPU, uint32 gprIndex)
bool PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)
{
PPCRecompilerX64Gen_crConditionFlags_forget(PPCRecFunction, ppcImlGenContext, x64GenContext);
if( imlInstruction->operation == PPCREC_IML_MACRO_BLR || imlInstruction->operation == PPCREC_IML_MACRO_BLRL )
if (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG)
{
uint32 currentInstructionAddress = imlInstruction->op_macro.param;
// MOV EDX, [SPR_LR]
x64Emit_mov_reg64_mem32(x64GenContext, REG_RDX, REG_RSP, offsetof(PPCInterpreter_t, spr.LR));
// if BLRL, then update SPR LR
if (imlInstruction->operation == PPCREC_IML_MACRO_BLRL)
x64Gen_mov_mem32Reg64_imm32(x64GenContext, REG_RSP, offsetof(PPCInterpreter_t, spr.LR), currentInstructionAddress + 4);
// JMP [offset+RDX*(8/4)+R15]
x64Gen_writeU8(x64GenContext, 0x41);
x64Gen_writeU8(x64GenContext, 0xFF);
x64Gen_writeU8(x64GenContext, 0xA4);
x64Gen_writeU8(x64GenContext, 0x57);
x64Gen_writeU32(x64GenContext, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));
return true;
}
else if( imlInstruction->operation == PPCREC_IML_MACRO_BCTR || imlInstruction->operation == PPCREC_IML_MACRO_BCTRL )
{
uint32 currentInstructionAddress = imlInstruction->op_macro.param;
// MOV EDX, [SPR_CTR]
x64Emit_mov_reg64_mem32(x64GenContext, REG_RDX, REG_RSP, offsetof(PPCInterpreter_t, spr.CTR));
// if BCTRL, then update SPR LR
if (imlInstruction->operation == PPCREC_IML_MACRO_BCTRL)
x64Gen_mov_mem32Reg64_imm32(x64GenContext, REG_RSP, offsetof(PPCInterpreter_t, spr.LR), currentInstructionAddress + 4);
uint32 branchDstReg = tempToRealRegister(imlInstruction->op_macro.param);
if(REG_RDX != branchDstReg)
x64Gen_mov_reg64_reg64(x64GenContext, REG_RDX, branchDstReg);
// potential optimization: Use branchDstReg directly if possible instead of moving to RDX/EDX
// JMP [offset+RDX*(8/4)+R15]
x64Gen_writeU8(x64GenContext, 0x41);
x64Gen_writeU8(x64GenContext, 0xFF);

View File

@ -294,21 +294,9 @@ void IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool
}
else if (inst.type == PPCREC_IML_TYPE_MACRO)
{
if (inst.operation == PPCREC_IML_MACRO_BLR)
if (inst.operation == PPCREC_IML_MACRO_B_TO_REG)
{
strOutput.addFmt("MACRO BLR 0x{:08x} cycles (depr): {}", inst.op_macro.param, (sint32)inst.op_macro.paramU16);
}
else if (inst.operation == PPCREC_IML_MACRO_BLRL)
{
strOutput.addFmt("MACRO BLRL 0x{:08x} cycles (depr): {}", inst.op_macro.param, (sint32)inst.op_macro.paramU16);
}
else if (inst.operation == PPCREC_IML_MACRO_BCTR)
{
strOutput.addFmt("MACRO BCTR 0x{:08x} cycles (depr): {}", inst.op_macro.param, (sint32)inst.op_macro.paramU16);
}
else if (inst.operation == PPCREC_IML_MACRO_BCTRL)
{
strOutput.addFmt("MACRO BCTRL 0x{:08x} cycles (depr): {}", inst.op_macro.param, (sint32)inst.op_macro.paramU16);
strOutput.addFmt("MACRO B_TO_REG t{}", inst.op_macro.param);
}
else if (inst.operation == PPCREC_IML_MACRO_BL)
{

View File

@ -130,10 +130,14 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_BLR || operation == PPCREC_IML_MACRO_BLRL || operation == PPCREC_IML_MACRO_BCTR || operation == PPCREC_IML_MACRO_BCTRL || 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 || operation == PPCREC_IML_MACRO_MFTB)
{
// no effect on registers
}
else if (operation == PPCREC_IML_MACRO_B_TO_REG)
{
registersUsed->readNamedReg1 = op_macro.param;
}
else
cemu_assert_unimplemented();
}
@ -480,10 +484,14 @@ void IMLInstruction::ReplaceGPR(sint32 gprRegisterSearched[4], sint32 gprRegiste
}
else if (type == PPCREC_IML_TYPE_MACRO)
{
if (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_BLR || operation == PPCREC_IML_MACRO_BLRL || operation == PPCREC_IML_MACRO_BCTR || operation == PPCREC_IML_MACRO_BCTRL || 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_MFTB || operation == PPCREC_IML_MACRO_COUNT_CYCLES)
{
// no effect on registers
}
else if (operation == PPCREC_IML_MACRO_B_TO_REG)
{
op_macro.param = replaceRegisterMultiple(op_macro.param, gprRegisterSearched, gprRegisterReplaced);
}
else
{
cemu_assert_unimplemented();

View File

@ -97,10 +97,8 @@ enum
enum
{
PPCREC_IML_MACRO_BLR, // macro for BLR instruction code
PPCREC_IML_MACRO_BLRL, // macro for BLRL instruction code
PPCREC_IML_MACRO_BCTR, // macro for BCTR instruction code
PPCREC_IML_MACRO_BCTRL, // macro for BCTRL instruction code
PPCREC_IML_MACRO_B_TO_REG, // branch to PPC address in register (used for BCCTR, BCLR)
PPCREC_IML_MACRO_BL, // call to different function (can be within same function)
PPCREC_IML_MACRO_B_FAR, // branch to different function
PPCREC_IML_MACRO_COUNT_CYCLES, // decrease current remaining thread cycles by a certain amount
@ -130,7 +128,7 @@ enum
{
PPCREC_CR_MODE_COMPARE_SIGNED,
PPCREC_CR_MODE_COMPARE_UNSIGNED, // alias logic compare
// others: PPCREC_CR_MODE_ARITHMETIC,
PPCREC_CR_MODE_ARITHMETIC, // arithmetic use (for use with add/sub instructions without generating extra code)
PPCREC_CR_MODE_LOGICAL,
};
@ -398,11 +396,9 @@ struct IMLInstruction
bool IsSuffixInstruction() const
{
if (type == PPCREC_IML_TYPE_MACRO && (operation == PPCREC_IML_MACRO_BLR || operation == PPCREC_IML_MACRO_BCTR) ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_BL ||
if (type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_BL ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_B_FAR ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_BLRL ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_BCTRL ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_B_TO_REG ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_LEAVE ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_HLE ||
type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_MFTB ||

View File

@ -1033,8 +1033,8 @@ void PPCRecRA_calculateSegmentMinMaxRanges(ppcImlGenContext_t* ppcImlGenContext,
while (index < imlSegment->imlList.size())
{
// end loop at suffix instruction
if (imlSegment->imlList[index].IsSuffixInstruction())
break;
//if (imlSegment->imlList[index].IsSuffixInstruction())
// break;
// get accessed GPRs
imlSegment->imlList[index].CheckRegisterUsage(&gprTracking);
for (sint32 t = 0; t < 4; t++)
@ -1125,9 +1125,10 @@ void PPCRecRA_createSegmentLivenessRanges(ppcImlGenContext_t* ppcImlGenContext,
IMLUsedRegisters gprTracking;
while (index < imlSegment->imlList.size())
{
// end loop at suffix instruction
if (imlSegment->imlList[index].IsSuffixInstruction())
break;
// we parse suffix instructions too for any potential input registers (writes not allowed), but note that any spills/stores need to happen before the suffix instruction
//// end loop at suffix instruction
//if (imlSegment->imlList[index].IsSuffixInstruction())
// break;
// get accessed GPRs
imlSegment->imlList[index].CheckRegisterUsage(&gprTracking);
// handle accessed GPR

View File

@ -797,194 +797,85 @@ bool PPCRecompilerImlGen_BC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
return true;
}
bool PPCRecompilerImlGen_BCLR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
// BCCTR or BCLR
bool PPCRecompilerImlGen_BCSPR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 sprReg)
{
PPCIMLGen_AssertIfNotLastSegmentInstruction(*ppcImlGenContext);
uint32 BO, BI, BD;
PPC_OPC_TEMPL_XL(opcode, BO, BI, BD);
Espresso::BOField BO;
uint32 BI;
bool LK;
Espresso::decodeOp_BCSPR(opcode, BO, BI, LK);
uint32 crRegister = BI/4;
uint32 crBit = BI%4;
uint32 jumpCondition = 0;
bool conditionMustBeTrue = (BO&8)!=0;
bool useDecrementer = (BO&4)==0; // bit not set -> decrement
bool decrementerMustBeZero = (BO&2)!=0; // bit set -> branch if CTR = 0, bit not set -> branch if CTR != 0
bool ignoreCondition = (BO&16)!=0;
bool saveLR = (opcode&PPC_OPC_LK)!=0;
// since we skip this instruction if the condition is true, we need to invert the logic
//bool invertedConditionMustBeTrue = !conditionMustBeTrue;
if( useDecrementer )
uint32 branchDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + sprReg);
if (LK)
{
cemu_assert_debug(false);
return false; // unsupported
}
else
{
if( ignoreCondition )
if (sprReg == SPR_LR)
{
// branch always, no condition and no decrementer check
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasContinuedFlow);
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);
if( saveLR )
{
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BLRL, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
}
else
{
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BLR, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
}
// if the branch target is LR, then preserve it in a temporary
cemu_assert_suspicious(); // this case needs testing
uint32 tmpRegister = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);
PPCRecompilerImlGen_generateNewInstruction_r_r(ppcImlGenContext, nullptr, PPCREC_IML_OP_ASSIGN, tmpRegister, branchDestReg);
branchDestReg = tmpRegister;
}
uint32 registerLR = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_LR);
PPCRecompilerImlGen_generateNewInstruction_r_s32(ppcImlGenContext, PPCREC_IML_OP_ASSIGN, registerLR, ppcImlGenContext->ppcAddressOfCurrentInstruction + 4, 0, false, false, PPC_REC_INVALID_REGISTER, 0);
}
if (!BO.decrementerIgnore())
{
cemu_assert_unimplemented();
return false;
}
else if (!BO.conditionIgnore())
{
// no decrementer but CR check
cemu_assert_debug(ppcImlGenContext->currentBasicBlock->hasContinuedFlow);
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);
// generate jump condition
uint32 jumpCondition = 0;
if (!BO.conditionInverted())
{
// CR bit must be set
if (crBit == 0)
jumpCondition = PPCREC_JUMP_CONDITION_L;
else if (crBit == 1)
jumpCondition = PPCREC_JUMP_CONDITION_G;
else if (crBit == 2)
jumpCondition = PPCREC_JUMP_CONDITION_E;
else if (crBit == 3)
jumpCondition = PPCREC_JUMP_CONDITION_SUMMARYOVERFLOW;
}
else
{
cemu_assert_debug(ppcImlGenContext->currentBasicBlock->hasContinuedFlow);
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);
//debug_printf("[Rec-Disable] BCLR with condition or LR\n");
//return false;
// store LR
if( saveLR )
{
cemu_assert_unimplemented(); // todo - this is difficult to handle because it needs to jump to the unmodified LR (we should cache it in a register which we pass to the macro?)
return false;
uint32 registerLR = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_SPR0+SPR_LR);
PPCRecompilerImlGen_generateNewInstruction_r_s32(ppcImlGenContext, PPCREC_IML_OP_ASSIGN, registerLR, (ppcImlGenContext->ppcAddressOfCurrentInstruction+4)&0x7FFFFFFF, 0, false, false, PPC_REC_INVALID_REGISTER, 0);
}
// generate jump condition
if(conditionMustBeTrue)
{
if( crBit == 0 )
jumpCondition = PPCREC_JUMP_CONDITION_L;
else if( crBit == 1 )
jumpCondition = PPCREC_JUMP_CONDITION_G;
else if( crBit == 2 )
jumpCondition = PPCREC_JUMP_CONDITION_E;
else if( crBit == 3 )
jumpCondition = PPCREC_JUMP_CONDITION_SUMMARYOVERFLOW;
}
else
{
if( crBit == 0 )
jumpCondition = PPCREC_JUMP_CONDITION_GE;
else if( crBit == 1 )
jumpCondition = PPCREC_JUMP_CONDITION_LE;
else if( crBit == 2 )
jumpCondition = PPCREC_JUMP_CONDITION_NE;
else if( crBit == 3 )
jumpCondition = PPCREC_JUMP_CONDITION_NSUMMARYOVERFLOW;
}
//if(conditionMustBeTrue)
// ppcImlGenContext->emitInst().make_debugbreak(ppcImlGenContext->ppcAddressOfCurrentInstruction);
// write the BCTR instruction to a new segment that is set as a branch target for the current segment
PPCBasicBlockInfo* currentBasicBlock = ppcImlGenContext->currentBasicBlock;
IMLSegment* bctrSeg = PPCIMLGen_CreateNewSegmentAsBranchTarget(*ppcImlGenContext, *currentBasicBlock);
PPCRecompilerImlGen_generateNewInstruction_conditionalJumpSegment(ppcImlGenContext, jumpCondition, crRegister, crBit, conditionMustBeTrue);
bctrSeg->AppendInstruction()->make_macro(PPCREC_IML_MACRO_BLR, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
if (crBit == 0)
jumpCondition = PPCREC_JUMP_CONDITION_GE;
else if (crBit == 1)
jumpCondition = PPCREC_JUMP_CONDITION_LE;
else if (crBit == 2)
jumpCondition = PPCREC_JUMP_CONDITION_NE;
else if (crBit == 3)
jumpCondition = PPCREC_JUMP_CONDITION_NSUMMARYOVERFLOW;
}
}
return true;
}
bool PPCRecompilerImlGen_BCCTR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
PPCIMLGen_AssertIfNotLastSegmentInstruction(*ppcImlGenContext);
// write the dynamic branch instruction to a new segment that is set as a branch target for the current segment
PPCBasicBlockInfo* currentBasicBlock = ppcImlGenContext->currentBasicBlock;
IMLSegment* bctrSeg = PPCIMLGen_CreateNewSegmentAsBranchTarget(*ppcImlGenContext, *currentBasicBlock);
uint32 BO, BI, BD;
PPC_OPC_TEMPL_XL(opcode, BO, BI, BD);
PPCRecompilerImlGen_generateNewInstruction_conditionalJumpSegment(ppcImlGenContext, jumpCondition, crRegister, crBit, !BO.conditionInverted());
uint32 crRegister = BI/4;
uint32 crBit = BI%4;
uint32 jumpCondition = 0;
bool conditionMustBeTrue = (BO&8)!=0;
bool useDecrementer = (BO&4)==0; // bit not set -> decrement
bool decrementerMustBeZero = (BO&2)!=0; // bit set -> branch if CTR = 0, bit not set -> branch if CTR != 0
bool ignoreCondition = (BO&16)!=0;
bool saveLR = (opcode&PPC_OPC_LK)!=0;
// since we skip this instruction if the condition is true, we need to invert the logic
bool invertedConditionMustBeTrue = !conditionMustBeTrue;
if( useDecrementer )
{
assert_dbg();
// if added, dont forget inverted logic
debug_printf("Rec: BCLR unsupported decrementer\n");
return false; // unsupported
bctrSeg->AppendInstruction()->make_macro(PPCREC_IML_MACRO_B_TO_REG, branchDestReg, 0, 0);
}
else
{
if( ignoreCondition )
{
// branch always, no condition and no decrementer
if( saveLR )
{
uint32 registerLR = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_SPR0+SPR_LR);
PPCRecompilerImlGen_generateNewInstruction_r_s32(ppcImlGenContext, PPCREC_IML_OP_ASSIGN, registerLR, (ppcImlGenContext->ppcAddressOfCurrentInstruction+4)&0x7FFFFFFF, 0, false, false, PPC_REC_INVALID_REGISTER, 0);
}
if (saveLR)
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BCTRL, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
else
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BCTR, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
}
else
{
// get jump condition
if (invertedConditionMustBeTrue)
{
if (crBit == 0)
jumpCondition = PPCREC_JUMP_CONDITION_L;
else if (crBit == 1)
jumpCondition = PPCREC_JUMP_CONDITION_G;
else if (crBit == 2)
jumpCondition = PPCREC_JUMP_CONDITION_E;
else if (crBit == 3)
jumpCondition = PPCREC_JUMP_CONDITION_SUMMARYOVERFLOW;
}
else
{
if (crBit == 0)
jumpCondition = PPCREC_JUMP_CONDITION_GE;
else if (crBit == 1)
jumpCondition = PPCREC_JUMP_CONDITION_LE;
else if (crBit == 2)
jumpCondition = PPCREC_JUMP_CONDITION_NE;
else if (crBit == 3)
jumpCondition = PPCREC_JUMP_CONDITION_NSUMMARYOVERFLOW;
}
// branch always, no condition and no decrementer check
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasContinuedFlow);
cemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_B_TO_REG, branchDestReg, 0, 0);
// debug checks
//if (saveLR)
// cemu_assert_debug(ppcImlGenContext->currentBasicBlock->);
// we always store LR
if (saveLR)
{
uint32 registerLR = PPCRecompilerImlGen_loadOverwriteRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_LR);
PPCRecompilerImlGen_generateNewInstruction_r_s32(ppcImlGenContext, PPCREC_IML_OP_ASSIGN, registerLR, (ppcImlGenContext->ppcAddressOfCurrentInstruction + 4) & 0x7FFFFFFF, 0, false, false, PPC_REC_INVALID_REGISTER, 0);
}
// write the BCTR instruction to a new segment that is set as a branch target for the current segment
__debugbreak();
PPCBasicBlockInfo* currentBasicBlock = ppcImlGenContext->currentBasicBlock;
IMLSegment* bctrSeg = PPCIMLGen_CreateNewSegmentAsBranchTarget(*ppcImlGenContext, *currentBasicBlock);
//PPCBasicBlockInfo* bctrSeg = currentBasicBlock->Get
__debugbreak();
// jump if BCLR condition NOT met (jump to jumpmark of next instruction, essentially skipping current instruction)
PPCRecompilerImlGen_generateNewInstruction_conditionalJump(ppcImlGenContext, ppcImlGenContext->ppcAddressOfCurrentInstruction+4, jumpCondition, crRegister, crBit, invertedConditionMustBeTrue);
ppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BCTR, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, ppcImlGenContext->cyclesSinceLastBranch);
}
}
return true;
}
@ -3333,8 +3224,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
case 19: // opcode category 19
switch (PPC_getBits(opcode, 30, 10))
{
case 16:
if (PPCRecompilerImlGen_BCLR(ppcImlGenContext, opcode) == false)
case 16: // BCLR
if (PPCRecompilerImlGen_BCSPR(ppcImlGenContext, opcode, SPR_LR) == false)
unsupportedInstructionFound = true;
break;
case 129:
@ -3365,8 +3256,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (PPCRecompilerImlGen_CROR(ppcImlGenContext, opcode) == false)
unsupportedInstructionFound = true;
break;
case 528:
if (PPCRecompilerImlGen_BCCTR(ppcImlGenContext, opcode) == false)
case 528: // BCCTR
if (PPCRecompilerImlGen_BCSPR(ppcImlGenContext, opcode, SPR_CTR) == false)
unsupportedInstructionFound = true;
break;
default:
@ -4008,14 +3899,6 @@ bool PPCRecompiler_CheckIfInstructionEndsSegment(PPCFunctionBoundaryTracker& bou
case Espresso::PrimaryOpcode::GROUP_19:
switch (Espresso::GetGroup19Opcode(opcode))
{
//case Espresso::Opcode19::BCLR:
////case Espresso::Opcode19::BCCTR:
//{
// continueDefaultPath = false; // todo - set this to true if this instruction has a condition (including decrementer check)
// makeNextInstEnterable = Espresso::DecodeLK(opcode);
// return true;
//}
case Espresso::Opcode19::BCLR:
case Espresso::Opcode19::BCCTR:
{
@ -4034,19 +3917,6 @@ bool PPCRecompiler_CheckIfInstructionEndsSegment(PPCFunctionBoundaryTracker& bou
case Espresso::PrimaryOpcode::GROUP_31:
switch (Espresso::GetGroup31Opcode(opcode))
{
//case Espresso::Opcode31::TW:
// continueDefaultPath = true;
// return true;
//case Espresso::Opcode31::MFTB:
// continueDefaultPath = true;
// return true;
//case Espresso::Opcode19::BCLR:
//case Espresso::Opcode19::BCCTR:
//{
// continueDefaultPath = false;
// makeNextInstEnterable = Espresso::DecodeLK(opcode);
// return true;
//}
default:
break;
}
@ -4336,7 +4206,6 @@ void PPCRecompiler_SetSegmentsUncertainFlow(ppcImlGenContext_t& ppcImlGenContext
for (IMLSegment* segIt : ppcImlGenContext.segmentList2)
{
bool isLastSegment = segIt == ppcImlGenContext.segmentList2.back();
//IMLSegment* nextSegment = isLastSegment ? nullptr : ppcImlGenContext->segmentList2[s + 1];
// handle empty segment
if (segIt->imlList.empty())
{
@ -4352,29 +4221,13 @@ void PPCRecompiler_SetSegmentsUncertainFlow(ppcImlGenContext_t& ppcImlGenContext
{
cemu_assert_debug(segIt->GetBranchNotTaken());
}
//// find destination segment by ppc jump address
//IMLSegment* jumpDestSegment = PPCRecompiler_getSegmentByPPCJumpAddress(ppcImlGenContext, imlInstruction->op_conditionalJump.jumpmarkAddress);
//if (jumpDestSegment)
//{
// if (imlInstruction->op_conditionalJump.condition != PPCREC_JUMP_CONDITION_NONE)
// IMLSegment_SetLinkBranchNotTaken(imlSegment, nextSegment);
// IMLSegment_SetLinkBranchTaken(imlSegment, jumpDestSegment);
//}
//else
//{
// imlSegment->nextSegmentIsUncertain = true;
//}
}
else if (imlInstruction->type == PPCREC_IML_TYPE_MACRO)
{
auto macroType = imlInstruction->operation;
switch (macroType)
{
case PPCREC_IML_MACRO_BLR:
case PPCREC_IML_MACRO_BLRL:
case PPCREC_IML_MACRO_BCTR:
case PPCREC_IML_MACRO_BCTRL:
case PPCREC_IML_MACRO_B_TO_REG:
case PPCREC_IML_MACRO_BL:
case PPCREC_IML_MACRO_B_FAR:
case PPCREC_IML_MACRO_HLE:
@ -4500,7 +4353,7 @@ bool PPCRecompiler_GenerateIML(ppcImlGenContext_t& ppcImlGenContext, PPCFunction
{
if (seg->imlList[f].IsSuffixInstruction())
{
debug_printf("---------------- SegmentDump (Suffix instruction at wrong pos in segment 0x%x):\n", segIndex);
debug_printf("---------------- SegmentDump (Suffix instruction at wrong pos in segment 0x%x):\n", (int)segIndex);
IMLDebug_Dump(&ppcImlGenContext);
__debugbreak();
}
@ -4510,7 +4363,7 @@ bool PPCRecompiler_GenerateIML(ppcImlGenContext_t& ppcImlGenContext, PPCFunction
{
if (!seg->HasSuffixInstruction())
{
debug_printf("---------------- SegmentDump (NoSuffixInstruction in segment 0x%x):\n", segIndex);
debug_printf("---------------- SegmentDump (NoSuffixInstruction in segment 0x%x):\n", (int)segIndex);
IMLDebug_Dump(&ppcImlGenContext);
__debugbreak();
}
@ -4540,7 +4393,7 @@ bool PPCRecompiler_GenerateIML(ppcImlGenContext_t& ppcImlGenContext, PPCFunction
{
if (!seg->GetBranchTaken() || !seg->GetBranchNotTaken())
{
debug_printf("---------------- SegmentDump (Missing branch for CJUMP in segment 0x%x):\n", segIndex);
debug_printf("---------------- SegmentDump (Missing branch for CJUMP in segment 0x%x):\n", (int)segIndex);
IMLDebug_Dump(&ppcImlGenContext);
cemu_assert_error();
}
@ -4551,10 +4404,6 @@ bool PPCRecompiler_GenerateIML(ppcImlGenContext_t& ppcImlGenContext, PPCFunction
}
}
}
//if (seg->list_prevSegments.empty())
//{
// cemu_assert_debug(seg->isEnterable);
//}
segIndex++;
}
#endif