PPCRec: Simplify PPC and IML logic instructions

Also implement PPC NAND instruction
This commit is contained in:
Exzap 2023-01-05 07:05:47 +01:00
parent 429413d88e
commit 1f6f74d6ac
3 changed files with 119 additions and 347 deletions

View file

@ -562,24 +562,6 @@ bool PPCRecompilerX64Gen_imlInstruction_r_r(PPCRecFunction_t* PPCRecFunction, pp
{ {
x64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext, imlInstruction->op_r_r.regR, reg32ToReg16(imlInstruction->op_r_r.regA)); x64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext, imlInstruction->op_r_r.regR, reg32ToReg16(imlInstruction->op_r_r.regA));
} }
else if( imlInstruction->operation == PPCREC_IML_OP_OR || imlInstruction->operation == PPCREC_IML_OP_AND || imlInstruction->operation == PPCREC_IML_OP_XOR )
{
if( imlInstruction->operation == PPCREC_IML_OP_OR )
{
// registerResult |= registerA
x64Gen_or_reg64Low32_reg64Low32(x64GenContext, imlInstruction->op_r_r.regR, imlInstruction->op_r_r.regA);
}
else if( imlInstruction->operation == PPCREC_IML_OP_AND )
{
// registerResult &= registerA
x64Gen_and_reg64Low32_reg64Low32(x64GenContext, imlInstruction->op_r_r.regR, imlInstruction->op_r_r.regA);
}
else
{
// registerResult ^= registerA
x64Gen_xor_reg64Low32_reg64Low32(x64GenContext, imlInstruction->op_r_r.regR, imlInstruction->op_r_r.regA);
}
}
else if( imlInstruction->operation == PPCREC_IML_OP_NOT ) else if( imlInstruction->operation == PPCREC_IML_OP_NOT )
{ {
// copy register content if different registers // copy register content if different registers
@ -652,18 +634,6 @@ bool PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction,
{ {
x64Gen_mov_reg64Low32_imm32(x64GenContext, imlInstruction->op_r_immS32.regR, (uint32)imlInstruction->op_r_immS32.immS32); x64Gen_mov_reg64Low32_imm32(x64GenContext, imlInstruction->op_r_immS32.regR, (uint32)imlInstruction->op_r_immS32.immS32);
} }
else if( imlInstruction->operation == PPCREC_IML_OP_AND )
{
x64Gen_and_reg64Low32_imm32(x64GenContext, imlInstruction->op_r_immS32.regR, (uint32)imlInstruction->op_r_immS32.immS32);
}
else if( imlInstruction->operation == PPCREC_IML_OP_OR )
{
x64Gen_or_reg64Low32_imm32(x64GenContext, imlInstruction->op_r_immS32.regR, (uint32)imlInstruction->op_r_immS32.immS32);
}
else if( imlInstruction->operation == PPCREC_IML_OP_XOR )
{
x64Gen_xor_reg64Low32_imm32(x64GenContext, imlInstruction->op_r_immS32.regR, (uint32)imlInstruction->op_r_immS32.immS32);
}
else if( imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE ) else if( imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE )
{ {
if( (imlInstruction->op_r_immS32.immS32&0x80) ) if( (imlInstruction->op_r_immS32.immS32&0x80) )

View file

@ -32,16 +32,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
registersUsed->readGPR1 = op_r_r.regR; registersUsed->readGPR1 = op_r_r.regR;
registersUsed->readGPR2 = op_r_r.regA; registersUsed->readGPR2 = op_r_r.regA;
} }
else if (
operation == PPCREC_IML_OP_OR ||
operation == PPCREC_IML_OP_AND ||
operation == PPCREC_IML_OP_XOR)
{
// result is read and written, operand is read
registersUsed->writtenGPR1 = op_r_r.regR;
registersUsed->readGPR1 = op_r_r.regR;
registersUsed->readGPR2 = op_r_r.regA;
}
else if ( else if (
operation == PPCREC_IML_OP_ASSIGN || operation == PPCREC_IML_OP_ASSIGN ||
operation == PPCREC_IML_OP_ENDIAN_SWAP || operation == PPCREC_IML_OP_ENDIAN_SWAP ||
@ -60,17 +50,18 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
} }
else if (type == PPCREC_IML_TYPE_R_S32) else if (type == PPCREC_IML_TYPE_R_S32)
{ {
cemu_assert_debug(operation != PPCREC_IML_OP_ADD &&
operation != PPCREC_IML_OP_SUB &&
operation != PPCREC_IML_OP_AND &&
operation != PPCREC_IML_OP_OR &&
operation != PPCREC_IML_OP_XOR); // deprecated, use r_r_s32 for these
if (operation == PPCREC_IML_OP_MTCRF) if (operation == PPCREC_IML_OP_MTCRF)
{ {
// operand register is read only // operand register is read only
registersUsed->readGPR1 = op_r_immS32.regR; registersUsed->readGPR1 = op_r_immS32.regR;
} }
else if (operation == PPCREC_IML_OP_ADD || // deprecated else if (operation == PPCREC_IML_OP_LEFT_ROTATE)
operation == PPCREC_IML_OP_SUB ||
operation == PPCREC_IML_OP_AND ||
operation == PPCREC_IML_OP_OR ||
operation == PPCREC_IML_OP_XOR ||
operation == PPCREC_IML_OP_LEFT_ROTATE)
{ {
// operand register is read and write // operand register is read and write
registersUsed->readGPR1 = op_r_immS32.regR; registersUsed->readGPR1 = op_r_immS32.regR;
@ -87,7 +78,7 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const
{ {
if (operation == PPCREC_IML_OP_ASSIGN) if (operation == PPCREC_IML_OP_ASSIGN)
{ {
// result is written, but also considered read (in case the condition fails) // result is written, but also considered read (in case the condition is false the input is preserved)
registersUsed->readGPR1 = op_conditional_r_s32.regR; registersUsed->readGPR1 = op_conditional_r_s32.regR;
registersUsed->writtenGPR1 = op_conditional_r_s32.regR; registersUsed->writtenGPR1 = op_conditional_r_s32.regR;
} }

View file

@ -982,7 +982,7 @@ bool PPCRecompilerImlGen_RLWINM(ppcImlGenContext_t* ppcImlGenContext, uint32 opc
if (SH != 0) if (SH != 0)
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_LEFT_ROTATE, registerRA, SH); ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_LEFT_ROTATE, registerRA, SH);
if (mask != 0xFFFFFFFF) if (mask != 0xFFFFFFFF)
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_AND, registerRA, (sint32)mask); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, registerRA, registerRA, (sint32)mask);
} }
if (opcode & PPC_OPC_RC) if (opcode & PPC_OPC_RC)
PPCImlGen_UpdateCR0(ppcImlGenContext, registerRA); PPCImlGen_UpdateCR0(ppcImlGenContext, registerRA);
@ -1014,7 +1014,7 @@ bool PPCRecompilerImlGen_RLWNM(ppcImlGenContext_t* ppcImlGenContext, uint32 opco
uint32 registerRA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA); uint32 registerRA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);
ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_LEFT_ROTATE, registerRA, registerRS, registerRB); ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_LEFT_ROTATE, registerRA, registerRS, registerRB);
if( mask != 0xFFFFFFFF ) if( mask != 0xFFFFFFFF )
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_AND, registerRA, (sint32)mask); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, registerRA, registerRA, (sint32)mask);
if (opcode & PPC_OPC_RC) if (opcode & PPC_OPC_RC)
PPCImlGen_UpdateCR0(ppcImlGenContext, registerRA); PPCImlGen_UpdateCR0(ppcImlGenContext, registerRA);
return true; return true;
@ -1336,22 +1336,25 @@ bool PPCRecompilerImlGen_LSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
// potential optimization: On x86 unaligned access is allowed and we could handle the case nb==4 with a single memory read, and nb==2 with a memory read and shift // potential optimization: On x86 unaligned access is allowed and we could handle the case nb==4 with a single memory read, and nb==2 with a memory read and shift
IMLReg memReg = _GetRegGPR(ppcImlGenContext, rA); IMLReg memReg = _GetRegGPR(ppcImlGenContext, rA);
IMLReg tmpReg = _GetRegTemporary(ppcImlGenContext, 0); IMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);
uint32 memOffset = 0; uint32 memOffset = 0;
while (nb > 0) while (nb > 0)
{ {
if (rD == rA) if (rD == rA)
return false; return false;
cemu_assert(rD < 32); cemu_assert(rD < 32);
IMLReg destinationRegister = _GetRegGPR(ppcImlGenContext, rD); IMLReg regDst = _GetRegGPR(ppcImlGenContext, rD);
// load bytes one-by-one // load bytes one-by-one
for (sint32 b = 0; b < 4; b++) for (sint32 b = 0; b < 4; b++)
{ {
ppcImlGenContext->emitInst().make_r_memory(tmpReg, memReg, memOffset + b, 8, false, false); ppcImlGenContext->emitInst().make_r_memory(regTmp, memReg, memOffset + b, 8, false, false);
sint32 shiftAmount = (3 - b) * 8; sint32 shiftAmount = (3 - b) * 8;
if(shiftAmount) if(shiftAmount)
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, tmpReg, tmpReg, shiftAmount); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, regTmp, regTmp, shiftAmount);
ppcImlGenContext->emitInst().make_r_r(b == 0 ? PPCREC_IML_OP_ASSIGN : PPCREC_IML_OP_OR, destinationRegister, tmpReg); if(b == 0)
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regDst, regTmp);
else
ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regDst, regDst, regTmp);
nb--; nb--;
if (nb == 0) if (nb == 0)
break; break;
@ -1369,23 +1372,23 @@ bool PPCRecompilerImlGen_STSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opco
if( nb == 0 ) if( nb == 0 )
nb = 32; nb = 32;
IMLReg memReg = _GetRegGPR(ppcImlGenContext, rA); IMLReg regMem = _GetRegGPR(ppcImlGenContext, rA);
IMLReg tmpReg = _GetRegTemporary(ppcImlGenContext, 0); IMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);
uint32 memOffset = 0; uint32 memOffset = 0;
while (nb > 0) while (nb > 0)
{ {
if (rS == rA) if (rS == rA)
return false; return false;
cemu_assert(rS < 32); cemu_assert(rS < 32);
IMLReg dataRegister = _GetRegGPR(ppcImlGenContext, rS); IMLReg regSrc = _GetRegGPR(ppcImlGenContext, rS);
// store bytes one-by-one // store bytes one-by-one
for (sint32 b = 0; b < 4; b++) for (sint32 b = 0; b < 4; b++)
{ {
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, tmpReg, dataRegister); ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regTmp, regSrc);
sint32 shiftAmount = (3 - b) * 8; sint32 shiftAmount = (3 - b) * 8;
if (shiftAmount) if (shiftAmount)
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, tmpReg, tmpReg, shiftAmount); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, regTmp, regTmp, shiftAmount);
ppcImlGenContext->emitInst().make_memory_r(tmpReg, memReg, memOffset + b, 8, false); ppcImlGenContext->emitInst().make_memory_r(regTmp, regMem, memOffset + b, 8, false);
nb--; nb--;
if (nb == 0) if (nb == 0)
break; break;
@ -1491,106 +1494,21 @@ bool PPCRecompilerImlGen_DCBZ(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
return true; return true;
} }
bool PPCRecompilerImlGen_OR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) bool PPCRecompilerImlGen_OR_NOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)
{ {
int rS, rA, rB; int rS, rA, rB;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB); PPC_OPC_TEMPL_X(opcode, rS, rA, rB);
// check for MR mnemonic IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
if( rS == rB ) IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
{ IMLReg regB = _GetRegGPR(ppcImlGenContext, rB);
// simple register copy if(regS == regB) // check for MR mnemonic
if( rA != rS ) // check if no-op ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regA, regS);
{
sint32 gprSourceReg = _GetRegGPR(ppcImlGenContext, rS);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSourceReg);
}
if ((opcode & PPC_OPC_RC))
{
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA);
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
}
else else
{ ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regA, regS, regB);
// rA = rS | rA if(complementResult)
sint32 gprSource1Reg = _GetRegGPR(ppcImlGenContext, rS); ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);
sint32 gprSource2Reg = _GetRegGPR(ppcImlGenContext, rB); if (opcode & PPC_OPC_RC)
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA); PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
if( gprSource1Reg == gprDestReg || gprSource2Reg == gprDestReg )
{
// make sure we don't overwrite rS or rA
if( gprSource1Reg == gprDestReg )
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource2Reg);
else
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource1Reg);
}
else
{
// rA = rS
if( gprDestReg != gprSource1Reg )
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSource1Reg);
// rA |= rB
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource2Reg);
}
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
return true;
}
bool PPCRecompilerImlGen_NOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
int rS, rA, rB;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB);
//hCPU->gpr[rA] = ~(hCPU->gpr[rS] | hCPU->gpr[rB]);
// check for NOT mnemonic
if (rS == rB)
{
// simple register copy with NOT
sint32 gprSourceReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rS);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA);
if (gprDestReg != gprSourceReg)
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSourceReg);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
else
{
// rA = rS | rA
sint32 gprSource1Reg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rS);
sint32 gprSource2Reg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rB);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA);
if (gprSource1Reg == gprDestReg || gprSource2Reg == gprDestReg)
{
// make sure we don't overwrite rS or rA
if (gprSource1Reg == gprDestReg)
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource2Reg);
}
else
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource1Reg);
}
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
else
{
// rA = rS
if (gprDestReg != gprSource1Reg)
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSource1Reg);
}
// rA |= rB
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprSource2Reg);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
}
return true; return true;
} }
@ -1610,60 +1528,21 @@ bool PPCRecompilerImlGen_ORC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode
return true; return true;
} }
bool PPCRecompilerImlGen_AND(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) bool PPCRecompilerImlGen_AND_NAND(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)
{ {
sint32 rS, rA, rB; int rS, rA, rB;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB); PPC_OPC_TEMPL_X(opcode, rS, rA, rB);
// check for MR mnemonic IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
if( rS == rB ) IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
{ IMLReg regB = _GetRegGPR(ppcImlGenContext, rB);
// simple register copy if (regS == regB)
if( rA != rS ) // check if no-op ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regA, regS);
{
sint32 gprSourceReg = _GetRegGPR(ppcImlGenContext, rS);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSourceReg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
else
{
cemu_assert_unimplemented(); // no-op -> verify this case
}
}
else else
{ ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regA, regS, regB);
// rA = rS & rA if (complementResult)
sint32 gprSource1Reg = _GetRegGPR(ppcImlGenContext, rS); ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);
sint32 gprSource2Reg = _GetRegGPR(ppcImlGenContext, rB); if (opcode & PPC_OPC_RC)
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA); PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
if( gprSource1Reg == gprDestReg || gprSource2Reg == gprDestReg )
{
// make sure we don't overwrite rS or rA
if( gprSource1Reg == gprDestReg )
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_AND, gprDestReg, gprSource2Reg);
}
else
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_AND, gprDestReg, gprSource1Reg);
}
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
else
{
// rA = rS
if( gprDestReg != gprSource1Reg )
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSource1Reg);
}
// rA &= rB
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_AND, gprDestReg, gprSource2Reg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
}
return true; return true;
} }
@ -1671,85 +1550,19 @@ bool PPCRecompilerImlGen_ANDC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod
{ {
sint32 rS, rA, rB; sint32 rS, rA, rB;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB); PPC_OPC_TEMPL_X(opcode, rS, rA, rB);
//hCPU->gpr[rA] = hCPU->gpr[rS] & ~hCPU->gpr[rB]; // rA = rS & ~rB;
//if (Opcode & PPC_OPC_RC) { IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
if( rS == rB ) IMLReg regB = _GetRegGPR(ppcImlGenContext, rB);
{ IMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);
// result is always 0 -> replace with XOR rA,rA sint32 regA = _GetRegGPR(ppcImlGenContext, rA);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA); ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regB);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_XOR, gprDestReg, gprDestReg); ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regA, regS, regTmp);
if ((opcode & PPC_OPC_RC)) if (opcode & PPC_OPC_RC)
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg); PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
}
else if( rA == rB )
{
// rB already in rA, therefore we complement rA first and then AND it with rS
sint32 gprRS = _GetRegGPR(ppcImlGenContext, rS);
sint32 gprDestReg = _GetRegGPR(ppcImlGenContext, rA);
// rA = ~rA
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
// rA &= rS
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_AND, gprDestReg, gprRS);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
else
{
// a & (~b) is the same as ~((~a) | b)
sint32 gprDestReg = _GetRegGPR(ppcImlGenContext, rA);
sint32 gprRB = _GetRegGPR(ppcImlGenContext, rB);
sint32 gprRS = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rS);
// move rS to rA (if required)
if( gprDestReg != gprRS )
{
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprRS);
}
// rS already in rA, therefore we complement rS first and then OR it with rB
// rA = ~rA
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
// rA |= rB
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_OR, gprDestReg, gprRB);
// rA = ~rA
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, gprDestReg, gprDestReg);
if ((opcode & PPC_OPC_RC))
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
return true; return true;
} }
void PPCRecompilerImlGen_ANDI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) bool PPCRecompilerImlGen_XOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)
{
sint32 rS, rA;
uint32 imm;
PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);
sint32 gprSourceReg = _GetRegGPR(ppcImlGenContext, rS);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);
// rA = rS
if( gprDestReg != gprSourceReg )
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSourceReg);
// rA &= imm32
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_AND, gprDestReg, (sint32)imm);
// ANDI. always sets cr0
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
void PPCRecompilerImlGen_ANDIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
sint32 rS, rA;
uint32 imm;
PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);
IMLReg gprSourceReg = _GetRegGPR(ppcImlGenContext, rS);
sint32 gprDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);
// rA = rS
if( gprDestReg != gprSourceReg )
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprDestReg, gprSourceReg);
// rA &= imm32
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_AND, gprDestReg, (sint32)imm);
// ANDIS. always sets cr0
PPCImlGen_UpdateCR0(ppcImlGenContext, gprDestReg);
}
bool PPCRecompilerImlGen_XOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{ {
sint32 rS, rA, rB; sint32 rS, rA, rB;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB); PPC_OPC_TEMPL_X(opcode, rS, rA, rB);
@ -1764,69 +1577,61 @@ bool PPCRecompilerImlGen_XOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode
IMLReg regB = _GetRegGPR(ppcImlGenContext, rB); IMLReg regB = _GetRegGPR(ppcImlGenContext, rB);
ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regA, regS, regB); ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regA, regS, regB);
} }
if (complementResult)
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);
if (opcode & PPC_OPC_RC) if (opcode & PPC_OPC_RC)
PPCImlGen_UpdateCR0(ppcImlGenContext, regA); PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
return true; return true;
} }
void PPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)
bool PPCRecompilerImlGen_EQV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{ {
sint32 rS, rA, rB; sint32 rS, rA;
PPC_OPC_TEMPL_X(opcode, rS, rA, rB); uint32 imm;
IMLReg regA = _GetRegGPR(ppcImlGenContext, rA); if (isShifted)
if( rS == rB )
{ {
ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regA, -1); PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);
} }
else else
{ {
// rA = ~(rS ^ rB) PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
IMLReg regB = _GetRegGPR(ppcImlGenContext, rB);
ppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regA, regS, regB);
ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);
} }
if (opcode & PPC_OPC_RC) IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
PPCImlGen_UpdateCR0(ppcImlGenContext, regA); IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
return true; ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regA, regS, (sint32)imm);
// ANDI/ANDIS always updates cr0
PPCImlGen_UpdateCR0(ppcImlGenContext, regA);
} }
void PPCRecompilerImlGen_ORI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) void PPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)
{ {
sint32 rS, rA; sint32 rS, rA;
uint32 imm; uint32 imm;
PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm); if (isShifted)
{
PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);
}
else
{
PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);
}
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS); IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
IMLReg regA = _GetRegGPR(ppcImlGenContext, rA); IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_OR, regA, regS, (sint32)imm); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_OR, regA, regS, (sint32)imm);
} }
void PPCRecompilerImlGen_ORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) void PPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)
{ {
sint32 rS, rA; sint32 rS, rA;
uint32 imm; uint32 imm;
PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm); if (isShifted)
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS); {
IMLReg regA = _GetRegGPR(ppcImlGenContext, rA); PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_OR, regA, regS, (sint32)imm); }
} else
{
void PPCRecompilerImlGen_XORI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);
{ }
sint32 rS, rA;
uint32 imm;
PPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regA, regS, (sint32)imm);
}
void PPCRecompilerImlGen_XORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)
{
sint32 rS, rA;
uint32 imm;
PPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);
IMLReg regS = _GetRegGPR(ppcImlGenContext, rS); IMLReg regS = _GetRegGPR(ppcImlGenContext, rS);
IMLReg regA = _GetRegGPR(ppcImlGenContext, rA); IMLReg regA = _GetRegGPR(ppcImlGenContext, rA);
ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regA, regS, (sint32)imm); ppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regA, regS, (sint32)imm);
@ -2308,23 +2113,23 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (PPCRecompilerImlGen_RLWNM(ppcImlGenContext, opcode) == false) if (PPCRecompilerImlGen_RLWNM(ppcImlGenContext, opcode) == false)
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 24: case 24: // ORI
PPCRecompilerImlGen_ORI(ppcImlGenContext, opcode); PPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext, opcode, false);
break; break;
case 25: case 25: // ORIS
PPCRecompilerImlGen_ORIS(ppcImlGenContext, opcode); PPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext, opcode, true);
break; break;
case 26: case 26: // XORI
PPCRecompilerImlGen_XORI(ppcImlGenContext, opcode); PPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext, opcode, false);
break; break;
case 27: case 27: // XORIS
PPCRecompilerImlGen_XORIS(ppcImlGenContext, opcode); PPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext, opcode, true);
break; break;
case 28: case 28: // ANDI
PPCRecompilerImlGen_ANDI(ppcImlGenContext, opcode); PPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext, opcode, false);
break; break;
case 29: case 29: // ANDIS
PPCRecompilerImlGen_ANDIS(ppcImlGenContext, opcode); PPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext, opcode, true);
break; break;
case 31: // opcode category case 31: // opcode category
switch (PPC_getBits(opcode, 30, 10)) switch (PPC_getBits(opcode, 30, 10))
@ -2367,8 +2172,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (PPCRecompilerImlGen_CNTLZW(ppcImlGenContext, opcode) == false) if (PPCRecompilerImlGen_CNTLZW(ppcImlGenContext, opcode) == false)
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 28: case 28: // AND
if (PPCRecompilerImlGen_AND(ppcImlGenContext, opcode) == false) if (!PPCRecompilerImlGen_AND_NAND(ppcImlGenContext, opcode, false))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 32: case 32:
@ -2385,8 +2190,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, true, true)) if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, true, true))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 60: case 60: // ANDC
if (PPCRecompilerImlGen_ANDC(ppcImlGenContext, opcode) == false) if (!PPCRecompilerImlGen_ANDC(ppcImlGenContext, opcode))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 75: case 75:
@ -2408,8 +2213,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 8, false, true, true)) if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 8, false, true, true))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 124: case 124: // NOR
if (PPCRecompilerImlGen_NOR(ppcImlGenContext, opcode) == false) if (!PPCRecompilerImlGen_OR_NOR(ppcImlGenContext, opcode, true))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 136: case 136:
@ -2421,7 +2226,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 144: case 144:
PPCRecompilerImlGen_MTCRF(ppcImlGenContext, opcode); if( !PPCRecompilerImlGen_MTCRF(ppcImlGenContext, opcode))
unsupportedInstructionFound = true;
break; break;
case 150: case 150:
if (!PPCRecompilerImlGen_STWCX(ppcImlGenContext, opcode)) if (!PPCRecompilerImlGen_STWCX(ppcImlGenContext, opcode))
@ -2467,15 +2273,16 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, false)) if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, false))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 284: case 284: // EQV (alias to NXOR)
PPCRecompilerImlGen_EQV(ppcImlGenContext, opcode); if (!PPCRecompilerImlGen_XOR(ppcImlGenContext, opcode, true))
unsupportedInstructionFound = true;
break; break;
case 311: // LHZUX case 311: // LHZUX
if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, true)) if (!PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, true))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 316: case 316: // XOR
if (PPCRecompilerImlGen_XOR(ppcImlGenContext, opcode) == false) if (!PPCRecompilerImlGen_XOR(ppcImlGenContext, opcode, false))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 339: case 339:
@ -2506,8 +2313,8 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 16, true, true)) if (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 16, true, true))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 444: case 444: // OR
if (PPCRecompilerImlGen_OR(ppcImlGenContext, opcode) == false) if (!PPCRecompilerImlGen_OR_NOR(ppcImlGenContext, opcode, false))
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 459: case 459:
@ -2517,6 +2324,10 @@ bool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)
if (PPCRecompilerImlGen_MTSPR(ppcImlGenContext, opcode) == false) if (PPCRecompilerImlGen_MTSPR(ppcImlGenContext, opcode) == false)
unsupportedInstructionFound = true; unsupportedInstructionFound = true;
break; break;
case 476: // NAND
if (!PPCRecompilerImlGen_AND_NAND(ppcImlGenContext, opcode, true))
unsupportedInstructionFound = true;
break;
case 491: case 491:
if (PPCRecompilerImlGen_DIVW(ppcImlGenContext, opcode) == false) if (PPCRecompilerImlGen_DIVW(ppcImlGenContext, opcode) == false)
unsupportedInstructionFound = true; unsupportedInstructionFound = true;