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:
JosJuice 2021-06-29 15:18:55 +02:00
parent d6987b98be
commit 6cc4f593e5
2 changed files with 27 additions and 20 deletions

View File

@ -506,7 +506,7 @@ void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool r
// Reorder integer compares, rlwinm., and carry-affecting ops
// (if we add more merged branch instructions, add them here!)
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!
if (type == ReorderType::Carry && i != start)
@ -570,40 +570,40 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code,
block->m_fpa->any = true;
}
code->wantsCR = BitSet8(0);
code->crIn = BitSet8(0);
if (opinfo->flags & FL_READ_ALL_CR)
{
code->wantsCR = BitSet8(0xFF);
code->crIn = BitSet8(0xFF);
}
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)
{
code->wantsCR[code->inst.BI] = true;
code->crIn[code->inst.BI] = true;
}
else if (opinfo->type == OpType::CR)
{
code->wantsCR[code->inst.CRBA >> 2] = true;
code->wantsCR[code->inst.CRBB >> 2] = true;
code->crIn[code->inst.CRBA >> 2] = true;
code->crIn[code->inst.CRBB >> 2] = true;
// CR instructions only write to one bit of the destination CR,
// 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)
code->outputCR = BitSet8(0xFF);
code->crOut = BitSet8(0xFF);
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))
code->outputCR[0] = true;
code->crOut[0] = true;
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)
code->outputCR[code->inst.CRBD >> 2] = true;
code->crOut[code->inst.CRBD >> 2] = true;
code->wantsFPRF = (opinfo->flags & FL_READ_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)
// wants flags, to be safe.
BitSet8 wantsCR = BitSet8(0xFF);
bool wantsFPRF = true;
bool wantsCA = true;
BitSet8 crInUse, crDiscardable;
BitSet32 gprBlockInputs, gprInUse, fprInUse, gprDiscardable, fprDiscardable, fprInXmm;
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 may_exit_block = hle || op.canEndBlock || op.canCauseException;
const BitSet8 opWantsCR = op.wantsCR;
const bool opWantsFPRF = op.wantsFPRF;
const bool opWantsCA = op.wantsCA;
op.wantsCR = wantsCR | BitSet8(may_exit_block ? 0xFF : 0);
op.wantsFPRF = wantsFPRF || may_exit_block;
op.wantsCA = wantsCA || may_exit_block;
wantsCR |= opWantsCR | BitSet8(may_exit_block ? 0xFF : 0);
wantsFPRF |= opWantsFPRF || may_exit_block;
wantsCA |= opWantsCA || may_exit_block;
wantsCR &= ~op.outputCR | opWantsCR;
wantsFPRF &= !op.outputFPRF || opWantsFPRF;
wantsCA &= !op.outputCA || opWantsCA;
op.gprInUse = gprInUse;
op.fprInUse = fprInUse;
op.crInUse = crInUse;
op.gprDiscardable = gprDiscardable;
op.fprDiscardable = fprDiscardable;
op.crDiscardable = crDiscardable;
op.fprInXmm = fprInXmm;
gprBlockInputs &= ~op.regsOut;
gprBlockInputs |= op.regsIn;
gprInUse |= op.regsIn | op.regsOut;
fprInUse |= op.fregsIn | op.GetFregsOut();
crInUse |= op.crIn | op.crOut;
if (strncmp(op.opinfo->opname, "stfd", 4))
fprInXmm |= op.fregsIn;
@ -1023,11 +1022,13 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
fprInXmm = BitSet32{};
gprDiscardable = BitSet32{};
fprDiscardable = BitSet32{};
crDiscardable = BitSet8{};
}
else if (op.canEndBlock || op.canCauseException)
{
gprDiscardable = BitSet32{};
fprDiscardable = BitSet32{};
crDiscardable = BitSet8{};
}
else
{
@ -1035,6 +1036,8 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
gprDiscardable &= ~op.regsIn;
fprDiscardable |= op.GetFregsOut();
fprDiscardable &= ~op.fregsIn;
crDiscardable |= op.crOut;
crDiscardable &= ~op.crIn;
}
}

View File

@ -32,10 +32,12 @@ struct CodeOp // 16B
const GekkoOPInfo* opinfo = nullptr;
u32 address = 0;
u32 branchTo = 0; // if UINT32_MAX, not a branch
BitSet32 regsOut;
BitSet32 regsIn;
BitSet32 regsOut;
BitSet32 fregsIn;
s8 fregOut = 0;
BitSet8 crIn;
BitSet8 crOut;
bool isBranchTarget = false;
bool branchUsesCtr = false;
bool branchIsIdleLoop = false;
@ -50,6 +52,8 @@ struct CodeOp // 16B
bool canCauseException = false;
bool skipLRStack = false;
bool skip = false; // followed BL-s for example
BitSet8 crInUse;
BitSet8 crDiscardable;
// which registers are still needed after this instruction in this block
BitSet32 fprInUse;
BitSet32 gprInUse;