diff --git a/boost.natvis b/boost.natvis index cee3e3d5..2781a585 100644 --- a/boost.natvis +++ b/boost.natvis @@ -11,4 +11,16 @@ + + {{ size={m_holder.m_size} }} + + m_holder.m_size + static_capacity + + m_holder.m_size + ($T1*)m_holder.storage.data + + + + diff --git a/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.cpp b/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.cpp index f60ac2b8..9c0b4416 100644 --- a/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.cpp @@ -7,6 +7,7 @@ #include "Cafe/OS/libs/coreinit/coreinit_Time.h" #include "util/MemMapper/MemMapper.h" #include "Common/cpu_features.h" +#include static x86Assembler64::GPR32 _reg32(IMLReg physReg) { @@ -658,29 +659,6 @@ bool PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction, return true; } -bool PPCRecompilerX64Gen_imlInstruction_conditional_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction) -{ - cemu_assert_unimplemented(); - //if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN) - //{ - // // registerResult = immS32 (conditional) - // if (imlInstruction->crRegister != PPC_REC_INVALID_REGISTER) - // { - // assert_dbg(); - // } - - // x64Gen_mov_reg64Low32_imm32(x64GenContext, REG_RESV_TEMP, (uint32)imlInstruction->op_conditional_r_s32.immS32); - // uint8 crBitIndex = imlInstruction->op_conditional_r_s32.crRegisterIndex * 4 + imlInstruction->op_conditional_r_s32.crBitIndex; - // x64Gen_bt_mem8(x64GenContext, X86_REG_RSP, offsetof(PPCInterpreter_t, cr) + crBitIndex * sizeof(uint8), 0); - // if (imlInstruction->op_conditional_r_s32.bitMustBeSet) - // x64Gen_cmovcc_reg64Low32_reg64Low32(x64GenContext, X86_CONDITION_CARRY, imlInstruction->op_conditional_r_s32.registerIndex, REG_RESV_TEMP); - // else - // x64Gen_cmovcc_reg64Low32_reg64Low32(x64GenContext, X86_CONDITION_NOT_CARRY, imlInstruction->op_conditional_r_s32.registerIndex, REG_RESV_TEMP); - // return true; - //} - return false; -} - bool PPCRecompilerX64Gen_imlInstruction_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction) { auto rRegResult = _reg32(imlInstruction->op_r_r_r.regR); @@ -973,47 +951,71 @@ bool PPCRecompilerX64Gen_imlInstruction_r_r_r_carry(PPCRecFunction_t* PPCRecFunc return true; } -bool PPCRecompilerX64Gen_imlInstruction_compare(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction) +bool PPCRecompilerX64Gen_IsSameCompare(IMLInstruction* imlInstructionA, IMLInstruction* imlInstructionB) { - auto regR = _reg8(imlInstruction->op_compare.regR); - auto regA = _reg32(imlInstruction->op_compare.regA); - auto regB = _reg32(imlInstruction->op_compare.regB); - X86Cond cond = _x86Cond(imlInstruction->op_compare.cond); - bool keepR = regR == regA || regR == regB; - if(!keepR) - { - x64GenContext->emitter->XOR_dd(_reg32_from_reg8(regR), _reg32_from_reg8(regR)); // zero bytes unaffected by SETcc - x64GenContext->emitter->CMP_dd(regA, regB); - x64GenContext->emitter->SETcc_b(cond, regR); - } - else - { - x64GenContext->emitter->CMP_dd(regA, regB); - x64GenContext->emitter->MOV_di32(_reg32_from_reg8(regR), 0); - x64GenContext->emitter->SETcc_b(cond, regR); - } - return true; + if(imlInstructionA->type != imlInstructionB->type) + return false; + if(imlInstructionA->type == PPCREC_IML_TYPE_COMPARE) + return imlInstructionA->op_compare.regA == imlInstructionB->op_compare.regA && imlInstructionA->op_compare.regB == imlInstructionB->op_compare.regB; + else if(imlInstructionA->type == PPCREC_IML_TYPE_COMPARE_S32) + return imlInstructionA->op_compare_s32.regA == imlInstructionB->op_compare_s32.regA && imlInstructionA->op_compare_s32.immS32 == imlInstructionB->op_compare_s32.immS32; + return false; } -bool PPCRecompilerX64Gen_imlInstruction_compare_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction) +bool PPCRecompilerX64Gen_imlInstruction_compare_x(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, sint32& extraInstructionsProcessed) { - auto regR = _reg8(imlInstruction->op_compare_s32.regR); - auto regA = _reg32(imlInstruction->op_compare_s32.regA); - sint32 imm = imlInstruction->op_compare_s32.immS32; - X86Cond cond = _x86Cond(imlInstruction->op_compare_s32.cond); - bool keepR = regR == regA; - if(!keepR) + extraInstructionsProcessed = 0; + boost::container::static_vector compareInstructions; + compareInstructions.push_back(imlInstruction); + for(sint32 i=1; i<4; i++) { - x64GenContext->emitter->XOR_dd(_reg32_from_reg8(regR), _reg32_from_reg8(regR)); // zero bytes unaffected by SETcc + IMLInstruction* nextIns = x64GenContext->GetNextInstruction(i); + if(!nextIns || !PPCRecompilerX64Gen_IsSameCompare(imlInstruction, nextIns)) + break; + compareInstructions.push_back(nextIns); + } + auto OperandOverlapsWithR = [&](IMLInstruction* ins) -> bool + { + if(ins->type == PPCREC_IML_TYPE_COMPARE) + return _reg32_from_reg8(_reg8(ins->op_compare.regR)) == _reg32(ins->op_compare.regA) || _reg32_from_reg8(_reg8(ins->op_compare.regR)) == _reg32(ins->op_compare.regB); + else if(ins->type == PPCREC_IML_TYPE_COMPARE_S32) + return _reg32_from_reg8(_reg8(ins->op_compare_s32.regR)) == _reg32(ins->op_compare_s32.regA); + }; + auto GetRegR = [](IMLInstruction* insn) + { + return insn->type == PPCREC_IML_TYPE_COMPARE ? _reg32_from_reg8(_reg8(insn->op_compare.regR)) : _reg32_from_reg8(_reg8(insn->op_compare_s32.regR)); + }; + // prefer XOR method for zeroing out registers if possible + for(auto& it : compareInstructions) + { + if(OperandOverlapsWithR(it)) + continue; + auto regR = GetRegR(it); + x64GenContext->emitter->XOR_dd(regR, regR); // zero bytes unaffected by SETcc + } + // emit the compare instruction + if(imlInstruction->type == PPCREC_IML_TYPE_COMPARE) + { + auto regA = _reg32(imlInstruction->op_compare.regA); + auto regB = _reg32(imlInstruction->op_compare.regB); + x64GenContext->emitter->CMP_dd(regA, regB); + } + else if(imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32) + { + auto regA = _reg32(imlInstruction->op_compare_s32.regA); + sint32 imm = imlInstruction->op_compare_s32.immS32; x64GenContext->emitter->CMP_di32(regA, imm); + } + // emit the SETcc instructions + for(auto& it : compareInstructions) + { + auto regR = _reg8(it->op_compare.regR); + X86Cond cond = _x86Cond(it->op_compare.cond); + if(OperandOverlapsWithR(it)) + x64GenContext->emitter->MOV_di32(_reg32_from_reg8(regR), 0); x64GenContext->emitter->SETcc_b(cond, regR); } - else - { - x64GenContext->emitter->CMP_di32(regA, imm); - x64GenContext->emitter->MOV_di32(_reg32_from_reg8(regR), 0); - x64GenContext->emitter->SETcc_b(cond, regR); - } + extraInstructionsProcessed = (sint32)compareInstructions.size() - 1; return true; } @@ -1383,6 +1385,7 @@ bool PPCRecompiler_generateX64Code(PPCRecFunction_t* PPCRecFunction, ppcImlGenCo segIt->x64Offset = x64GenContext.emitter->GetWriteIndex(); for(size_t i=0; iimlList.size(); i++) { + x64GenContext.m_currentInstructionEmitIndex = i; IMLInstruction* imlInstruction = segIt->imlList.data() + i; if( imlInstruction->type == PPCREC_IML_TYPE_R_NAME ) @@ -1403,11 +1406,6 @@ bool PPCRecompiler_generateX64Code(PPCRecFunction_t* PPCRecFunction, ppcImlGenCo if (PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false) codeGenerationFailed = true; } - else if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_R_S32) - { - if (PPCRecompilerX64Gen_imlInstruction_conditional_r_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false) - codeGenerationFailed = true; - } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32) { if (PPCRecompilerX64Gen_imlInstruction_r_r_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false) @@ -1428,13 +1426,11 @@ bool PPCRecompiler_generateX64Code(PPCRecFunction_t* PPCRecFunction, ppcImlGenCo if (PPCRecompilerX64Gen_imlInstruction_r_r_r_carry(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false) codeGenerationFailed = true; } - else if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE) + else if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE || imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32) { - PPCRecompilerX64Gen_imlInstruction_compare(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction); - } - else if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32) - { - PPCRecompilerX64Gen_imlInstruction_compare_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction); + sint32 extraInstructionsProcessed; + PPCRecompilerX64Gen_imlInstruction_compare_x(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, extraInstructionsProcessed); + i += extraInstructionsProcessed; } else if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP) { diff --git a/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.h b/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.h index 1a0fffec..a6646980 100644 --- a/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.h +++ b/src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.h @@ -15,6 +15,7 @@ struct x64GenContext_t { IMLSegment* currentSegment{}; x86Assembler64* emitter; + sint32 m_currentInstructionEmitIndex; x64GenContext_t() { @@ -26,6 +27,14 @@ struct x64GenContext_t delete emitter; } + IMLInstruction* GetNextInstruction(sint32 relativeIndex = 1) + { + sint32 index = m_currentInstructionEmitIndex + relativeIndex; + if(index < 0 || index >= (sint32)currentSegment->imlList.size()) + return nullptr; + return currentSegment->imlList.data() + index; + } + // relocate offsets std::vector relocateOffsetTable2; }; diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLDebug.cpp b/src/Cafe/HW/Espresso/Recompiler/IML/IMLDebug.cpp index 1cfb470d..07fd4002 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLDebug.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLDebug.cpp @@ -424,23 +424,6 @@ void IMLDebug_DisassembleInstruction(const IMLInstruction& inst, std::string& di { strOutput.addFmt("CYCLE_CHECK"); } - else if (inst.type == PPCREC_IML_TYPE_CONDITIONAL_R_S32) - { - strOutput.addFmt("{} ", IMLDebug_GetRegName(inst.op_conditional_r_s32.regR)); - bool displayAsHex = false; - if (inst.operation == PPCREC_IML_OP_ASSIGN) - { - displayAsHex = true; - strOutput.add("="); - } - else - strOutput.addFmt("(unknown operation CONDITIONAL_R_S32 {})", inst.operation); - if (displayAsHex) - strOutput.addFmt(" 0x{:x}", inst.op_conditional_r_s32.immS32); - else - strOutput.addFmt(" {}", inst.op_conditional_r_s32.immS32); - strOutput.add(" (conditional)"); - } else if (inst.type == PPCREC_IML_TYPE_X86_EFLAGS_JCC) { strOutput.addFmt("X86_JCC {}", IMLDebug_GetConditionName(inst.op_x86_eflags_jcc.cond)); diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.cpp b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.cpp index 480b0d8d..cb481043 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.cpp @@ -80,17 +80,6 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const registersUsed->writtenGPR1 = op_r_immS32.regR; } } - else if (type == PPCREC_IML_TYPE_CONDITIONAL_R_S32) - { - if (operation == PPCREC_IML_OP_ASSIGN) - { - // 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->writtenGPR1 = op_conditional_r_s32.regR; - } - else - cemu_assert_unimplemented(); - } else if (type == PPCREC_IML_TYPE_R_R_S32) { registersUsed->writtenGPR1 = op_r_r_s32.regR; @@ -117,9 +106,13 @@ void IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const else if (type == PPCREC_IML_TYPE_R_R_R) { // in all cases result is written and other operands are read only + // with the exception of XOR, where if regA == regB then all bits are zeroed out. So we don't consider it a read registersUsed->writtenGPR1 = op_r_r_r.regR; - registersUsed->readGPR1 = op_r_r_r.regA; - registersUsed->readGPR2 = op_r_r_r.regB; + if(!(operation == PPCREC_IML_OP_XOR && op_r_r_r.regA == op_r_r_r.regB)) + { + registersUsed->readGPR1 = op_r_r_r.regA; + registersUsed->readGPR2 = op_r_r_r.regB; + } } else if (type == PPCREC_IML_TYPE_R_R_R_CARRY) { @@ -502,10 +495,6 @@ void IMLInstruction::RewriteGPR(const std::unordered_map& tr { op_r_immS32.regR = replaceRegisterIdMultiple(op_r_immS32.regR, translationTable); } - else if (type == PPCREC_IML_TYPE_CONDITIONAL_R_S32) - { - op_conditional_r_s32.regR = replaceRegisterIdMultiple(op_conditional_r_s32.regR, translationTable); - } else if (type == PPCREC_IML_TYPE_R_R_S32) { op_r_r_s32.regR = replaceRegisterIdMultiple(op_r_r_s32.regR, translationTable); diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h index 2cd1d642..3ba0a1af 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h @@ -250,9 +250,6 @@ enum // atomic PPCREC_IML_TYPE_ATOMIC_CMP_STORE, - // conditional (legacy) - PPCREC_IML_TYPE_CONDITIONAL_R_S32, - // function call PPCREC_IML_TYPE_CALL_IMM, // call to fixed immediate address diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp index 55d4a94b..5ea424d3 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp @@ -54,23 +54,6 @@ IMLInstruction* PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext return &inst; } -void PPCRecompilerImlGen_generateNewInstruction_conditional_r_s32(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, uint32 operation, IMLReg registerIndex, sint32 immS32, uint32 crRegisterIndex, uint32 crBitIndex, bool bitMustBeSet) -{ - if(imlInstruction == NULL) - imlInstruction = PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext); - else - memset(imlInstruction, 0, sizeof(IMLInstruction)); - imlInstruction->type = PPCREC_IML_TYPE_CONDITIONAL_R_S32; - imlInstruction->operation = operation; - // r_s32 operation - imlInstruction->op_conditional_r_s32.regR = registerIndex; - imlInstruction->op_conditional_r_s32.immS32 = immS32; - // condition - imlInstruction->op_conditional_r_s32.crRegisterIndex = crRegisterIndex; - imlInstruction->op_conditional_r_s32.crBitIndex = crBitIndex; - imlInstruction->op_conditional_r_s32.bitMustBeSet = bitMustBeSet; -} - void PPCRecompilerImlGen_generateNewInstruction_r_memory_indexed(ppcImlGenContext_t* ppcImlGenContext, IMLReg registerDestination, IMLReg registerMemory1, IMLReg registerMemory2, uint32 copyWidth, bool signExtend, bool switchEndian) { cemu_assert_debug(registerMemory1.IsValid()); @@ -559,7 +542,6 @@ bool PPCRecompilerImlGen_BC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) uint32 BO, BI, BD; PPC_OPC_TEMPL_B(opcode, BO, BI, BD); - // decodeOp_BC(uint32 opcode, uint32& BD, BOField& BO, uint32& BI, bool& AA, bool& LK) Espresso::BOField boField(BO); uint32 crRegister = BI/4; diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index e38cb617..edc82276 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -2225,7 +2225,7 @@ void MainWindow::RecreateMenu() wxMenu* debugDumpMenu = new wxMenu; debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, _("&Textures"), wxEmptyString)->Check(ActiveSettings::DumpTexturesEnabled()); debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, _("&Shaders"), wxEmptyString)->Check(ActiveSettings::DumpShadersEnabled()); - debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, _("&Recompiler functions"), wxEmptyString)->Check(ActiveSettings::DumpRecompilerFunctionsEnabled()); + debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, _("&Recompiled functions"), wxEmptyString)->Check(ActiveSettings::DumpRecompilerFunctionsEnabled()); debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, _("&nlibcurl HTTP/HTTPS requests"), wxEmptyString); // debug submenu wxMenu* debugMenu = new wxMenu();