From 3b57fb1d21ef0ecbaecc6931c21b0a3f2abfe78b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 29 Jun 2021 14:00:58 +0200 Subject: [PATCH 1/3] PPCTables: Add new instruction flags for CR --- .../Core/PowerPC/Interpreter/Interpreter_Tables.cpp | 12 ++++++------ Source/Core/Core/PowerPC/PPCTables.h | 11 ++++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp index caecbd368a..8b14bb4b1e 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -29,7 +29,7 @@ static std::array primarytable = {59, Interpreter::RunTable59, {"RunTable59", OpType::Subtable, 0, 0, 0, 0, 0}}, {63, Interpreter::RunTable63, {"RunTable63", OpType::Subtable, 0, 0, 0, 0, 0}}, - {16, Interpreter::bcx, {"bcx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}}, + {16, Interpreter::bcx, {"bcx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, {18, Interpreter::bx, {"bx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}}, {3, Interpreter::twi, {"twi", OpType::System, FL_IN_A | FL_ENDBLOCK, 1, 0, 0, 0}}, @@ -143,8 +143,8 @@ static std::array table4_3 = static std::array table19 = {{ - {528, Interpreter::bcctrx, {"bcctrx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}}, - {16, Interpreter::bclrx, {"bclrx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}}, + {528, Interpreter::bcctrx, {"bcctrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, + {16, Interpreter::bclrx, {"bclrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, {257, Interpreter::crand, {"crand", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, {129, Interpreter::crandc, {"crandc", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, {289, Interpreter::creqv, {"creqv", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, @@ -155,7 +155,7 @@ static std::array table19 = {193, Interpreter::crxor, {"crxor", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, {150, Interpreter::isync, {"isync", OpType::InstructionCache, FL_EVIL, 1, 0, 0, 0}}, - {0, Interpreter::mcrf, {"mcrf", OpType::System, FL_EVIL | FL_SET_CRn, 1, 0, 0, 0}}, + {0, Interpreter::mcrf, {"mcrf", OpType::System, FL_EVIL | FL_SET_CRn | FL_READ_CRn, 1, 0, 0, 0}}, {50, Interpreter::rfi, {"rfi", OpType::System, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}}, }}; @@ -278,9 +278,9 @@ static std::array table31 = {759, Interpreter::stfdux, {"stfdux", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, {983, Interpreter::stfiwx, {"stfiwx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {19, Interpreter::mfcr, {"mfcr", OpType::System, FL_OUT_D, 1, 0, 0, 0}}, + {19, Interpreter::mfcr, {"mfcr", OpType::System, FL_OUT_D | FL_READ_ALL_CR, 1, 0, 0, 0}}, {83, Interpreter::mfmsr, {"mfmsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {144, Interpreter::mtcrf, {"mtcrf", OpType::System, FL_IN_S | FL_SET_CRn, 1, 0, 0, 0}}, + {144, Interpreter::mtcrf, {"mtcrf", OpType::System, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR, 1, 0, 0, 0}}, {146, Interpreter::mtmsr, {"mtmsr", OpType::System, FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {210, Interpreter::mtsr, {"mtsr", OpType::System, FL_IN_S | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {242, Interpreter::mtsrin, {"mtsrin", OpType::System, FL_IN_SB | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, diff --git a/Source/Core/Core/PowerPC/PPCTables.h b/Source/Core/Core/PowerPC/PPCTables.h index f88d5d8ef3..81567a452f 100644 --- a/Source/Core/Core/PowerPC/PPCTables.h +++ b/Source/Core/Core/PowerPC/PPCTables.h @@ -15,8 +15,7 @@ enum InstructionFlags : u64 { FL_SET_CR0 = (1ull << 0), // Sets CR0. FL_SET_CR1 = (1ull << 1), // Sets CR1. - FL_SET_CRn = (1ull << 2), // Encoding decides which CR can be set. - FL_SET_CRx = FL_SET_CR0 | FL_SET_CR1 | FL_SET_CRn, + FL_SET_CRn = (1ull << 2), // Sets a CR determined by the CRFD field. FL_SET_CA = (1ull << 3), // Sets the carry flag. FL_READ_CA = (1ull << 4), // Reads the carry flag. FL_RC_BIT = (1ull << 5), // Sets the record bit. @@ -66,7 +65,13 @@ enum InstructionFlags : u64 FL_IN_FLOAT_BC_BITEXACT = FL_IN_FLOAT_B_BITEXACT | FL_IN_FLOAT_C_BITEXACT, FL_PROGRAMEXCEPTION = (1ull << 32), // May generate a program exception (not floating point). FL_FLOAT_EXCEPTION = (1ull << 33), // May generate a program exception (floating point). - FL_FLOAT_DIV = (1ull << 34), // May generate a program exception (FP) due to division by 0. + FL_FLOAT_DIV = (1ull << 34), // May generate a program exception (FP) due to division by 0. + FL_SET_ALL_CR = (1ull << 35), // Sets every CR. + FL_READ_CRn = (1ull << 36), // Reads a CR determined by the CRFS field. + FL_READ_CR_BI = (1ull << 37), // Reads a CR determined by the BI field. + FL_READ_ALL_CR = (1ull << 38), // Reads every CR. + FL_SET_CRx = FL_SET_CR0 | FL_SET_CR1 | FL_SET_CRn | FL_SET_ALL_CR, + FL_READ_CRx = FL_READ_CRn | FL_READ_CR_BI | FL_READ_ALL_CR, }; enum class OpType From 9d2c4aa32594db5a7d9971420d43e3350c29d809 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 29 Jun 2021 14:25:56 +0200 Subject: [PATCH 2/3] PPCAnalyst: Use bitsets for CR analysis Currently we're only performing CR analysis for CR0 and CR1, but I would like to do it for all CRs. Bitsets are appropriate for this. --- Source/Core/Core/PowerPC/PPCAnalyst.cpp | 46 ++++++++++--------------- Source/Core/Core/PowerPC/PPCAnalyst.h | 6 ++-- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index ee15a21052..127d3f1cd4 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -475,7 +475,7 @@ void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool r // (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.outputCR0))) + (type == ReorderType::CMP && (isCmp(a) || a.outputCR[0]))) { // once we're next to a carry instruction, don't move away! if (type == ReorderType::Carry && i != start) @@ -524,9 +524,6 @@ void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp* code) const void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, const GekkoOPInfo* opinfo) const { - code->wantsCR0 = false; - code->wantsCR1 = false; - bool first_fpu_instruction = false; if (opinfo->flags & FL_USE_FPU) { @@ -534,21 +531,16 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, block->m_fpa->any = true; } - // Does the instruction output CR0? - if (opinfo->flags & FL_RC_BIT) - code->outputCR0 = code->inst.hex & 1; // todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 0) - code->outputCR0 = true; - else - code->outputCR0 = (opinfo->flags & FL_SET_CR0) != 0; - - // Does the instruction output CR1? - if (opinfo->flags & FL_RC_BIT_F) - code->outputCR1 = code->inst.hex & 1; // todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 1) - code->outputCR1 = true; - else - code->outputCR1 = (opinfo->flags & FL_SET_CR1) != 0; + code->wantsCR = BitSet8(0); + code->outputCR = BitSet8(0); + if (opinfo->flags & FL_SET_ALL_CR) + code->outputCR = BitSet8(0xFF); + else if (opinfo->flags & FL_SET_CRn) + code->outputCR[code->inst.CRFD] = true; + else if ((opinfo->flags & FL_SET_CR0) || ((opinfo->flags & FL_RC_BIT) && code->inst.Rc)) + code->outputCR[0] = true; + else if ((opinfo->flags & FL_SET_CR1) || ((opinfo->flags & FL_RC_BIT_F) && code->inst.Rc)) + code->outputCR[1] = true; code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) != 0; code->outputFPRF = (opinfo->flags & FL_SET_FPRF) != 0; @@ -906,26 +898,24 @@ 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. - bool wantsCR0 = true, wantsCR1 = true, wantsFPRF = true, wantsCA = true; + BitSet8 wantsCR = BitSet8(0xFF); + bool wantsFPRF = true; + bool wantsCA = true; BitSet32 fprInUse, gprInUse, gprDiscardable, fprDiscardable, fprInXmm; for (int i = block->m_num_instructions - 1; i >= 0; i--) { CodeOp& op = code[i]; - const bool opWantsCR0 = op.wantsCR0; - const bool opWantsCR1 = op.wantsCR1; + const BitSet8 opWantsCR = op.wantsCR; const bool opWantsFPRF = op.wantsFPRF; const bool opWantsCA = op.wantsCA; - op.wantsCR0 = wantsCR0 || op.canEndBlock || op.canCauseException; - op.wantsCR1 = wantsCR1 || op.canEndBlock || op.canCauseException; + op.wantsCR = wantsCR | BitSet8(op.canEndBlock || op.canCauseException ? 0xFF : 0); op.wantsFPRF = wantsFPRF || op.canEndBlock || op.canCauseException; op.wantsCA = wantsCA || op.canEndBlock || op.canCauseException; - wantsCR0 |= opWantsCR0 || op.canEndBlock || op.canCauseException; - wantsCR1 |= opWantsCR1 || op.canEndBlock || op.canCauseException; + wantsCR |= opWantsCR | BitSet8(op.canEndBlock || op.canCauseException ? 0xFF : 0); wantsFPRF |= opWantsFPRF || op.canEndBlock || op.canCauseException; wantsCA |= opWantsCA || op.canEndBlock || op.canCauseException; - wantsCR0 &= !op.outputCR0 || opWantsCR0; - wantsCR1 &= !op.outputCR1 || opWantsCR1; + wantsCR &= ~op.outputCR | opWantsCR; wantsFPRF &= !op.outputFPRF || opWantsFPRF; wantsCA &= !op.outputCA || opWantsCA; op.gprInUse = gprInUse; diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h index 283706ebc1..73bf707b51 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/PowerPC/PPCAnalyst.h @@ -34,13 +34,11 @@ struct CodeOp // 16B bool isBranchTarget = false; bool branchUsesCtr = false; bool branchIsIdleLoop = false; - bool wantsCR0 = false; - bool wantsCR1 = false; + BitSet8 wantsCR; bool wantsFPRF = false; bool wantsCA = false; bool wantsCAInFlags = false; - bool outputCR0 = false; - bool outputCR1 = false; + BitSet8 outputCR; bool outputFPRF = false; bool outputCA = false; bool canEndBlock = false; From e27339039caa8d2621b5d503acf2687936b3203d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 29 Jun 2021 14:59:38 +0200 Subject: [PATCH 3/3] PPCAnalyst: Actually check if instructions want CR --- Source/Core/Core/PowerPC/PPCAnalyst.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index 127d3f1cd4..f6d9459e21 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -532,6 +532,13 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, } code->wantsCR = BitSet8(0); + if (opinfo->flags & FL_READ_ALL_CR) + code->wantsCR = BitSet8(0xFF); + else if (opinfo->flags & FL_READ_CRn) + code->wantsCR[code->inst.CRFS] = true; + else if (opinfo->flags & FL_READ_CR_BI) + code->wantsCR[code->inst.BI] = true; + code->outputCR = BitSet8(0); if (opinfo->flags & FL_SET_ALL_CR) code->outputCR = BitSet8(0xFF);