Implement switch case generation.

This commit is contained in:
Skyth 2024-09-18 11:37:50 +03:00
parent fc43264f72
commit e0cb6c7903
4 changed files with 59 additions and 4 deletions

View File

@ -10,6 +10,14 @@ endif()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
include(FetchContent)
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)
add_subdirectory(${THIRDPARTY_ROOT}/disasm)
project ("PowerRecomp-ALL")

View File

@ -3,4 +3,4 @@ cmake_minimum_required (VERSION 3.8)
project("PowerRecomp")
add_executable(PowerRecomp "main.cpp")
target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse)
target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse tomlplusplus::tomlplusplus)

View File

@ -7,8 +7,10 @@
#include <filesystem>
#include <xbox.h>
#include <cassert>
#include <toml++/toml.hpp>
#include <unordered_map>
#define TEST_FILE "default.xex"
#define TEST_FILE "private/default.xex"
static uint64_t computeMask(uint32_t mstart, uint32_t mstop)
{
@ -23,6 +25,29 @@ int main()
const auto file = LoadFile(TEST_FILE).value();
auto image = Image::ParseImage(file.data(), file.size()).value();
std::println("Loading switch tables...");
struct SwitchTable
{
size_t r;
std::vector<size_t> labels;
};
std::unordered_map<size_t, SwitchTable> switchTables;
toml::table toml = toml::parse_file("out/switches.toml");
for (auto& entry : *toml["switch"].as_array())
{
auto& table = *entry.as_table();
SwitchTable switchTable;
switchTable.r = *table["r"].value<size_t>();
for (auto& array : *table["labels"].as_array())
switchTable.labels.push_back(*array.value<size_t>());
switchTables.emplace(*table["base"].value<size_t>(), std::move(switchTable));
}
std::println("Analysing functions...");
uint32_t cxxFrameHandler = std::byteswap(0x831B1C90);
@ -142,11 +167,16 @@ int main()
println("\tPPCRegister temp;");
println("\tuint32_t ea;\n");
auto switchTable = switchTables.end();
ppc_insn insn;
while (base < end)
{
println("loc_{:X}:", base);
if (switchTable == switchTables.end())
switchTable = switchTables.find(base);
ppc::Disassemble(data, 4, base, insn);
base += 4;
@ -264,8 +294,23 @@ int main()
break;
case PPC_INST_BCTR:
println("\tctx.fn[ctx.ctr / 4](ctx, base);");
println("\treturn;");
if (switchTable != switchTables.end())
{
println("\tswitch (ctx.r{}.u64) {{", switchTable->second.r);
for (size_t i = 0; i < switchTable->second.labels.size(); i++)
println("\t\tcase {}: goto loc_{:X};", i, switchTable->second.labels[i]);
println("\t\tdefault: __unreachable();");
println("\t}}");
switchTable = switchTables.end();
}
else
{
println("\tctx.fn[ctx.ctr / 4](ctx, base);");
println("\treturn;");
}
break;
case PPC_INST_BCTRL:

View File

@ -12,10 +12,12 @@
#define _byteswap_uint64 __builtin_bswap64
#define isnan __builtin_isnan
#define __assume __builtin_assume
#define __unreachable() __builtin_unreachable()
#define PPC_FUNC __attribute__((weak,noinline))
#else
#include <intrin.h>
#define PPC_FUNC __declspec(noinline)
#define __unreachable() __assume(0)
#endif
#define PPC_LOAD_U8(x) *(uint8_t*)(base + (x))