diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp b/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp index 048b316d..0453fae3 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp @@ -265,7 +265,7 @@ sint32 IMLRA_CountDistanceUntilFixedRegUsage(IMLSegment* imlSegment, raInstructi { if(fixedRegLoc.reg.IsInvalid() || fixedRegLoc.reg.GetRegID() != ourRegId) { - cemu_assert_debug(fixedRegLoc.physRegSet.HasExactlyOneAvailable()); // this whole function only makes sense when there is only one fixed register, otherwise there are extra permutations to consider + cemu_assert_debug(fixedRegLoc.reg.IsInvalid() || fixedRegLoc.physRegSet.HasExactlyOneAvailable()); // this whole function only makes sense when there is only one fixed register, otherwise there are extra permutations to consider. Except for IMLREG_INVALID which is used to indicate reserved registers if(fixedRegLoc.physRegSet.IsAvailable(physRegister)) return currentPos.GetRaw() - startPosition.GetRaw(); } @@ -572,30 +572,35 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment for(size_t i=0; isecond != entry.regId; - else - vgprHasChanged = true; - lastVGPR[physReg] = entry.regId; - - if(!vgprHasChanged) - continue; - - boost::container::small_vector overlappingRanges = IMLRA_GetRangeWithFixedRegReservationOverlappingPos(imlSegment, entry.pos, physReg); - if(entry.regId != IMLRegID_INVALID) - cemu_assert_debug(!overlappingRanges.empty()); // there should always be at least one range that overlaps corresponding to the fixed register requirement, except for IMLRegID_INVALID which is used to indicate reserved registers - - for(auto& range : overlappingRanges) + // we currently only handle fixed register requirements with a single register + // with one exception: When regId is IMLRegID_INVALID then the entry acts as a list of reserved registers + cemu_assert_debug(entry.regId == IMLRegID_INVALID || entry.allowedReg.HasExactlyOneAvailable()); + for(IMLPhysReg physReg = entry.allowedReg.GetFirstAvailableReg(); physReg >= 0; physReg = entry.allowedReg.GetNextAvailableReg(physReg+1)) { - if(range->interval2.start < entry.pos) + // check if the assigned vGPR has changed + bool vgprHasChanged = false; + auto it = lastVGPR.find(physReg); + if(it != lastVGPR.end()) + vgprHasChanged = it->second != entry.regId; + else + vgprHasChanged = true; + lastVGPR[physReg] = entry.regId; + + if(!vgprHasChanged) + continue; + + boost::container::small_vector overlappingRanges = IMLRA_GetRangeWithFixedRegReservationOverlappingPos(imlSegment, entry.pos, physReg); + if(entry.regId != IMLRegID_INVALID) + cemu_assert_debug(!overlappingRanges.empty()); // there should always be at least one range that overlaps corresponding to the fixed register requirement, except for IMLRegID_INVALID which is used to indicate reserved registers + + for(auto& range : overlappingRanges) { - PPCRecRA_splitLocalSubrange2(ppcImlGenContext, range, entry.pos, true); + if(range->interval2.start < entry.pos) + { + PPCRecRA_splitLocalSubrange2(ppcImlGenContext, range, entry.pos, true); + } } + } } // finally iterate ranges and assign fixed registers diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp index db48b9c0..980c9ce0 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp @@ -396,13 +396,14 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP { return nullptr; } - - if (ppcRecFunc->ppcAddress == 0x2B7A8D4) + if (ActiveSettings::DumpRecompilerFunctionsEnabled()) { - // write code to binary file - FILE* f = fopen("ppcRecFunc_2B7A8D4.bin", "wb"); - fwrite(ppcRecFunc->x86Code, 1, ppcRecFunc->x86Size, f); - fclose(f); + FileStream* fs = FileStream::createFile2(ActiveSettings::GetUserDataPath(fmt::format("dump/recompiler/ppc_{:08x}.bin", ppcRecFunc->ppcAddress))); + if (fs) + { + fs->writeData(ppcRecFunc->x86Code, ppcRecFunc->x86Size); + delete fs; + } } // collect list of PPC-->x64 entry points diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index f81f8336..e552d164 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -165,6 +165,11 @@ bool ActiveSettings::DumpTexturesEnabled() return s_dump_textures; } +bool ActiveSettings::DumpRecompilerFunctionsEnabled() +{ + return s_dump_recompiler_functions; +} + bool ActiveSettings::DumpLibcurlRequestsEnabled() { return s_dump_libcurl_requests; @@ -180,6 +185,11 @@ void ActiveSettings::EnableDumpTextures(bool state) s_dump_textures = state; } +void ActiveSettings::EnableDumpRecompilerFunctions(bool state) +{ + s_dump_recompiler_functions = state; +} + void ActiveSettings::EnableDumpLibcurlRequests(bool state) { s_dump_libcurl_requests = state; diff --git a/src/config/ActiveSettings.h b/src/config/ActiveSettings.h index e672fbee..0d7ecfec 100644 --- a/src/config/ActiveSettings.h +++ b/src/config/ActiveSettings.h @@ -109,9 +109,11 @@ public: // dump options [[nodiscard]] static bool DumpShadersEnabled(); [[nodiscard]] static bool DumpTexturesEnabled(); + [[nodiscard]] static bool DumpRecompilerFunctionsEnabled(); [[nodiscard]] static bool DumpLibcurlRequestsEnabled(); static void EnableDumpShaders(bool state); static void EnableDumpTextures(bool state); + static void EnableDumpRecompilerFunctions(bool state); static void EnableDumpLibcurlRequests(bool state); // hacks @@ -125,6 +127,7 @@ private: // dump options inline static bool s_dump_shaders = false; inline static bool s_dump_textures = false; + inline static bool s_dump_recompiler_functions = false; inline static bool s_dump_libcurl_requests = false; // timer speed diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 48bdd7d7..7649525b 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -144,6 +144,7 @@ enum // debug->dump MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600, MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, + MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, MAINFRAME_MENU_ID_DEBUG_DUMP_FST, MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, @@ -206,8 +207,9 @@ EVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_ EVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle) // debug -> dump menu -EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpUsedTextures) -EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MainWindow::OnDebugDumpUsedShaders) +EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpGeneric) +EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MainWindow::OnDebugDumpGeneric) +EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, MainWindow::OnDebugDumpGeneric) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, MainWindow::OnDebugSetting) // debug -> Other options EVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting) @@ -1091,31 +1093,29 @@ void MainWindow::OnPPCInfoToggle(wxCommandEvent& event) g_config.Save(); } -void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event) +void MainWindow::OnDebugDumpGeneric(wxCommandEvent& event) { - const bool value = event.IsChecked(); - ActiveSettings::EnableDumpTextures(value); - if (value) + std::string dumpSubpath; + std::function setDumpState; + switch(event.GetId()) { - try - { - // create directory - const fs::path path(ActiveSettings::GetUserDataPath()); - fs::create_directories(path / "dump" / "textures"); - } - catch (const std::exception& ex) - { - SystemException sys(ex); - cemuLog_log(LogType::Force, "can't create texture dump folder: {}", ex.what()); - ActiveSettings::EnableDumpTextures(false); - } + case MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES: + dumpSubpath = "dump/textures"; + setDumpState = ActiveSettings::EnableDumpTextures; + break; + case MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS: + dumpSubpath = "dump/shaders"; + setDumpState = ActiveSettings::EnableDumpShaders; + break; + case MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS: + dumpSubpath = "dump/recompiler"; + setDumpState = ActiveSettings::EnableDumpRecompilerFunctions; + break; + default: + UNREACHABLE; } -} - -void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event) -{ const bool value = event.IsChecked(); - ActiveSettings::EnableDumpShaders(value); + setDumpState(value); if (value) { try @@ -2239,6 +2239,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_CURL_REQUESTS, _("&nlibcurl HTTP/HTTPS requests"), wxEmptyString); // debug submenu wxMenu* debugMenu = new wxMenu(); diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index beb86f98..ddb9795d 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -107,8 +107,7 @@ public: void OnDebugSetting(wxCommandEvent& event); void OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event); void OnPPCInfoToggle(wxCommandEvent& event); - void OnDebugDumpUsedTextures(wxCommandEvent& event); - void OnDebugDumpUsedShaders(wxCommandEvent& event); + void OnDebugDumpGeneric(wxCommandEvent& event); void OnLoggingWindow(wxCommandEvent& event); void OnGDBStubToggle(wxCommandEvent& event); void OnDebugViewPPCThreads(wxCommandEvent& event);