From 10ad5db686900311b607319789db978ee5ec7978 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 1 Feb 2022 13:00:29 -0800 Subject: [PATCH] Adds an option to disable the IR interpreter By default we won't build with the interpeter to reduce user confusion. The interpreter isn't really useful to end users so remove it. Completely removes it from building except for the fallback operations. This also removes the selection from FEXConfig to remove selection confusion there. File Stats: FEXLoader Size with Interpreter: 3422768 bytes FEXLoader Size without Interpreter: 3301944 bytes Size difference: 96.4699915% Bytes removed: 120824 bytes 4k pages removed: 29.498046875 -> 30 rounded up VM Stats (Reported from bloaty): Memory Size with Interpreter: 6.50Mi Memory Size without Interpreter: 6.38Mi Size difference: 98.1538462% --- .github/workflows/ccpp.yml | 2 +- CMakeLists.txt | 6 + External/FEXCore/Source/CMakeLists.txt | 31 +-- .../Source/Interface/Config/Config.cpp | 7 +- .../FEXCore/Source/Interface/Core/Core.cpp | 2 + .../Core/Interpreter/InterpreterFallbacks.cpp | 209 ++++++++++++++++++ .../Core/Interpreter/InterpreterOps.cpp | 199 ----------------- Source/Tools/FEXConfig/Main.cpp | 3 +- 8 files changed, 244 insertions(+), 215 deletions(-) create mode 100644 External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index c23e2c71f..f427e5ed3 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -51,7 +51,7 @@ jobs: # Note the current convention is to use the -S and -B options here to specify source # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DENABLE_INTERPRETER=True - name: Build working-directory: ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index 69f4b405a..825742012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ option(ENABLE_JEMALLOC "Enables jemalloc allocator" TRUE) option(ENABLE_OFFLINE_TELEMETRY "Enables FEX offline telemetry" TRUE) option(ENABLE_COMPILE_TIME_TRACE "Enables time trace compile option" FALSE) option(ENABLE_LIBCXX "Enables LLVM libc++" FALSE) +option(ENABLE_INTERPRETER "Enables FEX's Interpreter" FALSE) set (X86_C_COMPILER "x86_64-linux-gnu-gcc" CACHE STRING "c compiler for compiling x86 guest libs") set (X86_CXX_COMPILER "x86_64-linux-gnu-g++" CACHE STRING "c++ compiler for compiling x86 guest libs") @@ -39,6 +40,11 @@ if (ENABLE_ASSERTIONS) add_definitions(-DASSERTIONS_ENABLED=1) endif() +if (ENABLE_INTERPRETER) + message(STATUS "Interpreter enabled") + add_definitions(-DINTERPRETER_ENABLED=1) +endif() + set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Bin) diff --git a/External/FEXCore/Source/CMakeLists.txt b/External/FEXCore/Source/CMakeLists.txt index c943c4ddb..123327598 100644 --- a/External/FEXCore/Source/CMakeLists.txt +++ b/External/FEXCore/Source/CMakeLists.txt @@ -100,19 +100,7 @@ set (SRCS Interface/Core/Dispatcher/Dispatcher.cpp Interface/Core/Dispatcher/X86Dispatcher.cpp Interface/Core/Dispatcher/Arm64Dispatcher.cpp - Interface/Core/Interpreter/InterpreterCore.cpp - Interface/Core/Interpreter/InterpreterOps.cpp - Interface/Core/Interpreter/ALUOps.cpp - Interface/Core/Interpreter/AtomicOps.cpp - Interface/Core/Interpreter/BranchOps.cpp - Interface/Core/Interpreter/ConversionOps.cpp - Interface/Core/Interpreter/EncryptionOps.cpp - Interface/Core/Interpreter/F80Ops.cpp - Interface/Core/Interpreter/FlagOps.cpp - Interface/Core/Interpreter/MemoryOps.cpp - Interface/Core/Interpreter/MiscOps.cpp - Interface/Core/Interpreter/MoveOps.cpp - Interface/Core/Interpreter/VectorOps.cpp + Interface/Core/Interpreter/InterpreterFallbacks.cpp Interface/Core/X86Tables/BaseTables.cpp Interface/Core/X86Tables/DDDTables.cpp Interface/Core/X86Tables/EVEXTables.cpp @@ -152,6 +140,23 @@ set (SRCS Utils/Threads.cpp ) +if (ENABLE_INTERPRETER) + list(APPEND SRCS + Interface/Core/Interpreter/InterpreterCore.cpp + Interface/Core/Interpreter/InterpreterOps.cpp + Interface/Core/Interpreter/ALUOps.cpp + Interface/Core/Interpreter/AtomicOps.cpp + Interface/Core/Interpreter/BranchOps.cpp + Interface/Core/Interpreter/ConversionOps.cpp + Interface/Core/Interpreter/EncryptionOps.cpp + Interface/Core/Interpreter/F80Ops.cpp + Interface/Core/Interpreter/FlagOps.cpp + Interface/Core/Interpreter/MemoryOps.cpp + Interface/Core/Interpreter/MiscOps.cpp + Interface/Core/Interpreter/MoveOps.cpp + Interface/Core/Interpreter/VectorOps.cpp) +endif() + if(_M_ARM_64) list(APPEND SRCS Interface/Core/ArchHelpers/Arm64.cpp) diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index f85b6d197..aabeb3c47 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -434,7 +434,12 @@ namespace JSON { #else constexpr uint32_t MaxCoreNumber = 1; #endif - if (Core > MaxCoreNumber) { +#ifdef INTERPRETER_ENABLED + constexpr uint32_t MinCoreNumber = 0; +#else + constexpr uint32_t MinCoreNumber = 1; +#endif + if (Core > MaxCoreNumber || Core < MinCoreNumber) { // Sanitize the core option by setting the core to the JIT if invalid FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_CORE, std::to_string(FEXCore::Config::CONFIG_IRJIT)); } diff --git a/External/FEXCore/Source/Interface/Core/Core.cpp b/External/FEXCore/Source/Interface/Core/Core.cpp index ee189a66e..497b224a1 100644 --- a/External/FEXCore/Source/Interface/Core/Core.cpp +++ b/External/FEXCore/Source/Interface/Core/Core.cpp @@ -493,9 +493,11 @@ namespace FEXCore::Context { // Create CPU backend switch (Config.Core) { +#ifdef INTERPRETER_ENABLED case FEXCore::Config::CONFIG_INTERPRETER: State->CPUBackend = FEXCore::CPU::CreateInterpreterCore(this, State, CompileThread); break; +#endif case FEXCore::Config::CONFIG_IRJIT: State->PassManager->InsertRegisterAllocationPass(DoSRA); diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp new file mode 100644 index 000000000..1434affa5 --- /dev/null +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp @@ -0,0 +1,209 @@ +#include "Interface/Core/Interpreter/InterpreterOps.h" +#include "Interface/Core/Interpreter/F80Ops.h" + +#include +#include + +namespace FEXCore::CPU { + +template +static FallbackInfo GetFallbackInfo(R(*fn)(Args...)) { + return {FABI_UNKNOWN, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(float)) { + return {FABI_F80_F32, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(double)) { + return {FABI_F80_F64, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(int16_t)) { + return {FABI_F80_I16, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(void(*fn)(uint16_t)) { + return {FABI_VOID_U16, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(int32_t)) { + return {FABI_F80_I32, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(float(*fn)(X80SoftFloat)) { + return {FABI_F32_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(double(*fn)(X80SoftFloat)) { + return {FABI_F64_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(int16_t(*fn)(X80SoftFloat)) { + return {FABI_I16_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(int32_t(*fn)(X80SoftFloat)) { + return {FABI_I32_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(int64_t(*fn)(X80SoftFloat)) { + return {FABI_I64_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(uint64_t(*fn)(X80SoftFloat, X80SoftFloat)) { + return {FABI_I64_F80_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(X80SoftFloat)) { + return {FABI_F80_F80, (void*)fn}; +} + +template<> +FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(X80SoftFloat, X80SoftFloat)) { + return {FABI_F80_F80_F80, (void*)fn}; +} + +bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info) { + uint8_t OpSize = IROp->Size; + switch(IROp->Op) { + case IR::OP_F80LOADFCW: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle); + return true; + } + + case IR::OP_F80CVTTO: { + auto Op = IROp->C(); + + switch (Op->Size) { + case 4: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); + return true; + } + case 8: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle8); + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CVT: { + switch (OpSize) { + case 4: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); + return true; + } + case 8: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle8); + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CVTINT: { + auto Op = IROp->C(); + + switch (OpSize) { + case 2: { + *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle2t : &FEXCore::CPU::OpHandlers::handle2); + return true; + } + case 4: { + *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle4t : &FEXCore::CPU::OpHandlers::handle4); + return true; + } + case 8: { + *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle8t : &FEXCore::CPU::OpHandlers::handle8); + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + case IR::OP_F80CMP: { + auto Op = IROp->C(); + + static constexpr std::array handlers{ + &FEXCore::CPU::OpHandlers::handle<0>, + &FEXCore::CPU::OpHandlers::handle<1>, + &FEXCore::CPU::OpHandlers::handle<2>, + &FEXCore::CPU::OpHandlers::handle<3>, + &FEXCore::CPU::OpHandlers::handle<4>, + &FEXCore::CPU::OpHandlers::handle<5>, + &FEXCore::CPU::OpHandlers::handle<6>, + &FEXCore::CPU::OpHandlers::handle<7>, + }; + + *Info = GetFallbackInfo(handlers[Op->Flags]); + return true; + } + + case IR::OP_F80CVTTOINT: { + auto Op = IROp->C(); + + switch (Op->Size) { + case 2: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle2); + return true; + } + case 4: { + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); + return true; + } + default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); + } + break; + } + +#define COMMON_X87_OP(OP) \ + case IR::OP_F80##OP: { \ + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle); \ + return true; \ + } + + // Unary + COMMON_X87_OP(ROUND) + COMMON_X87_OP(F2XM1) + COMMON_X87_OP(TAN) + COMMON_X87_OP(SQRT) + COMMON_X87_OP(SIN) + COMMON_X87_OP(COS) + COMMON_X87_OP(XTRACT_EXP) + COMMON_X87_OP(XTRACT_SIG) + COMMON_X87_OP(BCDSTORE) + COMMON_X87_OP(BCDLOAD) + + // Binary + COMMON_X87_OP(ADD) + COMMON_X87_OP(SUB) + COMMON_X87_OP(MUL) + COMMON_X87_OP(DIV) + COMMON_X87_OP(FYL2X) + COMMON_X87_OP(ATAN) + COMMON_X87_OP(FPREM1) + COMMON_X87_OP(FPREM) + COMMON_X87_OP(SCALE) + + default: + break; + } + + return false; +} + + +} diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp index a43cf0290..81f2e4324 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp @@ -322,205 +322,6 @@ void InterpreterOps::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, IROpData *Data void InterpreterOps::Op_NoOp(FEXCore::IR::IROp_Header *IROp, IROpData *Data, IR::NodeID Node) { } -template -static FallbackInfo GetFallbackInfo(R(*fn)(Args...)) { - return {FABI_UNKNOWN, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(float)) { - return {FABI_F80_F32, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(double)) { - return {FABI_F80_F64, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(int16_t)) { - return {FABI_F80_I16, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(void(*fn)(uint16_t)) { - return {FABI_VOID_U16, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(int32_t)) { - return {FABI_F80_I32, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(float(*fn)(X80SoftFloat)) { - return {FABI_F32_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(double(*fn)(X80SoftFloat)) { - return {FABI_F64_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(int16_t(*fn)(X80SoftFloat)) { - return {FABI_I16_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(int32_t(*fn)(X80SoftFloat)) { - return {FABI_I32_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(int64_t(*fn)(X80SoftFloat)) { - return {FABI_I64_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(uint64_t(*fn)(X80SoftFloat, X80SoftFloat)) { - return {FABI_I64_F80_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(X80SoftFloat)) { - return {FABI_F80_F80, (void*)fn}; -} - -template<> -FallbackInfo GetFallbackInfo(X80SoftFloat(*fn)(X80SoftFloat, X80SoftFloat)) { - return {FABI_F80_F80_F80, (void*)fn}; -} - -bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info) { - uint8_t OpSize = IROp->Size; - switch(IROp->Op) { - case IR::OP_F80LOADFCW: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle); - return true; - } - - case IR::OP_F80CVTTO: { - auto Op = IROp->C(); - - switch (Op->Size) { - case 4: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); - return true; - } - case 8: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle8); - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CVT: { - switch (OpSize) { - case 4: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); - return true; - } - case 8: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle8); - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CVTINT: { - auto Op = IROp->C(); - - switch (OpSize) { - case 2: { - *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle2t : &FEXCore::CPU::OpHandlers::handle2); - return true; - } - case 4: { - *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle4t : &FEXCore::CPU::OpHandlers::handle4); - return true; - } - case 8: { - *Info = GetFallbackInfo(Op->Truncate ? &FEXCore::CPU::OpHandlers::handle8t : &FEXCore::CPU::OpHandlers::handle8); - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - case IR::OP_F80CMP: { - auto Op = IROp->C(); - - static constexpr std::array handlers{ - &FEXCore::CPU::OpHandlers::handle<0>, - &FEXCore::CPU::OpHandlers::handle<1>, - &FEXCore::CPU::OpHandlers::handle<2>, - &FEXCore::CPU::OpHandlers::handle<3>, - &FEXCore::CPU::OpHandlers::handle<4>, - &FEXCore::CPU::OpHandlers::handle<5>, - &FEXCore::CPU::OpHandlers::handle<6>, - &FEXCore::CPU::OpHandlers::handle<7>, - }; - - *Info = GetFallbackInfo(handlers[Op->Flags]); - return true; - } - - case IR::OP_F80CVTTOINT: { - auto Op = IROp->C(); - - switch (Op->Size) { - case 2: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle2); - return true; - } - case 4: { - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle4); - return true; - } - default: LogMan::Msg::DFmt("Unhandled size: {}", OpSize); - } - break; - } - -#define COMMON_X87_OP(OP) \ - case IR::OP_F80##OP: { \ - *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle); \ - return true; \ - } - - // Unary - COMMON_X87_OP(ROUND) - COMMON_X87_OP(F2XM1) - COMMON_X87_OP(TAN) - COMMON_X87_OP(SQRT) - COMMON_X87_OP(SIN) - COMMON_X87_OP(COS) - COMMON_X87_OP(XTRACT_EXP) - COMMON_X87_OP(XTRACT_SIG) - COMMON_X87_OP(BCDSTORE) - COMMON_X87_OP(BCDLOAD) - - // Binary - COMMON_X87_OP(ADD) - COMMON_X87_OP(SUB) - COMMON_X87_OP(MUL) - COMMON_X87_OP(DIV) - COMMON_X87_OP(FYL2X) - COMMON_X87_OP(ATAN) - COMMON_X87_OP(FPREM1) - COMMON_X87_OP(FPREM) - COMMON_X87_OP(SCALE) - - default: - break; - } - - return false; -} - void InterpreterOps::InterpretIR(FEXCore::Core::InternalThreadState *Thread, uint64_t Entry, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData) { volatile void *StackEntry = alloca(0); diff --git a/Source/Tools/FEXConfig/Main.cpp b/Source/Tools/FEXConfig/Main.cpp index 8d5527b7b..23e1ef5fd 100644 --- a/Source/Tools/FEXConfig/Main.cpp +++ b/Source/Tools/FEXConfig/Main.cpp @@ -201,6 +201,7 @@ namespace { char EmulatedCPUCores[32]{}; if (ImGui::BeginTabItem("CPU")) { +#ifdef INTERPRETER_ENABLED ImGui::Text("Core:"); auto Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_CORE); @@ -214,7 +215,7 @@ namespace { LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_CORE, "1"); ConfigChanged = true; } - +#endif Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_MAXINST); if (Value.has_value() && !(*Value)->empty()) { strncpy(BlockSize, &(*Value)->at(0), 32);