mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
PPCAnalyst: Add in-register/discard analysis for CR
This brings the analysis done for condition registers more in line with the analysis done for GPRs and FPRs. This gets rid of the old wantsCR member, which wasn't actually used anyway. In case someone wants it again in the future, they can compute the bitwise inverse of crDiscardable.
This commit is contained in:
parent
d6987b98be
commit
6cc4f593e5
@ -506,7 +506,7 @@ void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool r
|
|||||||
// Reorder integer compares, rlwinm., and carry-affecting ops
|
// Reorder integer compares, rlwinm., and carry-affecting ops
|
||||||
// (if we add more merged branch instructions, add them here!)
|
// (if we add more merged branch instructions, add them here!)
|
||||||
if ((type == ReorderType::CROR && isCror(a)) || (type == ReorderType::Carry && isCarryOp(a)) ||
|
if ((type == ReorderType::CROR && isCror(a)) || (type == ReorderType::Carry && isCarryOp(a)) ||
|
||||||
(type == ReorderType::CMP && (isCmp(a) || a.outputCR[0])))
|
(type == ReorderType::CMP && (isCmp(a) || a.crOut[0])))
|
||||||
{
|
{
|
||||||
// once we're next to a carry instruction, don't move away!
|
// once we're next to a carry instruction, don't move away!
|
||||||
if (type == ReorderType::Carry && i != start)
|
if (type == ReorderType::Carry && i != start)
|
||||||
@ -570,40 +570,40 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code,
|
|||||||
block->m_fpa->any = true;
|
block->m_fpa->any = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
code->wantsCR = BitSet8(0);
|
code->crIn = BitSet8(0);
|
||||||
if (opinfo->flags & FL_READ_ALL_CR)
|
if (opinfo->flags & FL_READ_ALL_CR)
|
||||||
{
|
{
|
||||||
code->wantsCR = BitSet8(0xFF);
|
code->crIn = BitSet8(0xFF);
|
||||||
}
|
}
|
||||||
else if (opinfo->flags & FL_READ_CRn)
|
else if (opinfo->flags & FL_READ_CRn)
|
||||||
{
|
{
|
||||||
code->wantsCR[code->inst.CRFS] = true;
|
code->crIn[code->inst.CRFS] = true;
|
||||||
}
|
}
|
||||||
else if (opinfo->flags & FL_READ_CR_BI)
|
else if (opinfo->flags & FL_READ_CR_BI)
|
||||||
{
|
{
|
||||||
code->wantsCR[code->inst.BI] = true;
|
code->crIn[code->inst.BI] = true;
|
||||||
}
|
}
|
||||||
else if (opinfo->type == OpType::CR)
|
else if (opinfo->type == OpType::CR)
|
||||||
{
|
{
|
||||||
code->wantsCR[code->inst.CRBA >> 2] = true;
|
code->crIn[code->inst.CRBA >> 2] = true;
|
||||||
code->wantsCR[code->inst.CRBB >> 2] = true;
|
code->crIn[code->inst.CRBB >> 2] = true;
|
||||||
|
|
||||||
// CR instructions only write to one bit of the destination CR,
|
// CR instructions only write to one bit of the destination CR,
|
||||||
// so treat the other three bits of the destination as inputs
|
// so treat the other three bits of the destination as inputs
|
||||||
code->wantsCR[code->inst.CRBD >> 2] = true;
|
code->crIn[code->inst.CRBD >> 2] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
code->outputCR = BitSet8(0);
|
code->crOut = BitSet8(0);
|
||||||
if (opinfo->flags & FL_SET_ALL_CR)
|
if (opinfo->flags & FL_SET_ALL_CR)
|
||||||
code->outputCR = BitSet8(0xFF);
|
code->crOut = BitSet8(0xFF);
|
||||||
else if (opinfo->flags & FL_SET_CRn)
|
else if (opinfo->flags & FL_SET_CRn)
|
||||||
code->outputCR[code->inst.CRFD] = true;
|
code->crOut[code->inst.CRFD] = true;
|
||||||
else if ((opinfo->flags & FL_SET_CR0) || ((opinfo->flags & FL_RC_BIT) && code->inst.Rc))
|
else if ((opinfo->flags & FL_SET_CR0) || ((opinfo->flags & FL_RC_BIT) && code->inst.Rc))
|
||||||
code->outputCR[0] = true;
|
code->crOut[0] = true;
|
||||||
else if ((opinfo->flags & FL_SET_CR1) || ((opinfo->flags & FL_RC_BIT_F) && code->inst.Rc))
|
else if ((opinfo->flags & FL_SET_CR1) || ((opinfo->flags & FL_RC_BIT_F) && code->inst.Rc))
|
||||||
code->outputCR[1] = true;
|
code->crOut[1] = true;
|
||||||
else if (opinfo->type == OpType::CR)
|
else if (opinfo->type == OpType::CR)
|
||||||
code->outputCR[code->inst.CRBD >> 2] = true;
|
code->crOut[code->inst.CRBD >> 2] = true;
|
||||||
|
|
||||||
code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) != 0;
|
code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) != 0;
|
||||||
code->outputFPRF = (opinfo->flags & FL_SET_FPRF) != 0;
|
code->outputFPRF = (opinfo->flags & FL_SET_FPRF) != 0;
|
||||||
@ -972,9 +972,9 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||||||
|
|
||||||
// Scan for flag dependencies; assume the next block (or any branch that can leave the block)
|
// Scan for flag dependencies; assume the next block (or any branch that can leave the block)
|
||||||
// wants flags, to be safe.
|
// wants flags, to be safe.
|
||||||
BitSet8 wantsCR = BitSet8(0xFF);
|
|
||||||
bool wantsFPRF = true;
|
bool wantsFPRF = true;
|
||||||
bool wantsCA = true;
|
bool wantsCA = true;
|
||||||
|
BitSet8 crInUse, crDiscardable;
|
||||||
BitSet32 gprBlockInputs, gprInUse, fprInUse, gprDiscardable, fprDiscardable, fprInXmm;
|
BitSet32 gprBlockInputs, gprInUse, fprInUse, gprDiscardable, fprDiscardable, fprInXmm;
|
||||||
for (int i = block->m_num_instructions - 1; i >= 0; i--)
|
for (int i = block->m_num_instructions - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@ -991,27 +991,26 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||||||
const bool hle = !!HLE::TryReplaceFunction(op.address);
|
const bool hle = !!HLE::TryReplaceFunction(op.address);
|
||||||
const bool may_exit_block = hle || op.canEndBlock || op.canCauseException;
|
const bool may_exit_block = hle || op.canEndBlock || op.canCauseException;
|
||||||
|
|
||||||
const BitSet8 opWantsCR = op.wantsCR;
|
|
||||||
const bool opWantsFPRF = op.wantsFPRF;
|
const bool opWantsFPRF = op.wantsFPRF;
|
||||||
const bool opWantsCA = op.wantsCA;
|
const bool opWantsCA = op.wantsCA;
|
||||||
op.wantsCR = wantsCR | BitSet8(may_exit_block ? 0xFF : 0);
|
|
||||||
op.wantsFPRF = wantsFPRF || may_exit_block;
|
op.wantsFPRF = wantsFPRF || may_exit_block;
|
||||||
op.wantsCA = wantsCA || may_exit_block;
|
op.wantsCA = wantsCA || may_exit_block;
|
||||||
wantsCR |= opWantsCR | BitSet8(may_exit_block ? 0xFF : 0);
|
|
||||||
wantsFPRF |= opWantsFPRF || may_exit_block;
|
wantsFPRF |= opWantsFPRF || may_exit_block;
|
||||||
wantsCA |= opWantsCA || may_exit_block;
|
wantsCA |= opWantsCA || may_exit_block;
|
||||||
wantsCR &= ~op.outputCR | opWantsCR;
|
|
||||||
wantsFPRF &= !op.outputFPRF || opWantsFPRF;
|
wantsFPRF &= !op.outputFPRF || opWantsFPRF;
|
||||||
wantsCA &= !op.outputCA || opWantsCA;
|
wantsCA &= !op.outputCA || opWantsCA;
|
||||||
op.gprInUse = gprInUse;
|
op.gprInUse = gprInUse;
|
||||||
op.fprInUse = fprInUse;
|
op.fprInUse = fprInUse;
|
||||||
|
op.crInUse = crInUse;
|
||||||
op.gprDiscardable = gprDiscardable;
|
op.gprDiscardable = gprDiscardable;
|
||||||
op.fprDiscardable = fprDiscardable;
|
op.fprDiscardable = fprDiscardable;
|
||||||
|
op.crDiscardable = crDiscardable;
|
||||||
op.fprInXmm = fprInXmm;
|
op.fprInXmm = fprInXmm;
|
||||||
gprBlockInputs &= ~op.regsOut;
|
gprBlockInputs &= ~op.regsOut;
|
||||||
gprBlockInputs |= op.regsIn;
|
gprBlockInputs |= op.regsIn;
|
||||||
gprInUse |= op.regsIn | op.regsOut;
|
gprInUse |= op.regsIn | op.regsOut;
|
||||||
fprInUse |= op.fregsIn | op.GetFregsOut();
|
fprInUse |= op.fregsIn | op.GetFregsOut();
|
||||||
|
crInUse |= op.crIn | op.crOut;
|
||||||
|
|
||||||
if (strncmp(op.opinfo->opname, "stfd", 4))
|
if (strncmp(op.opinfo->opname, "stfd", 4))
|
||||||
fprInXmm |= op.fregsIn;
|
fprInXmm |= op.fregsIn;
|
||||||
@ -1023,11 +1022,13 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||||||
fprInXmm = BitSet32{};
|
fprInXmm = BitSet32{};
|
||||||
gprDiscardable = BitSet32{};
|
gprDiscardable = BitSet32{};
|
||||||
fprDiscardable = BitSet32{};
|
fprDiscardable = BitSet32{};
|
||||||
|
crDiscardable = BitSet8{};
|
||||||
}
|
}
|
||||||
else if (op.canEndBlock || op.canCauseException)
|
else if (op.canEndBlock || op.canCauseException)
|
||||||
{
|
{
|
||||||
gprDiscardable = BitSet32{};
|
gprDiscardable = BitSet32{};
|
||||||
fprDiscardable = BitSet32{};
|
fprDiscardable = BitSet32{};
|
||||||
|
crDiscardable = BitSet8{};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1035,6 +1036,8 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||||||
gprDiscardable &= ~op.regsIn;
|
gprDiscardable &= ~op.regsIn;
|
||||||
fprDiscardable |= op.GetFregsOut();
|
fprDiscardable |= op.GetFregsOut();
|
||||||
fprDiscardable &= ~op.fregsIn;
|
fprDiscardable &= ~op.fregsIn;
|
||||||
|
crDiscardable |= op.crOut;
|
||||||
|
crDiscardable &= ~op.crIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,12 @@ struct CodeOp // 16B
|
|||||||
const GekkoOPInfo* opinfo = nullptr;
|
const GekkoOPInfo* opinfo = nullptr;
|
||||||
u32 address = 0;
|
u32 address = 0;
|
||||||
u32 branchTo = 0; // if UINT32_MAX, not a branch
|
u32 branchTo = 0; // if UINT32_MAX, not a branch
|
||||||
BitSet32 regsOut;
|
|
||||||
BitSet32 regsIn;
|
BitSet32 regsIn;
|
||||||
|
BitSet32 regsOut;
|
||||||
BitSet32 fregsIn;
|
BitSet32 fregsIn;
|
||||||
s8 fregOut = 0;
|
s8 fregOut = 0;
|
||||||
|
BitSet8 crIn;
|
||||||
|
BitSet8 crOut;
|
||||||
bool isBranchTarget = false;
|
bool isBranchTarget = false;
|
||||||
bool branchUsesCtr = false;
|
bool branchUsesCtr = false;
|
||||||
bool branchIsIdleLoop = false;
|
bool branchIsIdleLoop = false;
|
||||||
@ -50,6 +52,8 @@ struct CodeOp // 16B
|
|||||||
bool canCauseException = false;
|
bool canCauseException = false;
|
||||||
bool skipLRStack = false;
|
bool skipLRStack = false;
|
||||||
bool skip = false; // followed BL-s for example
|
bool skip = false; // followed BL-s for example
|
||||||
|
BitSet8 crInUse;
|
||||||
|
BitSet8 crDiscardable;
|
||||||
// which registers are still needed after this instruction in this block
|
// which registers are still needed after this instruction in this block
|
||||||
BitSet32 fprInUse;
|
BitSet32 fprInUse;
|
||||||
BitSet32 gprInUse;
|
BitSet32 gprInUse;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user