PPCRec: Added dump option for recompiled functions + more fixes

This commit is contained in:
Exzap 2024-10-19 05:48:38 +02:00
parent b55785a0a0
commit 25794f70fa
6 changed files with 72 additions and 53 deletions

View file

@ -265,7 +265,7 @@ sint32 IMLRA_CountDistanceUntilFixedRegUsage(IMLSegment* imlSegment, raInstructi
{ {
if(fixedRegLoc.reg.IsInvalid() || fixedRegLoc.reg.GetRegID() != ourRegId) 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)) if(fixedRegLoc.physRegSet.IsAvailable(physRegister))
return currentPos.GetRaw() - startPosition.GetRaw(); return currentPos.GetRaw() - startPosition.GetRaw();
} }
@ -572,30 +572,35 @@ void IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment
for(size_t i=0; i<frr.size(); i++) for(size_t i=0; i<frr.size(); i++)
{ {
raFixedRegRequirementWithVGPR& entry = frr[i]; raFixedRegRequirementWithVGPR& entry = frr[i];
cemu_assert_debug(entry.allowedReg.HasExactlyOneAvailable()); // we currently only handle fixed register requirements with a single register // we currently only handle fixed register requirements with a single register
IMLPhysReg physReg = entry.allowedReg.GetFirstAvailableReg(); // with one exception: When regId is IMLRegID_INVALID then the entry acts as a list of reserved registers
// check if the assigned vGPR has changed cemu_assert_debug(entry.regId == IMLRegID_INVALID || entry.allowedReg.HasExactlyOneAvailable());
bool vgprHasChanged = false; for(IMLPhysReg physReg = entry.allowedReg.GetFirstAvailableReg(); physReg >= 0; physReg = entry.allowedReg.GetNextAvailableReg(physReg+1))
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<raLivenessRange*, 8> 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)
{ {
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<raLivenessRange*, 8> 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 // finally iterate ranges and assign fixed registers

View file

@ -396,13 +396,14 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP
{ {
return nullptr; return nullptr;
} }
if (ActiveSettings::DumpRecompilerFunctionsEnabled())
if (ppcRecFunc->ppcAddress == 0x2B7A8D4)
{ {
// write code to binary file FileStream* fs = FileStream::createFile2(ActiveSettings::GetUserDataPath(fmt::format("dump/recompiler/ppc_{:08x}.bin", ppcRecFunc->ppcAddress)));
FILE* f = fopen("ppcRecFunc_2B7A8D4.bin", "wb"); if (fs)
fwrite(ppcRecFunc->x86Code, 1, ppcRecFunc->x86Size, f); {
fclose(f); fs->writeData(ppcRecFunc->x86Code, ppcRecFunc->x86Size);
delete fs;
}
} }
// collect list of PPC-->x64 entry points // collect list of PPC-->x64 entry points

View file

@ -165,6 +165,11 @@ bool ActiveSettings::DumpTexturesEnabled()
return s_dump_textures; return s_dump_textures;
} }
bool ActiveSettings::DumpRecompilerFunctionsEnabled()
{
return s_dump_recompiler_functions;
}
bool ActiveSettings::DumpLibcurlRequestsEnabled() bool ActiveSettings::DumpLibcurlRequestsEnabled()
{ {
return s_dump_libcurl_requests; return s_dump_libcurl_requests;
@ -180,6 +185,11 @@ void ActiveSettings::EnableDumpTextures(bool state)
s_dump_textures = state; s_dump_textures = state;
} }
void ActiveSettings::EnableDumpRecompilerFunctions(bool state)
{
s_dump_recompiler_functions = state;
}
void ActiveSettings::EnableDumpLibcurlRequests(bool state) void ActiveSettings::EnableDumpLibcurlRequests(bool state)
{ {
s_dump_libcurl_requests = state; s_dump_libcurl_requests = state;

View file

@ -109,9 +109,11 @@ public:
// dump options // dump options
[[nodiscard]] static bool DumpShadersEnabled(); [[nodiscard]] static bool DumpShadersEnabled();
[[nodiscard]] static bool DumpTexturesEnabled(); [[nodiscard]] static bool DumpTexturesEnabled();
[[nodiscard]] static bool DumpRecompilerFunctionsEnabled();
[[nodiscard]] static bool DumpLibcurlRequestsEnabled(); [[nodiscard]] static bool DumpLibcurlRequestsEnabled();
static void EnableDumpShaders(bool state); static void EnableDumpShaders(bool state);
static void EnableDumpTextures(bool state); static void EnableDumpTextures(bool state);
static void EnableDumpRecompilerFunctions(bool state);
static void EnableDumpLibcurlRequests(bool state); static void EnableDumpLibcurlRequests(bool state);
// hacks // hacks
@ -125,6 +127,7 @@ private:
// dump options // dump options
inline static bool s_dump_shaders = false; inline static bool s_dump_shaders = false;
inline static bool s_dump_textures = false; inline static bool s_dump_textures = false;
inline static bool s_dump_recompiler_functions = false;
inline static bool s_dump_libcurl_requests = false; inline static bool s_dump_libcurl_requests = false;
// timer speed // timer speed

View file

@ -144,6 +144,7 @@ enum
// debug->dump // debug->dump
MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600, MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600,
MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS,
MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS,
MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, MAINFRAME_MENU_ID_DEBUG_DUMP_RAM,
MAINFRAME_MENU_ID_DEBUG_DUMP_FST, MAINFRAME_MENU_ID_DEBUG_DUMP_FST,
MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, 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_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) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle)
// debug -> dump menu // debug -> dump menu
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpUsedTextures) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpGeneric)
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MainWindow::OnDebugDumpUsedShaders) 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) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, MainWindow::OnDebugSetting)
// debug -> Other options // debug -> Other options
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting)
@ -1091,31 +1093,29 @@ void MainWindow::OnPPCInfoToggle(wxCommandEvent& event)
g_config.Save(); g_config.Save();
} }
void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event) void MainWindow::OnDebugDumpGeneric(wxCommandEvent& event)
{ {
const bool value = event.IsChecked(); std::string dumpSubpath;
ActiveSettings::EnableDumpTextures(value); std::function<void(bool)> setDumpState;
if (value) switch(event.GetId())
{ {
try case MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES:
{ dumpSubpath = "dump/textures";
// create directory setDumpState = ActiveSettings::EnableDumpTextures;
const fs::path path(ActiveSettings::GetUserDataPath()); break;
fs::create_directories(path / "dump" / "textures"); case MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS:
} dumpSubpath = "dump/shaders";
catch (const std::exception& ex) setDumpState = ActiveSettings::EnableDumpShaders;
{ break;
SystemException sys(ex); case MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS:
cemuLog_log(LogType::Force, "can't create texture dump folder: {}", ex.what()); dumpSubpath = "dump/recompiler";
ActiveSettings::EnableDumpTextures(false); setDumpState = ActiveSettings::EnableDumpRecompilerFunctions;
} break;
default:
UNREACHABLE;
} }
}
void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event)
{
const bool value = event.IsChecked(); const bool value = event.IsChecked();
ActiveSettings::EnableDumpShaders(value); setDumpState(value);
if (value) if (value)
{ {
try try
@ -2239,6 +2239,7 @@ void MainWindow::RecreateMenu()
wxMenu* debugDumpMenu = new wxMenu; wxMenu* debugDumpMenu = new wxMenu;
debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, _("&Textures"), wxEmptyString)->Check(ActiveSettings::DumpTexturesEnabled()); 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_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); debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, _("&nlibcurl HTTP/HTTPS requests"), wxEmptyString);
// debug submenu // debug submenu
wxMenu* debugMenu = new wxMenu(); wxMenu* debugMenu = new wxMenu();

View file

@ -107,8 +107,7 @@ public:
void OnDebugSetting(wxCommandEvent& event); void OnDebugSetting(wxCommandEvent& event);
void OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event); void OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event);
void OnPPCInfoToggle(wxCommandEvent& event); void OnPPCInfoToggle(wxCommandEvent& event);
void OnDebugDumpUsedTextures(wxCommandEvent& event); void OnDebugDumpGeneric(wxCommandEvent& event);
void OnDebugDumpUsedShaders(wxCommandEvent& event);
void OnLoggingWindow(wxCommandEvent& event); void OnLoggingWindow(wxCommandEvent& event);
void OnGDBStubToggle(wxCommandEvent& event); void OnGDBStubToggle(wxCommandEvent& event);
void OnDebugViewPPCThreads(wxCommandEvent& event); void OnDebugViewPPCThreads(wxCommandEvent& event);