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 // 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;
} }
} }

View File

@ -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;